diff --git a/.changeset/fancy-times-jog.md b/.changeset/fancy-times-jog.md new file mode 100644 index 0000000000..add52e7044 --- /dev/null +++ b/.changeset/fancy-times-jog.md @@ -0,0 +1,5 @@ +--- +'@tanstack/angular-table': patch +--- + +improve flexRender instance reuse and reduce adapter allocations diff --git a/.changeset/skip-stale-worker-rows.md b/.changeset/skip-stale-worker-rows.md new file mode 100644 index 0000000000..fec359f3c3 --- /dev/null +++ b/.changeset/skip-stale-worker-rows.md @@ -0,0 +1,5 @@ +--- +'@tanstack/table-core': patch +--- + +Skip missing core rows when rebuilding a worker row-model payload so stale worker results cannot crash the table diff --git a/AGENTS.md b/AGENTS.md index af9e354350..8b2068b4c1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,3 +8,19 @@ human-authored work. Keep every change focused on one topic. Understand and verify all generated code, run the required checks, and provide a concise pull request description that follows the repository template. + +## Packages that cannot be upgraded yet + +Leave these pins alone during routine dependency bumps. They currently break +Ember, the Svelte kitchen-sink types, or are intentionally deferred. + +- **TypeScript** — keep `6.0.3`. Do not bump it as part of a general upgrade. +- **Babel 7** — Ember is not compatible with Babel 8. In `packages/ember-table` + and every `examples/ember/*` app, keep `@babel/core`, + `@babel/plugin-transform-runtime`, `@babel/plugin-transform-typescript`, and + `@babel/runtime` at `7.29.7`. `@rollup/plugin-babel` `7.1.0` is the Rollup + plugin version, not Babel itself. +- **`@dnd-kit/abstract` and `@dnd-kit/helpers`** — keep `^0.2.3` in + `examples/svelte/kitchen-sink-shadcn`. `@dnd-kit-svelte/svelte@0.1.6` still + depends on the 0.2.x line. Bumping to 0.5.x installs a second copy, and + TypeScript treats those private-field types as incompatible. diff --git a/examples/alpine/aggregation/package.json b/examples/alpine/aggregation/package.json index f840e64450..787e790911 100644 --- a/examples/alpine/aggregation/package.json +++ b/examples/alpine/aggregation/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/basic-app-table/package.json b/examples/alpine/basic-app-table/package.json index dfb57d0cb2..cb351260a7 100644 --- a/examples/alpine/basic-app-table/package.json +++ b/examples/alpine/basic-app-table/package.json @@ -13,12 +13,13 @@ }, "dependencies": { "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/basic-create-table/package.json b/examples/alpine/basic-create-table/package.json index e234d5a8d8..2ec0250325 100644 --- a/examples/alpine/basic-create-table/package.json +++ b/examples/alpine/basic-create-table/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/basic-dynamic-columns/package.json b/examples/alpine/basic-dynamic-columns/package.json index d673fe30c4..7910154c26 100644 --- a/examples/alpine/basic-dynamic-columns/package.json +++ b/examples/alpine/basic-dynamic-columns/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/basic-external-atoms/package.json b/examples/alpine/basic-external-atoms/package.json index 4dfb928b63..60f890c815 100644 --- a/examples/alpine/basic-external-atoms/package.json +++ b/examples/alpine/basic-external-atoms/package.json @@ -12,15 +12,16 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", "@tanstack/store": "^0.11.1", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/basic-external-state/package.json b/examples/alpine/basic-external-state/package.json index 5918ee9e24..22f43db8ce 100644 --- a/examples/alpine/basic-external-state/package.json +++ b/examples/alpine/basic-external-state/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/cell-selection/package.json b/examples/alpine/cell-selection/package.json index 2c01490b4c..02af35451d 100644 --- a/examples/alpine/cell-selection/package.json +++ b/examples/alpine/cell-selection/package.json @@ -12,15 +12,16 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", "@tanstack/hotkeys": "^0.8.0", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/cell-spanning/package.json b/examples/alpine/cell-spanning/package.json index cd86e89ad6..d087edce25 100644 --- a/examples/alpine/cell-spanning/package.json +++ b/examples/alpine/cell-spanning/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/column-ordering/package.json b/examples/alpine/column-ordering/package.json index 16b297b059..f8c1447bfe 100644 --- a/examples/alpine/column-ordering/package.json +++ b/examples/alpine/column-ordering/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/column-pinning-split/package.json b/examples/alpine/column-pinning-split/package.json index baced8ea0c..9f2df28db9 100644 --- a/examples/alpine/column-pinning-split/package.json +++ b/examples/alpine/column-pinning-split/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/column-pinning-sticky/package.json b/examples/alpine/column-pinning-sticky/package.json index d2cc118b32..7ccb81bde4 100644 --- a/examples/alpine/column-pinning-sticky/package.json +++ b/examples/alpine/column-pinning-sticky/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/column-pinning/package.json b/examples/alpine/column-pinning/package.json index 97ba1e1d6f..f635ec8e59 100644 --- a/examples/alpine/column-pinning/package.json +++ b/examples/alpine/column-pinning/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/column-resizing-performant/package.json b/examples/alpine/column-resizing-performant/package.json index 56a9f76b91..f45d475a66 100644 --- a/examples/alpine/column-resizing-performant/package.json +++ b/examples/alpine/column-resizing-performant/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/column-resizing/package.json b/examples/alpine/column-resizing/package.json index 7cb8d0897f..22813654bf 100644 --- a/examples/alpine/column-resizing/package.json +++ b/examples/alpine/column-resizing/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/column-sizing/package.json b/examples/alpine/column-sizing/package.json index 6c2bd647e8..d687151458 100644 --- a/examples/alpine/column-sizing/package.json +++ b/examples/alpine/column-sizing/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/column-visibility/package.json b/examples/alpine/column-visibility/package.json index 795048c7d0..25296318db 100644 --- a/examples/alpine/column-visibility/package.json +++ b/examples/alpine/column-visibility/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/custom-plugin/package.json b/examples/alpine/custom-plugin/package.json index 1052e312b7..9b2d1a99d2 100644 --- a/examples/alpine/custom-plugin/package.json +++ b/examples/alpine/custom-plugin/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/expanding/package.json b/examples/alpine/expanding/package.json index 490f19e9f8..9d116e4b26 100644 --- a/examples/alpine/expanding/package.json +++ b/examples/alpine/expanding/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/filters-faceted-bucketed/package.json b/examples/alpine/filters-faceted-bucketed/package.json index be9daa0106..e3f8a50b83 100644 --- a/examples/alpine/filters-faceted-bucketed/package.json +++ b/examples/alpine/filters-faceted-bucketed/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/filters-faceted/package.json b/examples/alpine/filters-faceted/package.json index 33d8782195..7d2a869b88 100644 --- a/examples/alpine/filters-faceted/package.json +++ b/examples/alpine/filters-faceted/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/filters/package.json b/examples/alpine/filters/package.json index b048e51d3c..ff2869c0fe 100644 --- a/examples/alpine/filters/package.json +++ b/examples/alpine/filters/package.json @@ -11,14 +11,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/grouped-aggregation/package.json b/examples/alpine/grouped-aggregation/package.json index 0538d372e1..4b506704bd 100644 --- a/examples/alpine/grouped-aggregation/package.json +++ b/examples/alpine/grouped-aggregation/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/grouping/package.json b/examples/alpine/grouping/package.json index 9c732cd401..0be218159d 100644 --- a/examples/alpine/grouping/package.json +++ b/examples/alpine/grouping/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/header-groups/package.json b/examples/alpine/header-groups/package.json index 82a7314d15..4627ef1c3b 100644 --- a/examples/alpine/header-groups/package.json +++ b/examples/alpine/header-groups/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/pagination/package.json b/examples/alpine/pagination/package.json index 5da628bcbe..466bcd4c45 100644 --- a/examples/alpine/pagination/package.json +++ b/examples/alpine/pagination/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/realtime-trading/.gitignore b/examples/alpine/realtime-trading/.gitignore new file mode 100644 index 0000000000..1502ec233f --- /dev/null +++ b/examples/alpine/realtime-trading/.gitignore @@ -0,0 +1,3 @@ +dist +node_modules + diff --git a/examples/alpine/realtime-trading/README.md b/examples/alpine/realtime-trading/README.md new file mode 100644 index 0000000000..c897ca1556 --- /dev/null +++ b/examples/alpine/realtime-trading/README.md @@ -0,0 +1,150 @@ +# Alpine realtime trading benchmark + +This standalone example exercises the current TanStack Alpine Table adapter +with a high-frequency worker feed, immutable snapshots, interactive columns, +custom quote elements, Virtual Core, and browser diagnostics. It is a +repeatable UI stress workload, not an exchange or network benchmark. + +## Run and verify + +```bash +pnpm --dir examples/alpine/realtime-trading dev +``` + +Open `http://localhost:7777`. + +```bash +pnpm --dir examples/alpine/realtime-trading test:types +pnpm --dir examples/alpine/realtime-trading lint +pnpm --dir examples/alpine/realtime-trading build +pnpm --dir examples/alpine/realtime-trading test:e2e +``` + +Use a production build for performance recordings. + +## Structure and ownership + +| Path | Responsibility | +| ----------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| `src/feed/` | Market model, instrument universe, feed config, immutable update helpers, and direct TanStack atom controller. | +| `src/feed/worker/` | Typed protocol, deterministic engine, and module worker. | +| `src/benchmark/` | Browser monitor and benchmark controller. | +| `src/shell/configurator-options.ts` | Declarative select/range options used by the sidebar. | +| `src/table/table-config/` | Grouped columns and custom quote elements. | +| `src/table/` | Shared interaction helpers and virtualization constants. | +| `src/main.ts` | Alpine component factory and the imperative bridges to Store, Table, Virtual Core, observers, and DOM layout. | +| `index.html` | Declarative full-viewport shell, table template, controls, diagnostics, and status bar. | + +Alpine keeps the markup declarative in `index.html`; `tradingApp` owns only the +runtime coordination that cannot live in HTML. Feed and benchmark remain +separate controllers. Direct feed atoms are bridged into an Alpine reactive view +object individually: the high-frequency `quotes` atom is independent from +status and configuration atoms. Selected symbol and renderer mode are also +dedicated atoms. Every subscription, observer, virtualizer mount, controller, +and worker has explicit cleanup registered by `init()`/`destroy()`. + +## Feed and worker pipeline + +Defaults are 100 instruments, 10K generated samples/s, 20 ms delivery, enabled +intraday charts, and 16 ms chart sampling. + +Mutable quotes stay in the worker. A deterministic 16 ms budget loop generates +samples, a row-indexed `Map` coalesces repeated instrument changes, and a +separate timer publishes the latest unique rows. The main thread creates a new +outer array and only new changed rows. Unchanged rows and unsampled history +arrays retain identity. Session IDs reject late messages after resets or row +count changes. + +- **Synthetic quote workload** is generated worker samples/s, not Alpine DOM + updates or worker messages. +- **Worker delivery interval** controls coalesced message cadence; 20 ms targets + about 50 messages/s. +- **Row updates** counts unique immutable row objects applied. +- **Message samples** is the generated work represented by the latest batch. + +The 25K burst intentionally creates and flushes one expensive message. +Worker delivery resembles an upstream stream but does not include a network. + +## Alpine table architecture + +The table has 14 leaf columns grouped into Instrument, Price & Change, Order +Book, Session, and Chart. It supports sorting/filtering, on-change resizing, +double-click reset, drag column ordering, CSS hover, row selection, drag cell +ranges, keyboard navigation, and Price/Move/Percent/Sparkline custom elements. + +Stable instrument IDs back `getRowId`. The local `rows()` function caches the +row model by feed-array identity and table-state version so repeated Alpine +template reads do not call `getRowModel()` again during the same state. One +`TradingGridPointerController` handles all body input using `composedPath()` and +data attributes instead of per-cell listeners. + +Column widths are CSS custom properties updated only by sizing/order +subscriptions. `ResizeObserver` performs initial fit and stops after manual +resize. Component A/B swapping is an explicit lifecycle stress mode; stable +rendering is the realistic default. + +## Virtualization + +- Below 200 rows, automatic mode chooses Full DOM, but Virtual remains + selectable. +- From 200 through 1,499 rows, automatic mode chooses TanStack Virtual and Full + DOM remains selectable. +- At 1,500 rows or more, Virtual is forced and the control is locked. + +`main.ts` owns one `@tanstack/virtual-core` instance, updates its count/options, +and increments a narrow Alpine virtual version when its range changes. It uses +32 px estimates, 10-row overscan, row IDs as keys, transformed rows, and a body +spacer. The footer reads the instance range. Both modes apply +`content-visibility: auto`; Full DOM still creates all rows/cells. + +## Performance decisions + +- worker generation and coalescing before main-thread delivery; +- structural sharing for unchanged rows and histories; +- cached row-model reads keyed by actual dependencies; +- stable table/virtual row IDs; +- dedicated reactive versions for table and virtualizer changes; +- one delegated grid interaction controller and CSS hover; +- CSS variables for column sizes; +- configurable chart cadence and opt-in component churn; +- virtual mounting for large row sets; +- explicit lifecycle cleanup and low-frequency metrics publication. + +The immutable outer array changes by design. Stable inner references reduce +cell work, but sorting/filtering can still require a fresh row-model pass. + +## Diagnostics and interpretation + +The sidebar keeps four cross-framework health signals prominent: estimated +frame callbacks, average snapshot-to-DOM-commit latency, cumulative long +animation frames, and changed-row/snapshot throughput. The remaining counters +stay in Diagnostics so they do not look like equally important scores. + +`AVG COMMIT` is not the duration of an Alpine render function and it does not +include the browser's later layout or paint. It starts when a new immutable +snapshot is applied and ends in one coalesced `Alpine.nextTick()` callback, +after Alpine has flushed the corresponding DOM work. The average uses a rolling +3-second window; diagnostic p95/max use 10 seconds. If several worker +messages arrive before one Alpine flush, they intentionally produce one commit +sample from the earliest pending snapshot. + +The frame-rate estimate counts standard `requestAnimationFrame` callbacks over +one second; it is refresh-rate dependent and is not GPU/compositor FPS. +`Observed MutationRecords/s` is observer delivery count, not browser DOM +operations. It tracks text, child-list, class, and style changes while excluding +selection data attributes to reduce noise. The observer itself still adds work +at very high mutation rates. Heap is Chrome-only, current and GC-sensitive; +temporary growth is not proof of a leak without post-GC retention. React Scan is +not part of these shared measurements. User Timing commit and row-model entries +are sampled once every 20 candidates; the numeric counters remain exact, while +the Performance timeline avoids one retained entry per hot-path execution. + +## Standalone policy + +This folder intentionally contains its own instruments, feed, worker, +benchmark, shell markup, styles, and table code. It can run independently or be +copied to StackBlitz, so common source and README sections are duplicated across +adapters by design. + +The workspace resolves the pinned `@tanstack/alpine-table` dependency to the +local adapter package while keeping the manifest release-like. diff --git a/examples/alpine/realtime-trading/index.html b/examples/alpine/realtime-trading/index.html new file mode 100644 index 0000000000..3d0944c6a4 --- /dev/null +++ b/examples/alpine/realtime-trading/index.html @@ -0,0 +1,368 @@ + + + + + + TanStack Alpine Table · Realtime Trading + + +
+
+
+
MARKET MONITOR
+
+ +
+
+ +
+
+
+ + + + + + + +
+
+
+ + +
+ + + diff --git a/examples/alpine/realtime-trading/package.json b/examples/alpine/realtime-trading/package.json new file mode 100644 index 0000000000..5097d3d6eb --- /dev/null +++ b/examples/alpine/realtime-trading/package.json @@ -0,0 +1,25 @@ +{ + "name": "tanstack-alpine-table-example-realtime-trading", + "private": true, + "type": "module", + "scripts": { + "start": "vite", + "dev": "vite", + "build": "vite build", + "serve": "vite preview", + "lint": "eslint ./src", + "test:types": "tsc --noEmit", + "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" + }, + "dependencies": { + "@tanstack/alpine-table": "^9.2.3", + "@tanstack/store": "^0.11.1", + "alpinejs": "^3.16.3" + }, + "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", + "@types/alpinejs": "^3.13.11", + "typescript": "6.0.3", + "vite": "^8.2.2" + } +} diff --git a/examples/alpine/realtime-trading/src/benchmark/benchmark-monitor.ts b/examples/alpine/realtime-trading/src/benchmark/benchmark-monitor.ts new file mode 100644 index 0000000000..1bf9cdbc8c --- /dev/null +++ b/examples/alpine/realtime-trading/src/benchmark/benchmark-monitor.ts @@ -0,0 +1,436 @@ +import { + quoteCellLifecycle, + quoteRenderDiagnostics, +} from '../table/table-config/quote-cells' +import { rowModelDiagnostics } from '../table/trading-table' + +export interface NamedInvocationRate { + name: string + callsPerSecond: number +} + +interface TimedLatencySample { + recordedAt: number + duration: number +} + +const averageLatencyWindowMs = 3_000 +const percentileLatencyWindowMs = 10_000 +const frameRateWindowMs = 1_000 + +export interface FeedMetrics { + actualTicksPerSecond: number + rowUpdatesPerSecond: number + workerMessagesPerSecond: number + stateApplicationsPerSecond: number + supersededUpdatesPerSecond: number + totalTicks: number + rafCallbacksPerSecond: number + tableCommitsPerSecond: number + lastBatchSize: number + averageCommitLatencyMs: number + p95CommitLatencyMs: number + maxCommitLatencyMs: number + slowCommits: number + longAnimationFrames: number + worstLongAnimationFrameMs: number + heapMb: number | null + componentsCreated: number + componentsDestroyed: number + workerMessages: number + lastUpdateCount: number + cellRendererCallsPerSecond: number + componentRenderCallsPerSecond: number + cellRendererRates: ReadonlyArray + componentRenderRates: ReadonlyArray + domMutationsPerSecond: number + rowModelCallsPerSecond: number + rowModelAverageMs: number + rowModelMaxMs: number + visibleRows: number +} + +export const initialMetrics: FeedMetrics = { + actualTicksPerSecond: 0, + rowUpdatesPerSecond: 0, + workerMessagesPerSecond: 0, + stateApplicationsPerSecond: 0, + supersededUpdatesPerSecond: 0, + totalTicks: 0, + rafCallbacksPerSecond: 0, + tableCommitsPerSecond: 0, + lastBatchSize: 0, + averageCommitLatencyMs: 0, + p95CommitLatencyMs: 0, + maxCommitLatencyMs: 0, + slowCommits: 0, + longAnimationFrames: 0, + worstLongAnimationFrameMs: 0, + heapMb: null, + componentsCreated: 0, + componentsDestroyed: 0, + workerMessages: 0, + lastUpdateCount: 0, + cellRendererCallsPerSecond: 0, + componentRenderCallsPerSecond: 0, + cellRendererRates: [], + componentRenderRates: [], + domMutationsPerSecond: 0, + rowModelCallsPerSecond: 0, + rowModelAverageMs: 0, + rowModelMaxMs: 0, + visibleRows: 0, +} + +const userTiming = { entryCount: 0, measureCandidateCount: 0 } +const userTimingSamplingInterval = 20 + +export function recordMeasure( + name: string, + start: number, + end: number, + detail: Record, +): void { + userTiming.measureCandidateCount++ + if (userTiming.measureCandidateCount % userTimingSamplingInterval !== 0) + return + try { + performance.measure(name, { start, end, detail }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMeasures('market-update-to-dom-commit') + } + } catch { + // User Timing Level 3 options are not implemented in every browser. + } +} + +export function markBenchmarkAction( + name: string, + detail: Record = {}, +): void { + try { + performance.mark(`benchmark:${name}`, { detail }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMarks() + } + } catch { + // User Timing Level 3 detail is not implemented in every browser. + } +} + +export class BenchmarkMonitor { + readonly #runtime = { + sampleStartedAt: performance.now(), + sessionStartedAt: performance.now(), + pendingMutationStartedAt: null as number | null, + commitLatencySamples: [] as Array, + slowCommitCount: 0, + totalTicks: 0, + ticksInSample: 0, + rowUpdatesInSample: 0, + workerMessagesInSample: 0, + stateApplicationsInSample: 0, + supersededUpdatesInSample: 0, + lastBatchSize: 0, + lastUpdateCount: 0, + workerMessages: 0, + frameTrackingStartedAt: performance.now(), + frameTimestamps: [] as Array, + tableCommitsInSample: 0, + longAnimationFrameCount: 0, + worstLongAnimationFrameMs: 0, + previousCellRendererCalls: 0, + previousComponentRenderCalls: 0, + previousCellRendererCallsByName: { + ...quoteRenderDiagnostics.cellRendererCallsByName, + }, + previousComponentRenderCallsByName: { + ...quoteRenderDiagnostics.componentRenderCallsByName, + }, + domMutationsInSample: 0, + previousRowModelCalls: 0, + previousRowModelDuration: 0, + } + + markCommitPending(): void { + this.#runtime.pendingMutationStartedAt ??= performance.now() + } + + recordDomCommit(): void { + const runtime = this.#runtime + if (runtime.pendingMutationStartedAt !== null) { + const commitEndedAt = performance.now() + const duration = commitEndedAt - runtime.pendingMutationStartedAt + runtime.commitLatencySamples.push({ + recordedAt: commitEndedAt, + duration, + }) + if (duration > 16.7) runtime.slowCommitCount++ + recordMeasure( + 'market-update-to-dom-commit', + runtime.pendingMutationStartedAt, + commitEndedAt, + {}, + ) + runtime.pendingMutationStartedAt = null + runtime.tableCommitsInSample++ + } + } + + recordWorkerMessage(): void { + this.#runtime.workerMessages++ + this.#runtime.workerMessagesInSample++ + } + + recordBatch( + tickCount: number, + updateCount: number, + supersededUpdateCount: number, + ): void { + const runtime = this.#runtime + runtime.lastBatchSize = tickCount + runtime.lastUpdateCount = updateCount + runtime.ticksInSample += tickCount + runtime.totalTicks += tickCount + runtime.rowUpdatesInSample += updateCount + runtime.stateApplicationsInSample++ + runtime.supersededUpdatesInSample += supersededUpdateCount + } + + recordAnimationFrame(now: number): void { + const timestamps = this.#runtime.frameTimestamps + timestamps.push(now) + pruneFrameTimestamps(timestamps, now) + } + + recordLongAnimationFrame(duration: number, startTime: number): void { + const runtime = this.#runtime + if (startTime < runtime.sessionStartedAt) return + runtime.longAnimationFrameCount++ + runtime.worstLongAnimationFrameMs = Math.max( + runtime.worstLongAnimationFrameMs, + duration, + ) + } + + recordDomMutations(count: number): void { + this.#runtime.domMutationsInSample += count + } + + resetDomMutations(): void { + this.#runtime.domMutationsInSample = 0 + } + + shouldPublish(now: number): boolean { + return now - this.#runtime.sampleStartedAt >= 500 + } + + publish(now: number): FeedMetrics { + const runtime = this.#runtime + const sampleDuration = now - runtime.sampleStartedAt + pruneLatencySamples(runtime.commitLatencySamples, now) + pruneFrameTimestamps(runtime.frameTimestamps, now) + const averageCommitLatencySamples = runtime.commitLatencySamples + .filter((sample) => sample.recordedAt >= now - averageLatencyWindowMs) + .map((sample) => sample.duration) + const percentileCommitLatencySamples = runtime.commitLatencySamples.map( + (sample) => sample.duration, + ) + const sortedCommitLatencySamples = [...percentileCommitLatencySamples].sort( + (left, right) => left - right, + ) + const rowModelCalls = + rowModelDiagnostics.calls - runtime.previousRowModelCalls + const rowModelDuration = + rowModelDiagnostics.totalDurationMs - runtime.previousRowModelDuration + const cellRendererCalls = + quoteRenderDiagnostics.cellRendererCalls - + runtime.previousCellRendererCalls + const componentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls - + runtime.previousComponentRenderCalls + const cellRendererRates = calculateInvocationRates( + quoteRenderDiagnostics.cellRendererCallsByName, + runtime.previousCellRendererCallsByName, + sampleDuration, + ) + const componentRenderRates = calculateInvocationRates( + quoteRenderDiagnostics.componentRenderCallsByName, + runtime.previousComponentRenderCallsByName, + sampleDuration, + ) + const averageCommitLatencyMs = + averageCommitLatencySamples.length === 0 + ? 0 + : averageCommitLatencySamples.reduce((sum, value) => sum + value, 0) / + averageCommitLatencySamples.length + const p95Index = Math.max( + 0, + Math.ceil(sortedCommitLatencySamples.length * 0.95) - 1, + ) + const metrics: FeedMetrics = { + actualTicksPerSecond: + sampleDuration === 0 + ? 0 + : (runtime.ticksInSample / sampleDuration) * 1_000, + rowUpdatesPerSecond: + (runtime.rowUpdatesInSample / sampleDuration) * 1_000, + workerMessagesPerSecond: + (runtime.workerMessagesInSample / sampleDuration) * 1_000, + stateApplicationsPerSecond: + (runtime.stateApplicationsInSample / sampleDuration) * 1_000, + supersededUpdatesPerSecond: + (runtime.supersededUpdatesInSample / sampleDuration) * 1_000, + totalTicks: runtime.totalTicks, + rafCallbacksPerSecond: calculateFrameRate( + runtime.frameTimestamps, + runtime.frameTrackingStartedAt, + now, + ), + tableCommitsPerSecond: + (runtime.tableCommitsInSample / sampleDuration) * 1_000, + lastBatchSize: runtime.lastBatchSize, + averageCommitLatencyMs, + p95CommitLatencyMs: sortedCommitLatencySamples[p95Index] ?? 0, + maxCommitLatencyMs: sortedCommitLatencySamples.at(-1) ?? 0, + slowCommits: runtime.slowCommitCount, + longAnimationFrames: runtime.longAnimationFrameCount, + worstLongAnimationFrameMs: runtime.worstLongAnimationFrameMs, + heapMb: readHeapSizeMb(), + componentsCreated: quoteCellLifecycle.created, + componentsDestroyed: quoteCellLifecycle.destroyed, + workerMessages: runtime.workerMessages, + lastUpdateCount: runtime.lastUpdateCount, + cellRendererCallsPerSecond: (cellRendererCalls / sampleDuration) * 1_000, + componentRenderCallsPerSecond: + (componentRenderCalls / sampleDuration) * 1_000, + cellRendererRates, + componentRenderRates, + domMutationsPerSecond: + (runtime.domMutationsInSample / sampleDuration) * 1_000, + rowModelCallsPerSecond: (rowModelCalls / sampleDuration) * 1_000, + rowModelAverageMs: + rowModelCalls === 0 ? 0 : rowModelDuration / rowModelCalls, + rowModelMaxMs: rowModelDiagnostics.maxDurationMs, + visibleRows: rowModelDiagnostics.lastRowCount, + } + + runtime.sampleStartedAt = now + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.previousRowModelCalls = rowModelDiagnostics.calls + runtime.previousRowModelDuration = rowModelDiagnostics.totalDurationMs + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.tableCommitsInSample = 0 + return metrics + } + + reset(): void { + const runtime = this.#runtime + runtime.sampleStartedAt = performance.now() + runtime.sessionStartedAt = runtime.sampleStartedAt + runtime.pendingMutationStartedAt = null + runtime.commitLatencySamples = [] + runtime.slowCommitCount = 0 + runtime.totalTicks = 0 + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.lastBatchSize = 0 + runtime.lastUpdateCount = 0 + runtime.workerMessages = 0 + runtime.frameTrackingStartedAt = runtime.sampleStartedAt + runtime.frameTimestamps = [] + runtime.tableCommitsInSample = 0 + runtime.longAnimationFrameCount = 0 + runtime.worstLongAnimationFrameMs = 0 + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.previousRowModelCalls = rowModelDiagnostics.calls + runtime.previousRowModelDuration = rowModelDiagnostics.totalDurationMs + rowModelDiagnostics.maxDurationMs = 0 + } +} + +export const longAnimationFramesSupported = + PerformanceObserver.supportedEntryTypes.includes('long-animation-frame') + +function readHeapSizeMb(): number | null { + const memory = ( + performance as Performance & { + memory?: { usedJSHeapSize: number } + } + ).memory + return memory ? memory.usedJSHeapSize / 1_048_576 : null +} + +function calculateInvocationRates( + current: Record, + previous: Record, + sampleDuration: number, +): ReadonlyArray { + return Object.entries(current).map(([name, calls]) => ({ + name, + callsPerSecond: + sampleDuration === 0 + ? 0 + : ((calls - (previous[name] ?? 0)) / sampleDuration) * 1_000, + })) +} + +function pruneLatencySamples( + samples: Array, + now: number, +): void { + const cutoff = now - percentileLatencyWindowMs + const firstRetainedIndex = samples.findIndex( + (sample) => sample.recordedAt >= cutoff, + ) + if (firstRetainedIndex > 0) samples.splice(0, firstRetainedIndex) + else if (firstRetainedIndex === -1) samples.length = 0 +} + +function pruneFrameTimestamps(timestamps: Array, now: number): void { + const cutoff = now - frameRateWindowMs + const firstRetainedIndex = timestamps.findIndex( + (timestamp) => timestamp >= cutoff, + ) + if (firstRetainedIndex > 0) timestamps.splice(0, firstRetainedIndex) + else if (firstRetainedIndex === -1) timestamps.length = 0 +} + +function calculateFrameRate( + timestamps: ReadonlyArray, + trackingStartedAt: number, + now: number, +): number { + const observedWindowMs = Math.min( + frameRateWindowMs, + Math.max(1, now - trackingStartedAt), + ) + return (timestamps.length / observedWindowMs) * 1_000 +} diff --git a/examples/alpine/realtime-trading/src/benchmark/trading-benchmark-controller.ts b/examples/alpine/realtime-trading/src/benchmark/trading-benchmark-controller.ts new file mode 100644 index 0000000000..b7e74cccaf --- /dev/null +++ b/examples/alpine/realtime-trading/src/benchmark/trading-benchmark-controller.ts @@ -0,0 +1,138 @@ +import { batch, createAtom, createStore } from '@tanstack/store' +import { TRADING_COLUMN_COUNT } from '../table/trading-table' +import { + BenchmarkMonitor, + initialMetrics, + longAnimationFramesSupported, +} from './benchmark-monitor' +import type { FeedMetrics } from './benchmark-monitor' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { RendererMode } from '../table/trading-table' + +export interface TradingBenchmarkState { + metrics: FeedMetrics + mountedCells: number + liveComponents: number + longAnimationFramesSupported: boolean +} + +export interface TradingBenchmarkActions { + resetViewState: () => void + setRendererMode: (mode: RendererMode) => void + setRenderedRowCount: (count: number) => void + selectSymbol: (symbol: string | null) => void + resetMarket: () => void +} + +const initialState: TradingBenchmarkState = { + metrics: initialMetrics, + mountedCells: 0, + liveComponents: 0, + longAnimationFramesSupported, +} + +export class TradingBenchmarkController { + readonly store = createStore(initialState) + readonly renderAtoms = { + selectedSymbol: createAtom(null), + rendererMode: createAtom('stable'), + } + readonly monitor = new BenchmarkMonitor() + readonly feed: MarketFeedController + readonly actions: TradingBenchmarkActions + + readonly #runtime = { + animationFrameId: 0, + longAnimationFrameObserver: null as PerformanceObserver | null, + stopObservingFeed: null as (() => void) | null, + } + + constructor(feed: MarketFeedController) { + this.feed = feed + this.actions = { + resetViewState: () => { + this.renderAtoms.selectedSymbol.set(null) + }, + setRendererMode: (mode) => { + this.renderAtoms.rendererMode.set(mode) + }, + setRenderedRowCount: (count) => { + const mountedCells = count * TRADING_COLUMN_COUNT + if (mountedCells !== this.store.get().mountedCells) { + this.#patch({ mountedCells }) + } + }, + selectSymbol: (symbol) => { + this.renderAtoms.selectedSymbol.set(symbol) + }, + resetMarket: () => { + batch(() => { + this.monitor.reset() + this.store.setState((state) => ({ + ...state, + metrics: { ...initialMetrics }, + mountedCells: 0, + liveComponents: 0, + })) + this.renderAtoms.selectedSymbol.set(null) + this.feed.actions.reset() + }) + }, + } + } + + start(): () => void { + const longAnimationFrameObserver = longAnimationFramesSupported + ? new PerformanceObserver((entries) => { + for (const entry of entries.getEntries()) { + this.monitor.recordLongAnimationFrame( + entry.duration, + entry.startTime, + ) + } + }) + : null + + this.#runtime.longAnimationFrameObserver = longAnimationFrameObserver + this.#runtime.stopObservingFeed = this.feed.observe({ + messageReceived: () => this.monitor.recordWorkerMessage(), + mutationStarted: () => this.monitor.markCommitPending(), + batchApplied: ({ tickCount, updateCount, supersededUpdateCount }) => + this.monitor.recordBatch(tickCount, updateCount, supersededUpdateCount), + renderCommitted: () => this.monitor.recordDomCommit(), + }) + longAnimationFrameObserver?.observe({ + type: 'long-animation-frame', + }) + this.#runtime.animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + + return () => this.stop() + } + + stop(): void { + cancelAnimationFrame(this.#runtime.animationFrameId) + this.#runtime.longAnimationFrameObserver?.disconnect() + this.#runtime.stopObservingFeed?.() + this.#runtime.longAnimationFrameObserver = null + this.#runtime.stopObservingFeed = null + } + + readonly #benchmarkFrame = (now: number): void => { + this.monitor.recordAnimationFrame(now) + if (this.monitor.shouldPublish(now)) { + this.#publishMetrics(this.monitor.publish(now)) + } + this.#runtime.animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + } + + #patch(patch: Partial): void { + this.store.setState((state) => ({ ...state, ...patch })) + } + + #publishMetrics(metrics: FeedMetrics): void { + this.#patch({ + metrics, + liveComponents: metrics.componentsCreated - metrics.componentsDestroyed, + }) + } +} diff --git a/examples/alpine/realtime-trading/src/feed/feed-sample-rates.ts b/examples/alpine/realtime-trading/src/feed/feed-sample-rates.ts new file mode 100644 index 0000000000..17dc2015a6 --- /dev/null +++ b/examples/alpine/realtime-trading/src/feed/feed-sample-rates.ts @@ -0,0 +1,33 @@ +export const feedSampleRateOptions = [ + { label: '100', value: 100 }, + { label: '250', value: 250 }, + { label: '500', value: 500 }, + { label: '1K', value: 1_000 }, + { label: '2.5K', value: 2_500 }, + { label: '5K', value: 5_000 }, + { label: '10K', value: 10_000 }, + { label: '25K', value: 25_000 }, + { label: '50K', value: 50_000 }, + { label: '100K', value: 100_000 }, +] as const + +export function feedSampleRateIndex(rate: number): number { + return feedSampleRateOptions.reduce((closestIndex, candidate, index) => { + const closest = feedSampleRateOptions[closestIndex] + return Math.abs(candidate.value - rate) < Math.abs(closest.value - rate) + ? index + : closestIndex + }, 0) +} + +export function feedSampleRateAt(stepIndex: number): number { + const index = Math.min( + feedSampleRateOptions.length - 1, + Math.max(0, Math.round(stepIndex)), + ) + return feedSampleRateOptions[index].value +} + +export function normalizeFeedSampleRate(rate: number): number { + return feedSampleRateAt(feedSampleRateIndex(rate)) +} diff --git a/examples/alpine/realtime-trading/src/feed/market-data.ts b/examples/alpine/realtime-trading/src/feed/market-data.ts new file mode 100644 index 0000000000..6231865d3f --- /dev/null +++ b/examples/alpine/realtime-trading/src/feed/market-data.ts @@ -0,0 +1,38 @@ +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './worker/market-feed-protocol' + +export interface MarketQuote extends Omit { + history: ReadonlyArray +} + +export function hydrateMarketQuotes( + snapshots: Array, +): Array { + return snapshots.map((quote) => ({ + ...quote, + history: [...quote.history], + })) +} + +export function applyMarketUpdates( + quotes: Array, + updates: Array, +): Array { + const nextQuotes = [...quotes] + + for (const update of updates) { + const { index, history, ...values } = update + const previousQuote = quotes.at(index) + if (!previousQuote) continue + + nextQuotes[index] = { + ...previousQuote, + ...values, + history: history ?? previousQuote.history, + } + } + + return nextQuotes +} diff --git a/examples/alpine/realtime-trading/src/feed/market-feed-config.ts b/examples/alpine/realtime-trading/src/feed/market-feed-config.ts new file mode 100644 index 0000000000..9d477ed663 --- /dev/null +++ b/examples/alpine/realtime-trading/src/feed/market-feed-config.ts @@ -0,0 +1,15 @@ +export interface MarketFeedConfig { + readonly instrumentCount: number + readonly targetSamplesPerSecond: number + readonly publishIntervalMs: number + readonly updateSparklines: boolean + readonly sparklineSampleIntervalMs: number +} + +export const initialMarketFeedConfig: MarketFeedConfig = { + instrumentCount: 100, + targetSamplesPerSecond: 10_000, + publishIntervalMs: 20, + updateSparklines: true, + sparklineSampleIntervalMs: 16, +} diff --git a/examples/alpine/realtime-trading/src/feed/market-feed-controller.ts b/examples/alpine/realtime-trading/src/feed/market-feed-controller.ts new file mode 100644 index 0000000000..157c577821 --- /dev/null +++ b/examples/alpine/realtime-trading/src/feed/market-feed-controller.ts @@ -0,0 +1,229 @@ +import { batch, createAtom } from '@tanstack/store' +import { normalizeFeedSampleRate } from './feed-sample-rates' +import { initialMarketFeedConfig } from './market-feed-config' +import { applyMarketUpdates, hydrateMarketQuotes } from './market-data' +import type { + MarketFeedCommand, + MarketFeedEvent, +} from './worker/market-feed-protocol' +import type { MarketQuote } from './market-data' + +export interface MarketFeedBatch { + tickCount: number + updateCount: number + supersededUpdateCount: number +} + +export interface MarketFeedObserver { + messageReceived?: () => void + mutationStarted?: () => void + batchApplied?: (batch: MarketFeedBatch) => void + renderCommitted?: () => void +} + +export interface MarketFeedActions { + toggle: () => void + setInstrumentCount: (count: number) => void + setTargetRate: (rate: number) => void + setPublishInterval: (intervalMs: number) => void + setSparklineUpdates: (enabled: boolean) => void + setSparklineSampleInterval: (intervalMs: number) => void + runBurst: () => void + reset: () => void +} + +export class MarketFeedController { + readonly workerReady = createAtom(false) + readonly running = createAtom( + !new URLSearchParams(location.search).has('paused'), + ) + readonly instrumentCount = createAtom(initialMarketFeedConfig.instrumentCount) + readonly targetTicksPerSecond = createAtom( + initialMarketFeedConfig.targetSamplesPerSecond, + ) + readonly publishIntervalMs = createAtom( + initialMarketFeedConfig.publishIntervalMs, + ) + readonly updateSparklines = createAtom( + initialMarketFeedConfig.updateSparklines, + ) + readonly sparklineSampleIntervalMs = createAtom( + initialMarketFeedConfig.sparklineSampleIntervalMs, + ) + readonly quotes = createAtom>([]) + readonly actions: MarketFeedActions + readonly #observers = new Set() + readonly #runtime = { + worker: null as Worker | null, + feedSessionId: 0, + renderPending: false, + resetWaitingForCommit: false, + resetSnapshotReady: false, + quoteIndexBySymbol: new Map(), + } + + constructor() { + this.actions = { + toggle: () => { + const running = !this.running.get() + this.running.set(running) + this.#post({ type: 'set-running', running }) + }, + setInstrumentCount: (count) => { + this.instrumentCount.set(count) + this.#resetWorker(count) + }, + setTargetRate: (rate) => { + const sampleRate = normalizeFeedSampleRate(rate) + this.targetTicksPerSecond.set(sampleRate) + this.#post({ type: 'set-rate', ticksPerSecond: sampleRate }) + }, + setPublishInterval: (publishIntervalMs) => { + this.publishIntervalMs.set(publishIntervalMs) + this.#post({ + type: 'set-publish-interval', + intervalMs: publishIntervalMs, + }) + }, + setSparklineUpdates: (enabled) => { + this.updateSparklines.set(enabled) + this.#post({ type: 'set-sparklines', enabled }) + }, + setSparklineSampleInterval: (intervalMs) => { + this.sparklineSampleIntervalMs.set(intervalMs) + this.#post({ type: 'set-sparkline-interval', intervalMs }) + }, + runBurst: () => this.#post({ type: 'burst', tickCount: 25_000 }), + reset: () => this.#resetWorker(this.instrumentCount.get()), + } + } + + start(): () => void { + const worker = new Worker( + new URL('./worker/market-feed.worker.ts', import.meta.url), + { type: 'module' }, + ) + this.#runtime.worker = worker + worker.addEventListener('message', this.#handleWorkerMessage) + worker.addEventListener('error', this.#handleWorkerError) + this.#post({ + type: 'start', + rowCount: this.instrumentCount.get(), + running: this.running.get(), + ticksPerSecond: this.targetTicksPerSecond.get(), + publishIntervalMs: this.publishIntervalMs.get(), + updateSparklines: this.updateSparklines.get(), + sparklineSampleIntervalMs: this.sparklineSampleIntervalMs.get(), + }) + return () => this.stop() + } + + stop(): void { + this.#runtime.worker?.removeEventListener( + 'message', + this.#handleWorkerMessage, + ) + this.#runtime.worker?.removeEventListener('error', this.#handleWorkerError) + this.#runtime.worker?.terminate() + this.#runtime.worker = null + this.#observers.clear() + } + + observe(observer: MarketFeedObserver): () => void { + this.#observers.add(observer) + return () => this.#observers.delete(observer) + } + + getQuoteBySymbol( + quotes: Array, + symbol: string | null, + ): MarketQuote | null { + if (symbol === null) return null + + const index = this.#runtime.quoteIndexBySymbol.get(symbol) + return index === undefined ? null : (quotes[index] ?? null) + } + + completeRender(): void { + if (!this.#runtime.renderPending) return + + this.#runtime.renderPending = false + for (const observer of this.#observers) { + observer.renderCommitted?.() + } + if ( + this.#runtime.resetWaitingForCommit && + this.#runtime.resetSnapshotReady + ) { + this.#runtime.resetWaitingForCommit = false + this.#runtime.resetSnapshotReady = false + this.#post({ type: 'set-running', running: this.running.get() }) + } + } + + readonly #handleWorkerMessage = ({ + data, + }: MessageEvent): void => { + if (data.type === 'snapshot') { + this.#runtime.feedSessionId = data.sessionId + if (this.#runtime.resetWaitingForCommit) { + this.#runtime.resetSnapshotReady = true + } + this.#startMutation() + const quotes = hydrateMarketQuotes(data.quotes) + this.#runtime.quoteIndexBySymbol = new Map( + quotes.map((quote, index) => [quote.symbol, index]), + ) + batch(() => { + this.quotes.set(quotes) + this.workerReady.set(true) + }) + return + } + + if (data.sessionId !== this.#runtime.feedSessionId) return + + for (const observer of this.#observers) { + observer.messageReceived?.() + } + this.#startMutation() + this.quotes.set(applyMarketUpdates(this.quotes.get(), data.updates)) + const feedBatch = { + tickCount: data.tickCount, + updateCount: data.updates.length, + supersededUpdateCount: data.coalescedUpdateCount, + } + for (const observer of this.#observers) { + observer.batchApplied?.(feedBatch) + } + } + + readonly #handleWorkerError = (error: ErrorEvent): void => { + batch(() => { + this.workerReady.set(false) + this.running.set(false) + }) + console.error('Market feed worker failed', error) + } + + #resetWorker(rowCount: number): void { + this.workerReady.set(false) + if (this.running.get()) { + this.#runtime.resetWaitingForCommit = true + this.#runtime.resetSnapshotReady = false + this.#post({ type: 'set-running', running: false }) + } + this.#post({ type: 'reset', rowCount }) + } + + #startMutation(): void { + this.#runtime.renderPending = true + for (const observer of this.#observers) { + observer.mutationStarted?.() + } + } + + #post(command: MarketFeedCommand): void { + this.#runtime.worker?.postMessage(command) + } +} diff --git a/examples/alpine/realtime-trading/src/feed/market-instruments.ts b/examples/alpine/realtime-trading/src/feed/market-instruments.ts new file mode 100644 index 0000000000..ac18d14ea9 --- /dev/null +++ b/examples/alpine/realtime-trading/src/feed/market-instruments.ts @@ -0,0 +1,742 @@ +export type MarketCode = + | 'US' + | 'NL' + | 'DE' + | 'FR' + | 'IT' + | 'ES' + | 'CH' + | 'DK' + | 'SE' + | 'FI' + | 'GB' + | 'KR' + | 'JP' + | 'HK' + | 'CA' + | 'AU' + +export type BaseInstrument = readonly [ + symbol: string, + company: string, + market: MarketCode, +] + +/** + * Current S&P 500 constituent universe used by the realtime trading examples. + * + * Source snapshot: https://github.com/datasets/s-and-p-500-companies + * Retrieved: 2026-08-15. + * Multiple share classes are intentionally represented as separate instruments. + */ +export const marketInstruments = Object.freeze([ + ['MMM', '3M', 'US'], + ['AOS', 'A. O. Smith', 'US'], + ['ABT', 'Abbott Laboratories', 'US'], + ['ABBV', 'AbbVie', 'US'], + ['ACN', 'Accenture', 'US'], + ['ADBE', 'Adobe Inc.', 'US'], + ['AMD', 'Advanced Micro Devices', 'US'], + ['AES', 'AES Corporation', 'US'], + ['AFL', 'Aflac', 'US'], + ['A', 'Agilent Technologies', 'US'], + ['APD', 'Air Products', 'US'], + ['ABNB', 'Airbnb', 'US'], + ['AKAM', 'Akamai Technologies', 'US'], + ['ALB', 'Albemarle Corporation', 'US'], + ['ARE', 'Alexandria Real Estate Equities', 'US'], + ['ALGN', 'Align Technology', 'US'], + ['ALLE', 'Allegion', 'US'], + ['LNT', 'Alliant Energy', 'US'], + ['ALL', 'Allstate', 'US'], + ['GOOGL', 'Alphabet Inc. (Class A)', 'US'], + ['GOOG', 'Alphabet Inc. (Class C)', 'US'], + ['MO', 'Altria', 'US'], + ['AMZN', 'Amazon', 'US'], + ['AMCR', 'Amcor', 'US'], + ['AEE', 'Ameren', 'US'], + ['AEP', 'American Electric Power', 'US'], + ['AXP', 'American Express', 'US'], + ['AIG', 'American International Group', 'US'], + ['AMT', 'American Tower', 'US'], + ['AWK', 'American Water Works', 'US'], + ['AMP', 'Ameriprise Financial', 'US'], + ['AME', 'Ametek', 'US'], + ['AMGN', 'Amgen', 'US'], + ['APH', 'Amphenol', 'US'], + ['ADI', 'Analog Devices', 'US'], + ['AON', 'Aon plc', 'US'], + ['APA', 'APA Corporation', 'US'], + ['APO', 'Apollo Global Management', 'US'], + ['AAPL', 'Apple Inc.', 'US'], + ['AMAT', 'Applied Materials', 'US'], + ['APP', 'AppLovin', 'US'], + ['APTV', 'Aptiv', 'US'], + ['ACGL', 'Arch Capital Group', 'US'], + ['ADM', 'Archer Daniels Midland', 'US'], + ['ARES', 'Ares Management', 'US'], + ['ANET', 'Arista Networks', 'US'], + ['AJG', 'Arthur J. Gallagher & Co.', 'US'], + ['AIZ', 'Assurant', 'US'], + ['T', 'AT&T', 'US'], + ['ATO', 'Atmos Energy', 'US'], + ['ADSK', 'Autodesk', 'US'], + ['ADP', 'Automatic Data Processing', 'US'], + ['AZO', 'AutoZone', 'US'], + ['AVB', 'AvalonBay Communities', 'US'], + ['AVY', 'Avery Dennison', 'US'], + ['AXON', 'Axon Enterprise', 'US'], + ['BKR', 'Baker Hughes', 'US'], + ['BALL', 'Ball Corporation', 'US'], + ['BAC', 'Bank of America', 'US'], + ['BAX', 'Baxter International', 'US'], + ['BDX', 'Becton Dickinson', 'US'], + ['BRK.B', 'Berkshire Hathaway', 'US'], + ['BBY', 'Best Buy', 'US'], + ['TECH', 'Bio-Techne', 'US'], + ['BIIB', 'Biogen', 'US'], + ['BLK', 'BlackRock', 'US'], + ['BX', 'Blackstone Inc.', 'US'], + ['XYZ', 'Block, Inc.', 'US'], + ['BNY', 'BNY Mellon', 'US'], + ['BA', 'Boeing', 'US'], + ['BKNG', 'Booking Holdings', 'US'], + ['BSX', 'Boston Scientific', 'US'], + ['BMY', 'Bristol Myers Squibb', 'US'], + ['AVGO', 'Broadcom', 'US'], + ['BR', 'Broadridge Financial Solutions', 'US'], + ['BRO', 'Brown & Brown', 'US'], + ['BF.B', 'Brown–Forman', 'US'], + ['BLDR', 'Builders FirstSource', 'US'], + ['BG', 'Bunge Global', 'US'], + ['BXP', 'BXP, Inc.', 'US'], + ['CHRW', 'C.H. Robinson', 'US'], + ['CDNS', 'Cadence Design Systems', 'US'], + ['CPT', 'Camden Property Trust', 'US'], + ['COF', 'Capital One', 'US'], + ['CAH', 'Cardinal Health', 'US'], + ['CCL', 'Carnival Corporation', 'US'], + ['CARR', 'Carrier Global', 'US'], + ['CVNA', 'Carvana', 'US'], + ['CASY', "Casey's", 'US'], + ['CAT', 'Caterpillar Inc.', 'US'], + ['CBOE', 'Cboe Global Markets', 'US'], + ['CBRE', 'CBRE Group', 'US'], + ['CDW', 'CDW Corporation', 'US'], + ['COR', 'Cencora', 'US'], + ['CNC', 'Centene Corporation', 'US'], + ['CNP', 'CenterPoint Energy', 'US'], + ['CF', 'CF Industries', 'US'], + ['CRL', 'Charles River Laboratories', 'US'], + ['SCHW', 'Charles Schwab Corporation', 'US'], + ['CHTR', 'Charter Communications', 'US'], + ['CVX', 'Chevron Corporation', 'US'], + ['CMG', 'Chipotle Mexican Grill', 'US'], + ['CB', 'Chubb Limited', 'US'], + ['CHD', 'Church & Dwight', 'US'], + ['CIEN', 'Ciena', 'US'], + ['CI', 'Cigna', 'US'], + ['CINF', 'Cincinnati Financial', 'US'], + ['CTAS', 'Cintas', 'US'], + ['CSCO', 'Cisco', 'US'], + ['C', 'Citigroup', 'US'], + ['CFG', 'Citizens Financial Group', 'US'], + ['CLX', 'Clorox', 'US'], + ['CME', 'CME Group', 'US'], + ['CMS', 'CMS Energy', 'US'], + ['KO', 'Coca-Cola Company (The)', 'US'], + ['CTSH', 'Cognizant', 'US'], + ['COHR', 'Coherent Corp.', 'US'], + ['COIN', 'Coinbase', 'US'], + ['CL', 'Colgate-Palmolive', 'US'], + ['CMCSA', 'Comcast', 'US'], + ['FIX', 'Comfort Systems USA', 'US'], + ['COP', 'ConocoPhillips', 'US'], + ['ED', 'Consolidated Edison', 'US'], + ['STZ', 'Constellation Brands', 'US'], + ['CEG', 'Constellation Energy', 'US'], + ['COO', 'Cooper Companies (The)', 'US'], + ['CPRT', 'Copart', 'US'], + ['GLW', 'Corning Inc.', 'US'], + ['CPAY', 'Corpay', 'US'], + ['CTVA', 'Corteva', 'US'], + ['CSGP', 'CoStar Group', 'US'], + ['COST', 'Costco', 'US'], + ['CRH', 'CRH plc', 'US'], + ['CRWD', 'CrowdStrike', 'US'], + ['CCI', 'Crown Castle', 'US'], + ['CSX', 'CSX Corporation', 'US'], + ['CMI', 'Cummins', 'US'], + ['CVS', 'CVS Health', 'US'], + ['DHR', 'Danaher Corporation', 'US'], + ['DRI', 'Darden Restaurants', 'US'], + ['DDOG', 'Datadog', 'US'], + ['DVA', 'DaVita', 'US'], + ['DECK', 'Deckers Brands', 'US'], + ['DE', 'Deere & Company', 'US'], + ['DELL', 'Dell Technologies', 'US'], + ['DAL', 'Delta Air Lines', 'US'], + ['DVN', 'Devon Energy', 'US'], + ['DXCM', 'Dexcom', 'US'], + ['FANG', 'Diamondback Energy', 'US'], + ['DLR', 'Digital Realty', 'US'], + ['DG', 'Dollar General', 'US'], + ['DLTR', 'Dollar Tree', 'US'], + ['D', 'Dominion Energy', 'US'], + ['DPZ', "Domino's", 'US'], + ['DASH', 'DoorDash', 'US'], + ['DOV', 'Dover Corporation', 'US'], + ['DOW', 'Dow Inc.', 'US'], + ['DHI', 'D. R. Horton', 'US'], + ['DTE', 'DTE Energy', 'US'], + ['DUK', 'Duke Energy', 'US'], + ['DD', 'DuPont', 'US'], + ['ETN', 'Eaton Corporation', 'US'], + ['EBAY', 'eBay Inc.', 'US'], + ['ECHO', 'EchoStar', 'US'], + ['ECL', 'Ecolab', 'US'], + ['EIX', 'Edison International', 'US'], + ['EW', 'Edwards Lifesciences', 'US'], + ['ELV', 'Elevance Health', 'US'], + ['EME', 'Emcor', 'US'], + ['EMR', 'Emerson Electric', 'US'], + ['ETR', 'Entergy', 'US'], + ['EOG', 'EOG Resources', 'US'], + ['EQT', 'EQT Corporation', 'US'], + ['EFX', 'Equifax', 'US'], + ['EQIX', 'Equinix', 'US'], + ['EQR', 'Equity Residential', 'US'], + ['ERIE', 'Erie Indemnity', 'US'], + ['ESS', 'Essex Property Trust', 'US'], + ['EL', 'Estée Lauder Companies (The)', 'US'], + ['EG', 'Everest Group', 'US'], + ['EVRG', 'Evergy', 'US'], + ['ES', 'Eversource Energy', 'US'], + ['EXC', 'Exelon', 'US'], + ['EXE', 'Expand Energy', 'US'], + ['EXPE', 'Expedia Group', 'US'], + ['EXPD', 'Expeditors International', 'US'], + ['EXR', 'Extra Space Storage', 'US'], + ['XOM', 'ExxonMobil', 'US'], + ['FFIV', 'F5, Inc.', 'US'], + ['FDS', 'FactSet', 'US'], + ['FICO', 'Fair Isaac', 'US'], + ['FAST', 'Fastenal', 'US'], + ['FRT', 'Federal Realty Investment Trust', 'US'], + ['FDX', 'FedEx', 'US'], + ['FDXF', 'FedEx Freight', 'US'], + ['FERG', 'Ferguson Enterprises', 'US'], + ['FIS', 'Fidelity National Information Services', 'US'], + ['FITB', 'Fifth Third Bancorp', 'US'], + ['FSLR', 'First Solar', 'US'], + ['FE', 'FirstEnergy', 'US'], + ['FISV', 'Fiserv', 'US'], + ['FLEX', 'Flex Ltd.', 'US'], + ['F', 'Ford Motor Company', 'US'], + ['FTNT', 'Fortinet', 'US'], + ['FTV', 'Fortive', 'US'], + ['FOXA', 'Fox Corporation (Class A)', 'US'], + ['FOX', 'Fox Corporation (Class B)', 'US'], + ['BEN', 'Franklin Resources', 'US'], + ['FCX', 'Freeport-McMoRan', 'US'], + ['GRMN', 'Garmin', 'US'], + ['IT', 'Gartner', 'US'], + ['GE', 'GE Aerospace', 'US'], + ['GEHC', 'GE HealthCare', 'US'], + ['GEV', 'GE Vernova', 'US'], + ['GEN', 'Gen Digital', 'US'], + ['GNRC', 'Generac', 'US'], + ['GD', 'General Dynamics', 'US'], + ['GIS', 'General Mills', 'US'], + ['GM', 'General Motors', 'US'], + ['GPC', 'Genuine Parts Company', 'US'], + ['GILD', 'Gilead Sciences', 'US'], + ['GPN', 'Global Payments', 'US'], + ['GL', 'Globe Life', 'US'], + ['GDDY', 'GoDaddy', 'US'], + ['GS', 'Goldman Sachs', 'US'], + ['HAL', 'Halliburton', 'US'], + ['HIG', 'Hartford (The)', 'US'], + ['HAS', 'Hasbro', 'US'], + ['HCA', 'HCA Healthcare', 'US'], + ['DOC', 'Healthpeak Properties', 'US'], + ['HSIC', 'Henry Schein', 'US'], + ['HSY', 'Hershey Company (The)', 'US'], + ['HPE', 'Hewlett Packard Enterprise', 'US'], + ['HLT', 'Hilton Worldwide', 'US'], + ['HD', 'Home Depot (The)', 'US'], + ['HONA', 'Honeywell Aerospace', 'US'], + ['HON', 'Honeywell Technologies', 'US'], + ['HRL', 'Hormel Foods', 'US'], + ['HST', 'Host Hotels & Resorts', 'US'], + ['HWM', 'Howmet Aerospace', 'US'], + ['HPQ', 'HP Inc.', 'US'], + ['HUBB', 'Hubbell Incorporated', 'US'], + ['HUM', 'Humana', 'US'], + ['HBAN', 'Huntington Bancshares', 'US'], + ['HII', 'Huntington Ingalls Industries', 'US'], + ['IBM', 'IBM', 'US'], + ['IEX', 'IDEX Corporation', 'US'], + ['IDXX', 'Idexx Laboratories', 'US'], + ['ITW', 'Illinois Tool Works', 'US'], + ['INCY', 'Incyte', 'US'], + ['IR', 'Ingersoll Rand', 'US'], + ['PODD', 'Insulet Corporation', 'US'], + ['INTC', 'Intel', 'US'], + ['IBKR', 'Interactive Brokers', 'US'], + ['ICE', 'Intercontinental Exchange', 'US'], + ['IFF', 'International Flavors & Fragrances', 'US'], + ['IP', 'International Paper', 'US'], + ['INTU', 'Intuit', 'US'], + ['ISRG', 'Intuitive Surgical', 'US'], + ['IVZ', 'Invesco', 'US'], + ['INVH', 'Invitation Homes', 'US'], + ['IQV', 'IQVIA', 'US'], + ['IRM', 'Iron Mountain', 'US'], + ['JBHT', 'J.B. Hunt', 'US'], + ['JBL', 'Jabil', 'US'], + ['JKHY', 'Jack Henry & Associates', 'US'], + ['J', 'Jacobs Solutions', 'US'], + ['JNJ', 'Johnson & Johnson', 'US'], + ['JCI', 'Johnson Controls', 'US'], + ['JPM', 'JPMorgan Chase', 'US'], + ['KVUE', 'Kenvue', 'US'], + ['KDP', 'Keurig Dr Pepper', 'US'], + ['KEY', 'KeyCorp', 'US'], + ['KEYS', 'Keysight Technologies', 'US'], + ['KMB', 'Kimberly-Clark', 'US'], + ['KIM', 'Kimco Realty', 'US'], + ['KMI', 'Kinder Morgan', 'US'], + ['KKR', 'KKR & Co.', 'US'], + ['KLAC', 'KLA Corporation', 'US'], + ['KHC', 'Kraft Heinz', 'US'], + ['KR', 'Kroger', 'US'], + ['LHX', 'L3Harris', 'US'], + ['LH', 'Labcorp', 'US'], + ['LRCX', 'Lam Research', 'US'], + ['LVS', 'Las Vegas Sands', 'US'], + ['LDOS', 'Leidos', 'US'], + ['LEN', 'Lennar', 'US'], + ['LII', 'Lennox International', 'US'], + ['LLY', 'Lilly (Eli)', 'US'], + ['LIN', 'Linde plc', 'US'], + ['LYV', 'Live Nation Entertainment', 'US'], + ['LMT', 'Lockheed Martin', 'US'], + ['L', 'Loews Corporation', 'US'], + ['LOW', "Lowe's", 'US'], + ['LULU', 'Lululemon Athletica', 'US'], + ['LITE', 'Lumentum', 'US'], + ['LYB', 'LyondellBasell', 'US'], + ['MTB', 'M&T Bank', 'US'], + ['MPC', 'Marathon Petroleum', 'US'], + ['MAR', 'Marriott International', 'US'], + ['MRSH', 'Marsh McLennan', 'US'], + ['MLM', 'Martin Marietta Materials', 'US'], + ['MRVL', 'Marvell Technology', 'US'], + ['MAS', 'Masco', 'US'], + ['MA', 'Mastercard', 'US'], + ['MKC', 'McCormick & Company', 'US'], + ['MCD', "McDonald's", 'US'], + ['MCK', 'McKesson Corporation', 'US'], + ['MDT', 'Medtronic', 'US'], + ['MRK', 'Merck & Co.', 'US'], + ['META', 'Meta Platforms', 'US'], + ['MET', 'MetLife', 'US'], + ['MTD', 'Mettler Toledo', 'US'], + ['MGM', 'MGM Resorts', 'US'], + ['MCHP', 'Microchip Technology', 'US'], + ['MU', 'Micron Technology', 'US'], + ['MSFT', 'Microsoft', 'US'], + ['MAA', 'Mid-America Apartment Communities', 'US'], + ['MRNA', 'Moderna', 'US'], + ['TAP', 'Molson Coors Beverage Company', 'US'], + ['MDLZ', 'Mondelez International', 'US'], + ['MPWR', 'Monolithic Power Systems', 'US'], + ['MNST', 'Monster Beverage', 'US'], + ['MCO', "Moody's Corporation", 'US'], + ['MS', 'Morgan Stanley', 'US'], + ['MOS', 'Mosaic Company (The)', 'US'], + ['MSI', 'Motorola Solutions', 'US'], + ['MSCI', 'MSCI', 'US'], + ['NDAQ', 'Nasdaq, Inc.', 'US'], + ['NTAP', 'NetApp', 'US'], + ['NFLX', 'Netflix', 'US'], + ['NEM', 'Newmont', 'US'], + ['NWSA', 'News Corp (Class A)', 'US'], + ['NWS', 'News Corp (Class B)', 'US'], + ['NEE', 'NextEra Energy', 'US'], + ['NKE', 'Nike, Inc.', 'US'], + ['NI', 'NiSource', 'US'], + ['NDSN', 'Nordson Corporation', 'US'], + ['NSC', 'Norfolk Southern', 'US'], + ['NTRS', 'Northern Trust', 'US'], + ['NOC', 'Northrop Grumman', 'US'], + ['NCLH', 'Norwegian Cruise Line Holdings', 'US'], + ['NRG', 'NRG Energy', 'US'], + ['NUE', 'Nucor', 'US'], + ['NVDA', 'Nvidia', 'US'], + ['NVR', 'NVR, Inc.', 'US'], + ['NXPI', 'NXP Semiconductors', 'US'], + ['ORLY', "O'Reilly Automotive", 'US'], + ['OXY', 'Occidental Petroleum', 'US'], + ['ODFL', 'Old Dominion', 'US'], + ['OMC', 'Omnicom Group', 'US'], + ['ON', 'ON Semiconductor', 'US'], + ['OKE', 'Oneok', 'US'], + ['ORCL', 'Oracle Corporation', 'US'], + ['OTIS', 'Otis Worldwide', 'US'], + ['PCAR', 'Paccar', 'US'], + ['PKG', 'Packaging Corporation of America', 'US'], + ['PLTR', 'Palantir Technologies', 'US'], + ['PANW', 'Palo Alto Networks', 'US'], + ['PSKY', 'Paramount Skydance Corporation', 'US'], + ['PH', 'Parker Hannifin', 'US'], + ['PAYX', 'Paychex', 'US'], + ['PYPL', 'PayPal', 'US'], + ['PNR', 'Pentair', 'US'], + ['PEP', 'PepsiCo', 'US'], + ['PFE', 'Pfizer', 'US'], + ['PCG', 'PG&E Corporation', 'US'], + ['PM', 'Philip Morris International', 'US'], + ['PSX', 'Phillips 66', 'US'], + ['PNW', 'Pinnacle West Capital', 'US'], + ['PNC', 'PNC Financial Services', 'US'], + ['PPG', 'PPG Industries', 'US'], + ['PPL', 'PPL Corporation', 'US'], + ['PFG', 'Principal Financial Group', 'US'], + ['PG', 'Procter & Gamble', 'US'], + ['PGR', 'Progressive Corporation', 'US'], + ['PLD', 'Prologis', 'US'], + ['PRU', 'Prudential Financial', 'US'], + ['PEG', 'Public Service Enterprise Group', 'US'], + ['PTC', 'PTC Inc.', 'US'], + ['PSA', 'Public Storage', 'US'], + ['PHM', 'PulteGroup', 'US'], + ['PWR', 'Quanta Services', 'US'], + ['QCOM', 'Qualcomm', 'US'], + ['DGX', 'Quest Diagnostics', 'US'], + ['Q', 'Qnity Electronics', 'US'], + ['RL', 'Ralph Lauren Corporation', 'US'], + ['RJF', 'Raymond James Financial', 'US'], + ['RTX', 'RTX Corporation', 'US'], + ['O', 'Realty Income', 'US'], + ['REG', 'Regency Centers', 'US'], + ['REGN', 'Regeneron Pharmaceuticals', 'US'], + ['RF', 'Regions Financial Corporation', 'US'], + ['RSG', 'Republic Services', 'US'], + ['RMD', 'ResMed|', 'US'], + ['RVTY', 'Revvity', 'US'], + ['HOOD', 'Robinhood Markets', 'US'], + ['ROK', 'Rockwell Automation', 'US'], + ['ROL', 'Rollins, Inc.', 'US'], + ['ROP', 'Roper Technologies', 'US'], + ['ROST', 'Ross Stores', 'US'], + ['RCL', 'Royal Caribbean Group', 'US'], + ['SPGI', 'S&P Global', 'US'], + ['CRM', 'Salesforce', 'US'], + ['SNDK', 'Sandisk', 'US'], + ['SBAC', 'SBA Communications', 'US'], + ['SLB', 'Schlumberger', 'US'], + ['STX', 'Seagate Technology', 'US'], + ['SRE', 'Sempra', 'US'], + ['NOW', 'ServiceNow', 'US'], + ['SHW', 'Sherwin-Williams', 'US'], + ['SPG', 'Simon Property Group', 'US'], + ['SWKS', 'Skyworks Solutions', 'US'], + ['SJM', 'J.M. Smucker Company (The)', 'US'], + ['SW', 'Smurfit Westrock', 'US'], + ['SNA', 'Snap-on', 'US'], + ['SOLV', 'Solventum', 'US'], + ['SO', 'Southern Company', 'US'], + ['LUV', 'Southwest Airlines', 'US'], + ['SWK', 'Stanley Black & Decker', 'US'], + ['SBUX', 'Starbucks', 'US'], + ['STT', 'State Street Corporation', 'US'], + ['STLD', 'Steel Dynamics', 'US'], + ['STE', 'Steris', 'US'], + ['SYK', 'Stryker Corporation', 'US'], + ['SMCI', 'Supermicro', 'US'], + ['SYF', 'Synchrony Financial', 'US'], + ['SNPS', 'Synopsys', 'US'], + ['SYY', 'Sysco', 'US'], + ['TMUS', 'T-Mobile US', 'US'], + ['TROW', 'T. Rowe Price', 'US'], + ['TTWO', 'Take-Two Interactive', 'US'], + ['TPR', 'Tapestry, Inc.', 'US'], + ['TRGP', 'Targa Resources', 'US'], + ['TGT', 'Target Corporation', 'US'], + ['TEL', 'TE Connectivity', 'US'], + ['TDY', 'Teledyne Technologies', 'US'], + ['TER', 'Teradyne', 'US'], + ['TSLA', 'Tesla, Inc.', 'US'], + ['TXN', 'Texas Instruments', 'US'], + ['TPL', 'Texas Pacific Land Corporation', 'US'], + ['TXT', 'Textron', 'US'], + ['TMO', 'Thermo Fisher Scientific', 'US'], + ['TJX', 'TJX Companies', 'US'], + ['TKO', 'TKO Group Holdings', 'US'], + ['TTD', 'Trade Desk (The)', 'US'], + ['TSCO', 'Tractor Supply', 'US'], + ['TT', 'Trane Technologies', 'US'], + ['TDG', 'TransDigm Group', 'US'], + ['TRV', 'Travelers Companies (The)', 'US'], + ['TRMB', 'Trimble Inc.', 'US'], + ['TFC', 'Truist Financial', 'US'], + ['TYL', 'Tyler Technologies', 'US'], + ['TSN', 'Tyson Foods', 'US'], + ['USB', 'U.S. Bancorp', 'US'], + ['UBER', 'Uber', 'US'], + ['UDR', 'UDR, Inc.', 'US'], + ['ULTA', 'Ulta Beauty', 'US'], + ['UNP', 'Union Pacific Corporation', 'US'], + ['UAL', 'United Airlines Holdings', 'US'], + ['UPS', 'United Parcel Service', 'US'], + ['URI', 'United Rentals', 'US'], + ['UNH', 'UnitedHealth Group', 'US'], + ['UHS', 'Universal Health Services', 'US'], + ['VLO', 'Valero Energy', 'US'], + ['VEEV', 'Veeva Systems', 'US'], + ['VTR', 'Ventas', 'US'], + ['VLTO', 'Veralto', 'US'], + ['VRSN', 'Verisign', 'US'], + ['VRSK', 'Verisk Analytics', 'US'], + ['VZ', 'Verizon', 'US'], + ['VRTX', 'Vertex Pharmaceuticals', 'US'], + ['VRT', 'Vertiv', 'US'], + ['VTRS', 'Viatris', 'US'], + ['VICI', 'Vici Properties', 'US'], + ['V', 'Visa Inc.', 'US'], + ['VST', 'Vistra Corp.', 'US'], + ['VMC', 'Vulcan Materials Company', 'US'], + ['WRB', 'W. R. Berkley Corporation', 'US'], + ['GWW', 'W. W. Grainger', 'US'], + ['WAB', 'Wabtec', 'US'], + ['WMT', 'Walmart', 'US'], + ['DIS', 'Walt Disney Company (The)', 'US'], + ['WBD', 'Warner Bros. Discovery', 'US'], + ['WM', 'Waste Management', 'US'], + ['WAT', 'Waters Corporation', 'US'], + ['WEC', 'WEC Energy Group', 'US'], + ['WFC', 'Wells Fargo', 'US'], + ['WELL', 'Welltower', 'US'], + ['WST', 'West Pharmaceutical Services', 'US'], + ['WDC', 'Western Digital', 'US'], + ['WY', 'Weyerhaeuser', 'US'], + ['WSM', 'Williams-Sonoma, Inc.', 'US'], + ['WMB', 'Williams Companies', 'US'], + ['WTW', 'Willis Towers Watson', 'US'], + ['WDAY', 'Workday, Inc.', 'US'], + ['WYNN', 'Wynn Resorts', 'US'], + ['XEL', 'Xcel Energy', 'US'], + ['XYL', 'Xylem Inc.', 'US'], + ['YUM', 'Yum! Brands', 'US'], + ['ZBRA', 'Zebra Technologies', 'US'], + ['ZBH', 'Zimmer Biomet', 'US'], + ['ZTS', 'Zoetis', 'US'], +]) + +/** + * Representative liquid international listings used to diversify the fixture. + * Symbols use their local-market form and the third tuple value is an ISO-style + * country/market code, rather than a trading currency or exchange MIC. + * + * References checked 2026-08-15: STOXX Europe 50, KRX KOSPI market, + * JPX TOPIX Core30, and HKEX index constituent materials. + */ +const europeanInstruments = Object.freeze([ + ['ASML', 'ASML Holding', 'NL'], + ['INGA', 'ING Group', 'NL'], + ['ADYEN', 'Adyen', 'NL'], + ['PHIA', 'Philips', 'NL'], + ['HEIA', 'Heineken', 'NL'], + ['SAP', 'SAP', 'DE'], + ['SIE', 'Siemens', 'DE'], + ['ALV', 'Allianz', 'DE'], + ['DTE', 'Deutsche Telekom', 'DE'], + ['MBG', 'Mercedes-Benz Group', 'DE'], + ['BMW', 'BMW', 'DE'], + ['BAS', 'BASF', 'DE'], + ['MUV2', 'Munich Re', 'DE'], + ['VOW3', 'Volkswagen Preference', 'DE'], + ['IFX', 'Infineon Technologies', 'DE'], + ['MC', 'LVMH', 'FR'], + ['OR', "L'Oréal", 'FR'], + ['AIR', 'Airbus', 'FR'], + ['SU', 'Schneider Electric', 'FR'], + ['TTE', 'TotalEnergies', 'FR'], + ['SAN', 'Sanofi', 'FR'], + ['BNP', 'BNP Paribas', 'FR'], + ['CS', 'AXA', 'FR'], + ['DG', 'Vinci', 'FR'], + ['ENEL', 'Enel', 'IT'], + ['ENI', 'Eni', 'IT'], + ['ISP', 'Intesa Sanpaolo', 'IT'], + ['UCG', 'UniCredit', 'IT'], + ['STLAM', 'Stellantis', 'IT'], + ['SAN', 'Banco Santander', 'ES'], + ['IBE', 'Iberdrola', 'ES'], + ['ITX', 'Inditex', 'ES'], + ['BBVA', 'BBVA', 'ES'], + ['NESN', 'Nestlé', 'CH'], + ['ROG', 'Roche Holding', 'CH'], + ['NOVN', 'Novartis', 'CH'], + ['UBSG', 'UBS Group', 'CH'], + ['NOVO-B', 'Novo Nordisk', 'DK'], + ['MAERSK-B', 'A.P. Moller - Maersk', 'DK'], + ['VOLV-B', 'Volvo', 'SE'], + ['ERIC-B', 'Ericsson', 'SE'], + ['NOKIA', 'Nokia', 'FI'], + ['SHEL', 'Shell', 'GB'], + ['AZN', 'AstraZeneca', 'GB'], + ['HSBA', 'HSBC Holdings', 'GB'], + ['ULVR', 'Unilever', 'GB'], + ['LSEG', 'London Stock Exchange Group', 'GB'], +]) + +const europeanMarketCodes = Object.freeze([ + 'NL', + 'DE', + 'FR', + 'IT', + 'ES', + 'CH', + 'DK', + 'SE', + 'FI', + 'GB', +]) + +const europeanMarketGroups = Object.freeze( + europeanMarketCodes.map((market) => + europeanInstruments.filter(([, , instrumentMarket]) => + Object.is(instrumentMarket, market), + ), + ), +) + +const interleavedEuropeanInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...europeanMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + europeanMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const southKoreanInstruments = Object.freeze([ + ['005930', 'Samsung Electronics', 'KR'], + ['000660', 'SK hynix', 'KR'], + ['373220', 'LG Energy Solution', 'KR'], + ['207940', 'Samsung Biologics', 'KR'], + ['005380', 'Hyundai Motor', 'KR'], + ['000270', 'Kia', 'KR'], + ['068270', 'Celltrion', 'KR'], + ['105560', 'KB Financial Group', 'KR'], + ['055550', 'Shinhan Financial Group', 'KR'], + ['035420', 'NAVER', 'KR'], + ['035720', 'Kakao', 'KR'], + ['006400', 'Samsung SDI', 'KR'], + ['051910', 'LG Chem', 'KR'], + ['012330', 'Hyundai Mobis', 'KR'], + ['066570', 'LG Electronics', 'KR'], +]) + +const japaneseInstruments = Object.freeze([ + ['8306', 'Mitsubishi UFJ Financial Group', 'JP'], + ['7203', 'Toyota Motor', 'JP'], + ['6501', 'Hitachi', 'JP'], + ['8316', 'Sumitomo Mitsui Financial Group', 'JP'], + ['6758', 'Sony Group', 'JP'], + ['8058', 'Mitsubishi Corporation', 'JP'], + ['9984', 'SoftBank Group', 'JP'], + ['8035', 'Tokyo Electron', 'JP'], + ['8411', 'Mizuho Financial Group', 'JP'], + ['8031', 'Mitsui & Co.', 'JP'], + ['6861', 'Keyence', 'JP'], + ['7974', 'Nintendo', 'JP'], + ['6098', 'Recruit Holdings', 'JP'], + ['9432', 'Nippon Telegraph and Telephone', 'JP'], + ['4063', 'Shin-Etsu Chemical', 'JP'], +]) + +const hongKongInstruments = Object.freeze([ + ['0700', 'Tencent Holdings', 'HK'], + ['9988', 'Alibaba Group', 'HK'], + ['1810', 'Xiaomi', 'HK'], + ['3690', 'Meituan', 'HK'], + ['0941', 'China Mobile', 'HK'], + ['1211', 'BYD Company', 'HK'], + ['1299', 'AIA Group', 'HK'], + ['0388', 'Hong Kong Exchanges and Clearing', 'HK'], + ['0005', 'HSBC Holdings', 'HK'], + ['2318', 'Ping An Insurance', 'HK'], +]) + +const canadianInstruments = Object.freeze([ + ['RY', 'Royal Bank of Canada', 'CA'], + ['TD', 'Toronto-Dominion Bank', 'CA'], + ['SHOP', 'Shopify', 'CA'], + ['ENB', 'Enbridge', 'CA'], + ['CNR', 'Canadian National Railway', 'CA'], + ['CP', 'Canadian Pacific Kansas City', 'CA'], + ['BMO', 'Bank of Montreal', 'CA'], + ['CSU', 'Constellation Software', 'CA'], +]) + +const australianInstruments = Object.freeze([ + ['BHP', 'BHP Group', 'AU'], + ['CBA', 'Commonwealth Bank of Australia', 'AU'], + ['CSL', 'CSL', 'AU'], + ['NAB', 'National Australia Bank', 'AU'], + ['WBC', 'Westpac Banking Corporation', 'AU'], + ['ANZ', 'ANZ Group Holdings', 'AU'], + ['WES', 'Wesfarmers', 'AU'], + ['MQG', 'Macquarie Group', 'AU'], +]) + +const internationalMarketGroups = Object.freeze([ + interleavedEuropeanInstruments, + southKoreanInstruments, + japaneseInstruments, + hongKongInstruments, + canadianInstruments, + australianInstruments, +]) + +export const internationalInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...internationalMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + internationalMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const INTERNATIONAL_INSERTION_INTERVAL = 3 + +/** + * U.S. and international instruments are interleaved so ordinary benchmark + * sizes exercise multiple symbol formats and market labels. + */ +export const globalInstruments = Object.freeze( + marketInstruments.flatMap((instrument, index) => { + const internationalInstrument = + index % INTERNATIONAL_INSERTION_INTERVAL === 0 + ? internationalInstruments[index / INTERNATIONAL_INSERTION_INTERVAL] + : undefined + + return internationalInstrument + ? [instrument, internationalInstrument] + : [instrument] + }), +) as unknown as ReadonlyArray diff --git a/examples/alpine/realtime-trading/src/feed/worker/market-feed-engine.ts b/examples/alpine/realtime-trading/src/feed/worker/market-feed-engine.ts new file mode 100644 index 0000000000..fbd9c369c0 --- /dev/null +++ b/examples/alpine/realtime-trading/src/feed/worker/market-feed-engine.ts @@ -0,0 +1,177 @@ +import { globalInstruments } from '../market-instruments.ts' +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const INITIAL_MARKET_SEED = 0x4d41524b +const LIVE_FEED_SEED = 0x5449434b + +export class MarketFeedEngine { + #quotes: Array = [] + #lastHistorySampledAt = new Uint32Array(0) + #random = createRandom(2_026) + #rowCursor = 0 + #tickIndex = 0 + + reset(count: number): Array { + const random = createRandom(INITIAL_MARKET_SEED ^ count) + const createdAt = Date.now() + + this.#quotes = Array.from({ length: count }, (_, index) => { + const [baseSymbol, company, market] = + globalInstruments[index % globalInstruments.length] + const series = Math.floor(index / globalInstruments.length) + const symbol = series === 0 ? baseSymbol : `${baseSymbol}${series}` + const previousClose = roundPrice(20 + random() * 480) + const open = roundPrice(previousClose * (1 + (random() - 0.5) * 0.016)) + const spread = Math.max(0.01, open * (0.0002 + random() * 0.0004)) + const history = Array.from({ length: 24 }, (_, historyIndex) => + roundPrice( + open * + (1 + Math.sin(historyIndex / 4) * 0.002 + (random() - 0.5) * 0.001), + ), + ) + const volume = Math.floor(50_000 + random() * 2_000_000) + const lastSize = Math.floor(10 + random() * 5_000) + + return { + id: `instrument-${index}`, + symbol, + company, + venue: market, + previousClose, + open, + high: open, + low: open, + price: open, + bid: roundPrice(open - spread / 2), + ask: roundPrice(open + spread / 2), + bidSize: Math.floor(100 + random() * 25_000), + askSize: Math.floor(100 + random() * 25_000), + lastSize, + lastMove: 0, + lastUpdatedAt: createdAt, + volume, + turnover: roundMoney(open * volume), + history, + } + }) + + this.#random = createRandom(LIVE_FEED_SEED ^ count) + this.#rowCursor = 0 + this.#lastHistorySampledAt = new Uint32Array(count) + this.#lastHistorySampledAt.fill(createdAt >>> 0) + + return this.#quotes.map((quote) => ({ + ...quote, + history: [...quote.history], + })) + } + + applyTicks( + tickCount: number, + updateSparklines: boolean, + sparklineSampleIntervalMs: number, + ): Array { + if (this.#quotes.length === 0 || tickCount <= 0) return [] + + const updatedAt = Date.now() + const sampledAt = updatedAt >>> 0 + const sampleIntervalMs = Math.max(16, sparklineSampleIntervalMs) + const updatedQuotes = new Map() + const stride = 97 + + this.#tickIndex = 0 + while (this.#tickIndex < tickCount) { + this.#rowCursor = (this.#rowCursor + stride) % this.#quotes.length + const quote = this.#quotes[this.#rowCursor] + const lastSampledAt = this.#lastHistorySampledAt[this.#rowCursor] + const shouldUpdateHistory = + updateSparklines && + (sampledAt - lastSampledAt) >>> 0 >= sampleIntervalMs + + if (shouldUpdateHistory) { + this.#lastHistorySampledAt[this.#rowCursor] = sampledAt + } + + this.#applyTick(quote, shouldUpdateHistory, updatedAt) + + const previousUpdate = updatedQuotes.get(this.#rowCursor) + updatedQuotes.set(this.#rowCursor, { + index: this.#rowCursor, + price: quote.price, + bid: quote.bid, + ask: quote.ask, + bidSize: quote.bidSize, + askSize: quote.askSize, + lastSize: quote.lastSize, + lastMove: quote.lastMove, + lastUpdatedAt: quote.lastUpdatedAt, + high: quote.high, + low: quote.low, + volume: quote.volume, + turnover: quote.turnover, + ...(shouldUpdateHistory || previousUpdate?.history + ? { history: [...quote.history] } + : {}), + }) + this.#tickIndex++ + } + + return [...updatedQuotes.values()] + } + + #applyTick( + quote: MarketQuoteSnapshot, + updateHistory: boolean, + updatedAt: number, + ): void { + const previousPrice = quote.price + const volatility = 0.00015 + this.#random() * 0.0012 + const move = previousPrice * (this.#random() - 0.495) * volatility + const nextPrice = roundPrice(Math.max(0.1, previousPrice + move)) + const spread = Math.max( + 0.01, + nextPrice * (0.00015 + this.#random() * 0.0005), + ) + + quote.lastMove = nextPrice - previousPrice + quote.price = nextPrice + quote.high = Math.max(quote.high, nextPrice) + quote.low = Math.min(quote.low, nextPrice) + quote.bid = roundPrice(nextPrice - spread / 2) + quote.ask = roundPrice(nextPrice + spread / 2) + quote.bidSize = Math.floor(100 + this.#random() * 25_000) + quote.askSize = Math.floor(100 + this.#random() * 25_000) + quote.lastSize = Math.floor(10 + this.#random() * 5_000) + quote.lastUpdatedAt = updatedAt + quote.volume += quote.lastSize + quote.turnover = roundMoney(quote.turnover + nextPrice * quote.lastSize) + + if (updateHistory) { + quote.history = [...quote.history.slice(-23), nextPrice] + } + } +} + +function createRandom(seed: number): () => number { + const runtime = { state: seed >>> 0 } + return () => { + runtime.state += 0x6d2b79f5 + const stateValue = runtime.state + const firstMix = Math.imul(stateValue ^ (stateValue >>> 15), stateValue | 1) + const secondMix = + firstMix + Math.imul(firstMix ^ (firstMix >>> 7), firstMix | 61) + const value = firstMix ^ secondMix + return ((value ^ (value >>> 14)) >>> 0) / 4_294_967_296 + } +} + +function roundPrice(value: number): number { + return Math.round(value * 100) / 100 +} + +function roundMoney(value: number): number { + return Math.round(value * 100) / 100 +} diff --git a/examples/alpine/realtime-trading/src/feed/worker/market-feed-protocol.ts b/examples/alpine/realtime-trading/src/feed/worker/market-feed-protocol.ts new file mode 100644 index 0000000000..21997ec89c --- /dev/null +++ b/examples/alpine/realtime-trading/src/feed/worker/market-feed-protocol.ts @@ -0,0 +1,70 @@ +export interface MarketQuoteSnapshot { + id: string + symbol: string + company: string + venue: string + previousClose: number + open: number + high: number + low: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + volume: number + turnover: number + history: Array +} + +export interface MarketQuoteUpdate { + index: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + high: number + low: number + volume: number + turnover: number + history?: Array +} + +export type MarketFeedCommand = + | { + type: 'start' + rowCount: number + running: boolean + ticksPerSecond: number + publishIntervalMs: number + updateSparklines: boolean + sparklineSampleIntervalMs: number + } + | { type: 'set-running'; running: boolean } + | { type: 'set-rate'; ticksPerSecond: number } + | { type: 'set-publish-interval'; intervalMs: number } + | { type: 'set-sparklines'; enabled: boolean } + | { type: 'set-sparkline-interval'; intervalMs: number } + | { type: 'reset'; rowCount: number } + | { type: 'burst'; tickCount: number } + +export type MarketFeedEvent = + | { + type: 'snapshot' + sessionId: number + quotes: Array + } + | { + type: 'updates' + sessionId: number + tickCount: number + coalescedUpdateCount: number + updates: Array + } diff --git a/examples/alpine/realtime-trading/src/feed/worker/market-feed.worker.ts b/examples/alpine/realtime-trading/src/feed/worker/market-feed.worker.ts new file mode 100644 index 0000000000..2b7a642fd9 --- /dev/null +++ b/examples/alpine/realtime-trading/src/feed/worker/market-feed.worker.ts @@ -0,0 +1,143 @@ +import { initialMarketFeedConfig } from '../market-feed-config' +import { MarketFeedEngine } from './market-feed-engine' +import type { + MarketFeedCommand, + MarketFeedEvent, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const engine = new MarketFeedEngine() +const pendingUpdates = new Map() +const runtime = { + sessionId: 0, + pendingTickCount: 0, + pendingCoalescedUpdateCount: 0, + initialized: false, + running: true, + ticksPerSecond: initialMarketFeedConfig.targetSamplesPerSecond, + publishIntervalMs: initialMarketFeedConfig.publishIntervalMs, + publishTimerId: null as ReturnType | null, + updateSparklines: initialMarketFeedConfig.updateSparklines, + sparklineSampleIntervalMs: initialMarketFeedConfig.sparklineSampleIntervalMs, + tickBudget: 0, + lastTickAt: performance.now(), +} + +addEventListener('message', ({ data }: MessageEvent) => { + switch (data.type) { + case 'start': + runtime.running = data.running + runtime.ticksPerSecond = data.ticksPerSecond + runtime.publishIntervalMs = data.publishIntervalMs + runtime.updateSparklines = data.updateSparklines + runtime.sparklineSampleIntervalMs = data.sparklineSampleIntervalMs + restartPublishTimer() + reset(data.rowCount) + break + case 'set-running': + runtime.running = data.running + break + case 'set-rate': + runtime.ticksPerSecond = data.ticksPerSecond + break + case 'set-publish-interval': + runtime.publishIntervalMs = Math.max(4, data.intervalMs) + restartPublishTimer() + break + case 'set-sparklines': + runtime.updateSparklines = data.enabled + break + case 'set-sparkline-interval': + runtime.sparklineSampleIntervalMs = Math.max(16, data.intervalMs) + break + case 'reset': + reset(data.rowCount) + break + case 'burst': + produceTicks(data.tickCount) + flush() + break + } +}) + +setInterval(() => { + const now = performance.now() + const elapsed = Math.min(100, Math.max(0, now - runtime.lastTickAt)) + runtime.lastTickAt = now + + if (runtime.initialized && runtime.running) { + runtime.tickBudget += (runtime.ticksPerSecond * elapsed) / 1_000 + const tickCount = Math.floor(runtime.tickBudget) + runtime.tickBudget -= tickCount + produceTicks(tickCount) + } +}, 16) + +restartPublishTimer() + +function reset(rowCount: number): void { + runtime.initialized = true + runtime.sessionId++ + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + runtime.tickBudget = 0 + runtime.lastTickAt = performance.now() + + post({ + type: 'snapshot', + sessionId: runtime.sessionId, + quotes: engine.reset(rowCount), + }) +} + +function produceTicks(tickCount: number): void { + if (!runtime.initialized || tickCount <= 0) return + + runtime.pendingTickCount += tickCount + for (const update of engine.applyTicks( + tickCount, + runtime.updateSparklines, + runtime.sparklineSampleIntervalMs, + )) { + const previousUpdate = pendingUpdates.get(update.index) + if (previousUpdate) runtime.pendingCoalescedUpdateCount++ + pendingUpdates.set(update.index, { + ...update, + ...(update.history || !previousUpdate?.history + ? {} + : { history: previousUpdate.history }), + }) + } +} + +function flush(): void { + if (runtime.pendingTickCount === 0) return + + const message: MarketFeedEvent = { + type: 'updates', + sessionId: runtime.sessionId, + tickCount: runtime.pendingTickCount, + coalescedUpdateCount: runtime.pendingCoalescedUpdateCount, + updates: [...pendingUpdates.values()], + } + + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + post(message) +} + +function restartPublishTimer(): void { + if (runtime.publishTimerId !== null) { + clearInterval(runtime.publishTimerId) + } + runtime.publishTimerId = setInterval( + flush, + Math.max(4, runtime.publishIntervalMs), + ) +} + +function post(event: MarketFeedEvent): void { + postMessage(event) +} diff --git a/examples/alpine/realtime-trading/src/index.css b/examples/alpine/realtime-trading/src/index.css new file mode 100644 index 0000000000..7f670c5626 --- /dev/null +++ b/examples/alpine/realtime-trading/src/index.css @@ -0,0 +1,1007 @@ +:root { + color-scheme: dark; + --font-ui: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + 'Segoe UI', sans-serif; + --font-mono: 'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace; + font-family: var(--font-ui); + font-synthesis: none; + --background: #050505; + --panel: #080808; + --panel-raised: #111111; + --panel-hover: #181818; + --surface-bar: #080808; + --surface-toolbar: #0d0d0d; + --surface-table: #050505; + --surface-header: #101010; + --surface-control: #151515; + --border: #303030; + --border-soft: #242424; + --border-strong: #4a4a4a; + --text: #e7ebf0; + --text-strong: #ffffff; + --text-inverse: #f7f9fb; + --muted: #737982; + --blue: #62a9ff; + --blue-soft: #a9d0ff; + --green: #42e488; + --red: #ff646b; + --amber: #dfb465; + --depth-bid: #315774; + --depth-ask: #634049; + --row-alt: rgb(255 255 255 / 1.8%); + --row-selected: rgb(66 132 214 / 16%); + --control-border: #354456; + --control-hover: #192431; + --sidebar-width: 18rem; + --shell-bar-height: 2.625rem; + --metrics-height: 3.5rem; + --statusbar-height: 1.625rem; + --table-header-height: 2rem; + --table-row-height: 2rem; + --shell-inline-padding: 0.75rem; + --table-cell-inline-padding: 0.6rem; + --control-radius: 1px; +} + +* { + box-sizing: border-box; +} + +html, +body { + min-width: 320px; + min-height: 100%; + margin: 0; + background: var(--background); +} + +body { + color: var(--text); +} + +button, +select, +input { + font: inherit; +} + +button, +select { + color: var(--text); + background: var(--panel-raised); + border: 1px solid var(--control-border); + border-radius: var(--control-radius); +} + +button { + padding: 0.5rem 0.65rem; + cursor: pointer; + font-size: 0.72rem; + font-weight: 650; + letter-spacing: 0.025em; +} + +button:hover { + background: var(--control-hover); + border-color: var(--border-strong); +} + +button:focus-visible, +select:focus-visible, +input:focus-visible { + outline: 1px solid var(--blue); + outline-offset: 1px; +} + +select { + width: 100%; + padding: 0.45rem 0.55rem; + font-size: 0.75rem; +} + +.trading-terminal { + --active-sidebar-width: var(--sidebar-width); + display: grid; + width: 100%; + height: 100dvh; + min-height: 0; + overflow: hidden; + background: var(--background); + grid-template-areas: + 'header sidebar' + 'content sidebar' + 'footer sidebar'; + grid-template-columns: minmax(0, 1fr) var(--active-sidebar-width); + grid-template-rows: auto minmax(0, 1fr) auto; + transition: grid-template-columns 160ms ease; +} + +.trading-terminal.is-sidebar-collapsed { + --active-sidebar-width: 0px; +} + +.shell-header { + display: flex; + min-width: 0; + flex-direction: column; + grid-area: header; +} + +.app-bar { + display: flex; + min-height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + background: var(--surface-bar); + border-bottom: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.68rem; + letter-spacing: 0.045em; +} + +.brand, +.header-actions, +.feed-status { + display: flex; + align-items: center; +} + +.brand { + gap: 0.65rem; + color: var(--text-strong); +} + +.header-actions { + gap: 0.75rem; +} + +.sidebar-toggle { + display: grid; + width: 1.9rem; + height: 1.9rem; + padding: 0; + place-items: center; + color: var(--muted); + background: transparent; + border-color: transparent; +} + +.sidebar-toggle:hover { + color: var(--text-strong); + background: var(--surface-control); + border-color: var(--border); +} + +.sidebar-toggle svg { + width: 1rem; + height: 1rem; + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-width: 1.4; +} + +.feed-status { + gap: 0.4rem; + color: var(--muted); +} + +.feed-status.is-running { + color: var(--green); +} + +.status-dot { + width: 6px; + height: 6px; + background: var(--muted); + border-radius: 50%; +} + +.feed-status.is-running .status-dot { + background: var(--green); +} + +.development-warning { + flex: 0 0 auto; + padding: 0.3rem 0.75rem; + color: var(--amber); + background: color-mix(in srgb, var(--amber) 8%, var(--background)); + border-bottom: 1px solid color-mix(in srgb, var(--amber) 24%, var(--border)); + font-family: var(--font-mono); + font-size: 0.62rem; + letter-spacing: 0.04em; +} + +.market-panel { + display: flex; + min-width: 0; + min-height: 0; + flex-direction: column; + background: var(--panel); + grid-area: content; +} + +.metrics-strip { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + background: var(--border); + border-bottom: 1px solid var(--border); + gap: 1px; +} + +.metrics-strip h2 { + margin: 0; + padding: 0.65rem var(--shell-inline-padding) 0.45rem; + color: var(--muted); + background: var(--surface-table); + font-size: 0.58rem; + grid-column: 1 / -1; + letter-spacing: 0.075em; +} + +.metrics-strip article { + min-width: 0; + min-height: 4.25rem; + padding: 0.5rem var(--shell-inline-padding); + background: var(--surface-bar); +} + +.metrics-strip span, +.metrics-strip small { + display: block; + color: var(--muted); + font-size: 0.56rem; + letter-spacing: 0.045em; + line-height: 1.35; +} + +.metrics-strip strong { + display: block; + margin: 0.12rem 0 0.08rem; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.88rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +.metrics-strip strong.metric-alert { + color: var(--amber); +} + +.table-scroll { + flex: 1; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +table { + min-width: 100%; + border-spacing: 0; + table-layout: fixed; + font-family: var(--font-ui); + font-size: 0.78rem; + font-variant-numeric: tabular-nums; +} + +.trading-data-grid { + display: grid; +} + +.trading-data-grid thead, +.trading-data-grid tbody { + display: grid; +} + +.trading-data-grid tbody { + -webkit-user-select: none; + user-select: none; +} + +.trading-data-grid thead > tr, +.trading-data-grid tbody > tr { + display: flex; + width: 100%; +} + +.trading-data-grid tbody > tr { + min-height: var(--table-row-height); + content-visibility: auto; + contain-intrinsic-block-size: var(--table-row-height); +} + +.trading-data-grid th, +.trading-data-grid td { + flex: 0 0 auto; +} + +thead { + position: sticky; + z-index: 2; + top: 0; +} + +th { + height: var(--table-header-height); + padding: 0 var(--table-cell-inline-padding); + color: var(--muted); + background: var(--surface-header); + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border); + font-size: 0.7rem; + font-weight: 500; + letter-spacing: 0.005em; + text-align: left; + white-space: nowrap; +} + +th.column-group-header { + color: #666b72; + font-size: 0.72rem; + font-weight: 500; + text-align: center; +} + +thead tr:first-child th.column-group-header { + color: #777d85; + font-size: 0.76rem; +} + +th.numeric-header { + text-align: right; +} + +td { + height: var(--table-row-height); + padding: 0 var(--table-cell-inline-padding); + overflow: hidden; + color: #eef1f5; + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border-soft); + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +th:last-child, +td:last-child { + border-right: 0; +} + +td[data-column-id='market'], +td[data-column-id='name'], +td[data-column-id='symbol'] { + text-align: left; +} + +td[data-column-id='market'] { + color: var(--blue); + font-weight: 550; +} + +td[data-column-id='name'] { + color: var(--text-strong); +} + +td[data-column-id='symbol'] { + color: #d8dde4; + font-weight: 600; +} + +tbody tr:nth-child(even) { + background: var(--row-alt); +} + +tbody tr:hover { + background: var(--panel-hover); +} + +tbody tr[data-symbol-selected='true'] { + background: var(--row-selected); + box-shadow: inset 2px 0 0 var(--blue); +} + +.table-scroll:focus { + outline: none; +} + +th { + position: relative; +} + +.leaf-header-content { + display: flex; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + height: 100%; + align-items: stretch; + margin-inline: calc(-1 * var(--table-cell-inline-padding)); +} + +.column-drag-handle, +.sort-header-button { + min-width: 0; + height: 100%; + padding: 0; + color: inherit; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-weight: inherit; + letter-spacing: inherit; +} + +.column-drag-handle { + flex: 0 0 1.05rem; + color: var(--muted); + cursor: grab; + opacity: 0.35; + font-size: 0.56rem; + letter-spacing: -0.32rem; + text-align: center; +} + +.column-drag-handle:active { + cursor: grabbing; +} + +th:hover .column-drag-handle, +.column-drag-handle:focus-visible { + opacity: 0.9; +} + +.column-drag-handle:hover, +.sort-header-button:hover { + background: rgb(255 255 255 / 4%); + border-color: transparent; +} + +th.is-column-dragging { + opacity: 0.45; +} + +th.is-column-drop-target { + background: rgb(50 139 255 / 16%); + box-shadow: inset 4px 0 0 var(--blue); +} + +th.is-column-drop-target::before { + position: absolute; + z-index: 6; + top: -1px; + bottom: -1px; + left: -2px; + width: 4px; + background: #62a9ff; + box-shadow: + 0 0 0 1px rgb(0 0 0 / 55%), + 0 0 12px rgb(70 151 255 / 90%); + content: ''; + pointer-events: none; +} + +.sort-header-button { + display: flex; + min-width: 0; + flex: 1; + align-items: center; + justify-content: flex-start; + gap: 0.3rem; + padding-inline: 0.25rem var(--table-cell-inline-padding); + cursor: default; + text-align: inherit; +} + +.numeric-header .sort-header-button { + justify-content: flex-end; +} + +.sort-header-button.is-sortable { + cursor: pointer; +} + +.sort-header-button:disabled { + opacity: 1; +} + +.header-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.sort-indicator { + flex: 0 0 auto; + color: #66717e; + font-size: 0.72rem; +} + +.sort-indicator.is-active { + color: var(--blue-soft); +} + +.column-resize-handle { + position: absolute; + z-index: 3; + top: 0; + right: -3px; + width: 7px; + height: 100%; + cursor: col-resize; + touch-action: none; + user-select: none; +} + +.column-resize-handle::after { + position: absolute; + top: 20%; + right: 3px; + width: 1px; + height: 60%; + background: var(--border-strong); + content: ''; + opacity: 0; +} + +th:hover > .column-resize-handle::after, +.column-resize-handle.is-resizing::after { + background: var(--blue); + opacity: 1; +} + +tbody tr[aria-selected='true'] { + background: rgb(76 145 228 / 13%); +} + +td[aria-selected='true'] { + position: relative; + background: rgb(70 139 222 / 12%); +} + +td[data-cell-focused='true'] { + background: rgb(70 139 222 / 21%); +} + +td[aria-selected='true']::after { + position: absolute; + z-index: 1; + inset: 0; + border: 1px solid transparent; + content: ''; + pointer-events: none; +} + +td[data-selection-top='true']::after { + border-top-color: var(--blue); +} + +td[data-selection-right='true']::after { + border-right-color: var(--blue); +} + +td[data-selection-bottom='true']::after { + border-bottom-color: var(--blue); +} + +td[data-selection-left='true']::after { + border-left-color: var(--blue); +} + +.price-button { + min-width: 4.5rem; + padding: 0; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-variant-numeric: tabular-nums; + font-weight: 600; + text-align: right; +} + +.price-button:hover { + background: transparent; + text-decoration: underline; + text-underline-offset: 2px; +} + +.move-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.move-cell.quote-up, +.percent-change-cell.quote-up { + background: color-mix(in srgb, var(--green) 7%, transparent); +} + +.move-cell.quote-down, +.percent-change-cell.quote-down { + background: color-mix(in srgb, var(--red) 7%, transparent); +} + +.percent-change-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.spread-cell { + display: flex; + align-items: baseline; + justify-content: flex-end; + gap: 0.35rem; + color: var(--text); +} + +.spread-cell small { + min-width: 2.8rem; + color: var(--muted); + font-size: 0.55rem; +} + +.spread-cell.spread-wide, +.spread-cell.spread-wide small { + color: var(--amber); +} + +.depth-cell { + position: relative; + display: flex; + height: 17px; + overflow: hidden; + background: var(--surface-control); +} + +.depth-bid, +.depth-ask { + height: 100%; + opacity: 0.78; +} + +.depth-bid { + background: var(--depth-bid); + border-right: 1px solid var(--panel); +} + +.depth-ask { + background: var(--depth-ask); +} + +.depth-values { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 0.28rem; + color: var(--text-strong); + font-size: 0.57rem; + text-shadow: 0 1px var(--background); +} + +.quote-age { + color: var(--muted); +} + +.quote-age-warm { + color: var(--amber); +} + +.quote-age-stale { + color: var(--red); +} + +.quote-up { + color: var(--green); +} + +.quote-down { + color: var(--red); +} + +.sparkline { + display: block; + width: 100%; + height: 1.35rem; + margin-left: auto; + color: var(--blue-soft); + overflow: visible; +} + +.sparkline.quote-up { + color: var(--green); +} + +.sparkline.quote-down { + color: var(--red); +} + +.sparkline polyline { + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-linejoin: miter; + stroke-width: 1.25; + vector-effect: non-scaling-stroke; +} + +.market-statusbar { + display: flex; + flex: 0 0 var(--statusbar-height); + min-height: var(--statusbar-height); + gap: 1.1rem; + align-items: center; + padding: 0 0.65rem; + color: var(--muted); + background: var(--surface-bar); + border-top: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.56rem; + grid-area: footer; + letter-spacing: 0.035em; +} + +.market-statusbar strong { + margin-left: 0.25rem; + color: var(--text); + font-weight: 500; +} + +.sidebar-slot { + width: var(--sidebar-width); + min-width: 0; + min-height: 0; + overflow: hidden; + background: var(--surface-table); + border-left: 1px solid var(--border); + grid-area: sidebar; + transition: + opacity 120ms ease, + transform 160ms ease, + visibility 160ms; +} + +.is-sidebar-collapsed .sidebar-slot { + visibility: hidden; + opacity: 0; + pointer-events: none; + transform: translateX(100%); +} + +.configurator { + width: 100%; + height: 100%; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +.configurator > header { + display: flex; + height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + color: var(--text-strong); + background: var(--surface-toolbar); + border-bottom: 1px solid var(--border); + font-size: 0.65rem; + font-weight: 700; + letter-spacing: 0.055em; +} + +.configurator > header small { + color: var(--muted); + font-size: 0.54rem; + font-weight: 500; +} + +.config-section { + display: grid; + gap: 0.7rem; + padding: 0.8rem var(--shell-inline-padding); + border-bottom: 1px solid var(--border); +} + +.config-section h2 { + margin: 0; + color: var(--muted); + font-size: 0.58rem; + letter-spacing: 0.075em; +} + +.primary-action { + width: 100%; + color: var(--text-inverse); + background: var(--blue); + border-color: var(--blue-soft); +} + +.primary-action:hover { + background: var(--blue-soft); + border-color: var(--text-strong); +} + +.field { + display: grid; + gap: 0.35rem; + color: var(--text); + font-size: 0.66rem; +} + +.rate-field > span { + display: flex; + justify-content: space-between; +} + +.rate-field strong { + color: var(--text); + font-family: var(--font-mono); + font-weight: 500; +} + +.field small { + color: var(--muted); + font-family: var(--font-mono); + font-size: 0.55rem; +} + +input[type='range'] { + width: 100%; + margin: 0; + accent-color: var(--blue); +} + +.toggle-field { + display: flex; + gap: 0.5rem; + align-items: flex-start; + color: var(--text); + font-size: 0.66rem; + line-height: 1.3; +} + +.toggle-field input { + margin: 0.12rem 0 0; + accent-color: var(--blue); +} + +.toggle-field small { + display: block; + margin-top: 0.14rem; + color: var(--muted); + font-size: 0.57rem; +} + +.action-grid { + display: grid; + grid-template-columns: 1fr; + gap: 0.4rem; +} + +.diagnostics dl, +.selected-instrument dl { + display: grid; + gap: 0; + margin: 0; +} + +.diagnostics dl > div, +.selected-instrument dl > div { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 24px; + border-bottom: 1px solid var(--border-soft); +} + +.diagnostics dl > div:last-child, +.selected-instrument dl > div:last-child { + border-bottom: 0; +} + +.diagnostics dl > div:has(dd[data-testid$='-breakdown']) { + display: grid; + grid-template-columns: minmax(0, 1fr); + align-content: center; + padding-block: 0.28rem; +} + +.diagnostics dd[data-testid$='-breakdown'] { + width: 100%; + overflow-x: auto; + padding-block: 0.12rem; + white-space: nowrap; + scrollbar-width: thin; +} + +dt { + color: var(--muted); + font-size: 0.61rem; +} + +dd { + margin: 0; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.62rem; +} + +.selection { + display: flex; + align-items: flex-start; + justify-content: space-between; +} + +.selection div { + display: grid; + gap: 0.18rem; +} + +.selection strong { + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.85rem; +} + +.selection span, +.selection small, +.selected-instrument p { + color: var(--muted); + font-size: 0.61rem; +} + +.selected-instrument p { + margin: 0; + line-height: 1.45; +} + +@media (max-width: 980px) { + :root { + --sidebar-width: 15.625rem; + } +} + +@media (max-width: 720px) { + .trading-terminal { + --active-sidebar-width: 0px; + height: 100dvh; + min-height: 0; + overflow: hidden; + } + + .market-panel { + min-height: 0; + } + + .table-scroll { + min-height: 0; + } + + .sidebar-slot { + position: fixed; + z-index: 20; + top: 0; + right: 0; + bottom: 0; + width: min(var(--sidebar-width), calc(100vw - 2.75rem)); + box-shadow: -18px 0 42px rgb(0 0 0 / 48%); + } + + .is-sidebar-collapsed .sidebar-slot { + box-shadow: none; + } +} diff --git a/examples/alpine/realtime-trading/src/main.ts b/examples/alpine/realtime-trading/src/main.ts new file mode 100644 index 0000000000..5ad223d3c7 --- /dev/null +++ b/examples/alpine/realtime-trading/src/main.ts @@ -0,0 +1,565 @@ +import Alpine from 'alpinejs' +import { shallow } from '@tanstack/store' +import { FlexRender, createTable } from '@tanstack/alpine-table' +import { TradingBenchmarkController } from './benchmark/trading-benchmark-controller' +import { MarketFeedController } from './feed/market-feed-controller' +import { + feedSampleRateAt, + feedSampleRateIndex, + feedSampleRateOptions, +} from './feed/feed-sample-rates' +import { configuratorOptions } from './shell/configurator-options' +import { + createTradingColumns, + readMeasuredRows, +} from './table/table-config/trading-columns' +import { tradingFeatures } from './table/trading-features' +import { + TradingGridPointerController, + handleCellNavigation, + reorderColumnIds, + sortAriaValue, + sortIndicator, +} from './table/table-interactions' +import './table/table-config/quote-cells' +import './index.css' +import type { AlpineTable } from '@tanstack/alpine-table' +import type { MarketQuote } from './feed/market-data' + +type Table = AlpineTable +const integer = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }) +const rate = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +const ms = (number: number) => `${number.toFixed(2)} ms` + +function applyCellMarkup(element: HTMLElement, markup: unknown) { + const html = markup == null ? '' : String(markup) + const existing = element.firstElementChild as HTMLElement | null + if (existing && html.startsWith('<')) { + const closeIndex = html.indexOf('>') + const startTag = closeIndex === -1 ? html : html.slice(1, closeIndex) + const tagName = startTag.split(/\s/, 1)[0]?.replace(/\/$/, '') + if (tagName && existing.tagName.toLowerCase() === tagName) { + for (const match of startTag.matchAll(/([^\s=]+)="([^"]*)"/g)) { + const name = match[1]! + const value = match[2]! + if (existing.getAttribute(name) !== value) { + existing.setAttribute(name, value) + } + } + return + } + } + if (element.innerHTML !== html) { + element.innerHTML = html + } +} + +Alpine.data('tradingApp', () => { + const feed = new MarketFeedController() + const controller = new TradingBenchmarkController(feed) + const local = Alpine.reactive({ + feed: { + workerReady: feed.workerReady.get(), + running: feed.running.get(), + instrumentCount: feed.instrumentCount.get(), + targetTicksPerSecond: feed.targetTicksPerSecond.get(), + publishIntervalMs: feed.publishIntervalMs.get(), + updateSparklines: feed.updateSparklines.get(), + sparklineSampleIntervalMs: feed.sparklineSampleIntervalMs.get(), + quotes: feed.quotes.get(), + }, + benchmark: controller.store.get(), + selectedSymbol: controller.renderAtoms.selectedSymbol.get(), + rendererMode: controller.renderAtoms.rendererMode.get(), + sidebarOpen: true, + tableVersion: 0, + quotesVersion: 0, + }) + const columns = createTradingColumns(() => local.rendererMode) + const table = createTable( + { + key: 'alpine-realtime-trading', + features: tradingFeatures, + columns, + get data() { + return local.feed.quotes + }, + getRowId: (row: MarketQuote) => row.id, + columnResizeMode: 'onChange', + defaultColumn: { minSize: 56, maxSize: 800 }, + autoResetCellSelection: false, + }, + (state) => ({ + sorting: state.sorting, + columnFilters: state.columnFilters, + columnOrder: state.columnOrder, + rowSelection: state.rowSelection, + cellSelection: state.cellSelection, + }), + ) + const pointer = new TradingGridPointerController() + const runtime = { + cleanups: [] as Array<() => void>, + manuallyResized: false, + dragColumnId: null as string | null, + dragSource: null as HTMLTableCellElement | null, + dragTarget: null as HTMLTableCellElement | null, + cachedRows: [] as ReturnType['rows'], + cachedFeed: null as Array | null, + cachedTableVersion: -1, + lastRenderedRowCount: -1, + lastTableUi: null as { + sorting: unknown + columnFilters: unknown + columnOrder: unknown + rowSelection: unknown + cellSelection: unknown + } | null, + domCommitScheduled: false, + } + const rows = () => { + if ( + runtime.cachedFeed !== local.feed.quotes || + runtime.cachedTableVersion !== local.tableVersion + ) { + runtime.cachedFeed = local.feed.quotes + runtime.cachedTableVersion = local.tableVersion + runtime.cachedRows = readMeasuredRows(() => table.getRowModel().rows) + } + return runtime.cachedRows + } + const renderRows = () => { + void local.quotesVersion + const currentRows = rows() + if (runtime.lastRenderedRowCount !== currentRows.length) { + runtime.lastRenderedRowCount = currentRows.length + queueMicrotask(() => + controller.actions.setRenderedRowCount(runtime.lastRenderedRowCount), + ) + } + return currentRows + } + const writeSizes = (tableElement: HTMLTableElement) => { + for (const header of table.getFlatHeaders()) { + tableElement.style.setProperty( + `--header-${header.id}-size`, + String(header.getSize()), + ) + tableElement.style.setProperty( + `--col-${header.column.id}-size`, + String(header.column.getSize()), + ) + } + tableElement.style.width = `${table.getTotalSize()}px` + } + const scheduleDomCommit = () => { + if (runtime.domCommitScheduled) return + + runtime.domCommitScheduled = true + Alpine.nextTick(() => { + runtime.domCommitScheduled = false + feed.completeRender() + }) + } + + return { + table, + FlexRender, + applyCellMarkup, + local, + feed, + controller, + feedSampleRateOptions, + configuratorOptions, + init(this: { $refs: Record }) { + const scroll = this.$refs.scroll as HTMLDivElement + const tableElement = this.$refs.table as HTMLTableElement + const resizeObserver = new ResizeObserver(() => { + if (runtime.manuallyResized) return + const width = table.getTotalSize() + if (scroll.clientWidth <= width + 1 || width <= 0) return + const ratio = scroll.clientWidth / width + table.setColumnSizing( + Object.fromEntries( + table + .getVisibleLeafColumns() + .map((column) => [column.id, column.getSize() * ratio]), + ), + ) + }) + resizeObserver.observe(scroll) + const mutationObserver = new MutationObserver((records) => + controller.monitor.recordDomMutations(records.length), + ) + mutationObserver.observe(tableElement.tBodies[0], { + attributes: true, + attributeFilter: ['class', 'style'], + characterData: true, + childList: true, + subtree: true, + }) + const subscriptions = [ + feed.workerReady.subscribe((value) => { + local.feed.workerReady = value + }), + feed.running.subscribe((value) => { + local.feed.running = value + }), + feed.instrumentCount.subscribe((value) => { + local.feed.instrumentCount = value + }), + feed.targetTicksPerSecond.subscribe((value) => { + local.feed.targetTicksPerSecond = value + }), + feed.publishIntervalMs.subscribe((value) => { + local.feed.publishIntervalMs = value + }), + feed.updateSparklines.subscribe((value) => { + local.feed.updateSparklines = value + }), + feed.sparklineSampleIntervalMs.subscribe((value) => { + local.feed.sparklineSampleIntervalMs = value + }), + feed.quotes.subscribe((quotes) => { + const lengthChanged = quotes.length !== local.feed.quotes.length + runtime.cachedFeed = null + local.feed.quotes = quotes + if (lengthChanged) { + local.quotesVersion++ + local.tableVersion++ + } + table.setOptions((previous) => ({ ...previous, data: quotes })) + scheduleDomCommit() + }), + controller.store.subscribe((state) => { + const current = local.benchmark + if (current.mountedCells !== state.mountedCells) { + current.mountedCells = state.mountedCells + } + if (current.liveComponents !== state.liveComponents) { + current.liveComponents = state.liveComponents + } + current.metrics = state.metrics + }), + controller.renderAtoms.selectedSymbol.subscribe((symbol) => { + local.selectedSymbol = symbol + }), + controller.renderAtoms.rendererMode.subscribe((mode) => { + local.rendererMode = mode + local.tableVersion++ + }), + table.store.subscribe(() => { + const state = table.store.state + const next = { + sorting: state.sorting, + columnFilters: state.columnFilters, + columnOrder: state.columnOrder, + rowSelection: state.rowSelection, + cellSelection: state.cellSelection, + } + if (runtime.lastTableUi && shallow(runtime.lastTableUi, next)) { + return + } + runtime.lastTableUi = next + local.tableVersion++ + }), + table.atoms.columnSizing.subscribe(() => writeSizes(tableElement)), + table.atoms.columnOrder.subscribe(() => writeSizes(tableElement)), + table.atoms.columnResizing.subscribe((state) => { + if (state.isResizingColumn !== false) runtime.manuallyResized = true + }), + ] + const stopFeed = feed.start() + const stopBenchmark = controller.start() + runtime.cleanups.push( + stopFeed, + stopBenchmark, + () => resizeObserver.disconnect(), + () => mutationObserver.disconnect(), + ...subscriptions.map( + (subscription) => () => subscription.unsubscribe(), + ), + ) + Alpine.nextTick(() => writeSizes(tableElement)) + scheduleDomCommit() + }, + destroy() { + for (const cleanup of runtime.cleanups) cleanup() + runtime.cleanups.length = 0 + }, + rows, + renderRows, + toggleSidebar() { + local.sidebarOpen = !local.sidebarOpen + }, + feedStatus() { + return !local.feed.workerReady + ? 'FEED CONNECTING' + : local.feed.running + ? 'FEED LIVE' + : 'FEED PAUSED' + }, + setInstrumentCount(event: Event) { + controller.actions.resetViewState() + feed.actions.setInstrumentCount( + Number((event.target as HTMLSelectElement).value), + ) + }, + sampleRateIndex() { + return feedSampleRateIndex(local.feed.targetTicksPerSecond) + }, + setSampleRate(event: Event) { + feed.actions.setTargetRate( + feedSampleRateAt(Number((event.target as HTMLInputElement).value)), + ) + }, + setPublishInterval(event: Event) { + feed.actions.setPublishInterval( + Number((event.target as HTMLSelectElement).value), + ) + }, + setRendererMode(event: Event) { + controller.actions.setRendererMode( + (event.target as HTMLInputElement).checked ? 'swap' : 'stable', + ) + }, + setSparklineUpdates(event: Event) { + feed.actions.setSparklineUpdates( + (event.target as HTMLInputElement).checked, + ) + }, + setSparklineInterval(event: Event) { + feed.actions.setSparklineSampleInterval( + Number((event.target as HTMLSelectElement).value), + ) + }, + metricItems() { + const metrics = local.benchmark.metrics + return [ + [ + 'FRAME RATE (EST.)', + metrics.rafCallbacksPerSecond.toFixed(1), + 'rAF callbacks/s · rolling 1 s', + 'frame-rate', + ], + [ + 'AVG COMMIT', + ms(metrics.averageCommitLatencyMs), + 'snapshot → DOM · rolling 3 s', + 'average-commit-latency', + ], + [ + 'LONG FRAMES', + local.benchmark.longAnimationFramesSupported + ? String(metrics.longAnimationFrames) + : 'N/A', + local.benchmark.longAnimationFramesSupported + ? `since reset · worst ${ms(metrics.worstLongAnimationFrameMs)}` + : 'unsupported', + 'long-frame-count', + ], + [ + 'THROUGHPUT', + `${rate.format(metrics.rowUpdatesPerSecond)} rows/s`, + `${metrics.stateApplicationsPerSecond.toFixed(1)} snapshots/s · rows deduplicated per snapshot`, + 'throughput-rate', + ], + ] + }, + diagnostics() { + const metrics = local.benchmark.metrics + const invocation = (items: typeof metrics.cellRendererRates) => { + const active = items.filter((item) => item.callsPerSecond > 0) + return active.length + ? active + .map((item) => `${item.name} ${rate.format(item.callsPerSecond)}`) + .join(' · ') + : '—' + } + return [ + [ + 'Worker-generated samples / s', + rate.format(metrics.actualTicksPerSecond), + 'actual-rate', + ], + [ + 'Changed rows / s', + rate.format(metrics.rowUpdatesPerSecond), + 'row-update-rate', + ], + [ + 'Worker messages / s', + metrics.workerMessagesPerSecond.toFixed(1), + 'message-rate', + ], + [ + 'Snapshots applied / s', + metrics.stateApplicationsPerSecond.toFixed(1), + 'state-apply-rate', + ], + [ + 'DOM commits / s', + metrics.tableCommitsPerSecond.toFixed(1), + 'table-render-rate', + ], + [ + 'Commit latency p95 / max (10 s)', + `${ms(metrics.p95CommitLatencyMs)} / ${ms(metrics.maxCommitLatencyMs)}`, + '', + ], + ['Mounted cells', integer.format(local.benchmark.mountedCells), ''], + ['Live components', integer.format(local.benchmark.liveComponents), ''], + [ + 'Created / destroyed', + `${integer.format(metrics.componentsCreated)} / ${integer.format(metrics.componentsDestroyed)}`, + '', + ], + [ + 'Renderer callbacks / s', + rate.format(metrics.cellRendererCallsPerSecond), + 'cell-render-rate', + ], + [ + 'Component executions / s', + rate.format(metrics.componentRenderCallsPerSecond), + 'component-render-rate', + ], + [ + 'Executions by component / s', + invocation(metrics.componentRenderRates), + 'component-render-breakdown', + ], + [ + 'Callbacks by column / s', + invocation(metrics.cellRendererRates), + 'cell-render-breakdown', + ], + [ + 'Observed MutationRecords / s', + rate.format(metrics.domMutationsPerSecond), + 'dom-mutation-rate', + ], + [ + 'Core row model calls / s', + metrics.rowModelCallsPerSecond.toFixed(1), + 'row-model-call-rate', + ], + [ + 'Core row model avg / max', + `${ms(metrics.rowModelAverageMs)} / ${ms(metrics.rowModelMaxMs)}`, + 'row-model-duration', + ], + [ + 'Visible rows', + integer.format(metrics.visibleRows), + 'visible-row-count', + ], + [ + 'Worker messages', + integer.format(metrics.workerMessages), + 'worker-messages', + ], + [ + 'Worker-coalesced updates / s', + rate.format(metrics.supersededUpdatesPerSecond), + 'superseded-update-rate', + ], + [ + 'Last samples / updated rows', + `${integer.format(metrics.lastBatchSize)} / ${integer.format(metrics.lastUpdateCount)}`, + '', + ], + [ + 'Commits > 16.7 ms (since reset)', + integer.format(metrics.slowCommits), + '', + ], + [ + 'JS heap (current, GC-sensitive)', + metrics.heapMb === null ? 'N/A' : `${metrics.heapMb.toFixed(1)} MB`, + '', + ], + ] + }, + selectedQuote() { + return feed.getQuoteBySymbol(local.feed.quotes, local.selectedSymbol) + }, + formatInteger: (number: number) => integer.format(number), + formatRate: (number: number) => rate.format(number), + sortIndicator, + sortAriaValue, + isTextColumn(id: string) { + return ['market', 'name', 'symbol'].includes(id) + }, + onGridKeyDown(event: KeyboardEvent) { + handleCellNavigation(table, event) + }, + onBodyMouseDown(event: MouseEvent) { + pointer.handleMouseDown(table, event, controller.actions.selectSymbol) + }, + onBodyPointerOver(event: MouseEvent) { + pointer.handlePointerOver(table, event) + }, + onBodyClick(event: MouseEvent) { + pointer.handleClick(table, event) + }, + resetPointer() { + pointer.resetPointerCell() + }, + clearDrag() { + runtime.dragSource?.classList.remove('is-column-dragging') + runtime.dragTarget?.classList.remove('is-column-drop-target') + runtime.dragColumnId = null + runtime.dragSource = null + runtime.dragTarget = null + }, + dragStart( + header: ReturnType[number], + event: DragEvent, + ) { + runtime.dragColumnId = header.column.id + runtime.dragSource = (event.currentTarget as HTMLElement).closest('th') + runtime.dragSource?.classList.add('is-column-dragging') + if (event.dataTransfer) { + event.dataTransfer.effectAllowed = 'move' + event.dataTransfer.setData('text/plain', header.column.id) + } + }, + dragOver( + header: ReturnType[number], + event: DragEvent, + ) { + event.preventDefault() + runtime.dragTarget?.classList.remove('is-column-drop-target') + runtime.dragTarget = null + const element = (event.currentTarget as HTMLElement).closest('th') + if (runtime.dragColumnId !== header.column.id && element) { + element.classList.add('is-column-drop-target') + runtime.dragTarget = element + } + }, + drop( + header: ReturnType[number], + event: DragEvent, + ) { + event.preventDefault() + const source = + event.dataTransfer?.getData('text/plain') || runtime.dragColumnId + if (source) + table.setColumnOrder( + reorderColumnIds( + table.getVisibleLeafColumns().map((column) => column.id), + source, + header.column.id, + ), + ) + this.clearDrag() + }, + } +}) + +window.Alpine = Alpine +Alpine.start() diff --git a/examples/alpine/realtime-trading/src/shell/configurator-options.ts b/examples/alpine/realtime-trading/src/shell/configurator-options.ts new file mode 100644 index 0000000000..5e21d71492 --- /dev/null +++ b/examples/alpine/realtime-trading/src/shell/configurator-options.ts @@ -0,0 +1,49 @@ +export interface ConfiguratorOption { + readonly label: string + readonly value: TValue +} + +const instrumentCountOptions = [ + { label: '50', value: 50 }, + { label: '100', value: 100 }, + { label: '150', value: 150 }, + { label: '250', value: 250 }, + { label: '350', value: 350 }, + { label: '500', value: 500 }, + { label: '750', value: 750 }, + { label: '1,000', value: 1_000 }, + { label: '1,500', value: 1_500 }, + { label: '2,500', value: 2_500 }, + { label: '5,000', value: 5_000 }, + { label: '1,000,000', value: 1_000_000 }, + { label: '10,000,000', value: 10_000_000 }, +] as const satisfies ReadonlyArray> + +const workerDeliveryOptions = [ + { label: '8 ms · 125 msg/s', value: 8 }, + { label: '16 ms · 62.5 msg/s', value: 16 }, + { label: '20 ms · 50 msg/s', value: 20 }, + { label: '33 ms · 30 msg/s', value: 33 }, + { label: '50 ms · 20 msg/s', value: 50 }, + { label: '100 ms · 10 msg/s', value: 100 }, + { label: '250 ms · 4 msg/s', value: 250 }, + { label: '500 ms · 2 msg/s', value: 500 }, + { label: '1,000 ms · 1 msg/s', value: 1_000 }, +] as const satisfies ReadonlyArray> + +const intradaySamplingOptions = [ + { label: '16 ms · fastest', value: 16 }, + { label: '33 ms · very fast', value: 33 }, + { label: '50 ms · fast', value: 50 }, + { label: '100 ms', value: 100 }, + { label: '250 ms', value: 250 }, + { label: '500 ms', value: 500 }, + { label: '1,000 ms', value: 1_000 }, + { label: '2,000 ms', value: 2_000 }, +] as const satisfies ReadonlyArray> + +export const configuratorOptions = { + instrumentCounts: instrumentCountOptions, + workerDeliveryIntervals: workerDeliveryOptions, + intradaySamplingIntervals: intradaySamplingOptions, +} as const diff --git a/examples/alpine/realtime-trading/src/table/table-config/quote-cells.ts b/examples/alpine/realtime-trading/src/table/table-config/quote-cells.ts new file mode 100644 index 0000000000..b5f115e28f --- /dev/null +++ b/examples/alpine/realtime-trading/src/table/table-config/quote-cells.ts @@ -0,0 +1,145 @@ +export const quoteCellLifecycle = { created: 0, destroyed: 0 } +export const quoteCellRendererNames = [ + 'Market', + 'Name', + 'Symbol', + 'Last', + 'Change', + 'ChangePercent', + 'Bid', + 'BidVolume', + 'Ask', + 'AskVolume', + 'Open', + 'High', + 'Low', + 'Intraday', +] as const +export const quoteComponentNames = [ + 'PriceCell', + 'StableMoveCell', + 'UpMoveCell', + 'DownMoveCell', + 'PercentChangeCell', + 'SparklineCell', +] as const +export type QuoteCellRendererName = (typeof quoteCellRendererNames)[number] +export type QuoteComponentName = (typeof quoteComponentNames)[number] +const counters = (names: ReadonlyArray) => + Object.fromEntries(names.map((name) => [name, 0])) as Record +export const quoteRenderDiagnostics = { + cellRendererCalls: 0, + componentRenderCalls: 0, + cellRendererCallsByName: counters(quoteCellRendererNames), + componentRenderCallsByName: counters(quoteComponentNames), +} +export function recordCellRender(name: QuoteCellRendererName, value: T): T { + quoteRenderDiagnostics.cellRendererCalls++ + quoteRenderDiagnostics.cellRendererCallsByName[name]++ + return value +} +const signed = (value: number) => `${value >= 0 ? '+' : ''}${value.toFixed(2)}` + +abstract class QuoteElement extends HTMLElement { + protected abstract readonly componentName: QuoteComponentName + connectedCallback() { + quoteCellLifecycle.created++ + this.renderCell() + } + disconnectedCallback() { + quoteCellLifecycle.destroyed++ + } + attributeChangedCallback() { + if (this.isConnected) this.renderCell() + } + protected renderCell() { + quoteRenderDiagnostics.componentRenderCalls++ + quoteRenderDiagnostics.componentRenderCallsByName[this.componentName]++ + } + protected number(name: string) { + return Number(this.getAttribute(name) ?? 0) + } +} + +class PriceCell extends QuoteElement { + protected readonly componentName = 'PriceCell' + static observedAttributes = ['price', 'move'] + protected renderCell() { + super.renderCell() + const price = this.number('price') + const move = this.number('move') + this.innerHTML = `` + } +} +abstract class MoveCell extends QuoteElement { + static observedAttributes = ['move'] + protected direction: 'up' | 'down' | null = null + protected indicator = '' + protected renderCell() { + super.renderCell() + const move = this.number('move') + const direction = this.direction ?? (move >= 0 ? 'up' : 'down') + this.innerHTML = `${this.indicator}${signed(move)}` + } +} +class StableMoveCell extends MoveCell { + protected readonly componentName = 'StableMoveCell' +} +class UpMoveCell extends MoveCell { + protected readonly componentName = 'UpMoveCell' + protected direction = 'up' as const + protected indicator = '▲ ' +} +class DownMoveCell extends MoveCell { + protected readonly componentName = 'DownMoveCell' + protected direction = 'down' as const + protected indicator = '▼ ' +} +class PercentChangeCell extends QuoteElement { + protected readonly componentName = 'PercentChangeCell' + static observedAttributes = ['value'] + protected renderCell() { + super.renderCell() + const value = this.number('value') + this.innerHTML = `${signed(value)}%` + } +} +class SparklineCell extends QuoteElement { + protected readonly componentName = 'SparklineCell' + static observedAttributes = ['points', 'rising'] + protected renderCell() { + super.renderCell() + this.innerHTML = `` + } +} + +const definitions = [ + ['quote-price-cell', PriceCell], + ['quote-stable-move', StableMoveCell], + ['quote-up-move', UpMoveCell], + ['quote-down-move', DownMoveCell], + ['quote-percent-change', PercentChangeCell], + ['quote-sparkline', SparklineCell], +] as const +for (const [name, definition] of definitions) + if (!customElements.get(name)) customElements.define(name, definition) + +export function sparklineMarkup(values: ReadonlyArray): string { + const first = values[0] ?? 0 + const range = values.reduce( + (current, value) => ({ + min: Math.min(current.min, value), + max: Math.max(current.max, value), + }), + { min: first, max: first }, + ) + const height = range.max - range.min || 1 + const denominator = Math.max(1, values.length - 1) + const points = values + .map( + (value, index) => + `${((index / denominator) * 100).toFixed(1)},${(22 - ((value - range.min) / height) * 20).toFixed(1)}`, + ) + .join(' ') + return `` +} diff --git a/examples/alpine/realtime-trading/src/table/table-config/trading-columns.ts b/examples/alpine/realtime-trading/src/table/table-config/trading-columns.ts new file mode 100644 index 0000000000..14926a2fdc --- /dev/null +++ b/examples/alpine/realtime-trading/src/table/table-config/trading-columns.ts @@ -0,0 +1,199 @@ +import { createColumnHelper } from '@tanstack/alpine-table' +import { tradingFeatures } from '../trading-features' +import { recordCellRender, sparklineMarkup } from './quote-cells' +import type { MarketQuote } from '../../feed/market-data' + +export type RendererMode = 'stable' | 'swap' +export interface CoreTableState { + sorting: Array<{ id: string; desc: boolean }> + columnFilters: Array<{ id: string; value: unknown }> +} +const compact = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +const columnHelper = createColumnHelper() +const safe = (value: string) => + value + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + +export function createTradingColumns(getRendererMode: () => RendererMode) { + return columnHelper.columns([ + columnHelper.group({ + id: 'instrument', + header: 'Instrument', + columns: columnHelper.columns([ + columnHelper.accessor('venue', { + id: 'market', + header: 'Market', + size: 72, + cell: (info) => recordCellRender('Market', safe(info.getValue())), + }), + columnHelper.accessor('company', { + id: 'name', + header: 'Name', + size: 180, + cell: (info) => recordCellRender('Name', safe(info.getValue())), + }), + columnHelper.accessor('symbol', { + header: 'Symbol', + size: 92, + filterFn: 'includesString', + cell: (info) => recordCellRender('Symbol', safe(info.getValue())), + }), + ]), + }), + columnHelper.group({ + id: 'priceAndChange', + header: 'Price & Change', + columns: columnHelper.columns([ + columnHelper.accessor('price', { + header: 'Price', + size: 96, + sortFn: 'basic', + cell: (info) => + recordCellRender( + 'Last', + ``, + ), + }), + columnHelper.accessor(getDayChange, { + id: 'change', + header: 'Chg', + size: 94, + cell: (info) => + recordCellRender( + 'Change', + moveMarkup(getRendererMode(), info.getValue()), + ), + }), + columnHelper.accessor(getDayChangePercent, { + id: 'changePercent', + header: 'Chg%', + size: 90, + cell: (info) => + recordCellRender( + 'ChangePercent', + ``, + ), + }), + ]), + }), + columnHelper.group({ + id: 'orderBook', + header: 'Order Book', + columns: columnHelper.columns([ + columnHelper.accessor('bid', { + header: 'Bid', + size: 90, + cell: (info) => recordCellRender('Bid', info.getValue().toFixed(2)), + }), + columnHelper.accessor('bidSize', { + header: 'Bid Vol', + size: 100, + cell: (info) => + recordCellRender('BidVolume', compact.format(info.getValue())), + }), + columnHelper.accessor('ask', { + header: 'Ask', + size: 90, + cell: (info) => recordCellRender('Ask', info.getValue().toFixed(2)), + }), + columnHelper.accessor('askSize', { + header: 'Ask Vol', + size: 100, + cell: (info) => + recordCellRender('AskVolume', compact.format(info.getValue())), + }), + ]), + }), + columnHelper.group({ + id: 'session', + header: 'Session', + columns: columnHelper.columns([ + columnHelper.accessor('open', { + header: 'Open', + size: 90, + cell: (info) => recordCellRender('Open', info.getValue().toFixed(2)), + }), + columnHelper.accessor('high', { + header: 'High', + size: 90, + cell: (info) => recordCellRender('High', info.getValue().toFixed(2)), + }), + columnHelper.accessor('low', { + header: 'Low', + size: 90, + cell: (info) => recordCellRender('Low', info.getValue().toFixed(2)), + }), + ]), + }), + columnHelper.group({ + id: 'chart', + header: 'Chart', + columns: columnHelper.columns([ + columnHelper.accessor('history', { + header: 'Intraday', + size: 150, + enableSorting: false, + cell: (info) => + recordCellRender('Intraday', sparklineMarkup(info.getValue())), + }), + ]), + }), + ]) +} +function moveMarkup(mode: RendererMode, move: number) { + if (mode === 'stable') + return `` + return move >= 0 + ? `` + : `` +} +export const rowModelDiagnostics = { + hasMeasurement: false, + calls: 0, + totalDurationMs: 0, + maxDurationMs: 0, + lastRowCount: 0, +} +export const TRADING_COLUMN_COUNT = 14 +export function readMeasuredRows(readRows: () => Array): Array { + const start = performance.now() + const rows = readRows() + const end = performance.now() + const duration = end - start + rowModelDiagnostics.calls++ + rowModelDiagnostics.hasMeasurement = true + rowModelDiagnostics.totalDurationMs += duration + rowModelDiagnostics.maxDurationMs = Math.max( + rowModelDiagnostics.maxDurationMs, + duration, + ) + rowModelDiagnostics.lastRowCount = rows.length + if ((rowModelDiagnostics.calls - 1) % 20 === 0) { + try { + performance.measure('tanstack-row-model', { + start, + end, + detail: { rowCount: rows.length }, + }) + if (rowModelDiagnostics.calls % 1_000 === 0) + performance.clearMeasures('tanstack-row-model') + } catch { + /* optional sampled User Timing detail */ + } + } + return rows +} +export function getDayChange(quote: MarketQuote): number { + return quote.price - quote.previousClose +} +export function getDayChangePercent(quote: MarketQuote): number { + return quote.previousClose === 0 + ? 0 + : (getDayChange(quote) / quote.previousClose) * 100 +} diff --git a/examples/alpine/realtime-trading/src/table/table-interactions.ts b/examples/alpine/realtime-trading/src/table/table-interactions.ts new file mode 100644 index 0000000000..99649a40bd --- /dev/null +++ b/examples/alpine/realtime-trading/src/table/table-interactions.ts @@ -0,0 +1,187 @@ +export type CellDirection = 'up' | 'down' | 'left' | 'right' + +interface RowSelectionTable { + resetRowSelection: (defaultState?: boolean) => void +} + +interface SelectableRow { + getIsSelected: () => boolean + getToggleSelectedHandler: (options?: { + selectChildren?: boolean + }) => (event: unknown) => void +} + +interface SelectableGridCell { + row: SelectableGridRow + getSelectionStartHandler: ( + contextDocument?: Document, + ) => (event: unknown) => void + getSelectionExtendHandler: () => (event: unknown) => void +} + +interface SelectableGridRow extends SelectableRow { + original: { symbol: string } + getAllCellsByColumnId: () => Record +} + +interface TradingGridTable extends RowSelectionTable { + getRowModel: () => { + rowsById: Record + } +} + +interface SelectionCellTarget { + element: HTMLTableCellElement + cell: SelectableGridCell +} + +interface CellNavigationTable { + extendCellSelection: (direction: CellDirection) => void + moveCellSelection: (direction: CellDirection) => void + resetCellSelection: (defaultState?: boolean) => void + selectAllCells: () => void +} + +const keyDirections: Partial> = { + ArrowUp: 'up', + ArrowDown: 'down', + ArrowLeft: 'left', + ArrowRight: 'right', +} + +export function reorderColumnIds( + columnIds: Array, + sourceId: string, + targetId: string, +): Array { + if (sourceId === targetId || !columnIds.includes(sourceId)) return columnIds + + const withoutSource = columnIds.filter((id) => id !== sourceId) + const targetIndex = withoutSource.indexOf(targetId) + if (targetIndex < 0) return columnIds + + return [ + ...withoutSource.slice(0, targetIndex), + sourceId, + ...withoutSource.slice(targetIndex), + ] +} + +export function selectRowFromPointer( + table: RowSelectionTable, + row: SelectableRow, + event: MouseEvent, +): void { + const additive = event.ctrlKey || event.metaKey + const checked = additive ? !row.getIsSelected() : true + + if (!event.shiftKey && !additive) table.resetRowSelection(true) + + row.getToggleSelectedHandler({ selectChildren: false })({ + target: { checked }, + shiftKey: event.shiftKey, + ctrlKey: event.ctrlKey, + metaKey: event.metaKey, + }) +} + +export class TradingGridPointerController { + #lastPointerCell: HTMLTableCellElement | null = null + + handleMouseDown( + table: TradingGridTable, + event: MouseEvent, + selectSymbol: (symbol: string) => void, + ): void { + if (event.button !== 0) return + + const target = this.#findCellTarget(table, event.composedPath()) + if (!target) return + + event.preventDefault() + this.#lastPointerCell = target.element + selectSymbol(target.cell.row.original.symbol) + target.cell.getSelectionStartHandler(target.element.ownerDocument)(event) + } + + handlePointerOver(table: TradingGridTable, event: MouseEvent): void { + if ((event.buttons & 1) === 0) { + this.resetPointerCell() + return + } + + const target = this.#findCellTarget(table, event.composedPath()) + if (!target || target.element === this.#lastPointerCell) return + + this.#lastPointerCell = target.element + target.cell.getSelectionExtendHandler()(event) + } + + handleClick(table: TradingGridTable, event: MouseEvent): void { + const target = this.#findCellTarget(table, event.composedPath()) + if (!target) return + selectRowFromPointer(table, target.cell.row, event) + } + + resetPointerCell(): void { + this.#lastPointerCell = null + } + + #findCellTarget( + table: TradingGridTable, + path: Array, + ): SelectionCellTarget | null { + for (const target of path) { + if (!(target instanceof HTMLTableCellElement)) continue + + const columnId = target.dataset['columnId'] + const rowId = + target.closest('tr[data-row-id]')?.dataset['rowId'] + if (!columnId || !rowId) return null + + const row = table.getRowModel().rowsById[rowId] + const cell = row.getAllCellsByColumnId()[columnId] + return { element: target, cell } + } + + return null + } +} + +export function handleCellNavigation( + table: CellNavigationTable, + event: KeyboardEvent, +): void { + if (event.key === 'Escape') { + event.preventDefault() + table.resetCellSelection(true) + return + } + + if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'a') { + event.preventDefault() + table.selectAllCells() + return + } + + const direction = keyDirections[event.key] + if (!direction) return + + event.preventDefault() + if (event.shiftKey) table.extendCellSelection(direction) + else table.moveCellSelection(direction) +} + +export function sortIndicator(direction: false | 'asc' | 'desc'): string { + if (direction === 'asc') return '↑' + if (direction === 'desc') return '↓' + return '↕' +} + +export function sortAriaValue( + direction: false | 'asc' | 'desc', +): 'ascending' | 'descending' | 'none' { + if (direction === 'asc') return 'ascending' + if (direction === 'desc') return 'descending' + return 'none' +} diff --git a/examples/alpine/realtime-trading/src/table/trading-features.ts b/examples/alpine/realtime-trading/src/table/trading-features.ts new file mode 100644 index 0000000000..1a75ebdb36 --- /dev/null +++ b/examples/alpine/realtime-trading/src/table/trading-features.ts @@ -0,0 +1,16 @@ +import { + createFilteredRowModel, + createSortedRowModel, + filterFn_includesString, + sortFn_basic, + stockFeatures, + tableFeatures, +} from '@tanstack/alpine-table' + +export const tradingFeatures = tableFeatures({ + ...stockFeatures, + filteredRowModel: createFilteredRowModel(), + sortedRowModel: createSortedRowModel(), + filterFns: { includesString: filterFn_includesString }, + sortFns: { basic: sortFn_basic }, +}) diff --git a/examples/alpine/realtime-trading/src/table/trading-table.ts b/examples/alpine/realtime-trading/src/table/trading-table.ts new file mode 100644 index 0000000000..39fde46d14 --- /dev/null +++ b/examples/alpine/realtime-trading/src/table/trading-table.ts @@ -0,0 +1,8 @@ +export { + TRADING_COLUMN_COUNT, + rowModelDiagnostics, +} from './table-config/trading-columns' +export type { + CoreTableState, + RendererMode, +} from './table-config/trading-columns' diff --git a/examples/alpine/realtime-trading/src/vite-env.d.ts b/examples/alpine/realtime-trading/src/vite-env.d.ts new file mode 100644 index 0000000000..99f6333028 --- /dev/null +++ b/examples/alpine/realtime-trading/src/vite-env.d.ts @@ -0,0 +1,9 @@ +/// + +import type Alpine from 'alpinejs' + +declare global { + interface Window { + Alpine: typeof Alpine + } +} diff --git a/examples/alpine/realtime-trading/tests/e2e/smoke.spec.ts b/examples/alpine/realtime-trading/tests/e2e/smoke.spec.ts new file mode 100644 index 0000000000..874881a758 --- /dev/null +++ b/examples/alpine/realtime-trading/tests/e2e/smoke.spec.ts @@ -0,0 +1,133 @@ +import path from 'node:path' +import { expect, test } from '@playwright/test' +import { startExampleServer } from '../../../../../tests/e2e/helpers/startExampleServer' +import { + setRangeValue, + resumeTradingFeed, + pausedFeedUrl, +} from '../../../../../tests/e2e/helpers/setRangeValue' +import type { Page } from '@playwright/test' + +const exampleDir = path.resolve() + +function collectPageErrors(page: Page) { + const errors: Array = [] + page.on('pageerror', (error) => errors.push(error.message)) + page.on('console', (message) => { + if (message.type() === 'error') errors.push(message.text()) + }) + return errors +} + +test('runs the Alpine realtime trading workload', async ({ page }) => { + test.setTimeout(120_000) + const server = await startExampleServer(exampleDir) + const errors = collectPageErrors(page) + + try { + await page.goto(pausedFeedUrl(server.url)) + + const table = page.getByTestId('trading-table') + const instrumentCount = page.getByTestId('instrument-count-select') + await expect(table).toBeVisible() + await expect(instrumentCount).toHaveValue('100') + await expect(page.locator('.brand')).toHaveText('MARKET MONITOR') + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(table.locator('tbody')).toHaveCSS('user-select', 'none') + await expect(table.locator('tbody tr').first()).toHaveCSS( + 'content-visibility', + 'auto', + ) + await expect(table.locator('thead tr')).toHaveCount(2) + await expect(table.locator('thead tr').last().locator('th')).toHaveCount(14) + await expect(table.locator('thead')).not.toContainText('Identity') + await expect(table.locator('thead')).not.toContainText('Market Data') + await expect(table.locator('thead')).toContainText('Market') + await expect(table.locator('thead')).toContainText('Bid Vol') + await expect(table.locator('thead')).toContainText('Intraday') + const selectedRow = table.locator('tbody tr').first() + const selectedSymbol = await selectedRow.getAttribute('data-symbol') + await selectedRow.locator('td').nth(1).click() + await expect(page.getByTestId('selected-instrument')).toContainText( + selectedSymbol ?? '', + ) + await expect(page.getByTestId('feed-status')).toHaveText('FEED PAUSED') + await expect(instrumentCount.locator('option[value="150"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="350"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="750"]')).toHaveCount(1) + + const targetRateSlider = page.getByTestId('target-rate-slider') + await expect(targetRateSlider).toHaveAttribute('min', '0') + await expect(targetRateSlider).toHaveAttribute('max', '9') + await expect(targetRateSlider).toHaveAttribute('step', '1') + await expect(targetRateSlider).toHaveValue('6') + await setRangeValue(targetRateSlider, '7') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '25K samples/s', + ) + await setRangeValue(targetRateSlider, '8') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '50K samples/s', + ) + await setRangeValue(targetRateSlider, '6') + + const sparklineInterval = page.getByTestId( + 'sparkline-sample-interval-select', + ) + await expect(sparklineInterval).toHaveValue('16') + await sparklineInterval.selectOption('100') + await expect(sparklineInterval).toHaveValue('100') + await sparklineInterval.selectOption('16') + + const publishInterval = page.getByTestId('publish-interval-select') + await expect(publishInterval.locator('option[value="500"]')).toHaveCount(1) + await expect(publishInterval.locator('option[value="1000"]')).toHaveCount(1) + await publishInterval.selectOption('100') + + await resumeTradingFeed(page) + + await expect + .poll(async () => { + const text = await page.getByTestId('row-update-rate').textContent() + return Number(text?.replace(/\D/g, '') ?? 0) + }) + .toBeGreaterThan(0) + await expect + .poll(async () => { + const text = await page.getByTestId('worker-messages').textContent() + return Number(text?.replace(/\D/g, '') ?? 0) + }) + .toBeGreaterThan(0) + await expect + .poll(async () => + Number(await page.getByTestId('message-rate').textContent()), + ) + .toBeGreaterThan(0) + await expect + .poll(async () => + Number(await page.getByTestId('table-render-rate').textContent()), + ) + .toBeGreaterThan(0) + + const firstPrice = page.locator('tbody tr').first().getByRole('button') + const priceBeforeUpdate = await firstPrice.textContent() + await expect + .poll(() => firstPrice.textContent()) + .not.toBe(priceBeforeUpdate) + + await page.locator('.config-section input[type="checkbox"]').first().check() + await page.getByTestId('feed-toggle').click() + await expect(page.getByTestId('feed-toggle')).toHaveText('START FEED') + await expect(page.getByTestId('feed-status')).toHaveText('FEED PAUSED') + + expect( + await page.evaluate( + () => performance.getEntriesByName('tanstack-row-model').length > 0, + ), + ).toBe(true) + + expect(errors).toEqual([]) + } finally { + await server.close() + } +}) diff --git a/examples/alpine/realtime-trading/tsconfig.json b/examples/alpine/realtime-trading/tsconfig.json new file mode 100644 index 0000000000..4986527dc3 --- /dev/null +++ b/examples/alpine/realtime-trading/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] + }, + "include": ["src", "tests/e2e", "vite.config.ts"] +} diff --git a/examples/alpine/realtime-trading/vite.config.ts b/examples/alpine/realtime-trading/vite.config.ts new file mode 100644 index 0000000000..7af6c0bce8 --- /dev/null +++ b/examples/alpine/realtime-trading/vite.config.ts @@ -0,0 +1,2 @@ +import { defineConfig } from 'vite' +export default defineConfig({ server: { port: 7777, allowedHosts: true } }) diff --git a/examples/alpine/row-pinning/package.json b/examples/alpine/row-pinning/package.json index 30a7fd095d..d339cf5b63 100644 --- a/examples/alpine/row-pinning/package.json +++ b/examples/alpine/row-pinning/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/row-selection/package.json b/examples/alpine/row-selection/package.json index 5a31ac7c61..c36143512e 100644 --- a/examples/alpine/row-selection/package.json +++ b/examples/alpine/row-selection/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/sorting-dynamic-data/package.json b/examples/alpine/sorting-dynamic-data/package.json index 0a0ec89d73..b7270bb1c5 100644 --- a/examples/alpine/sorting-dynamic-data/package.json +++ b/examples/alpine/sorting-dynamic-data/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/sorting/package.json b/examples/alpine/sorting/package.json index 8d177ed5b2..0293b0a348 100644 --- a/examples/alpine/sorting/package.json +++ b/examples/alpine/sorting/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/alpine/sub-components/package.json b/examples/alpine/sub-components/package.json index 8e0af03a04..66334d494e 100644 --- a/examples/alpine/sub-components/package.json +++ b/examples/alpine/sub-components/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/alpine-table": "^9.2.3", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/alpinejs": "^3.13.11", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/angular/aggregation/package.json b/examples/angular/aggregation/package.json index f29883eb18..54a3a4be97 100644 --- a/examples/angular/aggregation/package.json +++ b/examples/angular/aggregation/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/basic-app-table/package.json b/examples/angular/basic-app-table/package.json index 6356dd2a51..218890b733 100644 --- a/examples/angular/basic-app-table/package.json +++ b/examples/angular/basic-app-table/package.json @@ -11,23 +11,23 @@ "watch": "ng build --watch --configuration development" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", "@angular/core": "^22.1.1", "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", - "@faker-js/faker": "^10.5.0", - "@tanstack/angular-devtools": "^0.0.9", + "@faker-js/faker": "^10.6.0", + "@tanstack/angular-devtools": "^0.0.11", "@tanstack/angular-table": "^9.2.3", "@tanstack/angular-table-devtools": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/basic-dynamic-columns/package.json b/examples/angular/basic-dynamic-columns/package.json index bd249c51bd..0e9103ff36 100644 --- a/examples/angular/basic-dynamic-columns/package.json +++ b/examples/angular/basic-dynamic-columns/package.json @@ -11,7 +11,7 @@ "watch": "ng build --watch --configuration development" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,15 +19,15 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-pacer": "^0.24.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/basic-external-atoms/package.json b/examples/angular/basic-external-atoms/package.json index 721a86881d..022d969bf5 100644 --- a/examples/angular/basic-external-atoms/package.json +++ b/examples/angular/basic-external-atoms/package.json @@ -11,15 +11,15 @@ "watch": "ng build --watch --configuration development" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", "@angular/core": "^22.1.1", "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", - "@faker-js/faker": "^10.5.0", - "@tanstack/angular-devtools": "^0.0.9", + "@faker-js/faker": "^10.6.0", + "@tanstack/angular-devtools": "^0.0.11", "@tanstack/angular-store": "^0.11.1", "@tanstack/angular-table": "^9.2.3", "@tanstack/angular-table-devtools": "^9.2.3", @@ -27,8 +27,8 @@ "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/basic-external-state/package.json b/examples/angular/basic-external-state/package.json index 1c9e0ce571..cd69883ebd 100644 --- a/examples/angular/basic-external-state/package.json +++ b/examples/angular/basic-external-state/package.json @@ -11,15 +11,15 @@ "watch": "ng build --watch --configuration development" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", "@angular/core": "^22.1.1", "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", - "@faker-js/faker": "^10.5.0", - "@tanstack/angular-devtools": "^0.0.9", + "@faker-js/faker": "^10.6.0", + "@tanstack/angular-devtools": "^0.0.11", "@tanstack/angular-store": "^0.11.1", "@tanstack/angular-table": "^9.2.3", "@tanstack/angular-table-devtools": "^9.2.3", @@ -27,8 +27,8 @@ "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/basic-inject-table/package.json b/examples/angular/basic-inject-table/package.json index ac586643d9..c05f181f78 100644 --- a/examples/angular/basic-inject-table/package.json +++ b/examples/angular/basic-inject-table/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,16 +19,16 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", - "@tanstack/angular-devtools": "^0.0.9", + "@faker-js/faker": "^10.6.0", + "@tanstack/angular-devtools": "^0.0.11", "@tanstack/angular-table": "^9.2.3", "@tanstack/angular-table-devtools": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/cell-selection/package.json b/examples/angular/cell-selection/package.json index 4b79dab9f3..06b3aa2cc7 100644 --- a/examples/angular/cell-selection/package.json +++ b/examples/angular/cell-selection/package.json @@ -11,17 +11,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { - "@angular/cdk": "^22.1.0", + "@angular/cdk": "^22.1.4", "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", "@angular/core": "^22.1.1", "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", - "@tanstack/angular-devtools": "^0.0.9", + "@faker-js/faker": "^10.6.0", + "@tanstack/angular-devtools": "^0.0.11", "@tanstack/angular-hotkeys": "^0.10.0", "@tanstack/angular-table": "^9.2.3", "@tanstack/angular-table-devtools": "^9.2.3", @@ -29,8 +29,8 @@ "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/cell-spanning/package.json b/examples/angular/cell-spanning/package.json index 32dee30dd2..70023c5583 100644 --- a/examples/angular/cell-spanning/package.json +++ b/examples/angular/cell-spanning/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/column-ordering/package.json b/examples/angular/column-ordering/package.json index b38a5c87de..cc50e9cd34 100644 --- a/examples/angular/column-ordering/package.json +++ b/examples/angular/column-ordering/package.json @@ -11,7 +11,7 @@ "watch": "ng build --watch --configuration development" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/column-pinning-split/package.json b/examples/angular/column-pinning-split/package.json index c180998c4e..84a89b4f59 100644 --- a/examples/angular/column-pinning-split/package.json +++ b/examples/angular/column-pinning-split/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/column-pinning-sticky/package.json b/examples/angular/column-pinning-sticky/package.json index eea4d914ce..952bf2e1f7 100644 --- a/examples/angular/column-pinning-sticky/package.json +++ b/examples/angular/column-pinning-sticky/package.json @@ -11,7 +11,7 @@ "watch": "ng build --watch --configuration development" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/column-pinning/package.json b/examples/angular/column-pinning/package.json index 7024beff04..09eae74fcb 100644 --- a/examples/angular/column-pinning/package.json +++ b/examples/angular/column-pinning/package.json @@ -11,7 +11,7 @@ "watch": "ng build --watch --configuration development" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/column-resizing-performant/package.json b/examples/angular/column-resizing-performant/package.json index d654029172..97b11bc96d 100644 --- a/examples/angular/column-resizing-performant/package.json +++ b/examples/angular/column-resizing-performant/package.json @@ -11,7 +11,7 @@ "watch": "ng build --watch --configuration development" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/column-resizing/package.json b/examples/angular/column-resizing/package.json index 189e684ae3..830d158214 100644 --- a/examples/angular/column-resizing/package.json +++ b/examples/angular/column-resizing/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/column-sizing/package.json b/examples/angular/column-sizing/package.json index ae7a4288bd..2cc903b946 100644 --- a/examples/angular/column-sizing/package.json +++ b/examples/angular/column-sizing/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/column-visibility/package.json b/examples/angular/column-visibility/package.json index d8eedaf459..7205fc5fe9 100644 --- a/examples/angular/column-visibility/package.json +++ b/examples/angular/column-visibility/package.json @@ -11,7 +11,7 @@ "watch": "ng build --watch --configuration development" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/composable-tables/package.json b/examples/angular/composable-tables/package.json index 60f388e007..32f9b348fb 100644 --- a/examples/angular/composable-tables/package.json +++ b/examples/angular/composable-tables/package.json @@ -11,7 +11,7 @@ "watch": "ng build --watch --configuration development" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,16 +19,16 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", - "@tanstack/angular-devtools": "^0.0.9", + "@faker-js/faker": "^10.6.0", + "@tanstack/angular-devtools": "^0.0.11", "@tanstack/angular-table": "^9.2.3", "@tanstack/angular-table-devtools": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/custom-plugin/.vscode/launch.json b/examples/angular/custom-plugin/.vscode/launch.json index f30a599183..1b3018404a 100644 --- a/examples/angular/custom-plugin/.vscode/launch.json +++ b/examples/angular/custom-plugin/.vscode/launch.json @@ -7,7 +7,7 @@ "type": "chrome", "request": "launch", "preLaunchTask": "npm: start", - "url": "http://localhost:4200/" + "url": "http://localhost:7777/" } ] } diff --git a/examples/angular/custom-plugin/package.json b/examples/angular/custom-plugin/package.json index 9f344e4f61..65ca7c140b 100644 --- a/examples/angular/custom-plugin/package.json +++ b/examples/angular/custom-plugin/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -24,8 +24,8 @@ "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/editable/package.json b/examples/angular/editable/package.json index 1f1bd7ac30..858ddee4bd 100644 --- a/examples/angular/editable/package.json +++ b/examples/angular/editable/package.json @@ -11,7 +11,7 @@ "watch": "ng build --watch --configuration development" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/expanding/package.json b/examples/angular/expanding/package.json index 4964608c36..663433e284 100644 --- a/examples/angular/expanding/package.json +++ b/examples/angular/expanding/package.json @@ -11,7 +11,7 @@ "watch": "ng build --watch --configuration development" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/filters-faceted-bucketed/package.json b/examples/angular/filters-faceted-bucketed/package.json index 908ba40c3f..1a7e1101b7 100644 --- a/examples/angular/filters-faceted-bucketed/package.json +++ b/examples/angular/filters-faceted-bucketed/package.json @@ -11,7 +11,7 @@ "watch": "ng build --watch --configuration development" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/filters-faceted/package.json b/examples/angular/filters-faceted/package.json index 146b9e47c9..a01d7ea1ef 100644 --- a/examples/angular/filters-faceted/package.json +++ b/examples/angular/filters-faceted/package.json @@ -11,7 +11,7 @@ "watch": "ng build --watch --configuration development" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,15 +19,15 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-pacer": "^0.24.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/filters-fuzzy/package.json b/examples/angular/filters-fuzzy/package.json index 70e681364f..7ba7c78acd 100644 --- a/examples/angular/filters-fuzzy/package.json +++ b/examples/angular/filters-fuzzy/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,7 +19,7 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-pacer": "^0.24.0", "@tanstack/angular-table": "^9.2.3", "@tanstack/match-sorter-utils": "^9.1.2", @@ -27,8 +27,8 @@ "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/filters/package.json b/examples/angular/filters/package.json index c3ca751a74..2778218da1 100644 --- a/examples/angular/filters/package.json +++ b/examples/angular/filters/package.json @@ -11,7 +11,7 @@ "watch": "ng build --watch --configuration development" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,15 +19,15 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-pacer": "^0.24.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/grouped-aggregation/package.json b/examples/angular/grouped-aggregation/package.json index c65dc3b347..80cf11a5f6 100644 --- a/examples/angular/grouped-aggregation/package.json +++ b/examples/angular/grouped-aggregation/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/grouping/package.json b/examples/angular/grouping/package.json index 4efb6036e8..43fa1278a8 100644 --- a/examples/angular/grouping/package.json +++ b/examples/angular/grouping/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/header-groups/package.json b/examples/angular/header-groups/package.json index cb81d00702..3d79e65afd 100644 --- a/examples/angular/header-groups/package.json +++ b/examples/angular/header-groups/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/kitchen-sink/package.json b/examples/angular/kitchen-sink/package.json index 383c79c0d0..f0588c7e2a 100644 --- a/examples/angular/kitchen-sink/package.json +++ b/examples/angular/kitchen-sink/package.json @@ -11,7 +11,7 @@ "watch": "ng build --watch --configuration development" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,8 +19,8 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", - "@tanstack/angular-devtools": "^0.0.9", + "@faker-js/faker": "^10.6.0", + "@tanstack/angular-devtools": "^0.0.11", "@tanstack/angular-table": "^9.2.3", "@tanstack/angular-table-devtools": "^9.2.3", "@tanstack/match-sorter-utils": "^9.1.2", @@ -28,8 +28,8 @@ "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/pagination/package.json b/examples/angular/pagination/package.json index 51af7bc3e6..fd45fa0ec1 100644 --- a/examples/angular/pagination/package.json +++ b/examples/angular/pagination/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/realtime-trading/README.md b/examples/angular/realtime-trading/README.md new file mode 100644 index 0000000000..35bae0169a --- /dev/null +++ b/examples/angular/realtime-trading/README.md @@ -0,0 +1,243 @@ +# Angular realtime trading benchmark + +This is a standalone stress example for the current TanStack Angular Table +adapter. It combines a high-frequency synthetic market feed, immutable row +snapshots, sortable and resizable columns, range selection, dynamic Angular +cell components, optional row virtualization, and browser performance +instrumentation. + +The goal is not to reproduce an exchange. It is to provide a repeatable grid +workload in which feed generation, message delivery, state application, table +work, Angular rendering, and browser layout can be measured separately. + +## Run and verify + +```bash +pnpm --dir examples/angular/realtime-trading dev +``` + +Open `http://localhost:7777`. + +Use a production build before recording representative timings: + +```bash +pnpm --dir examples/angular/realtime-trading build +pnpm --dir examples/angular/realtime-trading test:types +pnpm --dir examples/angular/realtime-trading lint +pnpm --dir examples/angular/realtime-trading test:e2e +``` + +Development mode includes Angular assertions and extra benchmark bookkeeping, +so its absolute timings should not be compared with a production build. + +## Directory structure + +| Path | Responsibility | +| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| `src/app/feed/` | Market types, the instrument universe, feed configuration, immutable update helpers, and the Angular feed service. | +| `src/app/feed/worker/` | Worker protocol, deterministic market engine, and the module Web Worker that generates and publishes quote updates. | +| `src/app/benchmark/` | Performance monitor and the controller that connects feed lifecycle events to UI diagnostics. | +| `src/app/shell/` | Full-viewport layout, header, metrics strip, sidebar configurator, selected-instrument panel, diagnostics, and status bar. | +| `src/app/table/table-config/` | Grouped column definitions and custom quote cell components. | +| `src/app/table/view/` | Header component plus table-level selection and cell host directives. | +| `src/app/table/` | Current table, table interactions, initial column fitting, and the TanStack Virtual integration. | +| `src/app/table/worker/` | Optional experimental table-worker implementation and its row-model worker. | +| `src/app/app.ts` | Composition root; it projects only the selected table implementation into the shell. | + +The feed, benchmark, shell, and table layers are deliberately separate. The +feed can run without the benchmark monitor, and shell components inject only +the controller or service whose state they display. + +## Data and worker pipeline + +The initial configuration is 100 instruments, 10K generated samples per +second, a 20 ms delivery interval, enabled intraday charts, and 16 ms intraday +sampling. + +1. `MarketFeedService` creates a module worker and sends the current + configuration. +2. `market-feed-engine.ts` owns mutable quote state inside the worker. A + deterministic PRNG and stable instrument IDs keep runs reproducible. +3. A 16 ms generation loop accrues a fractional sample budget and applies the + requested synthetic workload to the worker-owned quotes. +4. Updated instruments are stored in a `Map` by row index. Repeated updates to + one instrument are coalesced, retaining its latest value. +5. A separate publication timer posts one message at the configured delivery + interval. Generation rate and message rate are therefore independent. +6. The main thread creates a new outer quotes array and replaces only the row + objects included in the message. Unchanged rows retain their references. +7. A session ID rejects messages from an obsolete worker configuration after a + reset or instrument-count change. + +The terms in the UI are intentionally distinct: + +- **Synthetic quote workload** is generated samples per second inside the + worker. It is not DOM events, table renders, or `postMessage` calls. +- **Worker delivery interval** is the target cadence for coalesced messages. + For example, 20 ms targets roughly 50 messages per second. +- **Row updates** is the number of unique immutable row objects applied on the + main thread. It can be lower than generated samples because of coalescing. +- **Message samples** is the number of generated samples represented by the + latest delivered batch. + +Intraday history is sampled independently of quote generation. Its interval +controls how frequently a row receives a new history array; other quote fields +can continue changing between history samples. The 25K burst command generates +and flushes one intentionally expensive batch immediately. + +The worker is analogous to an upstream WebSocket/SSE producer, but it is not a +network benchmark: serialization, browser worker messaging, main-thread state +application, and rendering are in scope; network latency is not. + +## Angular state and rendering architecture + +- `MarketFeedService` owns feed signals and worker lifecycle. +- `TradingBenchmarkController` owns benchmark-only state, selected symbol, + renderer mode, virtualization preference, and derived metrics. +- The application is zoneless and uses signal inputs, outputs, queries, + `computed`, `effect`, `DestroyRef`, and `OnPush` components. +- The root component does not subscribe to individual diagnostics. It only + chooses the normal or experimental worker-backed table and supplies the same + signal values to it. +- Custom cells are declared with `flexRenderComponent` only where an Angular + component is required. Plain columns remain plain render callbacks. +- Stable row IDs come from the instrument ID, so sorting and updates do not + make row identity depend on the current array position. + +The optional **table worker** is separate from the market-feed worker. The feed +worker always produces market data; the table worker moves the supported +row-model work off the main thread. Both table paths intentionally have their +own column configuration boundary so component render tokens stay explicit. + +## Table behavior + +The grid has 14 leaf columns grouped into Instrument, Price & Change, Order +Book, Session, and Chart sections. It supports: + +- core sorting and filtering; +- on-change column resizing, including double-click reset; +- drag-and-drop leaf-column ordering with a visible drop target; +- CSS-only row hover; +- click/modified-click row selection; +- mouse-drag cell range selection and keyboard navigation; +- custom Price, Move, Percent Change, and Sparkline components; +- a stress mode that swaps the move component type when direction changes, + intentionally exercising destruction and recreation. + +Selection events are delegated once at the table boundary by +`TradingGridSelectionDirective`. It resolves a cell from `event.composedPath()` +and data attributes, avoiding a `mousedown`/move listener per cell. The cell +directive uses signal inputs and host properties for width, focus, ARIA, and +selection-edge attributes; it does not toggle CSS classes imperatively. + +Column sizes are written to table-level CSS custom properties. Cells reference +those variables rather than recomputing an inline pixel width during every +quote update. A `ResizeObserver` expands the initial column sizes to available +width; manual resizing disables subsequent automatic fitting. + +## Full DOM and virtual rows + +The internal preference is `auto`, `tanstack`, or `none`: + +- Below 200 rows, `auto` resolves to **Full DOM**, but virtualization remains + manually selectable. +- From 200 through 1,499 rows, `auto` resolves to **TanStack Virtual**, and the + user may still switch back to Full DOM. +- At 1,500 rows or more, virtualization is forced and the control is locked to + prevent an accidental full-table mount. + +TanStack Virtual uses a fixed 32 px estimate, 10-row overscan, instrument row +IDs as item keys, cached measurements, and transformed rows inside a body-sized +spacer. Only the visible overscan window creates Angular row views. The footer +reads the virtualizer range and reports the current row interval. + +The Angular virtualizer disables application-wide ticks and schedules a local +`detectChanges()` flush for virtualizer changes. This confines scroll-driven +updates to the table instead of checking the complete application shell. + +Both Full DOM and virtual rows use `content-visibility: auto` with a matching +intrinsic block size. In Full DOM this may save browser style/layout/paint work, +but Angular still creates every row and cell. In virtual mode it is an +additional browser hint; virtualization remains the mechanism that limits +mounted views. + +## Performance decisions + +- Market calculations execute off the main thread. +- Repeated worker samples are coalesced before crossing the worker boundary. +- Immutable snapshots preserve unchanged row and history references. +- Stable row IDs and keyed `@for` blocks preserve row identity. +- High-frequency selection input is delegated at the table, not bound per + cell. +- Column widths use CSS variables and update only on sizing/order changes. +- Shell widgets read narrow signal state and do not make the root consume the + complete feed. +- Dynamic component churn is opt-in; the stable renderer is the realistic + baseline. +- Virtualization limits framework and DOM work for larger data sets. +- Benchmark metrics publish at a lower cadence than the data feed. + +`content-visibility`, worker generation, and virtualization solve different +problems. None of them prevents the table core from rebuilding a sorted or +filtered row model when its data/state inputs require it. + +## Diagnostics + +The benchmark layer observes the feed through callbacks, so it can be removed +without changing feed semantics. It reports: + +- a compact **Live health** summary in the configurator: estimated frame + callbacks over a rolling 1-second window, average market-mutation-to-DOM- + commit latency over 3 seconds, cumulative long animation frames, and + throughput as changed rows plus applied snapshots per second; +- generated worker samples, changed rows, received messages, state applies, + and completed DOM commits; +- p95/maximum commit latency over a rolling 10-second window and commits over + 16.7 ms accumulated since reset; +- long animation frames and worst duration when the browser supports the Long + Animation Frames API; +- mounted cell hosts and live/created/destroyed dynamic components; +- cell-render callbacks by column and component executions by type; +- DOM `MutationRecord` delivery rate from a `MutationObserver` limited to text, + child-list, and `class`/`style` attributes; +- core row-model call rate and average/maximum duration; +- heap information where the browser exposes it. + +The frame-rate value is an estimated `requestAnimationFrame` callback rate, not +GPU-presented FPS; its healthy ceiling follows the display refresh rate. The +latency starts at the first pending feed mutation and ends in Angular's +`afterEveryRender` callback, after Angular has committed the DOM. + +`Changed rows/s` sums the update array lengths delivered by each snapshot. +Symbols are deduplicated inside one worker message, but the same row can count +again in the next snapshot; it is therefore applied row throughput, not the +number of distinct instruments touched during the entire second. + +Renderer callback counts are not DOM mutation counts. A callback can execute +and still reuse a component/view, while a component execution count records the +framework component path itself. `MutationObserver` reports delivered records, +not a one-to-one count of browser DOM operations; record coalescing and custom +component internals affect it, and observing a hot subtree has profiling +overhead. The attribute filter excludes selection-oriented `data-*` changes to +reduce noise. Heap is Chromium-only and GC-sensitive. Growth during swap mode is +not automatically a leak: confirm retention with repeated post-GC snapshots. +The rAF loop only appends a timestamp; rolling aggregation and heap reads run at +the 500 ms metrics publication cadence. Mutation observation remains the most +intrusive diagnostic because the browser must create records for the observed +subtree. + +Use Chrome Performance/Angular DevTools for call stacks and frame analysis, and +the in-app diagnostics for controlled comparisons. Keep row count, workload, +delivery interval, renderer mode, and virtual mode identical between runs. + +## Standalone example policy + +This folder intentionally contains its own instruments, feed engine, worker, +benchmark monitor, styles, and UI instead of importing a shared demo package. +That duplication lets the example run independently and be copied to +StackBlitz. Shared concepts and some README text are therefore repeated across +adapter examples by design. + +The package pins `@tanstack/angular-table` to the repository version. The root +workspace override resolves it to `packages/angular-table` while retaining a +release-like example manifest. diff --git a/examples/angular/realtime-trading/angular.json b/examples/angular/realtime-trading/angular.json new file mode 100644 index 0000000000..5512416689 --- /dev/null +++ b/examples/angular/realtime-trading/angular.json @@ -0,0 +1,76 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "cli": { + "packageManager": "pnpm", + "analytics": false, + "cache": { + "enabled": false + } + }, + "newProjectRoot": "projects", + "projects": { + "realtime-trading": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "inlineTemplate": true, + "inlineStyle": true, + "skipTests": true + } + }, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular/build:application", + "options": { + "browser": "src/main.ts", + "tsConfig": "tsconfig.app.json", + "assets": [], + "styles": ["src/styles.css"] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kB", + "maximumError": "1MB" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "4kB", + "maximumError": "8kB" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular/build:dev-server", + "options": { + "allowedHosts": true + }, + "configurations": { + "production": { + "buildTarget": "realtime-trading:build:production" + }, + "development": { + "buildTarget": "realtime-trading:build:development" + } + }, + "defaultConfiguration": "development" + } + } + } + } +} diff --git a/examples/angular/realtime-trading/package.json b/examples/angular/realtime-trading/package.json new file mode 100644 index 0000000000..9780bca98f --- /dev/null +++ b/examples/angular/realtime-trading/package.json @@ -0,0 +1,31 @@ +{ + "name": "tanstack-angular-table-example-realtime-trading", + "scripts": { + "ng": "ng", + "start": "ng serve --port 7777", + "dev": "ng serve --port 7777", + "build": "ng build", + "watch": "ng build --watch --configuration development", + "lint": "eslint ./src", + "test:types": "tsc -p tsconfig.app.json --noEmit", + "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" + }, + "private": true, + "packageManager": "pnpm@11.24.0", + "dependencies": { + "@angular/common": "^22.1.1", + "@angular/compiler": "^22.1.1", + "@angular/core": "^22.1.1", + "@angular/platform-browser": "^22.1.1", + "@tanstack/angular-table": "^9.2.3", + "@tanstack/angular-virtual": "^6.0.3", + "rxjs": "~7.8.2", + "tslib": "^2.8.1" + }, + "devDependencies": { + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", + "@angular/compiler-cli": "^22.1.1", + "typescript": "6.0.3" + } +} diff --git a/examples/angular/realtime-trading/src/app/app.config.ts b/examples/angular/realtime-trading/src/app/app.config.ts new file mode 100644 index 0000000000..cbb47d366c --- /dev/null +++ b/examples/angular/realtime-trading/src/app/app.config.ts @@ -0,0 +1,6 @@ +import { provideBrowserGlobalErrorListeners } from '@angular/core' +import type { ApplicationConfig } from '@angular/core' + +export const appConfig: ApplicationConfig = { + providers: [provideBrowserGlobalErrorListeners()], +} diff --git a/examples/angular/realtime-trading/src/app/app.ts b/examples/angular/realtime-trading/src/app/app.ts new file mode 100644 index 0000000000..e348e9374c --- /dev/null +++ b/examples/angular/realtime-trading/src/app/app.ts @@ -0,0 +1,35 @@ +import { ChangeDetectionStrategy, Component, inject } from '@angular/core' +import { TradingBenchmarkController } from './benchmark/trading-benchmark.controller' +import { CurrentTradingTable } from './table/current-trading-table' +import { TradingShell } from './shell/trading-shell' +import { WorkerTradingTable } from './table/worker/worker-trading-table' + +@Component({ + selector: 'app-root', + imports: [CurrentTradingTable, TradingShell, WorkerTradingTable], + template: ` + + @if (controller.tableWorkerEnabled()) { + + } @else { + + } + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class App { + readonly controller = inject(TradingBenchmarkController) +} diff --git a/examples/angular/realtime-trading/src/app/benchmark/benchmark-monitor.ts b/examples/angular/realtime-trading/src/app/benchmark/benchmark-monitor.ts new file mode 100644 index 0000000000..03a22f74b0 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/benchmark/benchmark-monitor.ts @@ -0,0 +1,254 @@ +import { quoteCellLifecycle } from '../table/table-config/quote-cells' + +export interface FeedMetrics { + actualTicksPerSecond: number + rowUpdatesPerSecond: number + workerMessagesPerSecond: number + stateApplicationsPerSecond: number + supersededUpdatesPerSecond: number + totalTicks: number + rafCallbacksPerSecond: number + tableRendersPerSecond: number + lastBatchSize: number + averageRenderMs: number + p95RenderMs: number + maxRenderMs: number + slowRenders: number + longAnimationFrames: number + worstLongAnimationFrameMs: number + heapMb: number | null + componentsCreated: number + componentsDestroyed: number + workerMessages: number + lastUpdateCount: number + domMutationsPerSecond: number +} + +export const initialMetrics: FeedMetrics = { + actualTicksPerSecond: 0, + rowUpdatesPerSecond: 0, + workerMessagesPerSecond: 0, + stateApplicationsPerSecond: 0, + supersededUpdatesPerSecond: 0, + totalTicks: 0, + rafCallbacksPerSecond: 0, + tableRendersPerSecond: 0, + lastBatchSize: 0, + averageRenderMs: 0, + p95RenderMs: 0, + maxRenderMs: 0, + slowRenders: 0, + longAnimationFrames: 0, + worstLongAnimationFrameMs: 0, + heapMb: null, + componentsCreated: 0, + componentsDestroyed: 0, + workerMessages: 0, + lastUpdateCount: 0, + domMutationsPerSecond: 0, +} + +interface CommitLatencySample { + recordedAt: number + duration: number +} + +const AVERAGE_COMMIT_WINDOW_MS = 3_000 +const PERCENTILE_COMMIT_WINDOW_MS = 10_000 +const FRAME_RATE_WINDOW_MS = 1_000 + +export class BenchmarkMonitor { + readonly #runtime = { + sampleStartedAt: performance.now(), + sessionStartedAt: performance.now(), + frameTrackingStartedAt: performance.now(), + pendingRenderStartedAt: null as number | null, + renderSamples: [] as Array, + frameTimestamps: [] as Array, + totalTicks: 0, + ticksInSample: 0, + rowUpdatesInSample: 0, + workerMessagesInSample: 0, + stateApplicationsInSample: 0, + supersededUpdatesInSample: 0, + lastBatchSize: 0, + lastUpdateCount: 0, + workerMessages: 0, + tableRendersInSample: 0, + slowRenderCount: 0, + longAnimationFrameCount: 0, + worstLongAnimationFrameMs: 0, + domMutationsInSample: 0, + } + + markRenderPending(): void { + this.#runtime.pendingRenderStartedAt ??= performance.now() + } + + recordCompletedRender(): void { + const runtime = this.#runtime + if (runtime.pendingRenderStartedAt !== null) { + const renderEndedAt = performance.now() + const duration = renderEndedAt - runtime.pendingRenderStartedAt + runtime.renderSamples.push({ recordedAt: renderEndedAt, duration }) + if (duration > 16.7) runtime.slowRenderCount++ + runtime.pendingRenderStartedAt = null + runtime.tableRendersInSample++ + } + } + + recordWorkerMessage(): void { + this.#runtime.workerMessages++ + this.#runtime.workerMessagesInSample++ + } + + recordBatch( + tickCount: number, + updateCount: number, + supersededUpdateCount: number, + ): void { + const runtime = this.#runtime + runtime.lastBatchSize = tickCount + runtime.lastUpdateCount = updateCount + runtime.ticksInSample += tickCount + runtime.totalTicks += tickCount + runtime.rowUpdatesInSample += updateCount + runtime.stateApplicationsInSample++ + runtime.supersededUpdatesInSample += supersededUpdateCount + } + + recordAnimationFrame(now: number): void { + this.#runtime.frameTimestamps.push(now) + } + + recordLongAnimationFrame(duration: number, startTime: number): void { + const runtime = this.#runtime + if (startTime < runtime.sessionStartedAt) return + runtime.longAnimationFrameCount++ + runtime.worstLongAnimationFrameMs = Math.max( + runtime.worstLongAnimationFrameMs, + duration, + ) + } + + recordDomMutations(count: number): void { + this.#runtime.domMutationsInSample += count + } + + resetDomMutations(): void { + this.#runtime.domMutationsInSample = 0 + } + + shouldPublish(now: number): boolean { + return now - this.#runtime.sampleStartedAt >= 500 + } + + publish(now: number): FeedMetrics { + const runtime = this.#runtime + const sampleDuration = now - runtime.sampleStartedAt + runtime.renderSamples = runtime.renderSamples.filter( + (sample) => sample.recordedAt >= now - PERCENTILE_COMMIT_WINDOW_MS, + ) + runtime.frameTimestamps = runtime.frameTimestamps.filter( + (timestamp) => timestamp >= now - FRAME_RATE_WINDOW_MS, + ) + const averageRenderSamples = runtime.renderSamples.filter( + (sample) => sample.recordedAt >= now - AVERAGE_COMMIT_WINDOW_MS, + ) + const sortedRenderSamples = runtime.renderSamples + .map((sample) => sample.duration) + .sort((left, right) => left - right) + const averageRenderMs = + averageRenderSamples.length === 0 + ? 0 + : averageRenderSamples.reduce( + (sum, sample) => sum + sample.duration, + 0, + ) / averageRenderSamples.length + const p95Index = Math.max( + 0, + Math.ceil(sortedRenderSamples.length * 0.95) - 1, + ) + const metrics: FeedMetrics = { + actualTicksPerSecond: + sampleDuration === 0 + ? 0 + : (runtime.ticksInSample / sampleDuration) * 1_000, + rowUpdatesPerSecond: + (runtime.rowUpdatesInSample / sampleDuration) * 1_000, + workerMessagesPerSecond: + (runtime.workerMessagesInSample / sampleDuration) * 1_000, + stateApplicationsPerSecond: + (runtime.stateApplicationsInSample / sampleDuration) * 1_000, + supersededUpdatesPerSecond: + (runtime.supersededUpdatesInSample / sampleDuration) * 1_000, + totalTicks: runtime.totalTicks, + rafCallbacksPerSecond: + (runtime.frameTimestamps.length / + Math.min( + FRAME_RATE_WINDOW_MS, + Math.max(1, now - runtime.frameTrackingStartedAt), + )) * + 1_000, + tableRendersPerSecond: + (runtime.tableRendersInSample / sampleDuration) * 1_000, + lastBatchSize: runtime.lastBatchSize, + averageRenderMs, + p95RenderMs: sortedRenderSamples[p95Index] ?? 0, + maxRenderMs: sortedRenderSamples.at(-1) ?? 0, + slowRenders: runtime.slowRenderCount, + longAnimationFrames: runtime.longAnimationFrameCount, + worstLongAnimationFrameMs: runtime.worstLongAnimationFrameMs, + heapMb: readHeapSizeMb(), + componentsCreated: quoteCellLifecycle.created, + componentsDestroyed: quoteCellLifecycle.destroyed, + workerMessages: runtime.workerMessages, + lastUpdateCount: runtime.lastUpdateCount, + domMutationsPerSecond: + (runtime.domMutationsInSample / sampleDuration) * 1_000, + } + + runtime.sampleStartedAt = now + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.domMutationsInSample = 0 + runtime.tableRendersInSample = 0 + return metrics + } + + reset(): void { + const runtime = this.#runtime + runtime.sampleStartedAt = performance.now() + runtime.sessionStartedAt = runtime.sampleStartedAt + runtime.pendingRenderStartedAt = null + runtime.renderSamples = [] + runtime.frameTrackingStartedAt = runtime.sampleStartedAt + runtime.frameTimestamps = [] + runtime.totalTicks = 0 + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.lastBatchSize = 0 + runtime.lastUpdateCount = 0 + runtime.workerMessages = 0 + runtime.tableRendersInSample = 0 + runtime.slowRenderCount = 0 + runtime.longAnimationFrameCount = 0 + runtime.worstLongAnimationFrameMs = 0 + runtime.domMutationsInSample = 0 + } +} + +function readHeapSizeMb(): number | null { + const memory = ( + performance as Performance & { + memory?: { usedJSHeapSize: number } + } + ).memory + return memory ? memory.usedJSHeapSize / 1_048_576 : null +} diff --git a/examples/angular/realtime-trading/src/app/benchmark/trading-benchmark.controller.ts b/examples/angular/realtime-trading/src/app/benchmark/trading-benchmark.controller.ts new file mode 100644 index 0000000000..00b15f534b --- /dev/null +++ b/examples/angular/realtime-trading/src/app/benchmark/trading-benchmark.controller.ts @@ -0,0 +1,145 @@ +import { + DestroyRef, + Injectable, + computed, + inject, + isDevMode, + signal, +} from '@angular/core' +import { TRADING_COLUMN_COUNT } from '../table/table-config/trading-column-types' +import { MarketFeedService } from '../feed/market-feed.service' +import { + FORCED_VIRTUALIZATION_ROW_COUNT, + resolveVirtualScrollMode, +} from '../table/trading-row-virtualizer' +import { BenchmarkMonitor, initialMetrics } from './benchmark-monitor' +import type { + VirtualScrollMode, + VirtualScrollPreference, +} from '../table/trading-row-virtualizer' +import type { FeedMetrics } from './benchmark-monitor' +import type { RendererMode } from '../table/table-config/trading-column-types' + +@Injectable({ providedIn: 'root' }) +export class TradingBenchmarkController { + readonly #destroyRef = inject(DestroyRef) + readonly #monitor = new BenchmarkMonitor() + readonly #feed = inject(MarketFeedService) + readonly #longAnimationFrameObserver: PerformanceObserver | null + + readonly devMode = isDevMode() + readonly longAnimationFramesSupported = + PerformanceObserver.supportedEntryTypes.includes('long-animation-frame') + readonly tableWorkerEnabled = signal(false) + readonly renderedRowCount = signal(0) + readonly rendererMode = signal('stable') + readonly requestedVirtualScrollMode = signal('auto') + readonly selectedSymbol = signal(null) + readonly metrics = signal(initialMetrics) + readonly displayQuotes = this.#feed.quotes + readonly selectedQuote = computed(() => { + const symbol = this.selectedSymbol() + return symbol + ? (this.displayQuotes().find((quote) => quote.symbol === symbol) ?? null) + : null + }) + readonly virtualScrollForced = computed( + () => this.#feed.instrumentCount() >= FORCED_VIRTUALIZATION_ROW_COUNT, + ) + readonly virtualScrollMode = computed(() => + resolveVirtualScrollMode( + this.requestedVirtualScrollMode(), + this.#feed.instrumentCount(), + ), + ) + readonly mountedCells = computed( + () => this.renderedRowCount() * TRADING_COLUMN_COUNT, + ) + readonly liveComponents = computed(() => { + const metrics = this.metrics() + return metrics.componentsCreated - metrics.componentsDestroyed + }) + + #animationFrameId: number | null = null + + constructor() { + const stopObservingFeed = this.#feed.observe({ + messageReceived: () => this.#monitor.recordWorkerMessage(), + mutationStarted: () => this.#monitor.markRenderPending(), + batchApplied: ({ tickCount, updateCount, supersededUpdateCount }) => + this.#monitor.recordBatch( + tickCount, + updateCount, + supersededUpdateCount, + ), + renderCommitted: () => this.#monitor.recordCompletedRender(), + }) + this.#longAnimationFrameObserver = this.longAnimationFramesSupported + ? new PerformanceObserver(this.#recordLongAnimationFrames) + : null + this.#longAnimationFrameObserver?.observe({ + type: 'long-animation-frame', + }) + this.#animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + this.#destroyRef.onDestroy(() => { + stopObservingFeed() + if (this.#animationFrameId !== null) { + cancelAnimationFrame(this.#animationFrameId) + } + this.#longAnimationFrameObserver?.disconnect() + }) + } + + setRendererMode(shouldSwap: boolean): void { + this.rendererMode.set(shouldSwap ? 'swap' : 'stable') + } + + setTableWorkerEnabled(enabled: boolean): void { + this.tableWorkerEnabled.set(enabled) + } + + setVirtualScrollEnabled(enabled: boolean): void { + if (this.virtualScrollForced()) return + this.requestedVirtualScrollMode.set(enabled ? 'tanstack' : 'none') + } + + setRenderedRowCount(count: number): void { + this.renderedRowCount.set(count) + } + + recordDomMutations(count: number): void { + this.#monitor.recordDomMutations(count) + } + + resetDomMutations(): void { + this.#monitor.resetDomMutations() + } + + resetViewState(): void { + this.selectedSymbol.set(null) + this.requestedVirtualScrollMode.set('auto') + } + + resetMarket(): void { + this.#monitor.reset() + this.resetViewState() + this.metrics.set(initialMetrics) + this.#feed.reset() + } + + readonly #benchmarkFrame = (now: number): void => { + this.#monitor.recordAnimationFrame(now) + if (this.#monitor.shouldPublish(now)) { + this.metrics.set(this.#monitor.publish(now)) + } + this.#animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + } + + readonly #recordLongAnimationFrames = ( + entries: PerformanceObserverEntryList, + ): void => { + for (const entry of entries.getEntries()) { + this.#monitor.recordLongAnimationFrame(entry.duration, entry.startTime) + } + } +} diff --git a/examples/angular/realtime-trading/src/app/feed/feed-sample-rates.ts b/examples/angular/realtime-trading/src/app/feed/feed-sample-rates.ts new file mode 100644 index 0000000000..17dc2015a6 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/feed/feed-sample-rates.ts @@ -0,0 +1,33 @@ +export const feedSampleRateOptions = [ + { label: '100', value: 100 }, + { label: '250', value: 250 }, + { label: '500', value: 500 }, + { label: '1K', value: 1_000 }, + { label: '2.5K', value: 2_500 }, + { label: '5K', value: 5_000 }, + { label: '10K', value: 10_000 }, + { label: '25K', value: 25_000 }, + { label: '50K', value: 50_000 }, + { label: '100K', value: 100_000 }, +] as const + +export function feedSampleRateIndex(rate: number): number { + return feedSampleRateOptions.reduce((closestIndex, candidate, index) => { + const closest = feedSampleRateOptions[closestIndex] + return Math.abs(candidate.value - rate) < Math.abs(closest.value - rate) + ? index + : closestIndex + }, 0) +} + +export function feedSampleRateAt(stepIndex: number): number { + const index = Math.min( + feedSampleRateOptions.length - 1, + Math.max(0, Math.round(stepIndex)), + ) + return feedSampleRateOptions[index].value +} + +export function normalizeFeedSampleRate(rate: number): number { + return feedSampleRateAt(feedSampleRateIndex(rate)) +} diff --git a/examples/angular/realtime-trading/src/app/feed/market-data.ts b/examples/angular/realtime-trading/src/app/feed/market-data.ts new file mode 100644 index 0000000000..6231865d3f --- /dev/null +++ b/examples/angular/realtime-trading/src/app/feed/market-data.ts @@ -0,0 +1,38 @@ +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './worker/market-feed-protocol' + +export interface MarketQuote extends Omit { + history: ReadonlyArray +} + +export function hydrateMarketQuotes( + snapshots: Array, +): Array { + return snapshots.map((quote) => ({ + ...quote, + history: [...quote.history], + })) +} + +export function applyMarketUpdates( + quotes: Array, + updates: Array, +): Array { + const nextQuotes = [...quotes] + + for (const update of updates) { + const { index, history, ...values } = update + const previousQuote = quotes.at(index) + if (!previousQuote) continue + + nextQuotes[index] = { + ...previousQuote, + ...values, + history: history ?? previousQuote.history, + } + } + + return nextQuotes +} diff --git a/examples/angular/realtime-trading/src/app/feed/market-feed-config.ts b/examples/angular/realtime-trading/src/app/feed/market-feed-config.ts new file mode 100644 index 0000000000..9d477ed663 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/feed/market-feed-config.ts @@ -0,0 +1,15 @@ +export interface MarketFeedConfig { + readonly instrumentCount: number + readonly targetSamplesPerSecond: number + readonly publishIntervalMs: number + readonly updateSparklines: boolean + readonly sparklineSampleIntervalMs: number +} + +export const initialMarketFeedConfig: MarketFeedConfig = { + instrumentCount: 100, + targetSamplesPerSecond: 10_000, + publishIntervalMs: 20, + updateSparklines: true, + sparklineSampleIntervalMs: 16, +} diff --git a/examples/angular/realtime-trading/src/app/feed/market-feed.service.ts b/examples/angular/realtime-trading/src/app/feed/market-feed.service.ts new file mode 100644 index 0000000000..284ba12ac9 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/feed/market-feed.service.ts @@ -0,0 +1,175 @@ +import { + DestroyRef, + Injectable, + afterEveryRender, + inject, + signal, +} from '@angular/core' +import { normalizeFeedSampleRate } from './feed-sample-rates' +import { initialMarketFeedConfig } from './market-feed-config' +import { applyMarketUpdates, hydrateMarketQuotes } from './market-data' +import type { + MarketFeedCommand, + MarketFeedEvent, +} from './worker/market-feed-protocol' +import type { MarketQuote } from './market-data' + +export interface MarketFeedBatch { + tickCount: number + updateCount: number + supersededUpdateCount: number +} + +export interface MarketFeedObserver { + messageReceived?: () => void + mutationStarted?: () => void + batchApplied?: (batch: MarketFeedBatch) => void + renderCommitted?: () => void +} + +@Injectable({ providedIn: 'root' }) +export class MarketFeedService { + readonly #destroyRef = inject(DestroyRef) + readonly #worker = new Worker( + new URL('./worker/market-feed.worker', import.meta.url), + { type: 'module' }, + ) + readonly #observers = new Set() + + readonly workerReady = signal(false) + readonly running = signal(true) + readonly instrumentCount = signal(initialMarketFeedConfig.instrumentCount) + readonly targetTicksPerSecond = signal( + initialMarketFeedConfig.targetSamplesPerSecond, + ) + readonly publishIntervalMs = signal(initialMarketFeedConfig.publishIntervalMs) + readonly updateSparklines = signal(initialMarketFeedConfig.updateSparklines) + readonly sparklineSampleIntervalMs = signal( + initialMarketFeedConfig.sparklineSampleIntervalMs, + ) + readonly quotes = signal>([]) + + #feedSessionId = 0 + #renderPending = false + + constructor() { + afterEveryRender(() => this.completeRender()) + this.#worker.addEventListener('message', this.#handleWorkerMessage) + this.#worker.addEventListener('error', this.#handleWorkerError) + this.#post({ + type: 'start', + rowCount: this.instrumentCount(), + running: this.running(), + ticksPerSecond: this.targetTicksPerSecond(), + publishIntervalMs: this.publishIntervalMs(), + updateSparklines: this.updateSparklines(), + sparklineSampleIntervalMs: this.sparklineSampleIntervalMs(), + }) + this.#destroyRef.onDestroy(() => { + this.#worker.removeEventListener('message', this.#handleWorkerMessage) + this.#worker.removeEventListener('error', this.#handleWorkerError) + this.#worker.terminate() + this.#observers.clear() + }) + } + + observe(observer: MarketFeedObserver): () => void { + this.#observers.add(observer) + return () => this.#observers.delete(observer) + } + + completeRender(): void { + if (!this.#renderPending) return + + this.#renderPending = false + for (const observer of this.#observers) { + observer.renderCommitted?.() + } + } + + toggle(): void { + const running = !this.running() + this.running.set(running) + this.#post({ type: 'set-running', running }) + } + + setInstrumentCount(count: number): void { + this.instrumentCount.set(count) + this.reset() + } + + setTargetRate(rate: number): void { + const sampleRate = normalizeFeedSampleRate(rate) + this.targetTicksPerSecond.set(sampleRate) + this.#post({ type: 'set-rate', ticksPerSecond: sampleRate }) + } + + setPublishInterval(publishIntervalMs: number): void { + this.publishIntervalMs.set(publishIntervalMs) + this.#post({ type: 'set-publish-interval', intervalMs: publishIntervalMs }) + } + + setSparklineUpdates(enabled: boolean): void { + this.updateSparklines.set(enabled) + this.#post({ type: 'set-sparklines', enabled }) + } + + setSparklineSampleInterval(intervalMs: number): void { + this.sparklineSampleIntervalMs.set(intervalMs) + this.#post({ type: 'set-sparkline-interval', intervalMs }) + } + + runBurst(): void { + this.#post({ type: 'burst', tickCount: 25_000 }) + } + + reset(): void { + this.workerReady.set(false) + this.#post({ type: 'reset', rowCount: this.instrumentCount() }) + } + + readonly #handleWorkerMessage = ({ + data, + }: MessageEvent): void => { + if (data.type === 'snapshot') { + this.#feedSessionId = data.sessionId + this.#startMutation() + this.quotes.set(hydrateMarketQuotes(data.quotes)) + this.workerReady.set(true) + return + } + + if (data.sessionId !== this.#feedSessionId) return + + for (const observer of this.#observers) { + observer.messageReceived?.() + } + this.#startMutation() + this.quotes.update((quotes) => applyMarketUpdates(quotes, data.updates)) + const batch = { + tickCount: data.tickCount, + updateCount: data.updates.length, + supersededUpdateCount: data.coalescedUpdateCount, + } + for (const observer of this.#observers) { + observer.batchApplied?.(batch) + } + } + + readonly #handleWorkerError = (error: ErrorEvent): void => { + this.workerReady.set(false) + this.running.set(false) + console.error('Market feed worker failed', error) + } + + #startMutation(): void { + this.#renderPending = true + for (const observer of this.#observers) { + observer.mutationStarted?.() + } + } + + #post(command: MarketFeedCommand): void { + this.#worker.postMessage(command) + } +} diff --git a/examples/angular/realtime-trading/src/app/feed/market-instruments.ts b/examples/angular/realtime-trading/src/app/feed/market-instruments.ts new file mode 100644 index 0000000000..ac18d14ea9 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/feed/market-instruments.ts @@ -0,0 +1,742 @@ +export type MarketCode = + | 'US' + | 'NL' + | 'DE' + | 'FR' + | 'IT' + | 'ES' + | 'CH' + | 'DK' + | 'SE' + | 'FI' + | 'GB' + | 'KR' + | 'JP' + | 'HK' + | 'CA' + | 'AU' + +export type BaseInstrument = readonly [ + symbol: string, + company: string, + market: MarketCode, +] + +/** + * Current S&P 500 constituent universe used by the realtime trading examples. + * + * Source snapshot: https://github.com/datasets/s-and-p-500-companies + * Retrieved: 2026-08-15. + * Multiple share classes are intentionally represented as separate instruments. + */ +export const marketInstruments = Object.freeze([ + ['MMM', '3M', 'US'], + ['AOS', 'A. O. Smith', 'US'], + ['ABT', 'Abbott Laboratories', 'US'], + ['ABBV', 'AbbVie', 'US'], + ['ACN', 'Accenture', 'US'], + ['ADBE', 'Adobe Inc.', 'US'], + ['AMD', 'Advanced Micro Devices', 'US'], + ['AES', 'AES Corporation', 'US'], + ['AFL', 'Aflac', 'US'], + ['A', 'Agilent Technologies', 'US'], + ['APD', 'Air Products', 'US'], + ['ABNB', 'Airbnb', 'US'], + ['AKAM', 'Akamai Technologies', 'US'], + ['ALB', 'Albemarle Corporation', 'US'], + ['ARE', 'Alexandria Real Estate Equities', 'US'], + ['ALGN', 'Align Technology', 'US'], + ['ALLE', 'Allegion', 'US'], + ['LNT', 'Alliant Energy', 'US'], + ['ALL', 'Allstate', 'US'], + ['GOOGL', 'Alphabet Inc. (Class A)', 'US'], + ['GOOG', 'Alphabet Inc. (Class C)', 'US'], + ['MO', 'Altria', 'US'], + ['AMZN', 'Amazon', 'US'], + ['AMCR', 'Amcor', 'US'], + ['AEE', 'Ameren', 'US'], + ['AEP', 'American Electric Power', 'US'], + ['AXP', 'American Express', 'US'], + ['AIG', 'American International Group', 'US'], + ['AMT', 'American Tower', 'US'], + ['AWK', 'American Water Works', 'US'], + ['AMP', 'Ameriprise Financial', 'US'], + ['AME', 'Ametek', 'US'], + ['AMGN', 'Amgen', 'US'], + ['APH', 'Amphenol', 'US'], + ['ADI', 'Analog Devices', 'US'], + ['AON', 'Aon plc', 'US'], + ['APA', 'APA Corporation', 'US'], + ['APO', 'Apollo Global Management', 'US'], + ['AAPL', 'Apple Inc.', 'US'], + ['AMAT', 'Applied Materials', 'US'], + ['APP', 'AppLovin', 'US'], + ['APTV', 'Aptiv', 'US'], + ['ACGL', 'Arch Capital Group', 'US'], + ['ADM', 'Archer Daniels Midland', 'US'], + ['ARES', 'Ares Management', 'US'], + ['ANET', 'Arista Networks', 'US'], + ['AJG', 'Arthur J. Gallagher & Co.', 'US'], + ['AIZ', 'Assurant', 'US'], + ['T', 'AT&T', 'US'], + ['ATO', 'Atmos Energy', 'US'], + ['ADSK', 'Autodesk', 'US'], + ['ADP', 'Automatic Data Processing', 'US'], + ['AZO', 'AutoZone', 'US'], + ['AVB', 'AvalonBay Communities', 'US'], + ['AVY', 'Avery Dennison', 'US'], + ['AXON', 'Axon Enterprise', 'US'], + ['BKR', 'Baker Hughes', 'US'], + ['BALL', 'Ball Corporation', 'US'], + ['BAC', 'Bank of America', 'US'], + ['BAX', 'Baxter International', 'US'], + ['BDX', 'Becton Dickinson', 'US'], + ['BRK.B', 'Berkshire Hathaway', 'US'], + ['BBY', 'Best Buy', 'US'], + ['TECH', 'Bio-Techne', 'US'], + ['BIIB', 'Biogen', 'US'], + ['BLK', 'BlackRock', 'US'], + ['BX', 'Blackstone Inc.', 'US'], + ['XYZ', 'Block, Inc.', 'US'], + ['BNY', 'BNY Mellon', 'US'], + ['BA', 'Boeing', 'US'], + ['BKNG', 'Booking Holdings', 'US'], + ['BSX', 'Boston Scientific', 'US'], + ['BMY', 'Bristol Myers Squibb', 'US'], + ['AVGO', 'Broadcom', 'US'], + ['BR', 'Broadridge Financial Solutions', 'US'], + ['BRO', 'Brown & Brown', 'US'], + ['BF.B', 'Brown–Forman', 'US'], + ['BLDR', 'Builders FirstSource', 'US'], + ['BG', 'Bunge Global', 'US'], + ['BXP', 'BXP, Inc.', 'US'], + ['CHRW', 'C.H. Robinson', 'US'], + ['CDNS', 'Cadence Design Systems', 'US'], + ['CPT', 'Camden Property Trust', 'US'], + ['COF', 'Capital One', 'US'], + ['CAH', 'Cardinal Health', 'US'], + ['CCL', 'Carnival Corporation', 'US'], + ['CARR', 'Carrier Global', 'US'], + ['CVNA', 'Carvana', 'US'], + ['CASY', "Casey's", 'US'], + ['CAT', 'Caterpillar Inc.', 'US'], + ['CBOE', 'Cboe Global Markets', 'US'], + ['CBRE', 'CBRE Group', 'US'], + ['CDW', 'CDW Corporation', 'US'], + ['COR', 'Cencora', 'US'], + ['CNC', 'Centene Corporation', 'US'], + ['CNP', 'CenterPoint Energy', 'US'], + ['CF', 'CF Industries', 'US'], + ['CRL', 'Charles River Laboratories', 'US'], + ['SCHW', 'Charles Schwab Corporation', 'US'], + ['CHTR', 'Charter Communications', 'US'], + ['CVX', 'Chevron Corporation', 'US'], + ['CMG', 'Chipotle Mexican Grill', 'US'], + ['CB', 'Chubb Limited', 'US'], + ['CHD', 'Church & Dwight', 'US'], + ['CIEN', 'Ciena', 'US'], + ['CI', 'Cigna', 'US'], + ['CINF', 'Cincinnati Financial', 'US'], + ['CTAS', 'Cintas', 'US'], + ['CSCO', 'Cisco', 'US'], + ['C', 'Citigroup', 'US'], + ['CFG', 'Citizens Financial Group', 'US'], + ['CLX', 'Clorox', 'US'], + ['CME', 'CME Group', 'US'], + ['CMS', 'CMS Energy', 'US'], + ['KO', 'Coca-Cola Company (The)', 'US'], + ['CTSH', 'Cognizant', 'US'], + ['COHR', 'Coherent Corp.', 'US'], + ['COIN', 'Coinbase', 'US'], + ['CL', 'Colgate-Palmolive', 'US'], + ['CMCSA', 'Comcast', 'US'], + ['FIX', 'Comfort Systems USA', 'US'], + ['COP', 'ConocoPhillips', 'US'], + ['ED', 'Consolidated Edison', 'US'], + ['STZ', 'Constellation Brands', 'US'], + ['CEG', 'Constellation Energy', 'US'], + ['COO', 'Cooper Companies (The)', 'US'], + ['CPRT', 'Copart', 'US'], + ['GLW', 'Corning Inc.', 'US'], + ['CPAY', 'Corpay', 'US'], + ['CTVA', 'Corteva', 'US'], + ['CSGP', 'CoStar Group', 'US'], + ['COST', 'Costco', 'US'], + ['CRH', 'CRH plc', 'US'], + ['CRWD', 'CrowdStrike', 'US'], + ['CCI', 'Crown Castle', 'US'], + ['CSX', 'CSX Corporation', 'US'], + ['CMI', 'Cummins', 'US'], + ['CVS', 'CVS Health', 'US'], + ['DHR', 'Danaher Corporation', 'US'], + ['DRI', 'Darden Restaurants', 'US'], + ['DDOG', 'Datadog', 'US'], + ['DVA', 'DaVita', 'US'], + ['DECK', 'Deckers Brands', 'US'], + ['DE', 'Deere & Company', 'US'], + ['DELL', 'Dell Technologies', 'US'], + ['DAL', 'Delta Air Lines', 'US'], + ['DVN', 'Devon Energy', 'US'], + ['DXCM', 'Dexcom', 'US'], + ['FANG', 'Diamondback Energy', 'US'], + ['DLR', 'Digital Realty', 'US'], + ['DG', 'Dollar General', 'US'], + ['DLTR', 'Dollar Tree', 'US'], + ['D', 'Dominion Energy', 'US'], + ['DPZ', "Domino's", 'US'], + ['DASH', 'DoorDash', 'US'], + ['DOV', 'Dover Corporation', 'US'], + ['DOW', 'Dow Inc.', 'US'], + ['DHI', 'D. R. Horton', 'US'], + ['DTE', 'DTE Energy', 'US'], + ['DUK', 'Duke Energy', 'US'], + ['DD', 'DuPont', 'US'], + ['ETN', 'Eaton Corporation', 'US'], + ['EBAY', 'eBay Inc.', 'US'], + ['ECHO', 'EchoStar', 'US'], + ['ECL', 'Ecolab', 'US'], + ['EIX', 'Edison International', 'US'], + ['EW', 'Edwards Lifesciences', 'US'], + ['ELV', 'Elevance Health', 'US'], + ['EME', 'Emcor', 'US'], + ['EMR', 'Emerson Electric', 'US'], + ['ETR', 'Entergy', 'US'], + ['EOG', 'EOG Resources', 'US'], + ['EQT', 'EQT Corporation', 'US'], + ['EFX', 'Equifax', 'US'], + ['EQIX', 'Equinix', 'US'], + ['EQR', 'Equity Residential', 'US'], + ['ERIE', 'Erie Indemnity', 'US'], + ['ESS', 'Essex Property Trust', 'US'], + ['EL', 'Estée Lauder Companies (The)', 'US'], + ['EG', 'Everest Group', 'US'], + ['EVRG', 'Evergy', 'US'], + ['ES', 'Eversource Energy', 'US'], + ['EXC', 'Exelon', 'US'], + ['EXE', 'Expand Energy', 'US'], + ['EXPE', 'Expedia Group', 'US'], + ['EXPD', 'Expeditors International', 'US'], + ['EXR', 'Extra Space Storage', 'US'], + ['XOM', 'ExxonMobil', 'US'], + ['FFIV', 'F5, Inc.', 'US'], + ['FDS', 'FactSet', 'US'], + ['FICO', 'Fair Isaac', 'US'], + ['FAST', 'Fastenal', 'US'], + ['FRT', 'Federal Realty Investment Trust', 'US'], + ['FDX', 'FedEx', 'US'], + ['FDXF', 'FedEx Freight', 'US'], + ['FERG', 'Ferguson Enterprises', 'US'], + ['FIS', 'Fidelity National Information Services', 'US'], + ['FITB', 'Fifth Third Bancorp', 'US'], + ['FSLR', 'First Solar', 'US'], + ['FE', 'FirstEnergy', 'US'], + ['FISV', 'Fiserv', 'US'], + ['FLEX', 'Flex Ltd.', 'US'], + ['F', 'Ford Motor Company', 'US'], + ['FTNT', 'Fortinet', 'US'], + ['FTV', 'Fortive', 'US'], + ['FOXA', 'Fox Corporation (Class A)', 'US'], + ['FOX', 'Fox Corporation (Class B)', 'US'], + ['BEN', 'Franklin Resources', 'US'], + ['FCX', 'Freeport-McMoRan', 'US'], + ['GRMN', 'Garmin', 'US'], + ['IT', 'Gartner', 'US'], + ['GE', 'GE Aerospace', 'US'], + ['GEHC', 'GE HealthCare', 'US'], + ['GEV', 'GE Vernova', 'US'], + ['GEN', 'Gen Digital', 'US'], + ['GNRC', 'Generac', 'US'], + ['GD', 'General Dynamics', 'US'], + ['GIS', 'General Mills', 'US'], + ['GM', 'General Motors', 'US'], + ['GPC', 'Genuine Parts Company', 'US'], + ['GILD', 'Gilead Sciences', 'US'], + ['GPN', 'Global Payments', 'US'], + ['GL', 'Globe Life', 'US'], + ['GDDY', 'GoDaddy', 'US'], + ['GS', 'Goldman Sachs', 'US'], + ['HAL', 'Halliburton', 'US'], + ['HIG', 'Hartford (The)', 'US'], + ['HAS', 'Hasbro', 'US'], + ['HCA', 'HCA Healthcare', 'US'], + ['DOC', 'Healthpeak Properties', 'US'], + ['HSIC', 'Henry Schein', 'US'], + ['HSY', 'Hershey Company (The)', 'US'], + ['HPE', 'Hewlett Packard Enterprise', 'US'], + ['HLT', 'Hilton Worldwide', 'US'], + ['HD', 'Home Depot (The)', 'US'], + ['HONA', 'Honeywell Aerospace', 'US'], + ['HON', 'Honeywell Technologies', 'US'], + ['HRL', 'Hormel Foods', 'US'], + ['HST', 'Host Hotels & Resorts', 'US'], + ['HWM', 'Howmet Aerospace', 'US'], + ['HPQ', 'HP Inc.', 'US'], + ['HUBB', 'Hubbell Incorporated', 'US'], + ['HUM', 'Humana', 'US'], + ['HBAN', 'Huntington Bancshares', 'US'], + ['HII', 'Huntington Ingalls Industries', 'US'], + ['IBM', 'IBM', 'US'], + ['IEX', 'IDEX Corporation', 'US'], + ['IDXX', 'Idexx Laboratories', 'US'], + ['ITW', 'Illinois Tool Works', 'US'], + ['INCY', 'Incyte', 'US'], + ['IR', 'Ingersoll Rand', 'US'], + ['PODD', 'Insulet Corporation', 'US'], + ['INTC', 'Intel', 'US'], + ['IBKR', 'Interactive Brokers', 'US'], + ['ICE', 'Intercontinental Exchange', 'US'], + ['IFF', 'International Flavors & Fragrances', 'US'], + ['IP', 'International Paper', 'US'], + ['INTU', 'Intuit', 'US'], + ['ISRG', 'Intuitive Surgical', 'US'], + ['IVZ', 'Invesco', 'US'], + ['INVH', 'Invitation Homes', 'US'], + ['IQV', 'IQVIA', 'US'], + ['IRM', 'Iron Mountain', 'US'], + ['JBHT', 'J.B. Hunt', 'US'], + ['JBL', 'Jabil', 'US'], + ['JKHY', 'Jack Henry & Associates', 'US'], + ['J', 'Jacobs Solutions', 'US'], + ['JNJ', 'Johnson & Johnson', 'US'], + ['JCI', 'Johnson Controls', 'US'], + ['JPM', 'JPMorgan Chase', 'US'], + ['KVUE', 'Kenvue', 'US'], + ['KDP', 'Keurig Dr Pepper', 'US'], + ['KEY', 'KeyCorp', 'US'], + ['KEYS', 'Keysight Technologies', 'US'], + ['KMB', 'Kimberly-Clark', 'US'], + ['KIM', 'Kimco Realty', 'US'], + ['KMI', 'Kinder Morgan', 'US'], + ['KKR', 'KKR & Co.', 'US'], + ['KLAC', 'KLA Corporation', 'US'], + ['KHC', 'Kraft Heinz', 'US'], + ['KR', 'Kroger', 'US'], + ['LHX', 'L3Harris', 'US'], + ['LH', 'Labcorp', 'US'], + ['LRCX', 'Lam Research', 'US'], + ['LVS', 'Las Vegas Sands', 'US'], + ['LDOS', 'Leidos', 'US'], + ['LEN', 'Lennar', 'US'], + ['LII', 'Lennox International', 'US'], + ['LLY', 'Lilly (Eli)', 'US'], + ['LIN', 'Linde plc', 'US'], + ['LYV', 'Live Nation Entertainment', 'US'], + ['LMT', 'Lockheed Martin', 'US'], + ['L', 'Loews Corporation', 'US'], + ['LOW', "Lowe's", 'US'], + ['LULU', 'Lululemon Athletica', 'US'], + ['LITE', 'Lumentum', 'US'], + ['LYB', 'LyondellBasell', 'US'], + ['MTB', 'M&T Bank', 'US'], + ['MPC', 'Marathon Petroleum', 'US'], + ['MAR', 'Marriott International', 'US'], + ['MRSH', 'Marsh McLennan', 'US'], + ['MLM', 'Martin Marietta Materials', 'US'], + ['MRVL', 'Marvell Technology', 'US'], + ['MAS', 'Masco', 'US'], + ['MA', 'Mastercard', 'US'], + ['MKC', 'McCormick & Company', 'US'], + ['MCD', "McDonald's", 'US'], + ['MCK', 'McKesson Corporation', 'US'], + ['MDT', 'Medtronic', 'US'], + ['MRK', 'Merck & Co.', 'US'], + ['META', 'Meta Platforms', 'US'], + ['MET', 'MetLife', 'US'], + ['MTD', 'Mettler Toledo', 'US'], + ['MGM', 'MGM Resorts', 'US'], + ['MCHP', 'Microchip Technology', 'US'], + ['MU', 'Micron Technology', 'US'], + ['MSFT', 'Microsoft', 'US'], + ['MAA', 'Mid-America Apartment Communities', 'US'], + ['MRNA', 'Moderna', 'US'], + ['TAP', 'Molson Coors Beverage Company', 'US'], + ['MDLZ', 'Mondelez International', 'US'], + ['MPWR', 'Monolithic Power Systems', 'US'], + ['MNST', 'Monster Beverage', 'US'], + ['MCO', "Moody's Corporation", 'US'], + ['MS', 'Morgan Stanley', 'US'], + ['MOS', 'Mosaic Company (The)', 'US'], + ['MSI', 'Motorola Solutions', 'US'], + ['MSCI', 'MSCI', 'US'], + ['NDAQ', 'Nasdaq, Inc.', 'US'], + ['NTAP', 'NetApp', 'US'], + ['NFLX', 'Netflix', 'US'], + ['NEM', 'Newmont', 'US'], + ['NWSA', 'News Corp (Class A)', 'US'], + ['NWS', 'News Corp (Class B)', 'US'], + ['NEE', 'NextEra Energy', 'US'], + ['NKE', 'Nike, Inc.', 'US'], + ['NI', 'NiSource', 'US'], + ['NDSN', 'Nordson Corporation', 'US'], + ['NSC', 'Norfolk Southern', 'US'], + ['NTRS', 'Northern Trust', 'US'], + ['NOC', 'Northrop Grumman', 'US'], + ['NCLH', 'Norwegian Cruise Line Holdings', 'US'], + ['NRG', 'NRG Energy', 'US'], + ['NUE', 'Nucor', 'US'], + ['NVDA', 'Nvidia', 'US'], + ['NVR', 'NVR, Inc.', 'US'], + ['NXPI', 'NXP Semiconductors', 'US'], + ['ORLY', "O'Reilly Automotive", 'US'], + ['OXY', 'Occidental Petroleum', 'US'], + ['ODFL', 'Old Dominion', 'US'], + ['OMC', 'Omnicom Group', 'US'], + ['ON', 'ON Semiconductor', 'US'], + ['OKE', 'Oneok', 'US'], + ['ORCL', 'Oracle Corporation', 'US'], + ['OTIS', 'Otis Worldwide', 'US'], + ['PCAR', 'Paccar', 'US'], + ['PKG', 'Packaging Corporation of America', 'US'], + ['PLTR', 'Palantir Technologies', 'US'], + ['PANW', 'Palo Alto Networks', 'US'], + ['PSKY', 'Paramount Skydance Corporation', 'US'], + ['PH', 'Parker Hannifin', 'US'], + ['PAYX', 'Paychex', 'US'], + ['PYPL', 'PayPal', 'US'], + ['PNR', 'Pentair', 'US'], + ['PEP', 'PepsiCo', 'US'], + ['PFE', 'Pfizer', 'US'], + ['PCG', 'PG&E Corporation', 'US'], + ['PM', 'Philip Morris International', 'US'], + ['PSX', 'Phillips 66', 'US'], + ['PNW', 'Pinnacle West Capital', 'US'], + ['PNC', 'PNC Financial Services', 'US'], + ['PPG', 'PPG Industries', 'US'], + ['PPL', 'PPL Corporation', 'US'], + ['PFG', 'Principal Financial Group', 'US'], + ['PG', 'Procter & Gamble', 'US'], + ['PGR', 'Progressive Corporation', 'US'], + ['PLD', 'Prologis', 'US'], + ['PRU', 'Prudential Financial', 'US'], + ['PEG', 'Public Service Enterprise Group', 'US'], + ['PTC', 'PTC Inc.', 'US'], + ['PSA', 'Public Storage', 'US'], + ['PHM', 'PulteGroup', 'US'], + ['PWR', 'Quanta Services', 'US'], + ['QCOM', 'Qualcomm', 'US'], + ['DGX', 'Quest Diagnostics', 'US'], + ['Q', 'Qnity Electronics', 'US'], + ['RL', 'Ralph Lauren Corporation', 'US'], + ['RJF', 'Raymond James Financial', 'US'], + ['RTX', 'RTX Corporation', 'US'], + ['O', 'Realty Income', 'US'], + ['REG', 'Regency Centers', 'US'], + ['REGN', 'Regeneron Pharmaceuticals', 'US'], + ['RF', 'Regions Financial Corporation', 'US'], + ['RSG', 'Republic Services', 'US'], + ['RMD', 'ResMed|', 'US'], + ['RVTY', 'Revvity', 'US'], + ['HOOD', 'Robinhood Markets', 'US'], + ['ROK', 'Rockwell Automation', 'US'], + ['ROL', 'Rollins, Inc.', 'US'], + ['ROP', 'Roper Technologies', 'US'], + ['ROST', 'Ross Stores', 'US'], + ['RCL', 'Royal Caribbean Group', 'US'], + ['SPGI', 'S&P Global', 'US'], + ['CRM', 'Salesforce', 'US'], + ['SNDK', 'Sandisk', 'US'], + ['SBAC', 'SBA Communications', 'US'], + ['SLB', 'Schlumberger', 'US'], + ['STX', 'Seagate Technology', 'US'], + ['SRE', 'Sempra', 'US'], + ['NOW', 'ServiceNow', 'US'], + ['SHW', 'Sherwin-Williams', 'US'], + ['SPG', 'Simon Property Group', 'US'], + ['SWKS', 'Skyworks Solutions', 'US'], + ['SJM', 'J.M. Smucker Company (The)', 'US'], + ['SW', 'Smurfit Westrock', 'US'], + ['SNA', 'Snap-on', 'US'], + ['SOLV', 'Solventum', 'US'], + ['SO', 'Southern Company', 'US'], + ['LUV', 'Southwest Airlines', 'US'], + ['SWK', 'Stanley Black & Decker', 'US'], + ['SBUX', 'Starbucks', 'US'], + ['STT', 'State Street Corporation', 'US'], + ['STLD', 'Steel Dynamics', 'US'], + ['STE', 'Steris', 'US'], + ['SYK', 'Stryker Corporation', 'US'], + ['SMCI', 'Supermicro', 'US'], + ['SYF', 'Synchrony Financial', 'US'], + ['SNPS', 'Synopsys', 'US'], + ['SYY', 'Sysco', 'US'], + ['TMUS', 'T-Mobile US', 'US'], + ['TROW', 'T. Rowe Price', 'US'], + ['TTWO', 'Take-Two Interactive', 'US'], + ['TPR', 'Tapestry, Inc.', 'US'], + ['TRGP', 'Targa Resources', 'US'], + ['TGT', 'Target Corporation', 'US'], + ['TEL', 'TE Connectivity', 'US'], + ['TDY', 'Teledyne Technologies', 'US'], + ['TER', 'Teradyne', 'US'], + ['TSLA', 'Tesla, Inc.', 'US'], + ['TXN', 'Texas Instruments', 'US'], + ['TPL', 'Texas Pacific Land Corporation', 'US'], + ['TXT', 'Textron', 'US'], + ['TMO', 'Thermo Fisher Scientific', 'US'], + ['TJX', 'TJX Companies', 'US'], + ['TKO', 'TKO Group Holdings', 'US'], + ['TTD', 'Trade Desk (The)', 'US'], + ['TSCO', 'Tractor Supply', 'US'], + ['TT', 'Trane Technologies', 'US'], + ['TDG', 'TransDigm Group', 'US'], + ['TRV', 'Travelers Companies (The)', 'US'], + ['TRMB', 'Trimble Inc.', 'US'], + ['TFC', 'Truist Financial', 'US'], + ['TYL', 'Tyler Technologies', 'US'], + ['TSN', 'Tyson Foods', 'US'], + ['USB', 'U.S. Bancorp', 'US'], + ['UBER', 'Uber', 'US'], + ['UDR', 'UDR, Inc.', 'US'], + ['ULTA', 'Ulta Beauty', 'US'], + ['UNP', 'Union Pacific Corporation', 'US'], + ['UAL', 'United Airlines Holdings', 'US'], + ['UPS', 'United Parcel Service', 'US'], + ['URI', 'United Rentals', 'US'], + ['UNH', 'UnitedHealth Group', 'US'], + ['UHS', 'Universal Health Services', 'US'], + ['VLO', 'Valero Energy', 'US'], + ['VEEV', 'Veeva Systems', 'US'], + ['VTR', 'Ventas', 'US'], + ['VLTO', 'Veralto', 'US'], + ['VRSN', 'Verisign', 'US'], + ['VRSK', 'Verisk Analytics', 'US'], + ['VZ', 'Verizon', 'US'], + ['VRTX', 'Vertex Pharmaceuticals', 'US'], + ['VRT', 'Vertiv', 'US'], + ['VTRS', 'Viatris', 'US'], + ['VICI', 'Vici Properties', 'US'], + ['V', 'Visa Inc.', 'US'], + ['VST', 'Vistra Corp.', 'US'], + ['VMC', 'Vulcan Materials Company', 'US'], + ['WRB', 'W. R. Berkley Corporation', 'US'], + ['GWW', 'W. W. Grainger', 'US'], + ['WAB', 'Wabtec', 'US'], + ['WMT', 'Walmart', 'US'], + ['DIS', 'Walt Disney Company (The)', 'US'], + ['WBD', 'Warner Bros. Discovery', 'US'], + ['WM', 'Waste Management', 'US'], + ['WAT', 'Waters Corporation', 'US'], + ['WEC', 'WEC Energy Group', 'US'], + ['WFC', 'Wells Fargo', 'US'], + ['WELL', 'Welltower', 'US'], + ['WST', 'West Pharmaceutical Services', 'US'], + ['WDC', 'Western Digital', 'US'], + ['WY', 'Weyerhaeuser', 'US'], + ['WSM', 'Williams-Sonoma, Inc.', 'US'], + ['WMB', 'Williams Companies', 'US'], + ['WTW', 'Willis Towers Watson', 'US'], + ['WDAY', 'Workday, Inc.', 'US'], + ['WYNN', 'Wynn Resorts', 'US'], + ['XEL', 'Xcel Energy', 'US'], + ['XYL', 'Xylem Inc.', 'US'], + ['YUM', 'Yum! Brands', 'US'], + ['ZBRA', 'Zebra Technologies', 'US'], + ['ZBH', 'Zimmer Biomet', 'US'], + ['ZTS', 'Zoetis', 'US'], +]) + +/** + * Representative liquid international listings used to diversify the fixture. + * Symbols use their local-market form and the third tuple value is an ISO-style + * country/market code, rather than a trading currency or exchange MIC. + * + * References checked 2026-08-15: STOXX Europe 50, KRX KOSPI market, + * JPX TOPIX Core30, and HKEX index constituent materials. + */ +const europeanInstruments = Object.freeze([ + ['ASML', 'ASML Holding', 'NL'], + ['INGA', 'ING Group', 'NL'], + ['ADYEN', 'Adyen', 'NL'], + ['PHIA', 'Philips', 'NL'], + ['HEIA', 'Heineken', 'NL'], + ['SAP', 'SAP', 'DE'], + ['SIE', 'Siemens', 'DE'], + ['ALV', 'Allianz', 'DE'], + ['DTE', 'Deutsche Telekom', 'DE'], + ['MBG', 'Mercedes-Benz Group', 'DE'], + ['BMW', 'BMW', 'DE'], + ['BAS', 'BASF', 'DE'], + ['MUV2', 'Munich Re', 'DE'], + ['VOW3', 'Volkswagen Preference', 'DE'], + ['IFX', 'Infineon Technologies', 'DE'], + ['MC', 'LVMH', 'FR'], + ['OR', "L'Oréal", 'FR'], + ['AIR', 'Airbus', 'FR'], + ['SU', 'Schneider Electric', 'FR'], + ['TTE', 'TotalEnergies', 'FR'], + ['SAN', 'Sanofi', 'FR'], + ['BNP', 'BNP Paribas', 'FR'], + ['CS', 'AXA', 'FR'], + ['DG', 'Vinci', 'FR'], + ['ENEL', 'Enel', 'IT'], + ['ENI', 'Eni', 'IT'], + ['ISP', 'Intesa Sanpaolo', 'IT'], + ['UCG', 'UniCredit', 'IT'], + ['STLAM', 'Stellantis', 'IT'], + ['SAN', 'Banco Santander', 'ES'], + ['IBE', 'Iberdrola', 'ES'], + ['ITX', 'Inditex', 'ES'], + ['BBVA', 'BBVA', 'ES'], + ['NESN', 'Nestlé', 'CH'], + ['ROG', 'Roche Holding', 'CH'], + ['NOVN', 'Novartis', 'CH'], + ['UBSG', 'UBS Group', 'CH'], + ['NOVO-B', 'Novo Nordisk', 'DK'], + ['MAERSK-B', 'A.P. Moller - Maersk', 'DK'], + ['VOLV-B', 'Volvo', 'SE'], + ['ERIC-B', 'Ericsson', 'SE'], + ['NOKIA', 'Nokia', 'FI'], + ['SHEL', 'Shell', 'GB'], + ['AZN', 'AstraZeneca', 'GB'], + ['HSBA', 'HSBC Holdings', 'GB'], + ['ULVR', 'Unilever', 'GB'], + ['LSEG', 'London Stock Exchange Group', 'GB'], +]) + +const europeanMarketCodes = Object.freeze([ + 'NL', + 'DE', + 'FR', + 'IT', + 'ES', + 'CH', + 'DK', + 'SE', + 'FI', + 'GB', +]) + +const europeanMarketGroups = Object.freeze( + europeanMarketCodes.map((market) => + europeanInstruments.filter(([, , instrumentMarket]) => + Object.is(instrumentMarket, market), + ), + ), +) + +const interleavedEuropeanInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...europeanMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + europeanMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const southKoreanInstruments = Object.freeze([ + ['005930', 'Samsung Electronics', 'KR'], + ['000660', 'SK hynix', 'KR'], + ['373220', 'LG Energy Solution', 'KR'], + ['207940', 'Samsung Biologics', 'KR'], + ['005380', 'Hyundai Motor', 'KR'], + ['000270', 'Kia', 'KR'], + ['068270', 'Celltrion', 'KR'], + ['105560', 'KB Financial Group', 'KR'], + ['055550', 'Shinhan Financial Group', 'KR'], + ['035420', 'NAVER', 'KR'], + ['035720', 'Kakao', 'KR'], + ['006400', 'Samsung SDI', 'KR'], + ['051910', 'LG Chem', 'KR'], + ['012330', 'Hyundai Mobis', 'KR'], + ['066570', 'LG Electronics', 'KR'], +]) + +const japaneseInstruments = Object.freeze([ + ['8306', 'Mitsubishi UFJ Financial Group', 'JP'], + ['7203', 'Toyota Motor', 'JP'], + ['6501', 'Hitachi', 'JP'], + ['8316', 'Sumitomo Mitsui Financial Group', 'JP'], + ['6758', 'Sony Group', 'JP'], + ['8058', 'Mitsubishi Corporation', 'JP'], + ['9984', 'SoftBank Group', 'JP'], + ['8035', 'Tokyo Electron', 'JP'], + ['8411', 'Mizuho Financial Group', 'JP'], + ['8031', 'Mitsui & Co.', 'JP'], + ['6861', 'Keyence', 'JP'], + ['7974', 'Nintendo', 'JP'], + ['6098', 'Recruit Holdings', 'JP'], + ['9432', 'Nippon Telegraph and Telephone', 'JP'], + ['4063', 'Shin-Etsu Chemical', 'JP'], +]) + +const hongKongInstruments = Object.freeze([ + ['0700', 'Tencent Holdings', 'HK'], + ['9988', 'Alibaba Group', 'HK'], + ['1810', 'Xiaomi', 'HK'], + ['3690', 'Meituan', 'HK'], + ['0941', 'China Mobile', 'HK'], + ['1211', 'BYD Company', 'HK'], + ['1299', 'AIA Group', 'HK'], + ['0388', 'Hong Kong Exchanges and Clearing', 'HK'], + ['0005', 'HSBC Holdings', 'HK'], + ['2318', 'Ping An Insurance', 'HK'], +]) + +const canadianInstruments = Object.freeze([ + ['RY', 'Royal Bank of Canada', 'CA'], + ['TD', 'Toronto-Dominion Bank', 'CA'], + ['SHOP', 'Shopify', 'CA'], + ['ENB', 'Enbridge', 'CA'], + ['CNR', 'Canadian National Railway', 'CA'], + ['CP', 'Canadian Pacific Kansas City', 'CA'], + ['BMO', 'Bank of Montreal', 'CA'], + ['CSU', 'Constellation Software', 'CA'], +]) + +const australianInstruments = Object.freeze([ + ['BHP', 'BHP Group', 'AU'], + ['CBA', 'Commonwealth Bank of Australia', 'AU'], + ['CSL', 'CSL', 'AU'], + ['NAB', 'National Australia Bank', 'AU'], + ['WBC', 'Westpac Banking Corporation', 'AU'], + ['ANZ', 'ANZ Group Holdings', 'AU'], + ['WES', 'Wesfarmers', 'AU'], + ['MQG', 'Macquarie Group', 'AU'], +]) + +const internationalMarketGroups = Object.freeze([ + interleavedEuropeanInstruments, + southKoreanInstruments, + japaneseInstruments, + hongKongInstruments, + canadianInstruments, + australianInstruments, +]) + +export const internationalInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...internationalMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + internationalMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const INTERNATIONAL_INSERTION_INTERVAL = 3 + +/** + * U.S. and international instruments are interleaved so ordinary benchmark + * sizes exercise multiple symbol formats and market labels. + */ +export const globalInstruments = Object.freeze( + marketInstruments.flatMap((instrument, index) => { + const internationalInstrument = + index % INTERNATIONAL_INSERTION_INTERVAL === 0 + ? internationalInstruments[index / INTERNATIONAL_INSERTION_INTERVAL] + : undefined + + return internationalInstrument + ? [instrument, internationalInstrument] + : [instrument] + }), +) as unknown as ReadonlyArray diff --git a/examples/angular/realtime-trading/src/app/feed/worker/market-feed-engine.ts b/examples/angular/realtime-trading/src/app/feed/worker/market-feed-engine.ts new file mode 100644 index 0000000000..86a68e2f64 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/feed/worker/market-feed-engine.ts @@ -0,0 +1,177 @@ +import { globalInstruments } from '../market-instruments' +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const INITIAL_MARKET_SEED = 0x4d41524b +const LIVE_FEED_SEED = 0x5449434b + +export class MarketFeedEngine { + #quotes: Array = [] + #lastHistorySampledAt = new Uint32Array(0) + #random = createRandom(2_026) + #rowCursor = 0 + #tickIndex = 0 + + reset(count: number): Array { + const random = createRandom(INITIAL_MARKET_SEED ^ count) + const createdAt = Date.now() + + this.#quotes = Array.from({ length: count }, (_, index) => { + const [baseSymbol, company, market] = + globalInstruments[index % globalInstruments.length] + const series = Math.floor(index / globalInstruments.length) + const symbol = series === 0 ? baseSymbol : `${baseSymbol}${series}` + const previousClose = roundPrice(20 + random() * 480) + const open = roundPrice(previousClose * (1 + (random() - 0.5) * 0.016)) + const spread = Math.max(0.01, open * (0.0002 + random() * 0.0004)) + const history = Array.from({ length: 24 }, (_, historyIndex) => + roundPrice( + open * + (1 + Math.sin(historyIndex / 4) * 0.002 + (random() - 0.5) * 0.001), + ), + ) + const volume = Math.floor(50_000 + random() * 2_000_000) + const lastSize = Math.floor(10 + random() * 5_000) + + return { + id: `instrument-${index}`, + symbol, + company, + venue: market, + previousClose, + open, + high: open, + low: open, + price: open, + bid: roundPrice(open - spread / 2), + ask: roundPrice(open + spread / 2), + bidSize: Math.floor(100 + random() * 25_000), + askSize: Math.floor(100 + random() * 25_000), + lastSize, + lastMove: 0, + lastUpdatedAt: createdAt, + volume, + turnover: roundMoney(open * volume), + history, + } + }) + + this.#random = createRandom(LIVE_FEED_SEED ^ count) + this.#rowCursor = 0 + this.#lastHistorySampledAt = new Uint32Array(count) + this.#lastHistorySampledAt.fill(createdAt >>> 0) + + return this.#quotes.map((quote) => ({ + ...quote, + history: [...quote.history], + })) + } + + applyTicks( + tickCount: number, + updateSparklines: boolean, + sparklineSampleIntervalMs: number, + ): Array { + if (this.#quotes.length === 0 || tickCount <= 0) return [] + + const updatedAt = Date.now() + const sampledAt = updatedAt >>> 0 + const sampleIntervalMs = Math.max(16, sparklineSampleIntervalMs) + const updatedQuotes = new Map() + const stride = 97 + + this.#tickIndex = 0 + while (this.#tickIndex < tickCount) { + this.#rowCursor = (this.#rowCursor + stride) % this.#quotes.length + const quote = this.#quotes[this.#rowCursor] + const lastSampledAt = this.#lastHistorySampledAt[this.#rowCursor] + const shouldUpdateHistory = + updateSparklines && + (sampledAt - lastSampledAt) >>> 0 >= sampleIntervalMs + + if (shouldUpdateHistory) { + this.#lastHistorySampledAt[this.#rowCursor] = sampledAt + } + + this.#applyTick(quote, shouldUpdateHistory, updatedAt) + + const previousUpdate = updatedQuotes.get(this.#rowCursor) + updatedQuotes.set(this.#rowCursor, { + index: this.#rowCursor, + price: quote.price, + bid: quote.bid, + ask: quote.ask, + bidSize: quote.bidSize, + askSize: quote.askSize, + lastSize: quote.lastSize, + lastMove: quote.lastMove, + lastUpdatedAt: quote.lastUpdatedAt, + high: quote.high, + low: quote.low, + volume: quote.volume, + turnover: quote.turnover, + ...(shouldUpdateHistory || previousUpdate?.history + ? { history: [...quote.history] } + : {}), + }) + this.#tickIndex++ + } + + return [...updatedQuotes.values()] + } + + #applyTick( + quote: MarketQuoteSnapshot, + updateHistory: boolean, + updatedAt: number, + ): void { + const previousPrice = quote.price + const volatility = 0.00015 + this.#random() * 0.0012 + const move = previousPrice * (this.#random() - 0.495) * volatility + const nextPrice = roundPrice(Math.max(0.1, previousPrice + move)) + const spread = Math.max( + 0.01, + nextPrice * (0.00015 + this.#random() * 0.0005), + ) + + quote.lastMove = nextPrice - previousPrice + quote.price = nextPrice + quote.high = Math.max(quote.high, nextPrice) + quote.low = Math.min(quote.low, nextPrice) + quote.bid = roundPrice(nextPrice - spread / 2) + quote.ask = roundPrice(nextPrice + spread / 2) + quote.bidSize = Math.floor(100 + this.#random() * 25_000) + quote.askSize = Math.floor(100 + this.#random() * 25_000) + quote.lastSize = Math.floor(10 + this.#random() * 5_000) + quote.lastUpdatedAt = updatedAt + quote.volume += quote.lastSize + quote.turnover = roundMoney(quote.turnover + nextPrice * quote.lastSize) + + if (updateHistory) { + quote.history = [...quote.history.slice(-23), nextPrice] + } + } +} + +function createRandom(seed: number): () => number { + const runtime = { state: seed >>> 0 } + return () => { + runtime.state += 0x6d2b79f5 + const stateValue = runtime.state + const firstMix = Math.imul(stateValue ^ (stateValue >>> 15), stateValue | 1) + const secondMix = + firstMix + Math.imul(firstMix ^ (firstMix >>> 7), firstMix | 61) + const value = firstMix ^ secondMix + return ((value ^ (value >>> 14)) >>> 0) / 4_294_967_296 + } +} + +function roundPrice(value: number): number { + return Math.round(value * 100) / 100 +} + +function roundMoney(value: number): number { + return Math.round(value * 100) / 100 +} diff --git a/examples/angular/realtime-trading/src/app/feed/worker/market-feed-protocol.ts b/examples/angular/realtime-trading/src/app/feed/worker/market-feed-protocol.ts new file mode 100644 index 0000000000..21997ec89c --- /dev/null +++ b/examples/angular/realtime-trading/src/app/feed/worker/market-feed-protocol.ts @@ -0,0 +1,70 @@ +export interface MarketQuoteSnapshot { + id: string + symbol: string + company: string + venue: string + previousClose: number + open: number + high: number + low: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + volume: number + turnover: number + history: Array +} + +export interface MarketQuoteUpdate { + index: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + high: number + low: number + volume: number + turnover: number + history?: Array +} + +export type MarketFeedCommand = + | { + type: 'start' + rowCount: number + running: boolean + ticksPerSecond: number + publishIntervalMs: number + updateSparklines: boolean + sparklineSampleIntervalMs: number + } + | { type: 'set-running'; running: boolean } + | { type: 'set-rate'; ticksPerSecond: number } + | { type: 'set-publish-interval'; intervalMs: number } + | { type: 'set-sparklines'; enabled: boolean } + | { type: 'set-sparkline-interval'; intervalMs: number } + | { type: 'reset'; rowCount: number } + | { type: 'burst'; tickCount: number } + +export type MarketFeedEvent = + | { + type: 'snapshot' + sessionId: number + quotes: Array + } + | { + type: 'updates' + sessionId: number + tickCount: number + coalescedUpdateCount: number + updates: Array + } diff --git a/examples/angular/realtime-trading/src/app/feed/worker/market-feed.worker.ts b/examples/angular/realtime-trading/src/app/feed/worker/market-feed.worker.ts new file mode 100644 index 0000000000..2b7a642fd9 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/feed/worker/market-feed.worker.ts @@ -0,0 +1,143 @@ +import { initialMarketFeedConfig } from '../market-feed-config' +import { MarketFeedEngine } from './market-feed-engine' +import type { + MarketFeedCommand, + MarketFeedEvent, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const engine = new MarketFeedEngine() +const pendingUpdates = new Map() +const runtime = { + sessionId: 0, + pendingTickCount: 0, + pendingCoalescedUpdateCount: 0, + initialized: false, + running: true, + ticksPerSecond: initialMarketFeedConfig.targetSamplesPerSecond, + publishIntervalMs: initialMarketFeedConfig.publishIntervalMs, + publishTimerId: null as ReturnType | null, + updateSparklines: initialMarketFeedConfig.updateSparklines, + sparklineSampleIntervalMs: initialMarketFeedConfig.sparklineSampleIntervalMs, + tickBudget: 0, + lastTickAt: performance.now(), +} + +addEventListener('message', ({ data }: MessageEvent) => { + switch (data.type) { + case 'start': + runtime.running = data.running + runtime.ticksPerSecond = data.ticksPerSecond + runtime.publishIntervalMs = data.publishIntervalMs + runtime.updateSparklines = data.updateSparklines + runtime.sparklineSampleIntervalMs = data.sparklineSampleIntervalMs + restartPublishTimer() + reset(data.rowCount) + break + case 'set-running': + runtime.running = data.running + break + case 'set-rate': + runtime.ticksPerSecond = data.ticksPerSecond + break + case 'set-publish-interval': + runtime.publishIntervalMs = Math.max(4, data.intervalMs) + restartPublishTimer() + break + case 'set-sparklines': + runtime.updateSparklines = data.enabled + break + case 'set-sparkline-interval': + runtime.sparklineSampleIntervalMs = Math.max(16, data.intervalMs) + break + case 'reset': + reset(data.rowCount) + break + case 'burst': + produceTicks(data.tickCount) + flush() + break + } +}) + +setInterval(() => { + const now = performance.now() + const elapsed = Math.min(100, Math.max(0, now - runtime.lastTickAt)) + runtime.lastTickAt = now + + if (runtime.initialized && runtime.running) { + runtime.tickBudget += (runtime.ticksPerSecond * elapsed) / 1_000 + const tickCount = Math.floor(runtime.tickBudget) + runtime.tickBudget -= tickCount + produceTicks(tickCount) + } +}, 16) + +restartPublishTimer() + +function reset(rowCount: number): void { + runtime.initialized = true + runtime.sessionId++ + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + runtime.tickBudget = 0 + runtime.lastTickAt = performance.now() + + post({ + type: 'snapshot', + sessionId: runtime.sessionId, + quotes: engine.reset(rowCount), + }) +} + +function produceTicks(tickCount: number): void { + if (!runtime.initialized || tickCount <= 0) return + + runtime.pendingTickCount += tickCount + for (const update of engine.applyTicks( + tickCount, + runtime.updateSparklines, + runtime.sparklineSampleIntervalMs, + )) { + const previousUpdate = pendingUpdates.get(update.index) + if (previousUpdate) runtime.pendingCoalescedUpdateCount++ + pendingUpdates.set(update.index, { + ...update, + ...(update.history || !previousUpdate?.history + ? {} + : { history: previousUpdate.history }), + }) + } +} + +function flush(): void { + if (runtime.pendingTickCount === 0) return + + const message: MarketFeedEvent = { + type: 'updates', + sessionId: runtime.sessionId, + tickCount: runtime.pendingTickCount, + coalescedUpdateCount: runtime.pendingCoalescedUpdateCount, + updates: [...pendingUpdates.values()], + } + + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + post(message) +} + +function restartPublishTimer(): void { + if (runtime.publishTimerId !== null) { + clearInterval(runtime.publishTimerId) + } + runtime.publishTimerId = setInterval( + flush, + Math.max(4, runtime.publishIntervalMs), + ) +} + +function post(event: MarketFeedEvent): void { + postMessage(event) +} diff --git a/examples/angular/realtime-trading/src/app/shell/configurator-options.ts b/examples/angular/realtime-trading/src/app/shell/configurator-options.ts new file mode 100644 index 0000000000..49a9566fe7 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/shell/configurator-options.ts @@ -0,0 +1,55 @@ +export interface ConfiguratorOption { + readonly label: string + readonly value: TValue +} + +const instrumentCountOptions = [ + { label: '50', value: 50 }, + { label: '100', value: 100 }, + { label: '150', value: 150 }, + { label: '250', value: 250 }, + { label: '350', value: 350 }, + { label: '500', value: 500 }, + { label: '750', value: 750 }, + { label: '1,000', value: 1_000 }, + { label: '1,500', value: 1_500 }, + { label: '2,500', value: 2_500 }, + { label: '5,000', value: 5_000 }, + { label: '1,000,000', value: 1_000_000 }, + { label: '10,000,000', value: 10_000_000 }, +] as const satisfies ReadonlyArray> + +const workerDeliveryOptions = [ + { label: '8 ms · 125 msg/s', value: 8 }, + { label: '16 ms · 62.5 msg/s', value: 16 }, + { label: '20 ms · 50 msg/s', value: 20 }, + { label: '33 ms · 30 msg/s', value: 33 }, + { label: '50 ms · 20 msg/s', value: 50 }, + { label: '100 ms · 10 msg/s', value: 100 }, + { label: '250 ms · 4 msg/s', value: 250 }, + { label: '500 ms · 2 msg/s', value: 500 }, + { label: '1,000 ms · 1 msg/s', value: 1_000 }, +] as const satisfies ReadonlyArray> + +const rowRenderingOptions = [ + { label: 'Full DOM · render every row', value: 'none' }, + { label: 'TanStack Virtual · visible rows only', value: 'tanstack' }, +] as const satisfies ReadonlyArray> + +const intradaySamplingOptions = [ + { label: '16 ms · fastest', value: 16 }, + { label: '33 ms · very fast', value: 33 }, + { label: '50 ms · fast', value: 50 }, + { label: '100 ms', value: 100 }, + { label: '250 ms', value: 250 }, + { label: '500 ms', value: 500 }, + { label: '1,000 ms', value: 1_000 }, + { label: '2,000 ms', value: 2_000 }, +] as const satisfies ReadonlyArray> + +export const configuratorOptions = { + instrumentCounts: instrumentCountOptions, + workerDeliveryIntervals: workerDeliveryOptions, + rowRenderingModes: rowRenderingOptions, + intradaySamplingIntervals: intradaySamplingOptions, +} as const diff --git a/examples/angular/realtime-trading/src/app/shell/configurator.html b/examples/angular/realtime-trading/src/app/shell/configurator.html new file mode 100644 index 0000000000..7b2ae6a228 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/shell/configurator.html @@ -0,0 +1,183 @@ + diff --git a/examples/angular/realtime-trading/src/app/shell/configurator.ts b/examples/angular/realtime-trading/src/app/shell/configurator.ts new file mode 100644 index 0000000000..83f8ab41b9 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/shell/configurator.ts @@ -0,0 +1,52 @@ +import { ChangeDetectionStrategy, Component, inject } from '@angular/core' +import { TradingBenchmarkController } from '../benchmark/trading-benchmark.controller' +import { + feedSampleRateAt, + feedSampleRateIndex, + feedSampleRateOptions, +} from '../feed/feed-sample-rates' +import { MarketFeedService } from '../feed/market-feed.service' +import { configuratorOptions } from './configurator-options' +import { Diagnostics } from './diagnostics' +import { MetricsStrip } from './metrics-strip' +import { SelectedInstrument } from './selected-instrument' +import { + formatRate, + inputChecked, + inputValue, + selectValue, +} from './shell-formatters' + +@Component({ + selector: 'app-configurator', + imports: [Diagnostics, MetricsStrip, SelectedInstrument], + templateUrl: './configurator.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class Configurator { + readonly controller = inject(TradingBenchmarkController) + readonly feed = inject(MarketFeedService) + readonly formatRate = formatRate + readonly options = configuratorOptions + readonly sampleRateOptions = feedSampleRateOptions + readonly sampleRateIndex = feedSampleRateIndex + + readonly setRowCount = (event: Event) => { + this.controller.resetViewState() + this.feed.setInstrumentCount(Number(selectValue(event))) + } + readonly setTargetRate = (event: Event) => + this.feed.setTargetRate(feedSampleRateAt(Number(inputValue(event)))) + readonly setPublishInterval = (event: Event) => + this.feed.setPublishInterval(Number(selectValue(event))) + readonly setRendererMode = (event: Event) => + this.controller.setRendererMode(inputChecked(event)) + readonly setTableWorkerEnabled = (event: Event) => + this.controller.setTableWorkerEnabled(inputChecked(event)) + readonly setVirtualScrollMode = (event: Event) => + this.controller.setVirtualScrollEnabled(selectValue(event) === 'tanstack') + readonly setSparklineUpdates = (event: Event) => + this.feed.setSparklineUpdates(inputChecked(event)) + readonly setSparklineSampleInterval = (event: Event) => + this.feed.setSparklineSampleInterval(Number(selectValue(event))) +} diff --git a/examples/angular/realtime-trading/src/app/shell/diagnostics.ts b/examples/angular/realtime-trading/src/app/shell/diagnostics.ts new file mode 100644 index 0000000000..0817db8c2b --- /dev/null +++ b/examples/angular/realtime-trading/src/app/shell/diagnostics.ts @@ -0,0 +1,134 @@ +import { ChangeDetectionStrategy, Component, inject } from '@angular/core' +import { TradingBenchmarkController } from '../benchmark/trading-benchmark.controller' +import { formatInteger, formatRate } from './shell-formatters' + +@Component({ + selector: 'app-diagnostics', + template: ` +
+

DIAGNOSTICS

+
+
+
Rendered rows / source
+
+ {{ formatInteger(controller.renderedRowCount()) }} / + {{ formatInteger(controller.displayQuotes().length) }} +
+
+
+
Mounted cell hosts
+
{{ formatInteger(controller.mountedCells()) }}
+
+
+
Live components
+
{{ formatInteger(controller.liveComponents()) }}
+
+
+
Created / destroyed
+
+ {{ formatInteger(controller.metrics().componentsCreated) }} / + {{ formatInteger(controller.metrics().componentsDestroyed) }} +
+
+
+
Worker samples / s
+
+ {{ formatRate(controller.metrics().actualTicksPerSecond) }} +
+
+
+
Worker messages / s
+
+ {{ controller.metrics().workerMessagesPerSecond.toFixed(1) }} +
+
+
+
Changed rows / s
+
+ {{ formatRate(controller.metrics().rowUpdatesPerSecond) }} +
+
+
+
State snapshots / s
+
+ {{ controller.metrics().stateApplicationsPerSecond.toFixed(1) }} +
+
+
+
Table DOM commits / s
+
+ {{ controller.metrics().tableRendersPerSecond.toFixed(1) }} +
+
+
+
P95 / max commit latency (rolling 10 s)
+
+ {{ controller.metrics().p95RenderMs.toFixed(2) }} ms / + {{ controller.metrics().maxRenderMs.toFixed(2) }} ms +
+
+
+
Worker messages since reset
+
+ {{ formatInteger(controller.metrics().workerMessages) }} +
+
+
+
Worker-coalesced updates / s
+
+ {{ formatRate(controller.metrics().supersededUpdatesPerSecond) }} +
+
+
+
Last message samples / updated rows
+
+ {{ formatInteger(controller.metrics().lastBatchSize) }} / + {{ formatInteger(controller.metrics().lastUpdateCount) }} +
+
+
+
Commits > 16.7 ms since reset
+
{{ controller.metrics().slowRenders }}
+
+
+
Observed MutationRecords / s
+
+ {{ formatRate(controller.metrics().domMutationsPerSecond) }} +
+
+
+
Long animation frames
+
+ {{ + controller.longAnimationFramesSupported + ? formatInteger(controller.metrics().longAnimationFrames) + : 'Unsupported' + }} +
+
+
+
JS heap (GC-sensitive)
+
+ {{ + controller.metrics().heapMb === null + ? 'N/A' + : controller.metrics().heapMb!.toFixed(1) + ' MB' + }} +
+
+
+

+ MutationObserver counts delivered records, not individual DOM + operations, and adds profiling overhead. Only class/style attributes, + text, and child-list changes are observed. Heap is a Chromium-only + point-in-time value and can move before garbage collection. +

+
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class Diagnostics { + readonly controller = inject(TradingBenchmarkController) + readonly formatInteger = formatInteger + readonly formatRate = formatRate +} diff --git a/examples/angular/realtime-trading/src/app/shell/market-statusbar.ts b/examples/angular/realtime-trading/src/app/shell/market-statusbar.ts new file mode 100644 index 0000000000..e092b39875 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/shell/market-statusbar.ts @@ -0,0 +1,36 @@ +import { ChangeDetectionStrategy, Component, inject } from '@angular/core' +import { TradingBenchmarkController } from '../benchmark/trading-benchmark.controller' +import { formatInteger } from './shell-formatters' + +@Component({ + selector: 'app-market-statusbar', + template: ` +
+ + MESSAGE SAMPLES + + {{ formatInteger(controller.metrics().lastBatchSize) }} + + + + CHANGED ROWS + + {{ formatInteger(controller.metrics().lastUpdateCount) }} + + + + CELL HOSTS + {{ formatInteger(controller.mountedCells()) }} + + + COMPONENTS + {{ formatInteger(controller.liveComponents()) }} + +
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class MarketStatusbar { + readonly controller = inject(TradingBenchmarkController) + readonly formatInteger = formatInteger +} diff --git a/examples/angular/realtime-trading/src/app/shell/metrics-strip.ts b/examples/angular/realtime-trading/src/app/shell/metrics-strip.ts new file mode 100644 index 0000000000..7e92dddac0 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/shell/metrics-strip.ts @@ -0,0 +1,60 @@ +import { ChangeDetectionStrategy, Component, inject } from '@angular/core' +import { TradingBenchmarkController } from '../benchmark/trading-benchmark.controller' +import { formatMs, formatRate } from './shell-formatters' + +@Component({ + selector: 'app-metrics-strip', + template: ` +
+

LIVE HEALTH

+
+ FRAME RATE (EST.) + + {{ controller.metrics().rafCallbacksPerSecond.toFixed(1) }} + + rAF callbacks/s · rolling 1 s +
+
+ AVG COMMIT + + {{ formatMs(controller.metrics().averageRenderMs) }} + + snapshot → DOM · rolling 3 s +
+
+ LONG FRAMES + @if (controller.longAnimationFramesSupported) { + + {{ controller.metrics().longAnimationFrames }} + + + since reset · worst + {{ formatMs(controller.metrics().worstLongAnimationFrameMs) }} + + } @else { + N/A + unsupported + } +
+
+ THROUGHPUT + + {{ formatRate(controller.metrics().rowUpdatesPerSecond) }} rows/s + + + {{ controller.metrics().stateApplicationsPerSecond.toFixed(1) }} + snapshots/s · rows deduplicated per snapshot + +
+
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class MetricsStrip { + readonly controller = inject(TradingBenchmarkController) + readonly formatMs = formatMs + readonly formatRate = formatRate +} diff --git a/examples/angular/realtime-trading/src/app/shell/selected-instrument.ts b/examples/angular/realtime-trading/src/app/shell/selected-instrument.ts new file mode 100644 index 0000000000..bd537d13ba --- /dev/null +++ b/examples/angular/realtime-trading/src/app/shell/selected-instrument.ts @@ -0,0 +1,41 @@ +import { ChangeDetectionStrategy, Component, inject } from '@angular/core' +import { TradingBenchmarkController } from '../benchmark/trading-benchmark.controller' + +@Component({ + selector: 'app-selected-instrument', + template: ` +
+

SELECTED INSTRUMENT

+ @if (controller.selectedQuote(); as quote) { +
+
+ {{ quote.symbol }} + {{ quote.company }} +
+ {{ quote.venue }} +
+
+
+
Last
+
{{ quote.price.toFixed(2) }}
+
+
+
Bid / ask
+
{{ quote.bid.toFixed(2) }} / {{ quote.ask.toFixed(2) }}
+
+
+ } @else { +

+ Click or begin a cell selection in any row to inspect its instrument. +

+ } +
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SelectedInstrument { + readonly controller = inject(TradingBenchmarkController) +} diff --git a/examples/angular/realtime-trading/src/app/shell/shell-formatters.ts b/examples/angular/realtime-trading/src/app/shell/shell-formatters.ts new file mode 100644 index 0000000000..5526e66d53 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/shell/shell-formatters.ts @@ -0,0 +1,19 @@ +const integerFormatter = new Intl.NumberFormat('en-US', { + maximumFractionDigits: 0, +}) +const rateFormatter = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) + +export const formatInteger = (value: number): string => + integerFormatter.format(value) +export const formatRate = (value: number): string => rateFormatter.format(value) +export const formatMs = (value: number): string => `${value.toFixed(2)} ms` + +export const selectValue = (event: Event): string => + (event.target as HTMLSelectElement).value +export const inputValue = (event: Event): string => + (event.target as HTMLInputElement).value +export const inputChecked = (event: Event): boolean => + (event.target as HTMLInputElement).checked diff --git a/examples/angular/realtime-trading/src/app/shell/shell-header.ts b/examples/angular/realtime-trading/src/app/shell/shell-header.ts new file mode 100644 index 0000000000..0398004644 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/shell/shell-header.ts @@ -0,0 +1,59 @@ +import { + ChangeDetectionStrategy, + Component, + inject, + input, + output, +} from '@angular/core' +import { MarketFeedService } from '../feed/market-feed.service' + +@Component({ + selector: 'app-shell-header', + template: ` +
+
+ MARKET MONITOR +
+
+ + + {{ + !feed.workerReady() + ? 'FEED CONNECTING' + : feed.running() + ? 'FEED LIVE' + : 'FEED PAUSED' + }} + + +
+
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ShellHeader { + readonly feed = inject(MarketFeedService) + readonly sidebarOpen = input.required() + readonly sidebarToggle = output() +} diff --git a/examples/angular/realtime-trading/src/app/shell/trading-shell.html b/examples/angular/realtime-trading/src/app/shell/trading-shell.html new file mode 100644 index 0000000000..ddce4e567d --- /dev/null +++ b/examples/angular/realtime-trading/src/app/shell/trading-shell.html @@ -0,0 +1,20 @@ +
+
+ + + @if (devMode) { + + } +
+ +
+ +
+ + + +
diff --git a/examples/angular/realtime-trading/src/app/shell/trading-shell.ts b/examples/angular/realtime-trading/src/app/shell/trading-shell.ts new file mode 100644 index 0000000000..02ffb4850f --- /dev/null +++ b/examples/angular/realtime-trading/src/app/shell/trading-shell.ts @@ -0,0 +1,22 @@ +import { + ChangeDetectionStrategy, + Component, + inject, + signal, +} from '@angular/core' +import { TradingBenchmarkController } from '../benchmark/trading-benchmark.controller' +import { Configurator } from './configurator' +import { MarketStatusbar } from './market-statusbar' +import { ShellHeader } from './shell-header' + +@Component({ + selector: 'app-trading-shell', + imports: [Configurator, MarketStatusbar, ShellHeader], + templateUrl: './trading-shell.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TradingShell { + readonly devMode = inject(TradingBenchmarkController).devMode + readonly sidebarOpen = signal(true) + readonly toggleSidebar = () => this.sidebarOpen.update((open) => !open) +} diff --git a/examples/angular/realtime-trading/src/app/table/current-trading-table.ts b/examples/angular/realtime-trading/src/app/table/current-trading-table.ts new file mode 100644 index 0000000000..5afdc6d03e --- /dev/null +++ b/examples/angular/realtime-trading/src/app/table/current-trading-table.ts @@ -0,0 +1,98 @@ +import { + ChangeDetectionStrategy, + Component, + computed, + inject, + input, + output, + untracked, + viewChild, +} from '@angular/core' +import { FlexRender, injectTable } from '@tanstack/angular-table' +import { TradingBenchmarkController } from '../benchmark/trading-benchmark.controller' +import { createTradingColumns } from './table-config/trading-columns' +import { tradingFeatures } from './trading-features' +import { TradingTableInteractionController } from './table-interactions' +import { injectTradingTableInitialFit } from './trading-table-initial-fit' +import { TradingGridCellDirective } from './view/trading-grid-cell.directive' +import { TradingGridSelectionDirective } from './view/trading-grid-selection.directive' +import { TradingHeaderCell } from './view/trading-header-cell' +import { TradingTableBenchmarkDirective } from './view/trading-table-benchmark.directive' +import { + TRADING_ROW_HEIGHT, + injectTradingRowVirtualizer, +} from './trading-row-virtualizer' +import type { ElementRef } from '@angular/core' +import type { MarketQuote } from '../feed/market-data' +import type { RendererMode } from './table-config/trading-column-types' +import type { VirtualScrollMode } from './trading-row-virtualizer' + +@Component({ + selector: 'app-current-trading-table', + imports: [ + FlexRender, + TradingGridCellDirective, + TradingGridSelectionDirective, + TradingHeaderCell, + TradingTableBenchmarkDirective, + ], + templateUrl: './table-v9.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class CurrentTradingTable { + readonly #controller = inject(TradingBenchmarkController) + readonly quotes = input>([]) + readonly rendererMode = input.required() + readonly selectedSymbol = input(null) + readonly virtualScrollMode = input.required() + readonly symbolSelected = output() + readonly tanStackScrollContainer = viewChild>( + 'tanStackScrollContainer', + ) + readonly rowHeight = TRADING_ROW_HEIGHT + readonly interactions = new TradingTableInteractionController() + + readonly columns = createTradingColumns({ + rendererMode: () => this.rendererMode(), + selectSymbol: (symbol) => this.symbolSelected.emit(symbol), + }) + + readonly table = injectTable(() => ({ + data: this.quotes(), + columns: this.columns, + features: tradingFeatures, + columnResizeMode: 'onChange' as const, + defaultColumn: { minSize: 56, maxSize: 800 }, + autoResetCellSelection: false, + getRowId: (row) => row.id, + })) + readonly tableStyle = computed(() => { + void this.table.atoms.columnSizing.get() + void this.table.atoms.columnOrder.get() + return untracked(() => { + const styles: Record = { + width: `${this.table.getTotalSize()}px`, + } + for (const header of this.table.getFlatHeaders()) { + styles[`--header-${header.id}-size`] = `${header.getSize()}` + styles[`--col-${header.column.id}-size`] = `${header.column.getSize()}` + } + return styles + }) + }) + readonly rows = computed(() => this.table.getRowModel().rows) + readonly virtualization = injectTradingRowVirtualizer( + this.rows, + this.virtualScrollMode, + this.tanStackScrollContainer, + (count) => this.#controller.setRenderedRowCount(count), + ) + + readonly tableHeight = computed(() => this.rows().length * this.rowHeight) + readonly workerPending = computed(() => null) + readonly workerComputeMs = computed(() => null) + + constructor() { + injectTradingTableInitialFit(this.table, this.tanStackScrollContainer) + } +} diff --git a/examples/angular/realtime-trading/src/app/table/table-config/quote-cells.ts b/examples/angular/realtime-trading/src/app/table/table-config/quote-cells.ts new file mode 100644 index 0000000000..d7bd35a9a2 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/table/table-config/quote-cells.ts @@ -0,0 +1,258 @@ +import { + ChangeDetectionStrategy, + Component, + DestroyRef, + computed, + inject, + input, + output, +} from '@angular/core' + +const compactNumber = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) + +export const quoteCellLifecycle = { + created: 0, + destroyed: 0, +} + +function trackLifecycle(): void { + quoteCellLifecycle.created++ + inject(DestroyRef).onDestroy(() => quoteCellLifecycle.destroyed++) +} + +@Component({ + selector: 'app-price-cell', + template: ` + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class PriceCell { + readonly price = input.required() + readonly move = input.required() + readonly select = output() + readonly formattedPrice = computed(() => this.price().toFixed(2)) + + constructor() { + trackLifecycle() + } +} + +@Component({ + selector: 'app-stable-move-cell', + template: ` + + {{ formattedMove() }} + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class StableMoveCell { + readonly move = input.required() + readonly formattedMove = computed(() => formatSigned(this.move())) + + constructor() { + trackLifecycle() + } +} + +@Component({ + selector: 'app-percent-change-cell', + template: ` + + {{ formattedValue() }} + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class PercentChangeCell { + readonly value = input.required() + readonly formattedValue = computed( + () => `${this.value() >= 0 ? '+' : ''}${this.value().toFixed(2)}%`, + ) + + constructor() { + trackLifecycle() + } +} + +@Component({ + selector: 'app-spread-cell', + template: ` + + {{ formattedSpread() }} + {{ basisPoints().toFixed(1) }} bp + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SpreadCell { + readonly bid = input.required() + readonly ask = input.required() + readonly spread = computed(() => Math.max(0, this.ask() - this.bid())) + readonly basisPoints = computed(() => { + const midpoint = (this.bid() + this.ask()) / 2 + return midpoint === 0 ? 0 : (this.spread() / midpoint) * 10_000 + }) + readonly formattedSpread = computed(() => this.spread().toFixed(2)) + + constructor() { + trackLifecycle() + } +} + +@Component({ + selector: 'app-depth-cell', + template: ` +
+ + + + {{ formattedBidSize() }} + {{ formattedAskSize() }} + +
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class DepthCell { + readonly bidSize = input.required() + readonly askSize = input.required() + readonly bidShare = computed(() => { + const total = this.bidSize() + this.askSize() + return total === 0 ? 50 : (this.bidSize() / total) * 100 + }) + readonly formattedBidSize = computed(() => + compactNumber.format(this.bidSize()), + ) + readonly formattedAskSize = computed(() => + compactNumber.format(this.askSize()), + ) + + constructor() { + trackLifecycle() + } +} + +@Component({ + selector: 'app-quote-age-cell', + template: ` + + {{ formattedAge() }} + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class QuoteAgeCell { + readonly ageMs = input.required() + readonly formattedAge = computed(() => { + const age = this.ageMs() + return age < 1_000 + ? `${Math.round(age)} ms` + : `${(age / 1_000).toFixed(1)} s` + }) + + constructor() { + trackLifecycle() + } +} + +@Component({ + selector: 'app-up-move-cell', + template: `▲ {{ formattedMove() }}`, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class UpMoveCell { + readonly move = input.required() + readonly formattedMove = computed(() => formatSigned(this.move())) + + constructor() { + trackLifecycle() + } +} + +@Component({ + selector: 'app-down-move-cell', + template: `▼ {{ formattedMove() }}`, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class DownMoveCell { + readonly move = input.required() + readonly formattedMove = computed(() => formatSigned(this.move())) + + constructor() { + trackLifecycle() + } +} + +@Component({ + selector: 'app-sparkline-cell', + template: ` + + + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SparklineCell { + readonly values = input.required>() + readonly rising = computed(() => { + const values = this.values() + return (values.at(-1) ?? 0) >= (values[0] ?? 0) + }) + readonly points = computed(() => { + const values = this.values() + const min = Math.min(...values) + const max = Math.max(...values) + const range = max - min || 1 + const denominator = Math.max(1, values.length - 1) + + return values + .map((value, index) => { + const x = (index / denominator) * 100 + const y = 22 - ((value - min) / range) * 20 + return `${x.toFixed(1)},${y.toFixed(1)}` + }) + .join(' ') + }) + + constructor() { + trackLifecycle() + } +} + +function formatSigned(value: number): string { + const sign = value >= 0 ? '+' : '' + return `${sign}${value.toFixed(2)}` +} diff --git a/examples/angular/realtime-trading/src/app/table/table-config/trading-column-types.ts b/examples/angular/realtime-trading/src/app/table/table-config/trading-column-types.ts new file mode 100644 index 0000000000..dc6e83a0b2 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/table/table-config/trading-column-types.ts @@ -0,0 +1,8 @@ +export type RendererMode = 'stable' | 'swap' + +export interface TradingColumnState { + rendererMode: () => RendererMode + selectSymbol: (symbol: string) => void +} + +export const TRADING_COLUMN_COUNT = 14 diff --git a/examples/angular/realtime-trading/src/app/table/table-config/trading-columns.ts b/examples/angular/realtime-trading/src/app/table/table-config/trading-columns.ts new file mode 100644 index 0000000000..e613dcd1ae --- /dev/null +++ b/examples/angular/realtime-trading/src/app/table/table-config/trading-columns.ts @@ -0,0 +1,165 @@ +import { + createColumnHelper, + flexRenderComponent, +} from '@tanstack/angular-table' +import { tradingFeatures } from '../trading-features' +import { + DownMoveCell, + PercentChangeCell, + PriceCell, + SparklineCell, + StableMoveCell, + UpMoveCell, +} from './quote-cells' +import type { MarketQuote } from '../../feed/market-data' +import type { TradingColumnState } from './trading-column-types' + +const compactFormatter = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +const columnHelper = createColumnHelper() + +export function createTradingColumns(state: TradingColumnState) { + return columnHelper.columns([ + columnHelper.group({ + id: 'instrument', + header: 'Instrument', + columns: columnHelper.columns([ + columnHelper.accessor('venue', { + id: 'market', + header: 'Market', + size: 72, + cell: (info) => info.getValue(), + }), + columnHelper.accessor('company', { + id: 'name', + header: 'Name', + size: 180, + cell: (info) => info.getValue(), + }), + columnHelper.accessor('symbol', { + header: 'Symbol', + size: 92, + cell: (info) => info.getValue(), + }), + ]), + }), + columnHelper.group({ + id: 'priceAndChange', + header: 'Price & Change', + columns: columnHelper.columns([ + columnHelper.accessor('price', { + header: 'Price', + size: 96, + cell: (info) => { + const change = getDayChange(info.row.original) + return flexRenderComponent(PriceCell, { + inputs: { price: info.getValue(), move: change }, + outputs: { + select: () => state.selectSymbol(info.row.original.symbol), + }, + }) + }, + }), + columnHelper.accessor((row) => getDayChange(row), { + id: 'change', + header: 'Chg', + size: 94, + cell: (info) => { + const move = info.getValue() + if (state.rendererMode() === 'stable') { + return flexRenderComponent(StableMoveCell, { + inputs: { move }, + }) + } + return flexRenderComponent(move >= 0 ? UpMoveCell : DownMoveCell, { + inputs: { move }, + }) + }, + }), + columnHelper.accessor((row) => getDayChangePercent(row), { + id: 'changePercent', + header: 'Chg%', + size: 90, + cell: (info) => + flexRenderComponent(PercentChangeCell, { + inputs: { value: info.getValue() }, + }), + }), + ]), + }), + columnHelper.group({ + id: 'orderBook', + header: 'Order Book', + columns: columnHelper.columns([ + columnHelper.accessor('bid', { + header: 'Bid', + size: 90, + cell: (info) => info.getValue().toFixed(2), + }), + columnHelper.accessor('bidSize', { + header: 'Bid Vol', + size: 100, + cell: (info) => compactFormatter.format(info.getValue()), + }), + columnHelper.accessor('ask', { + header: 'Ask', + size: 90, + cell: (info) => info.getValue().toFixed(2), + }), + columnHelper.accessor('askSize', { + header: 'Ask Vol', + size: 100, + cell: (info) => compactFormatter.format(info.getValue()), + }), + ]), + }), + columnHelper.group({ + id: 'session', + header: 'Session', + columns: columnHelper.columns([ + columnHelper.accessor('open', { + header: 'Open', + size: 90, + cell: (info) => info.getValue().toFixed(2), + }), + columnHelper.accessor('high', { + header: 'High', + size: 90, + cell: (info) => info.getValue().toFixed(2), + }), + columnHelper.accessor('low', { + header: 'Low', + size: 90, + cell: (info) => info.getValue().toFixed(2), + }), + ]), + }), + columnHelper.group({ + id: 'chart', + header: 'Chart', + columns: columnHelper.columns([ + columnHelper.accessor('history', { + header: 'Intraday', + size: 150, + enableSorting: false, + cell: (info) => + flexRenderComponent(SparklineCell, { + inputs: { values: info.getValue() }, + }), + }), + ]), + }), + ]) +} + +function getDayChange(quote: MarketQuote): number { + return quote.price - quote.previousClose +} + +function getDayChangePercent(quote: MarketQuote): number { + return quote.previousClose === 0 + ? 0 + : (getDayChange(quote) / quote.previousClose) * 100 +} diff --git a/examples/angular/realtime-trading/src/app/table/table-interactions.ts b/examples/angular/realtime-trading/src/app/table/table-interactions.ts new file mode 100644 index 0000000000..24d43b8138 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/table/table-interactions.ts @@ -0,0 +1,181 @@ +import { signal } from '@angular/core' + +export type CellDirection = 'up' | 'down' | 'left' | 'right' + +interface RowSelectionTable { + resetRowSelection: (defaultState?: boolean) => void +} + +interface SelectableRow { + getIsSelected: () => boolean + getToggleSelectedHandler: (options?: { + selectChildren?: boolean + }) => (event: unknown) => void +} + +interface CellNavigationTable { + extendCellSelection: (direction: CellDirection) => void + moveCellSelection: (direction: CellDirection) => void + resetCellSelection: (defaultState?: boolean) => void + selectAllCells: () => void +} + +export interface ColumnOrderTable { + getVisibleLeafColumns: () => Array<{ id: string }> + setColumnOrder: (columnIds: Array) => void +} + +const keyDirections: Partial> = { + ArrowUp: 'up', + ArrowDown: 'down', + ArrowLeft: 'left', + ArrowRight: 'right', +} + +export function reorderColumnIds( + columnIds: Array, + sourceId: string, + targetId: string, +): Array { + if (sourceId === targetId || !columnIds.includes(sourceId)) return columnIds + + const withoutSource = columnIds.filter((id) => id !== sourceId) + const targetIndex = withoutSource.indexOf(targetId) + if (targetIndex < 0) return columnIds + + return [ + ...withoutSource.slice(0, targetIndex), + sourceId, + ...withoutSource.slice(targetIndex), + ] +} + +export function selectRowFromPointer( + table: RowSelectionTable, + row: SelectableRow, + event: MouseEvent, +): void { + const additive = event.ctrlKey || event.metaKey + const checked = additive ? !row.getIsSelected() : true + + if (!event.shiftKey && !additive) table.resetRowSelection(true) + + row.getToggleSelectedHandler({ selectChildren: false })({ + target: { checked }, + shiftKey: event.shiftKey, + ctrlKey: event.ctrlKey, + metaKey: event.metaKey, + }) +} + +export function handleCellNavigation( + table: CellNavigationTable, + event: KeyboardEvent, +): void { + if (event.key === 'Escape') { + event.preventDefault() + table.resetCellSelection(true) + return + } + + if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'a') { + event.preventDefault() + table.selectAllCells() + return + } + + const direction = keyDirections[event.key] + if (!direction) return + + event.preventDefault() + if (event.shiftKey) table.extendCellSelection(direction) + else table.moveCellSelection(direction) +} + +export function sortIndicator(direction: false | 'asc' | 'desc'): string { + if (direction === 'asc') return '↑' + if (direction === 'desc') return '↓' + return '↕' +} + +export function sortAriaValue( + direction: false | 'asc' | 'desc', +): 'ascending' | 'descending' | 'none' { + if (direction === 'asc') return 'ascending' + if (direction === 'desc') return 'descending' + return 'none' +} + +export class TradingTableInteractionController { + readonly draggedColumnId = signal(null) + readonly dropTargetColumnId = signal(null) + + startColumnDrag(event: DragEvent, columnId: string): void { + this.draggedColumnId.set(columnId) + event.dataTransfer?.setData('text/plain', columnId) + if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move' + } + + dragOverColumn(event: DragEvent, targetId: string): void { + event.preventDefault() + if (targetId === this.draggedColumnId()) { + this.dropTargetColumnId.set(null) + return + } + this.dropTargetColumnId.set(targetId) + } + + dropColumn( + table: ColumnOrderTable, + event: DragEvent, + targetId: string, + ): void { + event.preventDefault() + const sourceId = + event.dataTransfer?.getData('text/plain') || this.draggedColumnId() + if (!sourceId) { + this.clearColumnDrag() + return + } + + table.setColumnOrder( + reorderColumnIds( + table.getVisibleLeafColumns().map((column) => column.id), + sourceId, + targetId, + ), + ) + this.clearColumnDrag() + } + + endColumnDrag(): void { + this.clearColumnDrag() + } + + private clearColumnDrag(): void { + this.draggedColumnId.set(null) + this.dropTargetColumnId.set(null) + } + + selectRow( + table: RowSelectionTable, + row: SelectableRow, + event: MouseEvent, + ): void { + selectRowFromPointer(table, row, event) + } + + navigateCells(table: CellNavigationTable, event: KeyboardEvent): void { + handleCellNavigation(table, event) + } + + sortIndicator(direction: false | 'asc' | 'desc'): string { + return sortIndicator(direction) + } + + sortAriaValue( + direction: false | 'asc' | 'desc', + ): 'ascending' | 'descending' | 'none' { + return sortAriaValue(direction) + } +} diff --git a/examples/angular/realtime-trading/src/app/table/table-v9.html b/examples/angular/realtime-trading/src/app/table/table-v9.html new file mode 100644 index 0000000000..06c7e85ada --- /dev/null +++ b/examples/angular/realtime-trading/src/app/table/table-v9.html @@ -0,0 +1,144 @@ +@switch (virtualScrollMode()) { + @case ('tanstack') { +
+ + + + @for (headerGroup of table.getHeaderGroups(); track headerGroup.id) { + + @for (header of headerGroup.headers; track header.id) { + + } + + } + + + @for (virtualRow of virtualization.tanStackVirtualRows(); track virtualRow.key) { + @if (rows()[virtualRow.index]; as row) { + + @for (cell of row.getVisibleCells(); track cell.id) { + + } + + } + } + +
+ + {{ renderCell }} + +
+
+ } + @default { +
+ + + @for (headerGroup of table.getHeaderGroups(); track headerGroup.id) { + + @for (header of headerGroup.headers; track header.id) { + + } + + } + + + @for (row of rows(); track row.id) { + + @for (cell of row.getVisibleCells(); track cell.id) { + + } + + } + +
+ + {{ renderCell }} + +
+
+ } +} + +@if (virtualScrollMode() !== 'none') { +
+ + TanStack · Total · {{ rows().length }} rows · + {{ table.getVisibleLeafColumns().length }} columns + + @if (virtualization.visibleRange(); as visibleRange) { + + Current · rows {{ visibleRange.start }}..{{ visibleRange.end }} + + } @else { + Current · rows — + } +
+} diff --git a/examples/angular/realtime-trading/src/app/table/trading-features.ts b/examples/angular/realtime-trading/src/app/table/trading-features.ts new file mode 100644 index 0000000000..3bd98b192e --- /dev/null +++ b/examples/angular/realtime-trading/src/app/table/trading-features.ts @@ -0,0 +1,10 @@ +import { + createSortedRowModel, + stockFeatures, + tableFeatures, +} from '@tanstack/angular-table' + +export const tradingFeatures = tableFeatures({ + ...stockFeatures, + sortedRowModel: createSortedRowModel(), +}) diff --git a/examples/angular/realtime-trading/src/app/table/trading-row-virtualizer.ts b/examples/angular/realtime-trading/src/app/table/trading-row-virtualizer.ts new file mode 100644 index 0000000000..122e4d1b6f --- /dev/null +++ b/examples/angular/realtime-trading/src/app/table/trading-row-virtualizer.ts @@ -0,0 +1,115 @@ +import { + ChangeDetectorRef, + DestroyRef, + computed, + effect, + inject, +} from '@angular/core' +import { injectVirtualizer } from '@tanstack/angular-virtual' +import type { ElementRef, Signal } from '@angular/core' + +export const TRADING_ROW_HEIGHT = 32 +export const DEFAULT_VIRTUALIZATION_ROW_COUNT = 200 +export const FORCED_VIRTUALIZATION_ROW_COUNT = 1_500 + +const TANSTACK_OVERSCAN = 10 + +export type VirtualScrollMode = 'tanstack' | 'none' +export type VirtualScrollPreference = VirtualScrollMode | 'auto' + +export function resolveVirtualScrollMode( + requestedMode: VirtualScrollPreference, + instrumentCount: number, +): VirtualScrollMode { + if (instrumentCount >= FORCED_VIRTUALIZATION_ROW_COUNT) return 'tanstack' + if (requestedMode !== 'auto') return requestedMode + return instrumentCount >= DEFAULT_VIRTUALIZATION_ROW_COUNT + ? 'tanstack' + : 'none' +} + +interface TradingVirtualRow { + id: string +} + +function injectLocalDomFlush() { + const changeDetectorRef = inject(ChangeDetectorRef) + const destroyRef = inject(DestroyRef) + const state = { + destroyed: false, + queued: false, + } + + destroyRef.onDestroy(() => { + state.destroyed = true + }) + + return () => { + if (state.queued || state.destroyed) return + + state.queued = true + queueMicrotask(() => { + state.queued = false + if (!state.destroyed) { + changeDetectorRef.detectChanges() + } + }) + } +} + +export function injectTradingRowVirtualizer( + rows: Signal>, + mode: Signal, + tanStackScrollContainer: Signal | undefined>, + reportRenderedRowCount: (count: number) => void, +) { + const scheduleLocalDomFlush = injectLocalDomFlush() + const rowVirtualizer = injectVirtualizer( + () => ({ + count: rows().length, + scrollElement: tanStackScrollContainer()?.nativeElement, + estimateSize: () => TRADING_ROW_HEIGHT, + getItemKey: (index) => rows()[index]?.id ?? index, + overscan: TANSTACK_OVERSCAN, + enabled: mode() === 'tanstack', + useCachedMeasurements: true, + useApplicationRefTick: false, + onChange: scheduleLocalDomFlush, + }), + ) + + const tanStackVirtualRows = rowVirtualizer.getVirtualItems + const tanStackTotalSize = rowVirtualizer.getTotalSize + const visibleRange = computed(() => { + const rowCount = rows().length + const range = rowVirtualizer.range() + + if (mode() !== 'tanstack' || rowCount === 0 || range === null) { + return null + } + + const lastRowIndex = rowCount - 1 + const start = Math.min(range.startIndex, lastRowIndex) + + return { + start, + end: Math.min(Math.max(start, range.endIndex), lastRowIndex), + } + }) + const renderedRowCount = computed(() => { + if (mode() === 'tanstack') { + return tanStackVirtualRows().length + } + return rows().length + }) + + effect(() => reportRenderedRowCount(renderedRowCount())) + + return { + rowVirtualizer, + tanStackVirtualRows, + tanStackTotalSize, + visibleRange, + renderedRowCount, + } +} diff --git a/examples/angular/realtime-trading/src/app/table/trading-table-initial-fit.ts b/examples/angular/realtime-trading/src/app/table/trading-table-initial-fit.ts new file mode 100644 index 0000000000..0786f26529 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/table/trading-table-initial-fit.ts @@ -0,0 +1,63 @@ +import { DestroyRef, afterNextRender, inject } from '@angular/core' +import type { ElementRef, Signal } from '@angular/core' + +interface FitColumn { + getSize: () => number + id: string +} + +interface FitTable { + atoms: { + columnResizing: { + subscribe: ( + listener: (state: { isResizingColumn: false | string }) => void, + ) => { unsubscribe: () => void } + } + } + getTotalSize: () => number + getVisibleLeafColumns: () => Array + setColumnSizing: (sizes: Record) => void +} + +export function injectTradingTableInitialFit( + table: FitTable, + scrollContainer: Signal | undefined>, +): void { + const destroyRef = inject(DestroyRef) + const runtime = { manuallyResized: false } + + afterNextRender(() => { + const element = scrollContainer()?.nativeElement + if (!element) return + + const fitAvailableWidth = () => { + if (runtime.manuallyResized) return + const currentWidth = table.getTotalSize() + const availableWidth = element.clientWidth + if (availableWidth <= currentWidth + 1 || currentWidth <= 0) return + + const ratio = availableWidth / currentWidth + table.setColumnSizing( + Object.fromEntries( + table + .getVisibleLeafColumns() + .map((column) => [column.id, column.getSize() * ratio]), + ), + ) + } + + const resizeObserver = new ResizeObserver(fitAvailableWidth) + const resizingSubscription = table.atoms.columnResizing.subscribe( + (state) => { + if (state.isResizingColumn !== false) runtime.manuallyResized = true + }, + ) + resizeObserver.observe(element) + fitAvailableWidth() + + destroyRef.onDestroy(() => { + resizeObserver.disconnect() + resizingSubscription.unsubscribe() + }) + }) +} diff --git a/examples/angular/realtime-trading/src/app/table/view/trading-grid-cell.directive.ts b/examples/angular/realtime-trading/src/app/table/view/trading-grid-cell.directive.ts new file mode 100644 index 0000000000..150b65c5d2 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/table/view/trading-grid-cell.directive.ts @@ -0,0 +1,42 @@ +import { Directive, computed, inject, input } from '@angular/core' +import { TradingGridSelectionDirective } from './trading-grid-selection.directive' +import type { Cell, TableFeatures } from '@tanstack/angular-table' +import type { MarketQuote } from '../../feed/market-data' + +type TradingCell = Cell + +@Directive({ + selector: 'td[appTradingGridCell]', + host: { + '[style.width]': 'staticHostState().width', + '[attr.data-column-id]': 'staticHostState().columnId', + '[attr.data-cell-focused]': "selectionHostState().focused ? 'true' : null", + '[attr.data-selection-top]': "selectionHostState().top ? 'true' : null", + '[attr.data-selection-right]': "selectionHostState().right ? 'true' : null", + '[attr.data-selection-bottom]': + "selectionHostState().bottom ? 'true' : null", + '[attr.data-selection-left]': "selectionHostState().left ? 'true' : null", + '[attr.tabindex]': 'selectionHostState().tabIndex', + '[attr.aria-selected]': 'selectionHostState().selected', + }, +}) +export class TradingGridCellDirective { + readonly #selection = inject(TradingGridSelectionDirective) + + readonly cell = input.required({ + alias: 'appTradingGridCell', + }) + + readonly staticHostState = computed(() => { + const columnId = this.cell().column.id + + return { + width: `calc(var(--col-${columnId}-size) * 1px)`, + columnId, + } + }) + + readonly selectionHostState = computed(() => { + return this.#selection.readCellSelectionState(this.cell()) + }) +} diff --git a/examples/angular/realtime-trading/src/app/table/view/trading-grid-selection.directive.ts b/examples/angular/realtime-trading/src/app/table/view/trading-grid-selection.directive.ts new file mode 100644 index 0000000000..f58c6f6b4c --- /dev/null +++ b/examples/angular/realtime-trading/src/app/table/view/trading-grid-selection.directive.ts @@ -0,0 +1,98 @@ +import { Directive, input, output } from '@angular/core' +import type { Cell, Table, TableFeatures } from '@tanstack/angular-table' +import type { MarketQuote } from '../../feed/market-data' +import type { TradingTableInteractionController } from '../table-interactions' + +type TradingCell = Cell +type TradingTable = Table + +interface SelectionCellTarget { + readonly element: HTMLTableCellElement + readonly cell: TradingCell +} + +@Directive({ + selector: 'table[appTradingGridSelection]', + host: { + '(mousedown)': 'handleMouseDown($event)', + '(mousemove)': 'handleMouseMove($event)', + '(mouseleave)': 'resetPointerCell()', + '(click)': 'handleClick($event)', + }, +}) +export class TradingGridSelectionDirective { + readonly table = input.required({ + alias: 'appTradingGridSelection', + }) + readonly interactions = input.required() + readonly symbolSelected = output() + + #lastPointerCell: HTMLTableCellElement | null = null + + readCellSelectionState(cell: TradingCell) { + this.table().atoms.cellSelection.get() + const edges = cell.getSelectionEdges() + + return { + selected: cell.getIsSelected(), + focused: cell.getIsFocused(), + top: edges.top, + right: edges.right, + bottom: edges.bottom, + left: edges.left, + tabIndex: cell.getTabIndex(), + } + } + + handleMouseDown(event: MouseEvent): void { + if (event.button !== 0) return + + const target = this.#findCellTarget(event.composedPath()) + if (!target) return + + event.preventDefault() + this.#lastPointerCell = target.element + this.symbolSelected.emit(target.cell.row.original.symbol) + target.cell.getSelectionStartHandler(target.element.ownerDocument)(event) + } + + handleMouseMove(event: MouseEvent): void { + if ((event.buttons & 1) === 0) { + this.#lastPointerCell = null + return + } + + const target = this.#findCellTarget(event.composedPath()) + if (!target || target.element === this.#lastPointerCell) return + + this.#lastPointerCell = target.element + target.cell.getSelectionExtendHandler()(event) + } + + resetPointerCell(): void { + this.#lastPointerCell = null + } + + handleClick(event: MouseEvent): void { + const target = this.#findCellTarget(event.composedPath()) + if (!target) return + this.interactions().selectRow(this.table(), target.cell.row, event) + } + + #findCellTarget(path: Array): SelectionCellTarget | null { + for (const target of path) { + if (!(target instanceof HTMLTableCellElement)) continue + + const columnId = target.dataset['columnId'] + const rowId = + target.closest('tr[data-row-id]')?.dataset['rowId'] + if (!columnId || !rowId) return null + + const row = this.table().getRowModel().rowsById[rowId] + const cell = row.getAllCellsByColumnId()[columnId] + return { element: target, cell } + } + + return null + } +} diff --git a/examples/angular/realtime-trading/src/app/table/view/trading-header-cell.html b/examples/angular/realtime-trading/src/app/table/view/trading-header-cell.html new file mode 100644 index 0000000000..4a79e34760 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/table/view/trading-header-cell.html @@ -0,0 +1,53 @@ +@if (!header().isPlaceholder) { + @if (isGroup()) { + + {{ headerCell }} + + } @else { +
+ + +
+ @if (header().column.getCanResize()) { + + } + } +} diff --git a/examples/angular/realtime-trading/src/app/table/view/trading-header-cell.ts b/examples/angular/realtime-trading/src/app/table/view/trading-header-cell.ts new file mode 100644 index 0000000000..d0fc7df5d8 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/table/view/trading-header-cell.ts @@ -0,0 +1,64 @@ +import { + ChangeDetectionStrategy, + Component, + computed, + input, +} from '@angular/core' +import { FlexRender } from '@tanstack/angular-table' +import type { Header, TableFeatures } from '@tanstack/angular-table' +import type { MarketQuote } from '../../feed/market-data' +import type { + ColumnOrderTable, + TradingTableInteractionController, +} from '../table-interactions' + +type TradingHeader = Header + +@Component({ + selector: 'th[appTradingHeaderCell]', + imports: [FlexRender], + templateUrl: './trading-header-cell.html', + host: { + '[attr.colspan]': 'header().colSpan', + '[attr.aria-sort]': 'ariaSort()', + '[class.column-group-header]': 'isGroup()', + '[class.numeric-header]': 'isNumeric()', + '[class.is-column-dragging]': + 'interactions().draggedColumnId() === header().column.id', + '[class.is-column-drop-target]': + 'interactions().dropTargetColumnId() === header().column.id', + '[style.width]': 'width()', + }, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TradingHeaderCell { + readonly header = input.required({ + alias: 'appTradingHeaderCell', + }) + readonly table = input.required() + readonly interactions = input.required() + + readonly isGroup = computed(() => this.header().subHeaders.length > 0) + readonly isNumeric = computed( + () => !this.isGroup() && !isTextColumn(this.header().column.id), + ) + readonly width = computed( + () => `calc(var(--header-${this.header().id}-size) * 1px)`, + ) + readonly sorted = computed(() => this.header().column.getIsSorted()) + readonly ariaSort = computed(() => + this.isGroup() ? null : this.interactions().sortAriaValue(this.sorted()), + ) + + startColumnDrag(event: DragEvent): void { + this.interactions().startColumnDrag(event, this.header().column.id) + } + + dropColumn(event: DragEvent): void { + this.interactions().dropColumn(this.table(), event, this.header().column.id) + } +} + +function isTextColumn(columnId: string): boolean { + return columnId === 'market' || columnId === 'name' || columnId === 'symbol' +} diff --git a/examples/angular/realtime-trading/src/app/table/view/trading-table-benchmark.directive.ts b/examples/angular/realtime-trading/src/app/table/view/trading-table-benchmark.directive.ts new file mode 100644 index 0000000000..75b3de8586 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/table/view/trading-table-benchmark.directive.ts @@ -0,0 +1,25 @@ +import { DestroyRef, Directive, ElementRef, inject } from '@angular/core' +import { TradingBenchmarkController } from '../../benchmark/trading-benchmark.controller' + +@Directive({ + selector: 'tbody[appTradingTableBenchmark]', +}) +export class TradingTableBenchmarkDirective { + readonly #controller = inject(TradingBenchmarkController) + readonly #element = inject>(ElementRef) + readonly #observer = new MutationObserver((records) => { + this.#controller.recordDomMutations(records.length) + }) + + constructor() { + this.#controller.resetDomMutations() + this.#observer.observe(this.#element.nativeElement, { + attributes: true, + attributeFilter: ['class', 'style'], + characterData: true, + childList: true, + subtree: true, + }) + inject(DestroyRef).onDestroy(() => this.#observer.disconnect()) + } +} diff --git a/examples/angular/realtime-trading/src/app/table/worker/table-row-model.worker.ts b/examples/angular/realtime-trading/src/app/table/worker/table-row-model.worker.ts new file mode 100644 index 0000000000..39252b634f --- /dev/null +++ b/examples/angular/realtime-trading/src/app/table/worker/table-row-model.worker.ts @@ -0,0 +1,53 @@ +import { + createColumnHelper, + createFilteredRowModel, + createSortedRowModel, + stockFeatures, + tableFeatures, +} from '@tanstack/angular-table' +import { + initTableWorker, + workerRowModelsFeature, +} from '@tanstack/angular-table/experimental-worker-plugin' +import type { MarketQuote } from '../../feed/market-data' + +const workerFeatures = tableFeatures({ + ...stockFeatures, + workerRowModelsFeature, + filteredRowModel: createFilteredRowModel(), + sortedRowModel: createSortedRowModel(), +}) +const columnHelper = createColumnHelper() + +// The worker only computes row models, so it needs portable accessors but none +// of the Angular render components used by the visible table. +const workerColumns = columnHelper.columns([ + columnHelper.accessor('venue', { id: 'market' }), + columnHelper.accessor('company', { id: 'name' }), + columnHelper.accessor('symbol', {}), + columnHelper.accessor('price', {}), + columnHelper.accessor((row) => row.price - row.previousClose, { + id: 'change', + }), + columnHelper.accessor( + (row) => + row.previousClose === 0 + ? 0 + : ((row.price - row.previousClose) / row.previousClose) * 100, + { id: 'changePercent' }, + ), + columnHelper.accessor('bid', {}), + columnHelper.accessor('bidSize', {}), + columnHelper.accessor('ask', {}), + columnHelper.accessor('askSize', {}), + columnHelper.accessor('open', {}), + columnHelper.accessor('high', {}), + columnHelper.accessor('low', {}), + columnHelper.accessor('history', { enableSorting: false }), +]) + +initTableWorker({ + features: workerFeatures, + columns: workerColumns, + getRowId: (row) => row.id, +}) diff --git a/examples/angular/realtime-trading/src/app/table/worker/worker-trading-table.ts b/examples/angular/realtime-trading/src/app/table/worker/worker-trading-table.ts new file mode 100644 index 0000000000..2c18b8a293 --- /dev/null +++ b/examples/angular/realtime-trading/src/app/table/worker/worker-trading-table.ts @@ -0,0 +1,138 @@ +import { + ChangeDetectionStrategy, + Component, + DestroyRef, + computed, + inject, + input, + output, + untracked, + viewChild, +} from '@angular/core' +import { + FlexRender, + injectTable, + stockFeatures, + tableFeatures, +} from '@tanstack/angular-table' +import { + createTableWorker, + createWorkerRowModel, + workerRowModelsFeature, +} from '@tanstack/angular-table/experimental-worker-plugin' +import { TradingBenchmarkController } from '../../benchmark/trading-benchmark.controller' +import { createTradingColumns } from '../table-config/trading-columns' +import { TradingTableInteractionController } from '../table-interactions' +import { injectTradingTableInitialFit } from '../trading-table-initial-fit' +import { TradingGridCellDirective } from '../view/trading-grid-cell.directive' +import { TradingGridSelectionDirective } from '../view/trading-grid-selection.directive' +import { TradingHeaderCell } from '../view/trading-header-cell' +import { TradingTableBenchmarkDirective } from '../view/trading-table-benchmark.directive' +import { + TRADING_ROW_HEIGHT, + injectTradingRowVirtualizer, +} from '../trading-row-virtualizer' +import type { ColumnDef } from '@tanstack/angular-table' +import type { ElementRef } from '@angular/core' +import type { MarketQuote } from '../../feed/market-data' +import type { RendererMode } from '../table-config/trading-column-types' +import type { VirtualScrollMode } from '../trading-row-virtualizer' + +function createWorkerTableRuntime() { + const worker = createTableWorker({ + createWorker: () => + new Worker(new URL('./table-row-model.worker', import.meta.url), { + type: 'module', + }), + }) + const features = tableFeatures({ + ...stockFeatures, + workerRowModelsFeature, + filteredRowModel: createWorkerRowModel(worker, 'filtered'), + sortedRowModel: createWorkerRowModel(worker, 'sorted'), + }) + + return { worker, features } +} + +type WorkerFeatures = ReturnType['features'] + +@Component({ + selector: 'app-worker-trading-table', + imports: [ + FlexRender, + TradingGridCellDirective, + TradingGridSelectionDirective, + TradingHeaderCell, + TradingTableBenchmarkDirective, + ], + templateUrl: '../table-v9.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class WorkerTradingTable { + readonly #controller = inject(TradingBenchmarkController) + readonly #destroyRef = inject(DestroyRef) + readonly #workerRuntime = createWorkerTableRuntime() + readonly quotes = input>([]) + readonly rendererMode = input.required() + readonly selectedSymbol = input(null) + readonly virtualScrollMode = input.required() + readonly symbolSelected = output() + readonly tanStackScrollContainer = viewChild>( + 'tanStackScrollContainer', + ) + readonly rowHeight = TRADING_ROW_HEIGHT + readonly interactions = new TradingTableInteractionController() + + readonly columns = createTradingColumns({ + rendererMode: () => this.rendererMode(), + selectSymbol: (symbol) => this.symbolSelected.emit(symbol), + }) + + readonly table = injectTable(() => ({ + data: this.quotes(), + columns: this.columns as Array>, + features: this.#workerRuntime.features, + columnResizeMode: 'onChange' as const, + defaultColumn: { minSize: 56, maxSize: 800 }, + autoResetCellSelection: false, + getRowId: (row) => row.id, + })) + readonly tableStyle = computed(() => { + void this.table.atoms.columnSizing.get() + void this.table.atoms.columnOrder.get() + return untracked(() => { + const styles: Record = { + width: `${this.table.getTotalSize()}px`, + } + for (const header of this.table.getFlatHeaders()) { + styles[`--header-${header.id}-size`] = `${header.getSize()}` + styles[`--col-${header.column.id}-size`] = `${header.column.getSize()}` + } + return styles + }) + }) + readonly rows = computed(() => this.table.getRowModel().rows) + readonly virtualization = injectTradingRowVirtualizer( + this.rows, + this.virtualScrollMode, + this.tanStackScrollContainer, + (count) => this.#controller.setRenderedRowCount(count), + ) + + readonly workerPending = computed(() => { + return String(this.table.atoms.workerRowModels.get().isPending) + }) + + readonly workerComputeMs = computed(() => { + const computeMs = this.table.atoms.workerRowModels.get().lastComputeMs + return computeMs === undefined ? null : computeMs.toFixed(3) + }) + + readonly tableHeight = computed(() => this.rows().length * this.rowHeight) + + constructor() { + injectTradingTableInitialFit(this.table, this.tanStackScrollContainer) + this.#destroyRef.onDestroy(() => this.#workerRuntime.worker.terminate()) + } +} diff --git a/examples/angular/realtime-trading/src/index.html b/examples/angular/realtime-trading/src/index.html new file mode 100644 index 0000000000..3122a836db --- /dev/null +++ b/examples/angular/realtime-trading/src/index.html @@ -0,0 +1,17 @@ + + + + + Angular Real-time Trading flexRender Lab + + + + + + + + + diff --git a/examples/angular/realtime-trading/src/main.ts b/examples/angular/realtime-trading/src/main.ts new file mode 100644 index 0000000000..c9b5d07d64 --- /dev/null +++ b/examples/angular/realtime-trading/src/main.ts @@ -0,0 +1,5 @@ +import { bootstrapApplication } from '@angular/platform-browser' +import { App } from './app/app' +import { appConfig } from './app/app.config' + +bootstrapApplication(App, appConfig).catch((error) => console.error(error)) diff --git a/examples/angular/realtime-trading/src/styles.css b/examples/angular/realtime-trading/src/styles.css new file mode 100644 index 0000000000..113476ec65 --- /dev/null +++ b/examples/angular/realtime-trading/src/styles.css @@ -0,0 +1,1088 @@ +:root { + color-scheme: dark; + --font-ui: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + 'Segoe UI', sans-serif; + --font-mono: 'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace; + font-family: var(--font-ui); + font-synthesis: none; + --background: #050505; + --panel: #080808; + --panel-raised: #111111; + --panel-hover: #181818; + --surface-bar: #080808; + --surface-toolbar: #0d0d0d; + --surface-table: #050505; + --surface-header: #101010; + --surface-control: #151515; + --border: #303030; + --border-soft: #242424; + --border-strong: #4a4a4a; + --text: #e7ebf0; + --text-strong: #ffffff; + --text-inverse: #f7f9fb; + --muted: #737982; + --blue: #62a9ff; + --blue-soft: #a9d0ff; + --green: #42e488; + --red: #ff646b; + --amber: #dfb465; + --depth-bid: #315774; + --depth-ask: #634049; + --row-alt: rgb(255 255 255 / 1.8%); + --row-selected: rgb(66 132 214 / 16%); + --control-border: #354456; + --control-hover: #192431; + --sidebar-width: 18rem; + --shell-bar-height: 2.625rem; + --metrics-height: 3.5rem; + --statusbar-height: 1.625rem; + --virtual-footer-height: 2.125rem; + --table-header-height: 2rem; + --table-row-height: 2rem; + --shell-inline-padding: 0.75rem; + --table-cell-inline-padding: 0.6rem; + --control-radius: 1px; +} + +* { + box-sizing: border-box; +} + +html, +body { + min-width: 320px; + min-height: 100%; + margin: 0; + background: var(--background); +} + +body { + color: var(--text); +} + +button, +select, +input { + font: inherit; +} + +button, +select { + color: var(--text); + background: var(--panel-raised); + border: 1px solid var(--control-border); + border-radius: var(--control-radius); +} + +button { + padding: 0.5rem 0.65rem; + cursor: pointer; + font-size: 0.72rem; + font-weight: 650; + letter-spacing: 0.025em; +} + +button:hover { + background: var(--control-hover); + border-color: var(--border-strong); +} + +button:focus-visible, +select:focus-visible, +input:focus-visible { + outline: 1px solid var(--blue); + outline-offset: 1px; +} + +select { + width: 100%; + padding: 0.45rem 0.55rem; + font-size: 0.75rem; +} + +.trading-terminal { + --active-sidebar-width: var(--sidebar-width); + display: grid; + width: 100%; + height: 100dvh; + min-height: 0; + overflow: hidden; + background: var(--background); + grid-template-areas: + 'header sidebar' + 'content sidebar' + 'footer sidebar'; + grid-template-columns: minmax(0, 1fr) var(--active-sidebar-width); + grid-template-rows: auto minmax(0, 1fr) auto; + transition: grid-template-columns 160ms ease; +} + +.trading-terminal.is-sidebar-collapsed { + --active-sidebar-width: 0px; +} + +.shell-header { + display: flex; + min-width: 0; + flex-direction: column; + grid-area: header; +} + +.app-bar { + display: flex; + min-height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + background: var(--surface-bar); + border-bottom: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.68rem; + letter-spacing: 0.045em; +} + +.brand, +.header-actions, +.feed-status { + display: flex; + align-items: center; +} + +.brand { + gap: 0.65rem; + color: var(--text-strong); +} + +.header-actions { + gap: 0.75rem; +} + +.sidebar-toggle { + display: grid; + width: 1.9rem; + height: 1.9rem; + padding: 0; + place-items: center; + color: var(--muted); + background: transparent; + border-color: transparent; +} + +.sidebar-toggle:hover { + color: var(--text-strong); + background: var(--surface-control); + border-color: var(--border); +} + +.sidebar-toggle svg { + width: 1rem; + height: 1rem; + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-width: 1.4; +} + +.feed-status { + gap: 0.4rem; + color: var(--muted); +} + +.feed-status.is-running { + color: var(--green); +} + +.status-dot { + width: 6px; + height: 6px; + background: var(--muted); + border-radius: 50%; +} + +.feed-status.is-running .status-dot { + background: var(--green); +} + +.development-warning { + flex: 0 0 auto; + padding: 0.3rem 0.75rem; + color: var(--amber); + background: color-mix(in srgb, var(--amber) 8%, var(--background)); + border-bottom: 1px solid color-mix(in srgb, var(--amber) 24%, var(--border)); + font-family: var(--font-mono); + font-size: 0.62rem; + letter-spacing: 0.04em; +} + +.market-panel { + display: flex; + min-width: 0; + min-height: 0; + flex-direction: column; + background: var(--panel); + grid-area: content; +} + +.metrics-strip { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + background: var(--border); + border-bottom: 1px solid var(--border); + gap: 1px; +} + +.metrics-strip h2 { + margin: 0; + padding: 0.65rem var(--shell-inline-padding) 0.45rem; + color: var(--muted); + background: var(--surface-table); + font-size: 0.58rem; + grid-column: 1 / -1; + letter-spacing: 0.075em; +} + +.metrics-strip article { + min-width: 0; + min-height: 4.25rem; + padding: 0.5rem var(--shell-inline-padding); + background: var(--surface-bar); +} + +.metrics-strip span, +.metrics-strip small { + display: block; + color: var(--muted); + font-size: 0.56rem; + letter-spacing: 0.045em; + line-height: 1.35; +} + +.metrics-strip strong { + display: block; + margin: 0.12rem 0 0.08rem; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.88rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +.metrics-strip strong.metric-alert { + color: var(--amber); +} + +.table-scroll { + flex: 1; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +app-current-trading-table, +app-worker-trading-table { + display: flex; + flex-direction: column; + flex: 1; + min-width: 0; + min-height: 0; +} + +.virtual-scroll-footer { + display: flex; + flex: 0 0 auto; + align-items: center; + justify-content: space-between; + min-height: var(--virtual-footer-height); + padding: 0 var(--shell-inline-padding); + color: var(--muted); + background: var(--surface-toolbar); + border-top: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.68rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +table { + min-width: 100%; + border-spacing: 0; + table-layout: fixed; + font-family: var(--font-ui); + font-size: 0.78rem; + font-variant-numeric: tabular-nums; +} + +.virtual-table { + display: grid; +} + +.virtual-table thead { + display: grid; +} + +.virtual-table thead tr, +.virtual-table-row { + display: flex; + width: 100%; +} + +.virtual-table th, +.virtual-table-row > td { + flex: 0 0 auto; +} + +.virtual-table-body { + position: relative; + display: grid; +} + +.virtual-table-row { + position: absolute; + left: 0; + height: var(--table-row-height); +} + +.virtual-table-row > td { + display: block; +} + +.trading-data-grid { + display: grid; +} + +.trading-data-grid thead, +.trading-data-grid tbody { + display: grid; +} + +.trading-data-grid tbody { + -webkit-user-select: none; + user-select: none; +} + +.trading-data-grid thead > tr, +.trading-data-grid tbody > tr { + display: flex; + width: 100%; +} + +.trading-data-grid tbody > tr { + min-height: var(--table-row-height); + content-visibility: auto; + contain-intrinsic-block-size: var(--table-row-height); +} + +.trading-data-grid th, +.trading-data-grid td { + flex: 0 0 auto; +} + +thead { + position: sticky; + z-index: 2; + top: 0; +} + +th { + height: var(--table-header-height); + padding: 0 var(--table-cell-inline-padding); + color: var(--muted); + background: var(--surface-header); + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border); + font-size: 0.7rem; + font-weight: 500; + letter-spacing: 0.005em; + text-align: left; + white-space: nowrap; +} + +th.column-group-header { + color: #666b72; + font-size: 0.72rem; + font-weight: 500; + text-align: center; +} + +thead tr:first-child th.column-group-header { + color: #777d85; + font-size: 0.76rem; +} + +th.numeric-header { + text-align: right; +} + +td { + height: var(--table-row-height); + padding: 0 var(--table-cell-inline-padding); + overflow: hidden; + color: #eef1f5; + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border-soft); + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +th:last-child, +td:last-child { + border-right: 0; +} + +td[data-column-id='market'], +td[data-column-id='name'], +td[data-column-id='symbol'] { + text-align: left; +} + +td[data-column-id='market'] { + color: var(--blue); + font-weight: 550; +} + +td[data-column-id='name'] { + color: var(--text-strong); +} + +td[data-column-id='symbol'] { + color: #d8dde4; + font-weight: 600; +} + +tbody tr:nth-child(even) { + background: var(--row-alt); +} + +tbody tr.virtual-table-row.is-even-row { + background: var(--row-alt); +} + +tbody tr:hover { + background: var(--panel-hover); +} + +tbody tr[data-symbol-selected='true'] { + background: var(--row-selected); + box-shadow: inset 2px 0 0 var(--blue); +} + +.table-scroll:focus { + outline: none; +} + +th { + position: relative; +} + +.leaf-header-content { + display: flex; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + height: 100%; + align-items: stretch; + margin-inline: calc(-1 * var(--table-cell-inline-padding)); +} + +.column-drag-handle, +.sort-header-button { + min-width: 0; + height: 100%; + padding: 0; + color: inherit; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-weight: inherit; + letter-spacing: inherit; +} + +.column-drag-handle { + flex: 0 0 1.05rem; + color: var(--muted); + cursor: grab; + opacity: 0.35; + font-size: 0.56rem; + letter-spacing: -0.32rem; + text-align: center; +} + +.column-drag-handle:active { + cursor: grabbing; +} + +th:hover .column-drag-handle, +.column-drag-handle:focus-visible { + opacity: 0.9; +} + +.column-drag-handle:hover, +.sort-header-button:hover { + background: rgb(255 255 255 / 4%); + border-color: transparent; +} + +th.is-column-dragging { + opacity: 0.45; +} + +th.is-column-drop-target { + background: rgb(50 139 255 / 16%); + box-shadow: inset 4px 0 0 var(--blue); +} + +th.is-column-drop-target::before { + position: absolute; + z-index: 6; + top: -1px; + bottom: -1px; + left: -2px; + width: 4px; + background: #62a9ff; + box-shadow: + 0 0 0 1px rgb(0 0 0 / 55%), + 0 0 12px rgb(70 151 255 / 90%); + content: ''; + pointer-events: none; +} + +.sort-header-button { + display: flex; + min-width: 0; + flex: 1; + align-items: center; + justify-content: flex-start; + gap: 0.3rem; + padding-inline: 0.25rem var(--table-cell-inline-padding); + cursor: default; + text-align: inherit; +} + +.numeric-header .sort-header-button { + justify-content: flex-end; +} + +.sort-header-button.is-sortable { + cursor: pointer; +} + +.sort-header-button:disabled { + opacity: 1; +} + +.header-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.sort-indicator { + flex: 0 0 auto; + color: #66717e; + font-size: 0.72rem; +} + +.sort-indicator.is-active { + color: var(--blue-soft); +} + +.column-resize-handle { + position: absolute; + z-index: 3; + top: 0; + right: -3px; + width: 7px; + height: 100%; + cursor: col-resize; + touch-action: none; + user-select: none; +} + +.column-resize-handle::after { + position: absolute; + top: 20%; + right: 3px; + width: 1px; + height: 60%; + background: var(--border-strong); + content: ''; + opacity: 0; +} + +th:hover > .column-resize-handle::after, +.column-resize-handle.is-resizing::after { + background: var(--blue); + opacity: 1; +} + +tbody tr[aria-selected='true'] { + background: rgb(76 145 228 / 13%); +} + +td[aria-selected='true'] { + position: relative; + background: rgb(70 139 222 / 12%); +} + +td[data-cell-focused='true'] { + background: rgb(70 139 222 / 21%); +} + +td[aria-selected='true']::after { + position: absolute; + z-index: 1; + inset: 0; + border: 1px solid transparent; + content: ''; + pointer-events: none; +} + +td[data-selection-top='true']::after { + border-top-color: var(--blue); +} + +td[data-selection-right='true']::after { + border-right-color: var(--blue); +} + +td[data-selection-bottom='true']::after { + border-bottom-color: var(--blue); +} + +td[data-selection-left='true']::after { + border-left-color: var(--blue); +} + +.price-button { + min-width: 4.5rem; + padding: 0; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-variant-numeric: tabular-nums; + font-weight: 600; + text-align: right; +} + +.price-button:hover { + background: transparent; + text-decoration: underline; + text-underline-offset: 2px; +} + +.move-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.move-cell.quote-up, +.percent-change-cell.quote-up { + background: color-mix(in srgb, var(--green) 7%, transparent); +} + +.move-cell.quote-down, +.percent-change-cell.quote-down { + background: color-mix(in srgb, var(--red) 7%, transparent); +} + +.percent-change-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.spread-cell { + display: flex; + align-items: baseline; + justify-content: flex-end; + gap: 0.35rem; + color: var(--text); +} + +.spread-cell small { + min-width: 2.8rem; + color: var(--muted); + font-size: 0.55rem; +} + +.spread-cell.spread-wide, +.spread-cell.spread-wide small { + color: var(--amber); +} + +app-depth-cell, +app-stable-move-cell, +app-up-move-cell, +app-down-move-cell, +app-percent-change-cell, +app-sparkline-cell { + display: block; + width: 100%; +} + +.depth-cell { + position: relative; + display: flex; + height: 17px; + overflow: hidden; + background: var(--surface-control); +} + +.depth-bid, +.depth-ask { + height: 100%; + opacity: 0.78; +} + +.depth-bid { + background: var(--depth-bid); + border-right: 1px solid var(--panel); +} + +.depth-ask { + background: var(--depth-ask); +} + +.depth-values { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 0.28rem; + color: var(--text-strong); + font-size: 0.57rem; + text-shadow: 0 1px var(--background); +} + +.quote-age { + color: var(--muted); +} + +.quote-age-warm { + color: var(--amber); +} + +.quote-age-stale { + color: var(--red); +} + +.quote-up { + color: var(--green); +} + +.quote-down { + color: var(--red); +} + +.sparkline { + display: block; + width: 100%; + height: 1.35rem; + margin-left: auto; + color: var(--blue-soft); + overflow: visible; +} + +.sparkline.quote-up { + color: var(--green); +} + +.sparkline.quote-down { + color: var(--red); +} + +.sparkline polyline { + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-linejoin: miter; + stroke-width: 1.25; + vector-effect: non-scaling-stroke; +} + +.market-statusbar { + display: flex; + flex: 0 0 var(--statusbar-height); + min-height: var(--statusbar-height); + gap: 1.1rem; + align-items: center; + padding: 0 0.65rem; + color: var(--muted); + background: var(--surface-bar); + border-top: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.56rem; + grid-area: footer; + letter-spacing: 0.035em; +} + +.market-statusbar strong { + margin-left: 0.25rem; + color: var(--text); + font-weight: 500; +} + +.sidebar-slot { + width: var(--sidebar-width); + min-width: 0; + min-height: 0; + overflow: hidden; + background: var(--surface-table); + border-left: 1px solid var(--border); + grid-area: sidebar; + transition: + opacity 120ms ease, + transform 160ms ease, + visibility 160ms; +} + +.is-sidebar-collapsed .sidebar-slot { + visibility: hidden; + opacity: 0; + pointer-events: none; + transform: translateX(100%); +} + +.configurator { + width: 100%; + height: 100%; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +.configurator > header { + display: flex; + height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + color: var(--text-strong); + background: var(--surface-toolbar); + border-bottom: 1px solid var(--border); + font-size: 0.65rem; + font-weight: 700; + letter-spacing: 0.055em; +} + +.configurator > header small { + color: var(--muted); + font-size: 0.54rem; + font-weight: 500; +} + +.config-section { + display: grid; + gap: 0.7rem; + padding: 0.8rem var(--shell-inline-padding); + border-bottom: 1px solid var(--border); +} + +.config-section h2 { + margin: 0; + color: var(--muted); + font-size: 0.58rem; + letter-spacing: 0.075em; +} + +.primary-action { + width: 100%; + color: var(--text-inverse); + background: var(--blue); + border-color: var(--blue-soft); +} + +.primary-action:hover { + background: var(--blue-soft); + border-color: var(--text-strong); +} + +.field { + display: grid; + gap: 0.35rem; + color: var(--text); + font-size: 0.66rem; +} + +.rate-field > span { + display: flex; + justify-content: space-between; +} + +.rate-field strong { + color: var(--text); + font-family: var(--font-mono); + font-weight: 500; +} + +.field small { + color: var(--muted); + font-family: var(--font-mono); + font-size: 0.55rem; +} + +input[type='range'] { + width: 100%; + margin: 0; + accent-color: var(--blue); +} + +.toggle-field { + display: flex; + gap: 0.5rem; + align-items: flex-start; + color: var(--text); + font-size: 0.66rem; + line-height: 1.3; +} + +.toggle-field input { + margin: 0.12rem 0 0; + accent-color: var(--blue); +} + +.toggle-field small { + display: block; + margin-top: 0.14rem; + color: var(--muted); + font-size: 0.57rem; +} + +.action-grid { + display: grid; + grid-template-columns: 1fr; + gap: 0.4rem; +} + +.diagnostics dl, +.selected-instrument dl { + display: grid; + gap: 0; + margin: 0; +} + +.diagnostics dl > div, +.selected-instrument dl > div { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 24px; + border-bottom: 1px solid var(--border-soft); +} + +.diagnostics dl > div:last-child, +.selected-instrument dl > div:last-child { + border-bottom: 0; +} + +.diagnostics dl > div:has(dd[data-testid$='-breakdown']) { + display: grid; + grid-template-columns: minmax(0, 1fr); + align-content: center; + padding-block: 0.28rem; +} + +.diagnostics dd[data-testid$='-breakdown'] { + width: 100%; + overflow-x: auto; + padding-block: 0.12rem; + white-space: nowrap; + scrollbar-width: thin; +} + +.diagnostic-note { + margin: 0.5rem 0 0; + color: var(--muted); + font-size: 0.56rem; + line-height: 1.45; +} + +dt { + color: var(--muted); + font-size: 0.61rem; +} + +dd { + margin: 0; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.62rem; +} + +.selection { + display: flex; + align-items: flex-start; + justify-content: space-between; +} + +.selection div { + display: grid; + gap: 0.18rem; +} + +.selection strong { + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.85rem; +} + +.selection span, +.selection small, +.selected-instrument p { + color: var(--muted); + font-size: 0.61rem; +} + +.selected-instrument p { + margin: 0; + line-height: 1.45; +} + +@media (max-width: 980px) { + :root { + --sidebar-width: 15.625rem; + } +} + +@media (max-width: 720px) { + .trading-terminal { + --active-sidebar-width: 0px; + height: 100dvh; + min-height: 0; + overflow: hidden; + } + + .market-panel { + min-height: 0; + } + + .table-scroll { + min-height: 0; + } + + .sidebar-slot { + position: fixed; + z-index: 20; + top: 0; + right: 0; + bottom: 0; + width: min(var(--sidebar-width), calc(100vw - 2.75rem)); + box-shadow: -18px 0 42px rgb(0 0 0 / 48%); + } + + .is-sidebar-collapsed .sidebar-slot { + box-shadow: none; + } +} diff --git a/examples/angular/realtime-trading/tests/e2e/smoke.spec.ts b/examples/angular/realtime-trading/tests/e2e/smoke.spec.ts new file mode 100644 index 0000000000..038af501a5 --- /dev/null +++ b/examples/angular/realtime-trading/tests/e2e/smoke.spec.ts @@ -0,0 +1,249 @@ +import path from 'node:path' +import { expect, test } from '@playwright/test' +import { startExampleServer } from '../../../../../tests/e2e/helpers/startExampleServer' +import { + setRangeValue, + scrollTradingTable, + pauseTradingFeed, + resumeTradingFeed, +} from '../../../../../tests/e2e/helpers/setRangeValue' +import type { Page } from '@playwright/test' + +const exampleDir = path.resolve() + +function collectPageErrors(page: Page) { + const errors: Array = [] + + page.on('pageerror', (error) => errors.push(error.message)) + page.on('console', (message) => { + if (message.type() === 'error') errors.push(message.text()) + }) + + return errors +} + +test('runs the Angular realtime trading workload', async ({ page }) => { + test.setTimeout(120_000) + const server = await startExampleServer(exampleDir) + const errors = collectPageErrors(page) + + try { + await page.goto(server.url) + + const table = page.getByTestId('trading-table') + const instrumentCount = page.getByTestId('instrument-count-select') + const virtualScrollSelect = page.getByTestId('virtual-scroll-select') + await expect(table).toBeVisible() + await expect(instrumentCount).toHaveValue('100') + await expect(page.locator('.brand')).toHaveText('MARKET MONITOR') + await expect(virtualScrollSelect).toHaveValue('none') + await expect(virtualScrollSelect).toBeEnabled() + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(table.locator('tbody')).toHaveCSS('user-select', 'none') + await expect(table.locator('tbody tr').first()).toHaveCSS( + 'content-visibility', + 'auto', + ) + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await instrumentCount.selectOption('250') + await expect(virtualScrollSelect).toHaveValue('tanstack') + await expect(virtualScrollSelect).toBeEnabled() + await expect.poll(() => table.locator('tbody tr').count()).toBeLessThan(250) + await expect(page.getByTestId('virtual-scroll-footer')).toBeVisible() + await instrumentCount.selectOption('100') + await expect(virtualScrollSelect).toHaveValue('none') + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await virtualScrollSelect.selectOption('tanstack') + await expect.poll(() => table.locator('tbody tr').count()).toBeLessThan(100) + await expect(table.locator('tbody tr').first()).toHaveCSS( + 'content-visibility', + 'auto', + ) + await expect(page.getByTestId('virtual-scroll-footer')).toBeVisible() + await virtualScrollSelect.selectOption('none') + await expect(table.locator('tbody tr')).toHaveCount(100) + await pauseTradingFeed(page) + await instrumentCount.selectOption('1500') + await expect(virtualScrollSelect).toHaveValue('tanstack') + await expect(virtualScrollSelect).toBeDisabled() + await expect + .poll(() => table.locator('tbody tr').count()) + .toBeLessThan(1500) + await expect(page.getByTestId('virtual-scroll-footer')).toContainText( + 'Total · 1500 rows · 14 columns', + ) + await expect(page.getByTestId('visible-row-range')).toHaveText( + /^\s*Current · rows 0\.\.\d+\s*$/, + ) + await scrollTradingTable(page, 2_000) + await expect + .poll(async () => + Number( + await table + .locator('tbody tr') + .first() + .getAttribute('data-virtual-index'), + ), + ) + .toBeGreaterThan(0) + await expect(page.getByTestId('visible-row-range')).toHaveText( + /^\s*Current · rows [1-9]\d*\.\.\d+\s*$/, + ) + await instrumentCount.selectOption('100') + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await expect(virtualScrollSelect).toHaveValue('none') + await expect(virtualScrollSelect).toBeEnabled() + await expect(table.locator('tbody tr')).toHaveCount(100) + await resumeTradingFeed(page) + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await expect(virtualScrollSelect).toHaveValue('none') + await expect(virtualScrollSelect).toBeEnabled() + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(table.locator('thead tr')).toHaveCount(2) + await expect(table.locator('thead tr').last().locator('th')).toHaveCount(14) + await expect(table.locator('thead')).not.toContainText('Identity') + await expect(table.locator('thead')).not.toContainText('Market Data') + await expect(table.locator('thead')).toContainText('Market') + await expect(table.locator('thead')).toContainText('Bid Vol') + await expect(table.locator('thead')).toContainText('Intraday') + + const selectionStart = table.locator('tbody tr').nth(0).locator('td').nth(1) + const selectionEnd = table.locator('tbody tr').nth(2).locator('td').nth(3) + const selectedSymbol = await table + .locator('tbody tr') + .nth(0) + .getAttribute('data-symbol') + const selectionStartBox = await selectionStart.boundingBox() + const selectionEndBox = await selectionEnd.boundingBox() + if (!selectionStartBox || !selectionEndBox) { + throw new Error('Expected visible cells for the drag-selection check') + } + await page.mouse.move( + selectionStartBox.x + selectionStartBox.width / 2, + selectionStartBox.y + selectionStartBox.height / 2, + ) + await page.mouse.down() + await page.mouse.move( + selectionEndBox.x + selectionEndBox.width / 2, + selectionEndBox.y + selectionEndBox.height / 2, + { steps: 4 }, + ) + await page.mouse.up() + await expect(table.locator('td[aria-selected="true"]')).toHaveCount(9) + await expect(page.getByTestId('selected-instrument')).toContainText( + selectedSymbol ?? '', + ) + + await expect(page.getByTestId('feed-status')).toHaveText('FEED LIVE') + await expect(instrumentCount.locator('option[value="150"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="350"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="750"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="1500"]')).toHaveCount(1) + + const targetRateSlider = page.getByTestId('target-rate-slider') + await expect(targetRateSlider).toHaveAttribute('min', '0') + await expect(targetRateSlider).toHaveAttribute('max', '9') + await expect(targetRateSlider).toHaveAttribute('step', '1') + await expect(targetRateSlider).toHaveValue('6') + await setRangeValue(targetRateSlider, '7') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '25K samples/s', + ) + await setRangeValue(targetRateSlider, '8') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '50K samples/s', + ) + await setRangeValue(targetRateSlider, '6') + + const sparklineInterval = page.getByTestId( + 'sparkline-sample-interval-select', + ) + await expect(sparklineInterval).toHaveValue('16') + await sparklineInterval.selectOption('100') + await expect(sparklineInterval).toHaveValue('100') + await sparklineInterval.selectOption('16') + + const publishInterval = page.getByTestId('publish-interval-select') + await expect(publishInterval.locator('option[value="500"]')).toHaveCount(1) + await expect(publishInterval.locator('option[value="1000"]')).toHaveCount(1) + + await expect + .poll(async () => { + const text = await page.getByTestId('row-update-rate').textContent() + return Number(text?.replace(/\D/g, '') ?? 0) + }) + .toBeGreaterThan(0) + await expect + .poll(async () => { + const text = await page.getByTestId('worker-messages').textContent() + return Number(text?.replace(/\D/g, '') ?? 0) + }) + .toBeGreaterThan(0) + await expect + .poll(async () => + Number(await page.getByTestId('message-rate').textContent()), + ) + .toBeGreaterThan(0) + await expect + .poll(async () => + Number(await page.getByTestId('table-render-rate').textContent()), + ) + .toBeGreaterThan(0) + await expect(page.getByTestId('long-frame-count')).toHaveText( + /^\s*(?:N\/A|\d+)\s*$/, + ) + + const tableWorker = page.getByTestId('table-worker-toggle') + await expect(tableWorker).toBeEnabled() + await tableWorker.check() + await expect(page.getByText('ROW MODEL WORKER ON')).toBeVisible() + await expect(table.locator('tbody tr')).toHaveCount(100) + await instrumentCount.selectOption('1500') + await expect + .poll(() => table.locator('tbody tr').count()) + .toBeLessThan(1500) + await instrumentCount.selectOption('100') + await expect(table.locator('tbody tr')).toHaveCount(100) + await page.getByTestId('feed-toggle').click() + await expect + .poll(() => + page + .locator('app-worker-trading-table [data-table-worker-pending]') + .getAttribute('data-table-worker-compute-ms'), + ) + .not.toBeNull() + await expect( + page.locator('app-worker-trading-table [data-table-worker-pending]'), + ).toHaveAttribute('data-table-worker-pending', 'false') + await page.getByTestId('feed-toggle').click() + await tableWorker.uncheck() + + await expect(tableWorker).toBeEnabled() + await instrumentCount.selectOption('1500') + await expect + .poll(() => table.locator('tbody tr').count()) + .toBeLessThan(1500) + await expect(page.getByTestId('virtual-scroll-footer')).toBeVisible() + const firstPrice = table.locator('tbody tr').first().getByRole('button') + const priceBeforeUpdate = await firstPrice.textContent() + await expect + .poll(() => firstPrice.textContent()) + .not.toBe(priceBeforeUpdate) + await instrumentCount.selectOption('100') + await expect(table.locator('tbody tr')).toHaveCount(100) + + await page + .getByLabel( + 'Swap Tick component A ↔ B destroy and recreate when direction changes', + ) + .check() + await page.getByTestId('feed-toggle').click() + await expect(page.getByTestId('feed-toggle')).toHaveText('START FEED') + await expect(page.getByTestId('feed-status')).toHaveText('FEED PAUSED') + + expect(errors).toEqual([]) + } finally { + await server.close() + } +}) diff --git a/examples/angular/realtime-trading/tsconfig.app.json b/examples/angular/realtime-trading/tsconfig.app.json new file mode 100644 index 0000000000..8426ad9558 --- /dev/null +++ b/examples/angular/realtime-trading/tsconfig.app.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [] + }, + "include": ["src/**/*.ts"], + "exclude": ["src/**/*.spec.ts"] +} diff --git a/examples/angular/realtime-trading/tsconfig.json b/examples/angular/realtime-trading/tsconfig.json new file mode 100644 index 0000000000..9ff0bce067 --- /dev/null +++ b/examples/angular/realtime-trading/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "skipLibCheck": true, + "isolatedModules": true, + "experimentalDecorators": true, + "importHelpers": true, + "target": "ES2022", + "module": "preserve" + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + }, + "include": ["**/*.ts", "tests/e2e"] +} diff --git a/examples/angular/remote-data/package.json b/examples/angular/remote-data/package.json index 0f49d863ff..82bd7a6bb4 100644 --- a/examples/angular/remote-data/package.json +++ b/examples/angular/remote-data/package.json @@ -14,7 +14,7 @@ "serve:ssr:remote-data": "node dist/remote-data/server/server.mjs" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -24,14 +24,14 @@ "@angular/platform-browser-dynamic": "^22.1.1", "@angular/platform-server": "^22.1.1", "@angular/router": "^22.1.1", - "@angular/ssr": "^22.1.2", + "@angular/ssr": "^22.1.6", "@tanstack/angular-table": "^9.2.3", "express": "^5.2.1", "rxjs": "~7.8.2" }, "devDependencies": { - "@angular-devkit/build-angular": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular-devkit/build-angular": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "@types/express": "^5.0.6", "@types/node": "^26.2.0", diff --git a/examples/angular/row-dnd/package.json b/examples/angular/row-dnd/package.json index 9cb47f6a15..6a8865b66e 100644 --- a/examples/angular/row-dnd/package.json +++ b/examples/angular/row-dnd/package.json @@ -11,23 +11,23 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { - "@angular/cdk": "^22.1.0", + "@angular/cdk": "^22.1.4", "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", "@angular/core": "^22.1.1", "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/row-pinning/package.json b/examples/angular/row-pinning/package.json index f2f72785ba..76033534f7 100644 --- a/examples/angular/row-pinning/package.json +++ b/examples/angular/row-pinning/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/row-selection-signal/package.json b/examples/angular/row-selection-signal/package.json index 1e51ecccd7..a640e6b630 100644 --- a/examples/angular/row-selection-signal/package.json +++ b/examples/angular/row-selection-signal/package.json @@ -12,7 +12,7 @@ "test:types": "tsc -p tsconfig.app.json --noEmit" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/animations": "^22.1.1", "@angular/common": "^22.1.1", @@ -21,16 +21,16 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/platform-browser-dynamic": "^22.1.1", - "@faker-js/faker": "^10.5.0", - "@tanstack/angular-devtools": "^0.0.9", + "@faker-js/faker": "^10.6.0", + "@tanstack/angular-devtools": "^0.0.11", "@tanstack/angular-table": "^9.2.3", "@tanstack/angular-table-devtools": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/row-selection/package.json b/examples/angular/row-selection/package.json index da89db224d..a25072ccf3 100644 --- a/examples/angular/row-selection/package.json +++ b/examples/angular/row-selection/package.json @@ -11,25 +11,25 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { - "@angular/cdk": "^22.1.0", + "@angular/cdk": "^22.1.4", "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", "@angular/core": "^22.1.1", "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", - "@tanstack/angular-devtools": "^0.0.9", + "@faker-js/faker": "^10.6.0", + "@tanstack/angular-devtools": "^0.0.11", "@tanstack/angular-table": "^9.2.3", "@tanstack/angular-table-devtools": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/signal-input/package.json b/examples/angular/signal-input/package.json index a1c8d0456f..027f41c349 100644 --- a/examples/angular/signal-input/package.json +++ b/examples/angular/signal-input/package.json @@ -11,23 +11,23 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { - "@angular/cdk": "^22.1.0", + "@angular/cdk": "^22.1.4", "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", "@angular/core": "^22.1.1", "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/sorting/package.json b/examples/angular/sorting/package.json index 35565c6a62..b93ce971c0 100644 --- a/examples/angular/sorting/package.json +++ b/examples/angular/sorting/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/sub-components/package.json b/examples/angular/sub-components/package.json index 88b1e9660a..a5d526b463 100644 --- a/examples/angular/sub-components/package.json +++ b/examples/angular/sub-components/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,14 +19,14 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/virtualized-columns/package.json b/examples/angular/virtualized-columns/package.json index db2b356b77..cdf4b4d151 100644 --- a/examples/angular/virtualized-columns/package.json +++ b/examples/angular/virtualized-columns/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,15 +19,15 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", - "@tanstack/angular-virtual": "^6.0.2", + "@tanstack/angular-virtual": "^6.0.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/virtualized-infinite-scrolling/package.json b/examples/angular/virtualized-infinite-scrolling/package.json index f68f244327..8dce8a25da 100644 --- a/examples/angular/virtualized-infinite-scrolling/package.json +++ b/examples/angular/virtualized-infinite-scrolling/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,15 +19,15 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", - "@tanstack/angular-virtual": "^6.0.2", + "@tanstack/angular-virtual": "^6.0.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/virtualized-rows/package.json b/examples/angular/virtualized-rows/package.json index e65088d0cc..5a3a2f1b9d 100644 --- a/examples/angular/virtualized-rows/package.json +++ b/examples/angular/virtualized-rows/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,15 +19,15 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/angular-table": "^9.2.3", - "@tanstack/angular-virtual": "^6.0.2", + "@tanstack/angular-virtual": "^6.0.3", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/with-tanstack-form/package.json b/examples/angular/with-tanstack-form/package.json index 9d91fa11ff..9b477276eb 100644 --- a/examples/angular/with-tanstack-form/package.json +++ b/examples/angular/with-tanstack-form/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,8 +19,8 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", - "@tanstack/angular-devtools": "^0.0.9", + "@faker-js/faker": "^10.6.0", + "@tanstack/angular-devtools": "^0.0.11", "@tanstack/angular-form": "^1.33.5", "@tanstack/angular-table": "^9.2.3", "@tanstack/angular-table-devtools": "^9.2.3", @@ -29,8 +29,8 @@ "zod": "^4.4.3" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/angular/with-tanstack-query/package.json b/examples/angular/with-tanstack-query/package.json index ddee7bfe6c..36829ef242 100644 --- a/examples/angular/with-tanstack-query/package.json +++ b/examples/angular/with-tanstack-query/package.json @@ -11,7 +11,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "private": true, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "dependencies": { "@angular/common": "^22.1.1", "@angular/compiler": "^22.1.1", @@ -19,8 +19,8 @@ "@angular/forms": "^22.1.1", "@angular/platform-browser": "^22.1.1", "@angular/router": "^22.1.1", - "@faker-js/faker": "^10.5.0", - "@tanstack/angular-devtools": "^0.0.9", + "@faker-js/faker": "^10.6.0", + "@tanstack/angular-devtools": "^0.0.11", "@tanstack/angular-query-experimental": "^5.101.4", "@tanstack/angular-table": "^9.2.3", "@tanstack/angular-table-devtools": "^9.2.3", @@ -28,8 +28,8 @@ "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.2", - "@angular/cli": "^22.1.2", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", "@angular/compiler-cli": "^22.1.1", "typescript": "6.0.3" } diff --git a/examples/ember/aggregation/package.json b/examples/ember/aggregation/package.json index 658e1c32d7..e14f7631cf 100644 --- a/examples/ember/aggregation/package.json +++ b/examples/ember/aggregation/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/basic-app-table/package.json b/examples/ember/basic-app-table/package.json index f64428a8ed..fcac83ca8e 100644 --- a/examples/ember/basic-app-table/package.json +++ b/examples/ember/basic-app-table/package.json @@ -38,14 +38,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/basic-external-atoms/package.json b/examples/ember/basic-external-atoms/package.json index da8191f41c..551c0aa7a4 100644 --- a/examples/ember/basic-external-atoms/package.json +++ b/examples/ember/basic-external-atoms/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/basic-external-state/package.json b/examples/ember/basic-external-state/package.json index 6f768787ff..d534843232 100644 --- a/examples/ember/basic-external-state/package.json +++ b/examples/ember/basic-external-state/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/basic-table/package.json b/examples/ember/basic-table/package.json index 1b9ffdf6ec..f212436ce4 100644 --- a/examples/ember/basic-table/package.json +++ b/examples/ember/basic-table/package.json @@ -38,14 +38,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/cell-selection/package.json b/examples/ember/cell-selection/package.json index 2820dd5c67..09d8d23851 100644 --- a/examples/ember/cell-selection/package.json +++ b/examples/ember/cell-selection/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "@tanstack/hotkeys": "^0.8.0", @@ -40,14 +40,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/cell-spanning/package.json b/examples/ember/cell-spanning/package.json index 615d860ae5..7b9443311c 100644 --- a/examples/ember/cell-spanning/package.json +++ b/examples/ember/cell-spanning/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/column-ordering/package.json b/examples/ember/column-ordering/package.json index f2d1dff020..bf1064b8f2 100644 --- a/examples/ember/column-ordering/package.json +++ b/examples/ember/column-ordering/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/column-pinning-split/package.json b/examples/ember/column-pinning-split/package.json index b73fd33d92..64ac649a64 100644 --- a/examples/ember/column-pinning-split/package.json +++ b/examples/ember/column-pinning-split/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/column-pinning-sticky/package.json b/examples/ember/column-pinning-sticky/package.json index d7b3547b6a..c289931e77 100644 --- a/examples/ember/column-pinning-sticky/package.json +++ b/examples/ember/column-pinning-sticky/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/column-pinning/package.json b/examples/ember/column-pinning/package.json index 1a4236b8bb..6fa5da9d65 100644 --- a/examples/ember/column-pinning/package.json +++ b/examples/ember/column-pinning/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/column-resizing-performant/package.json b/examples/ember/column-resizing-performant/package.json index d24e2a416c..716b3747f5 100644 --- a/examples/ember/column-resizing-performant/package.json +++ b/examples/ember/column-resizing-performant/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/column-resizing/package.json b/examples/ember/column-resizing/package.json index 0910b71512..fb9309f70e 100644 --- a/examples/ember/column-resizing/package.json +++ b/examples/ember/column-resizing/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/column-sizing/package.json b/examples/ember/column-sizing/package.json index 0ab737b8c1..7d432c4b66 100644 --- a/examples/ember/column-sizing/package.json +++ b/examples/ember/column-sizing/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/column-visibility/package.json b/examples/ember/column-visibility/package.json index e995e22aa7..6ebc8e2536 100644 --- a/examples/ember/column-visibility/package.json +++ b/examples/ember/column-visibility/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/custom-plugin/package.json b/examples/ember/custom-plugin/package.json index 96c2a530f3..e51e8c6b2a 100644 --- a/examples/ember/custom-plugin/package.json +++ b/examples/ember/custom-plugin/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "@tanstack/table-core": "^9.2.3", @@ -40,14 +40,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/editable/package.json b/examples/ember/editable/package.json index ebb3d5f547..6c39b8ca5a 100644 --- a/examples/ember/editable/package.json +++ b/examples/ember/editable/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/expanding/package.json b/examples/ember/expanding/package.json index 6fe922ef29..298c7f47ad 100644 --- a/examples/ember/expanding/package.json +++ b/examples/ember/expanding/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/filters-faceted-bucketed/package.json b/examples/ember/filters-faceted-bucketed/package.json index ace0cb08cd..b0f8668e26 100644 --- a/examples/ember/filters-faceted-bucketed/package.json +++ b/examples/ember/filters-faceted-bucketed/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/filters-faceted/package.json b/examples/ember/filters-faceted/package.json index 6af1bb1ff3..486bee1dc5 100644 --- a/examples/ember/filters-faceted/package.json +++ b/examples/ember/filters-faceted/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/filters-fuzzy/package.json b/examples/ember/filters-fuzzy/package.json index e5bd43c81d..52d37829dc 100644 --- a/examples/ember/filters-fuzzy/package.json +++ b/examples/ember/filters-fuzzy/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "@tanstack/match-sorter-utils": "^9.1.2", @@ -40,14 +40,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/filters/package.json b/examples/ember/filters/package.json index 7b5fabacf4..4347c35132 100644 --- a/examples/ember/filters/package.json +++ b/examples/ember/filters/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/grouped-aggregation/package.json b/examples/ember/grouped-aggregation/package.json index 48391bfb26..a7cf41961c 100644 --- a/examples/ember/grouped-aggregation/package.json +++ b/examples/ember/grouped-aggregation/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/grouping/package.json b/examples/ember/grouping/package.json index 2275ab8d7f..4a6fb46ec1 100644 --- a/examples/ember/grouping/package.json +++ b/examples/ember/grouping/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/header-groups/package.json b/examples/ember/header-groups/package.json index b112e6743a..66b9898dbc 100644 --- a/examples/ember/header-groups/package.json +++ b/examples/ember/header-groups/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/kitchen-sink/package.json b/examples/ember/kitchen-sink/package.json index 1c5701a70e..003eaea10f 100644 --- a/examples/ember/kitchen-sink/package.json +++ b/examples/ember/kitchen-sink/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "@tanstack/match-sorter-utils": "^9.1.2", @@ -40,14 +40,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/pagination/package.json b/examples/ember/pagination/package.json index d75a38ab94..1304e2538f 100644 --- a/examples/ember/pagination/package.json +++ b/examples/ember/pagination/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/realtime-trading/README.md b/examples/ember/realtime-trading/README.md new file mode 100644 index 0000000000..141a8603fb --- /dev/null +++ b/examples/ember/realtime-trading/README.md @@ -0,0 +1,154 @@ +# Ember realtime trading benchmark + +This standalone example exercises the current TanStack Ember Table adapter +with a high-frequency worker feed, immutable snapshots, interactive columns, +Glimmer quote components, Virtual Core, and browser diagnostics. It is a +repeatable rendering stress workload, not an exchange or network benchmark. + +## Run and verify + +```bash +pnpm --dir examples/ember/realtime-trading dev +``` + +Open `http://localhost:7777`. + +```bash +pnpm --dir examples/ember/realtime-trading test:types +pnpm --dir examples/ember/realtime-trading build +pnpm --dir examples/ember/realtime-trading test:e2e +``` + +This example currently has no separate `lint` package script. Use a production +build for performance recordings. + +## Structure and ownership + +| Path | Responsibility | +| ------------------------------- | ---------------------------------------------------------------------------------------------------------------- | +| `app/feed/` | Market model, instrument universe, configuration, immutable update helpers, and Ember-native tracked controller. | +| `app/feed/worker/` | Typed protocol, deterministic engine, and module worker. | +| `app/benchmark/` | Browser monitor and benchmark controller. | +| `app/components/shell/` | GTS header, metrics, configurator, diagnostics, selected instrument, status bar, and shell layout. | +| `app/components/table/` | Trading table Glimmer component. | +| `app/table/table-config/` | Grouped columns and custom GTS quote components. | +| `app/table/` | Table construction, features, delegated interactions, and Virtual Core integration. | +| `app/utils/subscriptions.ts` | Owner-bound destruction cleanup helper. | +| `app/templates/application.gts` | Creates feed/benchmark controllers and composes the shell. | + +`MarketFeedController` owns worker/feed state. `TradingBenchmarkController` +observes feed lifecycle callbacks and owns diagnostic/view state. The +application passes stable controllers to shell/table components; Glimmer +components read the controller's `@tracked` properties directly. `quotes` is +its own high-frequency tracked property; feed status and each configuration +value are separate tracked properties. Derived benchmark values use `@cached`. +There is no foreign Store subscription or mirrored component state, and the +root does not proxy every quote or metric as application state. + +## Feed and worker pipeline + +Defaults are 100 instruments, 10K generated samples/s, 20 ms delivery, enabled +intraday charts, and 16 ms chart sampling. + +Mutable quote state is private to the worker. A deterministic 16 ms budget loop +generates samples, a row-indexed `Map` coalesces repeated changes, and a separate +timer publishes the latest unique rows. The main thread creates a new outer +array and replaces only changed rows; untouched rows and unsampled history +arrays retain references. Session IDs reject stale messages after resets or +instrument-count changes. + +- **Synthetic quote workload** is worker-generated samples/s, not Glimmer + renders, events, or messages. +- **Worker delivery interval** controls coalesced message cadence; 20 ms targets + around 50 messages/s. +- **Row updates** is the number of unique immutable rows applied. +- **Message samples** is the generated work represented by the latest message. + +Intraday history uses its own cadence. The 25K burst deliberately publishes one +heavy batch. The worker resembles an upstream stream, without network latency. + +## Ember table architecture + +The grid has 14 leaf columns grouped into Instrument, Price & Change, Order +Book, Session, and Chart. It includes sorting/filtering, on-change resizing, +double-click reset, drag ordering, CSS hover, row selection, drag cell ranges, +keyboard navigation, and Price/Move/Percent/Sparkline Glimmer components. + +`flexRenderComponent` is used for actual component cells. Stable instrument IDs +back row identity. One table/body interaction path resolves cells through +`event.composedPath()` and data attributes instead of allocating handlers on +every cell. Column widths are CSS variables updated on sizing/order; a +`ResizeObserver` performs initial fitting until manual resize. The +CSS-variable string is an `@cached` getter that reads Ember-reactive table +sizing and order, so the first fit and later table updates reach the DOM +without an imperative Store subscription. A/B move component swapping is an +explicit lifecycle stress mode. + +## Virtualization + +- Below 200 rows, automatic mode uses Full DOM, while Virtual is selectable. +- From 200 through 1,499 rows, automatic mode uses TanStack Virtual and Full DOM + remains selectable. +- At 1,500 rows or more, Virtual is forced and its control is disabled. + +The local Virtual Core integration owns one instance with 32 px estimates, +10-row overscan, stable row IDs, transformed rows, and a spacer body. Instance +notifications invalidate only the table range, and the footer reads that range. +Both Full DOM and virtual rows use `content-visibility: auto`; Full DOM still +creates every Glimmer row/cell. + +## Performance decisions + +- worker-side generation and pre-message coalescing; +- immutable structural sharing for rows/history; +- direct `@tracked` feed/view state and `@cached` derived state; +- stable table and virtual row identity; +- componentized GTS shell/table/cell boundaries; +- delegated pointer input and CSS hover; +- CSS variables for width propagation; +- opt-in lifecycle churn and independently sampled charts; +- virtual mounting for larger row counts; +- explicit destructor cleanup and lower-frequency metric publication. + +The outer array intentionally changes for an immutable batch. Structural +sharing reduces cell work, but sorting/filtering can still trigger row-model +processing when data changes. + +## Diagnostics and interpretation + +The compact **Live health** section lives in the configurator and reports the +estimated frame callback rate over 1 second, average market-mutation-to-DOM- +commit latency over 3 seconds, cumulative long animation frames, and throughput +as changed rows plus applied snapshots per second. Detailed diagnostics retain +worker samples/messages, state applies, DOM commits, rolling 10-second p95/max +commit latency, cumulative slow commits, mounted hosts, component +lifecycle/execution, row-model timing, DOM mutation records, and heap. + +The frame value counts `requestAnimationFrame` callbacks, not GPU-presented +frames, so its ceiling follows the display refresh rate. Renderer callbacks and +DOM mutations are different measurements. `MutationObserver` counts delivered +records, not individual DOM operations, and has overhead on a hot subtree; it +only observes text, child-list, and `class`/`style` changes to reduce selection +noise. Heap is a Chromium-only, GC-sensitive point-in-time value. User Timing +timeline measures are sampled 1-in-20 while the in-memory latency calculation +keeps every commit, reducing profiler self-interference. Temporary heap growth +during component swapping is not a leak without post-GC retention. +The rAF loop only appends a timestamp; rolling aggregation and heap reads run at +the 500 ms metrics publication cadence. Mutation observation remains the most +intrusive diagnostic because the browser must create records for the observed +subtree. + +`Changed rows/s` sums the update array lengths delivered by each snapshot. +Symbols are deduplicated inside one message, but the same row can count again in +the next snapshot; it is applied row throughput, not distinct instruments per +second. + +## Standalone policy + +All instruments, feed, worker, benchmark, shell, styles, and table code are +copied into this directory intentionally. It remains independently runnable and +StackBlitz-friendly, so common implementation and README material is repeated +across adapters by design. + +The workspace resolves `@tanstack/ember-table` to the repository adapter while +the example package remains release-like. diff --git a/examples/ember/realtime-trading/app/app.css b/examples/ember/realtime-trading/app/app.css new file mode 100644 index 0000000000..de3e3d9155 --- /dev/null +++ b/examples/ember/realtime-trading/app/app.css @@ -0,0 +1,1014 @@ +:root { + color-scheme: dark; + --font-ui: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + 'Segoe UI', sans-serif; + --font-mono: 'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace; + font-family: var(--font-ui); + font-synthesis: none; + --background: #050505; + --panel: #080808; + --panel-raised: #111111; + --panel-hover: #181818; + --surface-bar: #080808; + --surface-toolbar: #0d0d0d; + --surface-table: #050505; + --surface-header: #101010; + --surface-control: #151515; + --border: #303030; + --border-soft: #242424; + --border-strong: #4a4a4a; + --text: #e7ebf0; + --text-strong: #ffffff; + --text-inverse: #f7f9fb; + --muted: #737982; + --blue: #62a9ff; + --blue-soft: #a9d0ff; + --green: #42e488; + --red: #ff646b; + --amber: #dfb465; + --depth-bid: #315774; + --depth-ask: #634049; + --row-alt: rgb(255 255 255 / 1.8%); + --row-selected: rgb(66 132 214 / 16%); + --control-border: #354456; + --control-hover: #192431; + --sidebar-width: 18rem; + --shell-bar-height: 2.625rem; + --metrics-height: 3.5rem; + --statusbar-height: 1.625rem; + --table-header-height: 2rem; + --table-row-height: 2rem; + --shell-inline-padding: 0.75rem; + --table-cell-inline-padding: 0.6rem; + --control-radius: 1px; +} + +* { + box-sizing: border-box; +} + +html, +body { + min-width: 320px; + min-height: 100%; + margin: 0; + background: var(--background); +} + +body { + color: var(--text); +} + +button, +select, +input { + font: inherit; +} + +button, +select { + color: var(--text); + background: var(--panel-raised); + border: 1px solid var(--control-border); + border-radius: var(--control-radius); +} + +button { + padding: 0.5rem 0.65rem; + cursor: pointer; + font-size: 0.72rem; + font-weight: 650; + letter-spacing: 0.025em; +} + +button:hover { + background: var(--control-hover); + border-color: var(--border-strong); +} + +button:focus-visible, +select:focus-visible, +input:focus-visible { + outline: 1px solid var(--blue); + outline-offset: 1px; +} + +select { + width: 100%; + padding: 0.45rem 0.55rem; + font-size: 0.75rem; +} + +.trading-terminal { + --active-sidebar-width: var(--sidebar-width); + display: grid; + width: 100%; + height: 100dvh; + min-height: 0; + overflow: hidden; + background: var(--background); + grid-template-areas: + 'header sidebar' + 'content sidebar' + 'footer sidebar'; + grid-template-columns: minmax(0, 1fr) var(--active-sidebar-width); + grid-template-rows: auto minmax(0, 1fr) auto; + transition: grid-template-columns 160ms ease; +} + +.trading-terminal.is-sidebar-collapsed { + --active-sidebar-width: 0px; +} + +.shell-header { + display: flex; + min-width: 0; + flex-direction: column; + grid-area: header; +} + +.app-bar { + display: flex; + min-height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + background: var(--surface-bar); + border-bottom: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.68rem; + letter-spacing: 0.045em; +} + +.brand, +.header-actions, +.feed-status { + display: flex; + align-items: center; +} + +.brand { + gap: 0.65rem; + color: var(--text-strong); +} + +.header-actions { + gap: 0.75rem; +} + +.sidebar-toggle { + display: grid; + width: 1.9rem; + height: 1.9rem; + padding: 0; + place-items: center; + color: var(--muted); + background: transparent; + border-color: transparent; +} + +.sidebar-toggle:hover { + color: var(--text-strong); + background: var(--surface-control); + border-color: var(--border); +} + +.sidebar-toggle svg { + width: 1rem; + height: 1rem; + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-width: 1.4; +} + +.feed-status { + gap: 0.4rem; + color: var(--muted); +} + +.feed-status.is-running { + color: var(--green); +} + +.status-dot { + width: 6px; + height: 6px; + background: var(--muted); + border-radius: 50%; +} + +.feed-status.is-running .status-dot { + background: var(--green); +} + +.development-warning { + flex: 0 0 auto; + padding: 0.3rem 0.75rem; + color: var(--amber); + background: color-mix(in srgb, var(--amber) 8%, var(--background)); + border-bottom: 1px solid color-mix(in srgb, var(--amber) 24%, var(--border)); + font-family: var(--font-mono); + font-size: 0.62rem; + letter-spacing: 0.04em; +} + +.market-panel { + display: flex; + min-width: 0; + min-height: 0; + flex-direction: column; + background: var(--panel); + grid-area: content; +} + +.metrics-strip { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + background: var(--border); + border-bottom: 1px solid var(--border); + gap: 1px; +} + +.metrics-strip h2 { + margin: 0; + padding: 0.65rem var(--shell-inline-padding) 0.45rem; + color: var(--muted); + background: var(--surface-table); + font-size: 0.58rem; + grid-column: 1 / -1; + letter-spacing: 0.075em; +} + +.metrics-strip article { + min-width: 0; + min-height: 4.25rem; + padding: 0.5rem var(--shell-inline-padding); + background: var(--surface-bar); +} + +.metrics-strip span, +.metrics-strip small { + display: block; + color: var(--muted); + font-size: 0.56rem; + letter-spacing: 0.045em; + line-height: 1.35; +} + +.metrics-strip strong { + display: block; + margin: 0.12rem 0 0.08rem; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.88rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +.metrics-strip strong.metric-alert { + color: var(--amber); +} + +.table-scroll { + flex: 1; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +table { + min-width: 100%; + border-spacing: 0; + table-layout: fixed; + font-family: var(--font-ui); + font-size: 0.78rem; + font-variant-numeric: tabular-nums; +} + +.trading-data-grid { + display: grid; +} + +.trading-data-grid thead, +.trading-data-grid tbody { + display: grid; +} + +.trading-data-grid tbody { + -webkit-user-select: none; + user-select: none; +} + +.trading-data-grid thead > tr, +.trading-data-grid tbody > tr { + display: flex; + width: 100%; +} + +.trading-data-grid tbody > tr { + min-height: var(--table-row-height); + content-visibility: auto; + contain-intrinsic-block-size: var(--table-row-height); +} + +.trading-data-grid th, +.trading-data-grid td { + flex: 0 0 auto; +} + +thead { + position: sticky; + z-index: 2; + top: 0; +} + +th { + height: var(--table-header-height); + padding: 0 var(--table-cell-inline-padding); + color: var(--muted); + background: var(--surface-header); + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border); + font-size: 0.7rem; + font-weight: 500; + letter-spacing: 0.005em; + text-align: left; + white-space: nowrap; +} + +th.column-group-header { + color: #666b72; + font-size: 0.72rem; + font-weight: 500; + text-align: center; +} + +thead tr:first-child th.column-group-header { + color: #777d85; + font-size: 0.76rem; +} + +th.numeric-header { + text-align: right; +} + +td { + height: var(--table-row-height); + padding: 0 var(--table-cell-inline-padding); + overflow: hidden; + color: #eef1f5; + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border-soft); + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +th:last-child, +td:last-child { + border-right: 0; +} + +td[data-column-id='market'], +td[data-column-id='name'], +td[data-column-id='symbol'] { + text-align: left; +} + +td[data-column-id='market'] { + color: var(--blue); + font-weight: 550; +} + +td[data-column-id='name'] { + color: var(--text-strong); +} + +td[data-column-id='symbol'] { + color: #d8dde4; + font-weight: 600; +} + +tbody tr:nth-child(even) { + background: var(--row-alt); +} + +tbody tr:hover { + background: var(--panel-hover); +} + +tbody tr[data-symbol-selected='true'] { + background: var(--row-selected); + box-shadow: inset 2px 0 0 var(--blue); +} + +.table-scroll:focus { + outline: none; +} + +th { + position: relative; +} + +.leaf-header-content { + display: flex; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + height: 100%; + align-items: stretch; + margin-inline: calc(-1 * var(--table-cell-inline-padding)); +} + +.column-drag-handle, +.sort-header-button { + min-width: 0; + height: 100%; + padding: 0; + color: inherit; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-weight: inherit; + letter-spacing: inherit; +} + +.column-drag-handle { + flex: 0 0 1.05rem; + color: var(--muted); + cursor: grab; + opacity: 0.35; + font-size: 0.56rem; + letter-spacing: -0.32rem; + text-align: center; +} + +.column-drag-handle:active { + cursor: grabbing; +} + +th:hover .column-drag-handle, +.column-drag-handle:focus-visible { + opacity: 0.9; +} + +.column-drag-handle:hover, +.sort-header-button:hover { + background: rgb(255 255 255 / 4%); + border-color: transparent; +} + +th.is-column-dragging { + opacity: 0.45; +} + +th.is-column-drop-target { + background: rgb(50 139 255 / 16%); + box-shadow: inset 4px 0 0 var(--blue); +} + +th.is-column-drop-target::before { + position: absolute; + z-index: 6; + top: -1px; + bottom: -1px; + left: -2px; + width: 4px; + background: #62a9ff; + box-shadow: + 0 0 0 1px rgb(0 0 0 / 55%), + 0 0 12px rgb(70 151 255 / 90%); + content: ''; + pointer-events: none; +} + +.sort-header-button { + display: flex; + min-width: 0; + flex: 1; + align-items: center; + justify-content: flex-start; + gap: 0.3rem; + padding-inline: 0.25rem var(--table-cell-inline-padding); + cursor: default; + text-align: inherit; +} + +.numeric-header .sort-header-button { + justify-content: flex-end; +} + +.sort-header-button.is-sortable { + cursor: pointer; +} + +.sort-header-button:disabled { + opacity: 1; +} + +.header-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.sort-indicator { + flex: 0 0 auto; + color: #66717e; + font-size: 0.72rem; +} + +.sort-indicator.is-active { + color: var(--blue-soft); +} + +.column-resize-handle { + position: absolute; + z-index: 3; + top: 0; + right: -3px; + width: 7px; + height: 100%; + cursor: col-resize; + touch-action: none; + user-select: none; +} + +.column-resize-handle::after { + position: absolute; + top: 20%; + right: 3px; + width: 1px; + height: 60%; + background: var(--border-strong); + content: ''; + opacity: 0; +} + +th:hover > .column-resize-handle::after, +.column-resize-handle.is-resizing::after { + background: var(--blue); + opacity: 1; +} + +tbody tr[aria-selected='true'] { + background: rgb(76 145 228 / 13%); +} + +td[aria-selected='true'] { + position: relative; + background: rgb(70 139 222 / 12%); +} + +td[data-cell-focused='true'] { + background: rgb(70 139 222 / 21%); +} + +td[aria-selected='true']::after { + position: absolute; + z-index: 1; + inset: 0; + border: 1px solid transparent; + content: ''; + pointer-events: none; +} + +td[data-selection-top='true']::after { + border-top-color: var(--blue); +} + +td[data-selection-right='true']::after { + border-right-color: var(--blue); +} + +td[data-selection-bottom='true']::after { + border-bottom-color: var(--blue); +} + +td[data-selection-left='true']::after { + border-left-color: var(--blue); +} + +.price-button { + min-width: 4.5rem; + padding: 0; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-variant-numeric: tabular-nums; + font-weight: 600; + text-align: right; +} + +.price-button:hover { + background: transparent; + text-decoration: underline; + text-underline-offset: 2px; +} + +.move-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.move-cell.quote-up, +.percent-change-cell.quote-up { + background: color-mix(in srgb, var(--green) 7%, transparent); +} + +.move-cell.quote-down, +.percent-change-cell.quote-down { + background: color-mix(in srgb, var(--red) 7%, transparent); +} + +.percent-change-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.spread-cell { + display: flex; + align-items: baseline; + justify-content: flex-end; + gap: 0.35rem; + color: var(--text); +} + +.spread-cell small { + min-width: 2.8rem; + color: var(--muted); + font-size: 0.55rem; +} + +.spread-cell.spread-wide, +.spread-cell.spread-wide small { + color: var(--amber); +} + +.depth-cell { + position: relative; + display: flex; + height: 17px; + overflow: hidden; + background: var(--surface-control); +} + +.depth-bid, +.depth-ask { + height: 100%; + opacity: 0.78; +} + +.depth-bid { + background: var(--depth-bid); + border-right: 1px solid var(--panel); +} + +.depth-ask { + background: var(--depth-ask); +} + +.depth-values { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 0.28rem; + color: var(--text-strong); + font-size: 0.57rem; + text-shadow: 0 1px var(--background); +} + +.quote-age { + color: var(--muted); +} + +.quote-age-warm { + color: var(--amber); +} + +.quote-age-stale { + color: var(--red); +} + +.quote-up { + color: var(--green); +} + +.quote-down { + color: var(--red); +} + +.sparkline { + display: block; + width: 100%; + height: 1.35rem; + margin-left: auto; + color: var(--blue-soft); + overflow: visible; +} + +.sparkline.quote-up { + color: var(--green); +} + +.sparkline.quote-down { + color: var(--red); +} + +.sparkline polyline { + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-linejoin: miter; + stroke-width: 1.25; + vector-effect: non-scaling-stroke; +} + +.market-statusbar { + display: flex; + flex: 0 0 var(--statusbar-height); + min-height: var(--statusbar-height); + gap: 1.1rem; + align-items: center; + padding: 0 0.65rem; + color: var(--muted); + background: var(--surface-bar); + border-top: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.56rem; + grid-area: footer; + letter-spacing: 0.035em; +} + +.market-statusbar strong { + margin-left: 0.25rem; + color: var(--text); + font-weight: 500; +} + +.sidebar-slot { + width: var(--sidebar-width); + min-width: 0; + min-height: 0; + overflow: hidden; + background: var(--surface-table); + border-left: 1px solid var(--border); + grid-area: sidebar; + transition: + opacity 120ms ease, + transform 160ms ease, + visibility 160ms; +} + +.is-sidebar-collapsed .sidebar-slot { + visibility: hidden; + opacity: 0; + pointer-events: none; + transform: translateX(100%); +} + +.configurator { + width: 100%; + height: 100%; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +.configurator > header { + display: flex; + height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + color: var(--text-strong); + background: var(--surface-toolbar); + border-bottom: 1px solid var(--border); + font-size: 0.65rem; + font-weight: 700; + letter-spacing: 0.055em; +} + +.configurator > header small { + color: var(--muted); + font-size: 0.54rem; + font-weight: 500; +} + +.config-section { + display: grid; + gap: 0.7rem; + padding: 0.8rem var(--shell-inline-padding); + border-bottom: 1px solid var(--border); +} + +.config-section h2 { + margin: 0; + color: var(--muted); + font-size: 0.58rem; + letter-spacing: 0.075em; +} + +.primary-action { + width: 100%; + color: var(--text-inverse); + background: var(--blue); + border-color: var(--blue-soft); +} + +.primary-action:hover { + background: var(--blue-soft); + border-color: var(--text-strong); +} + +.field { + display: grid; + gap: 0.35rem; + color: var(--text); + font-size: 0.66rem; +} + +.rate-field > span { + display: flex; + justify-content: space-between; +} + +.rate-field strong { + color: var(--text); + font-family: var(--font-mono); + font-weight: 500; +} + +.field small { + color: var(--muted); + font-family: var(--font-mono); + font-size: 0.55rem; +} + +input[type='range'] { + width: 100%; + margin: 0; + accent-color: var(--blue); +} + +.toggle-field { + display: flex; + gap: 0.5rem; + align-items: flex-start; + color: var(--text); + font-size: 0.66rem; + line-height: 1.3; +} + +.toggle-field input { + margin: 0.12rem 0 0; + accent-color: var(--blue); +} + +.toggle-field small { + display: block; + margin-top: 0.14rem; + color: var(--muted); + font-size: 0.57rem; +} + +.action-grid { + display: grid; + grid-template-columns: 1fr; + gap: 0.4rem; +} + +.diagnostics dl, +.selected-instrument dl { + display: grid; + gap: 0; + margin: 0; +} + +.diagnostics dl > div, +.selected-instrument dl > div { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 24px; + border-bottom: 1px solid var(--border-soft); +} + +.diagnostics dl > div:last-child, +.selected-instrument dl > div:last-child { + border-bottom: 0; +} + +.diagnostics dl > div:has(dd[data-testid$='-breakdown']) { + display: grid; + grid-template-columns: minmax(0, 1fr); + align-content: center; + padding-block: 0.28rem; +} + +.diagnostics dd[data-testid$='-breakdown'] { + width: 100%; + overflow-x: auto; + padding-block: 0.12rem; + white-space: nowrap; + scrollbar-width: thin; +} + +.diagnostic-note { + margin: 0.5rem 0 0; + color: var(--muted); + font-size: 0.56rem; + line-height: 1.45; +} + +dt { + color: var(--muted); + font-size: 0.61rem; +} + +dd { + margin: 0; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.62rem; +} + +.selection { + display: flex; + align-items: flex-start; + justify-content: space-between; +} + +.selection div { + display: grid; + gap: 0.18rem; +} + +.selection strong { + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.85rem; +} + +.selection span, +.selection small, +.selected-instrument p { + color: var(--muted); + font-size: 0.61rem; +} + +.selected-instrument p { + margin: 0; + line-height: 1.45; +} + +@media (max-width: 980px) { + :root { + --sidebar-width: 15.625rem; + } +} + +@media (max-width: 720px) { + .trading-terminal { + --active-sidebar-width: 0px; + height: 100dvh; + min-height: 0; + overflow: hidden; + } + + .market-panel { + min-height: 0; + } + + .table-scroll { + min-height: 0; + } + + .sidebar-slot { + position: fixed; + z-index: 20; + top: 0; + right: 0; + bottom: 0; + width: min(var(--sidebar-width), calc(100vw - 2.75rem)); + box-shadow: -18px 0 42px rgb(0 0 0 / 48%); + } + + .is-sidebar-collapsed .sidebar-slot { + box-shadow: none; + } +} diff --git a/examples/ember/realtime-trading/app/app.ts b/examples/ember/realtime-trading/app/app.ts new file mode 100644 index 0000000000..253a0de562 --- /dev/null +++ b/examples/ember/realtime-trading/app/app.ts @@ -0,0 +1,22 @@ +/** + * Looking for services that come from addons? + * + * See: https://github.com/embroider-build/embroider/issues/2659 + * + * We currently don't support app-tree merging from libraries. + * + * For services, I highly recommend looking into either of + * - https://github.com/chancancode/ember-polaris-service- + * - https://ember-primitives.pages.dev/6-utils/createService.md + * - https://ember-primitives.pages.dev/6-utils/createAsyncService.md + */ +import Application from 'ember-strict-application-resolver' +import './app.css' + +export default class App extends Application { + modules = { + ...import.meta.glob('./router.*', { eager: true }), + ...import.meta.glob('./templates/**/*', { eager: true }), + ...import.meta.glob('./services/**/*', { eager: true }), + } +} diff --git a/examples/ember/realtime-trading/app/benchmark/benchmark-monitor.ts b/examples/ember/realtime-trading/app/benchmark/benchmark-monitor.ts new file mode 100644 index 0000000000..ee174bcd53 --- /dev/null +++ b/examples/ember/realtime-trading/app/benchmark/benchmark-monitor.ts @@ -0,0 +1,402 @@ +import { + quoteCellLifecycle, + quoteRenderDiagnostics, +} from '../table/table-config/quote-cells.gts' +import { rowModelDiagnostics } from '../table/trading-table' + +export interface NamedInvocationRate { + name: string + callsPerSecond: number +} + +export interface FeedMetrics { + actualTicksPerSecond: number + rowUpdatesPerSecond: number + workerMessagesPerSecond: number + stateApplicationsPerSecond: number + supersededUpdatesPerSecond: number + totalTicks: number + rafCallbacksPerSecond: number + tableRendersPerSecond: number + lastBatchSize: number + averageRenderMs: number + p95RenderMs: number + maxRenderMs: number + slowRenders: number + longAnimationFrames: number + worstLongAnimationFrameMs: number + heapMb: number | null + componentsCreated: number + componentsDestroyed: number + workerMessages: number + lastUpdateCount: number + cellRendererCallsPerSecond: number + componentRenderCallsPerSecond: number + cellRendererRates: ReadonlyArray + componentRenderRates: ReadonlyArray + domMutationsPerSecond: number + rowModelCallsPerSecond: number + rowModelAverageMs: number + rowModelMaxMs: number + visibleRows: number +} + +export const initialMetrics: FeedMetrics = { + actualTicksPerSecond: 0, + rowUpdatesPerSecond: 0, + workerMessagesPerSecond: 0, + stateApplicationsPerSecond: 0, + supersededUpdatesPerSecond: 0, + totalTicks: 0, + rafCallbacksPerSecond: 0, + tableRendersPerSecond: 0, + lastBatchSize: 0, + averageRenderMs: 0, + p95RenderMs: 0, + maxRenderMs: 0, + slowRenders: 0, + longAnimationFrames: 0, + worstLongAnimationFrameMs: 0, + heapMb: null, + componentsCreated: 0, + componentsDestroyed: 0, + workerMessages: 0, + lastUpdateCount: 0, + cellRendererCallsPerSecond: 0, + componentRenderCallsPerSecond: 0, + cellRendererRates: [], + componentRenderRates: [], + domMutationsPerSecond: 0, + rowModelCallsPerSecond: 0, + rowModelAverageMs: 0, + rowModelMaxMs: 0, + visibleRows: 0, +} + +const userTiming = { entryCount: 0, measureCallCount: 0 } +const USER_TIMING_SAMPLE_INTERVAL = 20 + +interface CommitLatencySample { + recordedAt: number + duration: number +} + +const AVERAGE_COMMIT_WINDOW_MS = 3_000 +const PERCENTILE_COMMIT_WINDOW_MS = 10_000 +const FRAME_RATE_WINDOW_MS = 1_000 + +export function recordMeasure( + name: string, + start: number, + end: number, + detail: Record, +): void { + userTiming.measureCallCount++ + if (userTiming.measureCallCount % USER_TIMING_SAMPLE_INTERVAL !== 0) return + try { + performance.measure(name, { start, end, detail }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMeasures('market-update-to-dom-commit') + } + } catch { + // User Timing Level 3 options are not implemented in every browser. + } +} + +export function markBenchmarkAction( + name: string, + detail: Record = {}, +): void { + try { + performance.mark(`benchmark:${name}`, { detail }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMarks() + } + } catch { + // User Timing Level 3 detail is not implemented in every browser. + } +} + +export class BenchmarkMonitor { + readonly #runtime = { + sampleStartedAt: performance.now(), + sessionStartedAt: performance.now(), + frameTrackingStartedAt: performance.now(), + pendingRenderStartedAt: null as number | null, + renderSamples: [] as Array, + frameTimestamps: [] as Array, + totalTicks: 0, + ticksInSample: 0, + rowUpdatesInSample: 0, + workerMessagesInSample: 0, + stateApplicationsInSample: 0, + supersededUpdatesInSample: 0, + lastBatchSize: 0, + lastUpdateCount: 0, + workerMessages: 0, + tableRendersInSample: 0, + slowRenderCount: 0, + longAnimationFrameCount: 0, + worstLongAnimationFrameMs: 0, + previousCellRendererCalls: 0, + previousComponentRenderCalls: 0, + previousCellRendererCallsByName: { + ...quoteRenderDiagnostics.cellRendererCallsByName, + }, + previousComponentRenderCallsByName: { + ...quoteRenderDiagnostics.componentRenderCallsByName, + }, + domMutationsInSample: 0, + previousRowModelCalls: 0, + previousRowModelDuration: 0, + } + + markRenderPending(): void { + this.#runtime.pendingRenderStartedAt ??= performance.now() + } + + recordCompletedRender(): void { + const runtime = this.#runtime + if (runtime.pendingRenderStartedAt !== null) { + const renderEndedAt = performance.now() + const duration = renderEndedAt - runtime.pendingRenderStartedAt + runtime.renderSamples.push({ recordedAt: renderEndedAt, duration }) + if (duration > 16.7) runtime.slowRenderCount++ + recordMeasure( + 'market-update-to-dom-commit', + runtime.pendingRenderStartedAt, + renderEndedAt, + {}, + ) + runtime.pendingRenderStartedAt = null + runtime.tableRendersInSample++ + } + } + + recordWorkerMessage(): void { + this.#runtime.workerMessages++ + this.#runtime.workerMessagesInSample++ + } + + recordBatch( + tickCount: number, + updateCount: number, + supersededUpdateCount: number, + ): void { + const runtime = this.#runtime + runtime.lastBatchSize = tickCount + runtime.lastUpdateCount = updateCount + runtime.ticksInSample += tickCount + runtime.totalTicks += tickCount + runtime.rowUpdatesInSample += updateCount + runtime.stateApplicationsInSample++ + runtime.supersededUpdatesInSample += supersededUpdateCount + } + + recordAnimationFrame(now: number): void { + this.#runtime.frameTimestamps.push(now) + } + + recordLongAnimationFrame(duration: number, startTime: number): void { + const runtime = this.#runtime + if (startTime < runtime.sessionStartedAt) return + runtime.longAnimationFrameCount++ + runtime.worstLongAnimationFrameMs = Math.max( + runtime.worstLongAnimationFrameMs, + duration, + ) + } + + recordDomMutations(count: number): void { + this.#runtime.domMutationsInSample += count + } + + resetDomMutations(): void { + this.#runtime.domMutationsInSample = 0 + } + + shouldPublish(now: number): boolean { + return now - this.#runtime.sampleStartedAt >= 500 + } + + publish(now: number): FeedMetrics { + const runtime = this.#runtime + const sampleDuration = now - runtime.sampleStartedAt + runtime.renderSamples = runtime.renderSamples.filter( + (sample) => sample.recordedAt >= now - PERCENTILE_COMMIT_WINDOW_MS, + ) + runtime.frameTimestamps = runtime.frameTimestamps.filter( + (timestamp) => timestamp >= now - FRAME_RATE_WINDOW_MS, + ) + const averageRenderSamples = runtime.renderSamples.filter( + (sample) => sample.recordedAt >= now - AVERAGE_COMMIT_WINDOW_MS, + ) + const sortedRenderSamples = runtime.renderSamples + .map((sample) => sample.duration) + .sort((left, right) => left - right) + const rowModelCalls = + rowModelDiagnostics.calls - runtime.previousRowModelCalls + const rowModelDuration = + rowModelDiagnostics.totalDurationMs - runtime.previousRowModelDuration + const cellRendererCalls = + quoteRenderDiagnostics.cellRendererCalls - + runtime.previousCellRendererCalls + const componentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls - + runtime.previousComponentRenderCalls + const cellRendererRates = calculateInvocationRates( + quoteRenderDiagnostics.cellRendererCallsByName, + runtime.previousCellRendererCallsByName, + sampleDuration, + ) + const componentRenderRates = calculateInvocationRates( + quoteRenderDiagnostics.componentRenderCallsByName, + runtime.previousComponentRenderCallsByName, + sampleDuration, + ) + const averageRenderMs = + averageRenderSamples.length === 0 + ? 0 + : averageRenderSamples.reduce( + (sum, sample) => sum + sample.duration, + 0, + ) / averageRenderSamples.length + const p95Index = Math.max( + 0, + Math.ceil(sortedRenderSamples.length * 0.95) - 1, + ) + const metrics: FeedMetrics = { + actualTicksPerSecond: + sampleDuration === 0 + ? 0 + : (runtime.ticksInSample / sampleDuration) * 1_000, + rowUpdatesPerSecond: + (runtime.rowUpdatesInSample / sampleDuration) * 1_000, + workerMessagesPerSecond: + (runtime.workerMessagesInSample / sampleDuration) * 1_000, + stateApplicationsPerSecond: + (runtime.stateApplicationsInSample / sampleDuration) * 1_000, + supersededUpdatesPerSecond: + (runtime.supersededUpdatesInSample / sampleDuration) * 1_000, + totalTicks: runtime.totalTicks, + rafCallbacksPerSecond: + (runtime.frameTimestamps.length / + Math.min( + FRAME_RATE_WINDOW_MS, + Math.max(1, now - runtime.frameTrackingStartedAt), + )) * + 1_000, + tableRendersPerSecond: + (runtime.tableRendersInSample / sampleDuration) * 1_000, + lastBatchSize: runtime.lastBatchSize, + averageRenderMs, + p95RenderMs: sortedRenderSamples[p95Index] ?? 0, + maxRenderMs: sortedRenderSamples.at(-1) ?? 0, + slowRenders: runtime.slowRenderCount, + longAnimationFrames: runtime.longAnimationFrameCount, + worstLongAnimationFrameMs: runtime.worstLongAnimationFrameMs, + heapMb: readHeapSizeMb(), + componentsCreated: quoteCellLifecycle.created, + componentsDestroyed: quoteCellLifecycle.destroyed, + workerMessages: runtime.workerMessages, + lastUpdateCount: runtime.lastUpdateCount, + cellRendererCallsPerSecond: (cellRendererCalls / sampleDuration) * 1_000, + componentRenderCallsPerSecond: + (componentRenderCalls / sampleDuration) * 1_000, + cellRendererRates, + componentRenderRates, + domMutationsPerSecond: + (runtime.domMutationsInSample / sampleDuration) * 1_000, + rowModelCallsPerSecond: (rowModelCalls / sampleDuration) * 1_000, + rowModelAverageMs: + rowModelCalls === 0 ? 0 : rowModelDuration / rowModelCalls, + rowModelMaxMs: rowModelDiagnostics.maxDurationMs, + visibleRows: rowModelDiagnostics.lastRowCount, + } + + runtime.sampleStartedAt = now + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.previousRowModelCalls = rowModelDiagnostics.calls + runtime.previousRowModelDuration = rowModelDiagnostics.totalDurationMs + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.tableRendersInSample = 0 + return metrics + } + + reset(): void { + const runtime = this.#runtime + runtime.sampleStartedAt = performance.now() + runtime.sessionStartedAt = runtime.sampleStartedAt + runtime.pendingRenderStartedAt = null + runtime.renderSamples = [] + runtime.frameTrackingStartedAt = runtime.sampleStartedAt + runtime.frameTimestamps = [] + runtime.totalTicks = 0 + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.lastBatchSize = 0 + runtime.lastUpdateCount = 0 + runtime.workerMessages = 0 + runtime.tableRendersInSample = 0 + runtime.slowRenderCount = 0 + runtime.longAnimationFrameCount = 0 + runtime.worstLongAnimationFrameMs = 0 + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.previousRowModelCalls = rowModelDiagnostics.calls + runtime.previousRowModelDuration = rowModelDiagnostics.totalDurationMs + rowModelDiagnostics.maxDurationMs = 0 + } +} + +export const longAnimationFramesSupported = + PerformanceObserver.supportedEntryTypes.includes('long-animation-frame') + +function readHeapSizeMb(): number | null { + const memory = ( + performance as Performance & { + memory?: { usedJSHeapSize: number } + } + ).memory + return memory ? memory.usedJSHeapSize / 1_048_576 : null +} + +function calculateInvocationRates( + current: Record, + previous: Record, + sampleDuration: number, +): ReadonlyArray { + return Object.entries(current).map(([name, calls]) => ({ + name, + callsPerSecond: + sampleDuration === 0 + ? 0 + : ((calls - (previous[name] ?? 0)) / sampleDuration) * 1_000, + })) +} diff --git a/examples/ember/realtime-trading/app/benchmark/trading-benchmark-controller.ts b/examples/ember/realtime-trading/app/benchmark/trading-benchmark-controller.ts new file mode 100644 index 0000000000..54728c0a08 --- /dev/null +++ b/examples/ember/realtime-trading/app/benchmark/trading-benchmark-controller.ts @@ -0,0 +1,118 @@ +import { cached, tracked } from '@glimmer/tracking' +import { TRADING_COLUMN_COUNT } from '../table/trading-table' +import { + BenchmarkMonitor, + initialMetrics, + longAnimationFramesSupported, +} from './benchmark-monitor' +import type { FeedMetrics } from './benchmark-monitor' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { RendererMode } from '../table/trading-table' + +export interface TradingBenchmarkActions { + resetViewState: () => void + setRendererMode: (mode: RendererMode) => void + setRenderedRowCount: (count: number) => void + selectSymbol: (symbol: string | null) => void + resetMarket: () => void +} + +export class TradingBenchmarkController { + @tracked metrics: FeedMetrics = initialMetrics + @tracked mountedCells = 0 + @tracked selectedSymbol: string | null = null + @tracked rendererMode: RendererMode = 'stable' + invalidateTable: (() => void) | null = null + @cached + get liveComponents(): number { + const metrics = this.metrics + return metrics.componentsCreated - metrics.componentsDestroyed + } + readonly longAnimationFramesSupported = longAnimationFramesSupported + readonly monitor = new BenchmarkMonitor() + readonly feed: MarketFeedController + readonly actions: TradingBenchmarkActions + + readonly #runtime = { + animationFrameId: 0, + longAnimationFrameObserver: null as PerformanceObserver | null, + stopObservingFeed: null as (() => void) | null, + } + + constructor(feed: MarketFeedController) { + this.feed = feed + this.actions = { + resetViewState: () => { + this.selectedSymbol = null + this.invalidateTable?.() + }, + setRendererMode: (mode) => { + this.rendererMode = mode + }, + setRenderedRowCount: (count) => { + const mountedCells = count * TRADING_COLUMN_COUNT + if (mountedCells !== this.mountedCells) { + this.mountedCells = mountedCells + } + }, + selectSymbol: (symbol) => { + this.selectedSymbol = symbol + }, + resetMarket: () => { + this.monitor.reset() + this.metrics = { ...initialMetrics } + this.mountedCells = 0 + this.selectedSymbol = null + this.feed.actions.reset() + }, + } + } + + start(): () => void { + const longAnimationFrameObserver = longAnimationFramesSupported + ? new PerformanceObserver((entries) => { + for (const entry of entries.getEntries()) { + this.monitor.recordLongAnimationFrame( + entry.duration, + entry.startTime, + ) + } + }) + : null + + this.#runtime.longAnimationFrameObserver = longAnimationFrameObserver + this.#runtime.stopObservingFeed = this.feed.observe({ + messageReceived: () => this.monitor.recordWorkerMessage(), + mutationStarted: () => this.monitor.markRenderPending(), + batchApplied: ({ tickCount, updateCount, supersededUpdateCount }) => + this.monitor.recordBatch(tickCount, updateCount, supersededUpdateCount), + renderCommitted: () => this.monitor.recordCompletedRender(), + }) + longAnimationFrameObserver?.observe({ + type: 'long-animation-frame', + }) + this.#runtime.animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + + return () => this.stop() + } + + stop(): void { + cancelAnimationFrame(this.#runtime.animationFrameId) + this.#runtime.longAnimationFrameObserver?.disconnect() + this.#runtime.stopObservingFeed?.() + this.#runtime.longAnimationFrameObserver = null + this.#runtime.stopObservingFeed = null + } + + readonly #benchmarkFrame = (now: number): void => { + this.monitor.recordAnimationFrame(now) + if (this.monitor.shouldPublish(now)) { + this.#publishMetrics(this.monitor.publish(now)) + } + this.#runtime.animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + } + + #publishMetrics(metrics: FeedMetrics): void { + this.metrics = metrics + } +} diff --git a/examples/ember/realtime-trading/app/components/shell/app-header.gts b/examples/ember/realtime-trading/app/components/shell/app-header.gts new file mode 100644 index 0000000000..017ccddfe6 --- /dev/null +++ b/examples/ember/realtime-trading/app/components/shell/app-header.gts @@ -0,0 +1,63 @@ +import Component from '@glimmer/component' +import { on } from '@ember/modifier' +import type { MarketFeedController } from '../../feed/market-feed-controller' + +interface Signature { + Args: { + feed: MarketFeedController + sidebarOpen: boolean + toggleSidebar: () => void + } +} + +export default class AppHeader extends Component { + get workerReady() { + return this.args.feed.workerReady + } + get running() { + return this.args.feed.running + } + get status() { + return !this.workerReady + ? 'FEED CONNECTING' + : this.running + ? 'FEED LIVE' + : 'FEED PAUSED' + } + +} + +const and = (left: boolean, right: boolean): boolean => left && right diff --git a/examples/ember/realtime-trading/app/components/shell/configurator-options.ts b/examples/ember/realtime-trading/app/components/shell/configurator-options.ts new file mode 100644 index 0000000000..5e21d71492 --- /dev/null +++ b/examples/ember/realtime-trading/app/components/shell/configurator-options.ts @@ -0,0 +1,49 @@ +export interface ConfiguratorOption { + readonly label: string + readonly value: TValue +} + +const instrumentCountOptions = [ + { label: '50', value: 50 }, + { label: '100', value: 100 }, + { label: '150', value: 150 }, + { label: '250', value: 250 }, + { label: '350', value: 350 }, + { label: '500', value: 500 }, + { label: '750', value: 750 }, + { label: '1,000', value: 1_000 }, + { label: '1,500', value: 1_500 }, + { label: '2,500', value: 2_500 }, + { label: '5,000', value: 5_000 }, + { label: '1,000,000', value: 1_000_000 }, + { label: '10,000,000', value: 10_000_000 }, +] as const satisfies ReadonlyArray> + +const workerDeliveryOptions = [ + { label: '8 ms · 125 msg/s', value: 8 }, + { label: '16 ms · 62.5 msg/s', value: 16 }, + { label: '20 ms · 50 msg/s', value: 20 }, + { label: '33 ms · 30 msg/s', value: 33 }, + { label: '50 ms · 20 msg/s', value: 50 }, + { label: '100 ms · 10 msg/s', value: 100 }, + { label: '250 ms · 4 msg/s', value: 250 }, + { label: '500 ms · 2 msg/s', value: 500 }, + { label: '1,000 ms · 1 msg/s', value: 1_000 }, +] as const satisfies ReadonlyArray> + +const intradaySamplingOptions = [ + { label: '16 ms · fastest', value: 16 }, + { label: '33 ms · very fast', value: 33 }, + { label: '50 ms · fast', value: 50 }, + { label: '100 ms', value: 100 }, + { label: '250 ms', value: 250 }, + { label: '500 ms', value: 500 }, + { label: '1,000 ms', value: 1_000 }, + { label: '2,000 ms', value: 2_000 }, +] as const satisfies ReadonlyArray> + +export const configuratorOptions = { + instrumentCounts: instrumentCountOptions, + workerDeliveryIntervals: workerDeliveryOptions, + intradaySamplingIntervals: intradaySamplingOptions, +} as const diff --git a/examples/ember/realtime-trading/app/components/shell/configurator.gts b/examples/ember/realtime-trading/app/components/shell/configurator.gts new file mode 100644 index 0000000000..cd06e8fb5e --- /dev/null +++ b/examples/ember/realtime-trading/app/components/shell/configurator.gts @@ -0,0 +1,211 @@ +import Component from '@glimmer/component' +import { on } from '@ember/modifier' +import { modifier } from 'ember-modifier' +import { + feedSampleRateAt, + feedSampleRateIndex, + feedSampleRateOptions, +} from '../../feed/feed-sample-rates' +import { initialMarketFeedConfig } from '../../feed/market-feed-config' +import { configuratorOptions } from './configurator-options' +import Diagnostics from './diagnostics.gts' +import MetricsStrip from './metrics-strip.gts' +import SelectedInstrument from './selected-instrument.gts' +import type { MarketFeedController } from '../../feed/market-feed-controller' +import type { TradingBenchmarkController } from '../../benchmark/trading-benchmark-controller' + +interface Signature { + Args: { controller: TradingBenchmarkController; feed: MarketFeedController } +} +const rate = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +const captureSelect = modifier( + ( + element: HTMLSelectElement, + [capture]: [(el: HTMLSelectElement | null) => void], + ) => { + capture(element) + return () => capture(null) + }, +) + +export default class Configurator extends Component { + readonly feedSampleRateOptions = feedSampleRateOptions + readonly options = configuratorOptions + uiInstrumentCount = initialMarketFeedConfig.instrumentCount + instrumentSelect: HTMLSelectElement | null = null + captureInstrumentSelect = (element: HTMLSelectElement | null) => { + this.instrumentSelect = element + if (element) { + element.value = String(this.uiInstrumentCount) + } + } + get running() { + return this.args.feed.running + } + get targetTicksPerSecond() { + return this.args.feed.targetTicksPerSecond + } + get publishIntervalMs() { + return this.args.feed.publishIntervalMs + } + get updateSparklines() { + return this.args.feed.updateSparklines + } + get sparklineSampleIntervalMs() { + return this.args.feed.sparklineSampleIntervalMs + } + get rendererMode() { + return this.args.controller.rendererMode + } + get sampleRateIndex() { + return feedSampleRateIndex(this.targetTicksPerSecond) + } + get sampleRateLabel() { + return `${rate.format(this.targetTicksPerSecond)} samples/s` + } + + setInstrumentCount = (value: string) => { + const count = Number(value) + this.args.feed.actions.setInstrumentCount(count) + this.args.controller.actions.resetViewState() + this.uiInstrumentCount = count + } + setInstrumentCountFromEvent = (event: Event) => { + this.setInstrumentCount(selectValue(event)) + } + setSampleRate = (event: Event) => { + this.args.feed.actions.setTargetRate(feedSampleRateAt(numberValue(event))) + } + setPublishInterval = (event: Event) => { + this.args.feed.actions.setPublishInterval(numberValue(event)) + } + setRendererMode = (event: Event) => { + this.args.controller.actions.setRendererMode( + checked(event) ? 'swap' : 'stable', + ) + } + setSparklineUpdates = (event: Event) => { + this.args.feed.actions.setSparklineUpdates(checked(event)) + } + setSparklineInterval = (event: Event) => { + this.args.feed.actions.setSparklineSampleInterval(numberValue(event)) + } + + +} + +const selectValue = (event: Event): string => + (event.target as HTMLInputElement | HTMLSelectElement).value +const numberValue = (event: Event): number => Number(selectValue(event)) +const checked = (event: Event): boolean => + (event.target as HTMLInputElement).checked +const subtract = (left: number, right: number): number => left - right +const eq = (left: unknown, right: unknown): boolean => left === right +const optionValue = (option: { + readonly value: number | string +}): number | string => option.value +const optionLabel = (option: { readonly label: string }): string => option.label diff --git a/examples/ember/realtime-trading/app/components/shell/diagnostics.gts b/examples/ember/realtime-trading/app/components/shell/diagnostics.gts new file mode 100644 index 0000000000..8c6f3e2600 --- /dev/null +++ b/examples/ember/realtime-trading/app/components/shell/diagnostics.gts @@ -0,0 +1,154 @@ +import Component from '@glimmer/component' +import type { NamedInvocationRate } from '../../benchmark/benchmark-monitor' +import type { TradingBenchmarkController } from '../../benchmark/trading-benchmark-controller' + +interface Signature { + Args: { controller: TradingBenchmarkController } +} +const integer = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }) +const rate = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +const ms = (value: number): string => `${value.toFixed(2)} ms` +const invocations = (values: ReadonlyArray): string => { + const active = values.filter((entry) => entry.callsPerSecond > 0) + return active.length + ? active + .map((entry) => `${entry.name} ${rate.format(entry.callsPerSecond)}`) + .join(' · ') + : '—' +} + +export default class Diagnostics extends Component { + get items() { + const metrics = this.args.controller.metrics + return [ + { + label: 'Mounted cells', + value: integer.format(this.args.controller.mountedCells), + testId: '', + }, + { + label: 'Live components', + value: integer.format(this.args.controller.liveComponents), + testId: '', + }, + { + label: 'Created / destroyed', + value: `${integer.format(metrics.componentsCreated)} / ${integer.format(metrics.componentsDestroyed)}`, + testId: '', + }, + { + label: 'Renderer callbacks / s', + value: rate.format(metrics.cellRendererCallsPerSecond), + testId: 'cell-render-rate', + }, + { + label: 'Component executions / s', + value: rate.format(metrics.componentRenderCallsPerSecond), + testId: 'component-render-rate', + }, + { + label: 'Executions by component / s', + value: invocations(metrics.componentRenderRates), + testId: 'component-render-breakdown', + }, + { + label: 'Callbacks by column / s', + value: invocations(metrics.cellRendererRates), + testId: 'cell-render-breakdown', + }, + { + label: 'Observed MutationRecords / s', + value: rate.format(metrics.domMutationsPerSecond), + testId: 'dom-mutation-rate', + }, + { + label: 'Worker samples / s', + value: rate.format(metrics.actualTicksPerSecond), + testId: 'actual-rate', + }, + { + label: 'Worker messages / s', + value: metrics.workerMessagesPerSecond.toFixed(1), + testId: 'message-rate', + }, + { + label: 'Changed rows / s', + value: rate.format(metrics.rowUpdatesPerSecond), + testId: 'row-update-rate', + }, + { + label: 'State snapshots / s', + value: metrics.stateApplicationsPerSecond.toFixed(1), + testId: 'state-apply-rate', + }, + { + label: 'Table DOM commits / s', + value: metrics.tableRendersPerSecond.toFixed(1), + testId: 'table-render-rate', + }, + { + label: 'P95 / max commit latency (rolling 10 s)', + value: `${ms(metrics.p95RenderMs)} / ${ms(metrics.maxRenderMs)}`, + testId: '', + }, + { + label: 'Core row model calls / s', + value: metrics.rowModelCallsPerSecond.toFixed(1), + testId: 'row-model-call-rate', + }, + { + label: 'Core row model avg / max', + value: `${ms(metrics.rowModelAverageMs)} / ${ms(metrics.rowModelMaxMs)}`, + testId: 'row-model-duration', + }, + { + label: 'Visible rows', + value: integer.format(metrics.visibleRows), + testId: 'visible-row-count', + }, + { + label: 'Worker messages since reset', + value: integer.format(metrics.workerMessages), + testId: 'worker-messages', + }, + { + label: 'Worker-coalesced updates / s', + value: rate.format(metrics.supersededUpdatesPerSecond), + testId: 'superseded-update-rate', + }, + { + label: 'Last samples / updated rows', + value: `${integer.format(metrics.lastBatchSize)} / ${integer.format(metrics.lastUpdateCount)}`, + testId: '', + }, + { + label: 'Commits > 16.7 ms since reset', + value: integer.format(metrics.slowRenders), + testId: '', + }, + { + label: 'JS heap (GC-sensitive)', + value: + metrics.heapMb === null ? 'N/A' : `${metrics.heapMb.toFixed(1)} MB`, + testId: '', + }, + ] + } + +} +const or = (left: T, right: T): T => left || right diff --git a/examples/ember/realtime-trading/app/components/shell/market-statusbar.gts b/examples/ember/realtime-trading/app/components/shell/market-statusbar.gts new file mode 100644 index 0000000000..ba6a5d31f0 --- /dev/null +++ b/examples/ember/realtime-trading/app/components/shell/market-statusbar.gts @@ -0,0 +1,31 @@ +import Component from '@glimmer/component' +import type { TradingBenchmarkController } from '../../benchmark/trading-benchmark-controller' + +interface Signature { + Args: { controller: TradingBenchmarkController } +} +const integer = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }) + +export default class MarketStatusbar extends Component { + get metrics() { + return this.args.controller.metrics + } + get mountedCells() { + return this.args.controller.mountedCells + } + get liveComponents() { + return this.args.controller.liveComponents + } + +} +const format = (value: number): string => integer.format(value) diff --git a/examples/ember/realtime-trading/app/components/shell/metrics-strip.gts b/examples/ember/realtime-trading/app/components/shell/metrics-strip.gts new file mode 100644 index 0000000000..70b7d6f7bd --- /dev/null +++ b/examples/ember/realtime-trading/app/components/shell/metrics-strip.gts @@ -0,0 +1,59 @@ +import Component from '@glimmer/component' +import type { TradingBenchmarkController } from '../../benchmark/trading-benchmark-controller' + +interface Signature { + Args: { controller: TradingBenchmarkController } +} +const rate = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +const ms = (value: number): string => `${value.toFixed(2)} ms` + +export default class MetricsStrip extends Component { + get items() { + const metrics = this.args.controller.metrics + return [ + [ + 'FRAME RATE (EST.)', + metrics.rafCallbacksPerSecond.toFixed(1), + 'rAF callbacks/s · rolling 1 s', + 'frame-rate', + ], + [ + 'AVG COMMIT', + ms(metrics.averageRenderMs), + 'snapshot → DOM · rolling 3 s', + 'average-commit-latency', + ], + [ + 'LONG FRAMES', + this.args.controller.longAnimationFramesSupported + ? String(metrics.longAnimationFrames) + : 'N/A', + this.args.controller.longAnimationFramesSupported + ? `since reset · worst ${ms(metrics.worstLongAnimationFrameMs)}` + : 'unsupported', + 'long-frame-count', + ], + [ + 'THROUGHPUT', + `${rate.format(metrics.rowUpdatesPerSecond)} rows/s`, + `${metrics.stateApplicationsPerSecond.toFixed(1)} snapshots/s · rows deduplicated per snapshot`, + 'throughput-rate', + ], + ] as const + } + +} + +const or = (left: T, right: T): T => left || right diff --git a/examples/ember/realtime-trading/app/components/shell/selected-instrument.gts b/examples/ember/realtime-trading/app/components/shell/selected-instrument.gts new file mode 100644 index 0000000000..55d6ce99ae --- /dev/null +++ b/examples/ember/realtime-trading/app/components/shell/selected-instrument.gts @@ -0,0 +1,37 @@ +import Component from '@glimmer/component' +import type { MarketQuote } from '../../feed/market-data' +import type { MarketFeedController } from '../../feed/market-feed-controller' +import type { TradingBenchmarkController } from '../../benchmark/trading-benchmark-controller' + +interface Signature { + Args: { controller: TradingBenchmarkController; feed: MarketFeedController } +} + +export default class SelectedInstrument extends Component { + get quote(): MarketQuote | null { + return this.args.feed.getQuoteBySymbol( + this.args.feed.quotes, + this.args.controller.selectedSymbol, + ) + } + +} +const fixed = (value: number): string => value.toFixed(2) diff --git a/examples/ember/realtime-trading/app/components/shell/trading-shell.gts b/examples/ember/realtime-trading/app/components/shell/trading-shell.gts new file mode 100644 index 0000000000..26ed6fc155 --- /dev/null +++ b/examples/ember/realtime-trading/app/components/shell/trading-shell.gts @@ -0,0 +1,48 @@ +import Component from '@glimmer/component' +import { tracked } from '@glimmer/tracking' +import AppHeader from './app-header.gts' +import Configurator from './configurator.gts' +import MarketStatusbar from './market-statusbar.gts' +import TradingTable from '../table/trading-table.gts' +import type { MarketFeedController } from '../../feed/market-feed-controller' +import type { TradingBenchmarkController } from '../../benchmark/trading-benchmark-controller' + +interface Signature { + Args: { + controller: TradingBenchmarkController + feed: MarketFeedController + } +} + +export default class TradingShell extends Component { + @tracked sidebarOpen = true + toggleSidebar = () => { + this.sidebarOpen = !this.sidebarOpen + } + get rootClass() { + return `trading-terminal${this.sidebarOpen ? '' : ' is-sidebar-collapsed'}` + } + +} + +const isDevelopment = import.meta.env.DEV diff --git a/examples/ember/realtime-trading/app/components/table/trading-table.gts b/examples/ember/realtime-trading/app/components/table/trading-table.gts new file mode 100644 index 0000000000..aa58df5da8 --- /dev/null +++ b/examples/ember/realtime-trading/app/components/table/trading-table.gts @@ -0,0 +1,436 @@ +import Component from '@glimmer/component' +import { cached, tracked } from '@glimmer/tracking' +import { on } from '@ember/modifier' +import { htmlSafe } from '@ember/template' +import { modifier } from 'ember-modifier' +import { + FlexRenderCell, + FlexRenderHeader, + useTable, + type Header, + type Row, + type Table, +} from '@tanstack/ember-table' +import { + createTradingColumns, + readMeasuredRows, +} from '../../table/table-config/trading-columns.gts' +import { tradingFeatures } from '../../table/trading-features' +import { + TradingGridPointerController, + handleCellNavigation, + reorderColumnIds, + sortAriaValue, + sortIndicator, +} from '../../table/table-interactions' +import { registerCleanup } from '../../utils/subscriptions' +import { run } from '@ember/runloop' +import type Owner from '@ember/owner' +import type { MarketQuote } from '../../feed/market-data' +import type { MarketFeedController } from '../../feed/market-feed-controller' +import type { TradingBenchmarkController } from '../../benchmark/trading-benchmark-controller' + +interface Signature { + Args: { + controller: TradingBenchmarkController + feed: MarketFeedController + } +} +interface TableView { + quotes: Array +} +type TradingRow = Row +type TradingHeader = Header +interface RenderedRow { + id: string + row: TradingRow + cells: ReturnType +} + +const captureElement = modifier( + ( + element: HTMLElement, + [capture]: [(element: HTMLElement | null) => void], + ) => { + capture(element) + return () => capture(null) + }, +) + +const markRenderCommitted = modifier( + ( + _element: HTMLElement, + [feed, quotes]: [MarketFeedController, Array], + ) => { + void quotes + queueMicrotask(() => feed.completeRender()) + }, +) + +export default class TradingTable extends Component { + @tracked viewGeneration = 0 + tableView: TableView = { + quotes: [], + } + readonly pointer = new TradingGridPointerController() + readonly layout = { manuallyResized: false } + readonly drag = { + columnId: null as string | null, + source: null as HTMLTableCellElement | null, + target: null as HTMLTableCellElement | null, + } + scrollElement: HTMLDivElement | null = null + bodyElement: HTMLTableSectionElement | null = null + resizeObserver: ResizeObserver | null = null + mutationObserver: MutationObserver | null = null + + table: Table = useTable(this, () => ({ + features: tradingFeatures, + columns: this.columns, + data: this.data, + getRowId: (row: MarketQuote) => row.id, + columnResizeMode: 'onChange' as const, + defaultColumn: { minSize: 56, maxSize: 800 }, + autoResetCellSelection: false, + })) + + constructor(owner: Owner, args: Signature['Args']) { + super(owner, args) + this.args.controller.invalidateTable = this.queueSync + const stopObserving = this.args.feed.observe({ + viewChanged: this.queueSync, + }) + this.queueSync() + registerCleanup(this, () => { + this.args.controller.invalidateTable = null + stopObserving() + this.resizeObserver?.disconnect() + this.mutationObserver?.disconnect() + }) + } + + queueSync = () => { + queueMicrotask(() => { + run(() => this.syncView()) + }) + } + + syncView = () => { + this.tableView = { + quotes: this.args.feed.quotes, + } + this.viewGeneration++ + } + + @cached + get columns(): ReturnType { + return createTradingColumns( + this.args.controller, + this.args.controller.rendererMode, + ) + } + get data(): Array { + void this.viewGeneration + return this.tableView.quotes + } + get selectedSymbol() { + return this.args.controller.selectedSymbol + } + + get rows(): Array { + // The table-core memo compares `table.options.data` internally. Consume the + // Ember source explicitly as well so this template getter owns the Glimmer + // tag that schedules the row-block update for an external worker message. + void this.data + return readMeasuredRows(() => this.table.getRowModel().rows) + } + get headerGroups() { + return this.table.getHeaderGroups() + } + get sourceRowCount() { + void this.viewGeneration + return this.tableView.quotes.length + } + get renderedRows(): Array { + void this.viewGeneration + const result = this.rows.map((row) => ({ + id: row.id, + row, + cells: row.getVisibleCells(), + })) + queueMicrotask(() => + this.args.controller.actions.setRenderedRowCount(result.length), + ) + return result + } + + captureScroll = (element: HTMLElement | null) => { + this.scrollElement = element as HTMLDivElement | null + if (!this.scrollElement) return + this.resizeObserver?.disconnect() + this.resizeObserver = new ResizeObserver(() => this.fitAvailableWidth()) + this.resizeObserver.observe(this.scrollElement) + queueMicrotask(() => { + run(() => this.fitAvailableWidth()) + }) + } + captureBody = (element: HTMLElement | null) => { + this.mutationObserver?.disconnect() + this.bodyElement = element as HTMLTableSectionElement | null + if (!this.bodyElement) return + this.args.controller.monitor.resetDomMutations() + this.mutationObserver = new MutationObserver((records) => + this.args.controller.monitor.recordDomMutations(records.length), + ) + this.mutationObserver.observe(this.bodyElement, { + attributes: true, + attributeFilter: ['class', 'style'], + characterData: true, + childList: true, + subtree: true, + }) + } + + @cached + get columnSizeVars(): string { + void this.table.store.state.columnSizing + void this.table.store.state.columnOrder + return this.table + .getFlatHeaders() + .flatMap((header) => [ + `--header-${header.id}-size:${header.getSize()}`, + `--col-${header.column.id}-size:${header.column.getSize()}`, + ]) + .join(';') + } + get tableStyle() { + return htmlSafe( + `${this.columnSizeVars};width:${this.table.getTotalSize()}px`, + ) + } + fitAvailableWidth() { + if (!this.scrollElement || this.layout.manuallyResized) return + const width = this.table.getTotalSize() + if (this.scrollElement.clientWidth <= width + 1 || width <= 0) return + const ratio = this.scrollElement.clientWidth / width + this.table.setColumnSizing( + Object.fromEntries( + this.table + .getVisibleLeafColumns() + .map((column) => [column.id, column.getSize() * ratio]), + ), + ) + } + + resizeColumn = (header: TradingHeader) => (event: Event) => { + this.layout.manuallyResized = true + header.getResizeHandler()?.(event) + } + resetColumnSize = (header: TradingHeader) => () => { + this.layout.manuallyResized = true + header.column.resetSize() + } + + onGridKeyDown = (event: KeyboardEvent) => + handleCellNavigation(this.table, event) + onBodyMouseDown = (event: MouseEvent) => + this.pointer.handleMouseDown( + this.table, + event, + this.args.controller.actions.selectSymbol, + ) + onBodyPointerOver = (event: MouseEvent) => + this.pointer.handlePointerOver(this.table, event) + onBodyClick = (event: MouseEvent) => + this.pointer.handleClick(this.table, event) + resetPointer = () => this.pointer.resetPointerCell() + clearDrag = () => { + this.drag.source?.classList.remove('is-column-dragging') + this.drag.target?.classList.remove('is-column-drop-target') + this.drag.columnId = null + this.drag.source = null + this.drag.target = null + } + dragStart = (header: TradingHeader) => (event: DragEvent) => { + this.drag.columnId = header.column.id + this.drag.source = (event.currentTarget as HTMLElement).closest('th') + this.drag.source?.classList.add('is-column-dragging') + if (event.dataTransfer) { + event.dataTransfer.effectAllowed = 'move' + event.dataTransfer.setData('text/plain', header.column.id) + } + } + dragOver = (header: TradingHeader) => (event: DragEvent) => { + event.preventDefault() + this.drag.target?.classList.remove('is-column-drop-target') + this.drag.target = null + const element = (event.currentTarget as HTMLElement).closest('th') + if (this.drag.columnId !== header.column.id && element) { + element.classList.add('is-column-drop-target') + this.drag.target = element + } + } + drop = (header: TradingHeader) => (event: DragEvent) => { + event.preventDefault() + const source = + event.dataTransfer?.getData('text/plain') || this.drag.columnId + if (source) + this.table.setColumnOrder( + reorderColumnIds( + this.table.getVisibleLeafColumns().map((column) => column.id), + source, + header.column.id, + ), + ) + this.clearDrag() + } + + +} + +const isLeaf = (header: TradingHeader): boolean => + header.subHeaders.length === 0 +const canSort = (header: TradingHeader): boolean => header.column.getCanSort() +const isSorted = (header: TradingHeader): boolean => + header.column.getIsSorted() !== false +const canResize = (header: TradingHeader): boolean => + header.column.getCanResize() +const isResizing = (header: TradingHeader): boolean => + header.column.getIsResizing() +const toggleSort = (header: TradingHeader) => + header.column.getToggleSortingHandler() ?? (() => undefined) +const indicator = (header: TradingHeader): string => + sortIndicator(header.column.getIsSorted()) +const sortAria = (header: TradingHeader) => + isLeaf(header) ? sortAriaValue(header.column.getIsSorted()) : undefined +const headerStyle = (header: TradingHeader) => + htmlSafe(`width:calc(var(--header-${header.id}-size) * 1px)`) +const headerClass = (header: TradingHeader): string => + `${isLeaf(header) ? '' : 'column-group-header'} ${isLeaf(header) && !['market', 'name', 'symbol'].includes(header.column.id) ? 'numeric-header' : ''}` +const cellStyle = (columnId: string) => + htmlSafe(`width:calc(var(--col-${columnId}-size) * 1px)`) +const edgeAttr = ( + cell: { + getSelectionEdges: () => { + top: boolean + right: boolean + bottom: boolean + left: boolean + } + }, + edge: 'top' | 'right' | 'bottom' | 'left', +): string | undefined => (cell.getSelectionEdges()[edge] ? 'true' : undefined) +const rowSelected = (row: TradingRow): boolean => row.getIsSelected() +const cellSelected = ( + cell: ReturnType[number], +): boolean => cell.getIsSelected() +const cellFocused = ( + cell: ReturnType[number], +): string | undefined => (cell.getIsFocused() ? 'true' : undefined) +const cellTabIndex = ( + cell: ReturnType[number], +): number => cell.getTabIndex() +const eq = (left: unknown, right: unknown): boolean => left === right +const not = (value: boolean): boolean => !value diff --git a/examples/ember/realtime-trading/app/config.ts b/examples/ember/realtime-trading/app/config.ts new file mode 100644 index 0000000000..8b0d33268d --- /dev/null +++ b/examples/ember/realtime-trading/app/config.ts @@ -0,0 +1,17 @@ +interface Config { + environment: 'development' | 'production' + locationType: 'history' | 'hash' | 'none' | 'auto' + rootURL: string + EmberENV?: Record + APP: Record & { rootElement?: string; autoboot?: boolean } +} + +const ENV: Config = { + environment: import.meta.env.DEV ? 'development' : 'production', + rootURL: '/', + locationType: 'history', + EmberENV: {}, + APP: {}, +} + +export default ENV diff --git a/examples/ember/realtime-trading/app/feed/feed-sample-rates.ts b/examples/ember/realtime-trading/app/feed/feed-sample-rates.ts new file mode 100644 index 0000000000..dfacf21d02 --- /dev/null +++ b/examples/ember/realtime-trading/app/feed/feed-sample-rates.ts @@ -0,0 +1,33 @@ +export const feedSampleRateOptions = [ + { label: '100', value: 100 }, + { label: '250', value: 250 }, + { label: '500', value: 500 }, + { label: '1K', value: 1_000 }, + { label: '2.5K', value: 2_500 }, + { label: '5K', value: 5_000 }, + { label: '10K', value: 10_000 }, + { label: '25K', value: 25_000 }, + { label: '50K', value: 50_000 }, + { label: '100K', value: 100_000 }, +] as const + +export function feedSampleRateIndex(rate: number): number { + return feedSampleRateOptions.reduce((closestIndex, candidate, index) => { + const closest = feedSampleRateOptions[closestIndex]! + return Math.abs(candidate.value - rate) < Math.abs(closest.value - rate) + ? index + : closestIndex + }, 0) +} + +export function feedSampleRateAt(stepIndex: number): number { + const index = Math.min( + feedSampleRateOptions.length - 1, + Math.max(0, Math.round(stepIndex)), + ) + return feedSampleRateOptions[index]!.value +} + +export function normalizeFeedSampleRate(rate: number): number { + return feedSampleRateAt(feedSampleRateIndex(rate)) +} diff --git a/examples/ember/realtime-trading/app/feed/market-data.ts b/examples/ember/realtime-trading/app/feed/market-data.ts new file mode 100644 index 0000000000..6231865d3f --- /dev/null +++ b/examples/ember/realtime-trading/app/feed/market-data.ts @@ -0,0 +1,38 @@ +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './worker/market-feed-protocol' + +export interface MarketQuote extends Omit { + history: ReadonlyArray +} + +export function hydrateMarketQuotes( + snapshots: Array, +): Array { + return snapshots.map((quote) => ({ + ...quote, + history: [...quote.history], + })) +} + +export function applyMarketUpdates( + quotes: Array, + updates: Array, +): Array { + const nextQuotes = [...quotes] + + for (const update of updates) { + const { index, history, ...values } = update + const previousQuote = quotes.at(index) + if (!previousQuote) continue + + nextQuotes[index] = { + ...previousQuote, + ...values, + history: history ?? previousQuote.history, + } + } + + return nextQuotes +} diff --git a/examples/ember/realtime-trading/app/feed/market-feed-config.ts b/examples/ember/realtime-trading/app/feed/market-feed-config.ts new file mode 100644 index 0000000000..9d477ed663 --- /dev/null +++ b/examples/ember/realtime-trading/app/feed/market-feed-config.ts @@ -0,0 +1,15 @@ +export interface MarketFeedConfig { + readonly instrumentCount: number + readonly targetSamplesPerSecond: number + readonly publishIntervalMs: number + readonly updateSparklines: boolean + readonly sparklineSampleIntervalMs: number +} + +export const initialMarketFeedConfig: MarketFeedConfig = { + instrumentCount: 100, + targetSamplesPerSecond: 10_000, + publishIntervalMs: 20, + updateSparklines: true, + sparklineSampleIntervalMs: 16, +} diff --git a/examples/ember/realtime-trading/app/feed/market-feed-controller.ts b/examples/ember/realtime-trading/app/feed/market-feed-controller.ts new file mode 100644 index 0000000000..6bc135d2c3 --- /dev/null +++ b/examples/ember/realtime-trading/app/feed/market-feed-controller.ts @@ -0,0 +1,226 @@ +import { tracked } from '@glimmer/tracking' +import { normalizeFeedSampleRate } from './feed-sample-rates' +import { initialMarketFeedConfig } from './market-feed-config' +import { applyMarketUpdates, hydrateMarketQuotes } from './market-data' +import type { + MarketFeedCommand, + MarketFeedEvent, +} from './worker/market-feed-protocol' +import type { MarketQuote } from './market-data' + +export interface MarketFeedBatch { + tickCount: number + updateCount: number + supersededUpdateCount: number +} + +export interface MarketFeedObserver { + messageReceived?: () => void + mutationStarted?: () => void + batchApplied?: (batch: MarketFeedBatch) => void + renderCommitted?: () => void + viewChanged?: () => void +} + +export interface MarketFeedActions { + toggle: () => void + setInstrumentCount: (count: number) => void + setTargetRate: (rate: number) => void + setPublishInterval: (intervalMs: number) => void + setSparklineUpdates: (enabled: boolean) => void + setSparklineSampleInterval: (intervalMs: number) => void + runBurst: () => void + reset: () => void +} + +export class MarketFeedController { + @tracked workerReady = false + @tracked running = !new URLSearchParams(location.search).has('paused') + instrumentCount = initialMarketFeedConfig.instrumentCount + @tracked targetTicksPerSecond = initialMarketFeedConfig.targetSamplesPerSecond + @tracked publishIntervalMs = initialMarketFeedConfig.publishIntervalMs + @tracked updateSparklines = initialMarketFeedConfig.updateSparklines + @tracked sparklineSampleIntervalMs = + initialMarketFeedConfig.sparklineSampleIntervalMs + quotes: Array = [] + readonly actions: MarketFeedActions + readonly #observers = new Set() + readonly #runtime = { + worker: null as Worker | null, + feedSessionId: 0, + renderPending: false, + resetWaitingForCommit: false, + resetSnapshotReady: false, + quoteIndexBySymbol: new Map(), + } + + constructor() { + this.actions = { + toggle: () => { + const running = !this.running + this.running = running + this.#post({ type: 'set-running', running }) + }, + setInstrumentCount: (count) => { + this.instrumentCount = count + this.#resetWorker(count) + }, + setTargetRate: (rate) => { + const sampleRate = normalizeFeedSampleRate(rate) + this.targetTicksPerSecond = sampleRate + this.#post({ type: 'set-rate', ticksPerSecond: sampleRate }) + }, + setPublishInterval: (publishIntervalMs) => { + this.publishIntervalMs = publishIntervalMs + this.#post({ + type: 'set-publish-interval', + intervalMs: publishIntervalMs, + }) + }, + setSparklineUpdates: (enabled) => { + this.updateSparklines = enabled + this.#post({ type: 'set-sparklines', enabled }) + }, + setSparklineSampleInterval: (intervalMs) => { + this.sparklineSampleIntervalMs = intervalMs + this.#post({ type: 'set-sparkline-interval', intervalMs }) + }, + runBurst: () => this.#post({ type: 'burst', tickCount: 25_000 }), + reset: () => this.#resetWorker(this.instrumentCount), + } + } + + start(): () => void { + const worker = new Worker( + new URL('./worker/market-feed.worker.ts', import.meta.url), + { type: 'module' }, + ) + this.#runtime.worker = worker + worker.addEventListener('message', this.#handleWorkerMessage) + worker.addEventListener('error', this.#handleWorkerError) + this.#post({ + type: 'start', + rowCount: this.instrumentCount, + running: this.running, + ticksPerSecond: this.targetTicksPerSecond, + publishIntervalMs: this.publishIntervalMs, + updateSparklines: this.updateSparklines, + sparklineSampleIntervalMs: this.sparklineSampleIntervalMs, + }) + return () => this.stop() + } + + stop(): void { + this.#runtime.worker?.removeEventListener( + 'message', + this.#handleWorkerMessage, + ) + this.#runtime.worker?.removeEventListener('error', this.#handleWorkerError) + this.#runtime.worker?.terminate() + this.#runtime.worker = null + this.#observers.clear() + } + + observe(observer: MarketFeedObserver): () => void { + this.#observers.add(observer) + return () => this.#observers.delete(observer) + } + + getQuoteBySymbol( + quotes: Array, + symbol: string | null, + ): MarketQuote | null { + if (symbol === null) return null + + const index = this.#runtime.quoteIndexBySymbol.get(symbol) + return index === undefined ? null : (quotes[index] ?? null) + } + + completeRender(): void { + if (!this.#runtime.renderPending) return + + this.#runtime.renderPending = false + for (const observer of this.#observers) { + observer.renderCommitted?.() + } + if ( + this.#runtime.resetWaitingForCommit && + this.#runtime.resetSnapshotReady + ) { + this.#runtime.resetWaitingForCommit = false + this.#runtime.resetSnapshotReady = false + this.#post({ type: 'set-running', running: this.running }) + } + } + + readonly #handleWorkerMessage = ({ + data, + }: MessageEvent): void => { + if (data.type === 'snapshot') { + this.#runtime.feedSessionId = data.sessionId + if (this.#runtime.resetWaitingForCommit) { + this.#runtime.resetSnapshotReady = true + } + this.#startMutation() + const quotes = hydrateMarketQuotes(data.quotes) + this.#runtime.quoteIndexBySymbol = new Map( + quotes.map((quote, index) => [quote.symbol, index]), + ) + this.quotes = quotes + this.workerReady = true + this.#notifyView() + return + } + + if (data.sessionId !== this.#runtime.feedSessionId) return + + for (const observer of this.#observers) { + observer.messageReceived?.() + } + this.#startMutation() + const quotes = applyMarketUpdates(this.quotes, data.updates) + this.quotes = quotes + this.#notifyView() + const feedBatch = { + tickCount: data.tickCount, + updateCount: data.updates.length, + supersededUpdateCount: data.coalescedUpdateCount, + } + for (const observer of this.#observers) { + observer.batchApplied?.(feedBatch) + } + } + + readonly #handleWorkerError = (error: ErrorEvent): void => { + this.workerReady = false + this.running = false + console.error('Market feed worker failed', error) + } + + #resetWorker(rowCount: number): void { + if (this.running) { + this.workerReady = false + this.#runtime.resetWaitingForCommit = true + this.#runtime.resetSnapshotReady = false + this.#post({ type: 'set-running', running: false }) + } + this.#post({ type: 'reset', rowCount }) + } + + #startMutation(): void { + this.#runtime.renderPending = true + for (const observer of this.#observers) { + observer.mutationStarted?.() + } + } + + #notifyView(): void { + for (const observer of this.#observers) { + observer.viewChanged?.() + } + } + + #post(command: MarketFeedCommand): void { + this.#runtime.worker?.postMessage(command) + } +} diff --git a/examples/ember/realtime-trading/app/feed/market-instruments.ts b/examples/ember/realtime-trading/app/feed/market-instruments.ts new file mode 100644 index 0000000000..ac18d14ea9 --- /dev/null +++ b/examples/ember/realtime-trading/app/feed/market-instruments.ts @@ -0,0 +1,742 @@ +export type MarketCode = + | 'US' + | 'NL' + | 'DE' + | 'FR' + | 'IT' + | 'ES' + | 'CH' + | 'DK' + | 'SE' + | 'FI' + | 'GB' + | 'KR' + | 'JP' + | 'HK' + | 'CA' + | 'AU' + +export type BaseInstrument = readonly [ + symbol: string, + company: string, + market: MarketCode, +] + +/** + * Current S&P 500 constituent universe used by the realtime trading examples. + * + * Source snapshot: https://github.com/datasets/s-and-p-500-companies + * Retrieved: 2026-08-15. + * Multiple share classes are intentionally represented as separate instruments. + */ +export const marketInstruments = Object.freeze([ + ['MMM', '3M', 'US'], + ['AOS', 'A. O. Smith', 'US'], + ['ABT', 'Abbott Laboratories', 'US'], + ['ABBV', 'AbbVie', 'US'], + ['ACN', 'Accenture', 'US'], + ['ADBE', 'Adobe Inc.', 'US'], + ['AMD', 'Advanced Micro Devices', 'US'], + ['AES', 'AES Corporation', 'US'], + ['AFL', 'Aflac', 'US'], + ['A', 'Agilent Technologies', 'US'], + ['APD', 'Air Products', 'US'], + ['ABNB', 'Airbnb', 'US'], + ['AKAM', 'Akamai Technologies', 'US'], + ['ALB', 'Albemarle Corporation', 'US'], + ['ARE', 'Alexandria Real Estate Equities', 'US'], + ['ALGN', 'Align Technology', 'US'], + ['ALLE', 'Allegion', 'US'], + ['LNT', 'Alliant Energy', 'US'], + ['ALL', 'Allstate', 'US'], + ['GOOGL', 'Alphabet Inc. (Class A)', 'US'], + ['GOOG', 'Alphabet Inc. (Class C)', 'US'], + ['MO', 'Altria', 'US'], + ['AMZN', 'Amazon', 'US'], + ['AMCR', 'Amcor', 'US'], + ['AEE', 'Ameren', 'US'], + ['AEP', 'American Electric Power', 'US'], + ['AXP', 'American Express', 'US'], + ['AIG', 'American International Group', 'US'], + ['AMT', 'American Tower', 'US'], + ['AWK', 'American Water Works', 'US'], + ['AMP', 'Ameriprise Financial', 'US'], + ['AME', 'Ametek', 'US'], + ['AMGN', 'Amgen', 'US'], + ['APH', 'Amphenol', 'US'], + ['ADI', 'Analog Devices', 'US'], + ['AON', 'Aon plc', 'US'], + ['APA', 'APA Corporation', 'US'], + ['APO', 'Apollo Global Management', 'US'], + ['AAPL', 'Apple Inc.', 'US'], + ['AMAT', 'Applied Materials', 'US'], + ['APP', 'AppLovin', 'US'], + ['APTV', 'Aptiv', 'US'], + ['ACGL', 'Arch Capital Group', 'US'], + ['ADM', 'Archer Daniels Midland', 'US'], + ['ARES', 'Ares Management', 'US'], + ['ANET', 'Arista Networks', 'US'], + ['AJG', 'Arthur J. Gallagher & Co.', 'US'], + ['AIZ', 'Assurant', 'US'], + ['T', 'AT&T', 'US'], + ['ATO', 'Atmos Energy', 'US'], + ['ADSK', 'Autodesk', 'US'], + ['ADP', 'Automatic Data Processing', 'US'], + ['AZO', 'AutoZone', 'US'], + ['AVB', 'AvalonBay Communities', 'US'], + ['AVY', 'Avery Dennison', 'US'], + ['AXON', 'Axon Enterprise', 'US'], + ['BKR', 'Baker Hughes', 'US'], + ['BALL', 'Ball Corporation', 'US'], + ['BAC', 'Bank of America', 'US'], + ['BAX', 'Baxter International', 'US'], + ['BDX', 'Becton Dickinson', 'US'], + ['BRK.B', 'Berkshire Hathaway', 'US'], + ['BBY', 'Best Buy', 'US'], + ['TECH', 'Bio-Techne', 'US'], + ['BIIB', 'Biogen', 'US'], + ['BLK', 'BlackRock', 'US'], + ['BX', 'Blackstone Inc.', 'US'], + ['XYZ', 'Block, Inc.', 'US'], + ['BNY', 'BNY Mellon', 'US'], + ['BA', 'Boeing', 'US'], + ['BKNG', 'Booking Holdings', 'US'], + ['BSX', 'Boston Scientific', 'US'], + ['BMY', 'Bristol Myers Squibb', 'US'], + ['AVGO', 'Broadcom', 'US'], + ['BR', 'Broadridge Financial Solutions', 'US'], + ['BRO', 'Brown & Brown', 'US'], + ['BF.B', 'Brown–Forman', 'US'], + ['BLDR', 'Builders FirstSource', 'US'], + ['BG', 'Bunge Global', 'US'], + ['BXP', 'BXP, Inc.', 'US'], + ['CHRW', 'C.H. Robinson', 'US'], + ['CDNS', 'Cadence Design Systems', 'US'], + ['CPT', 'Camden Property Trust', 'US'], + ['COF', 'Capital One', 'US'], + ['CAH', 'Cardinal Health', 'US'], + ['CCL', 'Carnival Corporation', 'US'], + ['CARR', 'Carrier Global', 'US'], + ['CVNA', 'Carvana', 'US'], + ['CASY', "Casey's", 'US'], + ['CAT', 'Caterpillar Inc.', 'US'], + ['CBOE', 'Cboe Global Markets', 'US'], + ['CBRE', 'CBRE Group', 'US'], + ['CDW', 'CDW Corporation', 'US'], + ['COR', 'Cencora', 'US'], + ['CNC', 'Centene Corporation', 'US'], + ['CNP', 'CenterPoint Energy', 'US'], + ['CF', 'CF Industries', 'US'], + ['CRL', 'Charles River Laboratories', 'US'], + ['SCHW', 'Charles Schwab Corporation', 'US'], + ['CHTR', 'Charter Communications', 'US'], + ['CVX', 'Chevron Corporation', 'US'], + ['CMG', 'Chipotle Mexican Grill', 'US'], + ['CB', 'Chubb Limited', 'US'], + ['CHD', 'Church & Dwight', 'US'], + ['CIEN', 'Ciena', 'US'], + ['CI', 'Cigna', 'US'], + ['CINF', 'Cincinnati Financial', 'US'], + ['CTAS', 'Cintas', 'US'], + ['CSCO', 'Cisco', 'US'], + ['C', 'Citigroup', 'US'], + ['CFG', 'Citizens Financial Group', 'US'], + ['CLX', 'Clorox', 'US'], + ['CME', 'CME Group', 'US'], + ['CMS', 'CMS Energy', 'US'], + ['KO', 'Coca-Cola Company (The)', 'US'], + ['CTSH', 'Cognizant', 'US'], + ['COHR', 'Coherent Corp.', 'US'], + ['COIN', 'Coinbase', 'US'], + ['CL', 'Colgate-Palmolive', 'US'], + ['CMCSA', 'Comcast', 'US'], + ['FIX', 'Comfort Systems USA', 'US'], + ['COP', 'ConocoPhillips', 'US'], + ['ED', 'Consolidated Edison', 'US'], + ['STZ', 'Constellation Brands', 'US'], + ['CEG', 'Constellation Energy', 'US'], + ['COO', 'Cooper Companies (The)', 'US'], + ['CPRT', 'Copart', 'US'], + ['GLW', 'Corning Inc.', 'US'], + ['CPAY', 'Corpay', 'US'], + ['CTVA', 'Corteva', 'US'], + ['CSGP', 'CoStar Group', 'US'], + ['COST', 'Costco', 'US'], + ['CRH', 'CRH plc', 'US'], + ['CRWD', 'CrowdStrike', 'US'], + ['CCI', 'Crown Castle', 'US'], + ['CSX', 'CSX Corporation', 'US'], + ['CMI', 'Cummins', 'US'], + ['CVS', 'CVS Health', 'US'], + ['DHR', 'Danaher Corporation', 'US'], + ['DRI', 'Darden Restaurants', 'US'], + ['DDOG', 'Datadog', 'US'], + ['DVA', 'DaVita', 'US'], + ['DECK', 'Deckers Brands', 'US'], + ['DE', 'Deere & Company', 'US'], + ['DELL', 'Dell Technologies', 'US'], + ['DAL', 'Delta Air Lines', 'US'], + ['DVN', 'Devon Energy', 'US'], + ['DXCM', 'Dexcom', 'US'], + ['FANG', 'Diamondback Energy', 'US'], + ['DLR', 'Digital Realty', 'US'], + ['DG', 'Dollar General', 'US'], + ['DLTR', 'Dollar Tree', 'US'], + ['D', 'Dominion Energy', 'US'], + ['DPZ', "Domino's", 'US'], + ['DASH', 'DoorDash', 'US'], + ['DOV', 'Dover Corporation', 'US'], + ['DOW', 'Dow Inc.', 'US'], + ['DHI', 'D. R. Horton', 'US'], + ['DTE', 'DTE Energy', 'US'], + ['DUK', 'Duke Energy', 'US'], + ['DD', 'DuPont', 'US'], + ['ETN', 'Eaton Corporation', 'US'], + ['EBAY', 'eBay Inc.', 'US'], + ['ECHO', 'EchoStar', 'US'], + ['ECL', 'Ecolab', 'US'], + ['EIX', 'Edison International', 'US'], + ['EW', 'Edwards Lifesciences', 'US'], + ['ELV', 'Elevance Health', 'US'], + ['EME', 'Emcor', 'US'], + ['EMR', 'Emerson Electric', 'US'], + ['ETR', 'Entergy', 'US'], + ['EOG', 'EOG Resources', 'US'], + ['EQT', 'EQT Corporation', 'US'], + ['EFX', 'Equifax', 'US'], + ['EQIX', 'Equinix', 'US'], + ['EQR', 'Equity Residential', 'US'], + ['ERIE', 'Erie Indemnity', 'US'], + ['ESS', 'Essex Property Trust', 'US'], + ['EL', 'Estée Lauder Companies (The)', 'US'], + ['EG', 'Everest Group', 'US'], + ['EVRG', 'Evergy', 'US'], + ['ES', 'Eversource Energy', 'US'], + ['EXC', 'Exelon', 'US'], + ['EXE', 'Expand Energy', 'US'], + ['EXPE', 'Expedia Group', 'US'], + ['EXPD', 'Expeditors International', 'US'], + ['EXR', 'Extra Space Storage', 'US'], + ['XOM', 'ExxonMobil', 'US'], + ['FFIV', 'F5, Inc.', 'US'], + ['FDS', 'FactSet', 'US'], + ['FICO', 'Fair Isaac', 'US'], + ['FAST', 'Fastenal', 'US'], + ['FRT', 'Federal Realty Investment Trust', 'US'], + ['FDX', 'FedEx', 'US'], + ['FDXF', 'FedEx Freight', 'US'], + ['FERG', 'Ferguson Enterprises', 'US'], + ['FIS', 'Fidelity National Information Services', 'US'], + ['FITB', 'Fifth Third Bancorp', 'US'], + ['FSLR', 'First Solar', 'US'], + ['FE', 'FirstEnergy', 'US'], + ['FISV', 'Fiserv', 'US'], + ['FLEX', 'Flex Ltd.', 'US'], + ['F', 'Ford Motor Company', 'US'], + ['FTNT', 'Fortinet', 'US'], + ['FTV', 'Fortive', 'US'], + ['FOXA', 'Fox Corporation (Class A)', 'US'], + ['FOX', 'Fox Corporation (Class B)', 'US'], + ['BEN', 'Franklin Resources', 'US'], + ['FCX', 'Freeport-McMoRan', 'US'], + ['GRMN', 'Garmin', 'US'], + ['IT', 'Gartner', 'US'], + ['GE', 'GE Aerospace', 'US'], + ['GEHC', 'GE HealthCare', 'US'], + ['GEV', 'GE Vernova', 'US'], + ['GEN', 'Gen Digital', 'US'], + ['GNRC', 'Generac', 'US'], + ['GD', 'General Dynamics', 'US'], + ['GIS', 'General Mills', 'US'], + ['GM', 'General Motors', 'US'], + ['GPC', 'Genuine Parts Company', 'US'], + ['GILD', 'Gilead Sciences', 'US'], + ['GPN', 'Global Payments', 'US'], + ['GL', 'Globe Life', 'US'], + ['GDDY', 'GoDaddy', 'US'], + ['GS', 'Goldman Sachs', 'US'], + ['HAL', 'Halliburton', 'US'], + ['HIG', 'Hartford (The)', 'US'], + ['HAS', 'Hasbro', 'US'], + ['HCA', 'HCA Healthcare', 'US'], + ['DOC', 'Healthpeak Properties', 'US'], + ['HSIC', 'Henry Schein', 'US'], + ['HSY', 'Hershey Company (The)', 'US'], + ['HPE', 'Hewlett Packard Enterprise', 'US'], + ['HLT', 'Hilton Worldwide', 'US'], + ['HD', 'Home Depot (The)', 'US'], + ['HONA', 'Honeywell Aerospace', 'US'], + ['HON', 'Honeywell Technologies', 'US'], + ['HRL', 'Hormel Foods', 'US'], + ['HST', 'Host Hotels & Resorts', 'US'], + ['HWM', 'Howmet Aerospace', 'US'], + ['HPQ', 'HP Inc.', 'US'], + ['HUBB', 'Hubbell Incorporated', 'US'], + ['HUM', 'Humana', 'US'], + ['HBAN', 'Huntington Bancshares', 'US'], + ['HII', 'Huntington Ingalls Industries', 'US'], + ['IBM', 'IBM', 'US'], + ['IEX', 'IDEX Corporation', 'US'], + ['IDXX', 'Idexx Laboratories', 'US'], + ['ITW', 'Illinois Tool Works', 'US'], + ['INCY', 'Incyte', 'US'], + ['IR', 'Ingersoll Rand', 'US'], + ['PODD', 'Insulet Corporation', 'US'], + ['INTC', 'Intel', 'US'], + ['IBKR', 'Interactive Brokers', 'US'], + ['ICE', 'Intercontinental Exchange', 'US'], + ['IFF', 'International Flavors & Fragrances', 'US'], + ['IP', 'International Paper', 'US'], + ['INTU', 'Intuit', 'US'], + ['ISRG', 'Intuitive Surgical', 'US'], + ['IVZ', 'Invesco', 'US'], + ['INVH', 'Invitation Homes', 'US'], + ['IQV', 'IQVIA', 'US'], + ['IRM', 'Iron Mountain', 'US'], + ['JBHT', 'J.B. Hunt', 'US'], + ['JBL', 'Jabil', 'US'], + ['JKHY', 'Jack Henry & Associates', 'US'], + ['J', 'Jacobs Solutions', 'US'], + ['JNJ', 'Johnson & Johnson', 'US'], + ['JCI', 'Johnson Controls', 'US'], + ['JPM', 'JPMorgan Chase', 'US'], + ['KVUE', 'Kenvue', 'US'], + ['KDP', 'Keurig Dr Pepper', 'US'], + ['KEY', 'KeyCorp', 'US'], + ['KEYS', 'Keysight Technologies', 'US'], + ['KMB', 'Kimberly-Clark', 'US'], + ['KIM', 'Kimco Realty', 'US'], + ['KMI', 'Kinder Morgan', 'US'], + ['KKR', 'KKR & Co.', 'US'], + ['KLAC', 'KLA Corporation', 'US'], + ['KHC', 'Kraft Heinz', 'US'], + ['KR', 'Kroger', 'US'], + ['LHX', 'L3Harris', 'US'], + ['LH', 'Labcorp', 'US'], + ['LRCX', 'Lam Research', 'US'], + ['LVS', 'Las Vegas Sands', 'US'], + ['LDOS', 'Leidos', 'US'], + ['LEN', 'Lennar', 'US'], + ['LII', 'Lennox International', 'US'], + ['LLY', 'Lilly (Eli)', 'US'], + ['LIN', 'Linde plc', 'US'], + ['LYV', 'Live Nation Entertainment', 'US'], + ['LMT', 'Lockheed Martin', 'US'], + ['L', 'Loews Corporation', 'US'], + ['LOW', "Lowe's", 'US'], + ['LULU', 'Lululemon Athletica', 'US'], + ['LITE', 'Lumentum', 'US'], + ['LYB', 'LyondellBasell', 'US'], + ['MTB', 'M&T Bank', 'US'], + ['MPC', 'Marathon Petroleum', 'US'], + ['MAR', 'Marriott International', 'US'], + ['MRSH', 'Marsh McLennan', 'US'], + ['MLM', 'Martin Marietta Materials', 'US'], + ['MRVL', 'Marvell Technology', 'US'], + ['MAS', 'Masco', 'US'], + ['MA', 'Mastercard', 'US'], + ['MKC', 'McCormick & Company', 'US'], + ['MCD', "McDonald's", 'US'], + ['MCK', 'McKesson Corporation', 'US'], + ['MDT', 'Medtronic', 'US'], + ['MRK', 'Merck & Co.', 'US'], + ['META', 'Meta Platforms', 'US'], + ['MET', 'MetLife', 'US'], + ['MTD', 'Mettler Toledo', 'US'], + ['MGM', 'MGM Resorts', 'US'], + ['MCHP', 'Microchip Technology', 'US'], + ['MU', 'Micron Technology', 'US'], + ['MSFT', 'Microsoft', 'US'], + ['MAA', 'Mid-America Apartment Communities', 'US'], + ['MRNA', 'Moderna', 'US'], + ['TAP', 'Molson Coors Beverage Company', 'US'], + ['MDLZ', 'Mondelez International', 'US'], + ['MPWR', 'Monolithic Power Systems', 'US'], + ['MNST', 'Monster Beverage', 'US'], + ['MCO', "Moody's Corporation", 'US'], + ['MS', 'Morgan Stanley', 'US'], + ['MOS', 'Mosaic Company (The)', 'US'], + ['MSI', 'Motorola Solutions', 'US'], + ['MSCI', 'MSCI', 'US'], + ['NDAQ', 'Nasdaq, Inc.', 'US'], + ['NTAP', 'NetApp', 'US'], + ['NFLX', 'Netflix', 'US'], + ['NEM', 'Newmont', 'US'], + ['NWSA', 'News Corp (Class A)', 'US'], + ['NWS', 'News Corp (Class B)', 'US'], + ['NEE', 'NextEra Energy', 'US'], + ['NKE', 'Nike, Inc.', 'US'], + ['NI', 'NiSource', 'US'], + ['NDSN', 'Nordson Corporation', 'US'], + ['NSC', 'Norfolk Southern', 'US'], + ['NTRS', 'Northern Trust', 'US'], + ['NOC', 'Northrop Grumman', 'US'], + ['NCLH', 'Norwegian Cruise Line Holdings', 'US'], + ['NRG', 'NRG Energy', 'US'], + ['NUE', 'Nucor', 'US'], + ['NVDA', 'Nvidia', 'US'], + ['NVR', 'NVR, Inc.', 'US'], + ['NXPI', 'NXP Semiconductors', 'US'], + ['ORLY', "O'Reilly Automotive", 'US'], + ['OXY', 'Occidental Petroleum', 'US'], + ['ODFL', 'Old Dominion', 'US'], + ['OMC', 'Omnicom Group', 'US'], + ['ON', 'ON Semiconductor', 'US'], + ['OKE', 'Oneok', 'US'], + ['ORCL', 'Oracle Corporation', 'US'], + ['OTIS', 'Otis Worldwide', 'US'], + ['PCAR', 'Paccar', 'US'], + ['PKG', 'Packaging Corporation of America', 'US'], + ['PLTR', 'Palantir Technologies', 'US'], + ['PANW', 'Palo Alto Networks', 'US'], + ['PSKY', 'Paramount Skydance Corporation', 'US'], + ['PH', 'Parker Hannifin', 'US'], + ['PAYX', 'Paychex', 'US'], + ['PYPL', 'PayPal', 'US'], + ['PNR', 'Pentair', 'US'], + ['PEP', 'PepsiCo', 'US'], + ['PFE', 'Pfizer', 'US'], + ['PCG', 'PG&E Corporation', 'US'], + ['PM', 'Philip Morris International', 'US'], + ['PSX', 'Phillips 66', 'US'], + ['PNW', 'Pinnacle West Capital', 'US'], + ['PNC', 'PNC Financial Services', 'US'], + ['PPG', 'PPG Industries', 'US'], + ['PPL', 'PPL Corporation', 'US'], + ['PFG', 'Principal Financial Group', 'US'], + ['PG', 'Procter & Gamble', 'US'], + ['PGR', 'Progressive Corporation', 'US'], + ['PLD', 'Prologis', 'US'], + ['PRU', 'Prudential Financial', 'US'], + ['PEG', 'Public Service Enterprise Group', 'US'], + ['PTC', 'PTC Inc.', 'US'], + ['PSA', 'Public Storage', 'US'], + ['PHM', 'PulteGroup', 'US'], + ['PWR', 'Quanta Services', 'US'], + ['QCOM', 'Qualcomm', 'US'], + ['DGX', 'Quest Diagnostics', 'US'], + ['Q', 'Qnity Electronics', 'US'], + ['RL', 'Ralph Lauren Corporation', 'US'], + ['RJF', 'Raymond James Financial', 'US'], + ['RTX', 'RTX Corporation', 'US'], + ['O', 'Realty Income', 'US'], + ['REG', 'Regency Centers', 'US'], + ['REGN', 'Regeneron Pharmaceuticals', 'US'], + ['RF', 'Regions Financial Corporation', 'US'], + ['RSG', 'Republic Services', 'US'], + ['RMD', 'ResMed|', 'US'], + ['RVTY', 'Revvity', 'US'], + ['HOOD', 'Robinhood Markets', 'US'], + ['ROK', 'Rockwell Automation', 'US'], + ['ROL', 'Rollins, Inc.', 'US'], + ['ROP', 'Roper Technologies', 'US'], + ['ROST', 'Ross Stores', 'US'], + ['RCL', 'Royal Caribbean Group', 'US'], + ['SPGI', 'S&P Global', 'US'], + ['CRM', 'Salesforce', 'US'], + ['SNDK', 'Sandisk', 'US'], + ['SBAC', 'SBA Communications', 'US'], + ['SLB', 'Schlumberger', 'US'], + ['STX', 'Seagate Technology', 'US'], + ['SRE', 'Sempra', 'US'], + ['NOW', 'ServiceNow', 'US'], + ['SHW', 'Sherwin-Williams', 'US'], + ['SPG', 'Simon Property Group', 'US'], + ['SWKS', 'Skyworks Solutions', 'US'], + ['SJM', 'J.M. Smucker Company (The)', 'US'], + ['SW', 'Smurfit Westrock', 'US'], + ['SNA', 'Snap-on', 'US'], + ['SOLV', 'Solventum', 'US'], + ['SO', 'Southern Company', 'US'], + ['LUV', 'Southwest Airlines', 'US'], + ['SWK', 'Stanley Black & Decker', 'US'], + ['SBUX', 'Starbucks', 'US'], + ['STT', 'State Street Corporation', 'US'], + ['STLD', 'Steel Dynamics', 'US'], + ['STE', 'Steris', 'US'], + ['SYK', 'Stryker Corporation', 'US'], + ['SMCI', 'Supermicro', 'US'], + ['SYF', 'Synchrony Financial', 'US'], + ['SNPS', 'Synopsys', 'US'], + ['SYY', 'Sysco', 'US'], + ['TMUS', 'T-Mobile US', 'US'], + ['TROW', 'T. Rowe Price', 'US'], + ['TTWO', 'Take-Two Interactive', 'US'], + ['TPR', 'Tapestry, Inc.', 'US'], + ['TRGP', 'Targa Resources', 'US'], + ['TGT', 'Target Corporation', 'US'], + ['TEL', 'TE Connectivity', 'US'], + ['TDY', 'Teledyne Technologies', 'US'], + ['TER', 'Teradyne', 'US'], + ['TSLA', 'Tesla, Inc.', 'US'], + ['TXN', 'Texas Instruments', 'US'], + ['TPL', 'Texas Pacific Land Corporation', 'US'], + ['TXT', 'Textron', 'US'], + ['TMO', 'Thermo Fisher Scientific', 'US'], + ['TJX', 'TJX Companies', 'US'], + ['TKO', 'TKO Group Holdings', 'US'], + ['TTD', 'Trade Desk (The)', 'US'], + ['TSCO', 'Tractor Supply', 'US'], + ['TT', 'Trane Technologies', 'US'], + ['TDG', 'TransDigm Group', 'US'], + ['TRV', 'Travelers Companies (The)', 'US'], + ['TRMB', 'Trimble Inc.', 'US'], + ['TFC', 'Truist Financial', 'US'], + ['TYL', 'Tyler Technologies', 'US'], + ['TSN', 'Tyson Foods', 'US'], + ['USB', 'U.S. Bancorp', 'US'], + ['UBER', 'Uber', 'US'], + ['UDR', 'UDR, Inc.', 'US'], + ['ULTA', 'Ulta Beauty', 'US'], + ['UNP', 'Union Pacific Corporation', 'US'], + ['UAL', 'United Airlines Holdings', 'US'], + ['UPS', 'United Parcel Service', 'US'], + ['URI', 'United Rentals', 'US'], + ['UNH', 'UnitedHealth Group', 'US'], + ['UHS', 'Universal Health Services', 'US'], + ['VLO', 'Valero Energy', 'US'], + ['VEEV', 'Veeva Systems', 'US'], + ['VTR', 'Ventas', 'US'], + ['VLTO', 'Veralto', 'US'], + ['VRSN', 'Verisign', 'US'], + ['VRSK', 'Verisk Analytics', 'US'], + ['VZ', 'Verizon', 'US'], + ['VRTX', 'Vertex Pharmaceuticals', 'US'], + ['VRT', 'Vertiv', 'US'], + ['VTRS', 'Viatris', 'US'], + ['VICI', 'Vici Properties', 'US'], + ['V', 'Visa Inc.', 'US'], + ['VST', 'Vistra Corp.', 'US'], + ['VMC', 'Vulcan Materials Company', 'US'], + ['WRB', 'W. R. Berkley Corporation', 'US'], + ['GWW', 'W. W. Grainger', 'US'], + ['WAB', 'Wabtec', 'US'], + ['WMT', 'Walmart', 'US'], + ['DIS', 'Walt Disney Company (The)', 'US'], + ['WBD', 'Warner Bros. Discovery', 'US'], + ['WM', 'Waste Management', 'US'], + ['WAT', 'Waters Corporation', 'US'], + ['WEC', 'WEC Energy Group', 'US'], + ['WFC', 'Wells Fargo', 'US'], + ['WELL', 'Welltower', 'US'], + ['WST', 'West Pharmaceutical Services', 'US'], + ['WDC', 'Western Digital', 'US'], + ['WY', 'Weyerhaeuser', 'US'], + ['WSM', 'Williams-Sonoma, Inc.', 'US'], + ['WMB', 'Williams Companies', 'US'], + ['WTW', 'Willis Towers Watson', 'US'], + ['WDAY', 'Workday, Inc.', 'US'], + ['WYNN', 'Wynn Resorts', 'US'], + ['XEL', 'Xcel Energy', 'US'], + ['XYL', 'Xylem Inc.', 'US'], + ['YUM', 'Yum! Brands', 'US'], + ['ZBRA', 'Zebra Technologies', 'US'], + ['ZBH', 'Zimmer Biomet', 'US'], + ['ZTS', 'Zoetis', 'US'], +]) + +/** + * Representative liquid international listings used to diversify the fixture. + * Symbols use their local-market form and the third tuple value is an ISO-style + * country/market code, rather than a trading currency or exchange MIC. + * + * References checked 2026-08-15: STOXX Europe 50, KRX KOSPI market, + * JPX TOPIX Core30, and HKEX index constituent materials. + */ +const europeanInstruments = Object.freeze([ + ['ASML', 'ASML Holding', 'NL'], + ['INGA', 'ING Group', 'NL'], + ['ADYEN', 'Adyen', 'NL'], + ['PHIA', 'Philips', 'NL'], + ['HEIA', 'Heineken', 'NL'], + ['SAP', 'SAP', 'DE'], + ['SIE', 'Siemens', 'DE'], + ['ALV', 'Allianz', 'DE'], + ['DTE', 'Deutsche Telekom', 'DE'], + ['MBG', 'Mercedes-Benz Group', 'DE'], + ['BMW', 'BMW', 'DE'], + ['BAS', 'BASF', 'DE'], + ['MUV2', 'Munich Re', 'DE'], + ['VOW3', 'Volkswagen Preference', 'DE'], + ['IFX', 'Infineon Technologies', 'DE'], + ['MC', 'LVMH', 'FR'], + ['OR', "L'Oréal", 'FR'], + ['AIR', 'Airbus', 'FR'], + ['SU', 'Schneider Electric', 'FR'], + ['TTE', 'TotalEnergies', 'FR'], + ['SAN', 'Sanofi', 'FR'], + ['BNP', 'BNP Paribas', 'FR'], + ['CS', 'AXA', 'FR'], + ['DG', 'Vinci', 'FR'], + ['ENEL', 'Enel', 'IT'], + ['ENI', 'Eni', 'IT'], + ['ISP', 'Intesa Sanpaolo', 'IT'], + ['UCG', 'UniCredit', 'IT'], + ['STLAM', 'Stellantis', 'IT'], + ['SAN', 'Banco Santander', 'ES'], + ['IBE', 'Iberdrola', 'ES'], + ['ITX', 'Inditex', 'ES'], + ['BBVA', 'BBVA', 'ES'], + ['NESN', 'Nestlé', 'CH'], + ['ROG', 'Roche Holding', 'CH'], + ['NOVN', 'Novartis', 'CH'], + ['UBSG', 'UBS Group', 'CH'], + ['NOVO-B', 'Novo Nordisk', 'DK'], + ['MAERSK-B', 'A.P. Moller - Maersk', 'DK'], + ['VOLV-B', 'Volvo', 'SE'], + ['ERIC-B', 'Ericsson', 'SE'], + ['NOKIA', 'Nokia', 'FI'], + ['SHEL', 'Shell', 'GB'], + ['AZN', 'AstraZeneca', 'GB'], + ['HSBA', 'HSBC Holdings', 'GB'], + ['ULVR', 'Unilever', 'GB'], + ['LSEG', 'London Stock Exchange Group', 'GB'], +]) + +const europeanMarketCodes = Object.freeze([ + 'NL', + 'DE', + 'FR', + 'IT', + 'ES', + 'CH', + 'DK', + 'SE', + 'FI', + 'GB', +]) + +const europeanMarketGroups = Object.freeze( + europeanMarketCodes.map((market) => + europeanInstruments.filter(([, , instrumentMarket]) => + Object.is(instrumentMarket, market), + ), + ), +) + +const interleavedEuropeanInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...europeanMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + europeanMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const southKoreanInstruments = Object.freeze([ + ['005930', 'Samsung Electronics', 'KR'], + ['000660', 'SK hynix', 'KR'], + ['373220', 'LG Energy Solution', 'KR'], + ['207940', 'Samsung Biologics', 'KR'], + ['005380', 'Hyundai Motor', 'KR'], + ['000270', 'Kia', 'KR'], + ['068270', 'Celltrion', 'KR'], + ['105560', 'KB Financial Group', 'KR'], + ['055550', 'Shinhan Financial Group', 'KR'], + ['035420', 'NAVER', 'KR'], + ['035720', 'Kakao', 'KR'], + ['006400', 'Samsung SDI', 'KR'], + ['051910', 'LG Chem', 'KR'], + ['012330', 'Hyundai Mobis', 'KR'], + ['066570', 'LG Electronics', 'KR'], +]) + +const japaneseInstruments = Object.freeze([ + ['8306', 'Mitsubishi UFJ Financial Group', 'JP'], + ['7203', 'Toyota Motor', 'JP'], + ['6501', 'Hitachi', 'JP'], + ['8316', 'Sumitomo Mitsui Financial Group', 'JP'], + ['6758', 'Sony Group', 'JP'], + ['8058', 'Mitsubishi Corporation', 'JP'], + ['9984', 'SoftBank Group', 'JP'], + ['8035', 'Tokyo Electron', 'JP'], + ['8411', 'Mizuho Financial Group', 'JP'], + ['8031', 'Mitsui & Co.', 'JP'], + ['6861', 'Keyence', 'JP'], + ['7974', 'Nintendo', 'JP'], + ['6098', 'Recruit Holdings', 'JP'], + ['9432', 'Nippon Telegraph and Telephone', 'JP'], + ['4063', 'Shin-Etsu Chemical', 'JP'], +]) + +const hongKongInstruments = Object.freeze([ + ['0700', 'Tencent Holdings', 'HK'], + ['9988', 'Alibaba Group', 'HK'], + ['1810', 'Xiaomi', 'HK'], + ['3690', 'Meituan', 'HK'], + ['0941', 'China Mobile', 'HK'], + ['1211', 'BYD Company', 'HK'], + ['1299', 'AIA Group', 'HK'], + ['0388', 'Hong Kong Exchanges and Clearing', 'HK'], + ['0005', 'HSBC Holdings', 'HK'], + ['2318', 'Ping An Insurance', 'HK'], +]) + +const canadianInstruments = Object.freeze([ + ['RY', 'Royal Bank of Canada', 'CA'], + ['TD', 'Toronto-Dominion Bank', 'CA'], + ['SHOP', 'Shopify', 'CA'], + ['ENB', 'Enbridge', 'CA'], + ['CNR', 'Canadian National Railway', 'CA'], + ['CP', 'Canadian Pacific Kansas City', 'CA'], + ['BMO', 'Bank of Montreal', 'CA'], + ['CSU', 'Constellation Software', 'CA'], +]) + +const australianInstruments = Object.freeze([ + ['BHP', 'BHP Group', 'AU'], + ['CBA', 'Commonwealth Bank of Australia', 'AU'], + ['CSL', 'CSL', 'AU'], + ['NAB', 'National Australia Bank', 'AU'], + ['WBC', 'Westpac Banking Corporation', 'AU'], + ['ANZ', 'ANZ Group Holdings', 'AU'], + ['WES', 'Wesfarmers', 'AU'], + ['MQG', 'Macquarie Group', 'AU'], +]) + +const internationalMarketGroups = Object.freeze([ + interleavedEuropeanInstruments, + southKoreanInstruments, + japaneseInstruments, + hongKongInstruments, + canadianInstruments, + australianInstruments, +]) + +export const internationalInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...internationalMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + internationalMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const INTERNATIONAL_INSERTION_INTERVAL = 3 + +/** + * U.S. and international instruments are interleaved so ordinary benchmark + * sizes exercise multiple symbol formats and market labels. + */ +export const globalInstruments = Object.freeze( + marketInstruments.flatMap((instrument, index) => { + const internationalInstrument = + index % INTERNATIONAL_INSERTION_INTERVAL === 0 + ? internationalInstruments[index / INTERNATIONAL_INSERTION_INTERVAL] + : undefined + + return internationalInstrument + ? [instrument, internationalInstrument] + : [instrument] + }), +) as unknown as ReadonlyArray diff --git a/examples/ember/realtime-trading/app/feed/worker/market-feed-engine.ts b/examples/ember/realtime-trading/app/feed/worker/market-feed-engine.ts new file mode 100644 index 0000000000..3e5818f4d7 --- /dev/null +++ b/examples/ember/realtime-trading/app/feed/worker/market-feed-engine.ts @@ -0,0 +1,177 @@ +import { globalInstruments } from '../market-instruments.ts' +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const INITIAL_MARKET_SEED = 0x4d41524b +const LIVE_FEED_SEED = 0x5449434b + +export class MarketFeedEngine { + #quotes: Array = [] + #lastHistorySampledAt = new Uint32Array(0) + #random = createRandom(2_026) + #rowCursor = 0 + #tickIndex = 0 + + reset(count: number): Array { + const random = createRandom(INITIAL_MARKET_SEED ^ count) + const createdAt = Date.now() + + this.#quotes = Array.from({ length: count }, (_, index) => { + const [baseSymbol, company, market] = + globalInstruments[index % globalInstruments.length]! + const series = Math.floor(index / globalInstruments.length) + const symbol = series === 0 ? baseSymbol : `${baseSymbol}${series}` + const previousClose = roundPrice(20 + random() * 480) + const open = roundPrice(previousClose * (1 + (random() - 0.5) * 0.016)) + const spread = Math.max(0.01, open * (0.0002 + random() * 0.0004)) + const history = Array.from({ length: 24 }, (_, historyIndex) => + roundPrice( + open * + (1 + Math.sin(historyIndex / 4) * 0.002 + (random() - 0.5) * 0.001), + ), + ) + const volume = Math.floor(50_000 + random() * 2_000_000) + const lastSize = Math.floor(10 + random() * 5_000) + + return { + id: `instrument-${index}`, + symbol, + company, + venue: market, + previousClose, + open, + high: open, + low: open, + price: open, + bid: roundPrice(open - spread / 2), + ask: roundPrice(open + spread / 2), + bidSize: Math.floor(100 + random() * 25_000), + askSize: Math.floor(100 + random() * 25_000), + lastSize, + lastMove: 0, + lastUpdatedAt: createdAt, + volume, + turnover: roundMoney(open * volume), + history, + } + }) + + this.#random = createRandom(LIVE_FEED_SEED ^ count) + this.#rowCursor = 0 + this.#lastHistorySampledAt = new Uint32Array(count) + this.#lastHistorySampledAt.fill(createdAt >>> 0) + + return this.#quotes.map((quote) => ({ + ...quote, + history: [...quote.history], + })) + } + + applyTicks( + tickCount: number, + updateSparklines: boolean, + sparklineSampleIntervalMs: number, + ): Array { + if (this.#quotes.length === 0 || tickCount <= 0) return [] + + const updatedAt = Date.now() + const sampledAt = updatedAt >>> 0 + const sampleIntervalMs = Math.max(16, sparklineSampleIntervalMs) + const updatedQuotes = new Map() + const stride = 97 + + this.#tickIndex = 0 + while (this.#tickIndex < tickCount) { + this.#rowCursor = (this.#rowCursor + stride) % this.#quotes.length + const quote = this.#quotes[this.#rowCursor]! + const lastSampledAt = this.#lastHistorySampledAt[this.#rowCursor]! + const shouldUpdateHistory = + updateSparklines && + (sampledAt - lastSampledAt) >>> 0 >= sampleIntervalMs + + if (shouldUpdateHistory) { + this.#lastHistorySampledAt[this.#rowCursor] = sampledAt + } + + this.#applyTick(quote, shouldUpdateHistory, updatedAt) + + const previousUpdate = updatedQuotes.get(this.#rowCursor) + updatedQuotes.set(this.#rowCursor, { + index: this.#rowCursor, + price: quote.price, + bid: quote.bid, + ask: quote.ask, + bidSize: quote.bidSize, + askSize: quote.askSize, + lastSize: quote.lastSize, + lastMove: quote.lastMove, + lastUpdatedAt: quote.lastUpdatedAt, + high: quote.high, + low: quote.low, + volume: quote.volume, + turnover: quote.turnover, + ...(shouldUpdateHistory || previousUpdate?.history + ? { history: [...quote.history] } + : {}), + }) + this.#tickIndex++ + } + + return [...updatedQuotes.values()] + } + + #applyTick( + quote: MarketQuoteSnapshot, + updateHistory: boolean, + updatedAt: number, + ): void { + const previousPrice = quote.price + const volatility = 0.00015 + this.#random() * 0.0012 + const move = previousPrice * (this.#random() - 0.495) * volatility + const nextPrice = roundPrice(Math.max(0.1, previousPrice + move)) + const spread = Math.max( + 0.01, + nextPrice * (0.00015 + this.#random() * 0.0005), + ) + + quote.lastMove = nextPrice - previousPrice + quote.price = nextPrice + quote.high = Math.max(quote.high, nextPrice) + quote.low = Math.min(quote.low, nextPrice) + quote.bid = roundPrice(nextPrice - spread / 2) + quote.ask = roundPrice(nextPrice + spread / 2) + quote.bidSize = Math.floor(100 + this.#random() * 25_000) + quote.askSize = Math.floor(100 + this.#random() * 25_000) + quote.lastSize = Math.floor(10 + this.#random() * 5_000) + quote.lastUpdatedAt = updatedAt + quote.volume += quote.lastSize + quote.turnover = roundMoney(quote.turnover + nextPrice * quote.lastSize) + + if (updateHistory) { + quote.history = [...quote.history.slice(-23), nextPrice] + } + } +} + +function createRandom(seed: number): () => number { + const runtime = { state: seed >>> 0 } + return () => { + runtime.state += 0x6d2b79f5 + const stateValue = runtime.state + const firstMix = Math.imul(stateValue ^ (stateValue >>> 15), stateValue | 1) + const secondMix = + firstMix + Math.imul(firstMix ^ (firstMix >>> 7), firstMix | 61) + const value = firstMix ^ secondMix + return ((value ^ (value >>> 14)) >>> 0) / 4_294_967_296 + } +} + +function roundPrice(value: number): number { + return Math.round(value * 100) / 100 +} + +function roundMoney(value: number): number { + return Math.round(value * 100) / 100 +} diff --git a/examples/ember/realtime-trading/app/feed/worker/market-feed-protocol.ts b/examples/ember/realtime-trading/app/feed/worker/market-feed-protocol.ts new file mode 100644 index 0000000000..21997ec89c --- /dev/null +++ b/examples/ember/realtime-trading/app/feed/worker/market-feed-protocol.ts @@ -0,0 +1,70 @@ +export interface MarketQuoteSnapshot { + id: string + symbol: string + company: string + venue: string + previousClose: number + open: number + high: number + low: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + volume: number + turnover: number + history: Array +} + +export interface MarketQuoteUpdate { + index: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + high: number + low: number + volume: number + turnover: number + history?: Array +} + +export type MarketFeedCommand = + | { + type: 'start' + rowCount: number + running: boolean + ticksPerSecond: number + publishIntervalMs: number + updateSparklines: boolean + sparklineSampleIntervalMs: number + } + | { type: 'set-running'; running: boolean } + | { type: 'set-rate'; ticksPerSecond: number } + | { type: 'set-publish-interval'; intervalMs: number } + | { type: 'set-sparklines'; enabled: boolean } + | { type: 'set-sparkline-interval'; intervalMs: number } + | { type: 'reset'; rowCount: number } + | { type: 'burst'; tickCount: number } + +export type MarketFeedEvent = + | { + type: 'snapshot' + sessionId: number + quotes: Array + } + | { + type: 'updates' + sessionId: number + tickCount: number + coalescedUpdateCount: number + updates: Array + } diff --git a/examples/ember/realtime-trading/app/feed/worker/market-feed.worker.ts b/examples/ember/realtime-trading/app/feed/worker/market-feed.worker.ts new file mode 100644 index 0000000000..2b7a642fd9 --- /dev/null +++ b/examples/ember/realtime-trading/app/feed/worker/market-feed.worker.ts @@ -0,0 +1,143 @@ +import { initialMarketFeedConfig } from '../market-feed-config' +import { MarketFeedEngine } from './market-feed-engine' +import type { + MarketFeedCommand, + MarketFeedEvent, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const engine = new MarketFeedEngine() +const pendingUpdates = new Map() +const runtime = { + sessionId: 0, + pendingTickCount: 0, + pendingCoalescedUpdateCount: 0, + initialized: false, + running: true, + ticksPerSecond: initialMarketFeedConfig.targetSamplesPerSecond, + publishIntervalMs: initialMarketFeedConfig.publishIntervalMs, + publishTimerId: null as ReturnType | null, + updateSparklines: initialMarketFeedConfig.updateSparklines, + sparklineSampleIntervalMs: initialMarketFeedConfig.sparklineSampleIntervalMs, + tickBudget: 0, + lastTickAt: performance.now(), +} + +addEventListener('message', ({ data }: MessageEvent) => { + switch (data.type) { + case 'start': + runtime.running = data.running + runtime.ticksPerSecond = data.ticksPerSecond + runtime.publishIntervalMs = data.publishIntervalMs + runtime.updateSparklines = data.updateSparklines + runtime.sparklineSampleIntervalMs = data.sparklineSampleIntervalMs + restartPublishTimer() + reset(data.rowCount) + break + case 'set-running': + runtime.running = data.running + break + case 'set-rate': + runtime.ticksPerSecond = data.ticksPerSecond + break + case 'set-publish-interval': + runtime.publishIntervalMs = Math.max(4, data.intervalMs) + restartPublishTimer() + break + case 'set-sparklines': + runtime.updateSparklines = data.enabled + break + case 'set-sparkline-interval': + runtime.sparklineSampleIntervalMs = Math.max(16, data.intervalMs) + break + case 'reset': + reset(data.rowCount) + break + case 'burst': + produceTicks(data.tickCount) + flush() + break + } +}) + +setInterval(() => { + const now = performance.now() + const elapsed = Math.min(100, Math.max(0, now - runtime.lastTickAt)) + runtime.lastTickAt = now + + if (runtime.initialized && runtime.running) { + runtime.tickBudget += (runtime.ticksPerSecond * elapsed) / 1_000 + const tickCount = Math.floor(runtime.tickBudget) + runtime.tickBudget -= tickCount + produceTicks(tickCount) + } +}, 16) + +restartPublishTimer() + +function reset(rowCount: number): void { + runtime.initialized = true + runtime.sessionId++ + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + runtime.tickBudget = 0 + runtime.lastTickAt = performance.now() + + post({ + type: 'snapshot', + sessionId: runtime.sessionId, + quotes: engine.reset(rowCount), + }) +} + +function produceTicks(tickCount: number): void { + if (!runtime.initialized || tickCount <= 0) return + + runtime.pendingTickCount += tickCount + for (const update of engine.applyTicks( + tickCount, + runtime.updateSparklines, + runtime.sparklineSampleIntervalMs, + )) { + const previousUpdate = pendingUpdates.get(update.index) + if (previousUpdate) runtime.pendingCoalescedUpdateCount++ + pendingUpdates.set(update.index, { + ...update, + ...(update.history || !previousUpdate?.history + ? {} + : { history: previousUpdate.history }), + }) + } +} + +function flush(): void { + if (runtime.pendingTickCount === 0) return + + const message: MarketFeedEvent = { + type: 'updates', + sessionId: runtime.sessionId, + tickCount: runtime.pendingTickCount, + coalescedUpdateCount: runtime.pendingCoalescedUpdateCount, + updates: [...pendingUpdates.values()], + } + + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + post(message) +} + +function restartPublishTimer(): void { + if (runtime.publishTimerId !== null) { + clearInterval(runtime.publishTimerId) + } + runtime.publishTimerId = setInterval( + flush, + Math.max(4, runtime.publishIntervalMs), + ) +} + +function post(event: MarketFeedEvent): void { + postMessage(event) +} diff --git a/examples/ember/realtime-trading/app/router.ts b/examples/ember/realtime-trading/app/router.ts new file mode 100644 index 0000000000..eadbe60450 --- /dev/null +++ b/examples/ember/realtime-trading/app/router.ts @@ -0,0 +1,51 @@ +import EmbroiderRouter from '@embroider/router' +import config from '#config' + +export default class Router extends EmbroiderRouter { + location = config.locationType + rootURL = config.rootURL +} + +Router.map(function () {}) + +/** + * Caveat: + * - https://github.com/embroider-build/embroider/issues/2521 + * We don't yet have a way to do this in a nice way + * + */ +// function bundle(name: string, loader: () => Promise<{ default: unknown }>[]) { +// return { +// names: [name], +// load: async () => { +// const [template, route, controller] = await Promise.all(loader()); +// let slashName = name.replaceAll(".", "/"); +// let results: Record = {}; + +// if (template) results[`./templates/${slashName}`] = template.default; +// if (route) results[`./routes/${slashName}`] = route.default; +// if (controller) results[`./controllers/${slashName}`] = controller.default; + +// return { +// default: results, +// }; +// }, +// }; +// } + +/** + * Examples from: + * - https://github.com/NullVoxPopuli/limber/blob/67e2f54bbe224052e38f9a9e566d704411e65e86/apps/repl/app/router.ts#L35 + */ +// (window as any)._embroiderRouteBundles_ = [ +// bundle("docs", () => [import("./templates/docs.gts")]), +// bundle("docs.repl-sdk", () => [import("./templates/docs/repl-sdk.gts")]), +// bundle("docs.ember-repl", () => [import("./templates/docs/ember-repl.gts")]), +// bundle("docs.embedding", () => [import("./templates/docs/embedding.gts")]), +// bundle("docs.editor", () => [import("./templates/docs/editor.gts")]), +// bundle("docs.whatever", () => [ +// import("./the/template.gts"), +// import("./the/route.ts"), +// import("./the/controller.ts"), +// ]), +// ]; diff --git a/examples/ember/realtime-trading/app/table/table-config/quote-cells.gts b/examples/ember/realtime-trading/app/table/table-config/quote-cells.gts new file mode 100644 index 0000000000..2c2f8796c6 --- /dev/null +++ b/examples/ember/realtime-trading/app/table/table-config/quote-cells.gts @@ -0,0 +1,220 @@ +import Component from '@glimmer/component' +import { registerDestructor } from '@ember/destroyable' +import { on } from '@ember/modifier' +import type Owner from '@ember/owner' +import type { CellRenderableSignature } from '@tanstack/ember-table' +import type { MarketQuote } from '../../feed/market-data' +import type { tradingFeatures } from '../trading-features' + +export const quoteCellLifecycle = { created: 0, destroyed: 0 } + +export const quoteCellRendererNames = [ + 'Market', + 'Name', + 'Symbol', + 'Last', + 'Change', + 'ChangePercent', + 'Bid', + 'BidVolume', + 'Ask', + 'AskVolume', + 'Open', + 'High', + 'Low', + 'Intraday', +] as const +export const quoteComponentNames = [ + 'PriceCell', + 'StableMoveCell', + 'UpMoveCell', + 'DownMoveCell', + 'PercentChangeCell', + 'SpreadCell', + 'DepthCell', + 'QuoteAgeCell', + 'SparklineCell', +] as const +export type QuoteCellRendererName = (typeof quoteCellRendererNames)[number] +export type QuoteComponentName = (typeof quoteComponentNames)[number] + +const createCounterMap = (names: ReadonlyArray) => + Object.fromEntries(names.map((name) => [name, 0])) as Record + +export const quoteRenderDiagnostics = { + cellRendererCalls: 0, + componentRenderCalls: 0, + cellRendererCallsByName: createCounterMap(quoteCellRendererNames), + componentRenderCallsByName: createCounterMap(quoteComponentNames), +} + +export function recordCellRender(name: QuoteCellRendererName, value: T): T { + quoteRenderDiagnostics.cellRendererCalls++ + quoteRenderDiagnostics.cellRendererCallsByName[name]++ + return value +} + +interface PriceOptions { + selectSymbol: (symbol: string) => void +} +abstract class QuoteCell extends Component { + constructor(owner: Owner, args: object, name: QuoteComponentName) { + super(owner, args) + quoteCellLifecycle.created++ + registerDestructor(this, () => { + quoteCellLifecycle.destroyed++ + }) + } +} + +export class PriceCell extends QuoteCell< + CellRenderableSignature< + typeof tradingFeatures, + MarketQuote, + number, + PriceOptions + > +> { + constructor(owner: Owner, args: object) { + super(owner, args, 'PriceCell') + } + get quote() { + return this.args.ctx.row.original + } + select = () => { + this.args.options?.selectSymbol(this.quote.symbol) + } + +} + +abstract class MoveCellBase extends QuoteCell< + CellRenderableSignature +> { + get move() { + return ( + this.args.ctx.row.original.price - + this.args.ctx.row.original.previousClose + ) + } + get positive() { + return this.move >= 0 + } +} + +export class StableMoveCell extends MoveCellBase { + constructor(owner: Owner, args: object) { + super(owner, args, 'StableMoveCell') + } + +} + +export class UpMoveCell extends MoveCellBase { + constructor(owner: Owner, args: object) { + super(owner, args, 'UpMoveCell') + } + +} + +export class DownMoveCell extends MoveCellBase { + constructor(owner: Owner, args: object) { + super(owner, args, 'DownMoveCell') + } + +} + +export class PercentChangeCell extends QuoteCell< + CellRenderableSignature +> { + constructor(owner: Owner, args: object) { + super(owner, args, 'PercentChangeCell') + } + get value() { + const quote = this.args.ctx.row.original + return quote.previousClose === 0 + ? 0 + : ((quote.price - quote.previousClose) / quote.previousClose) * 100 + } + +} + +export class SparklineCell extends QuoteCell< + CellRenderableSignature +> { + constructor(owner: Owner, args: object) { + super(owner, args, 'SparklineCell') + } + get values() { + return this.args.ctx.row.original.history + } + get rising() { + return (this.values.at(-1) ?? 0) >= (this.values[0] ?? 0) + } + get points() { + const first = this.values[0] ?? 0 + const range = this.values.reduce( + (result, value) => ({ + min: Math.min(result.min, value), + max: Math.max(result.max, value), + }), + { min: first, max: first }, + ) + const scale = range.max - range.min || 1 + const denominator = Math.max(1, this.values.length - 1) + return this.values + .map((value, index) => { + const x = (index / denominator) * 100 + const y = 22 - ((value - range.min) / scale) * 20 + return `${x.toFixed(1)},${y.toFixed(1)}` + }) + .join(' ') + } + +} + +const fixed = (value: number): string => value.toFixed(2) +const signed = (value: number): string => + `${value >= 0 ? '+' : ''}${value.toFixed(2)}` +const percent = (value: number): string => + `${value >= 0 ? '+' : ''}${value.toFixed(2)}%` +const nonNegative = (value: number): boolean => value >= 0 +const isPositive = (quote: MarketQuote): boolean => + quote.price - quote.previousClose >= 0 +const recordComponent = (name: QuoteComponentName): string => { + quoteRenderDiagnostics.componentRenderCalls++ + quoteRenderDiagnostics.componentRenderCallsByName[name]++ + return '' +} diff --git a/examples/ember/realtime-trading/app/table/table-config/trading-columns.gts b/examples/ember/realtime-trading/app/table/table-config/trading-columns.gts new file mode 100644 index 0000000000..73e8fc6340 --- /dev/null +++ b/examples/ember/realtime-trading/app/table/table-config/trading-columns.gts @@ -0,0 +1,209 @@ +import { createColumnHelper, flexRenderComponent } from '@tanstack/ember-table' +import { + DownMoveCell, + PercentChangeCell, + PriceCell, + SparklineCell, + StableMoveCell, + UpMoveCell, + recordCellRender, +} from './quote-cells.gts' +import { tradingFeatures } from '../trading-features' +import type { MarketQuote } from '../../feed/market-data' +import type { TradingBenchmarkController } from '../../benchmark/trading-benchmark-controller' + +export type RendererMode = 'stable' | 'swap' +export interface CoreTableState { + sorting: Array<{ id: string; desc: boolean }> + columnFilters: Array<{ id: string; value: unknown }> +} + +const compact = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +const columnHelper = createColumnHelper() + +export function createTradingColumns( + controller: TradingBenchmarkController, + rendererMode: RendererMode, +) { + return columnHelper.columns([ + columnHelper.group({ + id: 'instrument', + header: 'Instrument', + columns: columnHelper.columns([ + columnHelper.accessor('venue', { + id: 'market', + header: 'Market', + size: 72, + cell: (info) => recordCellRender('Market', info.getValue()), + }), + columnHelper.accessor('company', { + id: 'name', + header: 'Name', + size: 180, + cell: (info) => recordCellRender('Name', info.getValue()), + }), + columnHelper.accessor('symbol', { + header: 'Symbol', + size: 92, + filterFn: 'includesString', + cell: (info) => recordCellRender('Symbol', info.getValue()), + }), + ]), + }), + columnHelper.group({ + id: 'priceAndChange', + header: 'Price & Change', + columns: columnHelper.columns([ + columnHelper.accessor('price', { + header: 'Price', + size: 96, + sortFn: 'basic', + cell: () => + recordCellRender( + 'Last', + flexRenderComponent(PriceCell, { + selectSymbol: controller.actions.selectSymbol, + }), + ), + }), + columnHelper.accessor(getDayChange, { + id: 'change', + header: 'Chg', + size: 94, + cell: (info) => + recordCellRender( + 'Change', + rendererMode === 'stable' + ? flexRenderComponent(StableMoveCell) + : info.getValue() >= 0 + ? flexRenderComponent(UpMoveCell) + : flexRenderComponent(DownMoveCell), + ), + }), + columnHelper.accessor(getDayChangePercent, { + id: 'changePercent', + header: 'Chg%', + size: 90, + cell: () => + recordCellRender( + 'ChangePercent', + flexRenderComponent(PercentChangeCell), + ), + }), + ]), + }), + columnHelper.group({ + id: 'orderBook', + header: 'Order Book', + columns: columnHelper.columns([ + columnHelper.accessor('bid', { + header: 'Bid', + size: 90, + cell: (info) => recordCellRender('Bid', info.getValue().toFixed(2)), + }), + columnHelper.accessor('bidSize', { + header: 'Bid Vol', + size: 100, + cell: (info) => + recordCellRender('BidVolume', compact.format(info.getValue())), + }), + columnHelper.accessor('ask', { + header: 'Ask', + size: 90, + cell: (info) => recordCellRender('Ask', info.getValue().toFixed(2)), + }), + columnHelper.accessor('askSize', { + header: 'Ask Vol', + size: 100, + cell: (info) => + recordCellRender('AskVolume', compact.format(info.getValue())), + }), + ]), + }), + columnHelper.group({ + id: 'session', + header: 'Session', + columns: columnHelper.columns([ + columnHelper.accessor('open', { + header: 'Open', + size: 90, + cell: (info) => recordCellRender('Open', info.getValue().toFixed(2)), + }), + columnHelper.accessor('high', { + header: 'High', + size: 90, + cell: (info) => recordCellRender('High', info.getValue().toFixed(2)), + }), + columnHelper.accessor('low', { + header: 'Low', + size: 90, + cell: (info) => recordCellRender('Low', info.getValue().toFixed(2)), + }), + ]), + }), + columnHelper.group({ + id: 'chart', + header: 'Chart', + columns: columnHelper.columns([ + columnHelper.accessor('history', { + header: 'Intraday', + size: 150, + enableSorting: false, + cell: () => + recordCellRender('Intraday', flexRenderComponent(SparklineCell)), + }), + ]), + }), + ]) +} + +export const rowModelDiagnostics = { + hasMeasurement: false, + calls: 0, + totalDurationMs: 0, + maxDurationMs: 0, + lastRowCount: 0, +} +export const TRADING_COLUMN_COUNT = 14 + +export function readMeasuredRows(readRows: () => Array): Array { + const start = performance.now() + const rows = readRows() + const end = performance.now() + const duration = end - start + rowModelDiagnostics.calls++ + rowModelDiagnostics.hasMeasurement = true + rowModelDiagnostics.totalDurationMs += duration + rowModelDiagnostics.maxDurationMs = Math.max( + rowModelDiagnostics.maxDurationMs, + duration, + ) + rowModelDiagnostics.lastRowCount = rows.length + if ((rowModelDiagnostics.calls - 1) % 20 !== 0) return rows + try { + performance.measure('tanstack-row-model', { + start, + end, + detail: { rowCount: rows.length }, + }) + if (rowModelDiagnostics.calls % 20_000 === 0) { + performance.clearMeasures('tanstack-row-model') + } + } catch { + /* optional User Timing detail */ + } + return rows +} + +export function getDayChange(quote: MarketQuote): number { + return quote.price - quote.previousClose +} + +export function getDayChangePercent(quote: MarketQuote): number { + return quote.previousClose === 0 + ? 0 + : (getDayChange(quote) / quote.previousClose) * 100 +} diff --git a/examples/ember/realtime-trading/app/table/table-interactions.ts b/examples/ember/realtime-trading/app/table/table-interactions.ts new file mode 100644 index 0000000000..a32e9d5963 --- /dev/null +++ b/examples/ember/realtime-trading/app/table/table-interactions.ts @@ -0,0 +1,189 @@ +export type CellDirection = 'up' | 'down' | 'left' | 'right' + +interface RowSelectionTable { + resetRowSelection: (defaultState?: boolean) => void +} + +interface SelectableRow { + getIsSelected: () => boolean + getToggleSelectedHandler: (options?: { + selectChildren?: boolean + }) => (event: unknown) => void +} + +interface SelectableGridCell { + row: SelectableGridRow + getSelectionStartHandler: ( + contextDocument?: Document, + ) => (event: unknown) => void + getSelectionExtendHandler: () => (event: unknown) => void +} + +interface SelectableGridRow extends SelectableRow { + original: { symbol: string } + getAllCellsByColumnId: () => Record +} + +interface TradingGridTable extends RowSelectionTable { + getRowModel: () => { + rowsById: Record + } +} + +interface SelectionCellTarget { + element: HTMLTableCellElement + cell: SelectableGridCell +} + +interface CellNavigationTable { + extendCellSelection: (direction: CellDirection) => void + moveCellSelection: (direction: CellDirection) => void + resetCellSelection: (defaultState?: boolean) => void + selectAllCells: () => void +} + +const keyDirections: Partial> = { + ArrowUp: 'up', + ArrowDown: 'down', + ArrowLeft: 'left', + ArrowRight: 'right', +} + +export function reorderColumnIds( + columnIds: Array, + sourceId: string, + targetId: string, +): Array { + if (sourceId === targetId || !columnIds.includes(sourceId)) return columnIds + + const withoutSource = columnIds.filter((id) => id !== sourceId) + const targetIndex = withoutSource.indexOf(targetId) + if (targetIndex < 0) return columnIds + + return [ + ...withoutSource.slice(0, targetIndex), + sourceId, + ...withoutSource.slice(targetIndex), + ] +} + +export function selectRowFromPointer( + table: RowSelectionTable, + row: SelectableRow, + event: MouseEvent, +): void { + const additive = event.ctrlKey || event.metaKey + const checked = additive ? !row.getIsSelected() : true + + if (!event.shiftKey && !additive) table.resetRowSelection(true) + + row.getToggleSelectedHandler({ selectChildren: false })({ + target: { checked }, + shiftKey: event.shiftKey, + ctrlKey: event.ctrlKey, + metaKey: event.metaKey, + }) +} + +export class TradingGridPointerController { + #lastPointerCell: HTMLTableCellElement | null = null + + handleMouseDown( + table: TradingGridTable, + event: MouseEvent, + selectSymbol: (symbol: string) => void, + ): void { + if (event.button !== 0) return + + const target = this.#findCellTarget(table, event.composedPath()) + if (!target) return + + event.preventDefault() + this.#lastPointerCell = target.element + selectSymbol(target.cell.row.original.symbol) + target.cell.getSelectionStartHandler(target.element.ownerDocument)(event) + } + + handlePointerOver(table: TradingGridTable, event: MouseEvent): void { + if ((event.buttons & 1) === 0) { + this.resetPointerCell() + return + } + + const target = this.#findCellTarget(table, event.composedPath()) + if (!target || target.element === this.#lastPointerCell) return + + this.#lastPointerCell = target.element + target.cell.getSelectionExtendHandler()(event) + } + + handleClick(table: TradingGridTable, event: MouseEvent): void { + const target = this.#findCellTarget(table, event.composedPath()) + if (!target) return + selectRowFromPointer(table, target.cell.row, event) + } + + resetPointerCell(): void { + this.#lastPointerCell = null + } + + #findCellTarget( + table: TradingGridTable, + path: Array, + ): SelectionCellTarget | null { + for (const target of path) { + if (!(target instanceof HTMLTableCellElement)) continue + + const columnId = target.dataset['columnId'] + const rowId = + target.closest('tr[data-row-id]')?.dataset['rowId'] + if (!columnId || !rowId) return null + + const row = table.getRowModel().rowsById[rowId] + if (!row) return null + const cell = row.getAllCellsByColumnId()[columnId] + if (!cell) return null + return { element: target, cell } + } + + return null + } +} + +export function handleCellNavigation( + table: CellNavigationTable, + event: KeyboardEvent, +): void { + if (event.key === 'Escape') { + event.preventDefault() + table.resetCellSelection(true) + return + } + + if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'a') { + event.preventDefault() + table.selectAllCells() + return + } + + const direction = keyDirections[event.key] + if (!direction) return + + event.preventDefault() + if (event.shiftKey) table.extendCellSelection(direction) + else table.moveCellSelection(direction) +} + +export function sortIndicator(direction: false | 'asc' | 'desc'): string { + if (direction === 'asc') return '↑' + if (direction === 'desc') return '↓' + return '↕' +} + +export function sortAriaValue( + direction: false | 'asc' | 'desc', +): 'ascending' | 'descending' | 'none' { + if (direction === 'asc') return 'ascending' + if (direction === 'desc') return 'descending' + return 'none' +} diff --git a/examples/ember/realtime-trading/app/table/trading-features.ts b/examples/ember/realtime-trading/app/table/trading-features.ts new file mode 100644 index 0000000000..7d0a780dda --- /dev/null +++ b/examples/ember/realtime-trading/app/table/trading-features.ts @@ -0,0 +1,16 @@ +import { + createFilteredRowModel, + createSortedRowModel, + filterFn_includesString, + sortFn_basic, + stockFeatures, + tableFeatures, +} from '@tanstack/ember-table' + +export const tradingFeatures = tableFeatures({ + ...stockFeatures, + filteredRowModel: createFilteredRowModel(), + sortedRowModel: createSortedRowModel(), + filterFns: { includesString: filterFn_includesString }, + sortFns: { basic: sortFn_basic }, +}) diff --git a/examples/ember/realtime-trading/app/table/trading-table.ts b/examples/ember/realtime-trading/app/table/trading-table.ts new file mode 100644 index 0000000000..6e1059f144 --- /dev/null +++ b/examples/ember/realtime-trading/app/table/trading-table.ts @@ -0,0 +1,8 @@ +export { + TRADING_COLUMN_COUNT, + rowModelDiagnostics, +} from './table-config/trading-columns.gts' +export type { + CoreTableState, + RendererMode, +} from './table-config/trading-columns.gts' diff --git a/examples/ember/realtime-trading/app/templates/application.gts b/examples/ember/realtime-trading/app/templates/application.gts new file mode 100644 index 0000000000..695fb27818 --- /dev/null +++ b/examples/ember/realtime-trading/app/templates/application.gts @@ -0,0 +1,25 @@ +import Component from '@glimmer/component' +import { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' +import { MarketFeedController } from '../feed/market-feed-controller' +import TradingShell from '../components/shell/trading-shell.gts' +import { registerCleanup } from '../utils/subscriptions' +import type Owner from '@ember/owner' + +export default class Application extends Component { + readonly feed = new MarketFeedController() + readonly controller = new TradingBenchmarkController(this.feed) + + constructor(owner: Owner, args: object) { + super(owner, args) + const stopFeed = this.feed.start() + const stopBenchmark = this.controller.start() + registerCleanup(this, () => { + stopBenchmark() + stopFeed() + }) + } + + +} diff --git a/examples/ember/realtime-trading/app/utils/subscriptions.ts b/examples/ember/realtime-trading/app/utils/subscriptions.ts new file mode 100644 index 0000000000..7d6ea1eaeb --- /dev/null +++ b/examples/ember/realtime-trading/app/utils/subscriptions.ts @@ -0,0 +1,5 @@ +import { registerDestructor } from '@ember/destroyable' + +export function registerCleanup(owner: object, cleanup: () => void): void { + registerDestructor(owner, cleanup) +} diff --git a/examples/ember/realtime-trading/babel.config.js b/examples/ember/realtime-trading/babel.config.js new file mode 100644 index 0000000000..10915e4299 --- /dev/null +++ b/examples/ember/realtime-trading/babel.config.js @@ -0,0 +1,49 @@ +import { buildMacros } from '@embroider/macros/babel' + +const macros = buildMacros({ + configure(config) { + if (process.env.EMBER_ENV === 'test') { + config.enableRuntimeMode() + } + }, +}) + +export default { + plugins: [ + [ + '@babel/plugin-transform-typescript', + { + allExtensions: true, + onlyRemoveTypeImports: true, + allowDeclareFields: true, + }, + ], + [ + 'babel-plugin-ember-template-compilation', + { + transforms: [...macros.templateMacros], + }, + ], + [ + 'module:decorator-transforms', + { + runtime: { + import: import.meta.resolve('decorator-transforms/runtime-esm'), + }, + }, + ], + [ + '@babel/plugin-transform-runtime', + { + absoluteRuntime: import.meta.dirname, + useESModules: true, + regenerator: false, + }, + ], + ...macros.babelMacros, + ], + + generatorOpts: { + compact: false, + }, +} diff --git a/examples/ember/realtime-trading/index.html b/examples/ember/realtime-trading/index.html new file mode 100644 index 0000000000..b9dbf7e836 --- /dev/null +++ b/examples/ember/realtime-trading/index.html @@ -0,0 +1,17 @@ + + + + + Minimal App + + + + + + + diff --git a/examples/ember/realtime-trading/package.json b/examples/ember/realtime-trading/package.json new file mode 100644 index 0000000000..1c6e77daad --- /dev/null +++ b/examples/ember/realtime-trading/package.json @@ -0,0 +1,59 @@ +{ + "name": "tanstack-ember-table-example-realtime-trading", + "private": true, + "type": "module", + "imports": { + "#app/*": "./app/*", + "#config": "./app/config.ts", + "#components/*": "./app/components/*", + "#services/*": "./app/services/*", + "#test-helpers/*": "./tests/helpers/*", + "#utils/*": "./app/utils/*" + }, + "exports": { + "./tests/*": "./tests/*", + "./*": "./app/*" + }, + "scripts": { + "dev": "vite", + "build": "vite build", + "serve": "vite preview", + "start": "vite", + "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts", + "test:types": "ember-tsc --noEmit" + }, + "dependencies": { + "@embroider/macros": "1.20.6", + "@embroider/router": "3.0.6", + "@glimmer/component": "2.1.1", + "@tanstack/ember-table": "^9.2.3", + "@tanstack/store": "^0.11.1", + "decorator-transforms": "2.4.0", + "ember-modifier": "^4.3.0", + "ember-source": "7.2.0", + "ember-strict-application-resolver": "0.1.1" + }, + "devDependencies": { + "@babel/core": "7.29.7", + "@babel/plugin-transform-runtime": "7.29.7", + "@babel/plugin-transform-typescript": "7.29.7", + "@babel/runtime": "7.29.7", + "@ember/app-tsconfig": "2.0.0", + "@embroider/core": "4.6.3", + "@glint/ember-tsc": "1.11.0", + "@glint/template": "1.8.0", + "@glint/tsserver-plugin": "2.7.3", + "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", + "@rollup/plugin-babel": "7.1.0", + "babel-plugin-ember-template-compilation": "4.0.0", + "typescript": "6.0.3", + "vite": "^8.2.2" + }, + "engines": { + "node": ">= 24" + }, + "ember": { + "edition": "octane" + } +} diff --git a/examples/ember/realtime-trading/tests/e2e/smoke.spec.ts b/examples/ember/realtime-trading/tests/e2e/smoke.spec.ts new file mode 100644 index 0000000000..a3e2f967b2 --- /dev/null +++ b/examples/ember/realtime-trading/tests/e2e/smoke.spec.ts @@ -0,0 +1,59 @@ +import path from 'node:path' +import { expect, test } from '@playwright/test' +import { startExampleServer } from '../../../../../tests/e2e/helpers/startExampleServer' +import { pausedFeedUrl } from '../../../../../tests/e2e/helpers/setRangeValue' +import type { Page } from '@playwright/test' + +const exampleDir = path.resolve() + +let server: Awaited> + +function collectPageErrors(page: Page) { + const errors: Array = [] + page.on('pageerror', (error) => errors.push(error.message)) + page.on('console', (message) => { + if (message.type() === 'error') errors.push(message.text()) + }) + return errors +} + +test.beforeAll(async () => { + test.setTimeout(120_000) + server = await startExampleServer(exampleDir) + await fetch(pausedFeedUrl(server.url)) +}) + +test.afterAll(async () => { + await server.close() +}) + +test('loads the Ember realtime trading table', async ({ page }) => { + test.setTimeout(60_000) + const errors = collectPageErrors(page) + + await page.goto(pausedFeedUrl(server.url)) + + const table = page.getByTestId('trading-table') + await expect(table).toBeVisible() + await expect(page.locator('.brand')).toHaveText('MARKET MONITOR') + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(table.locator('thead tr')).toHaveCount(2) + await expect(table.locator('thead tr').last().locator('th')).toHaveCount(14) + await expect(table.locator('thead')).toContainText('Market') + await expect(table.locator('thead')).toContainText('Bid Vol') + await expect(table.locator('thead')).toContainText('Intraday') + + const selectedRow = table.locator('tbody tr').first() + const selectedSymbol = await selectedRow.getAttribute('data-symbol') + await selectedRow.locator('td').nth(1).click() + await expect(page.getByTestId('selected-instrument')).toContainText( + selectedSymbol ?? '', + ) + + expect( + await page.evaluate( + () => performance.getEntriesByName('tanstack-row-model').length > 0, + ), + ).toBe(true) + expect(errors).toEqual([]) +}) diff --git a/examples/ember/realtime-trading/tsconfig.json b/examples/ember/realtime-trading/tsconfig.json new file mode 100644 index 0000000000..c4f982dc22 --- /dev/null +++ b/examples/ember/realtime-trading/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@ember/app-tsconfig", + "compilerOptions": { + "allowJs": true, + "lib": ["ES2025", "DOM", "DOM.Iterable"], + "types": [ + "ember-source/types", + "@embroider/core/virtual", + "vite/client", + "@glint/ember-tsc/types" + ] + } +} diff --git a/examples/ember/realtime-trading/vite.config.mjs b/examples/ember/realtime-trading/vite.config.mjs new file mode 100644 index 0000000000..0f024aaa3b --- /dev/null +++ b/examples/ember/realtime-trading/vite.config.mjs @@ -0,0 +1,10 @@ +import { defineConfig } from 'vite' +import { ember } from '@nullvoxpopuli/ember-vite' + +export default defineConfig({ + server: { + port: 7777, + allowedHosts: true, + }, + plugins: [ember()], +}) diff --git a/examples/ember/remote-data/package.json b/examples/ember/remote-data/package.json index d8419696e8..712eeb4046 100644 --- a/examples/ember/remote-data/package.json +++ b/examples/ember/remote-data/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/row-dnd/package.json b/examples/ember/row-dnd/package.json index ac746c9702..e5efc2daed 100644 --- a/examples/ember/row-dnd/package.json +++ b/examples/ember/row-dnd/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/row-pinning/package.json b/examples/ember/row-pinning/package.json index 1ce2c73f97..a3a06ae7a8 100644 --- a/examples/ember/row-pinning/package.json +++ b/examples/ember/row-pinning/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/row-selection/package.json b/examples/ember/row-selection/package.json index 3ce8c081f0..a1ea137631 100644 --- a/examples/ember/row-selection/package.json +++ b/examples/ember/row-selection/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/sorting/package.json b/examples/ember/sorting/package.json index 52c5c05de6..3d8a2f8618 100644 --- a/examples/ember/sorting/package.json +++ b/examples/ember/sorting/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/ember/sub-components/package.json b/examples/ember/sub-components/package.json index 83852f213f..f9c38f333d 100644 --- a/examples/ember/sub-components/package.json +++ b/examples/ember/sub-components/package.json @@ -25,7 +25,7 @@ "dependencies": { "@embroider/macros": "1.20.6", "@embroider/router": "3.0.6", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@glimmer/component": "2.1.1", "@tanstack/ember-table": "^9.2.3", "decorator-transforms": "2.4.0", @@ -39,14 +39,15 @@ "@babel/runtime": "7.29.7", "@ember/app-tsconfig": "2.0.0", "@embroider/core": "4.6.3", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@nullvoxpopuli/ember-vite": "1.1.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-babel": "7.1.0", "babel-plugin-ember-template-compilation": "4.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "engines": { "node": ">= 24" diff --git a/examples/lit/aggregation/package.json b/examples/lit/aggregation/package.json index 4a4ca20bbf..ff2155292e 100644 --- a/examples/lit/aggregation/package.json +++ b/examples/lit/aggregation/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/basic-app-table/package.json b/examples/lit/basic-app-table/package.json index 6589a02b40..4aea724431 100644 --- a/examples/lit/basic-app-table/package.json +++ b/examples/lit/basic-app-table/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@lit/context": "^1.1.6", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/basic-dynamic-columns/package.json b/examples/lit/basic-dynamic-columns/package.json index bd4fa838b8..f8306d4d8b 100644 --- a/examples/lit/basic-dynamic-columns/package.json +++ b/examples/lit/basic-dynamic-columns/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/basic-external-atoms/package.json b/examples/lit/basic-external-atoms/package.json index a3d742991a..cf705119dc 100644 --- a/examples/lit/basic-external-atoms/package.json +++ b/examples/lit/basic-external-atoms/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "@tanstack/store": "^0.11.1", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/basic-external-state/package.json b/examples/lit/basic-external-state/package.json index 4ffa8d0ec2..5d33d030d2 100644 --- a/examples/lit/basic-external-state/package.json +++ b/examples/lit/basic-external-state/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/basic-subscribe/package.json b/examples/lit/basic-subscribe/package.json index 29a6d4243b..2cad717e5c 100644 --- a/examples/lit/basic-subscribe/package.json +++ b/examples/lit/basic-subscribe/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-store": "^0.14.1", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/basic-table-controller/package.json b/examples/lit/basic-table-controller/package.json index 266b983d05..938ed28852 100644 --- a/examples/lit/basic-table-controller/package.json +++ b/examples/lit/basic-table-controller/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/cell-selection/package.json b/examples/lit/cell-selection/package.json index e5d4a24b93..f592a5e355 100644 --- a/examples/lit/cell-selection/package.json +++ b/examples/lit/cell-selection/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-hotkeys": "^0.11.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/cell-spanning/package.json b/examples/lit/cell-spanning/package.json index 6f4406ce0c..6c8e54f95d 100644 --- a/examples/lit/cell-spanning/package.json +++ b/examples/lit/cell-spanning/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/column-ordering/package.json b/examples/lit/column-ordering/package.json index e144c97462..d45e5c0fcd 100644 --- a/examples/lit/column-ordering/package.json +++ b/examples/lit/column-ordering/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/column-pinning-split/package.json b/examples/lit/column-pinning-split/package.json index 38150168f0..3342d67063 100644 --- a/examples/lit/column-pinning-split/package.json +++ b/examples/lit/column-pinning-split/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/column-pinning-sticky/package.json b/examples/lit/column-pinning-sticky/package.json index ce94a7f49a..d5568051ea 100644 --- a/examples/lit/column-pinning-sticky/package.json +++ b/examples/lit/column-pinning-sticky/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/column-pinning/package.json b/examples/lit/column-pinning/package.json index fb1dfa4f61..7aa62c5698 100644 --- a/examples/lit/column-pinning/package.json +++ b/examples/lit/column-pinning/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/column-resizing-performant/package.json b/examples/lit/column-resizing-performant/package.json index df18fab50a..26ec2efef7 100644 --- a/examples/lit/column-resizing-performant/package.json +++ b/examples/lit/column-resizing-performant/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/column-resizing/package.json b/examples/lit/column-resizing/package.json index 7f01118f23..860fa3d447 100644 --- a/examples/lit/column-resizing/package.json +++ b/examples/lit/column-resizing/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/column-sizing/package.json b/examples/lit/column-sizing/package.json index 8e86c018bc..196bff843a 100644 --- a/examples/lit/column-sizing/package.json +++ b/examples/lit/column-sizing/package.json @@ -11,13 +11,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/column-visibility/package.json b/examples/lit/column-visibility/package.json index 8f1203f127..d428274211 100644 --- a/examples/lit/column-visibility/package.json +++ b/examples/lit/column-visibility/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/composable-tables/package.json b/examples/lit/composable-tables/package.json index bb2449ff38..babc24b54a 100644 --- a/examples/lit/composable-tables/package.json +++ b/examples/lit/composable-tables/package.json @@ -12,14 +12,15 @@ "lint": "eslint ./src" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@lit/context": "^1.1.6", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/expanding/package.json b/examples/lit/expanding/package.json index 2b4a2b777c..914f7730ba 100644 --- a/examples/lit/expanding/package.json +++ b/examples/lit/expanding/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/filters-faceted-bucketed/package.json b/examples/lit/filters-faceted-bucketed/package.json index e983587efd..c5d178c8f7 100644 --- a/examples/lit/filters-faceted-bucketed/package.json +++ b/examples/lit/filters-faceted-bucketed/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/filters-faceted/package.json b/examples/lit/filters-faceted/package.json index 40ed429152..4d7aee9c19 100644 --- a/examples/lit/filters-faceted/package.json +++ b/examples/lit/filters-faceted/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/filters-fuzzy/package.json b/examples/lit/filters-fuzzy/package.json index a95e8e0783..87aecd7474 100644 --- a/examples/lit/filters-fuzzy/package.json +++ b/examples/lit/filters-fuzzy/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "@tanstack/match-sorter-utils": "^9.1.2", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/filters/package.json b/examples/lit/filters/package.json index 876ee20bdc..b94c00e02c 100644 --- a/examples/lit/filters/package.json +++ b/examples/lit/filters/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/grouped-aggregation/package.json b/examples/lit/grouped-aggregation/package.json index a2093becc9..5f51ef5ecc 100644 --- a/examples/lit/grouped-aggregation/package.json +++ b/examples/lit/grouped-aggregation/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/grouping/package.json b/examples/lit/grouping/package.json index f3740427ee..dec9a40eba 100644 --- a/examples/lit/grouping/package.json +++ b/examples/lit/grouping/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/header-groups/package.json b/examples/lit/header-groups/package.json index 818e27961a..3e11527e83 100644 --- a/examples/lit/header-groups/package.json +++ b/examples/lit/header-groups/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/kitchen-sink/package.json b/examples/lit/kitchen-sink/package.json index db09e05e5f..33285afe23 100644 --- a/examples/lit/kitchen-sink/package.json +++ b/examples/lit/kitchen-sink/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "@tanstack/match-sorter-utils": "^9.1.2", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/pagination/package.json b/examples/lit/pagination/package.json index 7bc26dca0e..0176b9bbf1 100644 --- a/examples/lit/pagination/package.json +++ b/examples/lit/pagination/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/realtime-trading/.gitignore b/examples/lit/realtime-trading/.gitignore new file mode 100644 index 0000000000..1502ec233f --- /dev/null +++ b/examples/lit/realtime-trading/.gitignore @@ -0,0 +1,3 @@ +dist +node_modules + diff --git a/examples/lit/realtime-trading/README.md b/examples/lit/realtime-trading/README.md new file mode 100644 index 0000000000..4ff29124a5 --- /dev/null +++ b/examples/lit/realtime-trading/README.md @@ -0,0 +1,147 @@ +# Lit realtime trading benchmark + +This standalone example exercises the current TanStack Lit Table adapter with +a high-frequency worker feed, immutable snapshots, interactive columns, custom +elements for quote cells, Lit Virtual, and browser diagnostics. It is a +repeatable rendering workload, not an exchange or network benchmark. + +## Run and verify + +```bash +pnpm --dir examples/lit/realtime-trading dev +``` + +Open `http://localhost:7777`. + +```bash +pnpm --dir examples/lit/realtime-trading test:types +pnpm --dir examples/lit/realtime-trading lint +pnpm --dir examples/lit/realtime-trading build +pnpm --dir examples/lit/realtime-trading test:e2e +``` + +Use the production build for measurements. + +## Structure and ownership + +| Path | Responsibility | +| --------------------------------- | ------------------------------------------------------------------------------------------------------ | +| `src/feed/` | Market types, instruments, configuration, immutable updates, and direct TanStack atom feed controller. | +| `src/feed/worker/` | Protocol, deterministic engine, and module worker. | +| `src/benchmark/` | Browser monitor, benchmark controller, table timing, and row-model diagnostics. | +| `src/shell/` | Custom elements for header, metrics, controls, diagnostics, selected instrument, status, and layout. | +| `src/shell/controller-element.ts` | Base element that subscribes to controller sources and releases subscriptions on disconnect. | +| `src/table/table-config/` | Grouped columns and custom quote cell elements. | +| `src/table/` | Lit Table element, delegated interactions, column layout, and Lit Virtual integration. | +| `src/main.ts` | Root custom element that creates, starts, stops, and passes the controllers. | + +The feed controller is independent from the benchmark controller. The root +passes stable controller objects; each shell/table custom element observes the +specific atom/store sources it consumes. Quotes and every feed control/status +value are independent direct atoms; the table observes only `quotes` and +`instrumentCount`. `ControllerElement` converts those +notifications into `requestUpdate()` and guarantees unsubscribe on disconnect, +avoiding one broad application-level subscription. + +## Feed and worker pipeline + +Defaults are 100 instruments, 10K generated samples/s, 20 ms delivery, enabled +intraday charts, and 16 ms chart sampling. + +Mutable market state stays inside the worker. A deterministic 16 ms budget loop +generates samples, a row-indexed `Map` coalesces repeated instrument changes, +and an independent timer publishes the latest unique rows. The main thread +creates a new outer array and only new changed rows; untouched rows and +unsampled histories retain identity. Session IDs reject obsolete batches after +reset or instrument-count changes. + +- **Synthetic quote workload** is worker-generated samples/s, not custom-element + updates or messages. +- **Worker delivery interval** controls coalesced `postMessage` cadence; 20 ms + targets about 50 messages/s. +- **Row updates** is the count of unique immutable rows applied. +- **Message samples** is generated work represented by the latest batch. + +Intraday sampling is independent. The 25K burst deliberately publishes one +heavy batch. Worker messaging resembles an upstream stream without including +network latency. + +## Lit table architecture + +The 14 leaf columns are grouped into Instrument, Price & Change, Order Book, +Session, and Chart. The grid supports sorting/filtering, on-change resizing, +double-click reset, drag column ordering, CSS hover, row selection, drag cell +ranges, keyboard navigation, and Price/Move/Percent/Sparkline custom elements. + +Stable instrument IDs define row identity. One body-level interaction +controller resolves cells from `event.composedPath()` and data attributes, +avoiding handlers on every cell. Column widths are CSS variables written only +when sizing/order changes; a `ResizeObserver` performs initial fitting until a +manual resize. The A/B move option is intentionally a custom-element lifecycle +stress path. + +## Virtualization + +- Below 200 rows, automatic mode uses Full DOM, with Virtual still selectable. +- From 200 through 1,499 rows, automatic mode uses TanStack Virtual, with Full + DOM still selectable. +- At 1,500 rows or more, Virtual is forced and its control is disabled. + +Lit Virtual uses a 32 px estimate, 10-row overscan, stable row IDs, transformed +rows, and a spacer body. The footer derives the visible interval from the +virtualizer. Both modes apply `content-visibility: auto`; Full DOM still creates +all elements even when the browser skips some offscreen layout/paint. + +## Performance decisions + +- worker-side generation and coalescing; +- structural sharing for unchanged rows/history arrays; +- source-specific atom/store subscriptions in custom elements; +- stable keyed row/virtual identity; +- lifecycle-safe controller element subscriptions; +- delegated pointer input and CSS hover; +- CSS variables for width propagation; +- independently configurable chart/component stress; +- virtual mounting at larger sizes; +- metrics published below feed frequency. + +A new outer array is required by the immutable contract. Stable row references +help rendering, but sorting/filtering may still recompute the row model when +data changes. + +## Diagnostics and interpretation + +The sidebar keeps four cross-framework health signals prominent: estimated +frame callbacks, average snapshot-to-DOM-commit latency, cumulative long +animation frames, and changed-row/snapshot throughput. The remaining counters +stay in Diagnostics so they do not look like equally important scores. + +`AVG COMMIT` is not the duration of `render()` and it does not include the +browser's later layout or paint. It starts when a new immutable snapshot is +applied and ends in a guarded microtask queued from `updated()`. That extra +microtask lets nested quote-cell custom elements finish their Lit updates +before the sample closes. The average uses a rolling 3-second window; diagnostic +p95/max use 10 seconds. The frame-rate estimate counts standard +`requestAnimationFrame` callbacks over one second. It is refresh-rate dependent +and is not a GPU/compositor FPS measurement. + +Callback counts and DOM mutations describe different layers. +`Observed MutationRecords/s` is the number delivered by a `MutationObserver` +on the table body, not the number of browser DOM operations. The observer tracks +text, child-list, class, and style changes; it excludes selection data +attributes to reduce noise. Registering an observer still adds work at very high +mutation rates, so confirm close results with a Performance recording without +treating this counter as a score. Heap is Chrome-only, current and GC-sensitive; +growth is not a leak without post-GC retention. React Scan is not part of these +shared measurements. User Timing commit and row-model entries are sampled once +every 20 candidates; the numeric counters remain exact, while the Performance +timeline avoids one retained entry per hot-path execution. + +## Standalone policy + +All instruments, feed, worker, benchmark, shell, styles, and table code live in +this folder intentionally. It runs independently and can be copied to +StackBlitz, so shared implementation and README text are duplicated by design. + +The workspace resolves the pinned `@tanstack/lit-table` dependency to the local +adapter package while keeping the manifest release-like. diff --git a/examples/lit/realtime-trading/index.html b/examples/lit/realtime-trading/index.html new file mode 100644 index 0000000000..25afac7a22 --- /dev/null +++ b/examples/lit/realtime-trading/index.html @@ -0,0 +1,12 @@ + + + + + + TanStack Lit Table · Realtime Trading + + + + + + diff --git a/examples/lit/realtime-trading/package.json b/examples/lit/realtime-trading/package.json new file mode 100644 index 0000000000..95de486b7a --- /dev/null +++ b/examples/lit/realtime-trading/package.json @@ -0,0 +1,25 @@ +{ + "name": "tanstack-lit-table-example-realtime-trading", + "private": true, + "type": "module", + "scripts": { + "start": "vite", + "dev": "vite", + "build": "vite build", + "serve": "vite preview", + "lint": "eslint ./src", + "test:types": "tsc --noEmit", + "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" + }, + "dependencies": { + "@tanstack/lit-table": "^9.2.3", + "@tanstack/lit-virtual": "^3.13.37", + "@tanstack/store": "^0.11.1", + "lit": "^3.3.3" + }, + "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", + "typescript": "6.0.3", + "vite": "^8.2.2" + } +} diff --git a/examples/lit/realtime-trading/src/benchmark/benchmark-monitor.ts b/examples/lit/realtime-trading/src/benchmark/benchmark-monitor.ts new file mode 100644 index 0000000000..1bf9cdbc8c --- /dev/null +++ b/examples/lit/realtime-trading/src/benchmark/benchmark-monitor.ts @@ -0,0 +1,436 @@ +import { + quoteCellLifecycle, + quoteRenderDiagnostics, +} from '../table/table-config/quote-cells' +import { rowModelDiagnostics } from '../table/trading-table' + +export interface NamedInvocationRate { + name: string + callsPerSecond: number +} + +interface TimedLatencySample { + recordedAt: number + duration: number +} + +const averageLatencyWindowMs = 3_000 +const percentileLatencyWindowMs = 10_000 +const frameRateWindowMs = 1_000 + +export interface FeedMetrics { + actualTicksPerSecond: number + rowUpdatesPerSecond: number + workerMessagesPerSecond: number + stateApplicationsPerSecond: number + supersededUpdatesPerSecond: number + totalTicks: number + rafCallbacksPerSecond: number + tableCommitsPerSecond: number + lastBatchSize: number + averageCommitLatencyMs: number + p95CommitLatencyMs: number + maxCommitLatencyMs: number + slowCommits: number + longAnimationFrames: number + worstLongAnimationFrameMs: number + heapMb: number | null + componentsCreated: number + componentsDestroyed: number + workerMessages: number + lastUpdateCount: number + cellRendererCallsPerSecond: number + componentRenderCallsPerSecond: number + cellRendererRates: ReadonlyArray + componentRenderRates: ReadonlyArray + domMutationsPerSecond: number + rowModelCallsPerSecond: number + rowModelAverageMs: number + rowModelMaxMs: number + visibleRows: number +} + +export const initialMetrics: FeedMetrics = { + actualTicksPerSecond: 0, + rowUpdatesPerSecond: 0, + workerMessagesPerSecond: 0, + stateApplicationsPerSecond: 0, + supersededUpdatesPerSecond: 0, + totalTicks: 0, + rafCallbacksPerSecond: 0, + tableCommitsPerSecond: 0, + lastBatchSize: 0, + averageCommitLatencyMs: 0, + p95CommitLatencyMs: 0, + maxCommitLatencyMs: 0, + slowCommits: 0, + longAnimationFrames: 0, + worstLongAnimationFrameMs: 0, + heapMb: null, + componentsCreated: 0, + componentsDestroyed: 0, + workerMessages: 0, + lastUpdateCount: 0, + cellRendererCallsPerSecond: 0, + componentRenderCallsPerSecond: 0, + cellRendererRates: [], + componentRenderRates: [], + domMutationsPerSecond: 0, + rowModelCallsPerSecond: 0, + rowModelAverageMs: 0, + rowModelMaxMs: 0, + visibleRows: 0, +} + +const userTiming = { entryCount: 0, measureCandidateCount: 0 } +const userTimingSamplingInterval = 20 + +export function recordMeasure( + name: string, + start: number, + end: number, + detail: Record, +): void { + userTiming.measureCandidateCount++ + if (userTiming.measureCandidateCount % userTimingSamplingInterval !== 0) + return + try { + performance.measure(name, { start, end, detail }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMeasures('market-update-to-dom-commit') + } + } catch { + // User Timing Level 3 options are not implemented in every browser. + } +} + +export function markBenchmarkAction( + name: string, + detail: Record = {}, +): void { + try { + performance.mark(`benchmark:${name}`, { detail }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMarks() + } + } catch { + // User Timing Level 3 detail is not implemented in every browser. + } +} + +export class BenchmarkMonitor { + readonly #runtime = { + sampleStartedAt: performance.now(), + sessionStartedAt: performance.now(), + pendingMutationStartedAt: null as number | null, + commitLatencySamples: [] as Array, + slowCommitCount: 0, + totalTicks: 0, + ticksInSample: 0, + rowUpdatesInSample: 0, + workerMessagesInSample: 0, + stateApplicationsInSample: 0, + supersededUpdatesInSample: 0, + lastBatchSize: 0, + lastUpdateCount: 0, + workerMessages: 0, + frameTrackingStartedAt: performance.now(), + frameTimestamps: [] as Array, + tableCommitsInSample: 0, + longAnimationFrameCount: 0, + worstLongAnimationFrameMs: 0, + previousCellRendererCalls: 0, + previousComponentRenderCalls: 0, + previousCellRendererCallsByName: { + ...quoteRenderDiagnostics.cellRendererCallsByName, + }, + previousComponentRenderCallsByName: { + ...quoteRenderDiagnostics.componentRenderCallsByName, + }, + domMutationsInSample: 0, + previousRowModelCalls: 0, + previousRowModelDuration: 0, + } + + markCommitPending(): void { + this.#runtime.pendingMutationStartedAt ??= performance.now() + } + + recordDomCommit(): void { + const runtime = this.#runtime + if (runtime.pendingMutationStartedAt !== null) { + const commitEndedAt = performance.now() + const duration = commitEndedAt - runtime.pendingMutationStartedAt + runtime.commitLatencySamples.push({ + recordedAt: commitEndedAt, + duration, + }) + if (duration > 16.7) runtime.slowCommitCount++ + recordMeasure( + 'market-update-to-dom-commit', + runtime.pendingMutationStartedAt, + commitEndedAt, + {}, + ) + runtime.pendingMutationStartedAt = null + runtime.tableCommitsInSample++ + } + } + + recordWorkerMessage(): void { + this.#runtime.workerMessages++ + this.#runtime.workerMessagesInSample++ + } + + recordBatch( + tickCount: number, + updateCount: number, + supersededUpdateCount: number, + ): void { + const runtime = this.#runtime + runtime.lastBatchSize = tickCount + runtime.lastUpdateCount = updateCount + runtime.ticksInSample += tickCount + runtime.totalTicks += tickCount + runtime.rowUpdatesInSample += updateCount + runtime.stateApplicationsInSample++ + runtime.supersededUpdatesInSample += supersededUpdateCount + } + + recordAnimationFrame(now: number): void { + const timestamps = this.#runtime.frameTimestamps + timestamps.push(now) + pruneFrameTimestamps(timestamps, now) + } + + recordLongAnimationFrame(duration: number, startTime: number): void { + const runtime = this.#runtime + if (startTime < runtime.sessionStartedAt) return + runtime.longAnimationFrameCount++ + runtime.worstLongAnimationFrameMs = Math.max( + runtime.worstLongAnimationFrameMs, + duration, + ) + } + + recordDomMutations(count: number): void { + this.#runtime.domMutationsInSample += count + } + + resetDomMutations(): void { + this.#runtime.domMutationsInSample = 0 + } + + shouldPublish(now: number): boolean { + return now - this.#runtime.sampleStartedAt >= 500 + } + + publish(now: number): FeedMetrics { + const runtime = this.#runtime + const sampleDuration = now - runtime.sampleStartedAt + pruneLatencySamples(runtime.commitLatencySamples, now) + pruneFrameTimestamps(runtime.frameTimestamps, now) + const averageCommitLatencySamples = runtime.commitLatencySamples + .filter((sample) => sample.recordedAt >= now - averageLatencyWindowMs) + .map((sample) => sample.duration) + const percentileCommitLatencySamples = runtime.commitLatencySamples.map( + (sample) => sample.duration, + ) + const sortedCommitLatencySamples = [...percentileCommitLatencySamples].sort( + (left, right) => left - right, + ) + const rowModelCalls = + rowModelDiagnostics.calls - runtime.previousRowModelCalls + const rowModelDuration = + rowModelDiagnostics.totalDurationMs - runtime.previousRowModelDuration + const cellRendererCalls = + quoteRenderDiagnostics.cellRendererCalls - + runtime.previousCellRendererCalls + const componentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls - + runtime.previousComponentRenderCalls + const cellRendererRates = calculateInvocationRates( + quoteRenderDiagnostics.cellRendererCallsByName, + runtime.previousCellRendererCallsByName, + sampleDuration, + ) + const componentRenderRates = calculateInvocationRates( + quoteRenderDiagnostics.componentRenderCallsByName, + runtime.previousComponentRenderCallsByName, + sampleDuration, + ) + const averageCommitLatencyMs = + averageCommitLatencySamples.length === 0 + ? 0 + : averageCommitLatencySamples.reduce((sum, value) => sum + value, 0) / + averageCommitLatencySamples.length + const p95Index = Math.max( + 0, + Math.ceil(sortedCommitLatencySamples.length * 0.95) - 1, + ) + const metrics: FeedMetrics = { + actualTicksPerSecond: + sampleDuration === 0 + ? 0 + : (runtime.ticksInSample / sampleDuration) * 1_000, + rowUpdatesPerSecond: + (runtime.rowUpdatesInSample / sampleDuration) * 1_000, + workerMessagesPerSecond: + (runtime.workerMessagesInSample / sampleDuration) * 1_000, + stateApplicationsPerSecond: + (runtime.stateApplicationsInSample / sampleDuration) * 1_000, + supersededUpdatesPerSecond: + (runtime.supersededUpdatesInSample / sampleDuration) * 1_000, + totalTicks: runtime.totalTicks, + rafCallbacksPerSecond: calculateFrameRate( + runtime.frameTimestamps, + runtime.frameTrackingStartedAt, + now, + ), + tableCommitsPerSecond: + (runtime.tableCommitsInSample / sampleDuration) * 1_000, + lastBatchSize: runtime.lastBatchSize, + averageCommitLatencyMs, + p95CommitLatencyMs: sortedCommitLatencySamples[p95Index] ?? 0, + maxCommitLatencyMs: sortedCommitLatencySamples.at(-1) ?? 0, + slowCommits: runtime.slowCommitCount, + longAnimationFrames: runtime.longAnimationFrameCount, + worstLongAnimationFrameMs: runtime.worstLongAnimationFrameMs, + heapMb: readHeapSizeMb(), + componentsCreated: quoteCellLifecycle.created, + componentsDestroyed: quoteCellLifecycle.destroyed, + workerMessages: runtime.workerMessages, + lastUpdateCount: runtime.lastUpdateCount, + cellRendererCallsPerSecond: (cellRendererCalls / sampleDuration) * 1_000, + componentRenderCallsPerSecond: + (componentRenderCalls / sampleDuration) * 1_000, + cellRendererRates, + componentRenderRates, + domMutationsPerSecond: + (runtime.domMutationsInSample / sampleDuration) * 1_000, + rowModelCallsPerSecond: (rowModelCalls / sampleDuration) * 1_000, + rowModelAverageMs: + rowModelCalls === 0 ? 0 : rowModelDuration / rowModelCalls, + rowModelMaxMs: rowModelDiagnostics.maxDurationMs, + visibleRows: rowModelDiagnostics.lastRowCount, + } + + runtime.sampleStartedAt = now + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.previousRowModelCalls = rowModelDiagnostics.calls + runtime.previousRowModelDuration = rowModelDiagnostics.totalDurationMs + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.tableCommitsInSample = 0 + return metrics + } + + reset(): void { + const runtime = this.#runtime + runtime.sampleStartedAt = performance.now() + runtime.sessionStartedAt = runtime.sampleStartedAt + runtime.pendingMutationStartedAt = null + runtime.commitLatencySamples = [] + runtime.slowCommitCount = 0 + runtime.totalTicks = 0 + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.lastBatchSize = 0 + runtime.lastUpdateCount = 0 + runtime.workerMessages = 0 + runtime.frameTrackingStartedAt = runtime.sampleStartedAt + runtime.frameTimestamps = [] + runtime.tableCommitsInSample = 0 + runtime.longAnimationFrameCount = 0 + runtime.worstLongAnimationFrameMs = 0 + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.previousRowModelCalls = rowModelDiagnostics.calls + runtime.previousRowModelDuration = rowModelDiagnostics.totalDurationMs + rowModelDiagnostics.maxDurationMs = 0 + } +} + +export const longAnimationFramesSupported = + PerformanceObserver.supportedEntryTypes.includes('long-animation-frame') + +function readHeapSizeMb(): number | null { + const memory = ( + performance as Performance & { + memory?: { usedJSHeapSize: number } + } + ).memory + return memory ? memory.usedJSHeapSize / 1_048_576 : null +} + +function calculateInvocationRates( + current: Record, + previous: Record, + sampleDuration: number, +): ReadonlyArray { + return Object.entries(current).map(([name, calls]) => ({ + name, + callsPerSecond: + sampleDuration === 0 + ? 0 + : ((calls - (previous[name] ?? 0)) / sampleDuration) * 1_000, + })) +} + +function pruneLatencySamples( + samples: Array, + now: number, +): void { + const cutoff = now - percentileLatencyWindowMs + const firstRetainedIndex = samples.findIndex( + (sample) => sample.recordedAt >= cutoff, + ) + if (firstRetainedIndex > 0) samples.splice(0, firstRetainedIndex) + else if (firstRetainedIndex === -1) samples.length = 0 +} + +function pruneFrameTimestamps(timestamps: Array, now: number): void { + const cutoff = now - frameRateWindowMs + const firstRetainedIndex = timestamps.findIndex( + (timestamp) => timestamp >= cutoff, + ) + if (firstRetainedIndex > 0) timestamps.splice(0, firstRetainedIndex) + else if (firstRetainedIndex === -1) timestamps.length = 0 +} + +function calculateFrameRate( + timestamps: ReadonlyArray, + trackingStartedAt: number, + now: number, +): number { + const observedWindowMs = Math.min( + frameRateWindowMs, + Math.max(1, now - trackingStartedAt), + ) + return (timestamps.length / observedWindowMs) * 1_000 +} diff --git a/examples/lit/realtime-trading/src/benchmark/table-benchmark.ts b/examples/lit/realtime-trading/src/benchmark/table-benchmark.ts new file mode 100644 index 0000000000..346a6cdc0c --- /dev/null +++ b/examples/lit/realtime-trading/src/benchmark/table-benchmark.ts @@ -0,0 +1,23 @@ +import type { TradingBenchmarkController } from './trading-benchmark-controller' + +export function startTableBenchmark( + controller: TradingBenchmarkController, +): () => void { + const tableBody = document.querySelector( + '.market-panel [data-trading-table] tbody', + ) + if (!tableBody) return () => undefined + + controller.monitor.resetDomMutations() + const observer = new MutationObserver((records) => { + controller.monitor.recordDomMutations(records.length) + }) + observer.observe(tableBody, { + attributes: true, + attributeFilter: ['class', 'style'], + characterData: true, + childList: true, + subtree: true, + }) + return () => observer.disconnect() +} diff --git a/examples/lit/realtime-trading/src/benchmark/trading-benchmark-controller.ts b/examples/lit/realtime-trading/src/benchmark/trading-benchmark-controller.ts new file mode 100644 index 0000000000..bcb84f2fa8 --- /dev/null +++ b/examples/lit/realtime-trading/src/benchmark/trading-benchmark-controller.ts @@ -0,0 +1,154 @@ +import { batch, createAtom, createStore } from '@tanstack/store' +import { TRADING_COLUMN_COUNT } from '../table/trading-table' +import { FORCED_VIRTUALIZATION_ROW_COUNT } from '../table/trading-row-virtualizer' +import { + BenchmarkMonitor, + initialMetrics, + longAnimationFramesSupported, +} from './benchmark-monitor' +import type { FeedMetrics } from './benchmark-monitor' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { RendererMode } from '../table/trading-table' +import type { VirtualScrollPreference } from '../table/trading-row-virtualizer' + +export interface TradingBenchmarkState { + requestedVirtualScrollMode: VirtualScrollPreference + metrics: FeedMetrics + mountedCells: number + liveComponents: number + longAnimationFramesSupported: boolean +} + +export interface TradingBenchmarkActions { + resetViewState: () => void + setRendererMode: (mode: RendererMode) => void + setVirtualScrollEnabled: (enabled: boolean) => void + setRenderedRowCount: (count: number) => void + selectSymbol: (symbol: string | null) => void + resetMarket: () => void +} + +const initialState: TradingBenchmarkState = { + requestedVirtualScrollMode: 'auto', + metrics: initialMetrics, + mountedCells: 0, + liveComponents: 0, + longAnimationFramesSupported, +} + +export class TradingBenchmarkController { + readonly store = createStore(initialState) + readonly renderAtoms = { + selectedSymbol: createAtom(null), + rendererMode: createAtom('stable'), + } + readonly monitor = new BenchmarkMonitor() + readonly feed: MarketFeedController + readonly actions: TradingBenchmarkActions + + readonly #runtime = { + animationFrameId: 0, + longAnimationFrameObserver: null as PerformanceObserver | null, + stopObservingFeed: null as (() => void) | null, + } + + constructor(feed: MarketFeedController) { + this.feed = feed + this.actions = { + resetViewState: () => { + this.renderAtoms.selectedSymbol.set(null) + this.#patch({ requestedVirtualScrollMode: 'auto' }) + }, + setRendererMode: (mode) => { + this.renderAtoms.rendererMode.set(mode) + }, + setVirtualScrollEnabled: (enabled) => { + if ( + this.feed.instrumentCount.get() >= FORCED_VIRTUALIZATION_ROW_COUNT + ) { + return + } + this.#patch({ + requestedVirtualScrollMode: enabled ? 'tanstack' : 'none', + }) + }, + setRenderedRowCount: (count) => { + const mountedCells = count * TRADING_COLUMN_COUNT + if (mountedCells !== this.store.get().mountedCells) { + this.#patch({ mountedCells }) + } + }, + selectSymbol: (symbol) => { + this.renderAtoms.selectedSymbol.set(symbol) + }, + resetMarket: () => { + batch(() => { + this.monitor.reset() + this.store.setState((state) => ({ + ...state, + metrics: { ...initialMetrics }, + mountedCells: 0, + liveComponents: 0, + })) + this.renderAtoms.selectedSymbol.set(null) + this.feed.actions.reset() + }) + }, + } + } + + start(): () => void { + const longAnimationFrameObserver = longAnimationFramesSupported + ? new PerformanceObserver((entries) => { + for (const entry of entries.getEntries()) { + this.monitor.recordLongAnimationFrame( + entry.duration, + entry.startTime, + ) + } + }) + : null + + this.#runtime.longAnimationFrameObserver = longAnimationFrameObserver + this.#runtime.stopObservingFeed = this.feed.observe({ + messageReceived: () => this.monitor.recordWorkerMessage(), + mutationStarted: () => this.monitor.markCommitPending(), + batchApplied: ({ tickCount, updateCount, supersededUpdateCount }) => + this.monitor.recordBatch(tickCount, updateCount, supersededUpdateCount), + renderCommitted: () => this.monitor.recordDomCommit(), + }) + longAnimationFrameObserver?.observe({ + type: 'long-animation-frame', + }) + this.#runtime.animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + + return () => this.stop() + } + + stop(): void { + cancelAnimationFrame(this.#runtime.animationFrameId) + this.#runtime.longAnimationFrameObserver?.disconnect() + this.#runtime.stopObservingFeed?.() + this.#runtime.longAnimationFrameObserver = null + this.#runtime.stopObservingFeed = null + } + + readonly #benchmarkFrame = (now: number): void => { + this.monitor.recordAnimationFrame(now) + if (this.monitor.shouldPublish(now)) { + this.#publishMetrics(this.monitor.publish(now)) + } + this.#runtime.animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + } + + #patch(patch: Partial): void { + this.store.setState((state) => ({ ...state, ...patch })) + } + + #publishMetrics(metrics: FeedMetrics): void { + this.#patch({ + metrics, + liveComponents: metrics.componentsCreated - metrics.componentsDestroyed, + }) + } +} diff --git a/examples/lit/realtime-trading/src/feed/feed-sample-rates.ts b/examples/lit/realtime-trading/src/feed/feed-sample-rates.ts new file mode 100644 index 0000000000..17dc2015a6 --- /dev/null +++ b/examples/lit/realtime-trading/src/feed/feed-sample-rates.ts @@ -0,0 +1,33 @@ +export const feedSampleRateOptions = [ + { label: '100', value: 100 }, + { label: '250', value: 250 }, + { label: '500', value: 500 }, + { label: '1K', value: 1_000 }, + { label: '2.5K', value: 2_500 }, + { label: '5K', value: 5_000 }, + { label: '10K', value: 10_000 }, + { label: '25K', value: 25_000 }, + { label: '50K', value: 50_000 }, + { label: '100K', value: 100_000 }, +] as const + +export function feedSampleRateIndex(rate: number): number { + return feedSampleRateOptions.reduce((closestIndex, candidate, index) => { + const closest = feedSampleRateOptions[closestIndex] + return Math.abs(candidate.value - rate) < Math.abs(closest.value - rate) + ? index + : closestIndex + }, 0) +} + +export function feedSampleRateAt(stepIndex: number): number { + const index = Math.min( + feedSampleRateOptions.length - 1, + Math.max(0, Math.round(stepIndex)), + ) + return feedSampleRateOptions[index].value +} + +export function normalizeFeedSampleRate(rate: number): number { + return feedSampleRateAt(feedSampleRateIndex(rate)) +} diff --git a/examples/lit/realtime-trading/src/feed/market-data.ts b/examples/lit/realtime-trading/src/feed/market-data.ts new file mode 100644 index 0000000000..6231865d3f --- /dev/null +++ b/examples/lit/realtime-trading/src/feed/market-data.ts @@ -0,0 +1,38 @@ +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './worker/market-feed-protocol' + +export interface MarketQuote extends Omit { + history: ReadonlyArray +} + +export function hydrateMarketQuotes( + snapshots: Array, +): Array { + return snapshots.map((quote) => ({ + ...quote, + history: [...quote.history], + })) +} + +export function applyMarketUpdates( + quotes: Array, + updates: Array, +): Array { + const nextQuotes = [...quotes] + + for (const update of updates) { + const { index, history, ...values } = update + const previousQuote = quotes.at(index) + if (!previousQuote) continue + + nextQuotes[index] = { + ...previousQuote, + ...values, + history: history ?? previousQuote.history, + } + } + + return nextQuotes +} diff --git a/examples/lit/realtime-trading/src/feed/market-feed-config.ts b/examples/lit/realtime-trading/src/feed/market-feed-config.ts new file mode 100644 index 0000000000..9d477ed663 --- /dev/null +++ b/examples/lit/realtime-trading/src/feed/market-feed-config.ts @@ -0,0 +1,15 @@ +export interface MarketFeedConfig { + readonly instrumentCount: number + readonly targetSamplesPerSecond: number + readonly publishIntervalMs: number + readonly updateSparklines: boolean + readonly sparklineSampleIntervalMs: number +} + +export const initialMarketFeedConfig: MarketFeedConfig = { + instrumentCount: 100, + targetSamplesPerSecond: 10_000, + publishIntervalMs: 20, + updateSparklines: true, + sparklineSampleIntervalMs: 16, +} diff --git a/examples/lit/realtime-trading/src/feed/market-feed-controller.ts b/examples/lit/realtime-trading/src/feed/market-feed-controller.ts new file mode 100644 index 0000000000..40f523562d --- /dev/null +++ b/examples/lit/realtime-trading/src/feed/market-feed-controller.ts @@ -0,0 +1,225 @@ +import { batch, createAtom } from '@tanstack/store' +import { normalizeFeedSampleRate } from './feed-sample-rates' +import { initialMarketFeedConfig } from './market-feed-config' +import { applyMarketUpdates, hydrateMarketQuotes } from './market-data' +import type { + MarketFeedCommand, + MarketFeedEvent, +} from './worker/market-feed-protocol' +import type { MarketQuote } from './market-data' + +export interface MarketFeedBatch { + tickCount: number + updateCount: number + supersededUpdateCount: number +} + +export interface MarketFeedObserver { + messageReceived?: () => void + mutationStarted?: () => void + batchApplied?: (batch: MarketFeedBatch) => void + renderCommitted?: () => void +} + +export interface MarketFeedActions { + toggle: () => void + setInstrumentCount: (count: number) => void + setTargetRate: (rate: number) => void + setPublishInterval: (intervalMs: number) => void + setSparklineUpdates: (enabled: boolean) => void + setSparklineSampleInterval: (intervalMs: number) => void + runBurst: () => void + reset: () => void +} + +export class MarketFeedController { + readonly workerReady = createAtom(false) + readonly running = createAtom(true) + readonly instrumentCount = createAtom(initialMarketFeedConfig.instrumentCount) + readonly targetTicksPerSecond = createAtom( + initialMarketFeedConfig.targetSamplesPerSecond, + ) + readonly publishIntervalMs = createAtom( + initialMarketFeedConfig.publishIntervalMs, + ) + readonly updateSparklines = createAtom( + initialMarketFeedConfig.updateSparklines, + ) + readonly sparklineSampleIntervalMs = createAtom( + initialMarketFeedConfig.sparklineSampleIntervalMs, + ) + readonly quotes = createAtom>([]) + readonly actions: MarketFeedActions + readonly #observers = new Set() + readonly #runtime = { + worker: null as Worker | null, + feedSessionId: 0, + renderPending: false, + resetWaitingForCommit: false, + resetSnapshotReady: false, + quoteIndexBySymbol: new Map(), + } + + constructor() { + this.actions = { + toggle: () => { + const running = !this.running.get() + this.running.set(running) + this.#post({ type: 'set-running', running }) + }, + setInstrumentCount: (count) => { + this.instrumentCount.set(count) + this.#resetWorker(count) + }, + setTargetRate: (rate) => { + const sampleRate = normalizeFeedSampleRate(rate) + this.targetTicksPerSecond.set(sampleRate) + this.#post({ type: 'set-rate', ticksPerSecond: sampleRate }) + }, + setPublishInterval: (publishIntervalMs) => { + this.publishIntervalMs.set(publishIntervalMs) + this.#post({ + type: 'set-publish-interval', + intervalMs: publishIntervalMs, + }) + }, + setSparklineUpdates: (enabled) => { + this.updateSparklines.set(enabled) + this.#post({ type: 'set-sparklines', enabled }) + }, + setSparklineSampleInterval: (intervalMs) => { + this.sparklineSampleIntervalMs.set(intervalMs) + this.#post({ type: 'set-sparkline-interval', intervalMs }) + }, + runBurst: () => this.#post({ type: 'burst', tickCount: 25_000 }), + reset: () => this.#resetWorker(this.instrumentCount.get()), + } + } + + start(): () => void { + const worker = new Worker( + new URL('./worker/market-feed.worker.ts', import.meta.url), + { type: 'module' }, + ) + this.#runtime.worker = worker + worker.addEventListener('message', this.#handleWorkerMessage) + worker.addEventListener('error', this.#handleWorkerError) + this.#post({ + type: 'start', + rowCount: this.instrumentCount.get(), + running: this.running.get(), + ticksPerSecond: this.targetTicksPerSecond.get(), + publishIntervalMs: this.publishIntervalMs.get(), + updateSparklines: this.updateSparklines.get(), + sparklineSampleIntervalMs: this.sparklineSampleIntervalMs.get(), + }) + return () => this.stop() + } + + stop(): void { + this.#runtime.worker?.removeEventListener( + 'message', + this.#handleWorkerMessage, + ) + this.#runtime.worker?.removeEventListener('error', this.#handleWorkerError) + this.#runtime.worker?.terminate() + this.#runtime.worker = null + this.#observers.clear() + } + + observe(observer: MarketFeedObserver): () => void { + this.#observers.add(observer) + return () => this.#observers.delete(observer) + } + + getQuoteBySymbol( + quotes: Array, + symbol: string | null, + ): MarketQuote | null { + if (symbol === null) return null + + const index = this.#runtime.quoteIndexBySymbol.get(symbol) + return index === undefined ? null : (quotes[index] ?? null) + } + + completeRender(): void { + if (!this.#runtime.renderPending) return + + this.#runtime.renderPending = false + for (const observer of this.#observers) { + observer.renderCommitted?.() + } + if ( + this.#runtime.resetWaitingForCommit && + this.#runtime.resetSnapshotReady + ) { + this.#runtime.resetWaitingForCommit = false + this.#runtime.resetSnapshotReady = false + this.#post({ type: 'set-running', running: this.running.get() }) + } + } + + readonly #handleWorkerMessage = ({ + data, + }: MessageEvent): void => { + if (data.type === 'snapshot') { + this.#runtime.feedSessionId = data.sessionId + if (this.#runtime.resetWaitingForCommit) { + this.#runtime.resetSnapshotReady = true + } + this.#startMutation() + const quotes = hydrateMarketQuotes(data.quotes) + this.#runtime.quoteIndexBySymbol = new Map( + quotes.map((quote, index) => [quote.symbol, index]), + ) + batch(() => { + this.quotes.set(quotes) + this.workerReady.set(true) + }) + return + } + + if (data.sessionId !== this.#runtime.feedSessionId) return + + for (const observer of this.#observers) { + observer.messageReceived?.() + } + this.#startMutation() + this.quotes.set(applyMarketUpdates(this.quotes.get(), data.updates)) + const feedBatch = { + tickCount: data.tickCount, + updateCount: data.updates.length, + supersededUpdateCount: data.coalescedUpdateCount, + } + for (const observer of this.#observers) { + observer.batchApplied?.(feedBatch) + } + } + + readonly #handleWorkerError = (error: ErrorEvent): void => { + batch(() => { + this.workerReady.set(false) + this.running.set(false) + }) + console.error('Market feed worker failed', error) + } + + #resetWorker(rowCount: number): void { + this.workerReady.set(false) + this.#runtime.resetWaitingForCommit = true + this.#runtime.resetSnapshotReady = false + this.#post({ type: 'set-running', running: false }) + this.#post({ type: 'reset', rowCount }) + } + + #startMutation(): void { + this.#runtime.renderPending = true + for (const observer of this.#observers) { + observer.mutationStarted?.() + } + } + + #post(command: MarketFeedCommand): void { + this.#runtime.worker?.postMessage(command) + } +} diff --git a/examples/lit/realtime-trading/src/feed/market-instruments.ts b/examples/lit/realtime-trading/src/feed/market-instruments.ts new file mode 100644 index 0000000000..ac18d14ea9 --- /dev/null +++ b/examples/lit/realtime-trading/src/feed/market-instruments.ts @@ -0,0 +1,742 @@ +export type MarketCode = + | 'US' + | 'NL' + | 'DE' + | 'FR' + | 'IT' + | 'ES' + | 'CH' + | 'DK' + | 'SE' + | 'FI' + | 'GB' + | 'KR' + | 'JP' + | 'HK' + | 'CA' + | 'AU' + +export type BaseInstrument = readonly [ + symbol: string, + company: string, + market: MarketCode, +] + +/** + * Current S&P 500 constituent universe used by the realtime trading examples. + * + * Source snapshot: https://github.com/datasets/s-and-p-500-companies + * Retrieved: 2026-08-15. + * Multiple share classes are intentionally represented as separate instruments. + */ +export const marketInstruments = Object.freeze([ + ['MMM', '3M', 'US'], + ['AOS', 'A. O. Smith', 'US'], + ['ABT', 'Abbott Laboratories', 'US'], + ['ABBV', 'AbbVie', 'US'], + ['ACN', 'Accenture', 'US'], + ['ADBE', 'Adobe Inc.', 'US'], + ['AMD', 'Advanced Micro Devices', 'US'], + ['AES', 'AES Corporation', 'US'], + ['AFL', 'Aflac', 'US'], + ['A', 'Agilent Technologies', 'US'], + ['APD', 'Air Products', 'US'], + ['ABNB', 'Airbnb', 'US'], + ['AKAM', 'Akamai Technologies', 'US'], + ['ALB', 'Albemarle Corporation', 'US'], + ['ARE', 'Alexandria Real Estate Equities', 'US'], + ['ALGN', 'Align Technology', 'US'], + ['ALLE', 'Allegion', 'US'], + ['LNT', 'Alliant Energy', 'US'], + ['ALL', 'Allstate', 'US'], + ['GOOGL', 'Alphabet Inc. (Class A)', 'US'], + ['GOOG', 'Alphabet Inc. (Class C)', 'US'], + ['MO', 'Altria', 'US'], + ['AMZN', 'Amazon', 'US'], + ['AMCR', 'Amcor', 'US'], + ['AEE', 'Ameren', 'US'], + ['AEP', 'American Electric Power', 'US'], + ['AXP', 'American Express', 'US'], + ['AIG', 'American International Group', 'US'], + ['AMT', 'American Tower', 'US'], + ['AWK', 'American Water Works', 'US'], + ['AMP', 'Ameriprise Financial', 'US'], + ['AME', 'Ametek', 'US'], + ['AMGN', 'Amgen', 'US'], + ['APH', 'Amphenol', 'US'], + ['ADI', 'Analog Devices', 'US'], + ['AON', 'Aon plc', 'US'], + ['APA', 'APA Corporation', 'US'], + ['APO', 'Apollo Global Management', 'US'], + ['AAPL', 'Apple Inc.', 'US'], + ['AMAT', 'Applied Materials', 'US'], + ['APP', 'AppLovin', 'US'], + ['APTV', 'Aptiv', 'US'], + ['ACGL', 'Arch Capital Group', 'US'], + ['ADM', 'Archer Daniels Midland', 'US'], + ['ARES', 'Ares Management', 'US'], + ['ANET', 'Arista Networks', 'US'], + ['AJG', 'Arthur J. Gallagher & Co.', 'US'], + ['AIZ', 'Assurant', 'US'], + ['T', 'AT&T', 'US'], + ['ATO', 'Atmos Energy', 'US'], + ['ADSK', 'Autodesk', 'US'], + ['ADP', 'Automatic Data Processing', 'US'], + ['AZO', 'AutoZone', 'US'], + ['AVB', 'AvalonBay Communities', 'US'], + ['AVY', 'Avery Dennison', 'US'], + ['AXON', 'Axon Enterprise', 'US'], + ['BKR', 'Baker Hughes', 'US'], + ['BALL', 'Ball Corporation', 'US'], + ['BAC', 'Bank of America', 'US'], + ['BAX', 'Baxter International', 'US'], + ['BDX', 'Becton Dickinson', 'US'], + ['BRK.B', 'Berkshire Hathaway', 'US'], + ['BBY', 'Best Buy', 'US'], + ['TECH', 'Bio-Techne', 'US'], + ['BIIB', 'Biogen', 'US'], + ['BLK', 'BlackRock', 'US'], + ['BX', 'Blackstone Inc.', 'US'], + ['XYZ', 'Block, Inc.', 'US'], + ['BNY', 'BNY Mellon', 'US'], + ['BA', 'Boeing', 'US'], + ['BKNG', 'Booking Holdings', 'US'], + ['BSX', 'Boston Scientific', 'US'], + ['BMY', 'Bristol Myers Squibb', 'US'], + ['AVGO', 'Broadcom', 'US'], + ['BR', 'Broadridge Financial Solutions', 'US'], + ['BRO', 'Brown & Brown', 'US'], + ['BF.B', 'Brown–Forman', 'US'], + ['BLDR', 'Builders FirstSource', 'US'], + ['BG', 'Bunge Global', 'US'], + ['BXP', 'BXP, Inc.', 'US'], + ['CHRW', 'C.H. Robinson', 'US'], + ['CDNS', 'Cadence Design Systems', 'US'], + ['CPT', 'Camden Property Trust', 'US'], + ['COF', 'Capital One', 'US'], + ['CAH', 'Cardinal Health', 'US'], + ['CCL', 'Carnival Corporation', 'US'], + ['CARR', 'Carrier Global', 'US'], + ['CVNA', 'Carvana', 'US'], + ['CASY', "Casey's", 'US'], + ['CAT', 'Caterpillar Inc.', 'US'], + ['CBOE', 'Cboe Global Markets', 'US'], + ['CBRE', 'CBRE Group', 'US'], + ['CDW', 'CDW Corporation', 'US'], + ['COR', 'Cencora', 'US'], + ['CNC', 'Centene Corporation', 'US'], + ['CNP', 'CenterPoint Energy', 'US'], + ['CF', 'CF Industries', 'US'], + ['CRL', 'Charles River Laboratories', 'US'], + ['SCHW', 'Charles Schwab Corporation', 'US'], + ['CHTR', 'Charter Communications', 'US'], + ['CVX', 'Chevron Corporation', 'US'], + ['CMG', 'Chipotle Mexican Grill', 'US'], + ['CB', 'Chubb Limited', 'US'], + ['CHD', 'Church & Dwight', 'US'], + ['CIEN', 'Ciena', 'US'], + ['CI', 'Cigna', 'US'], + ['CINF', 'Cincinnati Financial', 'US'], + ['CTAS', 'Cintas', 'US'], + ['CSCO', 'Cisco', 'US'], + ['C', 'Citigroup', 'US'], + ['CFG', 'Citizens Financial Group', 'US'], + ['CLX', 'Clorox', 'US'], + ['CME', 'CME Group', 'US'], + ['CMS', 'CMS Energy', 'US'], + ['KO', 'Coca-Cola Company (The)', 'US'], + ['CTSH', 'Cognizant', 'US'], + ['COHR', 'Coherent Corp.', 'US'], + ['COIN', 'Coinbase', 'US'], + ['CL', 'Colgate-Palmolive', 'US'], + ['CMCSA', 'Comcast', 'US'], + ['FIX', 'Comfort Systems USA', 'US'], + ['COP', 'ConocoPhillips', 'US'], + ['ED', 'Consolidated Edison', 'US'], + ['STZ', 'Constellation Brands', 'US'], + ['CEG', 'Constellation Energy', 'US'], + ['COO', 'Cooper Companies (The)', 'US'], + ['CPRT', 'Copart', 'US'], + ['GLW', 'Corning Inc.', 'US'], + ['CPAY', 'Corpay', 'US'], + ['CTVA', 'Corteva', 'US'], + ['CSGP', 'CoStar Group', 'US'], + ['COST', 'Costco', 'US'], + ['CRH', 'CRH plc', 'US'], + ['CRWD', 'CrowdStrike', 'US'], + ['CCI', 'Crown Castle', 'US'], + ['CSX', 'CSX Corporation', 'US'], + ['CMI', 'Cummins', 'US'], + ['CVS', 'CVS Health', 'US'], + ['DHR', 'Danaher Corporation', 'US'], + ['DRI', 'Darden Restaurants', 'US'], + ['DDOG', 'Datadog', 'US'], + ['DVA', 'DaVita', 'US'], + ['DECK', 'Deckers Brands', 'US'], + ['DE', 'Deere & Company', 'US'], + ['DELL', 'Dell Technologies', 'US'], + ['DAL', 'Delta Air Lines', 'US'], + ['DVN', 'Devon Energy', 'US'], + ['DXCM', 'Dexcom', 'US'], + ['FANG', 'Diamondback Energy', 'US'], + ['DLR', 'Digital Realty', 'US'], + ['DG', 'Dollar General', 'US'], + ['DLTR', 'Dollar Tree', 'US'], + ['D', 'Dominion Energy', 'US'], + ['DPZ', "Domino's", 'US'], + ['DASH', 'DoorDash', 'US'], + ['DOV', 'Dover Corporation', 'US'], + ['DOW', 'Dow Inc.', 'US'], + ['DHI', 'D. R. Horton', 'US'], + ['DTE', 'DTE Energy', 'US'], + ['DUK', 'Duke Energy', 'US'], + ['DD', 'DuPont', 'US'], + ['ETN', 'Eaton Corporation', 'US'], + ['EBAY', 'eBay Inc.', 'US'], + ['ECHO', 'EchoStar', 'US'], + ['ECL', 'Ecolab', 'US'], + ['EIX', 'Edison International', 'US'], + ['EW', 'Edwards Lifesciences', 'US'], + ['ELV', 'Elevance Health', 'US'], + ['EME', 'Emcor', 'US'], + ['EMR', 'Emerson Electric', 'US'], + ['ETR', 'Entergy', 'US'], + ['EOG', 'EOG Resources', 'US'], + ['EQT', 'EQT Corporation', 'US'], + ['EFX', 'Equifax', 'US'], + ['EQIX', 'Equinix', 'US'], + ['EQR', 'Equity Residential', 'US'], + ['ERIE', 'Erie Indemnity', 'US'], + ['ESS', 'Essex Property Trust', 'US'], + ['EL', 'Estée Lauder Companies (The)', 'US'], + ['EG', 'Everest Group', 'US'], + ['EVRG', 'Evergy', 'US'], + ['ES', 'Eversource Energy', 'US'], + ['EXC', 'Exelon', 'US'], + ['EXE', 'Expand Energy', 'US'], + ['EXPE', 'Expedia Group', 'US'], + ['EXPD', 'Expeditors International', 'US'], + ['EXR', 'Extra Space Storage', 'US'], + ['XOM', 'ExxonMobil', 'US'], + ['FFIV', 'F5, Inc.', 'US'], + ['FDS', 'FactSet', 'US'], + ['FICO', 'Fair Isaac', 'US'], + ['FAST', 'Fastenal', 'US'], + ['FRT', 'Federal Realty Investment Trust', 'US'], + ['FDX', 'FedEx', 'US'], + ['FDXF', 'FedEx Freight', 'US'], + ['FERG', 'Ferguson Enterprises', 'US'], + ['FIS', 'Fidelity National Information Services', 'US'], + ['FITB', 'Fifth Third Bancorp', 'US'], + ['FSLR', 'First Solar', 'US'], + ['FE', 'FirstEnergy', 'US'], + ['FISV', 'Fiserv', 'US'], + ['FLEX', 'Flex Ltd.', 'US'], + ['F', 'Ford Motor Company', 'US'], + ['FTNT', 'Fortinet', 'US'], + ['FTV', 'Fortive', 'US'], + ['FOXA', 'Fox Corporation (Class A)', 'US'], + ['FOX', 'Fox Corporation (Class B)', 'US'], + ['BEN', 'Franklin Resources', 'US'], + ['FCX', 'Freeport-McMoRan', 'US'], + ['GRMN', 'Garmin', 'US'], + ['IT', 'Gartner', 'US'], + ['GE', 'GE Aerospace', 'US'], + ['GEHC', 'GE HealthCare', 'US'], + ['GEV', 'GE Vernova', 'US'], + ['GEN', 'Gen Digital', 'US'], + ['GNRC', 'Generac', 'US'], + ['GD', 'General Dynamics', 'US'], + ['GIS', 'General Mills', 'US'], + ['GM', 'General Motors', 'US'], + ['GPC', 'Genuine Parts Company', 'US'], + ['GILD', 'Gilead Sciences', 'US'], + ['GPN', 'Global Payments', 'US'], + ['GL', 'Globe Life', 'US'], + ['GDDY', 'GoDaddy', 'US'], + ['GS', 'Goldman Sachs', 'US'], + ['HAL', 'Halliburton', 'US'], + ['HIG', 'Hartford (The)', 'US'], + ['HAS', 'Hasbro', 'US'], + ['HCA', 'HCA Healthcare', 'US'], + ['DOC', 'Healthpeak Properties', 'US'], + ['HSIC', 'Henry Schein', 'US'], + ['HSY', 'Hershey Company (The)', 'US'], + ['HPE', 'Hewlett Packard Enterprise', 'US'], + ['HLT', 'Hilton Worldwide', 'US'], + ['HD', 'Home Depot (The)', 'US'], + ['HONA', 'Honeywell Aerospace', 'US'], + ['HON', 'Honeywell Technologies', 'US'], + ['HRL', 'Hormel Foods', 'US'], + ['HST', 'Host Hotels & Resorts', 'US'], + ['HWM', 'Howmet Aerospace', 'US'], + ['HPQ', 'HP Inc.', 'US'], + ['HUBB', 'Hubbell Incorporated', 'US'], + ['HUM', 'Humana', 'US'], + ['HBAN', 'Huntington Bancshares', 'US'], + ['HII', 'Huntington Ingalls Industries', 'US'], + ['IBM', 'IBM', 'US'], + ['IEX', 'IDEX Corporation', 'US'], + ['IDXX', 'Idexx Laboratories', 'US'], + ['ITW', 'Illinois Tool Works', 'US'], + ['INCY', 'Incyte', 'US'], + ['IR', 'Ingersoll Rand', 'US'], + ['PODD', 'Insulet Corporation', 'US'], + ['INTC', 'Intel', 'US'], + ['IBKR', 'Interactive Brokers', 'US'], + ['ICE', 'Intercontinental Exchange', 'US'], + ['IFF', 'International Flavors & Fragrances', 'US'], + ['IP', 'International Paper', 'US'], + ['INTU', 'Intuit', 'US'], + ['ISRG', 'Intuitive Surgical', 'US'], + ['IVZ', 'Invesco', 'US'], + ['INVH', 'Invitation Homes', 'US'], + ['IQV', 'IQVIA', 'US'], + ['IRM', 'Iron Mountain', 'US'], + ['JBHT', 'J.B. Hunt', 'US'], + ['JBL', 'Jabil', 'US'], + ['JKHY', 'Jack Henry & Associates', 'US'], + ['J', 'Jacobs Solutions', 'US'], + ['JNJ', 'Johnson & Johnson', 'US'], + ['JCI', 'Johnson Controls', 'US'], + ['JPM', 'JPMorgan Chase', 'US'], + ['KVUE', 'Kenvue', 'US'], + ['KDP', 'Keurig Dr Pepper', 'US'], + ['KEY', 'KeyCorp', 'US'], + ['KEYS', 'Keysight Technologies', 'US'], + ['KMB', 'Kimberly-Clark', 'US'], + ['KIM', 'Kimco Realty', 'US'], + ['KMI', 'Kinder Morgan', 'US'], + ['KKR', 'KKR & Co.', 'US'], + ['KLAC', 'KLA Corporation', 'US'], + ['KHC', 'Kraft Heinz', 'US'], + ['KR', 'Kroger', 'US'], + ['LHX', 'L3Harris', 'US'], + ['LH', 'Labcorp', 'US'], + ['LRCX', 'Lam Research', 'US'], + ['LVS', 'Las Vegas Sands', 'US'], + ['LDOS', 'Leidos', 'US'], + ['LEN', 'Lennar', 'US'], + ['LII', 'Lennox International', 'US'], + ['LLY', 'Lilly (Eli)', 'US'], + ['LIN', 'Linde plc', 'US'], + ['LYV', 'Live Nation Entertainment', 'US'], + ['LMT', 'Lockheed Martin', 'US'], + ['L', 'Loews Corporation', 'US'], + ['LOW', "Lowe's", 'US'], + ['LULU', 'Lululemon Athletica', 'US'], + ['LITE', 'Lumentum', 'US'], + ['LYB', 'LyondellBasell', 'US'], + ['MTB', 'M&T Bank', 'US'], + ['MPC', 'Marathon Petroleum', 'US'], + ['MAR', 'Marriott International', 'US'], + ['MRSH', 'Marsh McLennan', 'US'], + ['MLM', 'Martin Marietta Materials', 'US'], + ['MRVL', 'Marvell Technology', 'US'], + ['MAS', 'Masco', 'US'], + ['MA', 'Mastercard', 'US'], + ['MKC', 'McCormick & Company', 'US'], + ['MCD', "McDonald's", 'US'], + ['MCK', 'McKesson Corporation', 'US'], + ['MDT', 'Medtronic', 'US'], + ['MRK', 'Merck & Co.', 'US'], + ['META', 'Meta Platforms', 'US'], + ['MET', 'MetLife', 'US'], + ['MTD', 'Mettler Toledo', 'US'], + ['MGM', 'MGM Resorts', 'US'], + ['MCHP', 'Microchip Technology', 'US'], + ['MU', 'Micron Technology', 'US'], + ['MSFT', 'Microsoft', 'US'], + ['MAA', 'Mid-America Apartment Communities', 'US'], + ['MRNA', 'Moderna', 'US'], + ['TAP', 'Molson Coors Beverage Company', 'US'], + ['MDLZ', 'Mondelez International', 'US'], + ['MPWR', 'Monolithic Power Systems', 'US'], + ['MNST', 'Monster Beverage', 'US'], + ['MCO', "Moody's Corporation", 'US'], + ['MS', 'Morgan Stanley', 'US'], + ['MOS', 'Mosaic Company (The)', 'US'], + ['MSI', 'Motorola Solutions', 'US'], + ['MSCI', 'MSCI', 'US'], + ['NDAQ', 'Nasdaq, Inc.', 'US'], + ['NTAP', 'NetApp', 'US'], + ['NFLX', 'Netflix', 'US'], + ['NEM', 'Newmont', 'US'], + ['NWSA', 'News Corp (Class A)', 'US'], + ['NWS', 'News Corp (Class B)', 'US'], + ['NEE', 'NextEra Energy', 'US'], + ['NKE', 'Nike, Inc.', 'US'], + ['NI', 'NiSource', 'US'], + ['NDSN', 'Nordson Corporation', 'US'], + ['NSC', 'Norfolk Southern', 'US'], + ['NTRS', 'Northern Trust', 'US'], + ['NOC', 'Northrop Grumman', 'US'], + ['NCLH', 'Norwegian Cruise Line Holdings', 'US'], + ['NRG', 'NRG Energy', 'US'], + ['NUE', 'Nucor', 'US'], + ['NVDA', 'Nvidia', 'US'], + ['NVR', 'NVR, Inc.', 'US'], + ['NXPI', 'NXP Semiconductors', 'US'], + ['ORLY', "O'Reilly Automotive", 'US'], + ['OXY', 'Occidental Petroleum', 'US'], + ['ODFL', 'Old Dominion', 'US'], + ['OMC', 'Omnicom Group', 'US'], + ['ON', 'ON Semiconductor', 'US'], + ['OKE', 'Oneok', 'US'], + ['ORCL', 'Oracle Corporation', 'US'], + ['OTIS', 'Otis Worldwide', 'US'], + ['PCAR', 'Paccar', 'US'], + ['PKG', 'Packaging Corporation of America', 'US'], + ['PLTR', 'Palantir Technologies', 'US'], + ['PANW', 'Palo Alto Networks', 'US'], + ['PSKY', 'Paramount Skydance Corporation', 'US'], + ['PH', 'Parker Hannifin', 'US'], + ['PAYX', 'Paychex', 'US'], + ['PYPL', 'PayPal', 'US'], + ['PNR', 'Pentair', 'US'], + ['PEP', 'PepsiCo', 'US'], + ['PFE', 'Pfizer', 'US'], + ['PCG', 'PG&E Corporation', 'US'], + ['PM', 'Philip Morris International', 'US'], + ['PSX', 'Phillips 66', 'US'], + ['PNW', 'Pinnacle West Capital', 'US'], + ['PNC', 'PNC Financial Services', 'US'], + ['PPG', 'PPG Industries', 'US'], + ['PPL', 'PPL Corporation', 'US'], + ['PFG', 'Principal Financial Group', 'US'], + ['PG', 'Procter & Gamble', 'US'], + ['PGR', 'Progressive Corporation', 'US'], + ['PLD', 'Prologis', 'US'], + ['PRU', 'Prudential Financial', 'US'], + ['PEG', 'Public Service Enterprise Group', 'US'], + ['PTC', 'PTC Inc.', 'US'], + ['PSA', 'Public Storage', 'US'], + ['PHM', 'PulteGroup', 'US'], + ['PWR', 'Quanta Services', 'US'], + ['QCOM', 'Qualcomm', 'US'], + ['DGX', 'Quest Diagnostics', 'US'], + ['Q', 'Qnity Electronics', 'US'], + ['RL', 'Ralph Lauren Corporation', 'US'], + ['RJF', 'Raymond James Financial', 'US'], + ['RTX', 'RTX Corporation', 'US'], + ['O', 'Realty Income', 'US'], + ['REG', 'Regency Centers', 'US'], + ['REGN', 'Regeneron Pharmaceuticals', 'US'], + ['RF', 'Regions Financial Corporation', 'US'], + ['RSG', 'Republic Services', 'US'], + ['RMD', 'ResMed|', 'US'], + ['RVTY', 'Revvity', 'US'], + ['HOOD', 'Robinhood Markets', 'US'], + ['ROK', 'Rockwell Automation', 'US'], + ['ROL', 'Rollins, Inc.', 'US'], + ['ROP', 'Roper Technologies', 'US'], + ['ROST', 'Ross Stores', 'US'], + ['RCL', 'Royal Caribbean Group', 'US'], + ['SPGI', 'S&P Global', 'US'], + ['CRM', 'Salesforce', 'US'], + ['SNDK', 'Sandisk', 'US'], + ['SBAC', 'SBA Communications', 'US'], + ['SLB', 'Schlumberger', 'US'], + ['STX', 'Seagate Technology', 'US'], + ['SRE', 'Sempra', 'US'], + ['NOW', 'ServiceNow', 'US'], + ['SHW', 'Sherwin-Williams', 'US'], + ['SPG', 'Simon Property Group', 'US'], + ['SWKS', 'Skyworks Solutions', 'US'], + ['SJM', 'J.M. Smucker Company (The)', 'US'], + ['SW', 'Smurfit Westrock', 'US'], + ['SNA', 'Snap-on', 'US'], + ['SOLV', 'Solventum', 'US'], + ['SO', 'Southern Company', 'US'], + ['LUV', 'Southwest Airlines', 'US'], + ['SWK', 'Stanley Black & Decker', 'US'], + ['SBUX', 'Starbucks', 'US'], + ['STT', 'State Street Corporation', 'US'], + ['STLD', 'Steel Dynamics', 'US'], + ['STE', 'Steris', 'US'], + ['SYK', 'Stryker Corporation', 'US'], + ['SMCI', 'Supermicro', 'US'], + ['SYF', 'Synchrony Financial', 'US'], + ['SNPS', 'Synopsys', 'US'], + ['SYY', 'Sysco', 'US'], + ['TMUS', 'T-Mobile US', 'US'], + ['TROW', 'T. Rowe Price', 'US'], + ['TTWO', 'Take-Two Interactive', 'US'], + ['TPR', 'Tapestry, Inc.', 'US'], + ['TRGP', 'Targa Resources', 'US'], + ['TGT', 'Target Corporation', 'US'], + ['TEL', 'TE Connectivity', 'US'], + ['TDY', 'Teledyne Technologies', 'US'], + ['TER', 'Teradyne', 'US'], + ['TSLA', 'Tesla, Inc.', 'US'], + ['TXN', 'Texas Instruments', 'US'], + ['TPL', 'Texas Pacific Land Corporation', 'US'], + ['TXT', 'Textron', 'US'], + ['TMO', 'Thermo Fisher Scientific', 'US'], + ['TJX', 'TJX Companies', 'US'], + ['TKO', 'TKO Group Holdings', 'US'], + ['TTD', 'Trade Desk (The)', 'US'], + ['TSCO', 'Tractor Supply', 'US'], + ['TT', 'Trane Technologies', 'US'], + ['TDG', 'TransDigm Group', 'US'], + ['TRV', 'Travelers Companies (The)', 'US'], + ['TRMB', 'Trimble Inc.', 'US'], + ['TFC', 'Truist Financial', 'US'], + ['TYL', 'Tyler Technologies', 'US'], + ['TSN', 'Tyson Foods', 'US'], + ['USB', 'U.S. Bancorp', 'US'], + ['UBER', 'Uber', 'US'], + ['UDR', 'UDR, Inc.', 'US'], + ['ULTA', 'Ulta Beauty', 'US'], + ['UNP', 'Union Pacific Corporation', 'US'], + ['UAL', 'United Airlines Holdings', 'US'], + ['UPS', 'United Parcel Service', 'US'], + ['URI', 'United Rentals', 'US'], + ['UNH', 'UnitedHealth Group', 'US'], + ['UHS', 'Universal Health Services', 'US'], + ['VLO', 'Valero Energy', 'US'], + ['VEEV', 'Veeva Systems', 'US'], + ['VTR', 'Ventas', 'US'], + ['VLTO', 'Veralto', 'US'], + ['VRSN', 'Verisign', 'US'], + ['VRSK', 'Verisk Analytics', 'US'], + ['VZ', 'Verizon', 'US'], + ['VRTX', 'Vertex Pharmaceuticals', 'US'], + ['VRT', 'Vertiv', 'US'], + ['VTRS', 'Viatris', 'US'], + ['VICI', 'Vici Properties', 'US'], + ['V', 'Visa Inc.', 'US'], + ['VST', 'Vistra Corp.', 'US'], + ['VMC', 'Vulcan Materials Company', 'US'], + ['WRB', 'W. R. Berkley Corporation', 'US'], + ['GWW', 'W. W. Grainger', 'US'], + ['WAB', 'Wabtec', 'US'], + ['WMT', 'Walmart', 'US'], + ['DIS', 'Walt Disney Company (The)', 'US'], + ['WBD', 'Warner Bros. Discovery', 'US'], + ['WM', 'Waste Management', 'US'], + ['WAT', 'Waters Corporation', 'US'], + ['WEC', 'WEC Energy Group', 'US'], + ['WFC', 'Wells Fargo', 'US'], + ['WELL', 'Welltower', 'US'], + ['WST', 'West Pharmaceutical Services', 'US'], + ['WDC', 'Western Digital', 'US'], + ['WY', 'Weyerhaeuser', 'US'], + ['WSM', 'Williams-Sonoma, Inc.', 'US'], + ['WMB', 'Williams Companies', 'US'], + ['WTW', 'Willis Towers Watson', 'US'], + ['WDAY', 'Workday, Inc.', 'US'], + ['WYNN', 'Wynn Resorts', 'US'], + ['XEL', 'Xcel Energy', 'US'], + ['XYL', 'Xylem Inc.', 'US'], + ['YUM', 'Yum! Brands', 'US'], + ['ZBRA', 'Zebra Technologies', 'US'], + ['ZBH', 'Zimmer Biomet', 'US'], + ['ZTS', 'Zoetis', 'US'], +]) + +/** + * Representative liquid international listings used to diversify the fixture. + * Symbols use their local-market form and the third tuple value is an ISO-style + * country/market code, rather than a trading currency or exchange MIC. + * + * References checked 2026-08-15: STOXX Europe 50, KRX KOSPI market, + * JPX TOPIX Core30, and HKEX index constituent materials. + */ +const europeanInstruments = Object.freeze([ + ['ASML', 'ASML Holding', 'NL'], + ['INGA', 'ING Group', 'NL'], + ['ADYEN', 'Adyen', 'NL'], + ['PHIA', 'Philips', 'NL'], + ['HEIA', 'Heineken', 'NL'], + ['SAP', 'SAP', 'DE'], + ['SIE', 'Siemens', 'DE'], + ['ALV', 'Allianz', 'DE'], + ['DTE', 'Deutsche Telekom', 'DE'], + ['MBG', 'Mercedes-Benz Group', 'DE'], + ['BMW', 'BMW', 'DE'], + ['BAS', 'BASF', 'DE'], + ['MUV2', 'Munich Re', 'DE'], + ['VOW3', 'Volkswagen Preference', 'DE'], + ['IFX', 'Infineon Technologies', 'DE'], + ['MC', 'LVMH', 'FR'], + ['OR', "L'Oréal", 'FR'], + ['AIR', 'Airbus', 'FR'], + ['SU', 'Schneider Electric', 'FR'], + ['TTE', 'TotalEnergies', 'FR'], + ['SAN', 'Sanofi', 'FR'], + ['BNP', 'BNP Paribas', 'FR'], + ['CS', 'AXA', 'FR'], + ['DG', 'Vinci', 'FR'], + ['ENEL', 'Enel', 'IT'], + ['ENI', 'Eni', 'IT'], + ['ISP', 'Intesa Sanpaolo', 'IT'], + ['UCG', 'UniCredit', 'IT'], + ['STLAM', 'Stellantis', 'IT'], + ['SAN', 'Banco Santander', 'ES'], + ['IBE', 'Iberdrola', 'ES'], + ['ITX', 'Inditex', 'ES'], + ['BBVA', 'BBVA', 'ES'], + ['NESN', 'Nestlé', 'CH'], + ['ROG', 'Roche Holding', 'CH'], + ['NOVN', 'Novartis', 'CH'], + ['UBSG', 'UBS Group', 'CH'], + ['NOVO-B', 'Novo Nordisk', 'DK'], + ['MAERSK-B', 'A.P. Moller - Maersk', 'DK'], + ['VOLV-B', 'Volvo', 'SE'], + ['ERIC-B', 'Ericsson', 'SE'], + ['NOKIA', 'Nokia', 'FI'], + ['SHEL', 'Shell', 'GB'], + ['AZN', 'AstraZeneca', 'GB'], + ['HSBA', 'HSBC Holdings', 'GB'], + ['ULVR', 'Unilever', 'GB'], + ['LSEG', 'London Stock Exchange Group', 'GB'], +]) + +const europeanMarketCodes = Object.freeze([ + 'NL', + 'DE', + 'FR', + 'IT', + 'ES', + 'CH', + 'DK', + 'SE', + 'FI', + 'GB', +]) + +const europeanMarketGroups = Object.freeze( + europeanMarketCodes.map((market) => + europeanInstruments.filter(([, , instrumentMarket]) => + Object.is(instrumentMarket, market), + ), + ), +) + +const interleavedEuropeanInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...europeanMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + europeanMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const southKoreanInstruments = Object.freeze([ + ['005930', 'Samsung Electronics', 'KR'], + ['000660', 'SK hynix', 'KR'], + ['373220', 'LG Energy Solution', 'KR'], + ['207940', 'Samsung Biologics', 'KR'], + ['005380', 'Hyundai Motor', 'KR'], + ['000270', 'Kia', 'KR'], + ['068270', 'Celltrion', 'KR'], + ['105560', 'KB Financial Group', 'KR'], + ['055550', 'Shinhan Financial Group', 'KR'], + ['035420', 'NAVER', 'KR'], + ['035720', 'Kakao', 'KR'], + ['006400', 'Samsung SDI', 'KR'], + ['051910', 'LG Chem', 'KR'], + ['012330', 'Hyundai Mobis', 'KR'], + ['066570', 'LG Electronics', 'KR'], +]) + +const japaneseInstruments = Object.freeze([ + ['8306', 'Mitsubishi UFJ Financial Group', 'JP'], + ['7203', 'Toyota Motor', 'JP'], + ['6501', 'Hitachi', 'JP'], + ['8316', 'Sumitomo Mitsui Financial Group', 'JP'], + ['6758', 'Sony Group', 'JP'], + ['8058', 'Mitsubishi Corporation', 'JP'], + ['9984', 'SoftBank Group', 'JP'], + ['8035', 'Tokyo Electron', 'JP'], + ['8411', 'Mizuho Financial Group', 'JP'], + ['8031', 'Mitsui & Co.', 'JP'], + ['6861', 'Keyence', 'JP'], + ['7974', 'Nintendo', 'JP'], + ['6098', 'Recruit Holdings', 'JP'], + ['9432', 'Nippon Telegraph and Telephone', 'JP'], + ['4063', 'Shin-Etsu Chemical', 'JP'], +]) + +const hongKongInstruments = Object.freeze([ + ['0700', 'Tencent Holdings', 'HK'], + ['9988', 'Alibaba Group', 'HK'], + ['1810', 'Xiaomi', 'HK'], + ['3690', 'Meituan', 'HK'], + ['0941', 'China Mobile', 'HK'], + ['1211', 'BYD Company', 'HK'], + ['1299', 'AIA Group', 'HK'], + ['0388', 'Hong Kong Exchanges and Clearing', 'HK'], + ['0005', 'HSBC Holdings', 'HK'], + ['2318', 'Ping An Insurance', 'HK'], +]) + +const canadianInstruments = Object.freeze([ + ['RY', 'Royal Bank of Canada', 'CA'], + ['TD', 'Toronto-Dominion Bank', 'CA'], + ['SHOP', 'Shopify', 'CA'], + ['ENB', 'Enbridge', 'CA'], + ['CNR', 'Canadian National Railway', 'CA'], + ['CP', 'Canadian Pacific Kansas City', 'CA'], + ['BMO', 'Bank of Montreal', 'CA'], + ['CSU', 'Constellation Software', 'CA'], +]) + +const australianInstruments = Object.freeze([ + ['BHP', 'BHP Group', 'AU'], + ['CBA', 'Commonwealth Bank of Australia', 'AU'], + ['CSL', 'CSL', 'AU'], + ['NAB', 'National Australia Bank', 'AU'], + ['WBC', 'Westpac Banking Corporation', 'AU'], + ['ANZ', 'ANZ Group Holdings', 'AU'], + ['WES', 'Wesfarmers', 'AU'], + ['MQG', 'Macquarie Group', 'AU'], +]) + +const internationalMarketGroups = Object.freeze([ + interleavedEuropeanInstruments, + southKoreanInstruments, + japaneseInstruments, + hongKongInstruments, + canadianInstruments, + australianInstruments, +]) + +export const internationalInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...internationalMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + internationalMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const INTERNATIONAL_INSERTION_INTERVAL = 3 + +/** + * U.S. and international instruments are interleaved so ordinary benchmark + * sizes exercise multiple symbol formats and market labels. + */ +export const globalInstruments = Object.freeze( + marketInstruments.flatMap((instrument, index) => { + const internationalInstrument = + index % INTERNATIONAL_INSERTION_INTERVAL === 0 + ? internationalInstruments[index / INTERNATIONAL_INSERTION_INTERVAL] + : undefined + + return internationalInstrument + ? [instrument, internationalInstrument] + : [instrument] + }), +) as unknown as ReadonlyArray diff --git a/examples/lit/realtime-trading/src/feed/worker/market-feed-engine.ts b/examples/lit/realtime-trading/src/feed/worker/market-feed-engine.ts new file mode 100644 index 0000000000..fbd9c369c0 --- /dev/null +++ b/examples/lit/realtime-trading/src/feed/worker/market-feed-engine.ts @@ -0,0 +1,177 @@ +import { globalInstruments } from '../market-instruments.ts' +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const INITIAL_MARKET_SEED = 0x4d41524b +const LIVE_FEED_SEED = 0x5449434b + +export class MarketFeedEngine { + #quotes: Array = [] + #lastHistorySampledAt = new Uint32Array(0) + #random = createRandom(2_026) + #rowCursor = 0 + #tickIndex = 0 + + reset(count: number): Array { + const random = createRandom(INITIAL_MARKET_SEED ^ count) + const createdAt = Date.now() + + this.#quotes = Array.from({ length: count }, (_, index) => { + const [baseSymbol, company, market] = + globalInstruments[index % globalInstruments.length] + const series = Math.floor(index / globalInstruments.length) + const symbol = series === 0 ? baseSymbol : `${baseSymbol}${series}` + const previousClose = roundPrice(20 + random() * 480) + const open = roundPrice(previousClose * (1 + (random() - 0.5) * 0.016)) + const spread = Math.max(0.01, open * (0.0002 + random() * 0.0004)) + const history = Array.from({ length: 24 }, (_, historyIndex) => + roundPrice( + open * + (1 + Math.sin(historyIndex / 4) * 0.002 + (random() - 0.5) * 0.001), + ), + ) + const volume = Math.floor(50_000 + random() * 2_000_000) + const lastSize = Math.floor(10 + random() * 5_000) + + return { + id: `instrument-${index}`, + symbol, + company, + venue: market, + previousClose, + open, + high: open, + low: open, + price: open, + bid: roundPrice(open - spread / 2), + ask: roundPrice(open + spread / 2), + bidSize: Math.floor(100 + random() * 25_000), + askSize: Math.floor(100 + random() * 25_000), + lastSize, + lastMove: 0, + lastUpdatedAt: createdAt, + volume, + turnover: roundMoney(open * volume), + history, + } + }) + + this.#random = createRandom(LIVE_FEED_SEED ^ count) + this.#rowCursor = 0 + this.#lastHistorySampledAt = new Uint32Array(count) + this.#lastHistorySampledAt.fill(createdAt >>> 0) + + return this.#quotes.map((quote) => ({ + ...quote, + history: [...quote.history], + })) + } + + applyTicks( + tickCount: number, + updateSparklines: boolean, + sparklineSampleIntervalMs: number, + ): Array { + if (this.#quotes.length === 0 || tickCount <= 0) return [] + + const updatedAt = Date.now() + const sampledAt = updatedAt >>> 0 + const sampleIntervalMs = Math.max(16, sparklineSampleIntervalMs) + const updatedQuotes = new Map() + const stride = 97 + + this.#tickIndex = 0 + while (this.#tickIndex < tickCount) { + this.#rowCursor = (this.#rowCursor + stride) % this.#quotes.length + const quote = this.#quotes[this.#rowCursor] + const lastSampledAt = this.#lastHistorySampledAt[this.#rowCursor] + const shouldUpdateHistory = + updateSparklines && + (sampledAt - lastSampledAt) >>> 0 >= sampleIntervalMs + + if (shouldUpdateHistory) { + this.#lastHistorySampledAt[this.#rowCursor] = sampledAt + } + + this.#applyTick(quote, shouldUpdateHistory, updatedAt) + + const previousUpdate = updatedQuotes.get(this.#rowCursor) + updatedQuotes.set(this.#rowCursor, { + index: this.#rowCursor, + price: quote.price, + bid: quote.bid, + ask: quote.ask, + bidSize: quote.bidSize, + askSize: quote.askSize, + lastSize: quote.lastSize, + lastMove: quote.lastMove, + lastUpdatedAt: quote.lastUpdatedAt, + high: quote.high, + low: quote.low, + volume: quote.volume, + turnover: quote.turnover, + ...(shouldUpdateHistory || previousUpdate?.history + ? { history: [...quote.history] } + : {}), + }) + this.#tickIndex++ + } + + return [...updatedQuotes.values()] + } + + #applyTick( + quote: MarketQuoteSnapshot, + updateHistory: boolean, + updatedAt: number, + ): void { + const previousPrice = quote.price + const volatility = 0.00015 + this.#random() * 0.0012 + const move = previousPrice * (this.#random() - 0.495) * volatility + const nextPrice = roundPrice(Math.max(0.1, previousPrice + move)) + const spread = Math.max( + 0.01, + nextPrice * (0.00015 + this.#random() * 0.0005), + ) + + quote.lastMove = nextPrice - previousPrice + quote.price = nextPrice + quote.high = Math.max(quote.high, nextPrice) + quote.low = Math.min(quote.low, nextPrice) + quote.bid = roundPrice(nextPrice - spread / 2) + quote.ask = roundPrice(nextPrice + spread / 2) + quote.bidSize = Math.floor(100 + this.#random() * 25_000) + quote.askSize = Math.floor(100 + this.#random() * 25_000) + quote.lastSize = Math.floor(10 + this.#random() * 5_000) + quote.lastUpdatedAt = updatedAt + quote.volume += quote.lastSize + quote.turnover = roundMoney(quote.turnover + nextPrice * quote.lastSize) + + if (updateHistory) { + quote.history = [...quote.history.slice(-23), nextPrice] + } + } +} + +function createRandom(seed: number): () => number { + const runtime = { state: seed >>> 0 } + return () => { + runtime.state += 0x6d2b79f5 + const stateValue = runtime.state + const firstMix = Math.imul(stateValue ^ (stateValue >>> 15), stateValue | 1) + const secondMix = + firstMix + Math.imul(firstMix ^ (firstMix >>> 7), firstMix | 61) + const value = firstMix ^ secondMix + return ((value ^ (value >>> 14)) >>> 0) / 4_294_967_296 + } +} + +function roundPrice(value: number): number { + return Math.round(value * 100) / 100 +} + +function roundMoney(value: number): number { + return Math.round(value * 100) / 100 +} diff --git a/examples/lit/realtime-trading/src/feed/worker/market-feed-protocol.ts b/examples/lit/realtime-trading/src/feed/worker/market-feed-protocol.ts new file mode 100644 index 0000000000..21997ec89c --- /dev/null +++ b/examples/lit/realtime-trading/src/feed/worker/market-feed-protocol.ts @@ -0,0 +1,70 @@ +export interface MarketQuoteSnapshot { + id: string + symbol: string + company: string + venue: string + previousClose: number + open: number + high: number + low: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + volume: number + turnover: number + history: Array +} + +export interface MarketQuoteUpdate { + index: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + high: number + low: number + volume: number + turnover: number + history?: Array +} + +export type MarketFeedCommand = + | { + type: 'start' + rowCount: number + running: boolean + ticksPerSecond: number + publishIntervalMs: number + updateSparklines: boolean + sparklineSampleIntervalMs: number + } + | { type: 'set-running'; running: boolean } + | { type: 'set-rate'; ticksPerSecond: number } + | { type: 'set-publish-interval'; intervalMs: number } + | { type: 'set-sparklines'; enabled: boolean } + | { type: 'set-sparkline-interval'; intervalMs: number } + | { type: 'reset'; rowCount: number } + | { type: 'burst'; tickCount: number } + +export type MarketFeedEvent = + | { + type: 'snapshot' + sessionId: number + quotes: Array + } + | { + type: 'updates' + sessionId: number + tickCount: number + coalescedUpdateCount: number + updates: Array + } diff --git a/examples/lit/realtime-trading/src/feed/worker/market-feed.worker.ts b/examples/lit/realtime-trading/src/feed/worker/market-feed.worker.ts new file mode 100644 index 0000000000..2b7a642fd9 --- /dev/null +++ b/examples/lit/realtime-trading/src/feed/worker/market-feed.worker.ts @@ -0,0 +1,143 @@ +import { initialMarketFeedConfig } from '../market-feed-config' +import { MarketFeedEngine } from './market-feed-engine' +import type { + MarketFeedCommand, + MarketFeedEvent, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const engine = new MarketFeedEngine() +const pendingUpdates = new Map() +const runtime = { + sessionId: 0, + pendingTickCount: 0, + pendingCoalescedUpdateCount: 0, + initialized: false, + running: true, + ticksPerSecond: initialMarketFeedConfig.targetSamplesPerSecond, + publishIntervalMs: initialMarketFeedConfig.publishIntervalMs, + publishTimerId: null as ReturnType | null, + updateSparklines: initialMarketFeedConfig.updateSparklines, + sparklineSampleIntervalMs: initialMarketFeedConfig.sparklineSampleIntervalMs, + tickBudget: 0, + lastTickAt: performance.now(), +} + +addEventListener('message', ({ data }: MessageEvent) => { + switch (data.type) { + case 'start': + runtime.running = data.running + runtime.ticksPerSecond = data.ticksPerSecond + runtime.publishIntervalMs = data.publishIntervalMs + runtime.updateSparklines = data.updateSparklines + runtime.sparklineSampleIntervalMs = data.sparklineSampleIntervalMs + restartPublishTimer() + reset(data.rowCount) + break + case 'set-running': + runtime.running = data.running + break + case 'set-rate': + runtime.ticksPerSecond = data.ticksPerSecond + break + case 'set-publish-interval': + runtime.publishIntervalMs = Math.max(4, data.intervalMs) + restartPublishTimer() + break + case 'set-sparklines': + runtime.updateSparklines = data.enabled + break + case 'set-sparkline-interval': + runtime.sparklineSampleIntervalMs = Math.max(16, data.intervalMs) + break + case 'reset': + reset(data.rowCount) + break + case 'burst': + produceTicks(data.tickCount) + flush() + break + } +}) + +setInterval(() => { + const now = performance.now() + const elapsed = Math.min(100, Math.max(0, now - runtime.lastTickAt)) + runtime.lastTickAt = now + + if (runtime.initialized && runtime.running) { + runtime.tickBudget += (runtime.ticksPerSecond * elapsed) / 1_000 + const tickCount = Math.floor(runtime.tickBudget) + runtime.tickBudget -= tickCount + produceTicks(tickCount) + } +}, 16) + +restartPublishTimer() + +function reset(rowCount: number): void { + runtime.initialized = true + runtime.sessionId++ + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + runtime.tickBudget = 0 + runtime.lastTickAt = performance.now() + + post({ + type: 'snapshot', + sessionId: runtime.sessionId, + quotes: engine.reset(rowCount), + }) +} + +function produceTicks(tickCount: number): void { + if (!runtime.initialized || tickCount <= 0) return + + runtime.pendingTickCount += tickCount + for (const update of engine.applyTicks( + tickCount, + runtime.updateSparklines, + runtime.sparklineSampleIntervalMs, + )) { + const previousUpdate = pendingUpdates.get(update.index) + if (previousUpdate) runtime.pendingCoalescedUpdateCount++ + pendingUpdates.set(update.index, { + ...update, + ...(update.history || !previousUpdate?.history + ? {} + : { history: previousUpdate.history }), + }) + } +} + +function flush(): void { + if (runtime.pendingTickCount === 0) return + + const message: MarketFeedEvent = { + type: 'updates', + sessionId: runtime.sessionId, + tickCount: runtime.pendingTickCount, + coalescedUpdateCount: runtime.pendingCoalescedUpdateCount, + updates: [...pendingUpdates.values()], + } + + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + post(message) +} + +function restartPublishTimer(): void { + if (runtime.publishTimerId !== null) { + clearInterval(runtime.publishTimerId) + } + runtime.publishTimerId = setInterval( + flush, + Math.max(4, runtime.publishIntervalMs), + ) +} + +function post(event: MarketFeedEvent): void { + postMessage(event) +} diff --git a/examples/lit/realtime-trading/src/index.css b/examples/lit/realtime-trading/src/index.css new file mode 100644 index 0000000000..0f57ee21d7 --- /dev/null +++ b/examples/lit/realtime-trading/src/index.css @@ -0,0 +1,1070 @@ +:root { + color-scheme: dark; + --font-ui: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + 'Segoe UI', sans-serif; + --font-mono: 'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace; + font-family: var(--font-ui); + font-synthesis: none; + --background: #050505; + --panel: #080808; + --panel-raised: #111111; + --panel-hover: #181818; + --surface-bar: #080808; + --surface-toolbar: #0d0d0d; + --surface-table: #050505; + --surface-header: #101010; + --surface-control: #151515; + --border: #303030; + --border-soft: #242424; + --border-strong: #4a4a4a; + --text: #e7ebf0; + --text-strong: #ffffff; + --text-inverse: #f7f9fb; + --muted: #737982; + --blue: #62a9ff; + --blue-soft: #a9d0ff; + --green: #42e488; + --red: #ff646b; + --amber: #dfb465; + --depth-bid: #315774; + --depth-ask: #634049; + --row-alt: rgb(255 255 255 / 1.8%); + --row-selected: rgb(66 132 214 / 16%); + --control-border: #354456; + --control-hover: #192431; + --sidebar-width: 18rem; + --shell-bar-height: 2.625rem; + --metrics-height: 3.5rem; + --statusbar-height: 1.625rem; + --virtual-footer-height: 2.125rem; + --table-header-height: 2rem; + --table-row-height: 2rem; + --shell-inline-padding: 0.75rem; + --table-cell-inline-padding: 0.6rem; + --control-radius: 1px; +} + +* { + box-sizing: border-box; +} + +html, +body { + min-width: 320px; + min-height: 100%; + margin: 0; + background: var(--background); +} + +body { + color: var(--text); +} + +button, +select, +input { + font: inherit; +} + +button, +select { + color: var(--text); + background: var(--panel-raised); + border: 1px solid var(--control-border); + border-radius: var(--control-radius); +} + +button { + padding: 0.5rem 0.65rem; + cursor: pointer; + font-size: 0.72rem; + font-weight: 650; + letter-spacing: 0.025em; +} + +button:hover { + background: var(--control-hover); + border-color: var(--border-strong); +} + +button:focus-visible, +select:focus-visible, +input:focus-visible { + outline: 1px solid var(--blue); + outline-offset: 1px; +} + +select { + width: 100%; + padding: 0.45rem 0.55rem; + font-size: 0.75rem; +} + +.trading-terminal { + --active-sidebar-width: var(--sidebar-width); + display: grid; + width: 100%; + height: 100dvh; + min-height: 0; + overflow: hidden; + background: var(--background); + grid-template-areas: + 'header sidebar' + 'content sidebar' + 'footer sidebar'; + grid-template-columns: minmax(0, 1fr) var(--active-sidebar-width); + grid-template-rows: auto minmax(0, 1fr) auto; + transition: grid-template-columns 160ms ease; +} + +.trading-terminal.is-sidebar-collapsed { + --active-sidebar-width: 0px; +} + +.shell-header { + display: flex; + min-width: 0; + flex-direction: column; + grid-area: header; +} + +.app-bar { + display: flex; + min-height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + background: var(--surface-bar); + border-bottom: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.68rem; + letter-spacing: 0.045em; +} + +.brand, +.header-actions, +.feed-status { + display: flex; + align-items: center; +} + +.brand { + gap: 0.65rem; + color: var(--text-strong); +} + +.header-actions { + gap: 0.75rem; +} + +.sidebar-toggle { + display: grid; + width: 1.9rem; + height: 1.9rem; + padding: 0; + place-items: center; + color: var(--muted); + background: transparent; + border-color: transparent; +} + +.sidebar-toggle:hover { + color: var(--text-strong); + background: var(--surface-control); + border-color: var(--border); +} + +.sidebar-toggle svg { + width: 1rem; + height: 1rem; + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-width: 1.4; +} + +.feed-status { + gap: 0.4rem; + color: var(--muted); +} + +.feed-status.is-running { + color: var(--green); +} + +.status-dot { + width: 6px; + height: 6px; + background: var(--muted); + border-radius: 50%; +} + +.feed-status.is-running .status-dot { + background: var(--green); +} + +.development-warning { + flex: 0 0 auto; + padding: 0.3rem 0.75rem; + color: var(--amber); + background: color-mix(in srgb, var(--amber) 8%, var(--background)); + border-bottom: 1px solid color-mix(in srgb, var(--amber) 24%, var(--border)); + font-family: var(--font-mono); + font-size: 0.62rem; + letter-spacing: 0.04em; +} + +.market-panel { + display: flex; + min-width: 0; + min-height: 0; + flex-direction: column; + background: var(--panel); + grid-area: content; +} + +.metrics-strip { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + background: var(--border); + border-bottom: 1px solid var(--border); + gap: 1px; +} + +.metrics-strip h2 { + margin: 0; + padding: 0.65rem var(--shell-inline-padding) 0.45rem; + color: var(--muted); + background: var(--surface-table); + font-size: 0.58rem; + grid-column: 1 / -1; + letter-spacing: 0.075em; +} + +trading-metrics-strip { + display: block; +} + +.metrics-strip article { + min-width: 0; + min-height: 4.25rem; + padding: 0.5rem var(--shell-inline-padding); + background: var(--surface-bar); +} + +.metrics-strip span, +.metrics-strip small { + display: block; + color: var(--muted); + font-size: 0.56rem; + letter-spacing: 0.045em; + line-height: 1.35; +} + +.metrics-strip strong { + display: block; + margin: 0.12rem 0 0.08rem; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.88rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +.metrics-strip strong.metric-alert { + color: var(--amber); +} + +.table-scroll { + flex: 1; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +trading-data-table { + display: flex; + flex-direction: column; + flex: 1; + min-width: 0; + min-height: 0; +} + +.virtual-scroll-footer { + display: flex; + flex: 0 0 auto; + align-items: center; + justify-content: space-between; + min-height: var(--virtual-footer-height); + padding: 0 var(--shell-inline-padding); + color: var(--muted); + background: var(--surface-toolbar); + border-top: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.68rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +table { + min-width: 100%; + border-spacing: 0; + table-layout: fixed; + font-family: var(--font-ui); + font-size: 0.78rem; + font-variant-numeric: tabular-nums; +} + +.virtual-table { + display: grid; +} + +.virtual-table thead { + display: grid; +} + +.virtual-table thead tr, +.virtual-table-row { + display: flex; + width: 100%; +} + +.virtual-table th, +.virtual-table-row > td { + flex: 0 0 auto; +} + +.virtual-table-body { + position: relative; + display: grid; +} + +.virtual-table-row { + position: absolute; + left: 0; + height: var(--table-row-height); +} + +.virtual-table-row > td { + display: block; +} + +.trading-data-grid { + display: grid; +} + +.trading-data-grid thead, +.trading-data-grid tbody { + display: grid; +} + +.trading-data-grid tbody { + -webkit-user-select: none; + user-select: none; +} + +.trading-data-grid thead > tr, +.trading-data-grid tbody > tr { + display: flex; + width: 100%; +} + +.trading-data-grid tbody > tr { + min-height: var(--table-row-height); + content-visibility: auto; + contain-intrinsic-block-size: var(--table-row-height); +} + +.trading-data-grid th, +.trading-data-grid td { + flex: 0 0 auto; +} + +thead { + position: sticky; + z-index: 2; + top: 0; +} + +th { + height: var(--table-header-height); + padding: 0 var(--table-cell-inline-padding); + color: var(--muted); + background: var(--surface-header); + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border); + font-size: 0.7rem; + font-weight: 500; + letter-spacing: 0.005em; + text-align: left; + white-space: nowrap; +} + +th.column-group-header { + color: #666b72; + font-size: 0.72rem; + font-weight: 500; + text-align: center; +} + +thead tr:first-child th.column-group-header { + color: #777d85; + font-size: 0.76rem; +} + +th.numeric-header { + text-align: right; +} + +td { + height: var(--table-row-height); + padding: 0 var(--table-cell-inline-padding); + overflow: hidden; + color: #eef1f5; + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border-soft); + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +th:last-child, +td:last-child { + border-right: 0; +} + +td[data-column-id='market'], +td[data-column-id='name'], +td[data-column-id='symbol'] { + text-align: left; +} + +td[data-column-id='market'] { + color: var(--blue); + font-weight: 550; +} + +td[data-column-id='name'] { + color: var(--text-strong); +} + +td[data-column-id='symbol'] { + color: #d8dde4; + font-weight: 600; +} + +tbody tr:nth-child(even) { + background: var(--row-alt); +} + +tbody tr:hover { + background: var(--panel-hover); +} + +tbody tr[data-symbol-selected='true'] { + background: var(--row-selected); + box-shadow: inset 2px 0 0 var(--blue); +} + +.table-scroll:focus { + outline: none; +} + +th { + position: relative; +} + +.leaf-header-content { + display: flex; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + height: 100%; + align-items: stretch; + margin-inline: calc(-1 * var(--table-cell-inline-padding)); +} + +.column-drag-handle, +.sort-header-button { + min-width: 0; + height: 100%; + padding: 0; + color: inherit; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-weight: inherit; + letter-spacing: inherit; +} + +.column-drag-handle { + flex: 0 0 1.05rem; + color: var(--muted); + cursor: grab; + opacity: 0.35; + font-size: 0.56rem; + letter-spacing: -0.32rem; + text-align: center; +} + +.column-drag-handle:active { + cursor: grabbing; +} + +th:hover .column-drag-handle, +.column-drag-handle:focus-visible { + opacity: 0.9; +} + +.column-drag-handle:hover, +.sort-header-button:hover { + background: rgb(255 255 255 / 4%); + border-color: transparent; +} + +th.is-column-dragging { + opacity: 0.45; +} + +th.is-column-drop-target { + background: rgb(50 139 255 / 16%); + box-shadow: inset 4px 0 0 var(--blue); +} + +th.is-column-drop-target::before { + position: absolute; + z-index: 6; + top: -1px; + bottom: -1px; + left: -2px; + width: 4px; + background: #62a9ff; + box-shadow: + 0 0 0 1px rgb(0 0 0 / 55%), + 0 0 12px rgb(70 151 255 / 90%); + content: ''; + pointer-events: none; +} + +.sort-header-button { + display: flex; + min-width: 0; + flex: 1; + align-items: center; + justify-content: flex-start; + gap: 0.3rem; + padding-inline: 0.25rem var(--table-cell-inline-padding); + cursor: default; + text-align: inherit; +} + +.numeric-header .sort-header-button { + justify-content: flex-end; +} + +.sort-header-button.is-sortable { + cursor: pointer; +} + +.sort-header-button:disabled { + opacity: 1; +} + +.header-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.sort-indicator { + flex: 0 0 auto; + color: #66717e; + font-size: 0.72rem; +} + +.sort-indicator.is-active { + color: var(--blue-soft); +} + +.column-resize-handle { + position: absolute; + z-index: 3; + top: 0; + right: -3px; + width: 7px; + height: 100%; + cursor: col-resize; + touch-action: none; + user-select: none; +} + +.column-resize-handle::after { + position: absolute; + top: 20%; + right: 3px; + width: 1px; + height: 60%; + background: var(--border-strong); + content: ''; + opacity: 0; +} + +th:hover > .column-resize-handle::after, +.column-resize-handle.is-resizing::after { + background: var(--blue); + opacity: 1; +} + +tbody tr[aria-selected='true'] { + background: rgb(76 145 228 / 13%); +} + +td[aria-selected='true'] { + position: relative; + background: rgb(70 139 222 / 12%); +} + +td[data-cell-focused='true'] { + background: rgb(70 139 222 / 21%); +} + +td[aria-selected='true']::after { + position: absolute; + z-index: 1; + inset: 0; + border: 1px solid transparent; + content: ''; + pointer-events: none; +} + +td[data-selection-top='true']::after { + border-top-color: var(--blue); +} + +td[data-selection-right='true']::after { + border-right-color: var(--blue); +} + +td[data-selection-bottom='true']::after { + border-bottom-color: var(--blue); +} + +td[data-selection-left='true']::after { + border-left-color: var(--blue); +} + +.price-button { + min-width: 4.5rem; + padding: 0; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-variant-numeric: tabular-nums; + font-weight: 600; + text-align: right; +} + +.price-button:hover { + background: transparent; + text-decoration: underline; + text-underline-offset: 2px; +} + +.move-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.move-cell.quote-up, +.percent-change-cell.quote-up { + background: color-mix(in srgb, var(--green) 7%, transparent); +} + +.move-cell.quote-down, +.percent-change-cell.quote-down { + background: color-mix(in srgb, var(--red) 7%, transparent); +} + +.percent-change-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.spread-cell { + display: flex; + align-items: baseline; + justify-content: flex-end; + gap: 0.35rem; + color: var(--text); +} + +.spread-cell small { + min-width: 2.8rem; + color: var(--muted); + font-size: 0.55rem; +} + +.spread-cell.spread-wide, +.spread-cell.spread-wide small { + color: var(--amber); +} + +.depth-cell { + position: relative; + display: flex; + height: 17px; + overflow: hidden; + background: var(--surface-control); +} + +.depth-bid, +.depth-ask { + height: 100%; + opacity: 0.78; +} + +.depth-bid { + background: var(--depth-bid); + border-right: 1px solid var(--panel); +} + +.depth-ask { + background: var(--depth-ask); +} + +.depth-values { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 0.28rem; + color: var(--text-strong); + font-size: 0.57rem; + text-shadow: 0 1px var(--background); +} + +.quote-age { + color: var(--muted); +} + +.quote-age-warm { + color: var(--amber); +} + +.quote-age-stale { + color: var(--red); +} + +.quote-up { + color: var(--green); +} + +.quote-down { + color: var(--red); +} + +.sparkline { + display: block; + width: 100%; + height: 1.35rem; + margin-left: auto; + color: var(--blue-soft); + overflow: visible; +} + +.sparkline.quote-up { + color: var(--green); +} + +.sparkline.quote-down { + color: var(--red); +} + +.sparkline polyline { + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-linejoin: miter; + stroke-width: 1.25; + vector-effect: non-scaling-stroke; +} + +.market-statusbar { + display: flex; + flex: 0 0 var(--statusbar-height); + min-height: var(--statusbar-height); + gap: 1.1rem; + align-items: center; + padding: 0 0.65rem; + color: var(--muted); + background: var(--surface-bar); + border-top: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.56rem; + grid-area: footer; + letter-spacing: 0.035em; +} + +.market-statusbar strong { + margin-left: 0.25rem; + color: var(--text); + font-weight: 500; +} + +.sidebar-slot { + width: var(--sidebar-width); + min-width: 0; + min-height: 0; + overflow: hidden; + background: var(--surface-table); + border-left: 1px solid var(--border); + grid-area: sidebar; + transition: + opacity 120ms ease, + transform 160ms ease, + visibility 160ms; +} + +.is-sidebar-collapsed .sidebar-slot { + visibility: hidden; + opacity: 0; + pointer-events: none; + transform: translateX(100%); +} + +.configurator { + width: 100%; + height: 100%; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +.configurator > header { + display: flex; + height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + color: var(--text-strong); + background: var(--surface-toolbar); + border-bottom: 1px solid var(--border); + font-size: 0.65rem; + font-weight: 700; + letter-spacing: 0.055em; +} + +.configurator > header small { + color: var(--muted); + font-size: 0.54rem; + font-weight: 500; +} + +.config-section { + display: grid; + gap: 0.7rem; + padding: 0.8rem var(--shell-inline-padding); + border-bottom: 1px solid var(--border); +} + +.config-section h2 { + margin: 0; + color: var(--muted); + font-size: 0.58rem; + letter-spacing: 0.075em; +} + +.primary-action { + width: 100%; + color: var(--text-inverse); + background: var(--blue); + border-color: var(--blue-soft); +} + +.primary-action:hover { + background: var(--blue-soft); + border-color: var(--text-strong); +} + +.field { + display: grid; + gap: 0.35rem; + color: var(--text); + font-size: 0.66rem; +} + +.rate-field > span { + display: flex; + justify-content: space-between; +} + +.rate-field strong { + color: var(--text); + font-family: var(--font-mono); + font-weight: 500; +} + +.field small { + color: var(--muted); + font-family: var(--font-mono); + font-size: 0.55rem; +} + +input[type='range'] { + width: 100%; + margin: 0; + accent-color: var(--blue); +} + +.toggle-field { + display: flex; + gap: 0.5rem; + align-items: flex-start; + color: var(--text); + font-size: 0.66rem; + line-height: 1.3; +} + +.toggle-field input { + margin: 0.12rem 0 0; + accent-color: var(--blue); +} + +.toggle-field small { + display: block; + margin-top: 0.14rem; + color: var(--muted); + font-size: 0.57rem; +} + +.action-grid { + display: grid; + grid-template-columns: 1fr; + gap: 0.4rem; +} + +.diagnostics dl, +.selected-instrument dl { + display: grid; + gap: 0; + margin: 0; +} + +.diagnostics dl > div, +.selected-instrument dl > div { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 24px; + border-bottom: 1px solid var(--border-soft); +} + +.diagnostics dl > div:last-child, +.selected-instrument dl > div:last-child { + border-bottom: 0; +} + +.diagnostics dl > div:has(dd[data-testid$='-breakdown']) { + display: grid; + grid-template-columns: minmax(0, 1fr); + align-content: center; + padding-block: 0.28rem; +} + +.diagnostics dd[data-testid$='-breakdown'] { + width: 100%; + overflow-x: auto; + padding-block: 0.12rem; + white-space: nowrap; + scrollbar-width: thin; +} + +dt { + color: var(--muted); + font-size: 0.61rem; +} + +dd { + margin: 0; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.62rem; +} + +.selection { + display: flex; + align-items: flex-start; + justify-content: space-between; +} + +.selection div { + display: grid; + gap: 0.18rem; +} + +.selection strong { + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.85rem; +} + +.selection span, +.selection small, +.selected-instrument p { + color: var(--muted); + font-size: 0.61rem; +} + +.selected-instrument p { + margin: 0; + line-height: 1.45; +} + +@media (max-width: 980px) { + :root { + --sidebar-width: 15.625rem; + } +} + +@media (max-width: 720px) { + .trading-terminal { + --active-sidebar-width: 0px; + height: 100dvh; + min-height: 0; + overflow: hidden; + } + + .market-panel { + min-height: 0; + } + + .table-scroll { + min-height: 0; + } + + .sidebar-slot { + position: fixed; + z-index: 20; + top: 0; + right: 0; + bottom: 0; + width: min(var(--sidebar-width), calc(100vw - 2.75rem)); + box-shadow: -18px 0 42px rgb(0 0 0 / 48%); + } + + .is-sidebar-collapsed .sidebar-slot { + box-shadow: none; + } +} diff --git a/examples/lit/realtime-trading/src/main.ts b/examples/lit/realtime-trading/src/main.ts new file mode 100644 index 0000000000..b0c36824e4 --- /dev/null +++ b/examples/lit/realtime-trading/src/main.ts @@ -0,0 +1,35 @@ +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' +import { TradingBenchmarkController } from './benchmark/trading-benchmark-controller' +import { MarketFeedController } from './feed/market-feed-controller' +import './shell/TradingShell' +import './index.css' + +@customElement('realtime-trading-app') +export class RealtimeTradingApp extends LitElement { + readonly #feed = new MarketFeedController() + readonly #benchmark = new TradingBenchmarkController(this.#feed) + readonly #stop = { + feed: null as (() => void) | null, + benchmark: null as (() => void) | null, + } + protected createRenderRoot() { + return this + } + connectedCallback() { + super.connectedCallback() + this.#stop.feed = this.#feed.start() + this.#stop.benchmark = this.#benchmark.start() + } + disconnectedCallback() { + this.#stop.benchmark?.() + this.#stop.feed?.() + super.disconnectedCallback() + } + protected render() { + return html`` + } +} diff --git a/examples/lit/realtime-trading/src/shell/AppHeader.ts b/examples/lit/realtime-trading/src/shell/AppHeader.ts new file mode 100644 index 0000000000..4b349bab9b --- /dev/null +++ b/examples/lit/realtime-trading/src/shell/AppHeader.ts @@ -0,0 +1,42 @@ +import { html } from 'lit' +import { customElement, property } from 'lit/decorators.js' +import { ControllerElement } from './controller-element' +import type { MarketFeedController } from '../feed/market-feed-controller' + +@customElement('trading-app-header') +export class AppHeader extends ControllerElement { + @property({ attribute: false }) feed!: MarketFeedController + @property({ type: Boolean }) sidebarOpen = true + @property({ attribute: false }) toggleSidebar: () => void = () => undefined + protected firstUpdated() { + this.observe(this.feed.workerReady) + this.observe(this.feed.running) + } + protected render() { + const workerReady = this.feed.workerReady.get() + const running = this.feed.running.get() + return html`
+
MARKET MONITOR
+
+ ${!workerReady ? 'FEED CONNECTING' : running ? 'FEED LIVE' : 'FEED PAUSED'} +
+
` + } +} diff --git a/examples/lit/realtime-trading/src/shell/Configurator.ts b/examples/lit/realtime-trading/src/shell/Configurator.ts new file mode 100644 index 0000000000..18b3c1f7a8 --- /dev/null +++ b/examples/lit/realtime-trading/src/shell/Configurator.ts @@ -0,0 +1,216 @@ +import { html } from 'lit' +import { customElement, property } from 'lit/decorators.js' +import { repeat } from 'lit/directives/repeat.js' +import { + feedSampleRateAt, + feedSampleRateIndex, + feedSampleRateOptions, +} from '../feed/feed-sample-rates' +import { + FORCED_VIRTUALIZATION_ROW_COUNT, + resolveVirtualScrollMode, +} from '../table/trading-row-virtualizer' +import { configuratorOptions } from './configurator-options' +import { ControllerElement } from './controller-element' +import './Diagnostics' +import './MetricsStrip' +import './SelectedInstrument' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' + +const rate = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +const value = (event: Event) => + (event.target as HTMLInputElement | HTMLSelectElement).value +const number = (event: Event) => Number(value(event)) +const checked = (event: Event) => (event.target as HTMLInputElement).checked +const options = ( + items: ReadonlyArray<{ + readonly label: string + readonly value: number | string + }>, + selectedValue: number | string, +) => + repeat( + items, + (item) => item.value, + (item) => + html``, + ) + +@customElement('trading-configurator') +export class Configurator extends ControllerElement { + @property({ attribute: false }) controller!: TradingBenchmarkController + @property({ attribute: false }) feed!: MarketFeedController + protected firstUpdated() { + this.observe(this.controller.store) + this.observe(this.controller.renderAtoms.rendererMode) + this.observe(this.feed.running) + this.observe(this.feed.instrumentCount) + this.observe(this.feed.targetTicksPerSecond) + this.observe(this.feed.publishIntervalMs) + this.observe(this.feed.updateSparklines) + this.observe(this.feed.sparklineSampleIntervalMs) + } + protected render() { + const feedState = { + running: this.feed.running.get(), + instrumentCount: this.feed.instrumentCount.get(), + targetTicksPerSecond: this.feed.targetTicksPerSecond.get(), + publishIntervalMs: this.feed.publishIntervalMs.get(), + updateSparklines: this.feed.updateSparklines.get(), + sparklineSampleIntervalMs: this.feed.sparklineSampleIntervalMs.get(), + } + const benchmark = this.controller.store.get() + const forced = feedState.instrumentCount >= FORCED_VIRTUALIZATION_ROW_COUNT + const virtualMode = resolveVirtualScrollMode( + benchmark.requestedVirtualScrollMode, + feedState.instrumentCount, + ) + return html`` + } +} diff --git a/examples/lit/realtime-trading/src/shell/Diagnostics.ts b/examples/lit/realtime-trading/src/shell/Diagnostics.ts new file mode 100644 index 0000000000..2d78db9cd8 --- /dev/null +++ b/examples/lit/realtime-trading/src/shell/Diagnostics.ts @@ -0,0 +1,153 @@ +import { html } from 'lit' +import { customElement, property } from 'lit/decorators.js' +import { repeat } from 'lit/directives/repeat.js' +import { ControllerElement } from './controller-element' +import type { NamedInvocationRate } from '../benchmark/benchmark-monitor' +import type { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' + +const integer = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }) +const rate = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +const ms = (value: number) => `${value.toFixed(2)} ms` +const invocations = (values: ReadonlyArray) => { + const active = values.filter((entry) => entry.callsPerSecond > 0) + return active.length + ? active + .map((entry) => `${entry.name} ${rate.format(entry.callsPerSecond)}`) + .join(' · ') + : '—' +} +@customElement('trading-diagnostics') +export class Diagnostics extends ControllerElement { + @property({ attribute: false }) controller!: TradingBenchmarkController + protected firstUpdated() { + this.observe(this.controller.store) + } + protected render() { + const state = this.controller.store.get() + const metrics = state.metrics + const items = [ + [ + 'Worker-generated samples / s', + rate.format(metrics.actualTicksPerSecond), + 'actual-rate', + ], + [ + 'Changed rows / s', + rate.format(metrics.rowUpdatesPerSecond), + 'row-update-rate', + ], + [ + 'Worker messages / s', + metrics.workerMessagesPerSecond.toFixed(1), + 'message-rate', + ], + [ + 'Snapshots applied / s', + metrics.stateApplicationsPerSecond.toFixed(1), + 'state-apply-rate', + ], + [ + 'DOM commits / s', + metrics.tableCommitsPerSecond.toFixed(1), + 'table-render-rate', + ], + [ + 'Commit latency p95 / max (10 s)', + `${ms(metrics.p95CommitLatencyMs)} / ${ms(metrics.maxCommitLatencyMs)}`, + '', + ], + ['Mounted cells', integer.format(state.mountedCells), ''], + ['Live components', integer.format(state.liveComponents), ''], + [ + 'Created / destroyed', + `${integer.format(metrics.componentsCreated)} / ${integer.format(metrics.componentsDestroyed)}`, + '', + ], + [ + 'Renderer callbacks / s', + rate.format(metrics.cellRendererCallsPerSecond), + 'cell-render-rate', + ], + [ + 'Component executions / s', + rate.format(metrics.componentRenderCallsPerSecond), + 'component-render-rate', + ], + [ + 'Executions by component / s', + invocations(metrics.componentRenderRates), + 'component-render-breakdown', + ], + [ + 'Callbacks by column / s', + invocations(metrics.cellRendererRates), + 'cell-render-breakdown', + ], + [ + 'Observed MutationRecords / s', + rate.format(metrics.domMutationsPerSecond), + 'dom-mutation-rate', + ], + [ + 'Core row model calls / s', + metrics.rowModelCallsPerSecond.toFixed(1), + 'row-model-call-rate', + ], + [ + 'Core row model avg / max', + `${ms(metrics.rowModelAverageMs)} / ${ms(metrics.rowModelMaxMs)}`, + 'row-model-duration', + ], + [ + 'Visible rows', + integer.format(metrics.visibleRows), + 'visible-row-count', + ], + [ + 'Worker messages', + integer.format(metrics.workerMessages), + 'worker-messages', + ], + [ + 'Worker-coalesced updates / s', + rate.format(metrics.supersededUpdatesPerSecond), + 'superseded-update-rate', + ], + [ + 'Last samples / updated rows', + `${integer.format(metrics.lastBatchSize)} / ${integer.format(metrics.lastUpdateCount)}`, + '', + ], + [ + 'Commits > 16.7 ms (since reset)', + integer.format(metrics.slowCommits), + '', + ], + [ + 'JS heap (current, GC-sensitive)', + metrics.heapMb === null ? 'N/A' : `${metrics.heapMb.toFixed(1)} MB`, + '', + ], + ] as const + return html`
+

DIAGNOSTICS

+
+ ${repeat( + items, + (item) => item[0], + (item) => + html`
+
${item[0]}
+
${item[1]}
+
`, + )} +
+
` + } +} diff --git a/examples/lit/realtime-trading/src/shell/MarketStatusbar.ts b/examples/lit/realtime-trading/src/shell/MarketStatusbar.ts new file mode 100644 index 0000000000..8c6a569c09 --- /dev/null +++ b/examples/lit/realtime-trading/src/shell/MarketStatusbar.ts @@ -0,0 +1,29 @@ +import { html } from 'lit' +import { customElement, property } from 'lit/decorators.js' +import { ControllerElement } from './controller-element' +import type { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' + +const integer = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }) +@customElement('trading-market-statusbar') +export class MarketStatusbar extends ControllerElement { + @property({ attribute: false }) controller!: TradingBenchmarkController + protected firstUpdated() { + this.observe(this.controller.store) + } + protected render() { + const state = this.controller.store.get() + return html`
+ MESSAGE SAMPLES + ${integer.format(state.metrics.lastBatchSize)}CHANGED ROWS + ${integer.format(state.metrics.lastUpdateCount)}HOSTS ${integer.format(state.mountedCells)}COMPONENTS + ${integer.format(state.liveComponents)} +
` + } +} diff --git a/examples/lit/realtime-trading/src/shell/MetricsStrip.ts b/examples/lit/realtime-trading/src/shell/MetricsStrip.ts new file mode 100644 index 0000000000..6dcb4bb849 --- /dev/null +++ b/examples/lit/realtime-trading/src/shell/MetricsStrip.ts @@ -0,0 +1,65 @@ +import { html } from 'lit' +import { customElement, property } from 'lit/decorators.js' +import { repeat } from 'lit/directives/repeat.js' +import { ControllerElement } from './controller-element' +import type { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' + +const rate = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +const ms = (value: number) => `${value.toFixed(2)} ms` +@customElement('trading-metrics-strip') +export class MetricsStrip extends ControllerElement { + @property({ attribute: false }) controller!: TradingBenchmarkController + protected firstUpdated() { + this.observe(this.controller.store) + } + protected render() { + const state = this.controller.store.get() + const metrics = state.metrics + const items = [ + [ + 'FRAME RATE (EST.)', + metrics.rafCallbacksPerSecond.toFixed(1), + 'rAF callbacks/s · rolling 1 s', + 'frame-rate', + ], + [ + 'AVG COMMIT', + ms(metrics.averageCommitLatencyMs), + 'snapshot → DOM · rolling 3 s', + 'average-commit-latency', + ], + [ + 'LONG FRAMES', + state.longAnimationFramesSupported + ? String(metrics.longAnimationFrames) + : 'N/A', + state.longAnimationFramesSupported + ? `since reset · worst ${ms(metrics.worstLongAnimationFrameMs)}` + : 'unsupported', + 'long-frame-count', + ], + [ + 'THROUGHPUT', + `${rate.format(metrics.rowUpdatesPerSecond)} rows/s`, + `${metrics.stateApplicationsPerSecond.toFixed(1)} snapshots/s · rows deduplicated per snapshot`, + 'throughput-rate', + ], + ] as const + return html`
+

LIVE HEALTH

+ ${repeat( + items, + (item) => item[0], + (item) => + html`
+ ${item[0]}${item[1]}${item[2]} +
`, + )} +
` + } +} diff --git a/examples/lit/realtime-trading/src/shell/SelectedInstrument.ts b/examples/lit/realtime-trading/src/shell/SelectedInstrument.ts new file mode 100644 index 0000000000..4676a16fe5 --- /dev/null +++ b/examples/lit/realtime-trading/src/shell/SelectedInstrument.ts @@ -0,0 +1,50 @@ +import { html } from 'lit' +import { customElement, property } from 'lit/decorators.js' +import { ControllerElement } from './controller-element' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' + +@customElement('trading-selected-instrument') +export class SelectedInstrument extends ControllerElement { + @property({ attribute: false }) controller!: TradingBenchmarkController + @property({ attribute: false }) feed!: MarketFeedController + protected firstUpdated() { + this.observe(this.controller.renderAtoms.selectedSymbol) + this.observe(this.feed.quotes) + } + protected render() { + const quote = this.feed.getQuoteBySymbol( + this.feed.quotes.get(), + this.controller.renderAtoms.selectedSymbol.get(), + ) + return html`
+

SELECTED INSTRUMENT

+ ${ + quote + ? html`
+
+ ${quote.symbol}${quote.company} +
+ ${quote.venue} +
+
+
+
Last
+
${quote.price.toFixed(2)}
+
+
+
Bid / ask
+
${quote.bid.toFixed(2)} / ${quote.ask.toFixed(2)}
+
+
` + : html`

+ Click or begin a cell selection in any row to inspect its + instrument. +

` + } +
` + } +} diff --git a/examples/lit/realtime-trading/src/shell/TradingShell.ts b/examples/lit/realtime-trading/src/shell/TradingShell.ts new file mode 100644 index 0000000000..dc34079d74 --- /dev/null +++ b/examples/lit/realtime-trading/src/shell/TradingShell.ts @@ -0,0 +1,44 @@ +import { html } from 'lit' +import { customElement, property, state } from 'lit/decorators.js' +import { ControllerElement } from './controller-element' +import './AppHeader' +import './Configurator' +import './MarketStatusbar' +import '../table/TradingTable' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' + +@customElement('trading-shell') +export class TradingShell extends ControllerElement { + @property({ attribute: false }) controller!: TradingBenchmarkController + @property({ attribute: false }) feed!: MarketFeedController + @state() private sidebarOpen = true + protected render() { + return html`
+
+ { + this.sidebarOpen = !this.sidebarOpen + }} + >${import.meta.env.DEV ? html`` : null} +
+
+ +
+ + +
` + } +} diff --git a/examples/lit/realtime-trading/src/shell/configurator-options.ts b/examples/lit/realtime-trading/src/shell/configurator-options.ts new file mode 100644 index 0000000000..49a9566fe7 --- /dev/null +++ b/examples/lit/realtime-trading/src/shell/configurator-options.ts @@ -0,0 +1,55 @@ +export interface ConfiguratorOption { + readonly label: string + readonly value: TValue +} + +const instrumentCountOptions = [ + { label: '50', value: 50 }, + { label: '100', value: 100 }, + { label: '150', value: 150 }, + { label: '250', value: 250 }, + { label: '350', value: 350 }, + { label: '500', value: 500 }, + { label: '750', value: 750 }, + { label: '1,000', value: 1_000 }, + { label: '1,500', value: 1_500 }, + { label: '2,500', value: 2_500 }, + { label: '5,000', value: 5_000 }, + { label: '1,000,000', value: 1_000_000 }, + { label: '10,000,000', value: 10_000_000 }, +] as const satisfies ReadonlyArray> + +const workerDeliveryOptions = [ + { label: '8 ms · 125 msg/s', value: 8 }, + { label: '16 ms · 62.5 msg/s', value: 16 }, + { label: '20 ms · 50 msg/s', value: 20 }, + { label: '33 ms · 30 msg/s', value: 33 }, + { label: '50 ms · 20 msg/s', value: 50 }, + { label: '100 ms · 10 msg/s', value: 100 }, + { label: '250 ms · 4 msg/s', value: 250 }, + { label: '500 ms · 2 msg/s', value: 500 }, + { label: '1,000 ms · 1 msg/s', value: 1_000 }, +] as const satisfies ReadonlyArray> + +const rowRenderingOptions = [ + { label: 'Full DOM · render every row', value: 'none' }, + { label: 'TanStack Virtual · visible rows only', value: 'tanstack' }, +] as const satisfies ReadonlyArray> + +const intradaySamplingOptions = [ + { label: '16 ms · fastest', value: 16 }, + { label: '33 ms · very fast', value: 33 }, + { label: '50 ms · fast', value: 50 }, + { label: '100 ms', value: 100 }, + { label: '250 ms', value: 250 }, + { label: '500 ms', value: 500 }, + { label: '1,000 ms', value: 1_000 }, + { label: '2,000 ms', value: 2_000 }, +] as const satisfies ReadonlyArray> + +export const configuratorOptions = { + instrumentCounts: instrumentCountOptions, + workerDeliveryIntervals: workerDeliveryOptions, + rowRenderingModes: rowRenderingOptions, + intradaySamplingIntervals: intradaySamplingOptions, +} as const diff --git a/examples/lit/realtime-trading/src/shell/controller-element.ts b/examples/lit/realtime-trading/src/shell/controller-element.ts new file mode 100644 index 0000000000..01ca122f3c --- /dev/null +++ b/examples/lit/realtime-trading/src/shell/controller-element.ts @@ -0,0 +1,19 @@ +import { LitElement } from 'lit' +import type { Subscription } from '@tanstack/store' + +export abstract class ControllerElement extends LitElement { + readonly #subscriptions: Array = [] + protected createRenderRoot() { + return this + } + protected observe(source: { + subscribe: (listener: () => void) => Subscription + }): void { + this.#subscriptions.push(source.subscribe(() => this.requestUpdate())) + } + disconnectedCallback() { + for (const subscription of this.#subscriptions) subscription.unsubscribe() + this.#subscriptions.length = 0 + super.disconnectedCallback() + } +} diff --git a/examples/lit/realtime-trading/src/table/TradingTable.ts b/examples/lit/realtime-trading/src/table/TradingTable.ts new file mode 100644 index 0000000000..d7c5e01390 --- /dev/null +++ b/examples/lit/realtime-trading/src/table/TradingTable.ts @@ -0,0 +1,394 @@ +import { html } from 'lit' +import { customElement, property } from 'lit/decorators.js' +import { repeat } from 'lit/directives/repeat.js' +import { createRef, ref } from 'lit/directives/ref.js' +import { VirtualizerController } from '@tanstack/lit-virtual' +import { FlexRender, TableController } from '@tanstack/lit-table' +import { startTableBenchmark } from '../benchmark/table-benchmark' +import { ControllerElement } from '../shell/controller-element' +import { + createTradingColumns, + readMeasuredRows, +} from './table-config/trading-columns' +import { tradingFeatures } from './trading-features' +import { + TradingGridPointerController, + handleCellNavigation, + reorderColumnIds, + sortAriaValue, + sortIndicator, +} from './table-interactions' +import { + TRADING_ROW_HEIGHT, + TRADING_ROW_OVERSCAN, + resolveVirtualScrollMode, +} from './trading-row-virtualizer' +import './table-config/quote-cells' +import type { Ref } from 'lit/directives/ref.js' +import type { LitTable } from '@tanstack/lit-table' +import type { MarketQuote } from '../feed/market-data' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' + +interface SelectedTableState { + sorting: unknown + columnFilters: unknown + columnOrder: unknown + rowSelection: unknown + cellSelection: unknown +} +type TradingTableInstance = LitTable< + typeof tradingFeatures, + MarketQuote, + SelectedTableState +> + +@customElement('trading-data-table') +export class TradingTable extends ControllerElement { + @property({ attribute: false }) controller!: TradingBenchmarkController + @property({ attribute: false }) feed!: MarketFeedController + readonly #tableController = new TableController< + typeof tradingFeatures, + MarketQuote + >(this) + readonly #scrollRef: Ref = createRef() + readonly #tableRef: Ref = createRef() + readonly #virtualizer = new VirtualizerController< + HTMLDivElement, + HTMLTableRowElement + >(this, { + count: 0, + getScrollElement: () => this.#scrollRef.value ?? null, + estimateSize: () => TRADING_ROW_HEIGHT, + overscan: TRADING_ROW_OVERSCAN, + }) + readonly #pointer = new TradingGridPointerController() + readonly #drag = { + columnId: null as string | null, + source: null as HTMLTableCellElement | null, + target: null as HTMLTableCellElement | null, + } + readonly #layout = { manuallyResized: false } + #table?: TradingTableInstance + #columns?: ReturnType + #cleanup: Array<() => void> = [] + #domCommitScheduled = false + + protected firstUpdated() { + this.observe(this.feed.quotes) + this.observe(this.feed.instrumentCount) + this.observe(this.controller.store) + this.observe(this.controller.renderAtoms.rendererMode) + this.observe(this.controller.renderAtoms.selectedSymbol) + const table = this.#table + if (!table) return + const sizing = table.atoms.columnSizing.subscribe(() => + this.#writeColumnSizes(), + ) + const order = table.atoms.columnOrder.subscribe(() => + this.#writeColumnSizes(), + ) + const resizing = table.atoms.columnResizing.subscribe((state) => { + if (state.isResizingColumn !== false) this.#layout.manuallyResized = true + }) + const resizeObserver = new ResizeObserver(() => this.#fitAvailableWidth()) + if (this.#scrollRef.value) resizeObserver.observe(this.#scrollRef.value) + this.#cleanup.push( + () => sizing.unsubscribe(), + () => order.unsubscribe(), + () => resizing.unsubscribe(), + () => resizeObserver.disconnect(), + startTableBenchmark(this.controller), + ) + this.#writeColumnSizes() + this.#fitAvailableWidth() + this.#scheduleDomCommit() + } + protected updated() { + this.#writeColumnSizes() + this.#scheduleDomCommit() + } + disconnectedCallback() { + for (const cleanup of this.#cleanup) cleanup() + this.#cleanup.length = 0 + super.disconnectedCallback() + } + + #writeColumnSizes() { + const element = this.#tableRef.value + const table = this.#table + if (!element || !table) return + for (const header of table.getFlatHeaders()) { + element.style.setProperty( + `--header-${header.id}-size`, + String(header.getSize()), + ) + element.style.setProperty( + `--col-${header.column.id}-size`, + String(header.column.getSize()), + ) + } + element.style.width = `${table.getTotalSize()}px` + } + + #scheduleDomCommit() { + if (this.#domCommitScheduled) return + + this.#domCommitScheduled = true + queueMicrotask(() => { + this.#domCommitScheduled = false + if (this.isConnected) this.feed.completeRender() + }) + } + #fitAvailableWidth() { + const container = this.#scrollRef.value + const table = this.#table + if (!container || !table || this.#layout.manuallyResized) return + const width = table.getTotalSize() + if (container.clientWidth <= width + 1 || width <= 0) return + const ratio = container.clientWidth / width + table.setColumnSizing( + Object.fromEntries( + table + .getVisibleLeafColumns() + .map((column) => [column.id, column.getSize() * ratio]), + ), + ) + } + #clearDrag = () => { + this.#drag.source?.classList.remove('is-column-dragging') + this.#drag.target?.classList.remove('is-column-drop-target') + this.#drag.columnId = null + this.#drag.source = null + this.#drag.target = null + } + #showDrop(columnId: string, element: HTMLTableCellElement | null) { + this.#drag.target?.classList.remove('is-column-drop-target') + this.#drag.target = null + if (this.#drag.columnId === columnId || !element) return + element.classList.add('is-column-drop-target') + this.#drag.target = element + } + + protected render() { + this.#columns ??= createTradingColumns(this.controller) + const table = this.#tableController.table( + { + key: 'lit-realtime-trading', + features: tradingFeatures, + columns: this.#columns, + data: this.feed.quotes.get(), + getRowId: (row) => row.id, + columnResizeMode: 'onChange', + defaultColumn: { minSize: 56, maxSize: 800 }, + autoResetCellSelection: false, + }, + (state) => ({ + sorting: state.sorting, + columnFilters: state.columnFilters, + columnOrder: state.columnOrder, + rowSelection: state.rowSelection, + cellSelection: state.cellSelection, + }), + ) + this.#table = table + const rows = readMeasuredRows(() => table.getRowModel().rows) + const benchmark = this.controller.store.get() + const virtualMode = resolveVirtualScrollMode( + benchmark.requestedVirtualScrollMode, + this.feed.instrumentCount.get(), + ) + const virtualizer = this.#virtualizer.getVirtualizer() + virtualizer.setOptions({ + ...virtualizer.options, + count: rows.length, + enabled: virtualMode === 'tanstack', + getItemKey: (index) => rows[index]?.id ?? index, + }) + virtualizer._willUpdate() + const virtualRows = virtualizer.getVirtualItems() + this.controller.actions.setRenderedRowCount( + virtualMode === 'tanstack' ? virtualRows.length : rows.length, + ) + const range = virtualizer.range + const visibleRange = + virtualMode === 'tanstack' && range && rows.length + ? { + start: Math.min(range.startIndex, rows.length - 1), + end: Math.min(range.endIndex, rows.length - 1), + } + : null + const renderRow = ( + row: (typeof rows)[number], + virtualRow?: (typeof virtualRows)[number], + ) => + html` + ${repeat( + row.getVisibleCells(), + (cell) => cell.id, + (cell) => { + const edges = cell.getSelectionEdges() + return html` + ${FlexRender({ cell })} + ` + }, + )} + ` + return html`
+ handleCellNavigation(table, event)} + > + + ${repeat( + table.getHeaderGroups(), + (group) => group.id, + (group) => + html` + ${repeat( + group.headers, + (header) => header.id, + (header) => { + const leaf = header.subHeaders.length === 0 + const sorted = header.column.getIsSorted() + return html`` + }, + )} + `, + )} + + this.#pointer.handleMouseDown(table, event, this.controller.actions.selectSymbol)} + @pointerover=${(event: MouseEvent) => this.#pointer.handlePointerOver(table, event)} + @mouseleave=${() => this.#pointer.resetPointerCell()} + @click=${(event: MouseEvent) => this.#pointer.handleClick(table, event)} + > + ${ + virtualMode === 'tanstack' + ? repeat( + virtualRows, + (item) => item.key, + (item) => renderRow(rows[item.index], item), + ) + : repeat( + rows, + (row) => row.id, + (row) => renderRow(row), + ) + } + +
+ ${ + !header.isPlaceholder + ? leaf + ? html`
{ + event.preventDefault() + this.#showDrop( + header.column.id, + ( + event.currentTarget as HTMLElement + ).closest('th'), + ) + }} + @drop=${(event: DragEvent) => { + event.preventDefault() + const source = + event.dataTransfer?.getData( + 'text/plain', + ) || this.#drag.columnId + if (source) + table.setColumnOrder( + reorderColumnIds( + table + .getVisibleLeafColumns() + .map((column) => column.id), + source, + header.column.id, + ), + ) + this.#clearDrag() + }} + > + +
+ ${header.column.getCanResize() ? html`` : null}` + : FlexRender({ header }) + : null + } +
+
+ ${virtualMode === 'tanstack' ? html`
TanStack · Total · ${rows.length} rows · ${table.getVisibleLeafColumns().length} columns${visibleRange ? `Current · rows ${visibleRange.start}..${visibleRange.end}` : 'Current · rows —'}
` : null}` + } +} diff --git a/examples/lit/realtime-trading/src/table/table-config/quote-cells.ts b/examples/lit/realtime-trading/src/table/table-config/quote-cells.ts new file mode 100644 index 0000000000..e10aa97938 --- /dev/null +++ b/examples/lit/realtime-trading/src/table/table-config/quote-cells.ts @@ -0,0 +1,149 @@ +import { LitElement, html, svg } from 'lit' +import { customElement, property } from 'lit/decorators.js' + +export const quoteCellLifecycle = { created: 0, destroyed: 0 } +export const quoteCellRendererNames = [ + 'Market', + 'Name', + 'Symbol', + 'Last', + 'Change', + 'ChangePercent', + 'Bid', + 'BidVolume', + 'Ask', + 'AskVolume', + 'Open', + 'High', + 'Low', + 'Intraday', +] as const +export const quoteComponentNames = [ + 'PriceCell', + 'StableMoveCell', + 'UpMoveCell', + 'DownMoveCell', + 'PercentChangeCell', + 'SparklineCell', +] as const +export type QuoteCellRendererName = (typeof quoteCellRendererNames)[number] +export type QuoteComponentName = (typeof quoteComponentNames)[number] +const counters = (names: ReadonlyArray) => + Object.fromEntries(names.map((name) => [name, 0])) as Record +export const quoteRenderDiagnostics = { + cellRendererCalls: 0, + componentRenderCalls: 0, + cellRendererCallsByName: counters(quoteCellRendererNames), + componentRenderCallsByName: counters(quoteComponentNames), +} +export function recordCellRender(name: QuoteCellRendererName, value: T): T { + quoteRenderDiagnostics.cellRendererCalls++ + quoteRenderDiagnostics.cellRendererCallsByName[name]++ + return value +} +const signed = (value: number) => `${value >= 0 ? '+' : ''}${value.toFixed(2)}` + +abstract class QuoteElement extends LitElement { + protected abstract readonly componentName: QuoteComponentName + protected createRenderRoot() { + return this + } + connectedCallback() { + super.connectedCallback() + quoteCellLifecycle.created++ + } + disconnectedCallback() { + quoteCellLifecycle.destroyed++ + super.disconnectedCallback() + } + protected recordRender() { + quoteRenderDiagnostics.componentRenderCalls++ + quoteRenderDiagnostics.componentRenderCallsByName[this.componentName]++ + } +} + +@customElement('quote-price-cell') +export class PriceCell extends QuoteElement { + protected readonly componentName = 'PriceCell' + @property({ type: Number }) price = 0 + @property({ type: Number }) move = 0 + @property({ attribute: false }) select: () => void = () => undefined + protected render() { + this.recordRender() + return html`` + } +} + +abstract class MoveCell extends QuoteElement { + @property({ type: Number }) move = 0 + protected direction: 'up' | 'down' | null = null + protected indicator = '' + protected render() { + this.recordRender() + const direction = this.direction ?? (this.move >= 0 ? 'up' : 'down') + return html`${this.indicator}${signed(this.move)}` + } +} +@customElement('quote-stable-move') +export class StableMoveCell extends MoveCell { + protected readonly componentName = 'StableMoveCell' +} +@customElement('quote-up-move') +export class UpMoveCell extends MoveCell { + protected readonly componentName = 'UpMoveCell' + protected direction = 'up' as const + protected indicator = '▲ ' +} +@customElement('quote-down-move') +export class DownMoveCell extends MoveCell { + protected readonly componentName = 'DownMoveCell' + protected direction = 'down' as const + protected indicator = '▼ ' +} + +@customElement('quote-percent-change') +export class PercentChangeCell extends QuoteElement { + protected readonly componentName = 'PercentChangeCell' + @property({ type: Number }) value = 0 + protected render() { + this.recordRender() + return html`${signed(this.value)}%` + } +} + +@customElement('quote-sparkline') +export class SparklineCell extends QuoteElement { + protected readonly componentName = 'SparklineCell' + @property({ attribute: false }) values: ReadonlyArray = [] + protected render() { + this.recordRender() + const first = this.values[0] ?? 0 + const range = this.values.reduce( + (current, value) => ({ + min: Math.min(current.min, value), + max: Math.max(current.max, value), + }), + { min: first, max: first }, + ) + const height = range.max - range.min || 1 + const denominator = Math.max(1, this.values.length - 1) + const points = this.values + .map( + (value, index) => + `${((index / denominator) * 100).toFixed(1)},${(22 - ((value - range.min) / height) * 20).toFixed(1)}`, + ) + .join(' ') + const rising = (this.values.at(-1) ?? 0) >= first + return svg`` + } +} diff --git a/examples/lit/realtime-trading/src/table/table-config/trading-columns.ts b/examples/lit/realtime-trading/src/table/table-config/trading-columns.ts new file mode 100644 index 0000000000..93d52876d3 --- /dev/null +++ b/examples/lit/realtime-trading/src/table/table-config/trading-columns.ts @@ -0,0 +1,212 @@ +import { html } from 'lit' +import { createColumnHelper } from '@tanstack/lit-table' +import { tradingFeatures } from '../trading-features' +import { recordCellRender } from './quote-cells' +import type { MarketQuote } from '../../feed/market-data' +import type { TradingBenchmarkController } from '../../benchmark/trading-benchmark-controller' + +export type RendererMode = 'stable' | 'swap' +export interface CoreTableState { + sorting: Array<{ id: string; desc: boolean }> + columnFilters: Array<{ id: string; value: unknown }> +} +const compact = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +const columnHelper = createColumnHelper() + +export function createTradingColumns(controller: TradingBenchmarkController) { + return columnHelper.columns([ + columnHelper.group({ + id: 'instrument', + header: 'Instrument', + columns: columnHelper.columns([ + columnHelper.accessor('venue', { + id: 'market', + header: 'Market', + size: 72, + cell: (info) => recordCellRender('Market', info.getValue()), + }), + columnHelper.accessor('company', { + id: 'name', + header: 'Name', + size: 180, + cell: (info) => recordCellRender('Name', info.getValue()), + }), + columnHelper.accessor('symbol', { + header: 'Symbol', + size: 92, + filterFn: 'includesString', + cell: (info) => recordCellRender('Symbol', info.getValue()), + }), + ]), + }), + columnHelper.group({ + id: 'priceAndChange', + header: 'Price & Change', + columns: columnHelper.columns([ + columnHelper.accessor('price', { + header: 'Price', + size: 96, + sortFn: 'basic', + cell: (info) => + recordCellRender( + 'Last', + html` + controller.actions.selectSymbol(info.row.original.symbol)} + >`, + ), + }), + columnHelper.accessor(getDayChange, { + id: 'change', + header: 'Chg', + size: 94, + cell: (info) => + recordCellRender( + 'Change', + renderMove( + controller.renderAtoms.rendererMode.get(), + info.getValue(), + ), + ), + }), + columnHelper.accessor(getDayChangePercent, { + id: 'changePercent', + header: 'Chg%', + size: 90, + cell: (info) => + recordCellRender( + 'ChangePercent', + html``, + ), + }), + ]), + }), + columnHelper.group({ + id: 'orderBook', + header: 'Order Book', + columns: columnHelper.columns([ + columnHelper.accessor('bid', { + header: 'Bid', + size: 90, + cell: (info) => recordCellRender('Bid', info.getValue().toFixed(2)), + }), + columnHelper.accessor('bidSize', { + header: 'Bid Vol', + size: 100, + cell: (info) => + recordCellRender('BidVolume', compact.format(info.getValue())), + }), + columnHelper.accessor('ask', { + header: 'Ask', + size: 90, + cell: (info) => recordCellRender('Ask', info.getValue().toFixed(2)), + }), + columnHelper.accessor('askSize', { + header: 'Ask Vol', + size: 100, + cell: (info) => + recordCellRender('AskVolume', compact.format(info.getValue())), + }), + ]), + }), + columnHelper.group({ + id: 'session', + header: 'Session', + columns: columnHelper.columns([ + columnHelper.accessor('open', { + header: 'Open', + size: 90, + cell: (info) => recordCellRender('Open', info.getValue().toFixed(2)), + }), + columnHelper.accessor('high', { + header: 'High', + size: 90, + cell: (info) => recordCellRender('High', info.getValue().toFixed(2)), + }), + columnHelper.accessor('low', { + header: 'Low', + size: 90, + cell: (info) => recordCellRender('Low', info.getValue().toFixed(2)), + }), + ]), + }), + columnHelper.group({ + id: 'chart', + header: 'Chart', + columns: columnHelper.columns([ + columnHelper.accessor('history', { + header: 'Intraday', + size: 150, + enableSorting: false, + cell: (info) => + recordCellRender( + 'Intraday', + html``, + ), + }), + ]), + }), + ]) +} + +function renderMove(mode: RendererMode, move: number) { + if (mode === 'stable') + return html`` + return move >= 0 + ? html`` + : html`` +} + +export const rowModelDiagnostics = { + hasMeasurement: false, + calls: 0, + totalDurationMs: 0, + maxDurationMs: 0, + lastRowCount: 0, +} +export const TRADING_COLUMN_COUNT = 14 +export function readMeasuredRows(readRows: () => Array): Array { + const start = performance.now() + const rows = readRows() + const end = performance.now() + const duration = end - start + rowModelDiagnostics.calls++ + rowModelDiagnostics.hasMeasurement = true + rowModelDiagnostics.totalDurationMs += duration + rowModelDiagnostics.maxDurationMs = Math.max( + rowModelDiagnostics.maxDurationMs, + duration, + ) + rowModelDiagnostics.lastRowCount = rows.length + if (rowModelDiagnostics.calls % 20 === 0) { + try { + performance.measure('tanstack-row-model', { + start, + end, + detail: { rowCount: rows.length }, + }) + if (rowModelDiagnostics.calls % 1_000 === 0) + performance.clearMeasures('tanstack-row-model') + } catch { + /* optional sampled User Timing detail */ + } + } + return rows +} +export function getDayChange(quote: MarketQuote): number { + return quote.price - quote.previousClose +} +export function getDayChangePercent(quote: MarketQuote): number { + return quote.previousClose === 0 + ? 0 + : (getDayChange(quote) / quote.previousClose) * 100 +} diff --git a/examples/lit/realtime-trading/src/table/table-interactions.ts b/examples/lit/realtime-trading/src/table/table-interactions.ts new file mode 100644 index 0000000000..99649a40bd --- /dev/null +++ b/examples/lit/realtime-trading/src/table/table-interactions.ts @@ -0,0 +1,187 @@ +export type CellDirection = 'up' | 'down' | 'left' | 'right' + +interface RowSelectionTable { + resetRowSelection: (defaultState?: boolean) => void +} + +interface SelectableRow { + getIsSelected: () => boolean + getToggleSelectedHandler: (options?: { + selectChildren?: boolean + }) => (event: unknown) => void +} + +interface SelectableGridCell { + row: SelectableGridRow + getSelectionStartHandler: ( + contextDocument?: Document, + ) => (event: unknown) => void + getSelectionExtendHandler: () => (event: unknown) => void +} + +interface SelectableGridRow extends SelectableRow { + original: { symbol: string } + getAllCellsByColumnId: () => Record +} + +interface TradingGridTable extends RowSelectionTable { + getRowModel: () => { + rowsById: Record + } +} + +interface SelectionCellTarget { + element: HTMLTableCellElement + cell: SelectableGridCell +} + +interface CellNavigationTable { + extendCellSelection: (direction: CellDirection) => void + moveCellSelection: (direction: CellDirection) => void + resetCellSelection: (defaultState?: boolean) => void + selectAllCells: () => void +} + +const keyDirections: Partial> = { + ArrowUp: 'up', + ArrowDown: 'down', + ArrowLeft: 'left', + ArrowRight: 'right', +} + +export function reorderColumnIds( + columnIds: Array, + sourceId: string, + targetId: string, +): Array { + if (sourceId === targetId || !columnIds.includes(sourceId)) return columnIds + + const withoutSource = columnIds.filter((id) => id !== sourceId) + const targetIndex = withoutSource.indexOf(targetId) + if (targetIndex < 0) return columnIds + + return [ + ...withoutSource.slice(0, targetIndex), + sourceId, + ...withoutSource.slice(targetIndex), + ] +} + +export function selectRowFromPointer( + table: RowSelectionTable, + row: SelectableRow, + event: MouseEvent, +): void { + const additive = event.ctrlKey || event.metaKey + const checked = additive ? !row.getIsSelected() : true + + if (!event.shiftKey && !additive) table.resetRowSelection(true) + + row.getToggleSelectedHandler({ selectChildren: false })({ + target: { checked }, + shiftKey: event.shiftKey, + ctrlKey: event.ctrlKey, + metaKey: event.metaKey, + }) +} + +export class TradingGridPointerController { + #lastPointerCell: HTMLTableCellElement | null = null + + handleMouseDown( + table: TradingGridTable, + event: MouseEvent, + selectSymbol: (symbol: string) => void, + ): void { + if (event.button !== 0) return + + const target = this.#findCellTarget(table, event.composedPath()) + if (!target) return + + event.preventDefault() + this.#lastPointerCell = target.element + selectSymbol(target.cell.row.original.symbol) + target.cell.getSelectionStartHandler(target.element.ownerDocument)(event) + } + + handlePointerOver(table: TradingGridTable, event: MouseEvent): void { + if ((event.buttons & 1) === 0) { + this.resetPointerCell() + return + } + + const target = this.#findCellTarget(table, event.composedPath()) + if (!target || target.element === this.#lastPointerCell) return + + this.#lastPointerCell = target.element + target.cell.getSelectionExtendHandler()(event) + } + + handleClick(table: TradingGridTable, event: MouseEvent): void { + const target = this.#findCellTarget(table, event.composedPath()) + if (!target) return + selectRowFromPointer(table, target.cell.row, event) + } + + resetPointerCell(): void { + this.#lastPointerCell = null + } + + #findCellTarget( + table: TradingGridTable, + path: Array, + ): SelectionCellTarget | null { + for (const target of path) { + if (!(target instanceof HTMLTableCellElement)) continue + + const columnId = target.dataset['columnId'] + const rowId = + target.closest('tr[data-row-id]')?.dataset['rowId'] + if (!columnId || !rowId) return null + + const row = table.getRowModel().rowsById[rowId] + const cell = row.getAllCellsByColumnId()[columnId] + return { element: target, cell } + } + + return null + } +} + +export function handleCellNavigation( + table: CellNavigationTable, + event: KeyboardEvent, +): void { + if (event.key === 'Escape') { + event.preventDefault() + table.resetCellSelection(true) + return + } + + if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'a') { + event.preventDefault() + table.selectAllCells() + return + } + + const direction = keyDirections[event.key] + if (!direction) return + + event.preventDefault() + if (event.shiftKey) table.extendCellSelection(direction) + else table.moveCellSelection(direction) +} + +export function sortIndicator(direction: false | 'asc' | 'desc'): string { + if (direction === 'asc') return '↑' + if (direction === 'desc') return '↓' + return '↕' +} + +export function sortAriaValue( + direction: false | 'asc' | 'desc', +): 'ascending' | 'descending' | 'none' { + if (direction === 'asc') return 'ascending' + if (direction === 'desc') return 'descending' + return 'none' +} diff --git a/examples/lit/realtime-trading/src/table/trading-features.ts b/examples/lit/realtime-trading/src/table/trading-features.ts new file mode 100644 index 0000000000..790e9a816b --- /dev/null +++ b/examples/lit/realtime-trading/src/table/trading-features.ts @@ -0,0 +1,16 @@ +import { + createFilteredRowModel, + createSortedRowModel, + filterFn_includesString, + sortFn_basic, + stockFeatures, + tableFeatures, +} from '@tanstack/lit-table' + +export const tradingFeatures = tableFeatures({ + ...stockFeatures, + filteredRowModel: createFilteredRowModel(), + sortedRowModel: createSortedRowModel(), + filterFns: { includesString: filterFn_includesString }, + sortFns: { basic: sortFn_basic }, +}) diff --git a/examples/lit/realtime-trading/src/table/trading-row-virtualizer.ts b/examples/lit/realtime-trading/src/table/trading-row-virtualizer.ts new file mode 100644 index 0000000000..bc4b34b528 --- /dev/null +++ b/examples/lit/realtime-trading/src/table/trading-row-virtualizer.ts @@ -0,0 +1,18 @@ +export const TRADING_ROW_HEIGHT = 32 +export const TRADING_ROW_OVERSCAN = 10 +export const DEFAULT_VIRTUALIZATION_ROW_COUNT = 200 +export const FORCED_VIRTUALIZATION_ROW_COUNT = 1_500 + +export type VirtualScrollMode = 'tanstack' | 'none' +export type VirtualScrollPreference = VirtualScrollMode | 'auto' + +export function resolveVirtualScrollMode( + requestedMode: VirtualScrollPreference, + instrumentCount: number, +): VirtualScrollMode { + if (instrumentCount >= FORCED_VIRTUALIZATION_ROW_COUNT) return 'tanstack' + if (requestedMode !== 'auto') return requestedMode + return instrumentCount >= DEFAULT_VIRTUALIZATION_ROW_COUNT + ? 'tanstack' + : 'none' +} diff --git a/examples/lit/realtime-trading/src/table/trading-table.ts b/examples/lit/realtime-trading/src/table/trading-table.ts new file mode 100644 index 0000000000..77e4e6bee1 --- /dev/null +++ b/examples/lit/realtime-trading/src/table/trading-table.ts @@ -0,0 +1,9 @@ +export { + TRADING_COLUMN_COUNT, + rowModelDiagnostics, +} from './table-config/trading-columns' +export type { + CoreTableState, + RendererMode, +} from './table-config/trading-columns' +export type { VirtualScrollMode } from './trading-row-virtualizer' diff --git a/examples/lit/realtime-trading/src/vite-env.d.ts b/examples/lit/realtime-trading/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/lit/realtime-trading/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/lit/realtime-trading/tests/e2e/smoke.spec.ts b/examples/lit/realtime-trading/tests/e2e/smoke.spec.ts new file mode 100644 index 0000000000..7d3ccb214a --- /dev/null +++ b/examples/lit/realtime-trading/tests/e2e/smoke.spec.ts @@ -0,0 +1,183 @@ +import path from 'node:path' +import { expect, test } from '@playwright/test' +import { startExampleServer } from '../../../../../tests/e2e/helpers/startExampleServer' +import { + setRangeValue, + scrollTradingTable, +} from '../../../../../tests/e2e/helpers/setRangeValue' +import type { Page } from '@playwright/test' + +const exampleDir = path.resolve() + +function collectPageErrors(page: Page) { + const errors: Array = [] + page.on('pageerror', (error) => errors.push(error.message)) + page.on('console', (message) => { + if (message.type() === 'error') errors.push(message.text()) + }) + return errors +} + +test('runs the Lit realtime trading workload', async ({ page }) => { + const server = await startExampleServer(exampleDir) + const errors = collectPageErrors(page) + + try { + await page.goto(server.url) + + const table = page.getByTestId('trading-table') + const instrumentCount = page.getByTestId('instrument-count-select') + const virtualScrollSelect = page.getByTestId('virtual-scroll-select') + await expect(table).toBeVisible() + await expect(instrumentCount).toHaveValue('100') + await expect(page.locator('.brand')).toHaveText('MARKET MONITOR') + await expect(virtualScrollSelect).toHaveValue('none') + await expect(virtualScrollSelect).toBeEnabled() + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(table.locator('tbody')).toHaveCSS('user-select', 'none') + await expect(table.locator('tbody tr').first()).toHaveCSS( + 'content-visibility', + 'auto', + ) + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await instrumentCount.selectOption('250') + await expect(virtualScrollSelect).toHaveValue('tanstack') + await expect(virtualScrollSelect).toBeEnabled() + await expect.poll(() => table.locator('tbody tr').count()).toBeLessThan(250) + await expect(page.getByTestId('virtual-scroll-footer')).toBeVisible() + await instrumentCount.selectOption('100') + await expect(virtualScrollSelect).toHaveValue('none') + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await virtualScrollSelect.selectOption('tanstack') + await expect.poll(() => table.locator('tbody tr').count()).toBeLessThan(100) + await expect(table.locator('tbody tr').first()).toHaveCSS( + 'content-visibility', + 'auto', + ) + await expect(page.getByTestId('virtual-scroll-footer')).toBeVisible() + await virtualScrollSelect.selectOption('none') + await expect(table.locator('tbody tr')).toHaveCount(100) + await instrumentCount.selectOption('1500') + await expect(virtualScrollSelect).toHaveValue('tanstack') + await expect(virtualScrollSelect).toBeDisabled() + await expect + .poll(() => table.locator('tbody tr').count()) + .toBeLessThan(1500) + await expect(page.getByTestId('virtual-scroll-footer')).toContainText( + 'Total · 1500 rows · 14 columns', + ) + await expect(page.getByTestId('visible-row-range')).toHaveText( + /^\s*Current · rows 0\.\.\d+\s*$/, + ) + await scrollTradingTable(page, 2_000) + await expect + .poll(async () => + Number( + await table + .locator('tbody tr') + .first() + .getAttribute('data-virtual-index'), + ), + ) + .toBeGreaterThan(0) + await expect(page.getByTestId('visible-row-range')).toHaveText( + /^\s*Current · rows [1-9]\d*\.\.\d+\s*$/, + ) + await instrumentCount.selectOption('100') + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await expect(virtualScrollSelect).toHaveValue('none') + await expect(virtualScrollSelect).toBeEnabled() + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(table.locator('thead tr')).toHaveCount(2) + await expect(table.locator('thead tr').last().locator('th')).toHaveCount(14) + await expect(table.locator('thead')).not.toContainText('Identity') + await expect(table.locator('thead')).not.toContainText('Market Data') + await expect(table.locator('thead')).toContainText('Market') + await expect(table.locator('thead')).toContainText('Bid Vol') + await expect(table.locator('thead')).toContainText('Intraday') + const selectedRow = table.locator('tbody tr').first() + const selectedSymbol = await selectedRow.getAttribute('data-symbol') + await selectedRow.locator('td').nth(1).click() + await expect(page.getByTestId('selected-instrument')).toContainText( + selectedSymbol ?? '', + ) + await expect(page.getByTestId('feed-status')).toHaveText('FEED LIVE') + await expect(instrumentCount.locator('option[value="150"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="350"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="750"]')).toHaveCount(1) + + const targetRateSlider = page.getByTestId('target-rate-slider') + await expect(targetRateSlider).toHaveAttribute('min', '0') + await expect(targetRateSlider).toHaveAttribute('max', '9') + await expect(targetRateSlider).toHaveAttribute('step', '1') + await expect(targetRateSlider).toHaveValue('6') + await setRangeValue(targetRateSlider, '7') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '25K samples/s', + ) + await setRangeValue(targetRateSlider, '8') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '50K samples/s', + ) + await setRangeValue(targetRateSlider, '6') + + const sparklineInterval = page.getByTestId( + 'sparkline-sample-interval-select', + ) + await expect(sparklineInterval).toHaveValue('16') + await sparklineInterval.selectOption('100') + await expect(sparklineInterval).toHaveValue('100') + await sparklineInterval.selectOption('16') + + const publishInterval = page.getByTestId('publish-interval-select') + await expect(publishInterval.locator('option[value="500"]')).toHaveCount(1) + await expect(publishInterval.locator('option[value="1000"]')).toHaveCount(1) + + await expect + .poll(async () => { + const text = await page.getByTestId('row-update-rate').textContent() + return Number(text?.replace(/\D/g, '') ?? 0) + }) + .toBeGreaterThan(0) + await expect + .poll(async () => { + const text = await page.getByTestId('worker-messages').textContent() + return Number(text?.replace(/\D/g, '') ?? 0) + }) + .toBeGreaterThan(0) + await expect + .poll(async () => + Number(await page.getByTestId('message-rate').textContent()), + ) + .toBeGreaterThan(0) + await expect + .poll(async () => + Number(await page.getByTestId('table-render-rate').textContent()), + ) + .toBeGreaterThan(0) + + const firstPrice = page.locator('tbody tr').first().getByRole('button') + const priceBeforeUpdate = await firstPrice.textContent() + await expect + .poll(() => firstPrice.textContent()) + .not.toBe(priceBeforeUpdate) + + await page.locator('.config-section input[type="checkbox"]').first().check() + await page.getByTestId('feed-toggle').click() + await expect(page.getByTestId('feed-toggle')).toHaveText('START FEED') + await expect(page.getByTestId('feed-status')).toHaveText('FEED PAUSED') + + await instrumentCount.selectOption('750') + await expect.poll(() => table.locator('tbody tr').count()).toBeLessThan(750) + expect( + await page.evaluate( + () => performance.getEntriesByName('tanstack-row-model').length > 0, + ), + ).toBe(true) + + expect(errors).toEqual([]) + } finally { + await server.close() + } +}) diff --git a/examples/lit/realtime-trading/tsconfig.json b/examples/lit/realtime-trading/tsconfig.json new file mode 100644 index 0000000000..91eacfe230 --- /dev/null +++ b/examples/lit/realtime-trading/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": false, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "experimentalDecorators": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] + }, + "include": ["src", "tests/e2e", "vite.config.ts"] +} diff --git a/examples/lit/realtime-trading/vite.config.ts b/examples/lit/realtime-trading/vite.config.ts new file mode 100644 index 0000000000..7af6c0bce8 --- /dev/null +++ b/examples/lit/realtime-trading/vite.config.ts @@ -0,0 +1,2 @@ +import { defineConfig } from 'vite' +export default defineConfig({ server: { port: 7777, allowedHosts: true } }) diff --git a/examples/lit/row-pinning/package.json b/examples/lit/row-pinning/package.json index 894759de21..5ef3d99ae6 100644 --- a/examples/lit/row-pinning/package.json +++ b/examples/lit/row-pinning/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/row-selection/package.json b/examples/lit/row-selection/package.json index 797a8efba9..f26fab6b75 100644 --- a/examples/lit/row-selection/package.json +++ b/examples/lit/row-selection/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/sorting-dynamic-data/package.json b/examples/lit/sorting-dynamic-data/package.json index 22087ccb9f..093baf6c3e 100644 --- a/examples/lit/sorting-dynamic-data/package.json +++ b/examples/lit/sorting-dynamic-data/package.json @@ -11,13 +11,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/sorting/package.json b/examples/lit/sorting/package.json index 7c8ea5a6f8..9197969cde 100644 --- a/examples/lit/sorting/package.json +++ b/examples/lit/sorting/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/sub-components/package.json b/examples/lit/sub-components/package.json index 1f9551df75..651891986a 100644 --- a/examples/lit/sub-components/package.json +++ b/examples/lit/sub-components/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/virtualized-columns/package.json b/examples/lit/virtualized-columns/package.json index 2e48756ec8..5bf39187f8 100644 --- a/examples/lit/virtualized-columns/package.json +++ b/examples/lit/virtualized-columns/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", - "@tanstack/lit-virtual": "^3.13.36", + "@tanstack/lit-virtual": "^3.13.37", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/virtualized-infinite-scrolling/package.json b/examples/lit/virtualized-infinite-scrolling/package.json index 92983e17b2..a0e8d925f4 100644 --- a/examples/lit/virtualized-infinite-scrolling/package.json +++ b/examples/lit/virtualized-infinite-scrolling/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", - "@tanstack/lit-virtual": "^3.13.36", + "@tanstack/lit-virtual": "^3.13.37", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/lit/virtualized-rows/package.json b/examples/lit/virtualized-rows/package.json index 11a67e97f3..c9641cb57a 100644 --- a/examples/lit/virtualized-rows/package.json +++ b/examples/lit/virtualized-rows/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/lit-table": "^9.2.3", - "@tanstack/lit-virtual": "^3.13.36", + "@tanstack/lit-virtual": "^3.13.37", "lit": "^3.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/aggregation/package.json b/examples/octane/aggregation/package.json index 4aae8637af..c38ed30437 100644 --- a/examples/octane/aggregation/package.json +++ b/examples/octane/aggregation/package.json @@ -11,14 +11,15 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-store": "^0.12.2", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/basic-dynamic-columns/package.json b/examples/octane/basic-dynamic-columns/package.json index 962c68d24b..3fef403201 100644 --- a/examples/octane/basic-dynamic-columns/package.json +++ b/examples/octane/basic-dynamic-columns/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/basic-external-atoms/package.json b/examples/octane/basic-external-atoms/package.json index 1f8cc1714e..c320eda308 100644 --- a/examples/octane/basic-external-atoms/package.json +++ b/examples/octane/basic-external-atoms/package.json @@ -11,14 +11,15 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-store": "^0.12.2", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/basic-external-state/package.json b/examples/octane/basic-external-state/package.json index 7de5a6bc53..ea813a8f37 100644 --- a/examples/octane/basic-external-state/package.json +++ b/examples/octane/basic-external-state/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/basic-subscribe/package.json b/examples/octane/basic-subscribe/package.json index caa469a045..29733812f1 100644 --- a/examples/octane/basic-subscribe/package.json +++ b/examples/octane/basic-subscribe/package.json @@ -11,14 +11,15 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-store": "^0.12.2", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/basic-use-app-table/package.json b/examples/octane/basic-use-app-table/package.json index 4f732c7752..897abf6779 100644 --- a/examples/octane/basic-use-app-table/package.json +++ b/examples/octane/basic-use-app-table/package.json @@ -15,8 +15,9 @@ "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/basic-use-table/package.json b/examples/octane/basic-use-table/package.json index 2f2ae3bd5e..48f03cc0ae 100644 --- a/examples/octane/basic-use-table/package.json +++ b/examples/octane/basic-use-table/package.json @@ -15,8 +15,9 @@ "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/cell-spanning/package.json b/examples/octane/cell-spanning/package.json index f371b884bb..5948739ec9 100644 --- a/examples/octane/cell-spanning/package.json +++ b/examples/octane/cell-spanning/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/column-ordering/package.json b/examples/octane/column-ordering/package.json index 8ebd09a923..e9e4c21b2c 100644 --- a/examples/octane/column-ordering/package.json +++ b/examples/octane/column-ordering/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/column-pinning-split/package.json b/examples/octane/column-pinning-split/package.json index 8493af2dcb..249bf53d8e 100644 --- a/examples/octane/column-pinning-split/package.json +++ b/examples/octane/column-pinning-split/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/column-pinning-sticky/package.json b/examples/octane/column-pinning-sticky/package.json index 3f4af61bfb..e6186f1c18 100644 --- a/examples/octane/column-pinning-sticky/package.json +++ b/examples/octane/column-pinning-sticky/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/column-pinning/package.json b/examples/octane/column-pinning/package.json index 372c2d235b..2de57cec79 100644 --- a/examples/octane/column-pinning/package.json +++ b/examples/octane/column-pinning/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/column-resizing-performant/package.json b/examples/octane/column-resizing-performant/package.json index 9ce654bd8c..75a0a4f75c 100644 --- a/examples/octane/column-resizing-performant/package.json +++ b/examples/octane/column-resizing-performant/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/column-resizing/package.json b/examples/octane/column-resizing/package.json index 07f2b24c53..0124498b25 100644 --- a/examples/octane/column-resizing/package.json +++ b/examples/octane/column-resizing/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/column-sizing/package.json b/examples/octane/column-sizing/package.json index fe09caa79d..d6c91f125a 100644 --- a/examples/octane/column-sizing/package.json +++ b/examples/octane/column-sizing/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/column-visibility/package.json b/examples/octane/column-visibility/package.json index ae5a9cc6f2..8f3556c898 100644 --- a/examples/octane/column-visibility/package.json +++ b/examples/octane/column-visibility/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/composable-tables/package.json b/examples/octane/composable-tables/package.json index 897fee23e7..4544973206 100644 --- a/examples/octane/composable-tables/package.json +++ b/examples/octane/composable-tables/package.json @@ -11,14 +11,15 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-store": "^0.12.2", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/custom-plugin/package.json b/examples/octane/custom-plugin/package.json index 80a3997d73..7f4cb38682 100644 --- a/examples/octane/custom-plugin/package.json +++ b/examples/octane/custom-plugin/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/expanding/package.json b/examples/octane/expanding/package.json index 174602a859..93dae76e9d 100644 --- a/examples/octane/expanding/package.json +++ b/examples/octane/expanding/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/filters-faceted-bucketed/package.json b/examples/octane/filters-faceted-bucketed/package.json index f8fce07031..9eb7c19afe 100644 --- a/examples/octane/filters-faceted-bucketed/package.json +++ b/examples/octane/filters-faceted-bucketed/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/filters-faceted/package.json b/examples/octane/filters-faceted/package.json index 3017539fb0..b7bec82afb 100644 --- a/examples/octane/filters-faceted/package.json +++ b/examples/octane/filters-faceted/package.json @@ -11,14 +11,15 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/filters-fuzzy/package.json b/examples/octane/filters-fuzzy/package.json index 4aa54207d1..e36068d338 100644 --- a/examples/octane/filters-fuzzy/package.json +++ b/examples/octane/filters-fuzzy/package.json @@ -11,14 +11,15 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/filters/package.json b/examples/octane/filters/package.json index a4b7ae2e64..31c961a9b2 100644 --- a/examples/octane/filters/package.json +++ b/examples/octane/filters/package.json @@ -11,14 +11,15 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/grouped-aggregation/package.json b/examples/octane/grouped-aggregation/package.json index 65dcb8100f..160e48b29e 100644 --- a/examples/octane/grouped-aggregation/package.json +++ b/examples/octane/grouped-aggregation/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/grouping/package.json b/examples/octane/grouping/package.json index bd53704258..d6f008d6ed 100644 --- a/examples/octane/grouping/package.json +++ b/examples/octane/grouping/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/header-groups/package.json b/examples/octane/header-groups/package.json index fade0f0e25..424b7d9218 100644 --- a/examples/octane/header-groups/package.json +++ b/examples/octane/header-groups/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/kitchen-sink/package.json b/examples/octane/kitchen-sink/package.json index 90a1a96991..b2a25bdc53 100644 --- a/examples/octane/kitchen-sink/package.json +++ b/examples/octane/kitchen-sink/package.json @@ -11,14 +11,15 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/pagination/package.json b/examples/octane/pagination/package.json index 3c7f7d463a..f226947d17 100644 --- a/examples/octane/pagination/package.json +++ b/examples/octane/pagination/package.json @@ -11,14 +11,15 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-store": "^0.12.2", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/realtime-trading/README.md b/examples/octane/realtime-trading/README.md new file mode 100644 index 0000000000..71637a3ba2 --- /dev/null +++ b/examples/octane/realtime-trading/README.md @@ -0,0 +1,157 @@ +# Octane realtime trading benchmark + +This standalone example exercises the current TanStack Octane Table adapter +with a high-frequency worker feed, immutable snapshots, interactive columns, +custom TSRX cells, Virtual Core, and browser diagnostics. It is a repeatable UI +stress workload rather than an exchange/network simulator. + +## Run and verify + +```bash +pnpm --dir examples/octane/realtime-trading dev +``` + +Open `http://localhost:7777`. + +```bash +pnpm --dir examples/octane/realtime-trading test:types +pnpm --dir examples/octane/realtime-trading lint +pnpm --dir examples/octane/realtime-trading build +pnpm --dir examples/octane/realtime-trading test:e2e +``` + +Use a production build for representative measurements. + +## Structure and ownership + +| Path | Responsibility | +| ------------------------- | ------------------------------------------------------------------------------------------------------------ | +| `src/feed/` | Market model, instruments, feed config, immutable update helpers, and direct TanStack atom feed controller. | +| `src/feed/worker/` | Typed protocol, deterministic engine, and module worker. | +| `src/benchmark/` | Browser monitor, benchmark controller, table observer, and row-model timing. | +| `src/shell/` | Separate TSRX header, metrics, configurator, diagnostics, selected-instrument, status, and shell components. | +| `src/table/table-config/` | Grouped columns and custom TSRX quote components. | +| `src/table/` | Octane Table view/setup, interactions, pointer hook, column layout, and Virtual Core hook. | +| `src/main.tsrx` | Creates controllers and renders the shell composition root. | + +`MarketFeedController` owns feed/worker state. `TradingBenchmarkController` +observes it and owns diagnostic/view state. The shell receives stable controller +objects; individual components call `useSelector` from `@tanstack/octane-store` for +the values they need. Quotes, feed status, row count, workload, delivery, and +chart controls are direct independent atoms. The table subscribes to `quotes` +and `instrumentCount`, so a configurator/status update cannot invalidate table +data. Benchmark metrics remain an aggregate snapshot store. + +## Feed and worker pipeline + +Defaults are 100 instruments, 10K generated samples/s, 20 ms delivery, enabled +intraday charts, and 16 ms chart sampling. + +The worker keeps mutable quote state private. A deterministic 16 ms budget loop +generates samples, and a row-indexed `Map` coalesces repeated updates. A separate +publication timer posts the latest unique rows. The main thread creates a new +outer array and replaces only changed row objects; untouched rows and unsampled +history arrays retain their references. Session IDs discard stale batches after +reset or instrument-count changes. + +- **Synthetic quote workload** means generated worker samples/s, not messages, + events, or component renders. +- **Worker delivery interval** controls coalesced message cadence; 20 ms targets + about 50 messages/s. +- **Row updates** counts unique immutable rows applied on the main thread. +- **Message samples** is the generated work represented by the latest message. + +The 25K burst immediately generates and flushes one deliberately heavy batch. +The worker approximates an upstream stream but does not measure network delay. + +## Octane table architecture + +The table has 14 leaf columns grouped into Instrument, Price & Change, Order +Book, Session, and Chart. Sorting/filtering, on-change resizing, double-click +reset, drag ordering, CSS row hover, row selection, drag cell ranges, keyboard +navigation, and custom Price/Move/Percent/Sparkline components are included. + +Stable instrument IDs back `getRowId`. Table, row, header, and quote component +boundaries keep ownership explicit. A local hook delegates pointer handling at +the body and stores transient drag state without publishing render state. It +resolves a cell through `event.composedPath()` and data attributes rather than +installing per-cell listeners. + +Column widths are table CSS variables updated only for sizing/order. A +`ResizeObserver` performs the initial fit and stops auto-fitting after manual +resize. The move A/B option deliberately changes component type to measure +creation/destruction; stable mode is the realistic baseline. + +## Virtualization + +- Below 200 rows, automatic mode resolves to Full DOM, while Virtual is + selectable. +- From 200 through 1,499 rows, automatic mode resolves to TanStack Virtual and + Full DOM remains selectable. +- At 1,500 rows or more, Virtual is forced and the control is locked. + +The local `useVirtualizer` bridge owns one `@tanstack/virtual-core` instance. +It updates options in place, mounts/unmounts through Octane layout effects, and +increments a local render version on virtualizer changes. Configuration uses a +32 px estimate, 10-row overscan, row IDs as keys, transformed rows, and a spacer +body. The footer reads the Virtualizer range. + +Both paths use `content-visibility: auto`. This can reduce offscreen browser +work in Full DOM but does not prevent Octane from creating every row/cell. + +## Performance decisions + +- worker generation and coalescing before main-thread delivery; +- immutable structural sharing for rows and chart histories; +- selector-based subscriptions with explicit equality; +- stable table and virtual row identity; +- componentized shell/table/cells with local state ownership; +- delegated pointer input and CSS hover; +- CSS variables for column sizes; +- opt-in component churn and independently sampled charts; +- virtual mounting for larger data sets; +- benchmark publication slower than feed updates. + +The outer array intentionally changes for immutable publication. Structural +sharing reduces renderer work, but sorted/filtered row models may still execute +when the data input changes. + +## Diagnostics and interpretation + +The compact **Live health** section lives in the configurator and reports the +estimated frame callback rate over 1 second, average market-mutation-to-DOM- +commit latency over 3 seconds, cumulative long animation frames, and throughput +as changed rows plus applied snapshots per second. Detailed diagnostics retain +worker samples/messages, state applies, DOM commits, rolling 10-second p95/max +commit latency, cumulative slow commits, mounted cells, component +lifecycle/execution, row-model timing, DOM mutation records, and heap. + +Octane's completed-render measurement is connected to the feed mutation and +the table's committed layout lifecycle; it should be compared using the same +build and settings. The frame value counts `requestAnimationFrame` callbacks, +not GPU-presented frames. `MutationObserver` reports delivered records, not +individual DOM operations, and adds overhead on a hot subtree; it is limited to +text, child-list, and `class`/`style` changes. Heap is Chromium-only and +GC-sensitive. User Timing timeline measures are sampled 1-in-20 while the +in-memory latency calculation keeps every commit. Callback execution does not +equal DOM mutation, and heap growth is not a confirmed leak without post-GC +retention. +The rAF loop only appends a timestamp; rolling aggregation and heap reads run at +the 500 ms metrics publication cadence. Mutation observation remains the most +intrusive diagnostic because the browser must create records for the observed +subtree. + +`Changed rows/s` sums the update array lengths delivered by each snapshot. +Symbols are deduplicated inside one message, but the same row can count again in +the next snapshot; it is applied row throughput, not distinct instruments per +second. + +## Standalone policy + +This folder owns copies of its feed, worker, instruments, benchmark, shell, +styles, and table implementation. That duplication keeps it independently +runnable and StackBlitz-friendly; shared README explanations are repeated +across adapters intentionally. + +The workspace resolves `@tanstack/octane-table` to the repository adapter while +the example manifest remains release-like. diff --git a/examples/octane/realtime-trading/index.html b/examples/octane/realtime-trading/index.html new file mode 100644 index 0000000000..ddd15fcca9 --- /dev/null +++ b/examples/octane/realtime-trading/index.html @@ -0,0 +1,12 @@ + + + + + + TanStack Octane Table + + +
+ + + diff --git a/examples/octane/realtime-trading/package.json b/examples/octane/realtime-trading/package.json new file mode 100644 index 0000000000..799c0afaae --- /dev/null +++ b/examples/octane/realtime-trading/package.json @@ -0,0 +1,25 @@ +{ + "name": "tanstack-octane-table-example-realtime-trading", + "private": true, + "type": "module", + "scripts": { + "start": "vite", + "dev": "vite", + "build": "vite build", + "serve": "vite preview", + "lint": "eslint ./src", + "test:types": "tsrx-tsc --noEmit", + "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" + }, + "dependencies": { + "@tanstack/octane-store": "^0.12.2", + "@tanstack/octane-table": "^9.2.3", + "octane": "0.1.36" + }, + "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", + "@tsrx/typescript-plugin": "^0.3.118", + "typescript": "6.0.3", + "vite": "^8.2.2" + } +} diff --git a/examples/octane/realtime-trading/src/benchmark/benchmark-monitor.ts b/examples/octane/realtime-trading/src/benchmark/benchmark-monitor.ts new file mode 100644 index 0000000000..36ea2ddc50 --- /dev/null +++ b/examples/octane/realtime-trading/src/benchmark/benchmark-monitor.ts @@ -0,0 +1,402 @@ +import { + quoteCellLifecycle, + quoteRenderDiagnostics, +} from '../table/table-config/quote-cells.tsrx' +import { rowModelDiagnostics } from '../table/trading-table' + +export interface NamedInvocationRate { + name: string + callsPerSecond: number +} + +export interface FeedMetrics { + actualTicksPerSecond: number + rowUpdatesPerSecond: number + workerMessagesPerSecond: number + stateApplicationsPerSecond: number + supersededUpdatesPerSecond: number + totalTicks: number + rafCallbacksPerSecond: number + tableRendersPerSecond: number + lastBatchSize: number + averageRenderMs: number + p95RenderMs: number + maxRenderMs: number + slowRenders: number + longAnimationFrames: number + worstLongAnimationFrameMs: number + heapMb: number | null + componentsCreated: number + componentsDestroyed: number + workerMessages: number + lastUpdateCount: number + cellRendererCallsPerSecond: number + componentRenderCallsPerSecond: number + cellRendererRates: ReadonlyArray + componentRenderRates: ReadonlyArray + domMutationsPerSecond: number + rowModelCallsPerSecond: number + rowModelAverageMs: number + rowModelMaxMs: number + visibleRows: number +} + +export const initialMetrics: FeedMetrics = { + actualTicksPerSecond: 0, + rowUpdatesPerSecond: 0, + workerMessagesPerSecond: 0, + stateApplicationsPerSecond: 0, + supersededUpdatesPerSecond: 0, + totalTicks: 0, + rafCallbacksPerSecond: 0, + tableRendersPerSecond: 0, + lastBatchSize: 0, + averageRenderMs: 0, + p95RenderMs: 0, + maxRenderMs: 0, + slowRenders: 0, + longAnimationFrames: 0, + worstLongAnimationFrameMs: 0, + heapMb: null, + componentsCreated: 0, + componentsDestroyed: 0, + workerMessages: 0, + lastUpdateCount: 0, + cellRendererCallsPerSecond: 0, + componentRenderCallsPerSecond: 0, + cellRendererRates: [], + componentRenderRates: [], + domMutationsPerSecond: 0, + rowModelCallsPerSecond: 0, + rowModelAverageMs: 0, + rowModelMaxMs: 0, + visibleRows: 0, +} + +const userTiming = { entryCount: 0, measureCallCount: 0 } +const USER_TIMING_SAMPLE_INTERVAL = 20 + +interface CommitLatencySample { + recordedAt: number + duration: number +} + +const AVERAGE_COMMIT_WINDOW_MS = 3_000 +const PERCENTILE_COMMIT_WINDOW_MS = 10_000 +const FRAME_RATE_WINDOW_MS = 1_000 + +export function recordMeasure( + name: string, + start: number, + end: number, + detail: Record, +): void { + userTiming.measureCallCount++ + if (userTiming.measureCallCount % USER_TIMING_SAMPLE_INTERVAL !== 0) return + try { + performance.measure(name, { start, end, detail }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMeasures('market-update-to-dom-commit') + } + } catch { + // User Timing Level 3 options are not implemented in every browser. + } +} + +export function markBenchmarkAction( + name: string, + detail: Record = {}, +): void { + try { + performance.mark(`benchmark:${name}`, { detail }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMarks() + } + } catch { + // User Timing Level 3 detail is not implemented in every browser. + } +} + +export class BenchmarkMonitor { + readonly #runtime = { + sampleStartedAt: performance.now(), + sessionStartedAt: performance.now(), + frameTrackingStartedAt: performance.now(), + pendingRenderStartedAt: null as number | null, + renderSamples: [] as Array, + frameTimestamps: [] as Array, + totalTicks: 0, + ticksInSample: 0, + rowUpdatesInSample: 0, + workerMessagesInSample: 0, + stateApplicationsInSample: 0, + supersededUpdatesInSample: 0, + lastBatchSize: 0, + lastUpdateCount: 0, + workerMessages: 0, + tableRendersInSample: 0, + slowRenderCount: 0, + longAnimationFrameCount: 0, + worstLongAnimationFrameMs: 0, + previousCellRendererCalls: 0, + previousComponentRenderCalls: 0, + previousCellRendererCallsByName: { + ...quoteRenderDiagnostics.cellRendererCallsByName, + }, + previousComponentRenderCallsByName: { + ...quoteRenderDiagnostics.componentRenderCallsByName, + }, + domMutationsInSample: 0, + previousRowModelCalls: 0, + previousRowModelDuration: 0, + } + + markRenderPending(): void { + this.#runtime.pendingRenderStartedAt ??= performance.now() + } + + recordCompletedRender(): void { + const runtime = this.#runtime + if (runtime.pendingRenderStartedAt !== null) { + const renderEndedAt = performance.now() + const duration = renderEndedAt - runtime.pendingRenderStartedAt + runtime.renderSamples.push({ recordedAt: renderEndedAt, duration }) + if (duration > 16.7) runtime.slowRenderCount++ + recordMeasure( + 'market-update-to-dom-commit', + runtime.pendingRenderStartedAt, + renderEndedAt, + {}, + ) + runtime.pendingRenderStartedAt = null + runtime.tableRendersInSample++ + } + } + + recordWorkerMessage(): void { + this.#runtime.workerMessages++ + this.#runtime.workerMessagesInSample++ + } + + recordBatch( + tickCount: number, + updateCount: number, + supersededUpdateCount: number, + ): void { + const runtime = this.#runtime + runtime.lastBatchSize = tickCount + runtime.lastUpdateCount = updateCount + runtime.ticksInSample += tickCount + runtime.totalTicks += tickCount + runtime.rowUpdatesInSample += updateCount + runtime.stateApplicationsInSample++ + runtime.supersededUpdatesInSample += supersededUpdateCount + } + + recordAnimationFrame(now: number): void { + this.#runtime.frameTimestamps.push(now) + } + + recordLongAnimationFrame(duration: number, startTime: number): void { + const runtime = this.#runtime + if (startTime < runtime.sessionStartedAt) return + runtime.longAnimationFrameCount++ + runtime.worstLongAnimationFrameMs = Math.max( + runtime.worstLongAnimationFrameMs, + duration, + ) + } + + recordDomMutations(count: number): void { + this.#runtime.domMutationsInSample += count + } + + resetDomMutations(): void { + this.#runtime.domMutationsInSample = 0 + } + + shouldPublish(now: number): boolean { + return now - this.#runtime.sampleStartedAt >= 500 + } + + publish(now: number): FeedMetrics { + const runtime = this.#runtime + const sampleDuration = now - runtime.sampleStartedAt + runtime.renderSamples = runtime.renderSamples.filter( + (sample) => sample.recordedAt >= now - PERCENTILE_COMMIT_WINDOW_MS, + ) + runtime.frameTimestamps = runtime.frameTimestamps.filter( + (timestamp) => timestamp >= now - FRAME_RATE_WINDOW_MS, + ) + const averageRenderSamples = runtime.renderSamples.filter( + (sample) => sample.recordedAt >= now - AVERAGE_COMMIT_WINDOW_MS, + ) + const sortedRenderSamples = runtime.renderSamples + .map((sample) => sample.duration) + .sort((left, right) => left - right) + const rowModelCalls = + rowModelDiagnostics.calls - runtime.previousRowModelCalls + const rowModelDuration = + rowModelDiagnostics.totalDurationMs - runtime.previousRowModelDuration + const cellRendererCalls = + quoteRenderDiagnostics.cellRendererCalls - + runtime.previousCellRendererCalls + const componentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls - + runtime.previousComponentRenderCalls + const cellRendererRates = calculateInvocationRates( + quoteRenderDiagnostics.cellRendererCallsByName, + runtime.previousCellRendererCallsByName, + sampleDuration, + ) + const componentRenderRates = calculateInvocationRates( + quoteRenderDiagnostics.componentRenderCallsByName, + runtime.previousComponentRenderCallsByName, + sampleDuration, + ) + const averageRenderMs = + averageRenderSamples.length === 0 + ? 0 + : averageRenderSamples.reduce( + (sum, sample) => sum + sample.duration, + 0, + ) / averageRenderSamples.length + const p95Index = Math.max( + 0, + Math.ceil(sortedRenderSamples.length * 0.95) - 1, + ) + const metrics: FeedMetrics = { + actualTicksPerSecond: + sampleDuration === 0 + ? 0 + : (runtime.ticksInSample / sampleDuration) * 1_000, + rowUpdatesPerSecond: + (runtime.rowUpdatesInSample / sampleDuration) * 1_000, + workerMessagesPerSecond: + (runtime.workerMessagesInSample / sampleDuration) * 1_000, + stateApplicationsPerSecond: + (runtime.stateApplicationsInSample / sampleDuration) * 1_000, + supersededUpdatesPerSecond: + (runtime.supersededUpdatesInSample / sampleDuration) * 1_000, + totalTicks: runtime.totalTicks, + rafCallbacksPerSecond: + (runtime.frameTimestamps.length / + Math.min( + FRAME_RATE_WINDOW_MS, + Math.max(1, now - runtime.frameTrackingStartedAt), + )) * + 1_000, + tableRendersPerSecond: + (runtime.tableRendersInSample / sampleDuration) * 1_000, + lastBatchSize: runtime.lastBatchSize, + averageRenderMs, + p95RenderMs: sortedRenderSamples[p95Index] ?? 0, + maxRenderMs: sortedRenderSamples.at(-1) ?? 0, + slowRenders: runtime.slowRenderCount, + longAnimationFrames: runtime.longAnimationFrameCount, + worstLongAnimationFrameMs: runtime.worstLongAnimationFrameMs, + heapMb: readHeapSizeMb(), + componentsCreated: quoteCellLifecycle.created, + componentsDestroyed: quoteCellLifecycle.destroyed, + workerMessages: runtime.workerMessages, + lastUpdateCount: runtime.lastUpdateCount, + cellRendererCallsPerSecond: (cellRendererCalls / sampleDuration) * 1_000, + componentRenderCallsPerSecond: + (componentRenderCalls / sampleDuration) * 1_000, + cellRendererRates, + componentRenderRates, + domMutationsPerSecond: + (runtime.domMutationsInSample / sampleDuration) * 1_000, + rowModelCallsPerSecond: (rowModelCalls / sampleDuration) * 1_000, + rowModelAverageMs: + rowModelCalls === 0 ? 0 : rowModelDuration / rowModelCalls, + rowModelMaxMs: rowModelDiagnostics.maxDurationMs, + visibleRows: rowModelDiagnostics.lastRowCount, + } + + runtime.sampleStartedAt = now + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.previousRowModelCalls = rowModelDiagnostics.calls + runtime.previousRowModelDuration = rowModelDiagnostics.totalDurationMs + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.tableRendersInSample = 0 + return metrics + } + + reset(): void { + const runtime = this.#runtime + runtime.sampleStartedAt = performance.now() + runtime.sessionStartedAt = runtime.sampleStartedAt + runtime.pendingRenderStartedAt = null + runtime.renderSamples = [] + runtime.frameTrackingStartedAt = runtime.sampleStartedAt + runtime.frameTimestamps = [] + runtime.totalTicks = 0 + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.lastBatchSize = 0 + runtime.lastUpdateCount = 0 + runtime.workerMessages = 0 + runtime.tableRendersInSample = 0 + runtime.slowRenderCount = 0 + runtime.longAnimationFrameCount = 0 + runtime.worstLongAnimationFrameMs = 0 + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.previousRowModelCalls = rowModelDiagnostics.calls + runtime.previousRowModelDuration = rowModelDiagnostics.totalDurationMs + rowModelDiagnostics.maxDurationMs = 0 + } +} + +export const longAnimationFramesSupported = + PerformanceObserver.supportedEntryTypes.includes('long-animation-frame') + +function readHeapSizeMb(): number | null { + const memory = ( + performance as Performance & { + memory?: { usedJSHeapSize: number } + } + ).memory + return memory ? memory.usedJSHeapSize / 1_048_576 : null +} + +function calculateInvocationRates( + current: Record, + previous: Record, + sampleDuration: number, +): ReadonlyArray { + return Object.entries(current).map(([name, calls]) => ({ + name, + callsPerSecond: + sampleDuration === 0 + ? 0 + : ((calls - (previous[name] ?? 0)) / sampleDuration) * 1_000, + })) +} diff --git a/examples/octane/realtime-trading/src/benchmark/table-benchmark.ts b/examples/octane/realtime-trading/src/benchmark/table-benchmark.ts new file mode 100644 index 0000000000..ee076b605f --- /dev/null +++ b/examples/octane/realtime-trading/src/benchmark/table-benchmark.ts @@ -0,0 +1,20 @@ +import type { TradingBenchmarkController } from './trading-benchmark-controller' + +export function startTableBenchmark( + controller: TradingBenchmarkController, + tableBody: HTMLTableSectionElement | null, +): () => void { + if (!tableBody) return () => undefined + controller.monitor.resetDomMutations() + const observer = new MutationObserver((records) => { + controller.monitor.recordDomMutations(records.length) + }) + observer.observe(tableBody, { + attributes: true, + attributeFilter: ['class', 'style'], + characterData: true, + childList: true, + subtree: true, + }) + return () => observer.disconnect() +} diff --git a/examples/octane/realtime-trading/src/benchmark/trading-benchmark-controller.ts b/examples/octane/realtime-trading/src/benchmark/trading-benchmark-controller.ts new file mode 100644 index 0000000000..72db440d6c --- /dev/null +++ b/examples/octane/realtime-trading/src/benchmark/trading-benchmark-controller.ts @@ -0,0 +1,138 @@ +import { batch, createAtom, createStore } from '@tanstack/octane-store' +import { TRADING_COLUMN_COUNT } from '../table/trading-table' +import { + BenchmarkMonitor, + initialMetrics, + longAnimationFramesSupported, +} from './benchmark-monitor' +import type { FeedMetrics } from './benchmark-monitor' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { RendererMode } from '../table/trading-table' + +export interface TradingBenchmarkState { + metrics: FeedMetrics + mountedCells: number + liveComponents: number + longAnimationFramesSupported: boolean +} + +export interface TradingBenchmarkActions { + resetViewState: () => void + setRendererMode: (mode: RendererMode) => void + setRenderedRowCount: (count: number) => void + selectSymbol: (symbol: string | null) => void + resetMarket: () => void +} + +const initialState: TradingBenchmarkState = { + metrics: initialMetrics, + mountedCells: 0, + liveComponents: 0, + longAnimationFramesSupported, +} + +export class TradingBenchmarkController { + readonly store = createStore(initialState) + readonly renderAtoms = { + selectedSymbol: createAtom(null), + rendererMode: createAtom('stable'), + } + readonly monitor = new BenchmarkMonitor() + readonly feed: MarketFeedController + readonly actions: TradingBenchmarkActions + + readonly #runtime = { + animationFrameId: 0, + longAnimationFrameObserver: null as PerformanceObserver | null, + stopObservingFeed: null as (() => void) | null, + } + + constructor(feed: MarketFeedController) { + this.feed = feed + this.actions = { + resetViewState: () => { + this.renderAtoms.selectedSymbol.set(null) + }, + setRendererMode: (mode) => { + this.renderAtoms.rendererMode.set(mode) + }, + setRenderedRowCount: (count) => { + const mountedCells = count * TRADING_COLUMN_COUNT + if (mountedCells !== this.store.get().mountedCells) { + this.#patch({ mountedCells }) + } + }, + selectSymbol: (symbol) => { + this.renderAtoms.selectedSymbol.set(symbol) + }, + resetMarket: () => { + batch(() => { + this.monitor.reset() + this.store.setState((state) => ({ + ...state, + metrics: { ...initialMetrics }, + mountedCells: 0, + liveComponents: 0, + })) + this.renderAtoms.selectedSymbol.set(null) + this.feed.actions.reset() + }) + }, + } + } + + start(): () => void { + const longAnimationFrameObserver = longAnimationFramesSupported + ? new PerformanceObserver((entries) => { + for (const entry of entries.getEntries()) { + this.monitor.recordLongAnimationFrame( + entry.duration, + entry.startTime, + ) + } + }) + : null + + this.#runtime.longAnimationFrameObserver = longAnimationFrameObserver + this.#runtime.stopObservingFeed = this.feed.observe({ + messageReceived: () => this.monitor.recordWorkerMessage(), + mutationStarted: () => this.monitor.markRenderPending(), + batchApplied: ({ tickCount, updateCount, supersededUpdateCount }) => + this.monitor.recordBatch(tickCount, updateCount, supersededUpdateCount), + renderCommitted: () => this.monitor.recordCompletedRender(), + }) + longAnimationFrameObserver?.observe({ + type: 'long-animation-frame', + }) + this.#runtime.animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + + return () => this.stop() + } + + stop(): void { + cancelAnimationFrame(this.#runtime.animationFrameId) + this.#runtime.longAnimationFrameObserver?.disconnect() + this.#runtime.stopObservingFeed?.() + this.#runtime.longAnimationFrameObserver = null + this.#runtime.stopObservingFeed = null + } + + readonly #benchmarkFrame = (now: number): void => { + this.monitor.recordAnimationFrame(now) + if (this.monitor.shouldPublish(now)) { + this.#publishMetrics(this.monitor.publish(now)) + } + this.#runtime.animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + } + + #patch(patch: Partial): void { + this.store.setState((state) => ({ ...state, ...patch })) + } + + #publishMetrics(metrics: FeedMetrics): void { + this.#patch({ + metrics, + liveComponents: metrics.componentsCreated - metrics.componentsDestroyed, + }) + } +} diff --git a/examples/octane/realtime-trading/src/feed/feed-sample-rates.ts b/examples/octane/realtime-trading/src/feed/feed-sample-rates.ts new file mode 100644 index 0000000000..17dc2015a6 --- /dev/null +++ b/examples/octane/realtime-trading/src/feed/feed-sample-rates.ts @@ -0,0 +1,33 @@ +export const feedSampleRateOptions = [ + { label: '100', value: 100 }, + { label: '250', value: 250 }, + { label: '500', value: 500 }, + { label: '1K', value: 1_000 }, + { label: '2.5K', value: 2_500 }, + { label: '5K', value: 5_000 }, + { label: '10K', value: 10_000 }, + { label: '25K', value: 25_000 }, + { label: '50K', value: 50_000 }, + { label: '100K', value: 100_000 }, +] as const + +export function feedSampleRateIndex(rate: number): number { + return feedSampleRateOptions.reduce((closestIndex, candidate, index) => { + const closest = feedSampleRateOptions[closestIndex] + return Math.abs(candidate.value - rate) < Math.abs(closest.value - rate) + ? index + : closestIndex + }, 0) +} + +export function feedSampleRateAt(stepIndex: number): number { + const index = Math.min( + feedSampleRateOptions.length - 1, + Math.max(0, Math.round(stepIndex)), + ) + return feedSampleRateOptions[index].value +} + +export function normalizeFeedSampleRate(rate: number): number { + return feedSampleRateAt(feedSampleRateIndex(rate)) +} diff --git a/examples/octane/realtime-trading/src/feed/market-data.ts b/examples/octane/realtime-trading/src/feed/market-data.ts new file mode 100644 index 0000000000..6231865d3f --- /dev/null +++ b/examples/octane/realtime-trading/src/feed/market-data.ts @@ -0,0 +1,38 @@ +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './worker/market-feed-protocol' + +export interface MarketQuote extends Omit { + history: ReadonlyArray +} + +export function hydrateMarketQuotes( + snapshots: Array, +): Array { + return snapshots.map((quote) => ({ + ...quote, + history: [...quote.history], + })) +} + +export function applyMarketUpdates( + quotes: Array, + updates: Array, +): Array { + const nextQuotes = [...quotes] + + for (const update of updates) { + const { index, history, ...values } = update + const previousQuote = quotes.at(index) + if (!previousQuote) continue + + nextQuotes[index] = { + ...previousQuote, + ...values, + history: history ?? previousQuote.history, + } + } + + return nextQuotes +} diff --git a/examples/octane/realtime-trading/src/feed/market-feed-config.ts b/examples/octane/realtime-trading/src/feed/market-feed-config.ts new file mode 100644 index 0000000000..9d477ed663 --- /dev/null +++ b/examples/octane/realtime-trading/src/feed/market-feed-config.ts @@ -0,0 +1,15 @@ +export interface MarketFeedConfig { + readonly instrumentCount: number + readonly targetSamplesPerSecond: number + readonly publishIntervalMs: number + readonly updateSparklines: boolean + readonly sparklineSampleIntervalMs: number +} + +export const initialMarketFeedConfig: MarketFeedConfig = { + instrumentCount: 100, + targetSamplesPerSecond: 10_000, + publishIntervalMs: 20, + updateSparklines: true, + sparklineSampleIntervalMs: 16, +} diff --git a/examples/octane/realtime-trading/src/feed/market-feed-controller.ts b/examples/octane/realtime-trading/src/feed/market-feed-controller.ts new file mode 100644 index 0000000000..ade45c007c --- /dev/null +++ b/examples/octane/realtime-trading/src/feed/market-feed-controller.ts @@ -0,0 +1,225 @@ +import { batch, createAtom } from '@tanstack/octane-store' +import { normalizeFeedSampleRate } from './feed-sample-rates' +import { initialMarketFeedConfig } from './market-feed-config' +import { applyMarketUpdates, hydrateMarketQuotes } from './market-data' +import type { + MarketFeedCommand, + MarketFeedEvent, +} from './worker/market-feed-protocol' +import type { MarketQuote } from './market-data' + +export interface MarketFeedBatch { + tickCount: number + updateCount: number + supersededUpdateCount: number +} + +export interface MarketFeedObserver { + messageReceived?: () => void + mutationStarted?: () => void + batchApplied?: (batch: MarketFeedBatch) => void + renderCommitted?: () => void +} + +export interface MarketFeedActions { + toggle: () => void + setInstrumentCount: (count: number) => void + setTargetRate: (rate: number) => void + setPublishInterval: (intervalMs: number) => void + setSparklineUpdates: (enabled: boolean) => void + setSparklineSampleInterval: (intervalMs: number) => void + runBurst: () => void + reset: () => void +} + +export class MarketFeedController { + readonly workerReady = createAtom(false) + readonly running = createAtom(true) + readonly instrumentCount = createAtom(initialMarketFeedConfig.instrumentCount) + readonly targetTicksPerSecond = createAtom( + initialMarketFeedConfig.targetSamplesPerSecond, + ) + readonly publishIntervalMs = createAtom( + initialMarketFeedConfig.publishIntervalMs, + ) + readonly updateSparklines = createAtom( + initialMarketFeedConfig.updateSparklines, + ) + readonly sparklineSampleIntervalMs = createAtom( + initialMarketFeedConfig.sparklineSampleIntervalMs, + ) + readonly quotes = createAtom>([]) + readonly actions: MarketFeedActions + readonly #observers = new Set() + readonly #runtime = { + worker: null as Worker | null, + feedSessionId: 0, + renderPending: false, + resetWaitingForCommit: false, + resetSnapshotReady: false, + quoteIndexBySymbol: new Map(), + } + + constructor() { + this.actions = { + toggle: () => { + const running = !this.running.get() + this.running.set(running) + this.#post({ type: 'set-running', running }) + }, + setInstrumentCount: (count) => { + this.instrumentCount.set(count) + this.#resetWorker(count) + }, + setTargetRate: (rate) => { + const sampleRate = normalizeFeedSampleRate(rate) + this.targetTicksPerSecond.set(sampleRate) + this.#post({ type: 'set-rate', ticksPerSecond: sampleRate }) + }, + setPublishInterval: (publishIntervalMs) => { + this.publishIntervalMs.set(publishIntervalMs) + this.#post({ + type: 'set-publish-interval', + intervalMs: publishIntervalMs, + }) + }, + setSparklineUpdates: (enabled) => { + this.updateSparklines.set(enabled) + this.#post({ type: 'set-sparklines', enabled }) + }, + setSparklineSampleInterval: (intervalMs) => { + this.sparklineSampleIntervalMs.set(intervalMs) + this.#post({ type: 'set-sparkline-interval', intervalMs }) + }, + runBurst: () => this.#post({ type: 'burst', tickCount: 25_000 }), + reset: () => this.#resetWorker(this.instrumentCount.get()), + } + } + + start(): () => void { + const worker = new Worker( + new URL('./worker/market-feed.worker.ts', import.meta.url), + { type: 'module' }, + ) + this.#runtime.worker = worker + worker.addEventListener('message', this.#handleWorkerMessage) + worker.addEventListener('error', this.#handleWorkerError) + this.#post({ + type: 'start', + rowCount: this.instrumentCount.get(), + running: this.running.get(), + ticksPerSecond: this.targetTicksPerSecond.get(), + publishIntervalMs: this.publishIntervalMs.get(), + updateSparklines: this.updateSparklines.get(), + sparklineSampleIntervalMs: this.sparklineSampleIntervalMs.get(), + }) + return () => this.stop() + } + + stop(): void { + this.#runtime.worker?.removeEventListener( + 'message', + this.#handleWorkerMessage, + ) + this.#runtime.worker?.removeEventListener('error', this.#handleWorkerError) + this.#runtime.worker?.terminate() + this.#runtime.worker = null + this.#observers.clear() + } + + observe(observer: MarketFeedObserver): () => void { + this.#observers.add(observer) + return () => this.#observers.delete(observer) + } + + getQuoteBySymbol( + quotes: Array, + symbol: string | null, + ): MarketQuote | null { + if (symbol === null) return null + + const index = this.#runtime.quoteIndexBySymbol.get(symbol) + return index === undefined ? null : (quotes[index] ?? null) + } + + completeRender(): void { + if (!this.#runtime.renderPending) return + + this.#runtime.renderPending = false + for (const observer of this.#observers) { + observer.renderCommitted?.() + } + if ( + this.#runtime.resetWaitingForCommit && + this.#runtime.resetSnapshotReady + ) { + this.#runtime.resetWaitingForCommit = false + this.#runtime.resetSnapshotReady = false + this.#post({ type: 'set-running', running: this.running.get() }) + } + } + + readonly #handleWorkerMessage = ({ + data, + }: MessageEvent): void => { + if (data.type === 'snapshot') { + this.#runtime.feedSessionId = data.sessionId + if (this.#runtime.resetWaitingForCommit) { + this.#runtime.resetSnapshotReady = true + } + this.#startMutation() + const quotes = hydrateMarketQuotes(data.quotes) + this.#runtime.quoteIndexBySymbol = new Map( + quotes.map((quote, index) => [quote.symbol, index]), + ) + batch(() => { + this.quotes.set(quotes) + this.workerReady.set(true) + }) + return + } + + if (data.sessionId !== this.#runtime.feedSessionId) return + + for (const observer of this.#observers) { + observer.messageReceived?.() + } + this.#startMutation() + this.quotes.set(applyMarketUpdates(this.quotes.get(), data.updates)) + const feedBatch = { + tickCount: data.tickCount, + updateCount: data.updates.length, + supersededUpdateCount: data.coalescedUpdateCount, + } + for (const observer of this.#observers) { + observer.batchApplied?.(feedBatch) + } + } + + readonly #handleWorkerError = (error: ErrorEvent): void => { + batch(() => { + this.workerReady.set(false) + this.running.set(false) + }) + console.error('Market feed worker failed', error) + } + + #resetWorker(rowCount: number): void { + this.workerReady.set(false) + this.#runtime.resetWaitingForCommit = true + this.#runtime.resetSnapshotReady = false + this.#post({ type: 'set-running', running: false }) + this.#post({ type: 'reset', rowCount }) + } + + #startMutation(): void { + this.#runtime.renderPending = true + for (const observer of this.#observers) { + observer.mutationStarted?.() + } + } + + #post(command: MarketFeedCommand): void { + this.#runtime.worker?.postMessage(command) + } +} diff --git a/examples/octane/realtime-trading/src/feed/market-instruments.ts b/examples/octane/realtime-trading/src/feed/market-instruments.ts new file mode 100644 index 0000000000..ac18d14ea9 --- /dev/null +++ b/examples/octane/realtime-trading/src/feed/market-instruments.ts @@ -0,0 +1,742 @@ +export type MarketCode = + | 'US' + | 'NL' + | 'DE' + | 'FR' + | 'IT' + | 'ES' + | 'CH' + | 'DK' + | 'SE' + | 'FI' + | 'GB' + | 'KR' + | 'JP' + | 'HK' + | 'CA' + | 'AU' + +export type BaseInstrument = readonly [ + symbol: string, + company: string, + market: MarketCode, +] + +/** + * Current S&P 500 constituent universe used by the realtime trading examples. + * + * Source snapshot: https://github.com/datasets/s-and-p-500-companies + * Retrieved: 2026-08-15. + * Multiple share classes are intentionally represented as separate instruments. + */ +export const marketInstruments = Object.freeze([ + ['MMM', '3M', 'US'], + ['AOS', 'A. O. Smith', 'US'], + ['ABT', 'Abbott Laboratories', 'US'], + ['ABBV', 'AbbVie', 'US'], + ['ACN', 'Accenture', 'US'], + ['ADBE', 'Adobe Inc.', 'US'], + ['AMD', 'Advanced Micro Devices', 'US'], + ['AES', 'AES Corporation', 'US'], + ['AFL', 'Aflac', 'US'], + ['A', 'Agilent Technologies', 'US'], + ['APD', 'Air Products', 'US'], + ['ABNB', 'Airbnb', 'US'], + ['AKAM', 'Akamai Technologies', 'US'], + ['ALB', 'Albemarle Corporation', 'US'], + ['ARE', 'Alexandria Real Estate Equities', 'US'], + ['ALGN', 'Align Technology', 'US'], + ['ALLE', 'Allegion', 'US'], + ['LNT', 'Alliant Energy', 'US'], + ['ALL', 'Allstate', 'US'], + ['GOOGL', 'Alphabet Inc. (Class A)', 'US'], + ['GOOG', 'Alphabet Inc. (Class C)', 'US'], + ['MO', 'Altria', 'US'], + ['AMZN', 'Amazon', 'US'], + ['AMCR', 'Amcor', 'US'], + ['AEE', 'Ameren', 'US'], + ['AEP', 'American Electric Power', 'US'], + ['AXP', 'American Express', 'US'], + ['AIG', 'American International Group', 'US'], + ['AMT', 'American Tower', 'US'], + ['AWK', 'American Water Works', 'US'], + ['AMP', 'Ameriprise Financial', 'US'], + ['AME', 'Ametek', 'US'], + ['AMGN', 'Amgen', 'US'], + ['APH', 'Amphenol', 'US'], + ['ADI', 'Analog Devices', 'US'], + ['AON', 'Aon plc', 'US'], + ['APA', 'APA Corporation', 'US'], + ['APO', 'Apollo Global Management', 'US'], + ['AAPL', 'Apple Inc.', 'US'], + ['AMAT', 'Applied Materials', 'US'], + ['APP', 'AppLovin', 'US'], + ['APTV', 'Aptiv', 'US'], + ['ACGL', 'Arch Capital Group', 'US'], + ['ADM', 'Archer Daniels Midland', 'US'], + ['ARES', 'Ares Management', 'US'], + ['ANET', 'Arista Networks', 'US'], + ['AJG', 'Arthur J. Gallagher & Co.', 'US'], + ['AIZ', 'Assurant', 'US'], + ['T', 'AT&T', 'US'], + ['ATO', 'Atmos Energy', 'US'], + ['ADSK', 'Autodesk', 'US'], + ['ADP', 'Automatic Data Processing', 'US'], + ['AZO', 'AutoZone', 'US'], + ['AVB', 'AvalonBay Communities', 'US'], + ['AVY', 'Avery Dennison', 'US'], + ['AXON', 'Axon Enterprise', 'US'], + ['BKR', 'Baker Hughes', 'US'], + ['BALL', 'Ball Corporation', 'US'], + ['BAC', 'Bank of America', 'US'], + ['BAX', 'Baxter International', 'US'], + ['BDX', 'Becton Dickinson', 'US'], + ['BRK.B', 'Berkshire Hathaway', 'US'], + ['BBY', 'Best Buy', 'US'], + ['TECH', 'Bio-Techne', 'US'], + ['BIIB', 'Biogen', 'US'], + ['BLK', 'BlackRock', 'US'], + ['BX', 'Blackstone Inc.', 'US'], + ['XYZ', 'Block, Inc.', 'US'], + ['BNY', 'BNY Mellon', 'US'], + ['BA', 'Boeing', 'US'], + ['BKNG', 'Booking Holdings', 'US'], + ['BSX', 'Boston Scientific', 'US'], + ['BMY', 'Bristol Myers Squibb', 'US'], + ['AVGO', 'Broadcom', 'US'], + ['BR', 'Broadridge Financial Solutions', 'US'], + ['BRO', 'Brown & Brown', 'US'], + ['BF.B', 'Brown–Forman', 'US'], + ['BLDR', 'Builders FirstSource', 'US'], + ['BG', 'Bunge Global', 'US'], + ['BXP', 'BXP, Inc.', 'US'], + ['CHRW', 'C.H. Robinson', 'US'], + ['CDNS', 'Cadence Design Systems', 'US'], + ['CPT', 'Camden Property Trust', 'US'], + ['COF', 'Capital One', 'US'], + ['CAH', 'Cardinal Health', 'US'], + ['CCL', 'Carnival Corporation', 'US'], + ['CARR', 'Carrier Global', 'US'], + ['CVNA', 'Carvana', 'US'], + ['CASY', "Casey's", 'US'], + ['CAT', 'Caterpillar Inc.', 'US'], + ['CBOE', 'Cboe Global Markets', 'US'], + ['CBRE', 'CBRE Group', 'US'], + ['CDW', 'CDW Corporation', 'US'], + ['COR', 'Cencora', 'US'], + ['CNC', 'Centene Corporation', 'US'], + ['CNP', 'CenterPoint Energy', 'US'], + ['CF', 'CF Industries', 'US'], + ['CRL', 'Charles River Laboratories', 'US'], + ['SCHW', 'Charles Schwab Corporation', 'US'], + ['CHTR', 'Charter Communications', 'US'], + ['CVX', 'Chevron Corporation', 'US'], + ['CMG', 'Chipotle Mexican Grill', 'US'], + ['CB', 'Chubb Limited', 'US'], + ['CHD', 'Church & Dwight', 'US'], + ['CIEN', 'Ciena', 'US'], + ['CI', 'Cigna', 'US'], + ['CINF', 'Cincinnati Financial', 'US'], + ['CTAS', 'Cintas', 'US'], + ['CSCO', 'Cisco', 'US'], + ['C', 'Citigroup', 'US'], + ['CFG', 'Citizens Financial Group', 'US'], + ['CLX', 'Clorox', 'US'], + ['CME', 'CME Group', 'US'], + ['CMS', 'CMS Energy', 'US'], + ['KO', 'Coca-Cola Company (The)', 'US'], + ['CTSH', 'Cognizant', 'US'], + ['COHR', 'Coherent Corp.', 'US'], + ['COIN', 'Coinbase', 'US'], + ['CL', 'Colgate-Palmolive', 'US'], + ['CMCSA', 'Comcast', 'US'], + ['FIX', 'Comfort Systems USA', 'US'], + ['COP', 'ConocoPhillips', 'US'], + ['ED', 'Consolidated Edison', 'US'], + ['STZ', 'Constellation Brands', 'US'], + ['CEG', 'Constellation Energy', 'US'], + ['COO', 'Cooper Companies (The)', 'US'], + ['CPRT', 'Copart', 'US'], + ['GLW', 'Corning Inc.', 'US'], + ['CPAY', 'Corpay', 'US'], + ['CTVA', 'Corteva', 'US'], + ['CSGP', 'CoStar Group', 'US'], + ['COST', 'Costco', 'US'], + ['CRH', 'CRH plc', 'US'], + ['CRWD', 'CrowdStrike', 'US'], + ['CCI', 'Crown Castle', 'US'], + ['CSX', 'CSX Corporation', 'US'], + ['CMI', 'Cummins', 'US'], + ['CVS', 'CVS Health', 'US'], + ['DHR', 'Danaher Corporation', 'US'], + ['DRI', 'Darden Restaurants', 'US'], + ['DDOG', 'Datadog', 'US'], + ['DVA', 'DaVita', 'US'], + ['DECK', 'Deckers Brands', 'US'], + ['DE', 'Deere & Company', 'US'], + ['DELL', 'Dell Technologies', 'US'], + ['DAL', 'Delta Air Lines', 'US'], + ['DVN', 'Devon Energy', 'US'], + ['DXCM', 'Dexcom', 'US'], + ['FANG', 'Diamondback Energy', 'US'], + ['DLR', 'Digital Realty', 'US'], + ['DG', 'Dollar General', 'US'], + ['DLTR', 'Dollar Tree', 'US'], + ['D', 'Dominion Energy', 'US'], + ['DPZ', "Domino's", 'US'], + ['DASH', 'DoorDash', 'US'], + ['DOV', 'Dover Corporation', 'US'], + ['DOW', 'Dow Inc.', 'US'], + ['DHI', 'D. R. Horton', 'US'], + ['DTE', 'DTE Energy', 'US'], + ['DUK', 'Duke Energy', 'US'], + ['DD', 'DuPont', 'US'], + ['ETN', 'Eaton Corporation', 'US'], + ['EBAY', 'eBay Inc.', 'US'], + ['ECHO', 'EchoStar', 'US'], + ['ECL', 'Ecolab', 'US'], + ['EIX', 'Edison International', 'US'], + ['EW', 'Edwards Lifesciences', 'US'], + ['ELV', 'Elevance Health', 'US'], + ['EME', 'Emcor', 'US'], + ['EMR', 'Emerson Electric', 'US'], + ['ETR', 'Entergy', 'US'], + ['EOG', 'EOG Resources', 'US'], + ['EQT', 'EQT Corporation', 'US'], + ['EFX', 'Equifax', 'US'], + ['EQIX', 'Equinix', 'US'], + ['EQR', 'Equity Residential', 'US'], + ['ERIE', 'Erie Indemnity', 'US'], + ['ESS', 'Essex Property Trust', 'US'], + ['EL', 'Estée Lauder Companies (The)', 'US'], + ['EG', 'Everest Group', 'US'], + ['EVRG', 'Evergy', 'US'], + ['ES', 'Eversource Energy', 'US'], + ['EXC', 'Exelon', 'US'], + ['EXE', 'Expand Energy', 'US'], + ['EXPE', 'Expedia Group', 'US'], + ['EXPD', 'Expeditors International', 'US'], + ['EXR', 'Extra Space Storage', 'US'], + ['XOM', 'ExxonMobil', 'US'], + ['FFIV', 'F5, Inc.', 'US'], + ['FDS', 'FactSet', 'US'], + ['FICO', 'Fair Isaac', 'US'], + ['FAST', 'Fastenal', 'US'], + ['FRT', 'Federal Realty Investment Trust', 'US'], + ['FDX', 'FedEx', 'US'], + ['FDXF', 'FedEx Freight', 'US'], + ['FERG', 'Ferguson Enterprises', 'US'], + ['FIS', 'Fidelity National Information Services', 'US'], + ['FITB', 'Fifth Third Bancorp', 'US'], + ['FSLR', 'First Solar', 'US'], + ['FE', 'FirstEnergy', 'US'], + ['FISV', 'Fiserv', 'US'], + ['FLEX', 'Flex Ltd.', 'US'], + ['F', 'Ford Motor Company', 'US'], + ['FTNT', 'Fortinet', 'US'], + ['FTV', 'Fortive', 'US'], + ['FOXA', 'Fox Corporation (Class A)', 'US'], + ['FOX', 'Fox Corporation (Class B)', 'US'], + ['BEN', 'Franklin Resources', 'US'], + ['FCX', 'Freeport-McMoRan', 'US'], + ['GRMN', 'Garmin', 'US'], + ['IT', 'Gartner', 'US'], + ['GE', 'GE Aerospace', 'US'], + ['GEHC', 'GE HealthCare', 'US'], + ['GEV', 'GE Vernova', 'US'], + ['GEN', 'Gen Digital', 'US'], + ['GNRC', 'Generac', 'US'], + ['GD', 'General Dynamics', 'US'], + ['GIS', 'General Mills', 'US'], + ['GM', 'General Motors', 'US'], + ['GPC', 'Genuine Parts Company', 'US'], + ['GILD', 'Gilead Sciences', 'US'], + ['GPN', 'Global Payments', 'US'], + ['GL', 'Globe Life', 'US'], + ['GDDY', 'GoDaddy', 'US'], + ['GS', 'Goldman Sachs', 'US'], + ['HAL', 'Halliburton', 'US'], + ['HIG', 'Hartford (The)', 'US'], + ['HAS', 'Hasbro', 'US'], + ['HCA', 'HCA Healthcare', 'US'], + ['DOC', 'Healthpeak Properties', 'US'], + ['HSIC', 'Henry Schein', 'US'], + ['HSY', 'Hershey Company (The)', 'US'], + ['HPE', 'Hewlett Packard Enterprise', 'US'], + ['HLT', 'Hilton Worldwide', 'US'], + ['HD', 'Home Depot (The)', 'US'], + ['HONA', 'Honeywell Aerospace', 'US'], + ['HON', 'Honeywell Technologies', 'US'], + ['HRL', 'Hormel Foods', 'US'], + ['HST', 'Host Hotels & Resorts', 'US'], + ['HWM', 'Howmet Aerospace', 'US'], + ['HPQ', 'HP Inc.', 'US'], + ['HUBB', 'Hubbell Incorporated', 'US'], + ['HUM', 'Humana', 'US'], + ['HBAN', 'Huntington Bancshares', 'US'], + ['HII', 'Huntington Ingalls Industries', 'US'], + ['IBM', 'IBM', 'US'], + ['IEX', 'IDEX Corporation', 'US'], + ['IDXX', 'Idexx Laboratories', 'US'], + ['ITW', 'Illinois Tool Works', 'US'], + ['INCY', 'Incyte', 'US'], + ['IR', 'Ingersoll Rand', 'US'], + ['PODD', 'Insulet Corporation', 'US'], + ['INTC', 'Intel', 'US'], + ['IBKR', 'Interactive Brokers', 'US'], + ['ICE', 'Intercontinental Exchange', 'US'], + ['IFF', 'International Flavors & Fragrances', 'US'], + ['IP', 'International Paper', 'US'], + ['INTU', 'Intuit', 'US'], + ['ISRG', 'Intuitive Surgical', 'US'], + ['IVZ', 'Invesco', 'US'], + ['INVH', 'Invitation Homes', 'US'], + ['IQV', 'IQVIA', 'US'], + ['IRM', 'Iron Mountain', 'US'], + ['JBHT', 'J.B. Hunt', 'US'], + ['JBL', 'Jabil', 'US'], + ['JKHY', 'Jack Henry & Associates', 'US'], + ['J', 'Jacobs Solutions', 'US'], + ['JNJ', 'Johnson & Johnson', 'US'], + ['JCI', 'Johnson Controls', 'US'], + ['JPM', 'JPMorgan Chase', 'US'], + ['KVUE', 'Kenvue', 'US'], + ['KDP', 'Keurig Dr Pepper', 'US'], + ['KEY', 'KeyCorp', 'US'], + ['KEYS', 'Keysight Technologies', 'US'], + ['KMB', 'Kimberly-Clark', 'US'], + ['KIM', 'Kimco Realty', 'US'], + ['KMI', 'Kinder Morgan', 'US'], + ['KKR', 'KKR & Co.', 'US'], + ['KLAC', 'KLA Corporation', 'US'], + ['KHC', 'Kraft Heinz', 'US'], + ['KR', 'Kroger', 'US'], + ['LHX', 'L3Harris', 'US'], + ['LH', 'Labcorp', 'US'], + ['LRCX', 'Lam Research', 'US'], + ['LVS', 'Las Vegas Sands', 'US'], + ['LDOS', 'Leidos', 'US'], + ['LEN', 'Lennar', 'US'], + ['LII', 'Lennox International', 'US'], + ['LLY', 'Lilly (Eli)', 'US'], + ['LIN', 'Linde plc', 'US'], + ['LYV', 'Live Nation Entertainment', 'US'], + ['LMT', 'Lockheed Martin', 'US'], + ['L', 'Loews Corporation', 'US'], + ['LOW', "Lowe's", 'US'], + ['LULU', 'Lululemon Athletica', 'US'], + ['LITE', 'Lumentum', 'US'], + ['LYB', 'LyondellBasell', 'US'], + ['MTB', 'M&T Bank', 'US'], + ['MPC', 'Marathon Petroleum', 'US'], + ['MAR', 'Marriott International', 'US'], + ['MRSH', 'Marsh McLennan', 'US'], + ['MLM', 'Martin Marietta Materials', 'US'], + ['MRVL', 'Marvell Technology', 'US'], + ['MAS', 'Masco', 'US'], + ['MA', 'Mastercard', 'US'], + ['MKC', 'McCormick & Company', 'US'], + ['MCD', "McDonald's", 'US'], + ['MCK', 'McKesson Corporation', 'US'], + ['MDT', 'Medtronic', 'US'], + ['MRK', 'Merck & Co.', 'US'], + ['META', 'Meta Platforms', 'US'], + ['MET', 'MetLife', 'US'], + ['MTD', 'Mettler Toledo', 'US'], + ['MGM', 'MGM Resorts', 'US'], + ['MCHP', 'Microchip Technology', 'US'], + ['MU', 'Micron Technology', 'US'], + ['MSFT', 'Microsoft', 'US'], + ['MAA', 'Mid-America Apartment Communities', 'US'], + ['MRNA', 'Moderna', 'US'], + ['TAP', 'Molson Coors Beverage Company', 'US'], + ['MDLZ', 'Mondelez International', 'US'], + ['MPWR', 'Monolithic Power Systems', 'US'], + ['MNST', 'Monster Beverage', 'US'], + ['MCO', "Moody's Corporation", 'US'], + ['MS', 'Morgan Stanley', 'US'], + ['MOS', 'Mosaic Company (The)', 'US'], + ['MSI', 'Motorola Solutions', 'US'], + ['MSCI', 'MSCI', 'US'], + ['NDAQ', 'Nasdaq, Inc.', 'US'], + ['NTAP', 'NetApp', 'US'], + ['NFLX', 'Netflix', 'US'], + ['NEM', 'Newmont', 'US'], + ['NWSA', 'News Corp (Class A)', 'US'], + ['NWS', 'News Corp (Class B)', 'US'], + ['NEE', 'NextEra Energy', 'US'], + ['NKE', 'Nike, Inc.', 'US'], + ['NI', 'NiSource', 'US'], + ['NDSN', 'Nordson Corporation', 'US'], + ['NSC', 'Norfolk Southern', 'US'], + ['NTRS', 'Northern Trust', 'US'], + ['NOC', 'Northrop Grumman', 'US'], + ['NCLH', 'Norwegian Cruise Line Holdings', 'US'], + ['NRG', 'NRG Energy', 'US'], + ['NUE', 'Nucor', 'US'], + ['NVDA', 'Nvidia', 'US'], + ['NVR', 'NVR, Inc.', 'US'], + ['NXPI', 'NXP Semiconductors', 'US'], + ['ORLY', "O'Reilly Automotive", 'US'], + ['OXY', 'Occidental Petroleum', 'US'], + ['ODFL', 'Old Dominion', 'US'], + ['OMC', 'Omnicom Group', 'US'], + ['ON', 'ON Semiconductor', 'US'], + ['OKE', 'Oneok', 'US'], + ['ORCL', 'Oracle Corporation', 'US'], + ['OTIS', 'Otis Worldwide', 'US'], + ['PCAR', 'Paccar', 'US'], + ['PKG', 'Packaging Corporation of America', 'US'], + ['PLTR', 'Palantir Technologies', 'US'], + ['PANW', 'Palo Alto Networks', 'US'], + ['PSKY', 'Paramount Skydance Corporation', 'US'], + ['PH', 'Parker Hannifin', 'US'], + ['PAYX', 'Paychex', 'US'], + ['PYPL', 'PayPal', 'US'], + ['PNR', 'Pentair', 'US'], + ['PEP', 'PepsiCo', 'US'], + ['PFE', 'Pfizer', 'US'], + ['PCG', 'PG&E Corporation', 'US'], + ['PM', 'Philip Morris International', 'US'], + ['PSX', 'Phillips 66', 'US'], + ['PNW', 'Pinnacle West Capital', 'US'], + ['PNC', 'PNC Financial Services', 'US'], + ['PPG', 'PPG Industries', 'US'], + ['PPL', 'PPL Corporation', 'US'], + ['PFG', 'Principal Financial Group', 'US'], + ['PG', 'Procter & Gamble', 'US'], + ['PGR', 'Progressive Corporation', 'US'], + ['PLD', 'Prologis', 'US'], + ['PRU', 'Prudential Financial', 'US'], + ['PEG', 'Public Service Enterprise Group', 'US'], + ['PTC', 'PTC Inc.', 'US'], + ['PSA', 'Public Storage', 'US'], + ['PHM', 'PulteGroup', 'US'], + ['PWR', 'Quanta Services', 'US'], + ['QCOM', 'Qualcomm', 'US'], + ['DGX', 'Quest Diagnostics', 'US'], + ['Q', 'Qnity Electronics', 'US'], + ['RL', 'Ralph Lauren Corporation', 'US'], + ['RJF', 'Raymond James Financial', 'US'], + ['RTX', 'RTX Corporation', 'US'], + ['O', 'Realty Income', 'US'], + ['REG', 'Regency Centers', 'US'], + ['REGN', 'Regeneron Pharmaceuticals', 'US'], + ['RF', 'Regions Financial Corporation', 'US'], + ['RSG', 'Republic Services', 'US'], + ['RMD', 'ResMed|', 'US'], + ['RVTY', 'Revvity', 'US'], + ['HOOD', 'Robinhood Markets', 'US'], + ['ROK', 'Rockwell Automation', 'US'], + ['ROL', 'Rollins, Inc.', 'US'], + ['ROP', 'Roper Technologies', 'US'], + ['ROST', 'Ross Stores', 'US'], + ['RCL', 'Royal Caribbean Group', 'US'], + ['SPGI', 'S&P Global', 'US'], + ['CRM', 'Salesforce', 'US'], + ['SNDK', 'Sandisk', 'US'], + ['SBAC', 'SBA Communications', 'US'], + ['SLB', 'Schlumberger', 'US'], + ['STX', 'Seagate Technology', 'US'], + ['SRE', 'Sempra', 'US'], + ['NOW', 'ServiceNow', 'US'], + ['SHW', 'Sherwin-Williams', 'US'], + ['SPG', 'Simon Property Group', 'US'], + ['SWKS', 'Skyworks Solutions', 'US'], + ['SJM', 'J.M. Smucker Company (The)', 'US'], + ['SW', 'Smurfit Westrock', 'US'], + ['SNA', 'Snap-on', 'US'], + ['SOLV', 'Solventum', 'US'], + ['SO', 'Southern Company', 'US'], + ['LUV', 'Southwest Airlines', 'US'], + ['SWK', 'Stanley Black & Decker', 'US'], + ['SBUX', 'Starbucks', 'US'], + ['STT', 'State Street Corporation', 'US'], + ['STLD', 'Steel Dynamics', 'US'], + ['STE', 'Steris', 'US'], + ['SYK', 'Stryker Corporation', 'US'], + ['SMCI', 'Supermicro', 'US'], + ['SYF', 'Synchrony Financial', 'US'], + ['SNPS', 'Synopsys', 'US'], + ['SYY', 'Sysco', 'US'], + ['TMUS', 'T-Mobile US', 'US'], + ['TROW', 'T. Rowe Price', 'US'], + ['TTWO', 'Take-Two Interactive', 'US'], + ['TPR', 'Tapestry, Inc.', 'US'], + ['TRGP', 'Targa Resources', 'US'], + ['TGT', 'Target Corporation', 'US'], + ['TEL', 'TE Connectivity', 'US'], + ['TDY', 'Teledyne Technologies', 'US'], + ['TER', 'Teradyne', 'US'], + ['TSLA', 'Tesla, Inc.', 'US'], + ['TXN', 'Texas Instruments', 'US'], + ['TPL', 'Texas Pacific Land Corporation', 'US'], + ['TXT', 'Textron', 'US'], + ['TMO', 'Thermo Fisher Scientific', 'US'], + ['TJX', 'TJX Companies', 'US'], + ['TKO', 'TKO Group Holdings', 'US'], + ['TTD', 'Trade Desk (The)', 'US'], + ['TSCO', 'Tractor Supply', 'US'], + ['TT', 'Trane Technologies', 'US'], + ['TDG', 'TransDigm Group', 'US'], + ['TRV', 'Travelers Companies (The)', 'US'], + ['TRMB', 'Trimble Inc.', 'US'], + ['TFC', 'Truist Financial', 'US'], + ['TYL', 'Tyler Technologies', 'US'], + ['TSN', 'Tyson Foods', 'US'], + ['USB', 'U.S. Bancorp', 'US'], + ['UBER', 'Uber', 'US'], + ['UDR', 'UDR, Inc.', 'US'], + ['ULTA', 'Ulta Beauty', 'US'], + ['UNP', 'Union Pacific Corporation', 'US'], + ['UAL', 'United Airlines Holdings', 'US'], + ['UPS', 'United Parcel Service', 'US'], + ['URI', 'United Rentals', 'US'], + ['UNH', 'UnitedHealth Group', 'US'], + ['UHS', 'Universal Health Services', 'US'], + ['VLO', 'Valero Energy', 'US'], + ['VEEV', 'Veeva Systems', 'US'], + ['VTR', 'Ventas', 'US'], + ['VLTO', 'Veralto', 'US'], + ['VRSN', 'Verisign', 'US'], + ['VRSK', 'Verisk Analytics', 'US'], + ['VZ', 'Verizon', 'US'], + ['VRTX', 'Vertex Pharmaceuticals', 'US'], + ['VRT', 'Vertiv', 'US'], + ['VTRS', 'Viatris', 'US'], + ['VICI', 'Vici Properties', 'US'], + ['V', 'Visa Inc.', 'US'], + ['VST', 'Vistra Corp.', 'US'], + ['VMC', 'Vulcan Materials Company', 'US'], + ['WRB', 'W. R. Berkley Corporation', 'US'], + ['GWW', 'W. W. Grainger', 'US'], + ['WAB', 'Wabtec', 'US'], + ['WMT', 'Walmart', 'US'], + ['DIS', 'Walt Disney Company (The)', 'US'], + ['WBD', 'Warner Bros. Discovery', 'US'], + ['WM', 'Waste Management', 'US'], + ['WAT', 'Waters Corporation', 'US'], + ['WEC', 'WEC Energy Group', 'US'], + ['WFC', 'Wells Fargo', 'US'], + ['WELL', 'Welltower', 'US'], + ['WST', 'West Pharmaceutical Services', 'US'], + ['WDC', 'Western Digital', 'US'], + ['WY', 'Weyerhaeuser', 'US'], + ['WSM', 'Williams-Sonoma, Inc.', 'US'], + ['WMB', 'Williams Companies', 'US'], + ['WTW', 'Willis Towers Watson', 'US'], + ['WDAY', 'Workday, Inc.', 'US'], + ['WYNN', 'Wynn Resorts', 'US'], + ['XEL', 'Xcel Energy', 'US'], + ['XYL', 'Xylem Inc.', 'US'], + ['YUM', 'Yum! Brands', 'US'], + ['ZBRA', 'Zebra Technologies', 'US'], + ['ZBH', 'Zimmer Biomet', 'US'], + ['ZTS', 'Zoetis', 'US'], +]) + +/** + * Representative liquid international listings used to diversify the fixture. + * Symbols use their local-market form and the third tuple value is an ISO-style + * country/market code, rather than a trading currency or exchange MIC. + * + * References checked 2026-08-15: STOXX Europe 50, KRX KOSPI market, + * JPX TOPIX Core30, and HKEX index constituent materials. + */ +const europeanInstruments = Object.freeze([ + ['ASML', 'ASML Holding', 'NL'], + ['INGA', 'ING Group', 'NL'], + ['ADYEN', 'Adyen', 'NL'], + ['PHIA', 'Philips', 'NL'], + ['HEIA', 'Heineken', 'NL'], + ['SAP', 'SAP', 'DE'], + ['SIE', 'Siemens', 'DE'], + ['ALV', 'Allianz', 'DE'], + ['DTE', 'Deutsche Telekom', 'DE'], + ['MBG', 'Mercedes-Benz Group', 'DE'], + ['BMW', 'BMW', 'DE'], + ['BAS', 'BASF', 'DE'], + ['MUV2', 'Munich Re', 'DE'], + ['VOW3', 'Volkswagen Preference', 'DE'], + ['IFX', 'Infineon Technologies', 'DE'], + ['MC', 'LVMH', 'FR'], + ['OR', "L'Oréal", 'FR'], + ['AIR', 'Airbus', 'FR'], + ['SU', 'Schneider Electric', 'FR'], + ['TTE', 'TotalEnergies', 'FR'], + ['SAN', 'Sanofi', 'FR'], + ['BNP', 'BNP Paribas', 'FR'], + ['CS', 'AXA', 'FR'], + ['DG', 'Vinci', 'FR'], + ['ENEL', 'Enel', 'IT'], + ['ENI', 'Eni', 'IT'], + ['ISP', 'Intesa Sanpaolo', 'IT'], + ['UCG', 'UniCredit', 'IT'], + ['STLAM', 'Stellantis', 'IT'], + ['SAN', 'Banco Santander', 'ES'], + ['IBE', 'Iberdrola', 'ES'], + ['ITX', 'Inditex', 'ES'], + ['BBVA', 'BBVA', 'ES'], + ['NESN', 'Nestlé', 'CH'], + ['ROG', 'Roche Holding', 'CH'], + ['NOVN', 'Novartis', 'CH'], + ['UBSG', 'UBS Group', 'CH'], + ['NOVO-B', 'Novo Nordisk', 'DK'], + ['MAERSK-B', 'A.P. Moller - Maersk', 'DK'], + ['VOLV-B', 'Volvo', 'SE'], + ['ERIC-B', 'Ericsson', 'SE'], + ['NOKIA', 'Nokia', 'FI'], + ['SHEL', 'Shell', 'GB'], + ['AZN', 'AstraZeneca', 'GB'], + ['HSBA', 'HSBC Holdings', 'GB'], + ['ULVR', 'Unilever', 'GB'], + ['LSEG', 'London Stock Exchange Group', 'GB'], +]) + +const europeanMarketCodes = Object.freeze([ + 'NL', + 'DE', + 'FR', + 'IT', + 'ES', + 'CH', + 'DK', + 'SE', + 'FI', + 'GB', +]) + +const europeanMarketGroups = Object.freeze( + europeanMarketCodes.map((market) => + europeanInstruments.filter(([, , instrumentMarket]) => + Object.is(instrumentMarket, market), + ), + ), +) + +const interleavedEuropeanInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...europeanMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + europeanMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const southKoreanInstruments = Object.freeze([ + ['005930', 'Samsung Electronics', 'KR'], + ['000660', 'SK hynix', 'KR'], + ['373220', 'LG Energy Solution', 'KR'], + ['207940', 'Samsung Biologics', 'KR'], + ['005380', 'Hyundai Motor', 'KR'], + ['000270', 'Kia', 'KR'], + ['068270', 'Celltrion', 'KR'], + ['105560', 'KB Financial Group', 'KR'], + ['055550', 'Shinhan Financial Group', 'KR'], + ['035420', 'NAVER', 'KR'], + ['035720', 'Kakao', 'KR'], + ['006400', 'Samsung SDI', 'KR'], + ['051910', 'LG Chem', 'KR'], + ['012330', 'Hyundai Mobis', 'KR'], + ['066570', 'LG Electronics', 'KR'], +]) + +const japaneseInstruments = Object.freeze([ + ['8306', 'Mitsubishi UFJ Financial Group', 'JP'], + ['7203', 'Toyota Motor', 'JP'], + ['6501', 'Hitachi', 'JP'], + ['8316', 'Sumitomo Mitsui Financial Group', 'JP'], + ['6758', 'Sony Group', 'JP'], + ['8058', 'Mitsubishi Corporation', 'JP'], + ['9984', 'SoftBank Group', 'JP'], + ['8035', 'Tokyo Electron', 'JP'], + ['8411', 'Mizuho Financial Group', 'JP'], + ['8031', 'Mitsui & Co.', 'JP'], + ['6861', 'Keyence', 'JP'], + ['7974', 'Nintendo', 'JP'], + ['6098', 'Recruit Holdings', 'JP'], + ['9432', 'Nippon Telegraph and Telephone', 'JP'], + ['4063', 'Shin-Etsu Chemical', 'JP'], +]) + +const hongKongInstruments = Object.freeze([ + ['0700', 'Tencent Holdings', 'HK'], + ['9988', 'Alibaba Group', 'HK'], + ['1810', 'Xiaomi', 'HK'], + ['3690', 'Meituan', 'HK'], + ['0941', 'China Mobile', 'HK'], + ['1211', 'BYD Company', 'HK'], + ['1299', 'AIA Group', 'HK'], + ['0388', 'Hong Kong Exchanges and Clearing', 'HK'], + ['0005', 'HSBC Holdings', 'HK'], + ['2318', 'Ping An Insurance', 'HK'], +]) + +const canadianInstruments = Object.freeze([ + ['RY', 'Royal Bank of Canada', 'CA'], + ['TD', 'Toronto-Dominion Bank', 'CA'], + ['SHOP', 'Shopify', 'CA'], + ['ENB', 'Enbridge', 'CA'], + ['CNR', 'Canadian National Railway', 'CA'], + ['CP', 'Canadian Pacific Kansas City', 'CA'], + ['BMO', 'Bank of Montreal', 'CA'], + ['CSU', 'Constellation Software', 'CA'], +]) + +const australianInstruments = Object.freeze([ + ['BHP', 'BHP Group', 'AU'], + ['CBA', 'Commonwealth Bank of Australia', 'AU'], + ['CSL', 'CSL', 'AU'], + ['NAB', 'National Australia Bank', 'AU'], + ['WBC', 'Westpac Banking Corporation', 'AU'], + ['ANZ', 'ANZ Group Holdings', 'AU'], + ['WES', 'Wesfarmers', 'AU'], + ['MQG', 'Macquarie Group', 'AU'], +]) + +const internationalMarketGroups = Object.freeze([ + interleavedEuropeanInstruments, + southKoreanInstruments, + japaneseInstruments, + hongKongInstruments, + canadianInstruments, + australianInstruments, +]) + +export const internationalInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...internationalMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + internationalMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const INTERNATIONAL_INSERTION_INTERVAL = 3 + +/** + * U.S. and international instruments are interleaved so ordinary benchmark + * sizes exercise multiple symbol formats and market labels. + */ +export const globalInstruments = Object.freeze( + marketInstruments.flatMap((instrument, index) => { + const internationalInstrument = + index % INTERNATIONAL_INSERTION_INTERVAL === 0 + ? internationalInstruments[index / INTERNATIONAL_INSERTION_INTERVAL] + : undefined + + return internationalInstrument + ? [instrument, internationalInstrument] + : [instrument] + }), +) as unknown as ReadonlyArray diff --git a/examples/octane/realtime-trading/src/feed/worker/market-feed-engine.ts b/examples/octane/realtime-trading/src/feed/worker/market-feed-engine.ts new file mode 100644 index 0000000000..fbd9c369c0 --- /dev/null +++ b/examples/octane/realtime-trading/src/feed/worker/market-feed-engine.ts @@ -0,0 +1,177 @@ +import { globalInstruments } from '../market-instruments.ts' +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const INITIAL_MARKET_SEED = 0x4d41524b +const LIVE_FEED_SEED = 0x5449434b + +export class MarketFeedEngine { + #quotes: Array = [] + #lastHistorySampledAt = new Uint32Array(0) + #random = createRandom(2_026) + #rowCursor = 0 + #tickIndex = 0 + + reset(count: number): Array { + const random = createRandom(INITIAL_MARKET_SEED ^ count) + const createdAt = Date.now() + + this.#quotes = Array.from({ length: count }, (_, index) => { + const [baseSymbol, company, market] = + globalInstruments[index % globalInstruments.length] + const series = Math.floor(index / globalInstruments.length) + const symbol = series === 0 ? baseSymbol : `${baseSymbol}${series}` + const previousClose = roundPrice(20 + random() * 480) + const open = roundPrice(previousClose * (1 + (random() - 0.5) * 0.016)) + const spread = Math.max(0.01, open * (0.0002 + random() * 0.0004)) + const history = Array.from({ length: 24 }, (_, historyIndex) => + roundPrice( + open * + (1 + Math.sin(historyIndex / 4) * 0.002 + (random() - 0.5) * 0.001), + ), + ) + const volume = Math.floor(50_000 + random() * 2_000_000) + const lastSize = Math.floor(10 + random() * 5_000) + + return { + id: `instrument-${index}`, + symbol, + company, + venue: market, + previousClose, + open, + high: open, + low: open, + price: open, + bid: roundPrice(open - spread / 2), + ask: roundPrice(open + spread / 2), + bidSize: Math.floor(100 + random() * 25_000), + askSize: Math.floor(100 + random() * 25_000), + lastSize, + lastMove: 0, + lastUpdatedAt: createdAt, + volume, + turnover: roundMoney(open * volume), + history, + } + }) + + this.#random = createRandom(LIVE_FEED_SEED ^ count) + this.#rowCursor = 0 + this.#lastHistorySampledAt = new Uint32Array(count) + this.#lastHistorySampledAt.fill(createdAt >>> 0) + + return this.#quotes.map((quote) => ({ + ...quote, + history: [...quote.history], + })) + } + + applyTicks( + tickCount: number, + updateSparklines: boolean, + sparklineSampleIntervalMs: number, + ): Array { + if (this.#quotes.length === 0 || tickCount <= 0) return [] + + const updatedAt = Date.now() + const sampledAt = updatedAt >>> 0 + const sampleIntervalMs = Math.max(16, sparklineSampleIntervalMs) + const updatedQuotes = new Map() + const stride = 97 + + this.#tickIndex = 0 + while (this.#tickIndex < tickCount) { + this.#rowCursor = (this.#rowCursor + stride) % this.#quotes.length + const quote = this.#quotes[this.#rowCursor] + const lastSampledAt = this.#lastHistorySampledAt[this.#rowCursor] + const shouldUpdateHistory = + updateSparklines && + (sampledAt - lastSampledAt) >>> 0 >= sampleIntervalMs + + if (shouldUpdateHistory) { + this.#lastHistorySampledAt[this.#rowCursor] = sampledAt + } + + this.#applyTick(quote, shouldUpdateHistory, updatedAt) + + const previousUpdate = updatedQuotes.get(this.#rowCursor) + updatedQuotes.set(this.#rowCursor, { + index: this.#rowCursor, + price: quote.price, + bid: quote.bid, + ask: quote.ask, + bidSize: quote.bidSize, + askSize: quote.askSize, + lastSize: quote.lastSize, + lastMove: quote.lastMove, + lastUpdatedAt: quote.lastUpdatedAt, + high: quote.high, + low: quote.low, + volume: quote.volume, + turnover: quote.turnover, + ...(shouldUpdateHistory || previousUpdate?.history + ? { history: [...quote.history] } + : {}), + }) + this.#tickIndex++ + } + + return [...updatedQuotes.values()] + } + + #applyTick( + quote: MarketQuoteSnapshot, + updateHistory: boolean, + updatedAt: number, + ): void { + const previousPrice = quote.price + const volatility = 0.00015 + this.#random() * 0.0012 + const move = previousPrice * (this.#random() - 0.495) * volatility + const nextPrice = roundPrice(Math.max(0.1, previousPrice + move)) + const spread = Math.max( + 0.01, + nextPrice * (0.00015 + this.#random() * 0.0005), + ) + + quote.lastMove = nextPrice - previousPrice + quote.price = nextPrice + quote.high = Math.max(quote.high, nextPrice) + quote.low = Math.min(quote.low, nextPrice) + quote.bid = roundPrice(nextPrice - spread / 2) + quote.ask = roundPrice(nextPrice + spread / 2) + quote.bidSize = Math.floor(100 + this.#random() * 25_000) + quote.askSize = Math.floor(100 + this.#random() * 25_000) + quote.lastSize = Math.floor(10 + this.#random() * 5_000) + quote.lastUpdatedAt = updatedAt + quote.volume += quote.lastSize + quote.turnover = roundMoney(quote.turnover + nextPrice * quote.lastSize) + + if (updateHistory) { + quote.history = [...quote.history.slice(-23), nextPrice] + } + } +} + +function createRandom(seed: number): () => number { + const runtime = { state: seed >>> 0 } + return () => { + runtime.state += 0x6d2b79f5 + const stateValue = runtime.state + const firstMix = Math.imul(stateValue ^ (stateValue >>> 15), stateValue | 1) + const secondMix = + firstMix + Math.imul(firstMix ^ (firstMix >>> 7), firstMix | 61) + const value = firstMix ^ secondMix + return ((value ^ (value >>> 14)) >>> 0) / 4_294_967_296 + } +} + +function roundPrice(value: number): number { + return Math.round(value * 100) / 100 +} + +function roundMoney(value: number): number { + return Math.round(value * 100) / 100 +} diff --git a/examples/octane/realtime-trading/src/feed/worker/market-feed-protocol.ts b/examples/octane/realtime-trading/src/feed/worker/market-feed-protocol.ts new file mode 100644 index 0000000000..21997ec89c --- /dev/null +++ b/examples/octane/realtime-trading/src/feed/worker/market-feed-protocol.ts @@ -0,0 +1,70 @@ +export interface MarketQuoteSnapshot { + id: string + symbol: string + company: string + venue: string + previousClose: number + open: number + high: number + low: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + volume: number + turnover: number + history: Array +} + +export interface MarketQuoteUpdate { + index: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + high: number + low: number + volume: number + turnover: number + history?: Array +} + +export type MarketFeedCommand = + | { + type: 'start' + rowCount: number + running: boolean + ticksPerSecond: number + publishIntervalMs: number + updateSparklines: boolean + sparklineSampleIntervalMs: number + } + | { type: 'set-running'; running: boolean } + | { type: 'set-rate'; ticksPerSecond: number } + | { type: 'set-publish-interval'; intervalMs: number } + | { type: 'set-sparklines'; enabled: boolean } + | { type: 'set-sparkline-interval'; intervalMs: number } + | { type: 'reset'; rowCount: number } + | { type: 'burst'; tickCount: number } + +export type MarketFeedEvent = + | { + type: 'snapshot' + sessionId: number + quotes: Array + } + | { + type: 'updates' + sessionId: number + tickCount: number + coalescedUpdateCount: number + updates: Array + } diff --git a/examples/octane/realtime-trading/src/feed/worker/market-feed.worker.ts b/examples/octane/realtime-trading/src/feed/worker/market-feed.worker.ts new file mode 100644 index 0000000000..2b7a642fd9 --- /dev/null +++ b/examples/octane/realtime-trading/src/feed/worker/market-feed.worker.ts @@ -0,0 +1,143 @@ +import { initialMarketFeedConfig } from '../market-feed-config' +import { MarketFeedEngine } from './market-feed-engine' +import type { + MarketFeedCommand, + MarketFeedEvent, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const engine = new MarketFeedEngine() +const pendingUpdates = new Map() +const runtime = { + sessionId: 0, + pendingTickCount: 0, + pendingCoalescedUpdateCount: 0, + initialized: false, + running: true, + ticksPerSecond: initialMarketFeedConfig.targetSamplesPerSecond, + publishIntervalMs: initialMarketFeedConfig.publishIntervalMs, + publishTimerId: null as ReturnType | null, + updateSparklines: initialMarketFeedConfig.updateSparklines, + sparklineSampleIntervalMs: initialMarketFeedConfig.sparklineSampleIntervalMs, + tickBudget: 0, + lastTickAt: performance.now(), +} + +addEventListener('message', ({ data }: MessageEvent) => { + switch (data.type) { + case 'start': + runtime.running = data.running + runtime.ticksPerSecond = data.ticksPerSecond + runtime.publishIntervalMs = data.publishIntervalMs + runtime.updateSparklines = data.updateSparklines + runtime.sparklineSampleIntervalMs = data.sparklineSampleIntervalMs + restartPublishTimer() + reset(data.rowCount) + break + case 'set-running': + runtime.running = data.running + break + case 'set-rate': + runtime.ticksPerSecond = data.ticksPerSecond + break + case 'set-publish-interval': + runtime.publishIntervalMs = Math.max(4, data.intervalMs) + restartPublishTimer() + break + case 'set-sparklines': + runtime.updateSparklines = data.enabled + break + case 'set-sparkline-interval': + runtime.sparklineSampleIntervalMs = Math.max(16, data.intervalMs) + break + case 'reset': + reset(data.rowCount) + break + case 'burst': + produceTicks(data.tickCount) + flush() + break + } +}) + +setInterval(() => { + const now = performance.now() + const elapsed = Math.min(100, Math.max(0, now - runtime.lastTickAt)) + runtime.lastTickAt = now + + if (runtime.initialized && runtime.running) { + runtime.tickBudget += (runtime.ticksPerSecond * elapsed) / 1_000 + const tickCount = Math.floor(runtime.tickBudget) + runtime.tickBudget -= tickCount + produceTicks(tickCount) + } +}, 16) + +restartPublishTimer() + +function reset(rowCount: number): void { + runtime.initialized = true + runtime.sessionId++ + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + runtime.tickBudget = 0 + runtime.lastTickAt = performance.now() + + post({ + type: 'snapshot', + sessionId: runtime.sessionId, + quotes: engine.reset(rowCount), + }) +} + +function produceTicks(tickCount: number): void { + if (!runtime.initialized || tickCount <= 0) return + + runtime.pendingTickCount += tickCount + for (const update of engine.applyTicks( + tickCount, + runtime.updateSparklines, + runtime.sparklineSampleIntervalMs, + )) { + const previousUpdate = pendingUpdates.get(update.index) + if (previousUpdate) runtime.pendingCoalescedUpdateCount++ + pendingUpdates.set(update.index, { + ...update, + ...(update.history || !previousUpdate?.history + ? {} + : { history: previousUpdate.history }), + }) + } +} + +function flush(): void { + if (runtime.pendingTickCount === 0) return + + const message: MarketFeedEvent = { + type: 'updates', + sessionId: runtime.sessionId, + tickCount: runtime.pendingTickCount, + coalescedUpdateCount: runtime.pendingCoalescedUpdateCount, + updates: [...pendingUpdates.values()], + } + + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + post(message) +} + +function restartPublishTimer(): void { + if (runtime.publishTimerId !== null) { + clearInterval(runtime.publishTimerId) + } + runtime.publishTimerId = setInterval( + flush, + Math.max(4, runtime.publishIntervalMs), + ) +} + +function post(event: MarketFeedEvent): void { + postMessage(event) +} diff --git a/examples/octane/realtime-trading/src/index.css b/examples/octane/realtime-trading/src/index.css new file mode 100644 index 0000000000..de3e3d9155 --- /dev/null +++ b/examples/octane/realtime-trading/src/index.css @@ -0,0 +1,1014 @@ +:root { + color-scheme: dark; + --font-ui: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + 'Segoe UI', sans-serif; + --font-mono: 'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace; + font-family: var(--font-ui); + font-synthesis: none; + --background: #050505; + --panel: #080808; + --panel-raised: #111111; + --panel-hover: #181818; + --surface-bar: #080808; + --surface-toolbar: #0d0d0d; + --surface-table: #050505; + --surface-header: #101010; + --surface-control: #151515; + --border: #303030; + --border-soft: #242424; + --border-strong: #4a4a4a; + --text: #e7ebf0; + --text-strong: #ffffff; + --text-inverse: #f7f9fb; + --muted: #737982; + --blue: #62a9ff; + --blue-soft: #a9d0ff; + --green: #42e488; + --red: #ff646b; + --amber: #dfb465; + --depth-bid: #315774; + --depth-ask: #634049; + --row-alt: rgb(255 255 255 / 1.8%); + --row-selected: rgb(66 132 214 / 16%); + --control-border: #354456; + --control-hover: #192431; + --sidebar-width: 18rem; + --shell-bar-height: 2.625rem; + --metrics-height: 3.5rem; + --statusbar-height: 1.625rem; + --table-header-height: 2rem; + --table-row-height: 2rem; + --shell-inline-padding: 0.75rem; + --table-cell-inline-padding: 0.6rem; + --control-radius: 1px; +} + +* { + box-sizing: border-box; +} + +html, +body { + min-width: 320px; + min-height: 100%; + margin: 0; + background: var(--background); +} + +body { + color: var(--text); +} + +button, +select, +input { + font: inherit; +} + +button, +select { + color: var(--text); + background: var(--panel-raised); + border: 1px solid var(--control-border); + border-radius: var(--control-radius); +} + +button { + padding: 0.5rem 0.65rem; + cursor: pointer; + font-size: 0.72rem; + font-weight: 650; + letter-spacing: 0.025em; +} + +button:hover { + background: var(--control-hover); + border-color: var(--border-strong); +} + +button:focus-visible, +select:focus-visible, +input:focus-visible { + outline: 1px solid var(--blue); + outline-offset: 1px; +} + +select { + width: 100%; + padding: 0.45rem 0.55rem; + font-size: 0.75rem; +} + +.trading-terminal { + --active-sidebar-width: var(--sidebar-width); + display: grid; + width: 100%; + height: 100dvh; + min-height: 0; + overflow: hidden; + background: var(--background); + grid-template-areas: + 'header sidebar' + 'content sidebar' + 'footer sidebar'; + grid-template-columns: minmax(0, 1fr) var(--active-sidebar-width); + grid-template-rows: auto minmax(0, 1fr) auto; + transition: grid-template-columns 160ms ease; +} + +.trading-terminal.is-sidebar-collapsed { + --active-sidebar-width: 0px; +} + +.shell-header { + display: flex; + min-width: 0; + flex-direction: column; + grid-area: header; +} + +.app-bar { + display: flex; + min-height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + background: var(--surface-bar); + border-bottom: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.68rem; + letter-spacing: 0.045em; +} + +.brand, +.header-actions, +.feed-status { + display: flex; + align-items: center; +} + +.brand { + gap: 0.65rem; + color: var(--text-strong); +} + +.header-actions { + gap: 0.75rem; +} + +.sidebar-toggle { + display: grid; + width: 1.9rem; + height: 1.9rem; + padding: 0; + place-items: center; + color: var(--muted); + background: transparent; + border-color: transparent; +} + +.sidebar-toggle:hover { + color: var(--text-strong); + background: var(--surface-control); + border-color: var(--border); +} + +.sidebar-toggle svg { + width: 1rem; + height: 1rem; + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-width: 1.4; +} + +.feed-status { + gap: 0.4rem; + color: var(--muted); +} + +.feed-status.is-running { + color: var(--green); +} + +.status-dot { + width: 6px; + height: 6px; + background: var(--muted); + border-radius: 50%; +} + +.feed-status.is-running .status-dot { + background: var(--green); +} + +.development-warning { + flex: 0 0 auto; + padding: 0.3rem 0.75rem; + color: var(--amber); + background: color-mix(in srgb, var(--amber) 8%, var(--background)); + border-bottom: 1px solid color-mix(in srgb, var(--amber) 24%, var(--border)); + font-family: var(--font-mono); + font-size: 0.62rem; + letter-spacing: 0.04em; +} + +.market-panel { + display: flex; + min-width: 0; + min-height: 0; + flex-direction: column; + background: var(--panel); + grid-area: content; +} + +.metrics-strip { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + background: var(--border); + border-bottom: 1px solid var(--border); + gap: 1px; +} + +.metrics-strip h2 { + margin: 0; + padding: 0.65rem var(--shell-inline-padding) 0.45rem; + color: var(--muted); + background: var(--surface-table); + font-size: 0.58rem; + grid-column: 1 / -1; + letter-spacing: 0.075em; +} + +.metrics-strip article { + min-width: 0; + min-height: 4.25rem; + padding: 0.5rem var(--shell-inline-padding); + background: var(--surface-bar); +} + +.metrics-strip span, +.metrics-strip small { + display: block; + color: var(--muted); + font-size: 0.56rem; + letter-spacing: 0.045em; + line-height: 1.35; +} + +.metrics-strip strong { + display: block; + margin: 0.12rem 0 0.08rem; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.88rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +.metrics-strip strong.metric-alert { + color: var(--amber); +} + +.table-scroll { + flex: 1; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +table { + min-width: 100%; + border-spacing: 0; + table-layout: fixed; + font-family: var(--font-ui); + font-size: 0.78rem; + font-variant-numeric: tabular-nums; +} + +.trading-data-grid { + display: grid; +} + +.trading-data-grid thead, +.trading-data-grid tbody { + display: grid; +} + +.trading-data-grid tbody { + -webkit-user-select: none; + user-select: none; +} + +.trading-data-grid thead > tr, +.trading-data-grid tbody > tr { + display: flex; + width: 100%; +} + +.trading-data-grid tbody > tr { + min-height: var(--table-row-height); + content-visibility: auto; + contain-intrinsic-block-size: var(--table-row-height); +} + +.trading-data-grid th, +.trading-data-grid td { + flex: 0 0 auto; +} + +thead { + position: sticky; + z-index: 2; + top: 0; +} + +th { + height: var(--table-header-height); + padding: 0 var(--table-cell-inline-padding); + color: var(--muted); + background: var(--surface-header); + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border); + font-size: 0.7rem; + font-weight: 500; + letter-spacing: 0.005em; + text-align: left; + white-space: nowrap; +} + +th.column-group-header { + color: #666b72; + font-size: 0.72rem; + font-weight: 500; + text-align: center; +} + +thead tr:first-child th.column-group-header { + color: #777d85; + font-size: 0.76rem; +} + +th.numeric-header { + text-align: right; +} + +td { + height: var(--table-row-height); + padding: 0 var(--table-cell-inline-padding); + overflow: hidden; + color: #eef1f5; + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border-soft); + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +th:last-child, +td:last-child { + border-right: 0; +} + +td[data-column-id='market'], +td[data-column-id='name'], +td[data-column-id='symbol'] { + text-align: left; +} + +td[data-column-id='market'] { + color: var(--blue); + font-weight: 550; +} + +td[data-column-id='name'] { + color: var(--text-strong); +} + +td[data-column-id='symbol'] { + color: #d8dde4; + font-weight: 600; +} + +tbody tr:nth-child(even) { + background: var(--row-alt); +} + +tbody tr:hover { + background: var(--panel-hover); +} + +tbody tr[data-symbol-selected='true'] { + background: var(--row-selected); + box-shadow: inset 2px 0 0 var(--blue); +} + +.table-scroll:focus { + outline: none; +} + +th { + position: relative; +} + +.leaf-header-content { + display: flex; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + height: 100%; + align-items: stretch; + margin-inline: calc(-1 * var(--table-cell-inline-padding)); +} + +.column-drag-handle, +.sort-header-button { + min-width: 0; + height: 100%; + padding: 0; + color: inherit; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-weight: inherit; + letter-spacing: inherit; +} + +.column-drag-handle { + flex: 0 0 1.05rem; + color: var(--muted); + cursor: grab; + opacity: 0.35; + font-size: 0.56rem; + letter-spacing: -0.32rem; + text-align: center; +} + +.column-drag-handle:active { + cursor: grabbing; +} + +th:hover .column-drag-handle, +.column-drag-handle:focus-visible { + opacity: 0.9; +} + +.column-drag-handle:hover, +.sort-header-button:hover { + background: rgb(255 255 255 / 4%); + border-color: transparent; +} + +th.is-column-dragging { + opacity: 0.45; +} + +th.is-column-drop-target { + background: rgb(50 139 255 / 16%); + box-shadow: inset 4px 0 0 var(--blue); +} + +th.is-column-drop-target::before { + position: absolute; + z-index: 6; + top: -1px; + bottom: -1px; + left: -2px; + width: 4px; + background: #62a9ff; + box-shadow: + 0 0 0 1px rgb(0 0 0 / 55%), + 0 0 12px rgb(70 151 255 / 90%); + content: ''; + pointer-events: none; +} + +.sort-header-button { + display: flex; + min-width: 0; + flex: 1; + align-items: center; + justify-content: flex-start; + gap: 0.3rem; + padding-inline: 0.25rem var(--table-cell-inline-padding); + cursor: default; + text-align: inherit; +} + +.numeric-header .sort-header-button { + justify-content: flex-end; +} + +.sort-header-button.is-sortable { + cursor: pointer; +} + +.sort-header-button:disabled { + opacity: 1; +} + +.header-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.sort-indicator { + flex: 0 0 auto; + color: #66717e; + font-size: 0.72rem; +} + +.sort-indicator.is-active { + color: var(--blue-soft); +} + +.column-resize-handle { + position: absolute; + z-index: 3; + top: 0; + right: -3px; + width: 7px; + height: 100%; + cursor: col-resize; + touch-action: none; + user-select: none; +} + +.column-resize-handle::after { + position: absolute; + top: 20%; + right: 3px; + width: 1px; + height: 60%; + background: var(--border-strong); + content: ''; + opacity: 0; +} + +th:hover > .column-resize-handle::after, +.column-resize-handle.is-resizing::after { + background: var(--blue); + opacity: 1; +} + +tbody tr[aria-selected='true'] { + background: rgb(76 145 228 / 13%); +} + +td[aria-selected='true'] { + position: relative; + background: rgb(70 139 222 / 12%); +} + +td[data-cell-focused='true'] { + background: rgb(70 139 222 / 21%); +} + +td[aria-selected='true']::after { + position: absolute; + z-index: 1; + inset: 0; + border: 1px solid transparent; + content: ''; + pointer-events: none; +} + +td[data-selection-top='true']::after { + border-top-color: var(--blue); +} + +td[data-selection-right='true']::after { + border-right-color: var(--blue); +} + +td[data-selection-bottom='true']::after { + border-bottom-color: var(--blue); +} + +td[data-selection-left='true']::after { + border-left-color: var(--blue); +} + +.price-button { + min-width: 4.5rem; + padding: 0; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-variant-numeric: tabular-nums; + font-weight: 600; + text-align: right; +} + +.price-button:hover { + background: transparent; + text-decoration: underline; + text-underline-offset: 2px; +} + +.move-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.move-cell.quote-up, +.percent-change-cell.quote-up { + background: color-mix(in srgb, var(--green) 7%, transparent); +} + +.move-cell.quote-down, +.percent-change-cell.quote-down { + background: color-mix(in srgb, var(--red) 7%, transparent); +} + +.percent-change-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.spread-cell { + display: flex; + align-items: baseline; + justify-content: flex-end; + gap: 0.35rem; + color: var(--text); +} + +.spread-cell small { + min-width: 2.8rem; + color: var(--muted); + font-size: 0.55rem; +} + +.spread-cell.spread-wide, +.spread-cell.spread-wide small { + color: var(--amber); +} + +.depth-cell { + position: relative; + display: flex; + height: 17px; + overflow: hidden; + background: var(--surface-control); +} + +.depth-bid, +.depth-ask { + height: 100%; + opacity: 0.78; +} + +.depth-bid { + background: var(--depth-bid); + border-right: 1px solid var(--panel); +} + +.depth-ask { + background: var(--depth-ask); +} + +.depth-values { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 0.28rem; + color: var(--text-strong); + font-size: 0.57rem; + text-shadow: 0 1px var(--background); +} + +.quote-age { + color: var(--muted); +} + +.quote-age-warm { + color: var(--amber); +} + +.quote-age-stale { + color: var(--red); +} + +.quote-up { + color: var(--green); +} + +.quote-down { + color: var(--red); +} + +.sparkline { + display: block; + width: 100%; + height: 1.35rem; + margin-left: auto; + color: var(--blue-soft); + overflow: visible; +} + +.sparkline.quote-up { + color: var(--green); +} + +.sparkline.quote-down { + color: var(--red); +} + +.sparkline polyline { + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-linejoin: miter; + stroke-width: 1.25; + vector-effect: non-scaling-stroke; +} + +.market-statusbar { + display: flex; + flex: 0 0 var(--statusbar-height); + min-height: var(--statusbar-height); + gap: 1.1rem; + align-items: center; + padding: 0 0.65rem; + color: var(--muted); + background: var(--surface-bar); + border-top: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.56rem; + grid-area: footer; + letter-spacing: 0.035em; +} + +.market-statusbar strong { + margin-left: 0.25rem; + color: var(--text); + font-weight: 500; +} + +.sidebar-slot { + width: var(--sidebar-width); + min-width: 0; + min-height: 0; + overflow: hidden; + background: var(--surface-table); + border-left: 1px solid var(--border); + grid-area: sidebar; + transition: + opacity 120ms ease, + transform 160ms ease, + visibility 160ms; +} + +.is-sidebar-collapsed .sidebar-slot { + visibility: hidden; + opacity: 0; + pointer-events: none; + transform: translateX(100%); +} + +.configurator { + width: 100%; + height: 100%; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +.configurator > header { + display: flex; + height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + color: var(--text-strong); + background: var(--surface-toolbar); + border-bottom: 1px solid var(--border); + font-size: 0.65rem; + font-weight: 700; + letter-spacing: 0.055em; +} + +.configurator > header small { + color: var(--muted); + font-size: 0.54rem; + font-weight: 500; +} + +.config-section { + display: grid; + gap: 0.7rem; + padding: 0.8rem var(--shell-inline-padding); + border-bottom: 1px solid var(--border); +} + +.config-section h2 { + margin: 0; + color: var(--muted); + font-size: 0.58rem; + letter-spacing: 0.075em; +} + +.primary-action { + width: 100%; + color: var(--text-inverse); + background: var(--blue); + border-color: var(--blue-soft); +} + +.primary-action:hover { + background: var(--blue-soft); + border-color: var(--text-strong); +} + +.field { + display: grid; + gap: 0.35rem; + color: var(--text); + font-size: 0.66rem; +} + +.rate-field > span { + display: flex; + justify-content: space-between; +} + +.rate-field strong { + color: var(--text); + font-family: var(--font-mono); + font-weight: 500; +} + +.field small { + color: var(--muted); + font-family: var(--font-mono); + font-size: 0.55rem; +} + +input[type='range'] { + width: 100%; + margin: 0; + accent-color: var(--blue); +} + +.toggle-field { + display: flex; + gap: 0.5rem; + align-items: flex-start; + color: var(--text); + font-size: 0.66rem; + line-height: 1.3; +} + +.toggle-field input { + margin: 0.12rem 0 0; + accent-color: var(--blue); +} + +.toggle-field small { + display: block; + margin-top: 0.14rem; + color: var(--muted); + font-size: 0.57rem; +} + +.action-grid { + display: grid; + grid-template-columns: 1fr; + gap: 0.4rem; +} + +.diagnostics dl, +.selected-instrument dl { + display: grid; + gap: 0; + margin: 0; +} + +.diagnostics dl > div, +.selected-instrument dl > div { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 24px; + border-bottom: 1px solid var(--border-soft); +} + +.diagnostics dl > div:last-child, +.selected-instrument dl > div:last-child { + border-bottom: 0; +} + +.diagnostics dl > div:has(dd[data-testid$='-breakdown']) { + display: grid; + grid-template-columns: minmax(0, 1fr); + align-content: center; + padding-block: 0.28rem; +} + +.diagnostics dd[data-testid$='-breakdown'] { + width: 100%; + overflow-x: auto; + padding-block: 0.12rem; + white-space: nowrap; + scrollbar-width: thin; +} + +.diagnostic-note { + margin: 0.5rem 0 0; + color: var(--muted); + font-size: 0.56rem; + line-height: 1.45; +} + +dt { + color: var(--muted); + font-size: 0.61rem; +} + +dd { + margin: 0; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.62rem; +} + +.selection { + display: flex; + align-items: flex-start; + justify-content: space-between; +} + +.selection div { + display: grid; + gap: 0.18rem; +} + +.selection strong { + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.85rem; +} + +.selection span, +.selection small, +.selected-instrument p { + color: var(--muted); + font-size: 0.61rem; +} + +.selected-instrument p { + margin: 0; + line-height: 1.45; +} + +@media (max-width: 980px) { + :root { + --sidebar-width: 15.625rem; + } +} + +@media (max-width: 720px) { + .trading-terminal { + --active-sidebar-width: 0px; + height: 100dvh; + min-height: 0; + overflow: hidden; + } + + .market-panel { + min-height: 0; + } + + .table-scroll { + min-height: 0; + } + + .sidebar-slot { + position: fixed; + z-index: 20; + top: 0; + right: 0; + bottom: 0; + width: min(var(--sidebar-width), calc(100vw - 2.75rem)); + box-shadow: -18px 0 42px rgb(0 0 0 / 48%); + } + + .is-sidebar-collapsed .sidebar-slot { + box-shadow: none; + } +} diff --git a/examples/octane/realtime-trading/src/main.tsrx b/examples/octane/realtime-trading/src/main.tsrx new file mode 100644 index 0000000000..d7b6eaee20 --- /dev/null +++ b/examples/octane/realtime-trading/src/main.tsrx @@ -0,0 +1,12 @@ +import { createRoot } from 'octane' +import { TradingBenchmarkController } from './benchmark/trading-benchmark-controller' +import { MarketFeedController } from './feed/market-feed-controller' +import { TradingShell } from './shell/TradingShell.tsrx' +import './index.css' + +const rootElement = document.getElementById('root') +if (!rootElement) throw new Error('Failed to find the root element') + +const feed = new MarketFeedController() +const controller = new TradingBenchmarkController(feed) +createRoot(rootElement).render(() => ) diff --git a/examples/octane/realtime-trading/src/shell/AppHeader.tsrx b/examples/octane/realtime-trading/src/shell/AppHeader.tsrx new file mode 100644 index 0000000000..59e44b77be --- /dev/null +++ b/examples/octane/realtime-trading/src/shell/AppHeader.tsrx @@ -0,0 +1,30 @@ +import { useSelector } from '@tanstack/octane-store' +import type { MarketFeedController } from '../feed/market-feed-controller' + +export function AppHeader(props: { + feed: MarketFeedController + sidebarOpen: boolean + toggleSidebar: () => void +}) @{ + const workerReady = useSelector(props.feed.workerReady) + const running = useSelector(props.feed.running) + const status = !workerReady ? 'FEED CONNECTING' : running ? 'FEED LIVE' : 'FEED PAUSED' +
+
MARKET MONITOR
+
+ + + +
+
+} diff --git a/examples/octane/realtime-trading/src/shell/Configurator.tsrx b/examples/octane/realtime-trading/src/shell/Configurator.tsrx new file mode 100644 index 0000000000..6e08e79b7a --- /dev/null +++ b/examples/octane/realtime-trading/src/shell/Configurator.tsrx @@ -0,0 +1,105 @@ +import { feedSampleRateAt, feedSampleRateIndex, feedSampleRateOptions } from '../feed/feed-sample-rates' +import { useSelector } from '@tanstack/octane-store' +import { configuratorOptions } from './configurator-options' +import { Diagnostics } from './Diagnostics.tsrx' +import { MetricsStrip } from './MetricsStrip.tsrx' +import { SelectedInstrument } from './SelectedInstrument.tsrx' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' + +const rate = new Intl.NumberFormat('en-US', { notation: 'compact', maximumFractionDigits: 1 }) + +export function Configurator(props: { + controller: TradingBenchmarkController + feed: MarketFeedController +}) @{ + const running = useSelector(props.feed.running) + const instrumentCount = useSelector(props.feed.instrumentCount) + const targetTicksPerSecond = useSelector(props.feed.targetTicksPerSecond) + const publishIntervalMs = useSelector(props.feed.publishIntervalMs) + const updateSparklines = useSelector(props.feed.updateSparklines) + const sparklineSampleIntervalMs = useSelector( + props.feed.sparklineSampleIntervalMs, + ) + const rendererMode = useSelector(props.controller.renderAtoms.rendererMode) + const value = (event: Event): string => (event.target as HTMLInputElement | HTMLSelectElement).value + const number = (event: Event): number => Number(value(event)) + const checked = (event: Event): boolean => (event.target as HTMLInputElement).checked + + +} diff --git a/examples/octane/realtime-trading/src/shell/Diagnostics.tsrx b/examples/octane/realtime-trading/src/shell/Diagnostics.tsrx new file mode 100644 index 0000000000..2226b4a1e1 --- /dev/null +++ b/examples/octane/realtime-trading/src/shell/Diagnostics.tsrx @@ -0,0 +1,51 @@ +import { useSelector } from '@tanstack/octane-store' +import type { NamedInvocationRate } from '../benchmark/benchmark-monitor' +import type { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' + +const integer = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }) +const rate = new Intl.NumberFormat('en-US', { notation: 'compact', maximumFractionDigits: 1 }) +const ms = (value: number): string => `${value.toFixed(2)} ms` +const invocations = (values: ReadonlyArray): string => { + const active = values.filter((entry) => entry.callsPerSecond > 0) + return active.length ? active.map((entry) => `${entry.name} ${rate.format(entry.callsPerSecond)}`).join(' · ') : '—' +} + +export function Diagnostics({ controller }: { controller: TradingBenchmarkController }) @{ + const state = useSelector(controller.store) + const metrics = state.metrics + const items = [ + ['Mounted cells', integer.format(state.mountedCells), ''], + ['Live components', integer.format(state.liveComponents), ''], + ['Created / destroyed', `${integer.format(metrics.componentsCreated)} / ${integer.format(metrics.componentsDestroyed)}`, ''], + ['Renderer callbacks / s', rate.format(metrics.cellRendererCallsPerSecond), 'cell-render-rate'], + ['Component executions / s', rate.format(metrics.componentRenderCallsPerSecond), 'component-render-rate'], + ['Executions by component / s', invocations(metrics.componentRenderRates), 'component-render-breakdown'], + ['Callbacks by column / s', invocations(metrics.cellRendererRates), 'cell-render-breakdown'], + ['Observed MutationRecords / s', rate.format(metrics.domMutationsPerSecond), 'dom-mutation-rate'], + ['Worker samples / s', rate.format(metrics.actualTicksPerSecond), 'actual-rate'], + ['Worker messages / s', metrics.workerMessagesPerSecond.toFixed(1), 'message-rate'], + ['Changed rows / s', rate.format(metrics.rowUpdatesPerSecond), 'row-update-rate'], + ['State snapshots / s', metrics.stateApplicationsPerSecond.toFixed(1), 'state-apply-rate'], + ['Table DOM commits / s', metrics.tableRendersPerSecond.toFixed(1), 'table-render-rate'], + ['P95 / max commit latency (rolling 10 s)', `${ms(metrics.p95RenderMs)} / ${ms(metrics.maxRenderMs)}`, ''], + ['Core row model calls / s', metrics.rowModelCallsPerSecond.toFixed(1), 'row-model-call-rate'], + ['Core row model avg / max', `${ms(metrics.rowModelAverageMs)} / ${ms(metrics.rowModelMaxMs)}`, 'row-model-duration'], + ['Visible rows', integer.format(metrics.visibleRows), 'visible-row-count'], + ['Worker messages since reset', integer.format(metrics.workerMessages), 'worker-messages'], + ['Worker-coalesced updates / s', rate.format(metrics.supersededUpdatesPerSecond), 'superseded-update-rate'], + ['Last samples / updated rows', `${integer.format(metrics.lastBatchSize)} / ${integer.format(metrics.lastUpdateCount)}`, ''], + ['Commits > 16.7 ms since reset', integer.format(metrics.slowRenders), ''], + ['JS heap (GC-sensitive)', metrics.heapMb === null ? 'N/A' : `${metrics.heapMb.toFixed(1)} MB`, ''], + ] as const +
+

DIAGNOSTICS

+
+ @for (const item of items; key item[0]) { +
{item[0]}
{item[1]}
+ } +
+

+ MutationObserver counts delivered records, not individual DOM operations, and adds profiling overhead. Only class/style attributes, text, and child-list changes are observed. Heap is a Chromium-only point-in-time value and can move before garbage collection. +

+
+} diff --git a/examples/octane/realtime-trading/src/shell/MarketStatusbar.tsrx b/examples/octane/realtime-trading/src/shell/MarketStatusbar.tsrx new file mode 100644 index 0000000000..7f586ed543 --- /dev/null +++ b/examples/octane/realtime-trading/src/shell/MarketStatusbar.tsrx @@ -0,0 +1,24 @@ +import { shallow, useSelector } from '@tanstack/octane-store' +import type { TradingBenchmarkController, TradingBenchmarkState } from '../benchmark/trading-benchmark-controller' + +const integer = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }) +const selectStatusbarState = (state: TradingBenchmarkState) => ({ + lastBatchSize: state.metrics.lastBatchSize, + lastUpdateCount: state.metrics.lastUpdateCount, + mountedCells: state.mountedCells, + liveComponents: state.liveComponents, +}) + +export function MarketStatusbar({ controller }: { controller: TradingBenchmarkController }) @{ + const state = useSelector( + controller.store, + selectStatusbarState, + { compare: shallow }, + ) +
+ MESSAGE SAMPLES {integer.format(state.lastBatchSize)} + CHANGED ROWS {integer.format(state.lastUpdateCount)} + HOSTS {integer.format(state.mountedCells)} + COMPONENTS {integer.format(state.liveComponents)} +
+} diff --git a/examples/octane/realtime-trading/src/shell/MetricsStrip.tsrx b/examples/octane/realtime-trading/src/shell/MetricsStrip.tsrx new file mode 100644 index 0000000000..93938c1bee --- /dev/null +++ b/examples/octane/realtime-trading/src/shell/MetricsStrip.tsrx @@ -0,0 +1,22 @@ +import { useSelector } from '@tanstack/octane-store' +import type { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' + +const rate = new Intl.NumberFormat('en-US', { notation: 'compact', maximumFractionDigits: 1 }) +const ms = (value: number): string => `${value.toFixed(2)} ms` + +export function MetricsStrip({ controller }: { controller: TradingBenchmarkController }) @{ + const state = useSelector(controller.store) + const metrics = state.metrics + const items = [ + ['FRAME RATE (EST.)', metrics.rafCallbacksPerSecond.toFixed(1), 'rAF callbacks/s · rolling 1 s', 'frame-rate'], + ['AVG COMMIT', ms(metrics.averageRenderMs), 'snapshot → DOM · rolling 3 s', 'average-commit-latency'], + ['LONG FRAMES', state.longAnimationFramesSupported ? String(metrics.longAnimationFrames) : 'N/A', state.longAnimationFramesSupported ? `since reset · worst ${ms(metrics.worstLongAnimationFrameMs)}` : 'unsupported', 'long-frame-count'], + ['THROUGHPUT', `${rate.format(metrics.rowUpdatesPerSecond)} rows/s`, `${metrics.stateApplicationsPerSecond.toFixed(1)} snapshots/s · rows deduplicated per snapshot`, 'throughput-rate'], + ] as const +
+

LIVE HEALTH

+ @for (const item of items; key item[0]) { +
{item[0]}{item[1]}{item[2]}
+ } +
+} diff --git a/examples/octane/realtime-trading/src/shell/SelectedInstrument.tsrx b/examples/octane/realtime-trading/src/shell/SelectedInstrument.tsrx new file mode 100644 index 0000000000..6c69f7901b --- /dev/null +++ b/examples/octane/realtime-trading/src/shell/SelectedInstrument.tsrx @@ -0,0 +1,19 @@ +import { useSelector } from '@tanstack/octane-store' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' + +export function SelectedInstrument(props: { + controller: TradingBenchmarkController + feed: MarketFeedController +}) @{ + const quotes = useSelector(props.feed.quotes) + const symbol = useSelector(props.controller.renderAtoms.selectedSymbol) + const quote = props.feed.getQuoteBySymbol(quotes, symbol) +
+

SELECTED INSTRUMENT

+ {quote ? <> +
{quote.symbol}{quote.company}
{quote.venue}
+
Last
{quote.price.toFixed(2)}
Bid / ask
{quote.bid.toFixed(2)} / {quote.ask.toFixed(2)}
+ :

Click or begin a cell selection in any row to inspect its instrument.

} +
+} diff --git a/examples/octane/realtime-trading/src/shell/TradingShell.tsrx b/examples/octane/realtime-trading/src/shell/TradingShell.tsrx new file mode 100644 index 0000000000..d0cec4fa46 --- /dev/null +++ b/examples/octane/realtime-trading/src/shell/TradingShell.tsrx @@ -0,0 +1,36 @@ +import { useEffect, useState } from 'octane' +import { AppHeader } from './AppHeader.tsrx' +import { Configurator } from './Configurator.tsrx' +import { MarketStatusbar } from './MarketStatusbar.tsrx' +import { TradingTable } from '../table/TradingTable.tsrx' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' + +export function TradingShell(props: { + controller: TradingBenchmarkController + feed: MarketFeedController +}) @{ + const [sidebarOpen, setSidebarOpen] = useState(true) + useEffect(() => { + const stopFeed = props.feed.start() + const stopBenchmark = props.controller.start() + return () => { + stopBenchmark() + stopFeed() + } + }, [props.controller, props.feed]) + +
+
+ setSidebarOpen((open) => !open)} /> + {import.meta.env.DEV && } +
+
+ +
+ +
+ {sidebarOpen && } +
+
+} diff --git a/examples/octane/realtime-trading/src/shell/configurator-options.ts b/examples/octane/realtime-trading/src/shell/configurator-options.ts new file mode 100644 index 0000000000..5e21d71492 --- /dev/null +++ b/examples/octane/realtime-trading/src/shell/configurator-options.ts @@ -0,0 +1,49 @@ +export interface ConfiguratorOption { + readonly label: string + readonly value: TValue +} + +const instrumentCountOptions = [ + { label: '50', value: 50 }, + { label: '100', value: 100 }, + { label: '150', value: 150 }, + { label: '250', value: 250 }, + { label: '350', value: 350 }, + { label: '500', value: 500 }, + { label: '750', value: 750 }, + { label: '1,000', value: 1_000 }, + { label: '1,500', value: 1_500 }, + { label: '2,500', value: 2_500 }, + { label: '5,000', value: 5_000 }, + { label: '1,000,000', value: 1_000_000 }, + { label: '10,000,000', value: 10_000_000 }, +] as const satisfies ReadonlyArray> + +const workerDeliveryOptions = [ + { label: '8 ms · 125 msg/s', value: 8 }, + { label: '16 ms · 62.5 msg/s', value: 16 }, + { label: '20 ms · 50 msg/s', value: 20 }, + { label: '33 ms · 30 msg/s', value: 33 }, + { label: '50 ms · 20 msg/s', value: 50 }, + { label: '100 ms · 10 msg/s', value: 100 }, + { label: '250 ms · 4 msg/s', value: 250 }, + { label: '500 ms · 2 msg/s', value: 500 }, + { label: '1,000 ms · 1 msg/s', value: 1_000 }, +] as const satisfies ReadonlyArray> + +const intradaySamplingOptions = [ + { label: '16 ms · fastest', value: 16 }, + { label: '33 ms · very fast', value: 33 }, + { label: '50 ms · fast', value: 50 }, + { label: '100 ms', value: 100 }, + { label: '250 ms', value: 250 }, + { label: '500 ms', value: 500 }, + { label: '1,000 ms', value: 1_000 }, + { label: '2,000 ms', value: 2_000 }, +] as const satisfies ReadonlyArray> + +export const configuratorOptions = { + instrumentCounts: instrumentCountOptions, + workerDeliveryIntervals: workerDeliveryOptions, + intradaySamplingIntervals: intradaySamplingOptions, +} as const diff --git a/examples/octane/realtime-trading/src/table/TradingTable.tsrx b/examples/octane/realtime-trading/src/table/TradingTable.tsrx new file mode 100644 index 0000000000..ca3e74eb83 --- /dev/null +++ b/examples/octane/realtime-trading/src/table/TradingTable.tsrx @@ -0,0 +1,242 @@ +import { useLayoutEffect, useMemo, useRef } from 'octane' +import { useTable } from '@tanstack/octane-table' +import { startTableBenchmark } from '../benchmark/table-benchmark' +import { useSelector } from '@tanstack/octane-store' +import { createTradingColumns, readMeasuredRows } from './table-config/trading-columns.tsrx' +import { tradingFeatures } from './trading-features' +import { handleCellNavigation, reorderColumnIds, sortAriaValue, sortIndicator } from './table-interactions' +import { useTradingGridPointer } from './use-trading-grid-pointer' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { MarketQuote } from '../feed/market-data' +import type { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' + +interface TradingTableProps { + controller: TradingBenchmarkController + feed: MarketFeedController +} + +export function TradingTable({ controller, feed }: TradingTableProps) @{ + const quotes = useSelector(feed.quotes) + const rendererMode = useSelector(controller.renderAtoms.rendererMode) + const selectedSymbol = useSelector(controller.renderAtoms.selectedSymbol) + const columns = useMemo( + () => createTradingColumns(controller, rendererMode), + [controller, rendererMode], + ) + const table = useTable( + { + features: tradingFeatures, + columns, + data: quotes, + getRowId: (row: MarketQuote) => row.id, + columnResizeMode: 'onChange', + defaultColumn: { minSize: 56, maxSize: 800 }, + autoResetCellSelection: false, + }, + (state) => ({ + sorting: state.sorting, + columnFilters: state.columnFilters, + columnOrder: state.columnOrder, + rowSelection: state.rowSelection, + cellSelection: state.cellSelection, + }), + ) + const rows = readMeasuredRows(() => table.getRowModel().rows) + const scrollRef = useRef(null) + const tableRef = useRef(null) + const bodyRef = useRef(null) + const manuallyResized = useRef(false) + const pointer = useTradingGridPointer(table, controller.actions.selectSymbol) + const drag = useRef({ + columnId: null as string | null, + source: null as HTMLTableCellElement | null, + target: null as HTMLTableCellElement | null, + }) + + useLayoutEffect(() => { + controller.actions.setRenderedRowCount(rows.length) + feed.completeRender() + }, null) + + useLayoutEffect(() => { + const writeColumnSizes = () => { + const element = tableRef.current + if (!element) return + for (const header of table.getFlatHeaders()) { + element.style.setProperty(`--header-${header.id}-size`, String(header.getSize())) + element.style.setProperty(`--col-${header.column.id}-size`, String(header.column.getSize())) + } + element.style.width = `${table.getTotalSize()}px` + } + const fitAvailableWidth = () => { + const container = scrollRef.current + if (!container || manuallyResized.current) return + const width = table.getTotalSize() + if (container.clientWidth <= width + 1 || width <= 0) return + const ratio = container.clientWidth / width + table.setColumnSizing(Object.fromEntries( + table.getVisibleLeafColumns().map((column) => [column.id, column.getSize() * ratio]), + )) + } + const sizing = table.atoms.columnSizing.subscribe(writeColumnSizes) + const order = table.atoms.columnOrder.subscribe(writeColumnSizes) + const resizing = table.atoms.columnResizing.subscribe((state) => { + if (state.isResizingColumn !== false) manuallyResized.current = true + }) + const resizeObserver = new ResizeObserver(fitAvailableWidth) + if (scrollRef.current) resizeObserver.observe(scrollRef.current) + writeColumnSizes() + fitAvailableWidth() + const stopBenchmark = startTableBenchmark(controller, bodyRef.current) + return () => { + sizing.unsubscribe() + order.unsubscribe() + resizing.unsubscribe() + resizeObserver.disconnect() + stopBenchmark() + } + }, [controller, table.store]) + + const clearDrag = () => { + drag.current.source?.classList.remove('is-column-dragging') + drag.current.target?.classList.remove('is-column-drop-target') + drag.current.columnId = null + drag.current.source = null + drag.current.target = null + } + const showDropTarget = (columnId: string, element: HTMLTableCellElement | null) => { + drag.current.target?.classList.remove('is-column-drop-target') + drag.current.target = null + if (drag.current.columnId === columnId || !element) return + element.classList.add('is-column-drop-target') + drag.current.target = element + } + const renderRow = (row: (typeof rows)[number]) => ( + + @for (const cell of row.getVisibleCells(); key cell.id) { + const edges = cell.getSelectionEdges() + + + + } + + ) + + <> +
+ handleCellNavigation(table, event)} + > + + @for (const group of table.getHeaderGroups(); key group.id) { + + @for (const header of group.headers; key header.id) { + const leaf = header.subHeaders.length === 0 + const sorted = header.column.getIsSorted() + + } + + } + + + {rows.map((row) => renderRow(row))} + +
+ {!header.isPlaceholder && (leaf ? <> +
{ + event.preventDefault() + showDropTarget(header.column.id, event.currentTarget.closest('th')) + }} + onDrop={(event) => { + event.preventDefault() + const source = event.dataTransfer?.getData('text/plain') || drag.current.columnId + if (source) { + table.setColumnOrder(reorderColumnIds( + table.getVisibleLeafColumns().map((column) => column.id), + source, + header.column.id, + )) + } + clearDrag() + }} + > + + +
+ {header.column.getCanResize() &&
header.column.resetSize()} + onMouseDown={header.getResizeHandler()} + onTouchStart={header.getResizeHandler()} + />} + : )} +
+
+ +} diff --git a/examples/octane/realtime-trading/src/table/table-config/quote-cells.tsrx b/examples/octane/realtime-trading/src/table/table-config/quote-cells.tsrx new file mode 100644 index 0000000000..2ca5ecf8e6 --- /dev/null +++ b/examples/octane/realtime-trading/src/table/table-config/quote-cells.tsrx @@ -0,0 +1,94 @@ +import { useEffect } from 'octane' + +export const quoteCellLifecycle = { created: 0, destroyed: 0 } + +export const quoteCellRendererNames = [ + 'Market', 'Name', 'Symbol', 'Last', 'Change', 'ChangePercent', 'Bid', + 'BidVolume', 'Ask', 'AskVolume', 'Open', 'High', 'Low', 'Intraday', +] as const + +export const quoteComponentNames = [ + 'PriceCell', 'StableMoveCell', 'UpMoveCell', 'DownMoveCell', + 'PercentChangeCell', 'SpreadCell', 'DepthCell', 'QuoteAgeCell', + 'SparklineCell', +] as const + +export type QuoteCellRendererName = (typeof quoteCellRendererNames)[number] +export type QuoteComponentName = (typeof quoteComponentNames)[number] + +const createCounterMap = (names: ReadonlyArray) => + Object.fromEntries(names.map((name) => [name, 0])) as Record + +export const quoteRenderDiagnostics = { + cellRendererCalls: 0, + componentRenderCalls: 0, + cellRendererCallsByName: createCounterMap(quoteCellRendererNames), + componentRenderCallsByName: createCounterMap(quoteComponentNames), +} + +export function recordCellRender(name: QuoteCellRendererName, value: T): T { + quoteRenderDiagnostics.cellRendererCalls++ + quoteRenderDiagnostics.cellRendererCallsByName[name]++ + return value +} + +function useLifecycleCounter(name: QuoteComponentName): void { + quoteRenderDiagnostics.componentRenderCalls++ + quoteRenderDiagnostics.componentRenderCallsByName[name]++ + useEffect(() => { + quoteCellLifecycle.created++ + return () => { quoteCellLifecycle.destroyed++ } + }, []) +} + +export function PriceCell(props: { price: number; move: number; onSelect: () => void }) @{ + useLifecycleCounter('PriceCell') + +} + +export function StableMoveCell({ move }: { move: number }) @{ + useLifecycleCounter('StableMoveCell') + = 0 ? 'quote-up' : 'quote-down'}`}>{formatSigned(move)} +} + +export function UpMoveCell({ move }: { move: number }) @{ + useLifecycleCounter('UpMoveCell') + ▲ {formatSigned(move)} +} + +export function DownMoveCell({ move }: { move: number }) @{ + useLifecycleCounter('DownMoveCell') + ▼ {formatSigned(move)} +} + +export function PercentChangeCell({ value }: { value: number }) @{ + useLifecycleCounter('PercentChangeCell') + = 0 ? 'quote-up' : 'quote-down'}`}> + {value >= 0 ? '+' : ''}{value.toFixed(2)}% + +} + +export function SparklineCell({ values }: { values: ReadonlyArray }) @{ + useLifecycleCounter('SparklineCell') + const rising = (values.at(-1) ?? 0) >= (values[0] ?? 0) + const first = values[0] ?? 0 + const range = values.reduce( + (result, value) => ({ min: Math.min(result.min, value), max: Math.max(result.max, value) }), + { min: first, max: first }, + ) + const scale = range.max - range.min || 1 + const denominator = Math.max(1, values.length - 1) + const points = values.map((value, index) => { + const x = (index / denominator) * 100 + const y = 22 - ((value - range.min) / scale) * 20 + return `${x.toFixed(1)},${y.toFixed(1)}` + }).join(' ') + + + + +} + +const formatSigned = (value: number): string => `${value >= 0 ? '+' : ''}${value.toFixed(2)}` diff --git a/examples/octane/realtime-trading/src/table/table-config/trading-columns.tsrx b/examples/octane/realtime-trading/src/table/table-config/trading-columns.tsrx new file mode 100644 index 0000000000..951a35bc3c --- /dev/null +++ b/examples/octane/realtime-trading/src/table/table-config/trading-columns.tsrx @@ -0,0 +1,200 @@ +import { createColumnHelper } from '@tanstack/octane-table' +import { tradingFeatures } from '../trading-features' +import { + DownMoveCell, + PercentChangeCell, + PriceCell, + SparklineCell, + StableMoveCell, + UpMoveCell, + recordCellRender, +} from './quote-cells.tsrx' +import type { MarketQuote } from '../../feed/market-data' +import type { TradingBenchmarkController } from '../../benchmark/trading-benchmark-controller' + +export type RendererMode = 'stable' | 'swap' +export interface CoreTableState { + sorting: Array<{ id: string; desc: boolean }> + columnFilters: Array<{ id: string; value: unknown }> +} + +const compact = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +const columnHelper = createColumnHelper() + +export function createTradingColumns( + controller: TradingBenchmarkController, + rendererMode: RendererMode, +) { + return columnHelper.columns([ + columnHelper.group({ + id: 'instrument', + header: 'Instrument', + columns: columnHelper.columns([ + columnHelper.accessor('venue', { + id: 'market', + header: 'Market', + size: 72, + cell: (info) => recordCellRender('Market', info.getValue()), + }), + columnHelper.accessor('company', { + id: 'name', + header: 'Name', + size: 180, + cell: (info) => recordCellRender('Name', info.getValue()), + }), + columnHelper.accessor('symbol', { + header: 'Symbol', + size: 92, + filterFn: 'includesString', + cell: (info) => recordCellRender('Symbol', info.getValue()), + }), + ]), + }), + columnHelper.group({ + id: 'priceAndChange', + header: 'Price & Change', + columns: columnHelper.columns([ + columnHelper.accessor('price', { + header: 'Price', + size: 96, + sortFn: 'basic', + cell: (info) => + recordCellRender( + 'Last', + controller.actions.selectSymbol(info.row.original.symbol)} + />, + ), + }), + columnHelper.accessor(getDayChange, { + id: 'change', + header: 'Chg', + size: 94, + cell: (info) => + recordCellRender( + 'Change', + , + ), + }), + columnHelper.accessor(getDayChangePercent, { + id: 'changePercent', + header: 'Chg%', + size: 90, + cell: (info) => + recordCellRender( + 'ChangePercent', + , + ), + }), + ]), + }), + columnHelper.group({ + id: 'orderBook', + header: 'Order Book', + columns: columnHelper.columns([ + columnHelper.accessor('bid', { + header: 'Bid', + size: 90, + cell: (info) => recordCellRender('Bid', info.getValue().toFixed(2)), + }), + columnHelper.accessor('bidSize', { + header: 'Bid Vol', + size: 100, + cell: (info) => + recordCellRender('BidVolume', compact.format(info.getValue())), + }), + columnHelper.accessor('ask', { + header: 'Ask', + size: 90, + cell: (info) => recordCellRender('Ask', info.getValue().toFixed(2)), + }), + columnHelper.accessor('askSize', { + header: 'Ask Vol', + size: 100, + cell: (info) => + recordCellRender('AskVolume', compact.format(info.getValue())), + }), + ]), + }), + columnHelper.group({ + id: 'session', + header: 'Session', + columns: columnHelper.columns([ + columnHelper.accessor('open', { + header: 'Open', + size: 90, + cell: (info) => recordCellRender('Open', info.getValue().toFixed(2)), + }), + columnHelper.accessor('high', { + header: 'High', + size: 90, + cell: (info) => recordCellRender('High', info.getValue().toFixed(2)), + }), + columnHelper.accessor('low', { + header: 'Low', + size: 90, + cell: (info) => recordCellRender('Low', info.getValue().toFixed(2)), + }), + ]), + }), + columnHelper.group({ + id: 'chart', + header: 'Chart', + columns: columnHelper.columns([ + columnHelper.accessor('history', { + header: 'Intraday', + size: 150, + enableSorting: false, + cell: (info) => + recordCellRender('Intraday', ), + }), + ]), + }), + ]) +} + +function MoveCell({ mode, move }: { mode: RendererMode; move: number }) @{ + if (mode === 'stable') return + if (move >= 0) return + +} + +export const rowModelDiagnostics = { + hasMeasurement: false, + calls: 0, + totalDurationMs: 0, + maxDurationMs: 0, + lastRowCount: 0, +} +export const TRADING_COLUMN_COUNT = 14 + +export function readMeasuredRows(readRows: () => Array): Array { + const start = performance.now() + const rows = readRows() + const end = performance.now() + const duration = end - start + rowModelDiagnostics.calls++ + rowModelDiagnostics.hasMeasurement = true + rowModelDiagnostics.totalDurationMs += duration + rowModelDiagnostics.maxDurationMs = Math.max(rowModelDiagnostics.maxDurationMs, duration) + rowModelDiagnostics.lastRowCount = rows.length + if (rowModelDiagnostics.calls % 20 !== 0) return rows + try { + performance.measure('tanstack-row-model', { start, end, detail: { rowCount: rows.length } }) + if (rowModelDiagnostics.calls % 20_000 === 0) performance.clearMeasures('tanstack-row-model') + } catch { /* optional User Timing detail */ } + return rows +} + +export function getDayChange(quote: MarketQuote): number { + return quote.price - quote.previousClose +} + +export function getDayChangePercent(quote: MarketQuote): number { + return quote.previousClose === 0 ? 0 : (getDayChange(quote) / quote.previousClose) * 100 +} diff --git a/examples/octane/realtime-trading/src/table/table-interactions.ts b/examples/octane/realtime-trading/src/table/table-interactions.ts new file mode 100644 index 0000000000..42356f5bd8 --- /dev/null +++ b/examples/octane/realtime-trading/src/table/table-interactions.ts @@ -0,0 +1,144 @@ +export type CellDirection = 'up' | 'down' | 'left' | 'right' + +interface RowSelectionTable { + resetRowSelection: (defaultState?: boolean) => void +} + +interface SelectableRow { + getIsSelected: () => boolean + getToggleSelectedHandler: (options?: { + selectChildren?: boolean + }) => (event: unknown) => void +} + +interface SelectableGridCell { + row: SelectableGridRow + getSelectionStartHandler: ( + contextDocument?: Document, + ) => (event: unknown) => void + getSelectionExtendHandler: () => (event: unknown) => void +} + +interface SelectableGridRow extends SelectableRow { + original: { symbol: string } + getAllCellsByColumnId: () => Partial> +} + +export interface TradingGridTable extends RowSelectionTable { + getRowModel: () => { + rowsById: Partial> + } +} + +export interface SelectionCellTarget { + element: HTMLTableCellElement + cell: SelectableGridCell +} + +interface CellNavigationTable { + extendCellSelection: (direction: CellDirection) => void + moveCellSelection: (direction: CellDirection) => void + resetCellSelection: (defaultState?: boolean) => void + selectAllCells: () => void +} + +const keyDirections: Partial> = { + ArrowUp: 'up', + ArrowDown: 'down', + ArrowLeft: 'left', + ArrowRight: 'right', +} + +export function reorderColumnIds( + columnIds: Array, + sourceId: string, + targetId: string, +): Array { + if (sourceId === targetId || !columnIds.includes(sourceId)) return columnIds + + const withoutSource = columnIds.filter((id) => id !== sourceId) + const targetIndex = withoutSource.indexOf(targetId) + if (targetIndex < 0) return columnIds + + return [ + ...withoutSource.slice(0, targetIndex), + sourceId, + ...withoutSource.slice(targetIndex), + ] +} + +export function selectRowFromPointer( + table: RowSelectionTable, + row: SelectableRow, + event: MouseEvent, +): void { + const additive = event.ctrlKey || event.metaKey + const checked = additive ? !row.getIsSelected() : true + + if (!event.shiftKey && !additive) table.resetRowSelection(true) + + row.getToggleSelectedHandler({ selectChildren: false })({ + target: { checked }, + shiftKey: event.shiftKey, + ctrlKey: event.ctrlKey, + metaKey: event.metaKey, + }) +} + +export function findTradingGridCellTarget( + table: TradingGridTable, + path: Array, +): SelectionCellTarget | null { + for (const target of path) { + if (!(target instanceof HTMLTableCellElement)) continue + + const columnId = target.dataset['columnId'] + const rowId = + target.closest('tr[data-row-id]')?.dataset['rowId'] + if (!columnId || !rowId) return null + + const row = table.getRowModel().rowsById[rowId] + const cell = row?.getAllCellsByColumnId()[columnId] + return row && cell ? { element: target, cell } : null + } + + return null +} + +export function handleCellNavigation( + table: CellNavigationTable, + event: KeyboardEvent, +): void { + if (event.key === 'Escape') { + event.preventDefault() + table.resetCellSelection(true) + return + } + + if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'a') { + event.preventDefault() + table.selectAllCells() + return + } + + const direction = keyDirections[event.key] + if (!direction) return + + event.preventDefault() + if (event.shiftKey) table.extendCellSelection(direction) + else table.moveCellSelection(direction) +} + +export function sortIndicator(direction: false | 'asc' | 'desc'): string { + if (direction === 'asc') return '↑' + if (direction === 'desc') return '↓' + return '↕' +} + +export function sortAriaValue( + direction: false | 'asc' | 'desc', +): 'ascending' | 'descending' | 'none' { + if (direction === 'asc') return 'ascending' + if (direction === 'desc') return 'descending' + return 'none' +} diff --git a/examples/octane/realtime-trading/src/table/trading-features.ts b/examples/octane/realtime-trading/src/table/trading-features.ts new file mode 100644 index 0000000000..0f3b980ccf --- /dev/null +++ b/examples/octane/realtime-trading/src/table/trading-features.ts @@ -0,0 +1,16 @@ +import { + createFilteredRowModel, + createSortedRowModel, + filterFn_includesString, + sortFn_basic, + stockFeatures, + tableFeatures, +} from '@tanstack/octane-table' + +export const tradingFeatures = tableFeatures({ + ...stockFeatures, + filteredRowModel: createFilteredRowModel(), + sortedRowModel: createSortedRowModel(), + filterFns: { includesString: filterFn_includesString }, + sortFns: { basic: sortFn_basic }, +}) diff --git a/examples/octane/realtime-trading/src/table/trading-table.ts b/examples/octane/realtime-trading/src/table/trading-table.ts new file mode 100644 index 0000000000..b5aaa8f2a6 --- /dev/null +++ b/examples/octane/realtime-trading/src/table/trading-table.ts @@ -0,0 +1,8 @@ +export { + TRADING_COLUMN_COUNT, + rowModelDiagnostics, +} from './table-config/trading-columns.tsrx' +export type { + CoreTableState, + RendererMode, +} from './table-config/trading-columns.tsrx' diff --git a/examples/octane/realtime-trading/src/table/use-trading-grid-pointer.ts b/examples/octane/realtime-trading/src/table/use-trading-grid-pointer.ts new file mode 100644 index 0000000000..671ad11f3f --- /dev/null +++ b/examples/octane/realtime-trading/src/table/use-trading-grid-pointer.ts @@ -0,0 +1,59 @@ +import { useMemo, useRef } from 'octane' +import { + findTradingGridCellTarget, + selectRowFromPointer, +} from './table-interactions' +import type { TradingGridTable } from './table-interactions' + +export interface TradingGridPointerHandlers { + readonly onMouseDown: (event: MouseEvent) => void + readonly onPointerOver: (event: PointerEvent) => void + readonly onMouseLeave: () => void + readonly onClick: (event: MouseEvent) => void +} + +export function useTradingGridPointer( + table: TradingGridTable, + selectSymbol: (symbol: string) => void, +): TradingGridPointerHandlers { + const lastPointerCell = useRef(null) + + return useMemo( + () => ({ + onMouseDown(event) { + if (event.button !== 0) return + + const target = findTradingGridCellTarget(table, event.composedPath()) + if (!target) return + + event.preventDefault() + lastPointerCell.current = target.element + selectSymbol(target.cell.row.original.symbol) + target.cell.getSelectionStartHandler(target.element.ownerDocument)( + event, + ) + }, + onPointerOver(event) { + if ((event.buttons & 1) === 0) { + lastPointerCell.current = null + return + } + + const target = findTradingGridCellTarget(table, event.composedPath()) + if (!target || target.element === lastPointerCell.current) return + + lastPointerCell.current = target.element + target.cell.getSelectionExtendHandler()(event) + }, + onMouseLeave() { + lastPointerCell.current = null + }, + onClick(event) { + const target = findTradingGridCellTarget(table, event.composedPath()) + if (!target) return + selectRowFromPointer(table, target.cell.row, event) + }, + }), + [selectSymbol, table], + ) +} diff --git a/examples/octane/realtime-trading/src/vite-env.d.ts b/examples/octane/realtime-trading/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/octane/realtime-trading/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/octane/realtime-trading/tests/e2e/smoke.spec.ts b/examples/octane/realtime-trading/tests/e2e/smoke.spec.ts new file mode 100644 index 0000000000..74fd867fa1 --- /dev/null +++ b/examples/octane/realtime-trading/tests/e2e/smoke.spec.ts @@ -0,0 +1,125 @@ +import path from 'node:path' +import { expect, test } from '@playwright/test' +import { startExampleServer } from '../../../../../tests/e2e/helpers/startExampleServer' +import { setRangeValue } from '../../../../../tests/e2e/helpers/setRangeValue' +import type { Page } from '@playwright/test' + +const exampleDir = path.resolve() + +function collectPageErrors(page: Page) { + const errors: Array = [] + page.on('pageerror', (error) => errors.push(error.message)) + page.on('console', (message) => { + if (message.type() === 'error') errors.push(message.text()) + }) + return errors +} + +test('runs the Octane realtime trading workload', async ({ page }) => { + const server = await startExampleServer(exampleDir) + const errors = collectPageErrors(page) + + try { + await page.goto(server.url) + + const table = page.getByTestId('trading-table') + const instrumentCount = page.getByTestId('instrument-count-select') + await expect(table).toBeVisible() + await expect(instrumentCount).toHaveValue('100') + await expect(page.locator('.brand')).toHaveText('MARKET MONITOR') + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(table.locator('tbody')).toHaveCSS('user-select', 'none') + await expect(table.locator('tbody tr').first()).toHaveCSS( + 'content-visibility', + 'auto', + ) + await expect(table.locator('thead tr')).toHaveCount(2) + await expect(table.locator('thead tr').last().locator('th')).toHaveCount(14) + await expect(table.locator('thead')).not.toContainText('Identity') + await expect(table.locator('thead')).not.toContainText('Market Data') + await expect(table.locator('thead')).toContainText('Market') + await expect(table.locator('thead')).toContainText('Bid Vol') + await expect(table.locator('thead')).toContainText('Intraday') + const selectedRow = table.locator('tbody tr').first() + const selectedSymbol = await selectedRow.getAttribute('data-symbol') + await selectedRow.locator('td').nth(1).click() + await expect(page.getByTestId('selected-instrument')).toContainText( + selectedSymbol ?? '', + ) + await expect(page.getByTestId('feed-status')).toHaveText('FEED LIVE') + await expect(instrumentCount.locator('option[value="150"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="350"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="750"]')).toHaveCount(1) + + const targetRateSlider = page.getByTestId('target-rate-slider') + await expect(targetRateSlider).toHaveAttribute('min', '0') + await expect(targetRateSlider).toHaveAttribute('max', '9') + await expect(targetRateSlider).toHaveAttribute('step', '1') + await expect(targetRateSlider).toHaveValue('6') + await setRangeValue(targetRateSlider, '7') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '25K samples/s', + ) + await setRangeValue(targetRateSlider, '8') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '50K samples/s', + ) + await setRangeValue(targetRateSlider, '6') + + const sparklineInterval = page.getByTestId( + 'sparkline-sample-interval-select', + ) + await expect(sparklineInterval).toHaveValue('16') + await sparklineInterval.selectOption('100') + await expect(sparklineInterval).toHaveValue('100') + await sparklineInterval.selectOption('16') + + const publishInterval = page.getByTestId('publish-interval-select') + await expect(publishInterval.locator('option[value="500"]')).toHaveCount(1) + await expect(publishInterval.locator('option[value="1000"]')).toHaveCount(1) + + await expect + .poll(async () => { + const text = await page.getByTestId('row-update-rate').textContent() + return Number(text?.replace(/\D/g, '') ?? 0) + }) + .toBeGreaterThan(0) + await expect + .poll(async () => { + const text = await page.getByTestId('worker-messages').textContent() + return Number(text?.replace(/\D/g, '') ?? 0) + }) + .toBeGreaterThan(0) + await expect + .poll(async () => + Number(await page.getByTestId('message-rate').textContent()), + ) + .toBeGreaterThan(0) + await expect + .poll(async () => + Number(await page.getByTestId('table-render-rate').textContent()), + ) + .toBeGreaterThan(0) + + const firstPrice = page.locator('tbody tr').first().getByRole('button') + const priceBeforeUpdate = await firstPrice.textContent() + await expect + .poll(() => firstPrice.textContent()) + .not.toBe(priceBeforeUpdate) + + await page.locator('.config-section input[type="checkbox"]').first().check() + await page.getByTestId('feed-toggle').click() + await expect(page.getByTestId('feed-toggle')).toHaveText('START FEED') + await expect(page.getByTestId('feed-status')).toHaveText('FEED PAUSED') + + expect( + await page.evaluate( + () => performance.getEntriesByName('tanstack-row-model').length > 0, + ), + ).toBe(true) + + expect(errors).toEqual([]) + } finally { + await server.close() + } +}) diff --git a/examples/octane/realtime-trading/tsconfig.json b/examples/octane/realtime-trading/tsconfig.json new file mode 100644 index 0000000000..a33b01356c --- /dev/null +++ b/examples/octane/realtime-trading/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "octane", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["node"] + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/octane/realtime-trading/vite.config.ts b/examples/octane/realtime-trading/vite.config.ts new file mode 100644 index 0000000000..42562920a8 --- /dev/null +++ b/examples/octane/realtime-trading/vite.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'vite' +import { octane } from 'octane/compiler/vite' + +export default defineConfig({ + server: { + port: 7777, + allowedHosts: true, + }, + plugins: [octane()], +}) diff --git a/examples/octane/row-pinning/package.json b/examples/octane/row-pinning/package.json index c0b2bd8582..3e87abf48b 100644 --- a/examples/octane/row-pinning/package.json +++ b/examples/octane/row-pinning/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/row-selection/package.json b/examples/octane/row-selection/package.json index 222cf9cd35..9b7d209122 100644 --- a/examples/octane/row-selection/package.json +++ b/examples/octane/row-selection/package.json @@ -11,14 +11,15 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-store": "^0.12.2", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/sorting/package.json b/examples/octane/sorting/package.json index bf4fc7286c..805697cba3 100644 --- a/examples/octane/sorting/package.json +++ b/examples/octane/sorting/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/octane/sub-components/package.json b/examples/octane/sub-components/package.json index d962320b9a..f473b52ec0 100644 --- a/examples/octane/sub-components/package.json +++ b/examples/octane/sub-components/package.json @@ -11,13 +11,14 @@ "test:types": "tsrx-tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/octane-table": "^9.2.3", "octane": "0.1.36" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@tsrx/typescript-plugin": "^0.3.118", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/aggregation/package.json b/examples/preact/aggregation/package.json index ca1a3f24b5..29ff0e8e59 100644 --- a/examples/preact/aggregation/package.json +++ b/examples/preact/aggregation/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-store": "^0.13.2", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/basic-dynamic-columns/package.json b/examples/preact/basic-dynamic-columns/package.json index a1d99a1384..2274aa6566 100644 --- a/examples/preact/basic-dynamic-columns/package.json +++ b/examples/preact/basic-dynamic-columns/package.json @@ -12,8 +12,8 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/preact-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/preact-devtools": "^0.10.12", "@tanstack/preact-pacer": "^0.23.0", "@tanstack/preact-table": "^9.2.3", "@tanstack/preact-table-devtools": "^9.2.0", @@ -21,7 +21,8 @@ }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/basic-external-atoms/package.json b/examples/preact/basic-external-atoms/package.json index 6355d464b4..24b6c3eaf0 100644 --- a/examples/preact/basic-external-atoms/package.json +++ b/examples/preact/basic-external-atoms/package.json @@ -12,8 +12,8 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/preact-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/preact-devtools": "^0.10.12", "@tanstack/preact-store": "^0.13.2", "@tanstack/preact-table": "^9.2.3", "@tanstack/preact-table-devtools": "^9.2.0", @@ -21,7 +21,8 @@ }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/basic-external-state/package.json b/examples/preact/basic-external-state/package.json index dc7ad1c1cf..e84ee89f27 100644 --- a/examples/preact/basic-external-state/package.json +++ b/examples/preact/basic-external-state/package.json @@ -12,8 +12,8 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/preact-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/preact-devtools": "^0.10.12", "@tanstack/preact-store": "^0.13.2", "@tanstack/preact-table": "^9.2.3", "@tanstack/preact-table-devtools": "^9.2.0", @@ -21,7 +21,8 @@ }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/basic-subscribe/package.json b/examples/preact/basic-subscribe/package.json index 5777dadd3e..4bb5c010d5 100644 --- a/examples/preact/basic-subscribe/package.json +++ b/examples/preact/basic-subscribe/package.json @@ -12,8 +12,8 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/preact-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/preact-devtools": "^0.10.12", "@tanstack/preact-store": "^0.13.2", "@tanstack/preact-table": "^9.2.3", "@tanstack/preact-table-devtools": "^9.2.0", @@ -21,7 +21,8 @@ }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/basic-use-app-table/package.json b/examples/preact/basic-use-app-table/package.json index 0e559d7526..332c9a9ffd 100644 --- a/examples/preact/basic-use-app-table/package.json +++ b/examples/preact/basic-use-app-table/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@tanstack/preact-devtools": "^0.10.10", + "@tanstack/preact-devtools": "^0.10.12", "@tanstack/preact-table": "^9.2.3", "@tanstack/preact-table-devtools": "^9.2.0", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/basic-use-table/package.json b/examples/preact/basic-use-table/package.json index 1f74de77b2..2a1ce89ebc 100644 --- a/examples/preact/basic-use-table/package.json +++ b/examples/preact/basic-use-table/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@tanstack/preact-devtools": "^0.10.10", + "@tanstack/preact-devtools": "^0.10.12", "@tanstack/preact-table": "^9.2.3", "@tanstack/preact-table-devtools": "^9.2.0", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/cell-selection/package.json b/examples/preact/cell-selection/package.json index daaaea1045..222d3e0d60 100644 --- a/examples/preact/cell-selection/package.json +++ b/examples/preact/cell-selection/package.json @@ -12,8 +12,8 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/preact-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/preact-devtools": "^0.10.12", "@tanstack/preact-hotkeys": "^0.10.0", "@tanstack/preact-store": "^0.13.2", "@tanstack/preact-table": "^9.2.3", @@ -22,7 +22,8 @@ }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/cell-spanning/package.json b/examples/preact/cell-spanning/package.json index b5489ba3e7..2cab8f4528 100644 --- a/examples/preact/cell-spanning/package.json +++ b/examples/preact/cell-spanning/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/column-ordering/package.json b/examples/preact/column-ordering/package.json index 8f9cbdd8a4..87ec52b905 100644 --- a/examples/preact/column-ordering/package.json +++ b/examples/preact/column-ordering/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/column-pinning-split/package.json b/examples/preact/column-pinning-split/package.json index 1f04cc6612..4085a9193f 100644 --- a/examples/preact/column-pinning-split/package.json +++ b/examples/preact/column-pinning-split/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/column-pinning-sticky/package.json b/examples/preact/column-pinning-sticky/package.json index 857984a9ff..813a6de8ad 100644 --- a/examples/preact/column-pinning-sticky/package.json +++ b/examples/preact/column-pinning-sticky/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/column-pinning/package.json b/examples/preact/column-pinning/package.json index c46a975a57..989290a5f7 100644 --- a/examples/preact/column-pinning/package.json +++ b/examples/preact/column-pinning/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/column-resizing-performant/package.json b/examples/preact/column-resizing-performant/package.json index 9269e40b2d..cded6d43b3 100644 --- a/examples/preact/column-resizing-performant/package.json +++ b/examples/preact/column-resizing-performant/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/column-resizing/package.json b/examples/preact/column-resizing/package.json index 927c840d4c..3e7034e981 100644 --- a/examples/preact/column-resizing/package.json +++ b/examples/preact/column-resizing/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/column-sizing/package.json b/examples/preact/column-sizing/package.json index 8c787a3eb6..28ef88e6bf 100644 --- a/examples/preact/column-sizing/package.json +++ b/examples/preact/column-sizing/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/column-visibility/package.json b/examples/preact/column-visibility/package.json index 9968a95d75..d5349fdb7f 100644 --- a/examples/preact/column-visibility/package.json +++ b/examples/preact/column-visibility/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/composable-tables/package.json b/examples/preact/composable-tables/package.json index 6338e0fec0..1a39ad285c 100644 --- a/examples/preact/composable-tables/package.json +++ b/examples/preact/composable-tables/package.json @@ -12,8 +12,8 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/preact-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/preact-devtools": "^0.10.12", "@tanstack/preact-store": "^0.13.2", "@tanstack/preact-table": "^9.2.3", "@tanstack/preact-table-devtools": "^9.2.0", @@ -21,7 +21,8 @@ }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/custom-plugin/package.json b/examples/preact/custom-plugin/package.json index eb2e728961..90f0c6e3f9 100644 --- a/examples/preact/custom-plugin/package.json +++ b/examples/preact/custom-plugin/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/expanding/package.json b/examples/preact/expanding/package.json index d24c89d902..388cdede67 100644 --- a/examples/preact/expanding/package.json +++ b/examples/preact/expanding/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/filters-faceted-bucketed/package.json b/examples/preact/filters-faceted-bucketed/package.json index 7c161b7742..b0bb355152 100644 --- a/examples/preact/filters-faceted-bucketed/package.json +++ b/examples/preact/filters-faceted-bucketed/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/filters-faceted/package.json b/examples/preact/filters-faceted/package.json index eac77e6558..b991b6a423 100644 --- a/examples/preact/filters-faceted/package.json +++ b/examples/preact/filters-faceted/package.json @@ -12,7 +12,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/preact-pacer": "^0.23.0", "@tanstack/preact-table": "^9.2.3", @@ -20,7 +20,8 @@ }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/filters-fuzzy/package.json b/examples/preact/filters-fuzzy/package.json index 46623531dc..5b882b1217 100644 --- a/examples/preact/filters-fuzzy/package.json +++ b/examples/preact/filters-fuzzy/package.json @@ -12,7 +12,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/preact-pacer": "^0.23.0", "@tanstack/preact-table": "^9.2.3", @@ -20,7 +20,8 @@ }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/filters/package.json b/examples/preact/filters/package.json index 05e8d15f58..542a16358b 100644 --- a/examples/preact/filters/package.json +++ b/examples/preact/filters/package.json @@ -12,7 +12,7 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/preact-pacer": "^0.23.0", "@tanstack/preact-table": "^9.2.3", @@ -20,7 +20,8 @@ }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/grouped-aggregation/package.json b/examples/preact/grouped-aggregation/package.json index 4ab0b9418d..d5a3894f00 100644 --- a/examples/preact/grouped-aggregation/package.json +++ b/examples/preact/grouped-aggregation/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/grouping/package.json b/examples/preact/grouping/package.json index 565320a5e3..839e2424e2 100644 --- a/examples/preact/grouping/package.json +++ b/examples/preact/grouping/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/header-groups/package.json b/examples/preact/header-groups/package.json index 96cac6a705..47f85091fb 100644 --- a/examples/preact/header-groups/package.json +++ b/examples/preact/header-groups/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/kitchen-sink/package.json b/examples/preact/kitchen-sink/package.json index a06c3677f9..b5830cf6f0 100644 --- a/examples/preact/kitchen-sink/package.json +++ b/examples/preact/kitchen-sink/package.json @@ -12,16 +12,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/match-sorter-utils": "^9.1.2", - "@tanstack/preact-devtools": "^0.10.10", + "@tanstack/preact-devtools": "^0.10.12", "@tanstack/preact-table": "^9.2.3", "@tanstack/preact-table-devtools": "^9.2.0", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/pagination/package.json b/examples/preact/pagination/package.json index d13b5c2ff8..dbe592b54b 100644 --- a/examples/preact/pagination/package.json +++ b/examples/preact/pagination/package.json @@ -12,14 +12,15 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-store": "^0.13.2", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/realtime-trading/README.md b/examples/preact/realtime-trading/README.md new file mode 100644 index 0000000000..349dd32476 --- /dev/null +++ b/examples/preact/realtime-trading/README.md @@ -0,0 +1,174 @@ +# Preact realtime trading benchmark + +This standalone example exercises the current TanStack Preact Table adapter +with an immutable high-frequency feed, table interactions, custom components, +virtual rows, and browser diagnostics. It is a rendering stress lab rather than +an exchange or network-latency simulation. + +## Run and verify + +```bash +pnpm --dir examples/preact/realtime-trading dev +``` + +Open `http://localhost:7777`. + +```bash +pnpm --dir examples/preact/realtime-trading test:types +pnpm --dir examples/preact/realtime-trading lint +pnpm --dir examples/preact/realtime-trading build +pnpm --dir examples/preact/realtime-trading test:e2e +``` + +Use the production build for measurements; development checks inflate the +absolute cost. + +## Structure and ownership + +| Path | Responsibility | +| ------------------------- | ------------------------------------------------------------------------------------------------- | +| `src/feed/` | Market types, instruments, immutable update helpers, config, controller, and controller hook. | +| `src/feed/worker/` | Worker protocol, deterministic market engine, and module worker. | +| `src/benchmark/` | Feed/render timing, DOM/long-frame observers, row-model and component diagnostics. | +| `src/shell/` | TanStack Store contexts, viewport shell, metrics, controls, selected instrument, and diagnostics. | +| `src/table/table-config/` | Grouped columns, row/cell components, and render counters. | +| `src/table/` | Preact Table instance, subscriptions, interactions, column layout, and Virtual Core hook. | +| `src/App.tsx` | Creates the controllers and composes providers, shell, and table. | + +Feed state and benchmark state are different controllers. The feed does not +depend on the monitor; the benchmark subscribes to feed lifecycle callbacks. +TanStack Preact Store contexts pass stable controller objects, while components +subscribe to direct feed atoms. `quotes` has an independent high-frequency atom; +status, instrument count, workload, delivery, and chart settings each have their +own atom and cannot notify the table data boundary. Renderer mode and selected +symbol are also separate atoms so their updates do not invalidate unrelated +shell content. Benchmark metrics remain an aggregate snapshot store. + +## Feed and worker pipeline + +The initial setup is 100 instruments, 10K generated samples/s, 20 ms worker +delivery, enabled intraday charts, and 16 ms chart sampling. + +The module worker keeps mutable quote state private. A deterministic PRNG and a +16 ms budget loop generate samples; a `Map` coalesces repeated updates for the +same row. A separate publication timer sends the latest unique row updates at +the configured interval. The main thread creates a new outer array and new +objects only for changed rows, preserving every untouched row reference. +History arrays are replaced only when their sampling interval elapses. Session +IDs reject stale messages after reset or row-count changes. + +- **Synthetic quote workload** is worker-side generated samples per second. It + is not pointer events, renders, or messages. +- **Worker delivery interval** controls coalesced `postMessage` cadence; 20 ms + targets about 50 messages/s. +- **Changed rows** counts row snapshots applied on the main thread. Rows are + deduplicated within one snapshot, but the same row can be counted again in a + later snapshot, so it is throughput rather than a global distinct-row count. +- **Message samples** shows how much generated work the latest message contains. + +The 25K burst deliberately creates and flushes one expensive batch. The worker +mimics an external streaming producer, but network transport is not measured. + +## Table and interaction architecture + +The 14 leaf columns are grouped into Instrument, Price & Change, Order Book, +Session, and Chart. The example supports core sorting/filtering, on-change +resizing, double-click size reset, drag column ordering, row selection, drag +cell ranges, keyboard navigation, and custom Price/Move/Percent/Sparkline cells. +Stable instrument IDs are supplied through `getRowId`. + +`table.Subscribe` boundaries isolate table state, resize handles, and row +selection. `TradingGridPointerController` is allocated once for the body and +receives delegated mouse/pointer events. It resolves cells from +`event.composedPath()` and data attributes, eliminating listeners per cell. +Row hover is CSS-only. + +Column widths are table-level CSS custom properties updated only when sizing or +ordering changes. Initial sizes expand to the viewport through a +`ResizeObserver`; manual resizing turns off further auto-fit. The optional move +component A/B mode intentionally destroys/recreates component types and should +not be treated as the normal baseline. + +## Virtualization + +The preference is `auto`, `tanstack`, or `none`: + +- below 200 rows, `auto` means Full DOM, while Virtual remains selectable; +- 200–1,499 rows default to TanStack Virtual but can be switched to Full DOM; +- 1,500 or more rows force Virtual and lock the control. + +Because this adapter consumes `@tanstack/virtual-core` directly, the local +`useVirtualizer` hook owns the Virtualizer instance and synchronizes its change +notifications with Preact. It uses 32 px rows, 10-row overscan, row IDs as item +keys, transformed rows, and a spacer body. The footer reads the virtualizer +range. Both modes use `content-visibility: auto`; that browser hint does not +avoid mounting every component in Full DOM mode. + +## Performance decisions + +- worker-side generation and pre-message coalescing; +- structural sharing for unchanged rows and histories; +- stable table/virtualizer keys; +- direct Preact Store atom subscriptions, including an isolated quote atom; +- table/row/resize subscription boundaries; +- one delegated grid interaction controller; +- CSS variables for column sizing; +- opt-in component churn and independently sampled sparklines; +- virtual mounting for large row counts; +- benchmark publication slower than the data stream. + +The immutable outer array must change when a batch is applied. Stable inner +references reduce renderer work, but sorting/filtering may still require a core +row-model pass when data changes. + +## Diagnostics and interpretation + +The compact **Live health** block lives in the configurator sidebar and shows +four cross-framework signals: + +- **Frame rate (est.)** counts `requestAnimationFrame` callbacks over a rolling + one-second window. It is capped by display refresh and is not a measurement of + GPU-presented frames. +- **Average commit latency** is a rolling three-second average from the first + pending market mutation to the table's DOM commit. It includes scheduling, + Preact work, and the commit; it is not component render duration. +- **Long frames** comes from the Long Animation Frames API and is cumulative + since reset, with the worst observed duration when supported. +- **Throughput** pairs changed rows/s with applied snapshots/s; changed rows are + deduplicated per snapshot, not across the complete reporting window. + +Detailed diagnostics retain worker samples, messages, state applies, table DOM +commits, a 10-second commit-latency p95/max, cumulative slow commits, mounted +hosts, component creation/destruction, cell callbacks by column, component +executions by type, DOM `MutationRecord` rate, row-model timing, and heap data +where supported. + +The in-memory latency and row-model aggregates inspect every call, while the +Performance timeline writes only one User Timing measure per 20 calls to keep +instrumentation from dominating a hot run. The `MutationObserver` watches the +table body for text/children and only `class`/`style` attribute changes. Its +rate counts browser records rather than DOM operations: records can be +coalesced, equivalent UIs can produce different patterns, and creating records +has real overhead. Heap is Chrome-only `usedJSHeapSize`, is sensitive to +garbage-collection timing, and should be read as a trend rather than proof of a +leak. + +The monitor itself adds one lightweight `requestAnimationFrame` callback and +publishes the sidebar snapshot every 500 ms. That subscription is independent +from the quote atom and table data boundary, but it remains instrumentation +overhead and must stay enabled on both sides of an A/B comparison. + +Callback execution does not imply a DOM mutation, and temporary heap growth is +not by itself a leak. Compare identical production configurations and confirm +retention with post-GC heap snapshots. Use browser Performance tooling and +Preact DevTools for call stacks alongside the in-app counters. + +## Standalone policy + +All feed, worker, instrument, shell, style, and benchmark files are copied into +this directory intentionally. The example can run alone or be moved to +StackBlitz without a shared example package, so common implementation and README +sections are duplicated across adapters by design. + +The workspace resolves the pinned `@tanstack/preact-table` dependency to the +repository package while keeping the example manifest release-like. diff --git a/examples/preact/realtime-trading/index.html b/examples/preact/realtime-trading/index.html new file mode 100644 index 0000000000..849dbe8b48 --- /dev/null +++ b/examples/preact/realtime-trading/index.html @@ -0,0 +1,17 @@ + + + + + + + + Preact Real-time Trading FlexRender Lab + + +
+ + + diff --git a/examples/preact/realtime-trading/package.json b/examples/preact/realtime-trading/package.json new file mode 100644 index 0000000000..75ac32642f --- /dev/null +++ b/examples/preact/realtime-trading/package.json @@ -0,0 +1,25 @@ +{ + "name": "tanstack-preact-table-example-realtime-trading", + "private": true, + "type": "module", + "scripts": { + "start": "vite", + "dev": "vite", + "build": "vite build", + "serve": "vite preview", + "lint": "eslint ./src", + "test:types": "tsc --noEmit", + "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" + }, + "dependencies": { + "@tanstack/preact-store": "^0.13.2", + "@tanstack/preact-table": "^9.2.3", + "preact": "^10.29.8" + }, + "devDependencies": { + "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", + "typescript": "6.0.3", + "vite": "^8.2.2" + } +} diff --git a/examples/preact/realtime-trading/src/App.tsx b/examples/preact/realtime-trading/src/App.tsx new file mode 100644 index 0000000000..3b702068d6 --- /dev/null +++ b/examples/preact/realtime-trading/src/App.tsx @@ -0,0 +1,21 @@ +import { useMarketFeedController } from './feed/use-market-feed-controller' +import { useTradingBenchmarkController } from './benchmark/use-trading-benchmark-controller' +import { TradingShell } from './shell/TradingShell' +import { TradingShellProvider } from './shell/trading-shell-context' +import { TradingTable } from './table/trading-table' + +export function App() { + const feed = useMarketFeedController() + const controller = useTradingBenchmarkController(feed) + return ( + + + + + + ) +} + +function TradingTableOutlet() { + return +} diff --git a/examples/preact/realtime-trading/src/benchmark/benchmark-monitor.ts b/examples/preact/realtime-trading/src/benchmark/benchmark-monitor.ts new file mode 100644 index 0000000000..f072634bbc --- /dev/null +++ b/examples/preact/realtime-trading/src/benchmark/benchmark-monitor.ts @@ -0,0 +1,440 @@ +import { + quoteCellLifecycle, + quoteRenderDiagnostics, +} from '../table/table-config/quote-cells' +import { rowModelDiagnostics } from '../table/trading-table' + +export interface NamedInvocationRate { + name: string + callsPerSecond: number +} + +interface TimedLatencySample { + recordedAt: number + duration: number +} + +const averageLatencyWindowMs = 3_000 +const percentileLatencyWindowMs = 10_000 +const frameRateWindowMs = 1_000 + +export interface FeedMetrics { + actualTicksPerSecond: number + rowUpdatesPerSecond: number + workerMessagesPerSecond: number + stateApplicationsPerSecond: number + supersededUpdatesPerSecond: number + totalTicks: number + estimatedFrameRate: number + tableCommitsPerSecond: number + lastBatchSize: number + averageCommitLatencyMs: number + p95CommitLatencyMs: number + maxCommitLatencyMs: number + slowCommits: number + longAnimationFrames: number + worstLongAnimationFrameMs: number + heapMb: number | null + componentsCreated: number + componentsDestroyed: number + workerMessages: number + lastUpdateCount: number + cellRendererCallsPerSecond: number + componentRenderCallsPerSecond: number + cellRendererRates: ReadonlyArray + componentRenderRates: ReadonlyArray + domMutationsPerSecond: number + rowModelCallsPerSecond: number + rowModelAverageMs: number + rowModelMaxMs: number + visibleRows: number +} + +export const initialMetrics: FeedMetrics = { + actualTicksPerSecond: 0, + rowUpdatesPerSecond: 0, + workerMessagesPerSecond: 0, + stateApplicationsPerSecond: 0, + supersededUpdatesPerSecond: 0, + totalTicks: 0, + estimatedFrameRate: 0, + tableCommitsPerSecond: 0, + lastBatchSize: 0, + averageCommitLatencyMs: 0, + p95CommitLatencyMs: 0, + maxCommitLatencyMs: 0, + slowCommits: 0, + longAnimationFrames: 0, + worstLongAnimationFrameMs: 0, + heapMb: null, + componentsCreated: 0, + componentsDestroyed: 0, + workerMessages: 0, + lastUpdateCount: 0, + cellRendererCallsPerSecond: 0, + componentRenderCallsPerSecond: 0, + cellRendererRates: [], + componentRenderRates: [], + domMutationsPerSecond: 0, + rowModelCallsPerSecond: 0, + rowModelAverageMs: 0, + rowModelMaxMs: 0, + visibleRows: 0, +} + +const userTiming = { + entryCount: 0, + measureCallsByName: {} as Record, +} + +export function recordMeasure( + name: string, + start: number, + end: number, + detail: Record, +): void { + const measureCall = (userTiming.measureCallsByName[name] ?? 0) + 1 + userTiming.measureCallsByName[name] = measureCall + if ((measureCall - 1) % 20 !== 0) return + + try { + performance.measure(name, { start, end, detail }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMeasures('market-update-to-dom-commit') + } + } catch { + // User Timing Level 3 options are not implemented in every browser. + } +} + +export function markBenchmarkAction( + name: string, + detail: Record = {}, +): void { + try { + performance.mark(`benchmark:${name}`, { detail }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMarks() + } + } catch { + // User Timing Level 3 detail is not implemented in every browser. + } +} + +export class BenchmarkMonitor { + readonly #runtime = { + sessionStartedAt: performance.now(), + sampleStartedAt: performance.now(), + pendingCommitStartedAt: null as number | null, + commitLatencySamples: [] as Array, + slowCommitCount: 0, + totalTicks: 0, + ticksInSample: 0, + rowUpdatesInSample: 0, + workerMessagesInSample: 0, + stateApplicationsInSample: 0, + supersededUpdatesInSample: 0, + lastBatchSize: 0, + lastUpdateCount: 0, + workerMessages: 0, + frameTrackingStartedAt: performance.now(), + frameTimestamps: [] as Array, + tableCommitsInSample: 0, + longAnimationFrameCount: 0, + worstLongAnimationFrameMs: 0, + previousCellRendererCalls: 0, + previousComponentRenderCalls: 0, + previousCellRendererCallsByName: { + ...quoteRenderDiagnostics.cellRendererCallsByName, + }, + previousComponentRenderCallsByName: { + ...quoteRenderDiagnostics.componentRenderCallsByName, + }, + domMutationsInSample: 0, + previousRowModelCalls: 0, + previousRowModelDuration: 0, + } + + markCommitPending(): void { + this.#runtime.pendingCommitStartedAt ??= performance.now() + } + + recordDomCommit(): void { + const runtime = this.#runtime + if (runtime.pendingCommitStartedAt !== null) { + const commitEndedAt = performance.now() + const duration = commitEndedAt - runtime.pendingCommitStartedAt + runtime.commitLatencySamples.push({ + recordedAt: commitEndedAt, + duration, + }) + if (duration > 16.7) runtime.slowCommitCount++ + recordMeasure( + 'market-update-to-dom-commit', + runtime.pendingCommitStartedAt, + commitEndedAt, + {}, + ) + runtime.pendingCommitStartedAt = null + runtime.tableCommitsInSample++ + } + } + + recordWorkerMessage(): void { + this.#runtime.workerMessages++ + this.#runtime.workerMessagesInSample++ + } + + recordBatch( + tickCount: number, + updateCount: number, + supersededUpdateCount: number, + ): void { + const runtime = this.#runtime + runtime.lastBatchSize = tickCount + runtime.lastUpdateCount = updateCount + runtime.ticksInSample += tickCount + runtime.totalTicks += tickCount + runtime.rowUpdatesInSample += updateCount + runtime.stateApplicationsInSample++ + runtime.supersededUpdatesInSample += supersededUpdateCount + } + + recordAnimationFrame(now: number): void { + const timestamps = this.#runtime.frameTimestamps + timestamps.push(now) + pruneFrameTimestamps(timestamps, now) + } + + recordLongAnimationFrame(duration: number, startTime: number): void { + const runtime = this.#runtime + if (startTime < runtime.sessionStartedAt) return + + runtime.longAnimationFrameCount++ + runtime.worstLongAnimationFrameMs = Math.max( + runtime.worstLongAnimationFrameMs, + duration, + ) + } + + recordDomMutations(count: number): void { + this.#runtime.domMutationsInSample += count + } + + resetDomMutations(): void { + this.#runtime.domMutationsInSample = 0 + } + + shouldPublish(now: number): boolean { + return now - this.#runtime.sampleStartedAt >= 500 + } + + publish(now: number): FeedMetrics { + const runtime = this.#runtime + const sampleDuration = now - runtime.sampleStartedAt + pruneLatencySamples(runtime.commitLatencySamples, now) + pruneFrameTimestamps(runtime.frameTimestamps, now) + const averageCommitLatencySamples = runtime.commitLatencySamples + .filter((sample) => sample.recordedAt >= now - averageLatencyWindowMs) + .map((sample) => sample.duration) + const percentileCommitLatencySamples = runtime.commitLatencySamples.map( + (sample) => sample.duration, + ) + const sortedCommitLatencySamples = [...percentileCommitLatencySamples].sort( + (left, right) => left - right, + ) + const rowModelCalls = + rowModelDiagnostics.calls - runtime.previousRowModelCalls + const rowModelDuration = + rowModelDiagnostics.totalDurationMs - runtime.previousRowModelDuration + const cellRendererCalls = + quoteRenderDiagnostics.cellRendererCalls - + runtime.previousCellRendererCalls + const componentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls - + runtime.previousComponentRenderCalls + const cellRendererRates = calculateInvocationRates( + quoteRenderDiagnostics.cellRendererCallsByName, + runtime.previousCellRendererCallsByName, + sampleDuration, + ) + const componentRenderRates = calculateInvocationRates( + quoteRenderDiagnostics.componentRenderCallsByName, + runtime.previousComponentRenderCallsByName, + sampleDuration, + ) + const averageCommitLatencyMs = + averageCommitLatencySamples.length === 0 + ? 0 + : averageCommitLatencySamples.reduce((sum, value) => sum + value, 0) / + averageCommitLatencySamples.length + const p95Index = Math.max( + 0, + Math.ceil(sortedCommitLatencySamples.length * 0.95) - 1, + ) + const metrics: FeedMetrics = { + actualTicksPerSecond: + sampleDuration === 0 + ? 0 + : (runtime.ticksInSample / sampleDuration) * 1_000, + rowUpdatesPerSecond: + (runtime.rowUpdatesInSample / sampleDuration) * 1_000, + workerMessagesPerSecond: + (runtime.workerMessagesInSample / sampleDuration) * 1_000, + stateApplicationsPerSecond: + (runtime.stateApplicationsInSample / sampleDuration) * 1_000, + supersededUpdatesPerSecond: + (runtime.supersededUpdatesInSample / sampleDuration) * 1_000, + totalTicks: runtime.totalTicks, + estimatedFrameRate: calculateFrameRate( + runtime.frameTimestamps, + runtime.frameTrackingStartedAt, + now, + ), + tableCommitsPerSecond: + (runtime.tableCommitsInSample / sampleDuration) * 1_000, + lastBatchSize: runtime.lastBatchSize, + averageCommitLatencyMs, + p95CommitLatencyMs: sortedCommitLatencySamples[p95Index] ?? 0, + maxCommitLatencyMs: sortedCommitLatencySamples.at(-1) ?? 0, + slowCommits: runtime.slowCommitCount, + longAnimationFrames: runtime.longAnimationFrameCount, + worstLongAnimationFrameMs: runtime.worstLongAnimationFrameMs, + heapMb: readHeapSizeMb(), + componentsCreated: quoteCellLifecycle.created, + componentsDestroyed: quoteCellLifecycle.destroyed, + workerMessages: runtime.workerMessages, + lastUpdateCount: runtime.lastUpdateCount, + cellRendererCallsPerSecond: (cellRendererCalls / sampleDuration) * 1_000, + componentRenderCallsPerSecond: + (componentRenderCalls / sampleDuration) * 1_000, + cellRendererRates, + componentRenderRates, + domMutationsPerSecond: + (runtime.domMutationsInSample / sampleDuration) * 1_000, + rowModelCallsPerSecond: (rowModelCalls / sampleDuration) * 1_000, + rowModelAverageMs: + rowModelCalls === 0 ? 0 : rowModelDuration / rowModelCalls, + rowModelMaxMs: rowModelDiagnostics.maxDurationMs, + visibleRows: rowModelDiagnostics.lastRowCount, + } + + runtime.sampleStartedAt = now + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.previousRowModelCalls = rowModelDiagnostics.calls + runtime.previousRowModelDuration = rowModelDiagnostics.totalDurationMs + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.tableCommitsInSample = 0 + return metrics + } + + reset(): void { + const runtime = this.#runtime + runtime.sessionStartedAt = performance.now() + runtime.sampleStartedAt = runtime.sessionStartedAt + runtime.pendingCommitStartedAt = null + runtime.commitLatencySamples = [] + runtime.slowCommitCount = 0 + runtime.totalTicks = 0 + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.lastBatchSize = 0 + runtime.lastUpdateCount = 0 + runtime.workerMessages = 0 + runtime.frameTrackingStartedAt = runtime.sampleStartedAt + runtime.frameTimestamps = [] + runtime.tableCommitsInSample = 0 + runtime.longAnimationFrameCount = 0 + runtime.worstLongAnimationFrameMs = 0 + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.previousRowModelCalls = rowModelDiagnostics.calls + runtime.previousRowModelDuration = rowModelDiagnostics.totalDurationMs + rowModelDiagnostics.maxDurationMs = 0 + } +} + +export const longAnimationFramesSupported = + PerformanceObserver.supportedEntryTypes.includes('long-animation-frame') + +function readHeapSizeMb(): number | null { + const memory = ( + performance as Performance & { + memory?: { usedJSHeapSize: number } + } + ).memory + return memory ? memory.usedJSHeapSize / 1_048_576 : null +} + +function calculateInvocationRates( + current: Record, + previous: Record, + sampleDuration: number, +): ReadonlyArray { + return Object.entries(current).map(([name, calls]) => ({ + name, + callsPerSecond: + sampleDuration === 0 + ? 0 + : ((calls - (previous[name] ?? 0)) / sampleDuration) * 1_000, + })) +} + +function pruneLatencySamples( + samples: Array, + now: number, +): void { + const cutoff = now - percentileLatencyWindowMs + const firstRetainedIndex = samples.findIndex( + (sample) => sample.recordedAt >= cutoff, + ) + if (firstRetainedIndex > 0) samples.splice(0, firstRetainedIndex) + else if (firstRetainedIndex === -1) samples.length = 0 +} + +function pruneFrameTimestamps(timestamps: Array, now: number): void { + const cutoff = now - frameRateWindowMs + const firstRetainedIndex = timestamps.findIndex( + (timestamp) => timestamp >= cutoff, + ) + if (firstRetainedIndex > 0) timestamps.splice(0, firstRetainedIndex) + else if (firstRetainedIndex === -1) timestamps.length = 0 +} + +function calculateFrameRate( + timestamps: ReadonlyArray, + trackingStartedAt: number, + now: number, +): number { + const observedWindowMs = Math.min( + frameRateWindowMs, + Math.max(1, now - trackingStartedAt), + ) + return (timestamps.length / observedWindowMs) * 1_000 +} diff --git a/examples/preact/realtime-trading/src/benchmark/trading-benchmark-controller.ts b/examples/preact/realtime-trading/src/benchmark/trading-benchmark-controller.ts new file mode 100644 index 0000000000..538929b373 --- /dev/null +++ b/examples/preact/realtime-trading/src/benchmark/trading-benchmark-controller.ts @@ -0,0 +1,138 @@ +import { batch, createAtom, createStore } from '@tanstack/preact-store' +import { TRADING_COLUMN_COUNT } from '../table/trading-table' +import { + BenchmarkMonitor, + initialMetrics, + longAnimationFramesSupported, +} from './benchmark-monitor' +import type { FeedMetrics } from './benchmark-monitor' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { RendererMode } from '../table/trading-table' + +export interface TradingBenchmarkState { + metrics: FeedMetrics + mountedCells: number + liveComponents: number + longAnimationFramesSupported: boolean +} + +export interface TradingBenchmarkActions { + resetViewState: () => void + setRendererMode: (mode: RendererMode) => void + setRenderedRowCount: (count: number) => void + selectSymbol: (symbol: string | null) => void + resetMarket: () => void +} + +const initialState: TradingBenchmarkState = { + metrics: initialMetrics, + mountedCells: 0, + liveComponents: 0, + longAnimationFramesSupported, +} + +export class TradingBenchmarkController { + readonly store = createStore(initialState) + readonly renderAtoms = { + selectedSymbol: createAtom(null), + rendererMode: createAtom('stable'), + } + readonly monitor = new BenchmarkMonitor() + readonly feed: MarketFeedController + readonly actions: TradingBenchmarkActions + + readonly #runtime = { + animationFrameId: 0, + longAnimationFrameObserver: null as PerformanceObserver | null, + stopObservingFeed: null as (() => void) | null, + } + + constructor(feed: MarketFeedController) { + this.feed = feed + this.actions = { + resetViewState: () => { + this.renderAtoms.selectedSymbol.set(null) + }, + setRendererMode: (mode) => { + this.renderAtoms.rendererMode.set(mode) + }, + setRenderedRowCount: (count) => { + const mountedCells = count * TRADING_COLUMN_COUNT + if (mountedCells !== this.store.get().mountedCells) { + this.#patch({ mountedCells }) + } + }, + selectSymbol: (symbol) => { + this.renderAtoms.selectedSymbol.set(symbol) + }, + resetMarket: () => { + batch(() => { + this.monitor.reset() + this.store.setState((state) => ({ + ...state, + metrics: { ...initialMetrics }, + mountedCells: 0, + liveComponents: 0, + })) + this.renderAtoms.selectedSymbol.set(null) + this.feed.actions.reset() + }) + }, + } + } + + start(): () => void { + const longAnimationFrameObserver = longAnimationFramesSupported + ? new PerformanceObserver((entries) => { + for (const entry of entries.getEntries()) { + this.monitor.recordLongAnimationFrame( + entry.duration, + entry.startTime, + ) + } + }) + : null + + this.#runtime.longAnimationFrameObserver = longAnimationFrameObserver + this.#runtime.stopObservingFeed = this.feed.observe({ + messageReceived: () => this.monitor.recordWorkerMessage(), + mutationStarted: () => this.monitor.markCommitPending(), + batchApplied: ({ tickCount, updateCount, supersededUpdateCount }) => + this.monitor.recordBatch(tickCount, updateCount, supersededUpdateCount), + renderCommitted: () => this.monitor.recordDomCommit(), + }) + longAnimationFrameObserver?.observe({ + type: 'long-animation-frame', + }) + this.#runtime.animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + + return () => this.stop() + } + + stop(): void { + cancelAnimationFrame(this.#runtime.animationFrameId) + this.#runtime.longAnimationFrameObserver?.disconnect() + this.#runtime.stopObservingFeed?.() + this.#runtime.longAnimationFrameObserver = null + this.#runtime.stopObservingFeed = null + } + + readonly #benchmarkFrame = (now: number): void => { + this.monitor.recordAnimationFrame(now) + if (this.monitor.shouldPublish(now)) { + this.#publishMetrics(this.monitor.publish(now)) + } + this.#runtime.animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + } + + #patch(patch: Partial): void { + this.store.setState((state) => ({ ...state, ...patch })) + } + + #publishMetrics(metrics: FeedMetrics): void { + this.#patch({ + metrics, + liveComponents: metrics.componentsCreated - metrics.componentsDestroyed, + }) + } +} diff --git a/examples/preact/realtime-trading/src/benchmark/use-table-benchmark.ts b/examples/preact/realtime-trading/src/benchmark/use-table-benchmark.ts new file mode 100644 index 0000000000..de40f98f9f --- /dev/null +++ b/examples/preact/realtime-trading/src/benchmark/use-table-benchmark.ts @@ -0,0 +1,28 @@ +import { useEffect } from 'preact/hooks' +import type { TradingBenchmarkController } from './trading-benchmark-controller' + +export function useTableBenchmark( + controller: TradingBenchmarkController, +): void { + useEffect(() => { + const tableBody = document.querySelector( + '.market-panel [data-trading-table] tbody', + ) + if (!tableBody) { + return + } + + controller.monitor.resetDomMutations() + const observer = new MutationObserver((records) => { + controller.monitor.recordDomMutations(records.length) + }) + observer.observe(tableBody, { + attributes: true, + attributeFilter: ['class', 'style'], + characterData: true, + childList: true, + subtree: true, + }) + return () => observer.disconnect() + }, [controller]) +} diff --git a/examples/preact/realtime-trading/src/benchmark/use-trading-benchmark-controller.ts b/examples/preact/realtime-trading/src/benchmark/use-trading-benchmark-controller.ts new file mode 100644 index 0000000000..670253ed6a --- /dev/null +++ b/examples/preact/realtime-trading/src/benchmark/use-trading-benchmark-controller.ts @@ -0,0 +1,13 @@ +import { useEffect, useState } from 'preact/hooks' +import { TradingBenchmarkController } from './trading-benchmark-controller' +import type { MarketFeedController } from '../feed/market-feed-controller' + +export function useTradingBenchmarkController(feed: MarketFeedController) { + const [controller] = useState(() => new TradingBenchmarkController(feed)) + + useEffect(() => controller.start(), [controller]) + + return controller +} + +export type { TradingBenchmarkController } from './trading-benchmark-controller' diff --git a/examples/preact/realtime-trading/src/feed/feed-sample-rates.ts b/examples/preact/realtime-trading/src/feed/feed-sample-rates.ts new file mode 100644 index 0000000000..17dc2015a6 --- /dev/null +++ b/examples/preact/realtime-trading/src/feed/feed-sample-rates.ts @@ -0,0 +1,33 @@ +export const feedSampleRateOptions = [ + { label: '100', value: 100 }, + { label: '250', value: 250 }, + { label: '500', value: 500 }, + { label: '1K', value: 1_000 }, + { label: '2.5K', value: 2_500 }, + { label: '5K', value: 5_000 }, + { label: '10K', value: 10_000 }, + { label: '25K', value: 25_000 }, + { label: '50K', value: 50_000 }, + { label: '100K', value: 100_000 }, +] as const + +export function feedSampleRateIndex(rate: number): number { + return feedSampleRateOptions.reduce((closestIndex, candidate, index) => { + const closest = feedSampleRateOptions[closestIndex] + return Math.abs(candidate.value - rate) < Math.abs(closest.value - rate) + ? index + : closestIndex + }, 0) +} + +export function feedSampleRateAt(stepIndex: number): number { + const index = Math.min( + feedSampleRateOptions.length - 1, + Math.max(0, Math.round(stepIndex)), + ) + return feedSampleRateOptions[index].value +} + +export function normalizeFeedSampleRate(rate: number): number { + return feedSampleRateAt(feedSampleRateIndex(rate)) +} diff --git a/examples/preact/realtime-trading/src/feed/market-data.ts b/examples/preact/realtime-trading/src/feed/market-data.ts new file mode 100644 index 0000000000..6231865d3f --- /dev/null +++ b/examples/preact/realtime-trading/src/feed/market-data.ts @@ -0,0 +1,38 @@ +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './worker/market-feed-protocol' + +export interface MarketQuote extends Omit { + history: ReadonlyArray +} + +export function hydrateMarketQuotes( + snapshots: Array, +): Array { + return snapshots.map((quote) => ({ + ...quote, + history: [...quote.history], + })) +} + +export function applyMarketUpdates( + quotes: Array, + updates: Array, +): Array { + const nextQuotes = [...quotes] + + for (const update of updates) { + const { index, history, ...values } = update + const previousQuote = quotes.at(index) + if (!previousQuote) continue + + nextQuotes[index] = { + ...previousQuote, + ...values, + history: history ?? previousQuote.history, + } + } + + return nextQuotes +} diff --git a/examples/preact/realtime-trading/src/feed/market-feed-config.ts b/examples/preact/realtime-trading/src/feed/market-feed-config.ts new file mode 100644 index 0000000000..9d477ed663 --- /dev/null +++ b/examples/preact/realtime-trading/src/feed/market-feed-config.ts @@ -0,0 +1,15 @@ +export interface MarketFeedConfig { + readonly instrumentCount: number + readonly targetSamplesPerSecond: number + readonly publishIntervalMs: number + readonly updateSparklines: boolean + readonly sparklineSampleIntervalMs: number +} + +export const initialMarketFeedConfig: MarketFeedConfig = { + instrumentCount: 100, + targetSamplesPerSecond: 10_000, + publishIntervalMs: 20, + updateSparklines: true, + sparklineSampleIntervalMs: 16, +} diff --git a/examples/preact/realtime-trading/src/feed/market-feed-controller.ts b/examples/preact/realtime-trading/src/feed/market-feed-controller.ts new file mode 100644 index 0000000000..21b5f59222 --- /dev/null +++ b/examples/preact/realtime-trading/src/feed/market-feed-controller.ts @@ -0,0 +1,227 @@ +import { batch, createAtom } from '@tanstack/preact-store' +import { normalizeFeedSampleRate } from './feed-sample-rates' +import { initialMarketFeedConfig } from './market-feed-config' +import { applyMarketUpdates, hydrateMarketQuotes } from './market-data' +import type { + MarketFeedCommand, + MarketFeedEvent, +} from './worker/market-feed-protocol' +import type { MarketQuote } from './market-data' + +export interface MarketFeedBatch { + tickCount: number + updateCount: number + supersededUpdateCount: number +} + +export interface MarketFeedObserver { + messageReceived?: () => void + mutationStarted?: () => void + batchApplied?: (batch: MarketFeedBatch) => void + renderCommitted?: () => void +} + +export interface MarketFeedActions { + toggle: () => void + setInstrumentCount: (count: number) => void + setTargetRate: (rate: number) => void + setPublishInterval: (intervalMs: number) => void + setSparklineUpdates: (enabled: boolean) => void + setSparklineSampleInterval: (intervalMs: number) => void + runBurst: () => void + reset: () => void +} + +export class MarketFeedController { + readonly workerReady = createAtom(false) + readonly running = createAtom( + !new URLSearchParams(location.search).has('paused'), + ) + readonly instrumentCount = createAtom(initialMarketFeedConfig.instrumentCount) + readonly targetTicksPerSecond = createAtom( + initialMarketFeedConfig.targetSamplesPerSecond, + ) + readonly publishIntervalMs = createAtom( + initialMarketFeedConfig.publishIntervalMs, + ) + readonly updateSparklines = createAtom( + initialMarketFeedConfig.updateSparklines, + ) + readonly sparklineSampleIntervalMs = createAtom( + initialMarketFeedConfig.sparklineSampleIntervalMs, + ) + readonly quotes = createAtom>([]) + readonly actions: MarketFeedActions + readonly #observers = new Set() + readonly #runtime = { + worker: null as Worker | null, + feedSessionId: 0, + renderPending: false, + resetWaitingForCommit: false, + resetSnapshotReady: false, + quoteIndexBySymbol: new Map(), + } + + constructor() { + this.actions = { + toggle: () => { + const running = !this.running.get() + this.running.set(running) + this.#post({ type: 'set-running', running }) + }, + setInstrumentCount: (count) => { + this.instrumentCount.set(count) + this.#resetWorker(count) + }, + setTargetRate: (rate) => { + const sampleRate = normalizeFeedSampleRate(rate) + this.targetTicksPerSecond.set(sampleRate) + this.#post({ type: 'set-rate', ticksPerSecond: sampleRate }) + }, + setPublishInterval: (publishIntervalMs) => { + this.publishIntervalMs.set(publishIntervalMs) + this.#post({ + type: 'set-publish-interval', + intervalMs: publishIntervalMs, + }) + }, + setSparklineUpdates: (enabled) => { + this.updateSparklines.set(enabled) + this.#post({ type: 'set-sparklines', enabled }) + }, + setSparklineSampleInterval: (intervalMs) => { + this.sparklineSampleIntervalMs.set(intervalMs) + this.#post({ type: 'set-sparkline-interval', intervalMs }) + }, + runBurst: () => this.#post({ type: 'burst', tickCount: 25_000 }), + reset: () => this.#resetWorker(this.instrumentCount.get()), + } + } + + start(): () => void { + const worker = new Worker( + new URL('./worker/market-feed.worker.ts', import.meta.url), + { type: 'module' }, + ) + this.#runtime.worker = worker + worker.addEventListener('message', this.#handleWorkerMessage) + worker.addEventListener('error', this.#handleWorkerError) + this.#post({ + type: 'start', + rowCount: this.instrumentCount.get(), + running: this.running.get(), + ticksPerSecond: this.targetTicksPerSecond.get(), + publishIntervalMs: this.publishIntervalMs.get(), + updateSparklines: this.updateSparklines.get(), + sparklineSampleIntervalMs: this.sparklineSampleIntervalMs.get(), + }) + return () => this.stop() + } + + stop(): void { + this.#runtime.worker?.removeEventListener( + 'message', + this.#handleWorkerMessage, + ) + this.#runtime.worker?.removeEventListener('error', this.#handleWorkerError) + this.#runtime.worker?.terminate() + this.#runtime.worker = null + this.#observers.clear() + } + + observe(observer: MarketFeedObserver): () => void { + this.#observers.add(observer) + return () => this.#observers.delete(observer) + } + + getQuoteBySymbol( + quotes: Array, + symbol: string | null, + ): MarketQuote | null { + if (symbol === null) return null + + const index = this.#runtime.quoteIndexBySymbol.get(symbol) + return index === undefined ? null : (quotes[index] ?? null) + } + + completeRender(): void { + if (!this.#runtime.renderPending) return + + this.#runtime.renderPending = false + for (const observer of this.#observers) { + observer.renderCommitted?.() + } + if ( + this.#runtime.resetWaitingForCommit && + this.#runtime.resetSnapshotReady + ) { + this.#runtime.resetWaitingForCommit = false + this.#runtime.resetSnapshotReady = false + this.#post({ type: 'set-running', running: this.running.get() }) + } + } + + readonly #handleWorkerMessage = ({ + data, + }: MessageEvent): void => { + if (data.type === 'snapshot') { + this.#runtime.feedSessionId = data.sessionId + if (this.#runtime.resetWaitingForCommit) { + this.#runtime.resetSnapshotReady = true + } + this.#startMutation() + const quotes = hydrateMarketQuotes(data.quotes) + this.#runtime.quoteIndexBySymbol = new Map( + quotes.map((quote, index) => [quote.symbol, index]), + ) + batch(() => { + this.quotes.set(quotes) + this.workerReady.set(true) + }) + return + } + + if (data.sessionId !== this.#runtime.feedSessionId) return + + for (const observer of this.#observers) { + observer.messageReceived?.() + } + this.#startMutation() + this.quotes.set(applyMarketUpdates(this.quotes.get(), data.updates)) + const feedBatch = { + tickCount: data.tickCount, + updateCount: data.updates.length, + supersededUpdateCount: data.coalescedUpdateCount, + } + for (const observer of this.#observers) { + observer.batchApplied?.(feedBatch) + } + } + + readonly #handleWorkerError = (error: ErrorEvent): void => { + batch(() => { + this.workerReady.set(false) + this.running.set(false) + }) + console.error('Market feed worker failed', error) + } + + #resetWorker(rowCount: number): void { + this.workerReady.set(false) + this.#runtime.resetWaitingForCommit = true + this.#runtime.resetSnapshotReady = false + this.#post({ type: 'set-running', running: false }) + this.#post({ type: 'reset', rowCount }) + } + + #startMutation(): void { + this.#runtime.renderPending = true + for (const observer of this.#observers) { + observer.mutationStarted?.() + } + } + + #post(command: MarketFeedCommand): void { + this.#runtime.worker?.postMessage(command) + } +} diff --git a/examples/preact/realtime-trading/src/feed/market-instruments.ts b/examples/preact/realtime-trading/src/feed/market-instruments.ts new file mode 100644 index 0000000000..ac18d14ea9 --- /dev/null +++ b/examples/preact/realtime-trading/src/feed/market-instruments.ts @@ -0,0 +1,742 @@ +export type MarketCode = + | 'US' + | 'NL' + | 'DE' + | 'FR' + | 'IT' + | 'ES' + | 'CH' + | 'DK' + | 'SE' + | 'FI' + | 'GB' + | 'KR' + | 'JP' + | 'HK' + | 'CA' + | 'AU' + +export type BaseInstrument = readonly [ + symbol: string, + company: string, + market: MarketCode, +] + +/** + * Current S&P 500 constituent universe used by the realtime trading examples. + * + * Source snapshot: https://github.com/datasets/s-and-p-500-companies + * Retrieved: 2026-08-15. + * Multiple share classes are intentionally represented as separate instruments. + */ +export const marketInstruments = Object.freeze([ + ['MMM', '3M', 'US'], + ['AOS', 'A. O. Smith', 'US'], + ['ABT', 'Abbott Laboratories', 'US'], + ['ABBV', 'AbbVie', 'US'], + ['ACN', 'Accenture', 'US'], + ['ADBE', 'Adobe Inc.', 'US'], + ['AMD', 'Advanced Micro Devices', 'US'], + ['AES', 'AES Corporation', 'US'], + ['AFL', 'Aflac', 'US'], + ['A', 'Agilent Technologies', 'US'], + ['APD', 'Air Products', 'US'], + ['ABNB', 'Airbnb', 'US'], + ['AKAM', 'Akamai Technologies', 'US'], + ['ALB', 'Albemarle Corporation', 'US'], + ['ARE', 'Alexandria Real Estate Equities', 'US'], + ['ALGN', 'Align Technology', 'US'], + ['ALLE', 'Allegion', 'US'], + ['LNT', 'Alliant Energy', 'US'], + ['ALL', 'Allstate', 'US'], + ['GOOGL', 'Alphabet Inc. (Class A)', 'US'], + ['GOOG', 'Alphabet Inc. (Class C)', 'US'], + ['MO', 'Altria', 'US'], + ['AMZN', 'Amazon', 'US'], + ['AMCR', 'Amcor', 'US'], + ['AEE', 'Ameren', 'US'], + ['AEP', 'American Electric Power', 'US'], + ['AXP', 'American Express', 'US'], + ['AIG', 'American International Group', 'US'], + ['AMT', 'American Tower', 'US'], + ['AWK', 'American Water Works', 'US'], + ['AMP', 'Ameriprise Financial', 'US'], + ['AME', 'Ametek', 'US'], + ['AMGN', 'Amgen', 'US'], + ['APH', 'Amphenol', 'US'], + ['ADI', 'Analog Devices', 'US'], + ['AON', 'Aon plc', 'US'], + ['APA', 'APA Corporation', 'US'], + ['APO', 'Apollo Global Management', 'US'], + ['AAPL', 'Apple Inc.', 'US'], + ['AMAT', 'Applied Materials', 'US'], + ['APP', 'AppLovin', 'US'], + ['APTV', 'Aptiv', 'US'], + ['ACGL', 'Arch Capital Group', 'US'], + ['ADM', 'Archer Daniels Midland', 'US'], + ['ARES', 'Ares Management', 'US'], + ['ANET', 'Arista Networks', 'US'], + ['AJG', 'Arthur J. Gallagher & Co.', 'US'], + ['AIZ', 'Assurant', 'US'], + ['T', 'AT&T', 'US'], + ['ATO', 'Atmos Energy', 'US'], + ['ADSK', 'Autodesk', 'US'], + ['ADP', 'Automatic Data Processing', 'US'], + ['AZO', 'AutoZone', 'US'], + ['AVB', 'AvalonBay Communities', 'US'], + ['AVY', 'Avery Dennison', 'US'], + ['AXON', 'Axon Enterprise', 'US'], + ['BKR', 'Baker Hughes', 'US'], + ['BALL', 'Ball Corporation', 'US'], + ['BAC', 'Bank of America', 'US'], + ['BAX', 'Baxter International', 'US'], + ['BDX', 'Becton Dickinson', 'US'], + ['BRK.B', 'Berkshire Hathaway', 'US'], + ['BBY', 'Best Buy', 'US'], + ['TECH', 'Bio-Techne', 'US'], + ['BIIB', 'Biogen', 'US'], + ['BLK', 'BlackRock', 'US'], + ['BX', 'Blackstone Inc.', 'US'], + ['XYZ', 'Block, Inc.', 'US'], + ['BNY', 'BNY Mellon', 'US'], + ['BA', 'Boeing', 'US'], + ['BKNG', 'Booking Holdings', 'US'], + ['BSX', 'Boston Scientific', 'US'], + ['BMY', 'Bristol Myers Squibb', 'US'], + ['AVGO', 'Broadcom', 'US'], + ['BR', 'Broadridge Financial Solutions', 'US'], + ['BRO', 'Brown & Brown', 'US'], + ['BF.B', 'Brown–Forman', 'US'], + ['BLDR', 'Builders FirstSource', 'US'], + ['BG', 'Bunge Global', 'US'], + ['BXP', 'BXP, Inc.', 'US'], + ['CHRW', 'C.H. Robinson', 'US'], + ['CDNS', 'Cadence Design Systems', 'US'], + ['CPT', 'Camden Property Trust', 'US'], + ['COF', 'Capital One', 'US'], + ['CAH', 'Cardinal Health', 'US'], + ['CCL', 'Carnival Corporation', 'US'], + ['CARR', 'Carrier Global', 'US'], + ['CVNA', 'Carvana', 'US'], + ['CASY', "Casey's", 'US'], + ['CAT', 'Caterpillar Inc.', 'US'], + ['CBOE', 'Cboe Global Markets', 'US'], + ['CBRE', 'CBRE Group', 'US'], + ['CDW', 'CDW Corporation', 'US'], + ['COR', 'Cencora', 'US'], + ['CNC', 'Centene Corporation', 'US'], + ['CNP', 'CenterPoint Energy', 'US'], + ['CF', 'CF Industries', 'US'], + ['CRL', 'Charles River Laboratories', 'US'], + ['SCHW', 'Charles Schwab Corporation', 'US'], + ['CHTR', 'Charter Communications', 'US'], + ['CVX', 'Chevron Corporation', 'US'], + ['CMG', 'Chipotle Mexican Grill', 'US'], + ['CB', 'Chubb Limited', 'US'], + ['CHD', 'Church & Dwight', 'US'], + ['CIEN', 'Ciena', 'US'], + ['CI', 'Cigna', 'US'], + ['CINF', 'Cincinnati Financial', 'US'], + ['CTAS', 'Cintas', 'US'], + ['CSCO', 'Cisco', 'US'], + ['C', 'Citigroup', 'US'], + ['CFG', 'Citizens Financial Group', 'US'], + ['CLX', 'Clorox', 'US'], + ['CME', 'CME Group', 'US'], + ['CMS', 'CMS Energy', 'US'], + ['KO', 'Coca-Cola Company (The)', 'US'], + ['CTSH', 'Cognizant', 'US'], + ['COHR', 'Coherent Corp.', 'US'], + ['COIN', 'Coinbase', 'US'], + ['CL', 'Colgate-Palmolive', 'US'], + ['CMCSA', 'Comcast', 'US'], + ['FIX', 'Comfort Systems USA', 'US'], + ['COP', 'ConocoPhillips', 'US'], + ['ED', 'Consolidated Edison', 'US'], + ['STZ', 'Constellation Brands', 'US'], + ['CEG', 'Constellation Energy', 'US'], + ['COO', 'Cooper Companies (The)', 'US'], + ['CPRT', 'Copart', 'US'], + ['GLW', 'Corning Inc.', 'US'], + ['CPAY', 'Corpay', 'US'], + ['CTVA', 'Corteva', 'US'], + ['CSGP', 'CoStar Group', 'US'], + ['COST', 'Costco', 'US'], + ['CRH', 'CRH plc', 'US'], + ['CRWD', 'CrowdStrike', 'US'], + ['CCI', 'Crown Castle', 'US'], + ['CSX', 'CSX Corporation', 'US'], + ['CMI', 'Cummins', 'US'], + ['CVS', 'CVS Health', 'US'], + ['DHR', 'Danaher Corporation', 'US'], + ['DRI', 'Darden Restaurants', 'US'], + ['DDOG', 'Datadog', 'US'], + ['DVA', 'DaVita', 'US'], + ['DECK', 'Deckers Brands', 'US'], + ['DE', 'Deere & Company', 'US'], + ['DELL', 'Dell Technologies', 'US'], + ['DAL', 'Delta Air Lines', 'US'], + ['DVN', 'Devon Energy', 'US'], + ['DXCM', 'Dexcom', 'US'], + ['FANG', 'Diamondback Energy', 'US'], + ['DLR', 'Digital Realty', 'US'], + ['DG', 'Dollar General', 'US'], + ['DLTR', 'Dollar Tree', 'US'], + ['D', 'Dominion Energy', 'US'], + ['DPZ', "Domino's", 'US'], + ['DASH', 'DoorDash', 'US'], + ['DOV', 'Dover Corporation', 'US'], + ['DOW', 'Dow Inc.', 'US'], + ['DHI', 'D. R. Horton', 'US'], + ['DTE', 'DTE Energy', 'US'], + ['DUK', 'Duke Energy', 'US'], + ['DD', 'DuPont', 'US'], + ['ETN', 'Eaton Corporation', 'US'], + ['EBAY', 'eBay Inc.', 'US'], + ['ECHO', 'EchoStar', 'US'], + ['ECL', 'Ecolab', 'US'], + ['EIX', 'Edison International', 'US'], + ['EW', 'Edwards Lifesciences', 'US'], + ['ELV', 'Elevance Health', 'US'], + ['EME', 'Emcor', 'US'], + ['EMR', 'Emerson Electric', 'US'], + ['ETR', 'Entergy', 'US'], + ['EOG', 'EOG Resources', 'US'], + ['EQT', 'EQT Corporation', 'US'], + ['EFX', 'Equifax', 'US'], + ['EQIX', 'Equinix', 'US'], + ['EQR', 'Equity Residential', 'US'], + ['ERIE', 'Erie Indemnity', 'US'], + ['ESS', 'Essex Property Trust', 'US'], + ['EL', 'Estée Lauder Companies (The)', 'US'], + ['EG', 'Everest Group', 'US'], + ['EVRG', 'Evergy', 'US'], + ['ES', 'Eversource Energy', 'US'], + ['EXC', 'Exelon', 'US'], + ['EXE', 'Expand Energy', 'US'], + ['EXPE', 'Expedia Group', 'US'], + ['EXPD', 'Expeditors International', 'US'], + ['EXR', 'Extra Space Storage', 'US'], + ['XOM', 'ExxonMobil', 'US'], + ['FFIV', 'F5, Inc.', 'US'], + ['FDS', 'FactSet', 'US'], + ['FICO', 'Fair Isaac', 'US'], + ['FAST', 'Fastenal', 'US'], + ['FRT', 'Federal Realty Investment Trust', 'US'], + ['FDX', 'FedEx', 'US'], + ['FDXF', 'FedEx Freight', 'US'], + ['FERG', 'Ferguson Enterprises', 'US'], + ['FIS', 'Fidelity National Information Services', 'US'], + ['FITB', 'Fifth Third Bancorp', 'US'], + ['FSLR', 'First Solar', 'US'], + ['FE', 'FirstEnergy', 'US'], + ['FISV', 'Fiserv', 'US'], + ['FLEX', 'Flex Ltd.', 'US'], + ['F', 'Ford Motor Company', 'US'], + ['FTNT', 'Fortinet', 'US'], + ['FTV', 'Fortive', 'US'], + ['FOXA', 'Fox Corporation (Class A)', 'US'], + ['FOX', 'Fox Corporation (Class B)', 'US'], + ['BEN', 'Franklin Resources', 'US'], + ['FCX', 'Freeport-McMoRan', 'US'], + ['GRMN', 'Garmin', 'US'], + ['IT', 'Gartner', 'US'], + ['GE', 'GE Aerospace', 'US'], + ['GEHC', 'GE HealthCare', 'US'], + ['GEV', 'GE Vernova', 'US'], + ['GEN', 'Gen Digital', 'US'], + ['GNRC', 'Generac', 'US'], + ['GD', 'General Dynamics', 'US'], + ['GIS', 'General Mills', 'US'], + ['GM', 'General Motors', 'US'], + ['GPC', 'Genuine Parts Company', 'US'], + ['GILD', 'Gilead Sciences', 'US'], + ['GPN', 'Global Payments', 'US'], + ['GL', 'Globe Life', 'US'], + ['GDDY', 'GoDaddy', 'US'], + ['GS', 'Goldman Sachs', 'US'], + ['HAL', 'Halliburton', 'US'], + ['HIG', 'Hartford (The)', 'US'], + ['HAS', 'Hasbro', 'US'], + ['HCA', 'HCA Healthcare', 'US'], + ['DOC', 'Healthpeak Properties', 'US'], + ['HSIC', 'Henry Schein', 'US'], + ['HSY', 'Hershey Company (The)', 'US'], + ['HPE', 'Hewlett Packard Enterprise', 'US'], + ['HLT', 'Hilton Worldwide', 'US'], + ['HD', 'Home Depot (The)', 'US'], + ['HONA', 'Honeywell Aerospace', 'US'], + ['HON', 'Honeywell Technologies', 'US'], + ['HRL', 'Hormel Foods', 'US'], + ['HST', 'Host Hotels & Resorts', 'US'], + ['HWM', 'Howmet Aerospace', 'US'], + ['HPQ', 'HP Inc.', 'US'], + ['HUBB', 'Hubbell Incorporated', 'US'], + ['HUM', 'Humana', 'US'], + ['HBAN', 'Huntington Bancshares', 'US'], + ['HII', 'Huntington Ingalls Industries', 'US'], + ['IBM', 'IBM', 'US'], + ['IEX', 'IDEX Corporation', 'US'], + ['IDXX', 'Idexx Laboratories', 'US'], + ['ITW', 'Illinois Tool Works', 'US'], + ['INCY', 'Incyte', 'US'], + ['IR', 'Ingersoll Rand', 'US'], + ['PODD', 'Insulet Corporation', 'US'], + ['INTC', 'Intel', 'US'], + ['IBKR', 'Interactive Brokers', 'US'], + ['ICE', 'Intercontinental Exchange', 'US'], + ['IFF', 'International Flavors & Fragrances', 'US'], + ['IP', 'International Paper', 'US'], + ['INTU', 'Intuit', 'US'], + ['ISRG', 'Intuitive Surgical', 'US'], + ['IVZ', 'Invesco', 'US'], + ['INVH', 'Invitation Homes', 'US'], + ['IQV', 'IQVIA', 'US'], + ['IRM', 'Iron Mountain', 'US'], + ['JBHT', 'J.B. Hunt', 'US'], + ['JBL', 'Jabil', 'US'], + ['JKHY', 'Jack Henry & Associates', 'US'], + ['J', 'Jacobs Solutions', 'US'], + ['JNJ', 'Johnson & Johnson', 'US'], + ['JCI', 'Johnson Controls', 'US'], + ['JPM', 'JPMorgan Chase', 'US'], + ['KVUE', 'Kenvue', 'US'], + ['KDP', 'Keurig Dr Pepper', 'US'], + ['KEY', 'KeyCorp', 'US'], + ['KEYS', 'Keysight Technologies', 'US'], + ['KMB', 'Kimberly-Clark', 'US'], + ['KIM', 'Kimco Realty', 'US'], + ['KMI', 'Kinder Morgan', 'US'], + ['KKR', 'KKR & Co.', 'US'], + ['KLAC', 'KLA Corporation', 'US'], + ['KHC', 'Kraft Heinz', 'US'], + ['KR', 'Kroger', 'US'], + ['LHX', 'L3Harris', 'US'], + ['LH', 'Labcorp', 'US'], + ['LRCX', 'Lam Research', 'US'], + ['LVS', 'Las Vegas Sands', 'US'], + ['LDOS', 'Leidos', 'US'], + ['LEN', 'Lennar', 'US'], + ['LII', 'Lennox International', 'US'], + ['LLY', 'Lilly (Eli)', 'US'], + ['LIN', 'Linde plc', 'US'], + ['LYV', 'Live Nation Entertainment', 'US'], + ['LMT', 'Lockheed Martin', 'US'], + ['L', 'Loews Corporation', 'US'], + ['LOW', "Lowe's", 'US'], + ['LULU', 'Lululemon Athletica', 'US'], + ['LITE', 'Lumentum', 'US'], + ['LYB', 'LyondellBasell', 'US'], + ['MTB', 'M&T Bank', 'US'], + ['MPC', 'Marathon Petroleum', 'US'], + ['MAR', 'Marriott International', 'US'], + ['MRSH', 'Marsh McLennan', 'US'], + ['MLM', 'Martin Marietta Materials', 'US'], + ['MRVL', 'Marvell Technology', 'US'], + ['MAS', 'Masco', 'US'], + ['MA', 'Mastercard', 'US'], + ['MKC', 'McCormick & Company', 'US'], + ['MCD', "McDonald's", 'US'], + ['MCK', 'McKesson Corporation', 'US'], + ['MDT', 'Medtronic', 'US'], + ['MRK', 'Merck & Co.', 'US'], + ['META', 'Meta Platforms', 'US'], + ['MET', 'MetLife', 'US'], + ['MTD', 'Mettler Toledo', 'US'], + ['MGM', 'MGM Resorts', 'US'], + ['MCHP', 'Microchip Technology', 'US'], + ['MU', 'Micron Technology', 'US'], + ['MSFT', 'Microsoft', 'US'], + ['MAA', 'Mid-America Apartment Communities', 'US'], + ['MRNA', 'Moderna', 'US'], + ['TAP', 'Molson Coors Beverage Company', 'US'], + ['MDLZ', 'Mondelez International', 'US'], + ['MPWR', 'Monolithic Power Systems', 'US'], + ['MNST', 'Monster Beverage', 'US'], + ['MCO', "Moody's Corporation", 'US'], + ['MS', 'Morgan Stanley', 'US'], + ['MOS', 'Mosaic Company (The)', 'US'], + ['MSI', 'Motorola Solutions', 'US'], + ['MSCI', 'MSCI', 'US'], + ['NDAQ', 'Nasdaq, Inc.', 'US'], + ['NTAP', 'NetApp', 'US'], + ['NFLX', 'Netflix', 'US'], + ['NEM', 'Newmont', 'US'], + ['NWSA', 'News Corp (Class A)', 'US'], + ['NWS', 'News Corp (Class B)', 'US'], + ['NEE', 'NextEra Energy', 'US'], + ['NKE', 'Nike, Inc.', 'US'], + ['NI', 'NiSource', 'US'], + ['NDSN', 'Nordson Corporation', 'US'], + ['NSC', 'Norfolk Southern', 'US'], + ['NTRS', 'Northern Trust', 'US'], + ['NOC', 'Northrop Grumman', 'US'], + ['NCLH', 'Norwegian Cruise Line Holdings', 'US'], + ['NRG', 'NRG Energy', 'US'], + ['NUE', 'Nucor', 'US'], + ['NVDA', 'Nvidia', 'US'], + ['NVR', 'NVR, Inc.', 'US'], + ['NXPI', 'NXP Semiconductors', 'US'], + ['ORLY', "O'Reilly Automotive", 'US'], + ['OXY', 'Occidental Petroleum', 'US'], + ['ODFL', 'Old Dominion', 'US'], + ['OMC', 'Omnicom Group', 'US'], + ['ON', 'ON Semiconductor', 'US'], + ['OKE', 'Oneok', 'US'], + ['ORCL', 'Oracle Corporation', 'US'], + ['OTIS', 'Otis Worldwide', 'US'], + ['PCAR', 'Paccar', 'US'], + ['PKG', 'Packaging Corporation of America', 'US'], + ['PLTR', 'Palantir Technologies', 'US'], + ['PANW', 'Palo Alto Networks', 'US'], + ['PSKY', 'Paramount Skydance Corporation', 'US'], + ['PH', 'Parker Hannifin', 'US'], + ['PAYX', 'Paychex', 'US'], + ['PYPL', 'PayPal', 'US'], + ['PNR', 'Pentair', 'US'], + ['PEP', 'PepsiCo', 'US'], + ['PFE', 'Pfizer', 'US'], + ['PCG', 'PG&E Corporation', 'US'], + ['PM', 'Philip Morris International', 'US'], + ['PSX', 'Phillips 66', 'US'], + ['PNW', 'Pinnacle West Capital', 'US'], + ['PNC', 'PNC Financial Services', 'US'], + ['PPG', 'PPG Industries', 'US'], + ['PPL', 'PPL Corporation', 'US'], + ['PFG', 'Principal Financial Group', 'US'], + ['PG', 'Procter & Gamble', 'US'], + ['PGR', 'Progressive Corporation', 'US'], + ['PLD', 'Prologis', 'US'], + ['PRU', 'Prudential Financial', 'US'], + ['PEG', 'Public Service Enterprise Group', 'US'], + ['PTC', 'PTC Inc.', 'US'], + ['PSA', 'Public Storage', 'US'], + ['PHM', 'PulteGroup', 'US'], + ['PWR', 'Quanta Services', 'US'], + ['QCOM', 'Qualcomm', 'US'], + ['DGX', 'Quest Diagnostics', 'US'], + ['Q', 'Qnity Electronics', 'US'], + ['RL', 'Ralph Lauren Corporation', 'US'], + ['RJF', 'Raymond James Financial', 'US'], + ['RTX', 'RTX Corporation', 'US'], + ['O', 'Realty Income', 'US'], + ['REG', 'Regency Centers', 'US'], + ['REGN', 'Regeneron Pharmaceuticals', 'US'], + ['RF', 'Regions Financial Corporation', 'US'], + ['RSG', 'Republic Services', 'US'], + ['RMD', 'ResMed|', 'US'], + ['RVTY', 'Revvity', 'US'], + ['HOOD', 'Robinhood Markets', 'US'], + ['ROK', 'Rockwell Automation', 'US'], + ['ROL', 'Rollins, Inc.', 'US'], + ['ROP', 'Roper Technologies', 'US'], + ['ROST', 'Ross Stores', 'US'], + ['RCL', 'Royal Caribbean Group', 'US'], + ['SPGI', 'S&P Global', 'US'], + ['CRM', 'Salesforce', 'US'], + ['SNDK', 'Sandisk', 'US'], + ['SBAC', 'SBA Communications', 'US'], + ['SLB', 'Schlumberger', 'US'], + ['STX', 'Seagate Technology', 'US'], + ['SRE', 'Sempra', 'US'], + ['NOW', 'ServiceNow', 'US'], + ['SHW', 'Sherwin-Williams', 'US'], + ['SPG', 'Simon Property Group', 'US'], + ['SWKS', 'Skyworks Solutions', 'US'], + ['SJM', 'J.M. Smucker Company (The)', 'US'], + ['SW', 'Smurfit Westrock', 'US'], + ['SNA', 'Snap-on', 'US'], + ['SOLV', 'Solventum', 'US'], + ['SO', 'Southern Company', 'US'], + ['LUV', 'Southwest Airlines', 'US'], + ['SWK', 'Stanley Black & Decker', 'US'], + ['SBUX', 'Starbucks', 'US'], + ['STT', 'State Street Corporation', 'US'], + ['STLD', 'Steel Dynamics', 'US'], + ['STE', 'Steris', 'US'], + ['SYK', 'Stryker Corporation', 'US'], + ['SMCI', 'Supermicro', 'US'], + ['SYF', 'Synchrony Financial', 'US'], + ['SNPS', 'Synopsys', 'US'], + ['SYY', 'Sysco', 'US'], + ['TMUS', 'T-Mobile US', 'US'], + ['TROW', 'T. Rowe Price', 'US'], + ['TTWO', 'Take-Two Interactive', 'US'], + ['TPR', 'Tapestry, Inc.', 'US'], + ['TRGP', 'Targa Resources', 'US'], + ['TGT', 'Target Corporation', 'US'], + ['TEL', 'TE Connectivity', 'US'], + ['TDY', 'Teledyne Technologies', 'US'], + ['TER', 'Teradyne', 'US'], + ['TSLA', 'Tesla, Inc.', 'US'], + ['TXN', 'Texas Instruments', 'US'], + ['TPL', 'Texas Pacific Land Corporation', 'US'], + ['TXT', 'Textron', 'US'], + ['TMO', 'Thermo Fisher Scientific', 'US'], + ['TJX', 'TJX Companies', 'US'], + ['TKO', 'TKO Group Holdings', 'US'], + ['TTD', 'Trade Desk (The)', 'US'], + ['TSCO', 'Tractor Supply', 'US'], + ['TT', 'Trane Technologies', 'US'], + ['TDG', 'TransDigm Group', 'US'], + ['TRV', 'Travelers Companies (The)', 'US'], + ['TRMB', 'Trimble Inc.', 'US'], + ['TFC', 'Truist Financial', 'US'], + ['TYL', 'Tyler Technologies', 'US'], + ['TSN', 'Tyson Foods', 'US'], + ['USB', 'U.S. Bancorp', 'US'], + ['UBER', 'Uber', 'US'], + ['UDR', 'UDR, Inc.', 'US'], + ['ULTA', 'Ulta Beauty', 'US'], + ['UNP', 'Union Pacific Corporation', 'US'], + ['UAL', 'United Airlines Holdings', 'US'], + ['UPS', 'United Parcel Service', 'US'], + ['URI', 'United Rentals', 'US'], + ['UNH', 'UnitedHealth Group', 'US'], + ['UHS', 'Universal Health Services', 'US'], + ['VLO', 'Valero Energy', 'US'], + ['VEEV', 'Veeva Systems', 'US'], + ['VTR', 'Ventas', 'US'], + ['VLTO', 'Veralto', 'US'], + ['VRSN', 'Verisign', 'US'], + ['VRSK', 'Verisk Analytics', 'US'], + ['VZ', 'Verizon', 'US'], + ['VRTX', 'Vertex Pharmaceuticals', 'US'], + ['VRT', 'Vertiv', 'US'], + ['VTRS', 'Viatris', 'US'], + ['VICI', 'Vici Properties', 'US'], + ['V', 'Visa Inc.', 'US'], + ['VST', 'Vistra Corp.', 'US'], + ['VMC', 'Vulcan Materials Company', 'US'], + ['WRB', 'W. R. Berkley Corporation', 'US'], + ['GWW', 'W. W. Grainger', 'US'], + ['WAB', 'Wabtec', 'US'], + ['WMT', 'Walmart', 'US'], + ['DIS', 'Walt Disney Company (The)', 'US'], + ['WBD', 'Warner Bros. Discovery', 'US'], + ['WM', 'Waste Management', 'US'], + ['WAT', 'Waters Corporation', 'US'], + ['WEC', 'WEC Energy Group', 'US'], + ['WFC', 'Wells Fargo', 'US'], + ['WELL', 'Welltower', 'US'], + ['WST', 'West Pharmaceutical Services', 'US'], + ['WDC', 'Western Digital', 'US'], + ['WY', 'Weyerhaeuser', 'US'], + ['WSM', 'Williams-Sonoma, Inc.', 'US'], + ['WMB', 'Williams Companies', 'US'], + ['WTW', 'Willis Towers Watson', 'US'], + ['WDAY', 'Workday, Inc.', 'US'], + ['WYNN', 'Wynn Resorts', 'US'], + ['XEL', 'Xcel Energy', 'US'], + ['XYL', 'Xylem Inc.', 'US'], + ['YUM', 'Yum! Brands', 'US'], + ['ZBRA', 'Zebra Technologies', 'US'], + ['ZBH', 'Zimmer Biomet', 'US'], + ['ZTS', 'Zoetis', 'US'], +]) + +/** + * Representative liquid international listings used to diversify the fixture. + * Symbols use their local-market form and the third tuple value is an ISO-style + * country/market code, rather than a trading currency or exchange MIC. + * + * References checked 2026-08-15: STOXX Europe 50, KRX KOSPI market, + * JPX TOPIX Core30, and HKEX index constituent materials. + */ +const europeanInstruments = Object.freeze([ + ['ASML', 'ASML Holding', 'NL'], + ['INGA', 'ING Group', 'NL'], + ['ADYEN', 'Adyen', 'NL'], + ['PHIA', 'Philips', 'NL'], + ['HEIA', 'Heineken', 'NL'], + ['SAP', 'SAP', 'DE'], + ['SIE', 'Siemens', 'DE'], + ['ALV', 'Allianz', 'DE'], + ['DTE', 'Deutsche Telekom', 'DE'], + ['MBG', 'Mercedes-Benz Group', 'DE'], + ['BMW', 'BMW', 'DE'], + ['BAS', 'BASF', 'DE'], + ['MUV2', 'Munich Re', 'DE'], + ['VOW3', 'Volkswagen Preference', 'DE'], + ['IFX', 'Infineon Technologies', 'DE'], + ['MC', 'LVMH', 'FR'], + ['OR', "L'Oréal", 'FR'], + ['AIR', 'Airbus', 'FR'], + ['SU', 'Schneider Electric', 'FR'], + ['TTE', 'TotalEnergies', 'FR'], + ['SAN', 'Sanofi', 'FR'], + ['BNP', 'BNP Paribas', 'FR'], + ['CS', 'AXA', 'FR'], + ['DG', 'Vinci', 'FR'], + ['ENEL', 'Enel', 'IT'], + ['ENI', 'Eni', 'IT'], + ['ISP', 'Intesa Sanpaolo', 'IT'], + ['UCG', 'UniCredit', 'IT'], + ['STLAM', 'Stellantis', 'IT'], + ['SAN', 'Banco Santander', 'ES'], + ['IBE', 'Iberdrola', 'ES'], + ['ITX', 'Inditex', 'ES'], + ['BBVA', 'BBVA', 'ES'], + ['NESN', 'Nestlé', 'CH'], + ['ROG', 'Roche Holding', 'CH'], + ['NOVN', 'Novartis', 'CH'], + ['UBSG', 'UBS Group', 'CH'], + ['NOVO-B', 'Novo Nordisk', 'DK'], + ['MAERSK-B', 'A.P. Moller - Maersk', 'DK'], + ['VOLV-B', 'Volvo', 'SE'], + ['ERIC-B', 'Ericsson', 'SE'], + ['NOKIA', 'Nokia', 'FI'], + ['SHEL', 'Shell', 'GB'], + ['AZN', 'AstraZeneca', 'GB'], + ['HSBA', 'HSBC Holdings', 'GB'], + ['ULVR', 'Unilever', 'GB'], + ['LSEG', 'London Stock Exchange Group', 'GB'], +]) + +const europeanMarketCodes = Object.freeze([ + 'NL', + 'DE', + 'FR', + 'IT', + 'ES', + 'CH', + 'DK', + 'SE', + 'FI', + 'GB', +]) + +const europeanMarketGroups = Object.freeze( + europeanMarketCodes.map((market) => + europeanInstruments.filter(([, , instrumentMarket]) => + Object.is(instrumentMarket, market), + ), + ), +) + +const interleavedEuropeanInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...europeanMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + europeanMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const southKoreanInstruments = Object.freeze([ + ['005930', 'Samsung Electronics', 'KR'], + ['000660', 'SK hynix', 'KR'], + ['373220', 'LG Energy Solution', 'KR'], + ['207940', 'Samsung Biologics', 'KR'], + ['005380', 'Hyundai Motor', 'KR'], + ['000270', 'Kia', 'KR'], + ['068270', 'Celltrion', 'KR'], + ['105560', 'KB Financial Group', 'KR'], + ['055550', 'Shinhan Financial Group', 'KR'], + ['035420', 'NAVER', 'KR'], + ['035720', 'Kakao', 'KR'], + ['006400', 'Samsung SDI', 'KR'], + ['051910', 'LG Chem', 'KR'], + ['012330', 'Hyundai Mobis', 'KR'], + ['066570', 'LG Electronics', 'KR'], +]) + +const japaneseInstruments = Object.freeze([ + ['8306', 'Mitsubishi UFJ Financial Group', 'JP'], + ['7203', 'Toyota Motor', 'JP'], + ['6501', 'Hitachi', 'JP'], + ['8316', 'Sumitomo Mitsui Financial Group', 'JP'], + ['6758', 'Sony Group', 'JP'], + ['8058', 'Mitsubishi Corporation', 'JP'], + ['9984', 'SoftBank Group', 'JP'], + ['8035', 'Tokyo Electron', 'JP'], + ['8411', 'Mizuho Financial Group', 'JP'], + ['8031', 'Mitsui & Co.', 'JP'], + ['6861', 'Keyence', 'JP'], + ['7974', 'Nintendo', 'JP'], + ['6098', 'Recruit Holdings', 'JP'], + ['9432', 'Nippon Telegraph and Telephone', 'JP'], + ['4063', 'Shin-Etsu Chemical', 'JP'], +]) + +const hongKongInstruments = Object.freeze([ + ['0700', 'Tencent Holdings', 'HK'], + ['9988', 'Alibaba Group', 'HK'], + ['1810', 'Xiaomi', 'HK'], + ['3690', 'Meituan', 'HK'], + ['0941', 'China Mobile', 'HK'], + ['1211', 'BYD Company', 'HK'], + ['1299', 'AIA Group', 'HK'], + ['0388', 'Hong Kong Exchanges and Clearing', 'HK'], + ['0005', 'HSBC Holdings', 'HK'], + ['2318', 'Ping An Insurance', 'HK'], +]) + +const canadianInstruments = Object.freeze([ + ['RY', 'Royal Bank of Canada', 'CA'], + ['TD', 'Toronto-Dominion Bank', 'CA'], + ['SHOP', 'Shopify', 'CA'], + ['ENB', 'Enbridge', 'CA'], + ['CNR', 'Canadian National Railway', 'CA'], + ['CP', 'Canadian Pacific Kansas City', 'CA'], + ['BMO', 'Bank of Montreal', 'CA'], + ['CSU', 'Constellation Software', 'CA'], +]) + +const australianInstruments = Object.freeze([ + ['BHP', 'BHP Group', 'AU'], + ['CBA', 'Commonwealth Bank of Australia', 'AU'], + ['CSL', 'CSL', 'AU'], + ['NAB', 'National Australia Bank', 'AU'], + ['WBC', 'Westpac Banking Corporation', 'AU'], + ['ANZ', 'ANZ Group Holdings', 'AU'], + ['WES', 'Wesfarmers', 'AU'], + ['MQG', 'Macquarie Group', 'AU'], +]) + +const internationalMarketGroups = Object.freeze([ + interleavedEuropeanInstruments, + southKoreanInstruments, + japaneseInstruments, + hongKongInstruments, + canadianInstruments, + australianInstruments, +]) + +export const internationalInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...internationalMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + internationalMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const INTERNATIONAL_INSERTION_INTERVAL = 3 + +/** + * U.S. and international instruments are interleaved so ordinary benchmark + * sizes exercise multiple symbol formats and market labels. + */ +export const globalInstruments = Object.freeze( + marketInstruments.flatMap((instrument, index) => { + const internationalInstrument = + index % INTERNATIONAL_INSERTION_INTERVAL === 0 + ? internationalInstruments[index / INTERNATIONAL_INSERTION_INTERVAL] + : undefined + + return internationalInstrument + ? [instrument, internationalInstrument] + : [instrument] + }), +) as unknown as ReadonlyArray diff --git a/examples/preact/realtime-trading/src/feed/use-market-feed-controller.ts b/examples/preact/realtime-trading/src/feed/use-market-feed-controller.ts new file mode 100644 index 0000000000..29196b8773 --- /dev/null +++ b/examples/preact/realtime-trading/src/feed/use-market-feed-controller.ts @@ -0,0 +1,10 @@ +import { useEffect, useState } from 'preact/hooks' +import { MarketFeedController } from './market-feed-controller' + +export function useMarketFeedController(): MarketFeedController { + const [controller] = useState(() => new MarketFeedController()) + + useEffect(() => controller.start(), [controller]) + + return controller +} diff --git a/examples/preact/realtime-trading/src/feed/worker/market-feed-engine.ts b/examples/preact/realtime-trading/src/feed/worker/market-feed-engine.ts new file mode 100644 index 0000000000..fbd9c369c0 --- /dev/null +++ b/examples/preact/realtime-trading/src/feed/worker/market-feed-engine.ts @@ -0,0 +1,177 @@ +import { globalInstruments } from '../market-instruments.ts' +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const INITIAL_MARKET_SEED = 0x4d41524b +const LIVE_FEED_SEED = 0x5449434b + +export class MarketFeedEngine { + #quotes: Array = [] + #lastHistorySampledAt = new Uint32Array(0) + #random = createRandom(2_026) + #rowCursor = 0 + #tickIndex = 0 + + reset(count: number): Array { + const random = createRandom(INITIAL_MARKET_SEED ^ count) + const createdAt = Date.now() + + this.#quotes = Array.from({ length: count }, (_, index) => { + const [baseSymbol, company, market] = + globalInstruments[index % globalInstruments.length] + const series = Math.floor(index / globalInstruments.length) + const symbol = series === 0 ? baseSymbol : `${baseSymbol}${series}` + const previousClose = roundPrice(20 + random() * 480) + const open = roundPrice(previousClose * (1 + (random() - 0.5) * 0.016)) + const spread = Math.max(0.01, open * (0.0002 + random() * 0.0004)) + const history = Array.from({ length: 24 }, (_, historyIndex) => + roundPrice( + open * + (1 + Math.sin(historyIndex / 4) * 0.002 + (random() - 0.5) * 0.001), + ), + ) + const volume = Math.floor(50_000 + random() * 2_000_000) + const lastSize = Math.floor(10 + random() * 5_000) + + return { + id: `instrument-${index}`, + symbol, + company, + venue: market, + previousClose, + open, + high: open, + low: open, + price: open, + bid: roundPrice(open - spread / 2), + ask: roundPrice(open + spread / 2), + bidSize: Math.floor(100 + random() * 25_000), + askSize: Math.floor(100 + random() * 25_000), + lastSize, + lastMove: 0, + lastUpdatedAt: createdAt, + volume, + turnover: roundMoney(open * volume), + history, + } + }) + + this.#random = createRandom(LIVE_FEED_SEED ^ count) + this.#rowCursor = 0 + this.#lastHistorySampledAt = new Uint32Array(count) + this.#lastHistorySampledAt.fill(createdAt >>> 0) + + return this.#quotes.map((quote) => ({ + ...quote, + history: [...quote.history], + })) + } + + applyTicks( + tickCount: number, + updateSparklines: boolean, + sparklineSampleIntervalMs: number, + ): Array { + if (this.#quotes.length === 0 || tickCount <= 0) return [] + + const updatedAt = Date.now() + const sampledAt = updatedAt >>> 0 + const sampleIntervalMs = Math.max(16, sparklineSampleIntervalMs) + const updatedQuotes = new Map() + const stride = 97 + + this.#tickIndex = 0 + while (this.#tickIndex < tickCount) { + this.#rowCursor = (this.#rowCursor + stride) % this.#quotes.length + const quote = this.#quotes[this.#rowCursor] + const lastSampledAt = this.#lastHistorySampledAt[this.#rowCursor] + const shouldUpdateHistory = + updateSparklines && + (sampledAt - lastSampledAt) >>> 0 >= sampleIntervalMs + + if (shouldUpdateHistory) { + this.#lastHistorySampledAt[this.#rowCursor] = sampledAt + } + + this.#applyTick(quote, shouldUpdateHistory, updatedAt) + + const previousUpdate = updatedQuotes.get(this.#rowCursor) + updatedQuotes.set(this.#rowCursor, { + index: this.#rowCursor, + price: quote.price, + bid: quote.bid, + ask: quote.ask, + bidSize: quote.bidSize, + askSize: quote.askSize, + lastSize: quote.lastSize, + lastMove: quote.lastMove, + lastUpdatedAt: quote.lastUpdatedAt, + high: quote.high, + low: quote.low, + volume: quote.volume, + turnover: quote.turnover, + ...(shouldUpdateHistory || previousUpdate?.history + ? { history: [...quote.history] } + : {}), + }) + this.#tickIndex++ + } + + return [...updatedQuotes.values()] + } + + #applyTick( + quote: MarketQuoteSnapshot, + updateHistory: boolean, + updatedAt: number, + ): void { + const previousPrice = quote.price + const volatility = 0.00015 + this.#random() * 0.0012 + const move = previousPrice * (this.#random() - 0.495) * volatility + const nextPrice = roundPrice(Math.max(0.1, previousPrice + move)) + const spread = Math.max( + 0.01, + nextPrice * (0.00015 + this.#random() * 0.0005), + ) + + quote.lastMove = nextPrice - previousPrice + quote.price = nextPrice + quote.high = Math.max(quote.high, nextPrice) + quote.low = Math.min(quote.low, nextPrice) + quote.bid = roundPrice(nextPrice - spread / 2) + quote.ask = roundPrice(nextPrice + spread / 2) + quote.bidSize = Math.floor(100 + this.#random() * 25_000) + quote.askSize = Math.floor(100 + this.#random() * 25_000) + quote.lastSize = Math.floor(10 + this.#random() * 5_000) + quote.lastUpdatedAt = updatedAt + quote.volume += quote.lastSize + quote.turnover = roundMoney(quote.turnover + nextPrice * quote.lastSize) + + if (updateHistory) { + quote.history = [...quote.history.slice(-23), nextPrice] + } + } +} + +function createRandom(seed: number): () => number { + const runtime = { state: seed >>> 0 } + return () => { + runtime.state += 0x6d2b79f5 + const stateValue = runtime.state + const firstMix = Math.imul(stateValue ^ (stateValue >>> 15), stateValue | 1) + const secondMix = + firstMix + Math.imul(firstMix ^ (firstMix >>> 7), firstMix | 61) + const value = firstMix ^ secondMix + return ((value ^ (value >>> 14)) >>> 0) / 4_294_967_296 + } +} + +function roundPrice(value: number): number { + return Math.round(value * 100) / 100 +} + +function roundMoney(value: number): number { + return Math.round(value * 100) / 100 +} diff --git a/examples/preact/realtime-trading/src/feed/worker/market-feed-protocol.ts b/examples/preact/realtime-trading/src/feed/worker/market-feed-protocol.ts new file mode 100644 index 0000000000..21997ec89c --- /dev/null +++ b/examples/preact/realtime-trading/src/feed/worker/market-feed-protocol.ts @@ -0,0 +1,70 @@ +export interface MarketQuoteSnapshot { + id: string + symbol: string + company: string + venue: string + previousClose: number + open: number + high: number + low: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + volume: number + turnover: number + history: Array +} + +export interface MarketQuoteUpdate { + index: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + high: number + low: number + volume: number + turnover: number + history?: Array +} + +export type MarketFeedCommand = + | { + type: 'start' + rowCount: number + running: boolean + ticksPerSecond: number + publishIntervalMs: number + updateSparklines: boolean + sparklineSampleIntervalMs: number + } + | { type: 'set-running'; running: boolean } + | { type: 'set-rate'; ticksPerSecond: number } + | { type: 'set-publish-interval'; intervalMs: number } + | { type: 'set-sparklines'; enabled: boolean } + | { type: 'set-sparkline-interval'; intervalMs: number } + | { type: 'reset'; rowCount: number } + | { type: 'burst'; tickCount: number } + +export type MarketFeedEvent = + | { + type: 'snapshot' + sessionId: number + quotes: Array + } + | { + type: 'updates' + sessionId: number + tickCount: number + coalescedUpdateCount: number + updates: Array + } diff --git a/examples/preact/realtime-trading/src/feed/worker/market-feed.worker.ts b/examples/preact/realtime-trading/src/feed/worker/market-feed.worker.ts new file mode 100644 index 0000000000..2b7a642fd9 --- /dev/null +++ b/examples/preact/realtime-trading/src/feed/worker/market-feed.worker.ts @@ -0,0 +1,143 @@ +import { initialMarketFeedConfig } from '../market-feed-config' +import { MarketFeedEngine } from './market-feed-engine' +import type { + MarketFeedCommand, + MarketFeedEvent, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const engine = new MarketFeedEngine() +const pendingUpdates = new Map() +const runtime = { + sessionId: 0, + pendingTickCount: 0, + pendingCoalescedUpdateCount: 0, + initialized: false, + running: true, + ticksPerSecond: initialMarketFeedConfig.targetSamplesPerSecond, + publishIntervalMs: initialMarketFeedConfig.publishIntervalMs, + publishTimerId: null as ReturnType | null, + updateSparklines: initialMarketFeedConfig.updateSparklines, + sparklineSampleIntervalMs: initialMarketFeedConfig.sparklineSampleIntervalMs, + tickBudget: 0, + lastTickAt: performance.now(), +} + +addEventListener('message', ({ data }: MessageEvent) => { + switch (data.type) { + case 'start': + runtime.running = data.running + runtime.ticksPerSecond = data.ticksPerSecond + runtime.publishIntervalMs = data.publishIntervalMs + runtime.updateSparklines = data.updateSparklines + runtime.sparklineSampleIntervalMs = data.sparklineSampleIntervalMs + restartPublishTimer() + reset(data.rowCount) + break + case 'set-running': + runtime.running = data.running + break + case 'set-rate': + runtime.ticksPerSecond = data.ticksPerSecond + break + case 'set-publish-interval': + runtime.publishIntervalMs = Math.max(4, data.intervalMs) + restartPublishTimer() + break + case 'set-sparklines': + runtime.updateSparklines = data.enabled + break + case 'set-sparkline-interval': + runtime.sparklineSampleIntervalMs = Math.max(16, data.intervalMs) + break + case 'reset': + reset(data.rowCount) + break + case 'burst': + produceTicks(data.tickCount) + flush() + break + } +}) + +setInterval(() => { + const now = performance.now() + const elapsed = Math.min(100, Math.max(0, now - runtime.lastTickAt)) + runtime.lastTickAt = now + + if (runtime.initialized && runtime.running) { + runtime.tickBudget += (runtime.ticksPerSecond * elapsed) / 1_000 + const tickCount = Math.floor(runtime.tickBudget) + runtime.tickBudget -= tickCount + produceTicks(tickCount) + } +}, 16) + +restartPublishTimer() + +function reset(rowCount: number): void { + runtime.initialized = true + runtime.sessionId++ + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + runtime.tickBudget = 0 + runtime.lastTickAt = performance.now() + + post({ + type: 'snapshot', + sessionId: runtime.sessionId, + quotes: engine.reset(rowCount), + }) +} + +function produceTicks(tickCount: number): void { + if (!runtime.initialized || tickCount <= 0) return + + runtime.pendingTickCount += tickCount + for (const update of engine.applyTicks( + tickCount, + runtime.updateSparklines, + runtime.sparklineSampleIntervalMs, + )) { + const previousUpdate = pendingUpdates.get(update.index) + if (previousUpdate) runtime.pendingCoalescedUpdateCount++ + pendingUpdates.set(update.index, { + ...update, + ...(update.history || !previousUpdate?.history + ? {} + : { history: previousUpdate.history }), + }) + } +} + +function flush(): void { + if (runtime.pendingTickCount === 0) return + + const message: MarketFeedEvent = { + type: 'updates', + sessionId: runtime.sessionId, + tickCount: runtime.pendingTickCount, + coalescedUpdateCount: runtime.pendingCoalescedUpdateCount, + updates: [...pendingUpdates.values()], + } + + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + post(message) +} + +function restartPublishTimer(): void { + if (runtime.publishTimerId !== null) { + clearInterval(runtime.publishTimerId) + } + runtime.publishTimerId = setInterval( + flush, + Math.max(4, runtime.publishIntervalMs), + ) +} + +function post(event: MarketFeedEvent): void { + postMessage(event) +} diff --git a/examples/preact/realtime-trading/src/index.css b/examples/preact/realtime-trading/src/index.css new file mode 100644 index 0000000000..7f670c5626 --- /dev/null +++ b/examples/preact/realtime-trading/src/index.css @@ -0,0 +1,1007 @@ +:root { + color-scheme: dark; + --font-ui: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + 'Segoe UI', sans-serif; + --font-mono: 'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace; + font-family: var(--font-ui); + font-synthesis: none; + --background: #050505; + --panel: #080808; + --panel-raised: #111111; + --panel-hover: #181818; + --surface-bar: #080808; + --surface-toolbar: #0d0d0d; + --surface-table: #050505; + --surface-header: #101010; + --surface-control: #151515; + --border: #303030; + --border-soft: #242424; + --border-strong: #4a4a4a; + --text: #e7ebf0; + --text-strong: #ffffff; + --text-inverse: #f7f9fb; + --muted: #737982; + --blue: #62a9ff; + --blue-soft: #a9d0ff; + --green: #42e488; + --red: #ff646b; + --amber: #dfb465; + --depth-bid: #315774; + --depth-ask: #634049; + --row-alt: rgb(255 255 255 / 1.8%); + --row-selected: rgb(66 132 214 / 16%); + --control-border: #354456; + --control-hover: #192431; + --sidebar-width: 18rem; + --shell-bar-height: 2.625rem; + --metrics-height: 3.5rem; + --statusbar-height: 1.625rem; + --table-header-height: 2rem; + --table-row-height: 2rem; + --shell-inline-padding: 0.75rem; + --table-cell-inline-padding: 0.6rem; + --control-radius: 1px; +} + +* { + box-sizing: border-box; +} + +html, +body { + min-width: 320px; + min-height: 100%; + margin: 0; + background: var(--background); +} + +body { + color: var(--text); +} + +button, +select, +input { + font: inherit; +} + +button, +select { + color: var(--text); + background: var(--panel-raised); + border: 1px solid var(--control-border); + border-radius: var(--control-radius); +} + +button { + padding: 0.5rem 0.65rem; + cursor: pointer; + font-size: 0.72rem; + font-weight: 650; + letter-spacing: 0.025em; +} + +button:hover { + background: var(--control-hover); + border-color: var(--border-strong); +} + +button:focus-visible, +select:focus-visible, +input:focus-visible { + outline: 1px solid var(--blue); + outline-offset: 1px; +} + +select { + width: 100%; + padding: 0.45rem 0.55rem; + font-size: 0.75rem; +} + +.trading-terminal { + --active-sidebar-width: var(--sidebar-width); + display: grid; + width: 100%; + height: 100dvh; + min-height: 0; + overflow: hidden; + background: var(--background); + grid-template-areas: + 'header sidebar' + 'content sidebar' + 'footer sidebar'; + grid-template-columns: minmax(0, 1fr) var(--active-sidebar-width); + grid-template-rows: auto minmax(0, 1fr) auto; + transition: grid-template-columns 160ms ease; +} + +.trading-terminal.is-sidebar-collapsed { + --active-sidebar-width: 0px; +} + +.shell-header { + display: flex; + min-width: 0; + flex-direction: column; + grid-area: header; +} + +.app-bar { + display: flex; + min-height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + background: var(--surface-bar); + border-bottom: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.68rem; + letter-spacing: 0.045em; +} + +.brand, +.header-actions, +.feed-status { + display: flex; + align-items: center; +} + +.brand { + gap: 0.65rem; + color: var(--text-strong); +} + +.header-actions { + gap: 0.75rem; +} + +.sidebar-toggle { + display: grid; + width: 1.9rem; + height: 1.9rem; + padding: 0; + place-items: center; + color: var(--muted); + background: transparent; + border-color: transparent; +} + +.sidebar-toggle:hover { + color: var(--text-strong); + background: var(--surface-control); + border-color: var(--border); +} + +.sidebar-toggle svg { + width: 1rem; + height: 1rem; + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-width: 1.4; +} + +.feed-status { + gap: 0.4rem; + color: var(--muted); +} + +.feed-status.is-running { + color: var(--green); +} + +.status-dot { + width: 6px; + height: 6px; + background: var(--muted); + border-radius: 50%; +} + +.feed-status.is-running .status-dot { + background: var(--green); +} + +.development-warning { + flex: 0 0 auto; + padding: 0.3rem 0.75rem; + color: var(--amber); + background: color-mix(in srgb, var(--amber) 8%, var(--background)); + border-bottom: 1px solid color-mix(in srgb, var(--amber) 24%, var(--border)); + font-family: var(--font-mono); + font-size: 0.62rem; + letter-spacing: 0.04em; +} + +.market-panel { + display: flex; + min-width: 0; + min-height: 0; + flex-direction: column; + background: var(--panel); + grid-area: content; +} + +.metrics-strip { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + background: var(--border); + border-bottom: 1px solid var(--border); + gap: 1px; +} + +.metrics-strip h2 { + margin: 0; + padding: 0.65rem var(--shell-inline-padding) 0.45rem; + color: var(--muted); + background: var(--surface-table); + font-size: 0.58rem; + grid-column: 1 / -1; + letter-spacing: 0.075em; +} + +.metrics-strip article { + min-width: 0; + min-height: 4.25rem; + padding: 0.5rem var(--shell-inline-padding); + background: var(--surface-bar); +} + +.metrics-strip span, +.metrics-strip small { + display: block; + color: var(--muted); + font-size: 0.56rem; + letter-spacing: 0.045em; + line-height: 1.35; +} + +.metrics-strip strong { + display: block; + margin: 0.12rem 0 0.08rem; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.88rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +.metrics-strip strong.metric-alert { + color: var(--amber); +} + +.table-scroll { + flex: 1; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +table { + min-width: 100%; + border-spacing: 0; + table-layout: fixed; + font-family: var(--font-ui); + font-size: 0.78rem; + font-variant-numeric: tabular-nums; +} + +.trading-data-grid { + display: grid; +} + +.trading-data-grid thead, +.trading-data-grid tbody { + display: grid; +} + +.trading-data-grid tbody { + -webkit-user-select: none; + user-select: none; +} + +.trading-data-grid thead > tr, +.trading-data-grid tbody > tr { + display: flex; + width: 100%; +} + +.trading-data-grid tbody > tr { + min-height: var(--table-row-height); + content-visibility: auto; + contain-intrinsic-block-size: var(--table-row-height); +} + +.trading-data-grid th, +.trading-data-grid td { + flex: 0 0 auto; +} + +thead { + position: sticky; + z-index: 2; + top: 0; +} + +th { + height: var(--table-header-height); + padding: 0 var(--table-cell-inline-padding); + color: var(--muted); + background: var(--surface-header); + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border); + font-size: 0.7rem; + font-weight: 500; + letter-spacing: 0.005em; + text-align: left; + white-space: nowrap; +} + +th.column-group-header { + color: #666b72; + font-size: 0.72rem; + font-weight: 500; + text-align: center; +} + +thead tr:first-child th.column-group-header { + color: #777d85; + font-size: 0.76rem; +} + +th.numeric-header { + text-align: right; +} + +td { + height: var(--table-row-height); + padding: 0 var(--table-cell-inline-padding); + overflow: hidden; + color: #eef1f5; + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border-soft); + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +th:last-child, +td:last-child { + border-right: 0; +} + +td[data-column-id='market'], +td[data-column-id='name'], +td[data-column-id='symbol'] { + text-align: left; +} + +td[data-column-id='market'] { + color: var(--blue); + font-weight: 550; +} + +td[data-column-id='name'] { + color: var(--text-strong); +} + +td[data-column-id='symbol'] { + color: #d8dde4; + font-weight: 600; +} + +tbody tr:nth-child(even) { + background: var(--row-alt); +} + +tbody tr:hover { + background: var(--panel-hover); +} + +tbody tr[data-symbol-selected='true'] { + background: var(--row-selected); + box-shadow: inset 2px 0 0 var(--blue); +} + +.table-scroll:focus { + outline: none; +} + +th { + position: relative; +} + +.leaf-header-content { + display: flex; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + height: 100%; + align-items: stretch; + margin-inline: calc(-1 * var(--table-cell-inline-padding)); +} + +.column-drag-handle, +.sort-header-button { + min-width: 0; + height: 100%; + padding: 0; + color: inherit; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-weight: inherit; + letter-spacing: inherit; +} + +.column-drag-handle { + flex: 0 0 1.05rem; + color: var(--muted); + cursor: grab; + opacity: 0.35; + font-size: 0.56rem; + letter-spacing: -0.32rem; + text-align: center; +} + +.column-drag-handle:active { + cursor: grabbing; +} + +th:hover .column-drag-handle, +.column-drag-handle:focus-visible { + opacity: 0.9; +} + +.column-drag-handle:hover, +.sort-header-button:hover { + background: rgb(255 255 255 / 4%); + border-color: transparent; +} + +th.is-column-dragging { + opacity: 0.45; +} + +th.is-column-drop-target { + background: rgb(50 139 255 / 16%); + box-shadow: inset 4px 0 0 var(--blue); +} + +th.is-column-drop-target::before { + position: absolute; + z-index: 6; + top: -1px; + bottom: -1px; + left: -2px; + width: 4px; + background: #62a9ff; + box-shadow: + 0 0 0 1px rgb(0 0 0 / 55%), + 0 0 12px rgb(70 151 255 / 90%); + content: ''; + pointer-events: none; +} + +.sort-header-button { + display: flex; + min-width: 0; + flex: 1; + align-items: center; + justify-content: flex-start; + gap: 0.3rem; + padding-inline: 0.25rem var(--table-cell-inline-padding); + cursor: default; + text-align: inherit; +} + +.numeric-header .sort-header-button { + justify-content: flex-end; +} + +.sort-header-button.is-sortable { + cursor: pointer; +} + +.sort-header-button:disabled { + opacity: 1; +} + +.header-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.sort-indicator { + flex: 0 0 auto; + color: #66717e; + font-size: 0.72rem; +} + +.sort-indicator.is-active { + color: var(--blue-soft); +} + +.column-resize-handle { + position: absolute; + z-index: 3; + top: 0; + right: -3px; + width: 7px; + height: 100%; + cursor: col-resize; + touch-action: none; + user-select: none; +} + +.column-resize-handle::after { + position: absolute; + top: 20%; + right: 3px; + width: 1px; + height: 60%; + background: var(--border-strong); + content: ''; + opacity: 0; +} + +th:hover > .column-resize-handle::after, +.column-resize-handle.is-resizing::after { + background: var(--blue); + opacity: 1; +} + +tbody tr[aria-selected='true'] { + background: rgb(76 145 228 / 13%); +} + +td[aria-selected='true'] { + position: relative; + background: rgb(70 139 222 / 12%); +} + +td[data-cell-focused='true'] { + background: rgb(70 139 222 / 21%); +} + +td[aria-selected='true']::after { + position: absolute; + z-index: 1; + inset: 0; + border: 1px solid transparent; + content: ''; + pointer-events: none; +} + +td[data-selection-top='true']::after { + border-top-color: var(--blue); +} + +td[data-selection-right='true']::after { + border-right-color: var(--blue); +} + +td[data-selection-bottom='true']::after { + border-bottom-color: var(--blue); +} + +td[data-selection-left='true']::after { + border-left-color: var(--blue); +} + +.price-button { + min-width: 4.5rem; + padding: 0; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-variant-numeric: tabular-nums; + font-weight: 600; + text-align: right; +} + +.price-button:hover { + background: transparent; + text-decoration: underline; + text-underline-offset: 2px; +} + +.move-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.move-cell.quote-up, +.percent-change-cell.quote-up { + background: color-mix(in srgb, var(--green) 7%, transparent); +} + +.move-cell.quote-down, +.percent-change-cell.quote-down { + background: color-mix(in srgb, var(--red) 7%, transparent); +} + +.percent-change-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.spread-cell { + display: flex; + align-items: baseline; + justify-content: flex-end; + gap: 0.35rem; + color: var(--text); +} + +.spread-cell small { + min-width: 2.8rem; + color: var(--muted); + font-size: 0.55rem; +} + +.spread-cell.spread-wide, +.spread-cell.spread-wide small { + color: var(--amber); +} + +.depth-cell { + position: relative; + display: flex; + height: 17px; + overflow: hidden; + background: var(--surface-control); +} + +.depth-bid, +.depth-ask { + height: 100%; + opacity: 0.78; +} + +.depth-bid { + background: var(--depth-bid); + border-right: 1px solid var(--panel); +} + +.depth-ask { + background: var(--depth-ask); +} + +.depth-values { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 0.28rem; + color: var(--text-strong); + font-size: 0.57rem; + text-shadow: 0 1px var(--background); +} + +.quote-age { + color: var(--muted); +} + +.quote-age-warm { + color: var(--amber); +} + +.quote-age-stale { + color: var(--red); +} + +.quote-up { + color: var(--green); +} + +.quote-down { + color: var(--red); +} + +.sparkline { + display: block; + width: 100%; + height: 1.35rem; + margin-left: auto; + color: var(--blue-soft); + overflow: visible; +} + +.sparkline.quote-up { + color: var(--green); +} + +.sparkline.quote-down { + color: var(--red); +} + +.sparkline polyline { + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-linejoin: miter; + stroke-width: 1.25; + vector-effect: non-scaling-stroke; +} + +.market-statusbar { + display: flex; + flex: 0 0 var(--statusbar-height); + min-height: var(--statusbar-height); + gap: 1.1rem; + align-items: center; + padding: 0 0.65rem; + color: var(--muted); + background: var(--surface-bar); + border-top: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.56rem; + grid-area: footer; + letter-spacing: 0.035em; +} + +.market-statusbar strong { + margin-left: 0.25rem; + color: var(--text); + font-weight: 500; +} + +.sidebar-slot { + width: var(--sidebar-width); + min-width: 0; + min-height: 0; + overflow: hidden; + background: var(--surface-table); + border-left: 1px solid var(--border); + grid-area: sidebar; + transition: + opacity 120ms ease, + transform 160ms ease, + visibility 160ms; +} + +.is-sidebar-collapsed .sidebar-slot { + visibility: hidden; + opacity: 0; + pointer-events: none; + transform: translateX(100%); +} + +.configurator { + width: 100%; + height: 100%; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +.configurator > header { + display: flex; + height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + color: var(--text-strong); + background: var(--surface-toolbar); + border-bottom: 1px solid var(--border); + font-size: 0.65rem; + font-weight: 700; + letter-spacing: 0.055em; +} + +.configurator > header small { + color: var(--muted); + font-size: 0.54rem; + font-weight: 500; +} + +.config-section { + display: grid; + gap: 0.7rem; + padding: 0.8rem var(--shell-inline-padding); + border-bottom: 1px solid var(--border); +} + +.config-section h2 { + margin: 0; + color: var(--muted); + font-size: 0.58rem; + letter-spacing: 0.075em; +} + +.primary-action { + width: 100%; + color: var(--text-inverse); + background: var(--blue); + border-color: var(--blue-soft); +} + +.primary-action:hover { + background: var(--blue-soft); + border-color: var(--text-strong); +} + +.field { + display: grid; + gap: 0.35rem; + color: var(--text); + font-size: 0.66rem; +} + +.rate-field > span { + display: flex; + justify-content: space-between; +} + +.rate-field strong { + color: var(--text); + font-family: var(--font-mono); + font-weight: 500; +} + +.field small { + color: var(--muted); + font-family: var(--font-mono); + font-size: 0.55rem; +} + +input[type='range'] { + width: 100%; + margin: 0; + accent-color: var(--blue); +} + +.toggle-field { + display: flex; + gap: 0.5rem; + align-items: flex-start; + color: var(--text); + font-size: 0.66rem; + line-height: 1.3; +} + +.toggle-field input { + margin: 0.12rem 0 0; + accent-color: var(--blue); +} + +.toggle-field small { + display: block; + margin-top: 0.14rem; + color: var(--muted); + font-size: 0.57rem; +} + +.action-grid { + display: grid; + grid-template-columns: 1fr; + gap: 0.4rem; +} + +.diagnostics dl, +.selected-instrument dl { + display: grid; + gap: 0; + margin: 0; +} + +.diagnostics dl > div, +.selected-instrument dl > div { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 24px; + border-bottom: 1px solid var(--border-soft); +} + +.diagnostics dl > div:last-child, +.selected-instrument dl > div:last-child { + border-bottom: 0; +} + +.diagnostics dl > div:has(dd[data-testid$='-breakdown']) { + display: grid; + grid-template-columns: minmax(0, 1fr); + align-content: center; + padding-block: 0.28rem; +} + +.diagnostics dd[data-testid$='-breakdown'] { + width: 100%; + overflow-x: auto; + padding-block: 0.12rem; + white-space: nowrap; + scrollbar-width: thin; +} + +dt { + color: var(--muted); + font-size: 0.61rem; +} + +dd { + margin: 0; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.62rem; +} + +.selection { + display: flex; + align-items: flex-start; + justify-content: space-between; +} + +.selection div { + display: grid; + gap: 0.18rem; +} + +.selection strong { + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.85rem; +} + +.selection span, +.selection small, +.selected-instrument p { + color: var(--muted); + font-size: 0.61rem; +} + +.selected-instrument p { + margin: 0; + line-height: 1.45; +} + +@media (max-width: 980px) { + :root { + --sidebar-width: 15.625rem; + } +} + +@media (max-width: 720px) { + .trading-terminal { + --active-sidebar-width: 0px; + height: 100dvh; + min-height: 0; + overflow: hidden; + } + + .market-panel { + min-height: 0; + } + + .table-scroll { + min-height: 0; + } + + .sidebar-slot { + position: fixed; + z-index: 20; + top: 0; + right: 0; + bottom: 0; + width: min(var(--sidebar-width), calc(100vw - 2.75rem)); + box-shadow: -18px 0 42px rgb(0 0 0 / 48%); + } + + .is-sidebar-collapsed .sidebar-slot { + box-shadow: none; + } +} diff --git a/examples/preact/realtime-trading/src/main.tsx b/examples/preact/realtime-trading/src/main.tsx new file mode 100644 index 0000000000..ff31652405 --- /dev/null +++ b/examples/preact/realtime-trading/src/main.tsx @@ -0,0 +1,10 @@ +import { render } from 'preact' +import { App } from './App' +import './index.css' + +const rootElement = document.getElementById('root') +if (!rootElement) throw new Error('Failed to find the root element') + +// StrictMode is intentionally omitted: its development-only mount replay would +// contaminate the component lifecycle counters used by this benchmark. +render(, rootElement) diff --git a/examples/preact/realtime-trading/src/shell/TradingShell.tsx b/examples/preact/realtime-trading/src/shell/TradingShell.tsx new file mode 100644 index 0000000000..671e467563 --- /dev/null +++ b/examples/preact/realtime-trading/src/shell/TradingShell.tsx @@ -0,0 +1,615 @@ +import { shallow, useSelector } from '@tanstack/preact-store' +import { useState } from 'preact/hooks' +import { + feedSampleRateAt, + feedSampleRateIndex, + feedSampleRateOptions, +} from '../feed/feed-sample-rates' +import { + useMarketFeedController, + useTradingShellController, + useTradingShellState, +} from './trading-shell-context' +import { configuratorOptions } from './configurator-options' +import type { ComponentChildren } from 'preact' +import type { FeedMetrics } from '../benchmark/benchmark-monitor' + +const integerFormatter = new Intl.NumberFormat('en-US', { + maximumFractionDigits: 0, +}) +const rateFormatter = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +export function TradingShell(props: { children: ComponentChildren }) { + const [sidebarOpen, setSidebarOpen] = useState(true) + const toggleSidebar = () => setSidebarOpen((open) => !open) + + return ( +
+
+ + + {import.meta.env.DEV && ( + + )} +
+ +
+ {props.children} +
+ +
{sidebarOpen && }
+
+ ) +} + +function AppHeader(props: { + sidebarOpen: boolean + onSidebarToggle: () => void +}) { + const feed = useMarketFeedController() + const workerReady = useSelector(feed.workerReady) + const running = useSelector(feed.running) + return ( +
+
+ MARKET MONITOR +
+
+ + + +
+
+ ) +} + +function MarketStatusbar() { + const { lastBatchSize, lastUpdateCount, mountedCells, liveComponents } = + useTradingShellState( + (state) => ({ + lastBatchSize: state.metrics.lastBatchSize, + lastUpdateCount: state.metrics.lastUpdateCount, + mountedCells: state.mountedCells, + liveComponents: state.liveComponents, + }), + { compare: shallow }, + ) + return ( +
+ + MESSAGE SAMPLES {formatInteger(lastBatchSize)} + + + CHANGED ROWS {formatInteger(lastUpdateCount)} + + + HOSTS {formatInteger(mountedCells)} + + + COMPONENTS {formatInteger(liveComponents)} + +
+ ) +} + +function Configurator() { + const controller = useTradingShellController() + const feed = useMarketFeedController() + const running = useSelector(feed.running) + const instrumentCount = useSelector(feed.instrumentCount) + const targetTicksPerSecond = useSelector(feed.targetTicksPerSecond) + const publishIntervalMs = useSelector(feed.publishIntervalMs) + const updateSparklines = useSelector(feed.updateSparklines) + const sparklineSampleIntervalMs = useSelector(feed.sparklineSampleIntervalMs) + const rendererMode = useSelector(controller.renderAtoms.rendererMode) + const { actions } = controller + const feedActions = feed.actions + const { setRendererMode, resetMarket } = actions + const { + toggle, + setInstrumentCount, + setTargetRate, + setPublishInterval, + setSparklineUpdates, + setSparklineSampleInterval, + runBurst, + } = feedActions + + return ( + + ) +} + +function LiveHealth() { + const { metrics, longAnimationFramesSupported } = useTradingShellState( + (state) => ({ + metrics: state.metrics, + longAnimationFramesSupported: state.longAnimationFramesSupported, + }), + { compare: shallow }, + ) + return ( +
+

LIVE HEALTH

+
+ FRAME RATE (EST.) + + {metrics.estimatedFrameRate.toFixed(1)} + + rAF callbacks/s · rolling 1 s +
+
+ AVG COMMIT + + {formatMs(metrics.averageCommitLatencyMs)} + + snapshot → DOM · rolling 3 s +
+
+ LONG FRAMES + {longAnimationFramesSupported ? ( + <> + 0 ? 'metric-alert' : ''} + > + {metrics.longAnimationFrames} + + + since reset · worst {formatMs(metrics.worstLongAnimationFrameMs)} + + + ) : ( + <> + N/A + unsupported + + )} +
+
+ THROUGHPUT + + {formatRate(metrics.rowUpdatesPerSecond)} rows/s + + + {metrics.stateApplicationsPerSecond.toFixed(1)} snapshots/s · rows + deduplicated per snapshot + +
+
+ ) +} + +function Diagnostics() { + const { + metrics, + mountedCells, + liveComponents, + longAnimationFramesSupported, + } = useTradingShellState( + (state) => ({ + metrics: state.metrics, + mountedCells: state.mountedCells, + liveComponents: state.liveComponents, + longAnimationFramesSupported: state.longAnimationFramesSupported, + }), + { compare: shallow }, + ) + return ( +
+

DIAGNOSTICS

+
+
+
Worker samples / s
+
+ {formatRate(metrics.actualTicksPerSecond)} +
+
+
+
Changed rows / s
+
+ {formatRate(metrics.rowUpdatesPerSecond)} +
+
+
+
Worker messages / s
+
+ {metrics.workerMessagesPerSecond.toFixed(1)} +
+
+
+
State applies / s
+
+ {metrics.stateApplicationsPerSecond.toFixed(1)} +
+
+
+
Table DOM commits / s
+
+ {metrics.tableCommitsPerSecond.toFixed(1)} +
+
+
+
Commit latency p95 / max
+
+ {formatMs(metrics.p95CommitLatencyMs)} /{' '} + {formatMs(metrics.maxCommitLatencyMs)} +
+
+
+
Mounted cells
+
{formatInteger(mountedCells)}
+
+
+
Live components
+
{formatInteger(liveComponents)}
+
+
+
Created / destroyed
+
+ {formatInteger(metrics.componentsCreated)} /{' '} + {formatInteger(metrics.componentsDestroyed)} +
+
+
+
Renderer callbacks / s
+
+ {formatRate(metrics.cellRendererCallsPerSecond)} +
+
+
+
Component executions / s
+
+ {formatRate(metrics.componentRenderCallsPerSecond)} +
+
+
+
Executions by component / s
+
+ {formatInvocationRates(metrics.componentRenderRates)} +
+
+
+
Callbacks by column / s
+
+ {formatInvocationRates(metrics.cellRendererRates)} +
+
+
+
Observed MutationRecords / s
+
+ {formatRate(metrics.domMutationsPerSecond)} +
+
+
+
Core row model calls / s
+
+ {metrics.rowModelCallsPerSecond.toFixed(1)} +
+
+
+
Core row model avg / max
+
+ {formatMs(metrics.rowModelAverageMs)} /{' '} + {formatMs(metrics.rowModelMaxMs)} +
+
+
+
Visible rows
+
+ {formatInteger(metrics.visibleRows)} +
+
+
+
Worker messages
+
+ {formatInteger(metrics.workerMessages)} +
+
+
+
Worker-coalesced updates / s
+
+ {formatRate(metrics.supersededUpdatesPerSecond)} +
+
+
+
Last message samples / updated rows
+
+ {formatInteger(metrics.lastBatchSize)} /{' '} + {formatInteger(metrics.lastUpdateCount)} +
+
+
+
Commits > 16.7 ms since reset
+
{metrics.slowCommits}
+
+
+
Long animation frames
+
+ {longAnimationFramesSupported + ? formatInteger(metrics.longAnimationFrames) + : 'Unsupported'} +
+
+
+
+ JS heap (GC-sensitive) +
+
+ {metrics.heapMb === null + ? 'N/A' + : `${metrics.heapMb.toFixed(1)} MB`} +
+
+
+
+ ) +} + +function SelectedInstrument() { + const controller = useTradingShellController() + const feed = useMarketFeedController() + const selectedSymbol = useSelector(controller.renderAtoms.selectedSymbol) + const quotes = useSelector(feed.quotes) + const selectedQuote = feed.getQuoteBySymbol(quotes, selectedSymbol) + return ( +
+

SELECTED INSTRUMENT

+ {selectedQuote ? ( + <> +
+
+ {selectedQuote.symbol} + {selectedQuote.company} +
+ {selectedQuote.venue} +
+
+
+
Last
+
{selectedQuote.price.toFixed(2)}
+
+
+
Bid / ask
+
+ {selectedQuote.bid.toFixed(2)} / {selectedQuote.ask.toFixed(2)} +
+
+
+ + ) : ( +

+ Click or begin a cell selection in any row to inspect its instrument. +

+ )} +
+ ) +} + +function formatInteger(value: number): string { + return integerFormatter.format(value) +} + +function formatRate(value: number): string { + return rateFormatter.format(value) +} + +function formatMs(value: number): string { + return `${value.toFixed(2)} ms` +} + +function formatInvocationRates( + rates: FeedMetrics['componentRenderRates'], +): string { + const activeRates = rates + .filter((rate) => rate.callsPerSecond > 0) + .sort((left, right) => right.callsPerSecond - left.callsPerSecond) + return activeRates.length === 0 + ? 'No calls in sample' + : activeRates + .map((rate) => `${rate.name} ${formatRate(rate.callsPerSecond)}`) + .join(' · ') +} diff --git a/examples/preact/realtime-trading/src/shell/configurator-options.ts b/examples/preact/realtime-trading/src/shell/configurator-options.ts new file mode 100644 index 0000000000..5e21d71492 --- /dev/null +++ b/examples/preact/realtime-trading/src/shell/configurator-options.ts @@ -0,0 +1,49 @@ +export interface ConfiguratorOption { + readonly label: string + readonly value: TValue +} + +const instrumentCountOptions = [ + { label: '50', value: 50 }, + { label: '100', value: 100 }, + { label: '150', value: 150 }, + { label: '250', value: 250 }, + { label: '350', value: 350 }, + { label: '500', value: 500 }, + { label: '750', value: 750 }, + { label: '1,000', value: 1_000 }, + { label: '1,500', value: 1_500 }, + { label: '2,500', value: 2_500 }, + { label: '5,000', value: 5_000 }, + { label: '1,000,000', value: 1_000_000 }, + { label: '10,000,000', value: 10_000_000 }, +] as const satisfies ReadonlyArray> + +const workerDeliveryOptions = [ + { label: '8 ms · 125 msg/s', value: 8 }, + { label: '16 ms · 62.5 msg/s', value: 16 }, + { label: '20 ms · 50 msg/s', value: 20 }, + { label: '33 ms · 30 msg/s', value: 33 }, + { label: '50 ms · 20 msg/s', value: 50 }, + { label: '100 ms · 10 msg/s', value: 100 }, + { label: '250 ms · 4 msg/s', value: 250 }, + { label: '500 ms · 2 msg/s', value: 500 }, + { label: '1,000 ms · 1 msg/s', value: 1_000 }, +] as const satisfies ReadonlyArray> + +const intradaySamplingOptions = [ + { label: '16 ms · fastest', value: 16 }, + { label: '33 ms · very fast', value: 33 }, + { label: '50 ms · fast', value: 50 }, + { label: '100 ms', value: 100 }, + { label: '250 ms', value: 250 }, + { label: '500 ms', value: 500 }, + { label: '1,000 ms', value: 1_000 }, + { label: '2,000 ms', value: 2_000 }, +] as const satisfies ReadonlyArray> + +export const configuratorOptions = { + instrumentCounts: instrumentCountOptions, + workerDeliveryIntervals: workerDeliveryOptions, + intradaySamplingIntervals: intradaySamplingOptions, +} as const diff --git a/examples/preact/realtime-trading/src/shell/trading-shell-context.tsx b/examples/preact/realtime-trading/src/shell/trading-shell-context.tsx new file mode 100644 index 0000000000..8ad0654958 --- /dev/null +++ b/examples/preact/realtime-trading/src/shell/trading-shell-context.tsx @@ -0,0 +1,50 @@ +import { createStoreContext, useSelector } from '@tanstack/preact-store' +import type { ComponentChildren } from 'preact' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { TradingBenchmarkController } from '../benchmark/use-trading-benchmark-controller' +import type { TradingBenchmarkState } from '../benchmark/trading-benchmark-controller' +import type { UseSelectorOptions } from '@tanstack/preact-store' + +const { + StoreProvider: TradingStoreProvider, + useStoreContext: useTradingShellController, +} = createStoreContext() + +const { + StoreProvider: MarketFeedStoreProvider, + useStoreContext: useMarketFeedController, +} = createStoreContext() + +export function MarketFeedProvider(props: { + controller: MarketFeedController + children: ComponentChildren +}) { + return ( + + {props.children} + + ) +} + +export function TradingShellProvider(props: { + controller: TradingBenchmarkController + children: ComponentChildren +}) { + return ( + + + {props.children} + + + ) +} + +export { useMarketFeedController, useTradingShellController } + +export function useTradingShellState( + selector: (state: TradingBenchmarkState) => TSelected, + options?: UseSelectorOptions, +): TSelected { + const controller = useTradingShellController() + return useSelector(controller.store, selector, options) +} diff --git a/examples/preact/realtime-trading/src/table/table-config/quote-cells.tsx b/examples/preact/realtime-trading/src/table/table-config/quote-cells.tsx new file mode 100644 index 0000000000..05c16e9578 --- /dev/null +++ b/examples/preact/realtime-trading/src/table/table-config/quote-cells.tsx @@ -0,0 +1,219 @@ +import { useEffect } from 'preact/hooks' + +const compactNumber = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) + +export const quoteCellLifecycle = { + created: 0, + destroyed: 0, +} + +export const quoteCellRendererNames = [ + 'Market', + 'Name', + 'Symbol', + 'Last', + 'Change', + 'ChangePercent', + 'Bid', + 'BidVolume', + 'Ask', + 'AskVolume', + 'Open', + 'High', + 'Low', + 'Intraday', +] as const + +export const quoteComponentNames = [ + 'PriceCell', + 'StableMoveCell', + 'UpMoveCell', + 'DownMoveCell', + 'PercentChangeCell', + 'SpreadCell', + 'DepthCell', + 'QuoteAgeCell', + 'SparklineCell', +] as const + +export type QuoteCellRendererName = (typeof quoteCellRendererNames)[number] +export type QuoteComponentName = (typeof quoteComponentNames)[number] + +const createCounterMap = ( + names: ReadonlyArray, +): Record => + Object.fromEntries(names.map((name) => [name, 0])) as Record + +export const quoteRenderDiagnostics = { + cellRendererCalls: 0, + componentRenderCalls: 0, + cellRendererCallsByName: createCounterMap(quoteCellRendererNames), + componentRenderCallsByName: createCounterMap(quoteComponentNames), +} + +export function recordCellRender(name: QuoteCellRendererName, value: T): T { + 'use no memo' + // Benchmark instrumentation is intentionally impure and must run per call. + quoteRenderDiagnostics.cellRendererCalls++ + quoteRenderDiagnostics.cellRendererCallsByName[name]++ + return value +} + +function useLifecycleCounter(componentName: QuoteComponentName): void { + 'use no memo' + // This diagnostic mutation measures component-function invocation itself. + quoteRenderDiagnostics.componentRenderCalls++ + quoteRenderDiagnostics.componentRenderCallsByName[componentName]++ + useEffect(() => { + quoteCellLifecycle.created++ + return () => { + quoteCellLifecycle.destroyed++ + } + }, []) +} + +export function PriceCell(props: { + price: number + move: number + onSelect: () => void +}) { + useLifecycleCounter('PriceCell') + return ( + + ) +} + +export function StableMoveCell({ move }: { move: number }) { + useLifecycleCounter('StableMoveCell') + return ( + = 0 ? 'quote-up' : 'quote-down'}`}> + {formatSigned(move)} + + ) +} + +export function UpMoveCell({ move }: { move: number }) { + useLifecycleCounter('UpMoveCell') + return ▲ {formatSigned(move)} +} + +export function DownMoveCell({ move }: { move: number }) { + useLifecycleCounter('DownMoveCell') + return ▼ {formatSigned(move)} +} + +export function PercentChangeCell({ value }: { value: number }) { + useLifecycleCounter('PercentChangeCell') + return ( + = 0 ? 'quote-up' : 'quote-down'}`} + > + {value >= 0 ? '+' : ''} + {value.toFixed(2)}% + + ) +} + +export function SpreadCell({ bid, ask }: { bid: number; ask: number }) { + useLifecycleCounter('SpreadCell') + const spread = Math.max(0, ask - bid) + const midpoint = (bid + ask) / 2 + const basisPoints = midpoint === 0 ? 0 : (spread / midpoint) * 10_000 + + return ( + = 4 ? 'spread-wide' : ''}`}> + {spread.toFixed(2)} + {basisPoints.toFixed(1)} bp + + ) +} + +export function DepthCell(props: { bidSize: number; askSize: number }) { + useLifecycleCounter('DepthCell') + const total = props.bidSize + props.askSize + const bidShare = total === 0 ? 50 : (props.bidSize / total) * 100 + + return ( +
+ + + + {compactNumber.format(props.bidSize)} + {compactNumber.format(props.askSize)} + +
+ ) +} + +export function QuoteAgeCell({ ageMs }: { ageMs: number }) { + useLifecycleCounter('QuoteAgeCell') + const className = + ageMs >= 1_500 + ? 'quote-age quote-age-stale' + : ageMs >= 500 + ? 'quote-age quote-age-warm' + : 'quote-age' + + return ( + + {ageMs < 1_000 + ? `${Math.round(ageMs)} ms` + : `${(ageMs / 1_000).toFixed(1)} s`} + + ) +} + +export function SparklineCell({ values }: { values: ReadonlyArray }) { + useLifecycleCounter('SparklineCell') + const rising = (values.at(-1) ?? 0) >= (values[0] ?? 0) + const { min, max } = findRange(values) + const range = max - min || 1 + const denominator = Math.max(1, values.length - 1) + const points = values + .map((value, index) => { + const x = (index / denominator) * 100 + const y = 22 - ((value - min) / range) * 20 + return `${x.toFixed(1)},${y.toFixed(1)}` + }) + .join(' ') + + return ( + + + + ) +} + +function formatSigned(value: number): string { + return `${value >= 0 ? '+' : ''}${value.toFixed(2)}` +} + +function findRange(values: ReadonlyArray): { + min: number + max: number +} { + const first = values[0] ?? 0 + return values.reduce( + (range, value) => { + range.min = Math.min(range.min, value) + range.max = Math.max(range.max, value) + return range + }, + { min: first, max: first }, + ) +} diff --git a/examples/preact/realtime-trading/src/table/table-config/trading-table-config.tsx b/examples/preact/realtime-trading/src/table/table-config/trading-table-config.tsx new file mode 100644 index 0000000000..f8b23abd0f --- /dev/null +++ b/examples/preact/realtime-trading/src/table/table-config/trading-table-config.tsx @@ -0,0 +1,259 @@ +import { createColumnHelper } from '@tanstack/preact-table' +import { useSelector } from '@tanstack/preact-store' +import { useTradingShellController } from '../../shell/trading-shell-context' +import { tradingFeatures } from '../trading-features' +import { + DownMoveCell, + PercentChangeCell, + PriceCell, + SparklineCell, + StableMoveCell, + UpMoveCell, + recordCellRender, +} from './quote-cells' +import type { ComponentChildren } from 'preact' +import type { MarketQuote } from '../../feed/market-data' + +export type RendererMode = 'stable' | 'swap' +export interface CoreTableState { + sorting: Array<{ id: string; desc: boolean }> + columnFilters: Array<{ id: string; value: unknown }> +} + +const compactFormatter = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +const columnHelper = createColumnHelper() + +export const tradingColumns = columnHelper.columns([ + columnHelper.group({ + id: 'instrument', + header: 'Instrument', + columns: columnHelper.columns([ + columnHelper.accessor('venue', { + id: 'market', + header: 'Market', + size: 72, + cell: (info) => recordCellRender('Market', info.getValue()), + }), + columnHelper.accessor('company', { + id: 'name', + header: 'Name', + size: 180, + cell: (info) => recordCellRender('Name', info.getValue()), + }), + columnHelper.accessor('symbol', { + header: 'Symbol', + size: 92, + filterFn: 'includesString', + cell: (info) => recordCellRender('Symbol', info.getValue()), + }), + ]), + }), + columnHelper.group({ + id: 'priceAndChange', + header: 'Price & Change', + columns: columnHelper.columns([ + columnHelper.accessor('price', { + header: 'Price', + size: 96, + sortFn: 'basic', + cell: (info) => + recordCellRender('Last', ), + }), + columnHelper.accessor((row) => getDayChange(row), { + id: 'change', + header: 'Chg', + size: 94, + cell: (info) => + recordCellRender( + 'Change', + , + ), + }), + columnHelper.accessor((row) => getDayChangePercent(row), { + id: 'changePercent', + header: 'Chg%', + size: 90, + cell: (info) => + recordCellRender( + 'ChangePercent', + , + ), + }), + ]), + }), + columnHelper.group({ + id: 'orderBook', + header: 'Order Book', + columns: columnHelper.columns([ + columnHelper.accessor('bid', { + header: 'Bid', + size: 90, + cell: (info) => recordCellRender('Bid', info.getValue().toFixed(2)), + }), + columnHelper.accessor('bidSize', { + header: 'Bid Vol', + size: 100, + cell: (info) => + recordCellRender( + 'BidVolume', + compactFormatter.format(info.getValue()), + ), + }), + columnHelper.accessor('ask', { + header: 'Ask', + size: 90, + cell: (info) => recordCellRender('Ask', info.getValue().toFixed(2)), + }), + columnHelper.accessor('askSize', { + header: 'Ask Vol', + size: 100, + cell: (info) => + recordCellRender( + 'AskVolume', + compactFormatter.format(info.getValue()), + ), + }), + ]), + }), + columnHelper.group({ + id: 'session', + header: 'Session', + columns: columnHelper.columns([ + columnHelper.accessor('open', { + header: 'Open', + size: 90, + cell: (info) => recordCellRender('Open', info.getValue().toFixed(2)), + }), + columnHelper.accessor('high', { + header: 'High', + size: 90, + cell: (info) => recordCellRender('High', info.getValue().toFixed(2)), + }), + columnHelper.accessor('low', { + header: 'Low', + size: 90, + cell: (info) => recordCellRender('Low', info.getValue().toFixed(2)), + }), + ]), + }), + columnHelper.group({ + id: 'chart', + header: 'Chart', + columns: columnHelper.columns([ + columnHelper.accessor('history', { + header: 'Intraday', + size: 150, + enableSorting: false, + cell: (info) => + recordCellRender( + 'Intraday', + , + ), + }), + ]), + }), +]) + +export const rowModelDiagnostics = { + hasMeasurement: false, + calls: 0, + totalDurationMs: 0, + maxDurationMs: 0, + lastRowCount: 0, +} + +export const TRADING_COLUMN_COUNT = 14 + +export function readMeasuredRows(readRows: () => Array): Array { + const start = performance.now() + const rows = readRows() + const end = performance.now() + const duration = end - start + + rowModelDiagnostics.calls++ + rowModelDiagnostics.hasMeasurement = true + rowModelDiagnostics.totalDurationMs += duration + rowModelDiagnostics.maxDurationMs = Math.max( + rowModelDiagnostics.maxDurationMs, + duration, + ) + rowModelDiagnostics.lastRowCount = rows.length + + if (rowModelDiagnostics.calls % 1_000 === 0) { + performance.clearMeasures('tanstack-row-model') + } + if ((rowModelDiagnostics.calls - 1) % 20 === 0) { + try { + performance.measure('tanstack-row-model', { + start, + end, + detail: { rowCount: rows.length }, + }) + } catch { + // User Timing Level 3 detail is not implemented in every browser. + } + } + + return rows +} + +function LastPriceCell(props: { quote: MarketQuote }) { + const { selectSymbol } = useTradingShellController().actions + return ( + selectSymbol(props.quote.symbol)} + /> + ) +} + +function DayChangeCell(props: { quote: MarketQuote }) { + const { rendererMode } = useTradingShellController().renderAtoms + const mode = useSelector(rendererMode) + const change = getDayChange(props.quote) + if (mode === 'stable') { + return + } + return change >= 0 ? ( + + ) : ( + + ) +} + +export function TradingRow(props: { + quote: MarketQuote + children: ComponentChildren + rowSelected: boolean +}) { + const { selectedSymbol } = useTradingShellController().renderAtoms + const selected = useSelector( + selectedSymbol, + (symbol) => symbol === props.quote.symbol, + ) + return ( + + {props.children} + + ) +} + +function getDayChange(quote: MarketQuote): number { + return quote.price - quote.previousClose +} + +function getDayChangePercent(quote: MarketQuote): number { + return quote.previousClose === 0 + ? 0 + : (getDayChange(quote) / quote.previousClose) * 100 +} diff --git a/examples/preact/realtime-trading/src/table/table-interactions.ts b/examples/preact/realtime-trading/src/table/table-interactions.ts new file mode 100644 index 0000000000..5b20a5b795 --- /dev/null +++ b/examples/preact/realtime-trading/src/table/table-interactions.ts @@ -0,0 +1,190 @@ +import type { JSX } from 'preact' + +export type CellDirection = 'up' | 'down' | 'left' | 'right' + +interface RowSelectionTable { + resetRowSelection: (defaultState?: boolean) => void +} + +interface SelectableRow { + getIsSelected: () => boolean + getToggleSelectedHandler: (options?: { + selectChildren?: boolean + }) => (event: unknown) => void +} + +interface SelectableGridCell { + row: SelectableGridRow + getSelectionStartHandler: ( + contextDocument?: Document, + ) => (event: unknown) => void + getSelectionExtendHandler: () => (event: unknown) => void +} + +interface SelectableGridRow extends SelectableRow { + original: { symbol: string } + getAllCellsByColumnId: () => Record +} + +interface TradingGridTable extends RowSelectionTable { + getRowModel: () => { + rowsById: Record + } +} + +interface SelectionCellTarget { + element: HTMLTableCellElement + cell: SelectableGridCell +} + +interface CellNavigationTable { + extendCellSelection: (direction: CellDirection) => void + moveCellSelection: (direction: CellDirection) => void + resetCellSelection: (defaultState?: boolean) => void + selectAllCells: () => void +} + +const keyDirections: Partial> = { + ArrowUp: 'up', + ArrowDown: 'down', + ArrowLeft: 'left', + ArrowRight: 'right', +} + +export function reorderColumnIds( + columnIds: Array, + sourceId: string, + targetId: string, +): Array { + if (sourceId === targetId || !columnIds.includes(sourceId)) return columnIds + + const withoutSource = columnIds.filter((id) => id !== sourceId) + const targetIndex = withoutSource.indexOf(targetId) + if (targetIndex < 0) return columnIds + + return [ + ...withoutSource.slice(0, targetIndex), + sourceId, + ...withoutSource.slice(targetIndex), + ] +} + +export function selectRowFromPointer( + table: RowSelectionTable, + row: SelectableRow, + event: MouseEvent, +): void { + const additive = event.ctrlKey || event.metaKey + const checked = additive ? !row.getIsSelected() : true + + if (!event.shiftKey && !additive) table.resetRowSelection(true) + + row.getToggleSelectedHandler({ selectChildren: false })({ + target: { checked }, + shiftKey: event.shiftKey, + ctrlKey: event.ctrlKey, + metaKey: event.metaKey, + nativeEvent: event, + }) +} + +export class TradingGridPointerController { + #lastPointerCell: HTMLTableCellElement | null = null + + handleMouseDown( + table: TradingGridTable, + event: MouseEvent, + selectSymbol: (symbol: string) => void, + ): void { + if (event.button !== 0) return + + const target = this.#findCellTarget(table, event.composedPath()) + if (!target) return + + event.preventDefault() + this.#lastPointerCell = target.element + selectSymbol(target.cell.row.original.symbol) + target.cell.getSelectionStartHandler(target.element.ownerDocument)(event) + } + + handlePointerOver(table: TradingGridTable, event: MouseEvent): void { + if ((event.buttons & 1) === 0) { + this.resetPointerCell() + return + } + + const target = this.#findCellTarget(table, event.composedPath()) + if (!target || target.element === this.#lastPointerCell) return + + this.#lastPointerCell = target.element + target.cell.getSelectionExtendHandler()(event) + } + + handleClick(table: TradingGridTable, event: MouseEvent): void { + const target = this.#findCellTarget(table, event.composedPath()) + if (!target) return + selectRowFromPointer(table, target.cell.row, event) + } + + resetPointerCell(): void { + this.#lastPointerCell = null + } + + #findCellTarget( + table: TradingGridTable, + path: Array, + ): SelectionCellTarget | null { + for (const target of path) { + if (!(target instanceof HTMLTableCellElement)) continue + + const columnId = target.dataset['columnId'] + const rowId = + target.closest('tr[data-row-id]')?.dataset['rowId'] + if (!columnId || !rowId) return null + + const row = table.getRowModel().rowsById[rowId] + const cell = row.getAllCellsByColumnId()[columnId] + return { element: target, cell } + } + + return null + } +} + +export function handleCellNavigation( + table: CellNavigationTable, + event: JSX.TargetedKeyboardEvent, +): void { + if (event.key === 'Escape') { + event.preventDefault() + table.resetCellSelection(true) + return + } + + if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'a') { + event.preventDefault() + table.selectAllCells() + return + } + + const direction = keyDirections[event.key] + if (!direction) return + + event.preventDefault() + if (event.shiftKey) table.extendCellSelection(direction) + else table.moveCellSelection(direction) +} + +export function sortIndicator(direction: false | 'asc' | 'desc'): string { + if (direction === 'asc') return '↑' + if (direction === 'desc') return '↓' + return '↕' +} + +export function sortAriaValue( + direction: false | 'asc' | 'desc', +): JSX.AriaAttributes['aria-sort'] { + if (direction === 'asc') return 'ascending' + if (direction === 'desc') return 'descending' + return 'none' +} diff --git a/examples/preact/realtime-trading/src/table/trading-features.ts b/examples/preact/realtime-trading/src/table/trading-features.ts new file mode 100644 index 0000000000..c31972ec47 --- /dev/null +++ b/examples/preact/realtime-trading/src/table/trading-features.ts @@ -0,0 +1,16 @@ +import { + createFilteredRowModel, + createSortedRowModel, + filterFn_includesString, + sortFn_basic, + stockFeatures, + tableFeatures, +} from '@tanstack/preact-table' + +export const tradingFeatures = tableFeatures({ + ...stockFeatures, + filteredRowModel: createFilteredRowModel(), + sortedRowModel: createSortedRowModel(), + filterFns: { includesString: filterFn_includesString }, + sortFns: { basic: sortFn_basic }, +}) diff --git a/examples/preact/realtime-trading/src/table/trading-table.tsx b/examples/preact/realtime-trading/src/table/trading-table.tsx new file mode 100644 index 0000000000..65f23f642a --- /dev/null +++ b/examples/preact/realtime-trading/src/table/trading-table.tsx @@ -0,0 +1,491 @@ +import { FlexRender, useTable } from '@tanstack/preact-table' +import { useSelector } from '@tanstack/preact-store' +import { useLayoutEffect, useRef, useState } from 'preact/hooks' +import { useTableBenchmark } from '../benchmark/use-table-benchmark' +import { + useMarketFeedController, + useTradingShellController, +} from '../shell/trading-shell-context' +import { + TradingRow, + readMeasuredRows, + tradingColumns, +} from './table-config/trading-table-config' +import { tradingFeatures } from './trading-features' +import { + TradingGridPointerController, + handleCellNavigation, + reorderColumnIds, + sortAriaValue, + sortIndicator, +} from './table-interactions' +import type { + CellSelectionBounds, + CellSelectionState, +} from '@tanstack/preact-table' +import type { MarketQuote } from '../feed/market-data' +import type { CoreTableState } from './table-config/trading-table-config' + +export { + TRADING_COLUMN_COUNT, + rowModelDiagnostics, +} from './table-config/trading-table-config' +export type { + CoreTableState, + RendererMode, +} from './table-config/trading-table-config' + +export function TradingTable() { + const controller = useTradingShellController() + const feed = useMarketFeedController() + const quotes = useSelector(feed.quotes) + + useLayoutEffect(() => feed.completeRender()) + useTableBenchmark(controller) + const table = useTradingTable({ quotes }) + const layoutRefs = useTradingTableLayout(table) + + return ( + ({ + sorting: state.sorting, + columnFilters: state.columnFilters, + columnOrder: state.columnOrder, + })} + > + {(coreState) => ( + + )} + + ) +} + +type TradingTableInstance = ReturnType + +interface ColumnDragRuntime { + columnId: string | null + sourceElement: HTMLTableCellElement | null + targetElement: HTMLTableCellElement | null +} + +function clearColumnDrag(runtime: ColumnDragRuntime): void { + runtime.sourceElement?.classList.remove('is-column-dragging') + runtime.targetElement?.classList.remove('is-column-drop-target') + runtime.columnId = null + runtime.sourceElement = null + runtime.targetElement = null +} + +function showColumnDropTarget( + runtime: ColumnDragRuntime, + targetColumnId: string, + targetElement: HTMLTableCellElement | null, +): void { + runtime.targetElement?.classList.remove('is-column-drop-target') + runtime.targetElement = null + if (runtime.columnId === targetColumnId || !targetElement) return + targetElement.classList.add('is-column-drop-target') + runtime.targetElement = targetElement +} + +function useTradingTableLayout(table: TradingTableInstance) { + const scrollRef = useRef(null) + const tableRef = useRef(null) + const fitRuntime = useRef({ manuallyResized: false }) + const tableRuntime = useRef(table) + tableRuntime.current = table + + useLayoutEffect(() => { + const writeColumnSizes = () => { + const currentTable = tableRuntime.current + const tableElement = tableRef.current + if (!tableElement) return + for (const header of currentTable.getFlatHeaders()) { + tableElement.style.setProperty( + `--header-${header.id}-size`, + String(header.getSize()), + ) + tableElement.style.setProperty( + `--col-${header.column.id}-size`, + String(header.column.getSize()), + ) + } + tableElement.style.width = `${currentTable.getTotalSize()}px` + } + + writeColumnSizes() + const sizingSubscription = + tableRuntime.current.atoms.columnSizing.subscribe(writeColumnSizes) + const orderSubscription = + tableRuntime.current.atoms.columnOrder.subscribe(writeColumnSizes) + const fitAvailableWidth = () => { + const currentTable = tableRuntime.current + const scrollElement = scrollRef.current + if (!scrollElement || fitRuntime.current.manuallyResized) return + const currentWidth = currentTable.getTotalSize() + const availableWidth = scrollElement.clientWidth + if (availableWidth <= currentWidth + 1 || currentWidth <= 0) return + + const ratio = availableWidth / currentWidth + currentTable.setColumnSizing( + Object.fromEntries( + currentTable + .getVisibleLeafColumns() + .map((column) => [column.id, column.getSize() * ratio]), + ), + ) + } + const resizeObserver = new ResizeObserver(fitAvailableWidth) + const resizingSubscription = + tableRuntime.current.atoms.columnResizing.subscribe((state) => { + if (state.isResizingColumn !== false) { + fitRuntime.current.manuallyResized = true + } + }) + if (scrollRef.current) resizeObserver.observe(scrollRef.current) + fitAvailableWidth() + + return () => { + sizingSubscription.unsubscribe() + orderSubscription.unsubscribe() + resizingSubscription.unsubscribe() + resizeObserver.disconnect() + } + }, []) + + return { scrollRef, tableRef } +} + +function TradingTableHeader(props: { table: TradingTableInstance }) { + const dragRuntime = useRef({ + columnId: null, + sourceElement: null, + targetElement: null, + }) + + return ( + ({ + columnOrder: state.columnOrder, + sorting: state.sorting, + })} + > + {() => ( + + {props.table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + const isLeaf = header.subHeaders.length === 0 + const sorted = header.column.getIsSorted() + return ( + + {!header.isPlaceholder && + (isLeaf ? ( + <> +
{ + event.preventDefault() + showColumnDropTarget( + dragRuntime.current, + header.column.id, + event.currentTarget.closest('th'), + ) + }} + onDrop={(event) => { + event.preventDefault() + const dataTransfer = event.dataTransfer + const sourceId = + dataTransfer?.getData('text/plain') || + dragRuntime.current.columnId + if (sourceId) { + props.table.setColumnOrder( + reorderColumnIds( + props.table + .getVisibleLeafColumns() + .map((column) => column.id), + sourceId, + header.column.id, + ), + ) + } + clearColumnDrag(dragRuntime.current) + }} + > + + +
+ {header.column.getCanResize() && ( + + state.columnResizing.isResizingColumn === + header.column.id + } + > + {(isResizing) => ( +
header.column.resetSize()} + onMouseDown={header.getResizeHandler()} + onTouchStart={header.getResizeHandler()} + /> + )} + + )} + + ) : ( + + ))} + + ) + })} + + ))} + + )} + + ) +} + +function useTradingTable(props: { quotes: Array }) { + return useTable( + { + key: 'preact-realtime-trading', + features: tradingFeatures, + columns: tradingColumns, + data: props.quotes, + getRowId: (row) => row.id, + columnResizeMode: 'onChange', + defaultColumn: { minSize: 56, maxSize: 800 }, + autoResetCellSelection: false, + }, + () => null, + ) +} + +function TradingTableViewport(props: { + table: ReturnType + rows: ReturnType['getRowModel']>['rows'] + sourceRowCount: number + layoutRefs: ReturnType + reportRenderedRowCount: (count: number) => void +}) { + const renderedRowCount = props.rows.length + + useLayoutEffect(() => { + props.reportRenderedRowCount(renderedRowCount) + }, [props.reportRenderedRowCount, renderedRowCount]) + + return ( +
handleCellNavigation(props.table, event)} + > + + + +
+
+ ) +} + +function TradingRows(props: { + table: ReturnType + rows: ReturnType['getRowModel']>['rows'] + sourceRowCount: number +}) { + const { selectSymbol } = useTradingShellController().actions + const [pointerInteractions] = useState( + () => new TradingGridPointerController(), + ) + + return ( + + pointerInteractions.handleMouseDown(props.table, event, selectSymbol) + } + onPointerOver={(event) => + pointerInteractions.handlePointerOver(props.table, event) + } + onMouseLeave={() => pointerInteractions.resetPointerCell()} + onClick={(event) => pointerInteractions.handleClick(props.table, event)} + > + {props.rows.map((row) => ( + + ))} + + ) +} + +type TradingTableRow = ReturnType< + ReturnType['getRowModel'] +>['rows'][number] + +function TradingRowBoundary(props: { + table: ReturnType + row: TradingTableRow +}) { + const { row, table } = props + + return ( + + `${row.id in state.rowSelection ? 1 : 0}:${cellSelectionRowKey( + state.cellSelection, + table.getCellSelectionBounds(), + row.getDisplayIndex(), + row.id, + )}` + } + > + {() => ( + + {row.getVisibleCells().map((cell) => { + const edges = cell.getSelectionEdges() + + return ( + + + + ) + })} + + )} + + ) +} + +function getHeaderClassName(header: { + subHeaders: ReadonlyArray + column: { id: string } +}): string | undefined { + if (header.subHeaders.length > 0) return 'column-group-header' + return isTextColumn(header.column.id) ? undefined : 'numeric-header' +} + +function isTextColumn(columnId: string): boolean { + return columnId === 'market' || columnId === 'name' || columnId === 'symbol' +} + +function readRows( + table: ReturnType, + quoteSnapshot: Array, + coreState: CoreTableState, +) { + void quoteSnapshot + void coreState + return readMeasuredRows(() => table.getRowModel().rows) +} + +function cellSelectionRowKey( + ranges: CellSelectionState, + bounds: Array, + rowIndex: number, + rowId: string, +): string { + const active = ranges.at(-1) + const initial = + active?.anchorRowId === rowId ? `f${active.anchorColumnId}` : '' + + return bounds.reduce((key, bound) => { + const self = rowIndex >= bound.minRowIndex && rowIndex <= bound.maxRowIndex + const above = + rowIndex - 1 >= bound.minRowIndex && rowIndex - 1 <= bound.maxRowIndex + const below = + rowIndex + 1 >= bound.minRowIndex && rowIndex + 1 <= bound.maxRowIndex + if (!self && !above && !below) return key + return `${key}|${self ? 1 : 0}${above ? 1 : 0}${below ? 1 : 0}:${bound.minColumnIndex}-${bound.maxColumnIndex}` + }, initial) +} diff --git a/examples/preact/realtime-trading/src/vite-env.d.ts b/examples/preact/realtime-trading/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/preact/realtime-trading/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/preact/realtime-trading/tests/e2e/smoke.spec.ts b/examples/preact/realtime-trading/tests/e2e/smoke.spec.ts new file mode 100644 index 0000000000..49789a8140 --- /dev/null +++ b/examples/preact/realtime-trading/tests/e2e/smoke.spec.ts @@ -0,0 +1,94 @@ +import path from 'node:path' +import { expect, test } from '@playwright/test' +import { startExampleServer } from '../../../../../tests/e2e/helpers/startExampleServer' +import { + setRangeValue, + pausedFeedUrl, +} from '../../../../../tests/e2e/helpers/setRangeValue' +import type { Page } from '@playwright/test' + +const exampleDir = path.resolve() + +function collectPageErrors(page: Page) { + const errors: Array = [] + page.on('pageerror', (error) => errors.push(error.message)) + page.on('console', (message) => { + if (message.type() === 'error') errors.push(message.text()) + }) + return errors +} + +test('runs the Preact realtime trading workload', async ({ page }) => { + const server = await startExampleServer(exampleDir) + const errors = collectPageErrors(page) + + try { + await page.goto(pausedFeedUrl(server.url)) + + const table = page.getByTestId('trading-table') + const instrumentCount = page.getByTestId('instrument-count-select') + await expect(table).toBeVisible() + await expect(instrumentCount).toHaveValue('100') + await expect(page.locator('.brand')).toHaveText('MARKET MONITOR') + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(table.locator('tbody')).toHaveCSS('user-select', 'none') + await expect(table.locator('tbody tr').first()).toHaveCSS( + 'content-visibility', + 'auto', + ) + await expect(table.locator('thead tr')).toHaveCount(2) + await expect(table.locator('thead tr').last().locator('th')).toHaveCount(14) + await expect(table.locator('thead')).not.toContainText('Identity') + await expect(table.locator('thead')).not.toContainText('Market Data') + await expect(table.locator('thead')).toContainText('Market') + await expect(table.locator('thead')).toContainText('Bid Vol') + await expect(table.locator('thead')).toContainText('Intraday') + const selectedRow = table.locator('tbody tr').first() + const selectedSymbol = await selectedRow.getAttribute('data-symbol') + await selectedRow.locator('td').nth(1).click() + await expect(page.getByTestId('selected-instrument')).toContainText( + selectedSymbol ?? '', + ) + await expect(page.getByTestId('feed-status')).toHaveText('FEED PAUSED') + await expect(instrumentCount.locator('option[value="150"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="350"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="750"]')).toHaveCount(1) + + const targetRateSlider = page.getByTestId('target-rate-slider') + await expect(targetRateSlider).toHaveAttribute('min', '0') + await expect(targetRateSlider).toHaveAttribute('max', '9') + await expect(targetRateSlider).toHaveAttribute('step', '1') + await expect(targetRateSlider).toHaveValue('6') + await setRangeValue(targetRateSlider, '7') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '25K samples/s', + ) + await setRangeValue(targetRateSlider, '8') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '50K samples/s', + ) + await setRangeValue(targetRateSlider, '6') + + const sparklineInterval = page.getByTestId( + 'sparkline-sample-interval-select', + ) + await expect(sparklineInterval).toHaveValue('16') + await sparklineInterval.selectOption('100') + await expect(sparklineInterval).toHaveValue('100') + await sparklineInterval.selectOption('16') + + const publishInterval = page.getByTestId('publish-interval-select') + await expect(publishInterval.locator('option[value="500"]')).toHaveCount(1) + await expect(publishInterval.locator('option[value="1000"]')).toHaveCount(1) + + expect( + await page.evaluate( + () => performance.getEntriesByName('tanstack-row-model').length > 0, + ), + ).toBe(true) + + expect(errors).toEqual([]) + } finally { + await server.close() + } +}) diff --git a/examples/preact/realtime-trading/tsconfig.json b/examples/preact/realtime-trading/tsconfig.json new file mode 100644 index 0000000000..2172bff227 --- /dev/null +++ b/examples/preact/realtime-trading/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src", "tests/e2e", "vite.config.ts"] +} diff --git a/examples/preact/realtime-trading/vite.config.ts b/examples/preact/realtime-trading/vite.config.ts new file mode 100644 index 0000000000..e208c56eb2 --- /dev/null +++ b/examples/preact/realtime-trading/vite.config.ts @@ -0,0 +1,10 @@ +import preact from '@preact/preset-vite' +import { defineConfig } from 'vite' + +export default defineConfig({ + server: { + port: 7777, + allowedHosts: true, + }, + plugins: [preact()], +}) diff --git a/examples/preact/row-pinning/package.json b/examples/preact/row-pinning/package.json index 2a32e3a4d6..43faf4e204 100644 --- a/examples/preact/row-pinning/package.json +++ b/examples/preact/row-pinning/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/row-selection/package.json b/examples/preact/row-selection/package.json index a73d1d2f18..19defe15cc 100644 --- a/examples/preact/row-selection/package.json +++ b/examples/preact/row-selection/package.json @@ -12,8 +12,8 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/preact-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/preact-devtools": "^0.10.12", "@tanstack/preact-store": "^0.13.2", "@tanstack/preact-table": "^9.2.3", "@tanstack/preact-table-devtools": "^9.2.0", @@ -21,7 +21,8 @@ }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/sorting/package.json b/examples/preact/sorting/package.json index 62626dfb1b..43a2fcdda4 100644 --- a/examples/preact/sorting/package.json +++ b/examples/preact/sorting/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/sub-components/package.json b/examples/preact/sub-components/package.json index 6ab08ac9db..c32fcf6bac 100644 --- a/examples/preact/sub-components/package.json +++ b/examples/preact/sub-components/package.json @@ -12,13 +12,14 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/preact-table": "^9.2.3", "preact": "^10.29.8" }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/with-tanstack-form/package.json b/examples/preact/with-tanstack-form/package.json index dedd6542bd..2db24bd182 100644 --- a/examples/preact/with-tanstack-form/package.json +++ b/examples/preact/with-tanstack-form/package.json @@ -12,8 +12,8 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/preact-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/preact-devtools": "^0.10.12", "@tanstack/preact-form": "^1.30.5", "@tanstack/preact-pacer": "^0.23.0", "@tanstack/preact-pacer-devtools": "0.7.0", @@ -25,7 +25,8 @@ }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/preact/with-tanstack-query/package.json b/examples/preact/with-tanstack-query/package.json index a20eae75c3..d3c632d276 100644 --- a/examples/preact/with-tanstack-query/package.json +++ b/examples/preact/with-tanstack-query/package.json @@ -12,8 +12,8 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/preact-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/preact-devtools": "^0.10.12", "@tanstack/preact-query": "^5.101.4", "@tanstack/preact-query-devtools": "^5.101.4", "@tanstack/preact-table": "^9.2.3", @@ -22,7 +22,8 @@ }, "devDependencies": { "@preact/preset-vite": "^2.10.6", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/aggregation/package.json b/examples/react/aggregation/package.json index 18cf361b7f..a9c91a28ad 100644 --- a/examples/react/aggregation/package.json +++ b/examples/react/aggregation/package.json @@ -11,19 +11,20 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/basic-dynamic-columns/package.json b/examples/react/basic-dynamic-columns/package.json index 90ab6293d8..e59e6ce199 100644 --- a/examples/react/basic-dynamic-columns/package.json +++ b/examples/react/basic-dynamic-columns/package.json @@ -12,8 +12,8 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/react-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", @@ -21,13 +21,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/basic-external-atoms/package.json b/examples/react/basic-external-atoms/package.json index 7d803beb09..7869d233d1 100644 --- a/examples/react/basic-external-atoms/package.json +++ b/examples/react/basic-external-atoms/package.json @@ -12,8 +12,8 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/react-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-store": "^0.11.1", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", @@ -21,13 +21,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/basic-external-state/package.json b/examples/react/basic-external-state/package.json index 836ae89690..b25631490c 100644 --- a/examples/react/basic-external-state/package.json +++ b/examples/react/basic-external-state/package.json @@ -12,8 +12,8 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/react-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-store": "^0.11.1", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", @@ -21,13 +21,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/basic-subscribe/package.json b/examples/react/basic-subscribe/package.json index 15281f5a8d..07bb8c9999 100644 --- a/examples/react/basic-subscribe/package.json +++ b/examples/react/basic-subscribe/package.json @@ -12,8 +12,8 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/react-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-store": "^0.11.1", "@tanstack/react-table": "^9.2.3", @@ -22,13 +22,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/basic-use-app-table/package.json b/examples/react/basic-use-app-table/package.json index eb9d936e67..e0950477b7 100644 --- a/examples/react/basic-use-app-table/package.json +++ b/examples/react/basic-use-app-table/package.json @@ -12,20 +12,21 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/react-devtools": "^0.10.10", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/basic-use-legacy-table/package.json b/examples/react/basic-use-legacy-table/package.json index 58e83bc5ab..50f60c196e 100644 --- a/examples/react/basic-use-legacy-table/package.json +++ b/examples/react/basic-use-legacy-table/package.json @@ -12,8 +12,8 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/react-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", @@ -21,13 +21,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/basic-use-table/package.json b/examples/react/basic-use-table/package.json index 2f4ba12a1b..07c5927d2e 100644 --- a/examples/react/basic-use-table/package.json +++ b/examples/react/basic-use-table/package.json @@ -12,20 +12,21 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/react-devtools": "^0.10.10", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/cell-selection/package.json b/examples/react/cell-selection/package.json index 78313b5719..e1b399f999 100644 --- a/examples/react/cell-selection/package.json +++ b/examples/react/cell-selection/package.json @@ -12,8 +12,8 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/react-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-hotkeys": "^0.10.0", "@tanstack/react-store": "^0.11.1", "@tanstack/react-table": "^9.2.3", @@ -22,13 +22,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/cell-spanning/package.json b/examples/react/cell-spanning/package.json index ac7e6aea19..8918b8ed98 100644 --- a/examples/react/cell-spanning/package.json +++ b/examples/react/cell-spanning/package.json @@ -12,19 +12,20 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/column-dnd/package.json b/examples/react/column-dnd/package.json index cab77722ec..3e322ce9f4 100644 --- a/examples/react/column-dnd/package.json +++ b/examples/react/column-dnd/package.json @@ -16,19 +16,20 @@ "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/column-ordering/package.json b/examples/react/column-ordering/package.json index f47c63463a..c0399ac67a 100644 --- a/examples/react/column-ordering/package.json +++ b/examples/react/column-ordering/package.json @@ -12,19 +12,20 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/column-pinning-split/package.json b/examples/react/column-pinning-split/package.json index f9137ce510..7b02f8f889 100644 --- a/examples/react/column-pinning-split/package.json +++ b/examples/react/column-pinning-split/package.json @@ -12,19 +12,20 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/column-pinning-sticky/package.json b/examples/react/column-pinning-sticky/package.json index c18cbe5113..099d45cf50 100644 --- a/examples/react/column-pinning-sticky/package.json +++ b/examples/react/column-pinning-sticky/package.json @@ -12,19 +12,20 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/column-pinning/package.json b/examples/react/column-pinning/package.json index 2df4f4da99..5c2c068473 100644 --- a/examples/react/column-pinning/package.json +++ b/examples/react/column-pinning/package.json @@ -12,19 +12,20 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/column-resizing-performant/package.json b/examples/react/column-resizing-performant/package.json index e814fb6bfd..8cf7174360 100644 --- a/examples/react/column-resizing-performant/package.json +++ b/examples/react/column-resizing-performant/package.json @@ -12,19 +12,20 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/column-resizing/package.json b/examples/react/column-resizing/package.json index df98c311a2..943628755d 100644 --- a/examples/react/column-resizing/package.json +++ b/examples/react/column-resizing/package.json @@ -12,19 +12,20 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/column-sizing/package.json b/examples/react/column-sizing/package.json index aa1080c7af..7eff72bca9 100644 --- a/examples/react/column-sizing/package.json +++ b/examples/react/column-sizing/package.json @@ -12,19 +12,20 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/column-visibility/package.json b/examples/react/column-visibility/package.json index afb1cdec38..d803677c2b 100644 --- a/examples/react/column-visibility/package.json +++ b/examples/react/column-visibility/package.json @@ -12,19 +12,20 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/composable-tables/package.json b/examples/react/composable-tables/package.json index 5b3deac40f..9a16d4e16f 100644 --- a/examples/react/composable-tables/package.json +++ b/examples/react/composable-tables/package.json @@ -12,8 +12,8 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/react-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-store": "^0.11.1", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", @@ -21,13 +21,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/custom-plugin/package.json b/examples/react/custom-plugin/package.json index b202a72628..8089d1a7fd 100644 --- a/examples/react/custom-plugin/package.json +++ b/examples/react/custom-plugin/package.json @@ -12,20 +12,21 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/expanding/package.json b/examples/react/expanding/package.json index c7814ce6c9..22d662f9c4 100644 --- a/examples/react/expanding/package.json +++ b/examples/react/expanding/package.json @@ -12,20 +12,21 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/filters-faceted-bucketed/package.json b/examples/react/filters-faceted-bucketed/package.json index a03e90cc31..eecb0c0055 100644 --- a/examples/react/filters-faceted-bucketed/package.json +++ b/examples/react/filters-faceted-bucketed/package.json @@ -12,19 +12,20 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/filters-faceted/package.json b/examples/react/filters-faceted/package.json index 39779a5cf3..9aec315f4e 100644 --- a/examples/react/filters-faceted/package.json +++ b/examples/react/filters-faceted/package.json @@ -12,7 +12,7 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", @@ -20,13 +20,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/filters-fuzzy/package.json b/examples/react/filters-fuzzy/package.json index 83d5d1092a..1fb6ec4122 100644 --- a/examples/react/filters-fuzzy/package.json +++ b/examples/react/filters-fuzzy/package.json @@ -12,7 +12,7 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", @@ -20,13 +20,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/filters/package.json b/examples/react/filters/package.json index 956d04b463..3b7b12e0bb 100644 --- a/examples/react/filters/package.json +++ b/examples/react/filters/package.json @@ -12,7 +12,7 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", @@ -20,13 +20,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/grouped-aggregation/package.json b/examples/react/grouped-aggregation/package.json index 43cf44f709..906b709249 100644 --- a/examples/react/grouped-aggregation/package.json +++ b/examples/react/grouped-aggregation/package.json @@ -11,19 +11,20 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/grouping/package.json b/examples/react/grouping/package.json index f8d256ba23..e06230c58e 100644 --- a/examples/react/grouping/package.json +++ b/examples/react/grouping/package.json @@ -12,19 +12,20 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/header-groups/package.json b/examples/react/header-groups/package.json index fae7ced997..cc94bd4f1b 100644 --- a/examples/react/header-groups/package.json +++ b/examples/react/header-groups/package.json @@ -12,19 +12,20 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/kitchen-sink-chakra-ui/package.json b/examples/react/kitchen-sink-chakra-ui/package.json index 0917e70080..9286ba423d 100644 --- a/examples/react/kitchen-sink-chakra-ui/package.json +++ b/examples/react/kitchen-sink-chakra-ui/package.json @@ -18,10 +18,10 @@ "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@emotion/react": "^11.14.0", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tabler/icons-react": "^3.46.0", "@tanstack/match-sorter-utils": "^9.1.2", - "@tanstack/react-devtools": "^0.10.10", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", @@ -31,13 +31,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/kitchen-sink-hero-ui/package.json b/examples/react/kitchen-sink-hero-ui/package.json index 329fae06c2..a156f67eef 100644 --- a/examples/react/kitchen-sink-hero-ui/package.json +++ b/examples/react/kitchen-sink-hero-ui/package.json @@ -16,12 +16,12 @@ "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@heroui/react": "^3.2.4", "@heroui/styles": "^3.2.4", "@tailwindcss/vite": "^4.3.3", "@tanstack/match-sorter-utils": "^9.1.2", - "@tanstack/react-devtools": "^0.10.10", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", @@ -31,13 +31,14 @@ "tailwindcss": "^4.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/kitchen-sink-mantine/package.json b/examples/react/kitchen-sink-mantine/package.json index c06d9d4e9d..bc31f759e6 100644 --- a/examples/react/kitchen-sink-mantine/package.json +++ b/examples/react/kitchen-sink-mantine/package.json @@ -16,12 +16,12 @@ "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@faker-js/faker": "^10.5.0", - "@mantine/core": "^9.5.1", - "@mantine/hooks": "^9.5.1", + "@faker-js/faker": "^10.6.0", + "@mantine/core": "^9.5.2", + "@mantine/hooks": "^9.5.2", "@tabler/icons-react": "^3.46.0", "@tanstack/match-sorter-utils": "^9.1.2", - "@tanstack/react-devtools": "^0.10.10", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", @@ -30,16 +30,17 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "postcss": "^8.5.26", "postcss-preset-mantine": "^1.18.0", "postcss-simple-vars": "^7.0.1", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/kitchen-sink-material-ui/package.json b/examples/react/kitchen-sink-material-ui/package.json index dfaaf32742..cdedbda35e 100644 --- a/examples/react/kitchen-sink-material-ui/package.json +++ b/examples/react/kitchen-sink-material-ui/package.json @@ -18,11 +18,11 @@ "@dnd-kit/utilities": "^3.2.2", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@mui/icons-material": "^9.3.1", "@mui/material": "^9.3.1", "@tanstack/match-sorter-utils": "^9.1.2", - "@tanstack/react-devtools": "^0.10.10", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", @@ -31,13 +31,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/kitchen-sink-react-aria/package.json b/examples/react/kitchen-sink-react-aria/package.json index 27055f0b37..3c79c7889a 100644 --- a/examples/react/kitchen-sink-react-aria/package.json +++ b/examples/react/kitchen-sink-react-aria/package.json @@ -16,10 +16,10 @@ "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tailwindcss/vite": "^4.3.3", "@tanstack/match-sorter-utils": "^9.1.2", - "@tanstack/react-devtools": "^0.10.10", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", @@ -30,13 +30,14 @@ "tailwindcss": "^4.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/kitchen-sink-shadcn-base/package.json b/examples/react/kitchen-sink-shadcn-base/package.json index ee4c79541e..f518c17652 100644 --- a/examples/react/kitchen-sink-shadcn-base/package.json +++ b/examples/react/kitchen-sink-shadcn-base/package.json @@ -18,10 +18,10 @@ "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tailwindcss/vite": "^4.3.3", "@tanstack/match-sorter-utils": "^9.1.2", - "@tanstack/react-devtools": "^0.10.10", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", @@ -29,7 +29,7 @@ "clsx": "^2.1.1", "cmdk": "1.1.1", "date-fns": "^4.4.0", - "lucide-react": "^1.31.0", + "lucide-react": "^1.34.0", "react": "^19.2.8", "react-day-picker": "10.0.1", "react-dom": "^19.2.8", @@ -38,13 +38,14 @@ "tw-animate-css": "^1.4.0" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/kitchen-sink-shadcn-radix/package.json b/examples/react/kitchen-sink-shadcn-radix/package.json index 6fec5d635b..7ebfba5332 100644 --- a/examples/react/kitchen-sink-shadcn-radix/package.json +++ b/examples/react/kitchen-sink-shadcn-radix/package.json @@ -17,10 +17,10 @@ "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tailwindcss/vite": "^4.3.3", "@tanstack/match-sorter-utils": "^9.1.2", - "@tanstack/react-devtools": "^0.10.10", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", @@ -28,7 +28,7 @@ "clsx": "^2.1.1", "cmdk": "1.1.1", "date-fns": "^4.4.0", - "lucide-react": "^1.31.0", + "lucide-react": "^1.34.0", "radix-ui": "^1.6.7", "react": "^19.2.8", "react-day-picker": "10.0.1", @@ -38,13 +38,14 @@ "tw-animate-css": "^1.4.0" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/kitchen-sink/package.json b/examples/react/kitchen-sink/package.json index 3c7b76383f..d54c42b623 100644 --- a/examples/react/kitchen-sink/package.json +++ b/examples/react/kitchen-sink/package.json @@ -16,13 +16,13 @@ "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/match-sorter-utils": "^9.1.2", - "@tanstack/react-devtools": "^0.10.10", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-hotkeys": "^0.10.0", "@tanstack/react-pacer": "^0.23.0", - "@tanstack/react-router": "^1.170.27", - "@tanstack/react-start": "^1.168.44", + "@tanstack/react-router": "^1.170.32", + "@tanstack/react-start": "^1.168.49", "@tanstack/react-store": "^0.11.1", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", @@ -30,13 +30,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@types/node": "^26.2.0", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/lib-chakra-ui/package.json b/examples/react/lib-chakra-ui/package.json index c6578e151a..edbf58c0af 100644 --- a/examples/react/lib-chakra-ui/package.json +++ b/examples/react/lib-chakra-ui/package.json @@ -14,20 +14,21 @@ "dependencies": { "@chakra-ui/react": "^3.36.1", "@emotion/react": "^11.14.0", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tabler/icons-react": "^3.46.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/lib-hero-ui/package.json b/examples/react/lib-hero-ui/package.json index c6af0352a9..02df550fb8 100644 --- a/examples/react/lib-hero-ui/package.json +++ b/examples/react/lib-hero-ui/package.json @@ -12,7 +12,7 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@heroui/react": "^3.2.4", "@heroui/styles": "^3.2.4", "@tailwindcss/vite": "^4.3.3", @@ -22,13 +22,14 @@ "tailwindcss": "^4.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/lib-mantine/package.json b/examples/react/lib-mantine/package.json index a323f5ac0e..ea22dce7bf 100644 --- a/examples/react/lib-mantine/package.json +++ b/examples/react/lib-mantine/package.json @@ -12,25 +12,26 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@mantine/core": "^9.5.1", - "@mantine/hooks": "^9.5.1", + "@faker-js/faker": "^10.6.0", + "@mantine/core": "^9.5.2", + "@mantine/hooks": "^9.5.2", "@tabler/icons-react": "^3.46.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "postcss": "^8.5.26", "postcss-preset-mantine": "^1.18.0", "postcss-simple-vars": "^7.0.1", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/lib-material-ui/package.json b/examples/react/lib-material-ui/package.json index 73bb68b940..172ea8c278 100644 --- a/examples/react/lib-material-ui/package.json +++ b/examples/react/lib-material-ui/package.json @@ -14,7 +14,7 @@ "dependencies": { "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@mui/icons-material": "^9.3.1", "@mui/material": "^9.3.1", "@tanstack/react-table": "^9.2.3", @@ -22,13 +22,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/lib-react-aria/package.json b/examples/react/lib-react-aria/package.json index 1c58164ea7..d666027e6f 100644 --- a/examples/react/lib-react-aria/package.json +++ b/examples/react/lib-react-aria/package.json @@ -12,7 +12,7 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tailwindcss/vite": "^4.3.3", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", @@ -21,13 +21,14 @@ "tailwindcss": "^4.3.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/lib-shadcn-base/package.json b/examples/react/lib-shadcn-base/package.json index 5ab048d4a6..633348febc 100644 --- a/examples/react/lib-shadcn-base/package.json +++ b/examples/react/lib-shadcn-base/package.json @@ -13,13 +13,13 @@ }, "dependencies": { "@base-ui/react": "^1.7.0", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tailwindcss/vite": "^4.3.3", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^1.31.0", + "lucide-react": "^1.34.0", "react": "^19.2.8", "react-dom": "^19.2.8", "tailwind-merge": "^3.6.0", @@ -27,13 +27,14 @@ "tw-animate-css": "^1.4.0" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/lib-shadcn-radix/package.json b/examples/react/lib-shadcn-radix/package.json index 1f1c05cd54..230318a017 100644 --- a/examples/react/lib-shadcn-radix/package.json +++ b/examples/react/lib-shadcn-radix/package.json @@ -12,13 +12,13 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tailwindcss/vite": "^4.3.3", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^1.31.0", + "lucide-react": "^1.34.0", "radix-ui": "^1.6.7", "react": "^19.2.8", "react-dom": "^19.2.8", @@ -27,13 +27,14 @@ "tw-animate-css": "^1.4.0" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/mantine-react-table/package.json b/examples/react/mantine-react-table/package.json index de8a14e54d..baeb1efe78 100644 --- a/examples/react/mantine-react-table/package.json +++ b/examples/react/mantine-react-table/package.json @@ -12,31 +12,32 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@mantine/core": "^9.5.1", - "@mantine/dates": "^9.5.1", - "@mantine/hooks": "^9.5.1", + "@faker-js/faker": "^10.6.0", + "@mantine/core": "^9.5.2", + "@mantine/dates": "^9.5.2", + "@mantine/hooks": "^9.5.2", "@tabler/icons-react": "^3.46.0", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/react-store": "^0.11.1", "@tanstack/react-table": "^9.2.3", - "@tanstack/react-virtual": "^3.14.9", + "@tanstack/react-virtual": "^3.14.10", "clsx": "^2.1.1", - "dayjs": "^1.11.21", + "dayjs": "^1.11.23", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "postcss": "^8.5.26", "postcss-preset-mantine": "^1.18.0", "postcss-simple-vars": "^7.0.1", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/material-react-table/package.json b/examples/react/material-react-table/package.json index 3bdc6e4084..0b9f17ec62 100644 --- a/examples/react/material-react-table/package.json +++ b/examples/react/material-react-table/package.json @@ -14,27 +14,28 @@ "dependencies": { "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@mui/icons-material": "^9.3.1", "@mui/material": "^9.3.1", - "@mui/x-date-pickers": "^9.11.0", + "@mui/x-date-pickers": "^9.12.0", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-store": "^0.11.1", "@tanstack/react-table": "^9.2.3", - "@tanstack/react-virtual": "^3.14.9", + "@tanstack/react-virtual": "^3.14.10", "highlight-words": "^2.0.0", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/pagination/package.json b/examples/react/pagination/package.json index 8a530c062b..f5ab11e658 100644 --- a/examples/react/pagination/package.json +++ b/examples/react/pagination/package.json @@ -12,20 +12,21 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-store": "^0.11.1", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/realtime-trading/README.md b/examples/react/realtime-trading/README.md new file mode 100644 index 0000000000..3b92048931 --- /dev/null +++ b/examples/react/realtime-trading/README.md @@ -0,0 +1,252 @@ +# React realtime trading benchmark + +This is a standalone stress example for the current TanStack React Table +adapter. It combines a high-frequency synthetic market feed, immutable row +snapshots, sortable and resizable columns, range selection, dynamic React cell +components, optional row virtualization, React Profiler measurements, and +browser performance instrumentation. + +The goal is to make feed work, message delivery, state application, table work, +React commits, and browser layout independently observable. It is a repeatable +rendering benchmark, not an exchange or network simulator. + +## Run and verify + +```bash +pnpm --dir examples/react/realtime-trading dev +``` + +Open `http://localhost:7777`. + +For React commit timings, use the profiling production build: + +```bash +pnpm --dir examples/react/realtime-trading build:profile +``` + +The normal verification commands are: + +```bash +pnpm --dir examples/react/realtime-trading test:types +pnpm --dir examples/react/realtime-trading lint +pnpm --dir examples/react/realtime-trading build +pnpm --dir examples/react/realtime-trading test:e2e +``` + +Development builds include React checks and produce deliberately pessimistic +timings. The standard production build disables Profiler callbacks; the +`profile` mode aliases the profiling React DOM client so commit metrics remain +available. + +## Directory structure + +| Path | Responsibility | +| ------------------------- | ------------------------------------------------------------------------------------------------------------------ | +| `src/feed/` | Market types, instruments, feed configuration, immutable update helpers, controller, and React lifecycle hook. | +| `src/feed/worker/` | Worker protocol, deterministic market engine, and the module Web Worker. | +| `src/benchmark/` | Browser monitor, benchmark controller, table observers, and React Profiler integration. | +| `src/shell/` | Controller contexts, full-viewport shell, metrics, configurator, diagnostics, selected instrument, and status bar. | +| `src/table/table-config/` | Grouped columns, row boundary, custom cells, and render counters. | +| `src/table/` | Table instance, subscription boundaries, interactions, pointer hook, initial fit, and virtualization. | +| `src/App.tsx` | Composition root; creates controllers, providers, shell, table, and Profiler boundary. | + +Feed state and benchmark state are intentionally separate. `MarketFeedController` +can run without `TradingBenchmarkController`; the latter observes feed lifecycle +events and owns only controls/metrics used by this benchmark UI. + +## Data and worker pipeline + +The initial configuration is 100 instruments, 10K generated samples per +second, a 20 ms delivery interval, enabled intraday charts, and 16 ms intraday +sampling. + +1. `MarketFeedController` starts a module worker and sends the active config. +2. `market-feed-engine.ts` mutates worker-private quote state using a + deterministic PRNG and stable instrument IDs. +3. A 16 ms loop accrues a fractional sample budget and produces the requested + amount of synthetic market work. +4. A `Map` keyed by row index retains the latest pending update for each + instrument, coalescing repeated samples. +5. A separate timer publishes at the selected delivery interval. Worker work + rate and `postMessage` rate are deliberately independent. +6. The main thread creates a new outer quotes array and replaces only the rows + present in the message. Unchanged row objects remain referentially stable. +7. History arrays change only on an intraday sample. A session ID discards stale + messages after reset or instrument-count changes. + +UI terminology: + +- **Synthetic quote workload** means generated samples per second inside the + worker, not browser events, React renders, or messages. +- **Worker delivery interval** is the target coalesced-message cadence; 20 ms + targets approximately 50 messages per second. +- **Changed rows** counts immutable row objects applied on the main thread. + Rows are deduplicated within one snapshot, but the same row can be counted + again in a later snapshot, so this is intentionally a throughput rate rather + than a count of distinct instruments over the whole second. +- **Message samples** is the generated work represented by the latest message. + +Intraday history sampling is independent of the quote workload, and the 25K +burst creates one intentionally expensive immediate batch. The worker resembles +an upstream WebSocket/SSE producer but does not include network latency. + +## React state and rendering architecture + +- `MarketFeedController` exposes each feed value as a direct TanStack atom: + `quotes`, status, row count, workload, delivery, and chart controls do not + share one aggregate `MarketFeedState` notification. +- `quotes` is its own high-frequency atom. The table subscribes to it directly, + while the header/configurator subscribe only to their lower-frequency atoms. +- Benchmark summary state remains a TanStack Store because its metrics are + published together as one coherent snapshot. +- `createStoreContext` provides the controllers without making every consumer + subscribe to the complete state object. +- Shell components call `useSelector` with narrow slices and shallow comparison + where a selector returns an object. +- Selected symbol and renderer mode are dedicated atoms because they have + different consumers and update frequencies from aggregate diagnostics. +- `TradingTable` subscribes directly to quote data and the virtualization + inputs it needs; the parent shell does not receive the quotes array. +- `table.Subscribe` boundaries isolate sorting/filtering/order changes, each + resize handle, and each row's selection state. +- Stable row IDs come from instrument IDs through `getRowId`. + +React Compiler is enabled in the Vite Babel pipeline for `src`. The current +adapter is compiled normally; there is no historical v8 implementation or +`use no memo` compatibility boundary in this example. Compiler optimization +does not replace correct subscription ownership: components still subscribe to +the smallest practical state slice. + +## Table behavior + +The grid has 14 leaf columns grouped into Instrument, Price & Change, Order +Book, Session, and Chart sections. It provides: + +- core sorting and filtering; +- on-change column resizing with double-click reset; +- drag-and-drop leaf-column ordering; +- CSS-only row hover; +- click/modified-click row selection; +- mouse-drag cell range selection and keyboard navigation; +- custom Price, Move, Percent Change, and Sparkline components; +- an opt-in mode that swaps move component A/B as direction changes. + +`useTradingGridPointer` installs handlers once on `tbody`. It uses +`event.composedPath()` and data attributes to resolve the TanStack cell, so the +table does not allocate pointer handlers for every cell. Refs retain transient +drag state without triggering React renders. + +Column sizes are written to CSS custom properties only when sizing or ordering +changes. Cells reference those properties, avoiding width-object churn during +quote updates. A `ResizeObserver` expands the initial column sizes to the +available viewport; the first manual resize disables later automatic fitting. + +## Full DOM and virtual rows + +The internal preference is `auto`, `tanstack`, or `none`: + +- Below 200 rows, `auto` resolves to **Full DOM**, while virtualization remains + manually selectable. +- From 200 through 1,499 rows, `auto` resolves to **TanStack Virtual**, but the + user may still choose Full DOM. +- At 1,500 rows or more, virtualization is forced and the control is locked. + +React Virtual uses a fixed 32 px estimate, 10-row overscan, stable row IDs as +item keys, transformed rows, and a body-sized spacer. The footer reports the +current range from the virtualizer. Full DOM maps the complete row model. + +Both paths apply `content-visibility: auto` with a matching intrinsic height. +For Full DOM this can reduce browser work but not React element creation or DOM +mount count. Virtualization is what limits mounted row components. + +## Performance decisions + +- Market calculations run outside the main thread. +- Repeated samples are coalesced before worker messaging. +- Immutable snapshots preserve untouched row/history references. +- Stable row keys and `getRowId` preserve identity through sorting. +- Controller contexts carry stable objects; selectors subscribe to slices. +- Table, header, resize handle, row selection, and cell renderer boundaries are + independently subscribable. +- Pointer selection is delegated and transient pointer state lives in refs. +- Column widths use CSS variables instead of per-tick style recalculation. +- Dynamic component destruction is opt-in; stable components are the baseline. +- Virtualization limits React and DOM work at larger row counts. +- Benchmark publication is throttled separately from the feed. + +A new outer data array is required to publish immutable state. Referentially +stable untouched rows, keyed rows, and narrow subscriptions reduce downstream +work; they do not guarantee that the table's sorted/filtered row model can skip +all processing when its data input changes. + +## Diagnostics + +The compact **Live health** block lives in the configurator sidebar and keeps +four cross-framework signals visible: + +- **Frame rate (est.)** counts `requestAnimationFrame` callbacks over a rolling + one-second window. It is a main-thread scheduling signal capped by the + display refresh rate, not proof of GPU-presented frames or a React Scan FPS + value. +- **Average commit latency** is the rolling three-second average from the first + pending market mutation to the table's DOM commit. Several snapshots may be + coalesced behind one commit, so this includes scheduling, React work, and DOM + commit latency; it is not component render duration. +- **Long frames** comes from the browser Long Animation Frames API and is + cumulative since reset. The worst duration is shown when supported. +- **Throughput** pairs changed rows/s with applied snapshots/s. Changed rows are + deduplicated per snapshot, not across the full reporting window. + +The detailed section retains generated worker samples, messages, state applies, +table DOM commits, a 10-second commit-latency p95/max, cumulative slow commits, +mounted hosts, component lifecycle counts, callbacks by column, executions by +component type, DOM `MutationRecord` rate, core row-model timing, and optional +heap information. + +The React Profiler additionally records actual/base duration and commit counts +when using development or the profiling build. The in-memory latency, Profiler, +and row-model aggregates inspect every call, but the Performance timeline emits +only one User Timing measure per 20 calls to avoid making instrumentation a +significant part of a hot run. Old measures are periodically pruned. + +The `MutationObserver` watches the table body for text/children and only +`class`/`style` attribute changes. Its value is browser `MutationRecord`s per +second, not DOM operations: a record can represent a coalesced change, and +framework write patterns can produce different record counts for equivalent +screens. Creating records also has real overhead at high rates, so treat it as +a diagnostic and confirm important comparisons with a Performance recording. +Heap is Chrome-only `usedJSHeapSize`, changes with garbage-collection timing, +and is useful as a trend rather than a leak verdict. + +The monitor itself schedules one lightweight `requestAnimationFrame` callback +and publishes its sidebar snapshot every 500 ms. The sidebar subscribes to that +snapshot independently, so publishing diagnostics does not update the quotes +atom or table data boundary, but it is still instrumentation overhead and must +remain enabled in both sides of an A/B comparison. React Profiler and React +DevTools also add overhead by design. + +Callback counts are not DOM mutation counts. A cell callback can execute while +React reuses the existing component and DOM. Likewise, a rising heap during the +component-swap stress test is not proof of a leak until repeated post-GC heap +snapshots show retained instances. + +Use Chrome Performance and React DevTools for call stacks/flamegraphs, and keep +the instrument count, workload, delivery interval, renderer mode, build mode, +and virtualization mode fixed between comparisons. + +React Scan remains an optional development-only aid in this example. It is not +used by any canonical counter because the other adapter examples cannot share +it, and its instrumentation can alter a recording. Use the profiling production +build without React Scan for cross-framework comparisons. + +## Standalone example policy + +This directory owns its instrument list, feed engine, worker, diagnostics, +styles, and UI instead of importing a common demo package. The duplication is +intentional: each adapter example must run independently and remain easy to +copy to StackBlitz. Shared architectural explanations are repeated in the +READMEs for the same reason. + +The package pins `@tanstack/react-table` to the repository version. The root +workspace override resolves it to `packages/react-table` while preserving a +release-like manifest. diff --git a/examples/react/realtime-trading/index.html b/examples/react/realtime-trading/index.html new file mode 100644 index 0000000000..c3dac68d53 --- /dev/null +++ b/examples/react/realtime-trading/index.html @@ -0,0 +1,17 @@ + + + + + + + + React Real-time Trading flexRender Lab + + +
+ + + diff --git a/examples/react/realtime-trading/package.json b/examples/react/realtime-trading/package.json new file mode 100644 index 0000000000..7315552143 --- /dev/null +++ b/examples/react/realtime-trading/package.json @@ -0,0 +1,33 @@ +{ + "name": "tanstack-react-table-example-realtime-trading", + "private": true, + "type": "module", + "scripts": { + "start": "vite", + "dev": "vite", + "build": "vite build", + "build:profile": "vite build --mode profile", + "serve": "vite preview", + "lint": "eslint ./src", + "test:types": "tsc --noEmit", + "test:e2e": "PLAYWRIGHT_VITE_MODE=profile PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" + }, + "dependencies": { + "@tanstack/react-store": "^0.11.1", + "@tanstack/react-table": "^9.2.3", + "@tanstack/react-virtual": "^3.14.10", + "react": "^19.2.8", + "react-dom": "^19.2.8" + }, + "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", + "@rolldown/plugin-babel": "^0.2.3", + "@rollup/plugin-replace": "^6.0.3", + "@types/react": "^19.2.18", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", + "babel-plugin-react-compiler": "^1.0.0", + "typescript": "6.0.3", + "vite": "^8.2.2" + } +} diff --git a/examples/react/realtime-trading/src/App.tsx b/examples/react/realtime-trading/src/App.tsx new file mode 100644 index 0000000000..2df39ff073 --- /dev/null +++ b/examples/react/realtime-trading/src/App.tsx @@ -0,0 +1,34 @@ +import { Profiler } from 'react' +import { useMarketFeedController } from './feed/use-market-feed-controller' +import { useTradingBenchmarkController } from './benchmark/use-trading-benchmark-controller' +import { TradingShell } from './shell/TradingShell' +import { + TradingShellProvider, + useTradingShellController, +} from './shell/trading-shell-context' +import { TradingTable } from './table/trading-table' + +export function App() { + const feed = useMarketFeedController() + const controller = useTradingBenchmarkController(feed) + return ( + + + + + + ) +} + +function TradingTableOutlet() { + const controller = useTradingShellController() + + return ( + + + + ) +} diff --git a/examples/react/realtime-trading/src/benchmark/benchmark-monitor.ts b/examples/react/realtime-trading/src/benchmark/benchmark-monitor.ts new file mode 100644 index 0000000000..7d37abb354 --- /dev/null +++ b/examples/react/realtime-trading/src/benchmark/benchmark-monitor.ts @@ -0,0 +1,500 @@ +import { + quoteCellLifecycle, + quoteRenderDiagnostics, +} from '../table/table-config/quote-cells' +import { rowModelDiagnostics } from '../table/trading-table' +import type { ProfilerOnRenderCallback } from 'react' + +export interface NamedInvocationRate { + name: string + callsPerSecond: number +} + +interface TimedLatencySample { + recordedAt: number + duration: number +} + +const averageLatencyWindowMs = 3_000 +const percentileLatencyWindowMs = 10_000 +const frameRateWindowMs = 1_000 + +export interface FeedMetrics { + actualTicksPerSecond: number + rowUpdatesPerSecond: number + workerMessagesPerSecond: number + stateApplicationsPerSecond: number + supersededUpdatesPerSecond: number + totalTicks: number + estimatedFrameRate: number + tableCommitsPerSecond: number + lastBatchSize: number + averageCommitLatencyMs: number + p95CommitLatencyMs: number + maxCommitLatencyMs: number + slowCommits: number + longAnimationFrames: number + worstLongAnimationFrameMs: number + heapMb: number | null + componentsCreated: number + componentsDestroyed: number + workerMessages: number + lastUpdateCount: number + cellRendererCallsPerSecond: number + componentRenderCallsPerSecond: number + cellRendererRates: ReadonlyArray + componentRenderRates: ReadonlyArray + domMutationsPerSecond: number + profilerCommitsPerSecond: number + profilerAverageActualMs: number + profilerP95ActualMs: number + profilerAverageBaseMs: number + rowModelCallsPerSecond: number + rowModelAverageMs: number + rowModelMaxMs: number + visibleRows: number +} + +export const initialMetrics: FeedMetrics = { + actualTicksPerSecond: 0, + rowUpdatesPerSecond: 0, + workerMessagesPerSecond: 0, + stateApplicationsPerSecond: 0, + supersededUpdatesPerSecond: 0, + totalTicks: 0, + estimatedFrameRate: 0, + tableCommitsPerSecond: 0, + lastBatchSize: 0, + averageCommitLatencyMs: 0, + p95CommitLatencyMs: 0, + maxCommitLatencyMs: 0, + slowCommits: 0, + longAnimationFrames: 0, + worstLongAnimationFrameMs: 0, + heapMb: null, + componentsCreated: 0, + componentsDestroyed: 0, + workerMessages: 0, + lastUpdateCount: 0, + cellRendererCallsPerSecond: 0, + componentRenderCallsPerSecond: 0, + cellRendererRates: [], + componentRenderRates: [], + domMutationsPerSecond: 0, + profilerCommitsPerSecond: 0, + profilerAverageActualMs: 0, + profilerP95ActualMs: 0, + profilerAverageBaseMs: 0, + rowModelCallsPerSecond: 0, + rowModelAverageMs: 0, + rowModelMaxMs: 0, + visibleRows: 0, +} + +const userTiming = { + entryCount: 0, + measureCallsByName: {} as Record, +} + +export function recordMeasure( + name: string, + start: number, + end: number, + detail: Record, +): void { + const measureCall = (userTiming.measureCallsByName[name] ?? 0) + 1 + userTiming.measureCallsByName[name] = measureCall + if ((measureCall - 1) % 20 !== 0) return + + try { + performance.measure(name, { start, end, detail }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMeasures('react-profiler-commit') + performance.clearMeasures('market-update-to-dom-commit') + } + } catch { + // User Timing Level 3 options are not implemented in every browser. + } +} + +export function markBenchmarkAction( + name: string, + detail: Record = {}, +): void { + try { + performance.mark(`benchmark:${name}`, { detail }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMarks() + } + } catch { + // User Timing Level 3 detail is not implemented in every browser. + } +} + +interface ProfilerSample { + actualDuration: number + baseDuration: number +} + +export class BenchmarkMonitor { + readonly #runtime = { + sessionStartedAt: performance.now(), + sampleStartedAt: performance.now(), + pendingCommitStartedAt: null as number | null, + commitLatencySamples: [] as Array, + slowCommitCount: 0, + profilerSamples: [] as Array, + totalTicks: 0, + ticksInSample: 0, + rowUpdatesInSample: 0, + workerMessagesInSample: 0, + stateApplicationsInSample: 0, + supersededUpdatesInSample: 0, + lastBatchSize: 0, + lastUpdateCount: 0, + workerMessages: 0, + frameTrackingStartedAt: performance.now(), + frameTimestamps: [] as Array, + tableCommitsInSample: 0, + longAnimationFrameCount: 0, + worstLongAnimationFrameMs: 0, + previousCellRendererCalls: 0, + previousComponentRenderCalls: 0, + previousCellRendererCallsByName: { + ...quoteRenderDiagnostics.cellRendererCallsByName, + }, + previousComponentRenderCallsByName: { + ...quoteRenderDiagnostics.componentRenderCallsByName, + }, + domMutationsInSample: 0, + previousRowModelCalls: 0, + previousRowModelDuration: 0, + } + + readonly recordProfilerRender: ProfilerOnRenderCallback = ( + id, + phase, + actualDuration, + baseDuration, + startTime, + commitTime, + ) => { + this.#runtime.profilerSamples.push({ actualDuration, baseDuration }) + recordMeasure('react-profiler-commit', startTime, commitTime, { + id, + phase, + actualDuration, + baseDuration, + }) + } + + markCommitPending(): void { + this.#runtime.pendingCommitStartedAt ??= performance.now() + } + + recordDomCommit(): void { + const runtime = this.#runtime + if (runtime.pendingCommitStartedAt !== null) { + const commitEndedAt = performance.now() + const duration = commitEndedAt - runtime.pendingCommitStartedAt + runtime.commitLatencySamples.push({ + recordedAt: commitEndedAt, + duration, + }) + if (duration > 16.7) runtime.slowCommitCount++ + recordMeasure( + 'market-update-to-dom-commit', + runtime.pendingCommitStartedAt, + commitEndedAt, + {}, + ) + runtime.pendingCommitStartedAt = null + runtime.tableCommitsInSample++ + } + } + + recordWorkerMessage(): void { + this.#runtime.workerMessages++ + this.#runtime.workerMessagesInSample++ + } + + recordBatch( + tickCount: number, + updateCount: number, + supersededUpdateCount: number, + ): void { + const runtime = this.#runtime + runtime.lastBatchSize = tickCount + runtime.lastUpdateCount = updateCount + runtime.ticksInSample += tickCount + runtime.totalTicks += tickCount + runtime.rowUpdatesInSample += updateCount + runtime.stateApplicationsInSample++ + runtime.supersededUpdatesInSample += supersededUpdateCount + } + + recordAnimationFrame(now: number): void { + const timestamps = this.#runtime.frameTimestamps + timestamps.push(now) + pruneFrameTimestamps(timestamps, now) + } + + recordLongAnimationFrame(duration: number, startTime: number): void { + const runtime = this.#runtime + if (startTime < runtime.sessionStartedAt) return + + runtime.longAnimationFrameCount++ + runtime.worstLongAnimationFrameMs = Math.max( + runtime.worstLongAnimationFrameMs, + duration, + ) + } + + recordDomMutations(count: number): void { + this.#runtime.domMutationsInSample += count + } + + resetDomMutations(): void { + this.#runtime.domMutationsInSample = 0 + } + + shouldPublish(now: number): boolean { + return now - this.#runtime.sampleStartedAt >= 500 + } + + publish(now: number): FeedMetrics { + const runtime = this.#runtime + const sampleDuration = now - runtime.sampleStartedAt + pruneLatencySamples(runtime.commitLatencySamples, now) + pruneFrameTimestamps(runtime.frameTimestamps, now) + const averageCommitLatencySamples = runtime.commitLatencySamples + .filter((sample) => sample.recordedAt >= now - averageLatencyWindowMs) + .map((sample) => sample.duration) + const percentileCommitLatencySamples = runtime.commitLatencySamples.map( + (sample) => sample.duration, + ) + const sortedCommitLatencySamples = [...percentileCommitLatencySamples].sort( + (left, right) => left - right, + ) + const profilerSamples = runtime.profilerSamples + const sortedProfilerSamples = profilerSamples + .map((sample) => sample.actualDuration) + .sort((left, right) => left - right) + const rowModelCalls = + rowModelDiagnostics.calls - runtime.previousRowModelCalls + const rowModelDuration = + rowModelDiagnostics.totalDurationMs - runtime.previousRowModelDuration + const cellRendererCalls = + quoteRenderDiagnostics.cellRendererCalls - + runtime.previousCellRendererCalls + const componentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls - + runtime.previousComponentRenderCalls + const cellRendererRates = calculateInvocationRates( + quoteRenderDiagnostics.cellRendererCallsByName, + runtime.previousCellRendererCallsByName, + sampleDuration, + ) + const componentRenderRates = calculateInvocationRates( + quoteRenderDiagnostics.componentRenderCallsByName, + runtime.previousComponentRenderCallsByName, + sampleDuration, + ) + const averageCommitLatencyMs = + averageCommitLatencySamples.length === 0 + ? 0 + : averageCommitLatencySamples.reduce((sum, value) => sum + value, 0) / + averageCommitLatencySamples.length + const p95Index = Math.max( + 0, + Math.ceil(sortedCommitLatencySamples.length * 0.95) - 1, + ) + const profilerP95Index = Math.max( + 0, + Math.ceil(sortedProfilerSamples.length * 0.95) - 1, + ) + const metrics: FeedMetrics = { + actualTicksPerSecond: + sampleDuration === 0 + ? 0 + : (runtime.ticksInSample / sampleDuration) * 1_000, + rowUpdatesPerSecond: + (runtime.rowUpdatesInSample / sampleDuration) * 1_000, + workerMessagesPerSecond: + (runtime.workerMessagesInSample / sampleDuration) * 1_000, + stateApplicationsPerSecond: + (runtime.stateApplicationsInSample / sampleDuration) * 1_000, + supersededUpdatesPerSecond: + (runtime.supersededUpdatesInSample / sampleDuration) * 1_000, + totalTicks: runtime.totalTicks, + estimatedFrameRate: calculateFrameRate( + runtime.frameTimestamps, + runtime.frameTrackingStartedAt, + now, + ), + tableCommitsPerSecond: + (runtime.tableCommitsInSample / sampleDuration) * 1_000, + lastBatchSize: runtime.lastBatchSize, + averageCommitLatencyMs, + p95CommitLatencyMs: sortedCommitLatencySamples[p95Index] ?? 0, + maxCommitLatencyMs: sortedCommitLatencySamples.at(-1) ?? 0, + slowCommits: runtime.slowCommitCount, + longAnimationFrames: runtime.longAnimationFrameCount, + worstLongAnimationFrameMs: runtime.worstLongAnimationFrameMs, + heapMb: readHeapSizeMb(), + componentsCreated: quoteCellLifecycle.created, + componentsDestroyed: quoteCellLifecycle.destroyed, + workerMessages: runtime.workerMessages, + lastUpdateCount: runtime.lastUpdateCount, + cellRendererCallsPerSecond: (cellRendererCalls / sampleDuration) * 1_000, + componentRenderCallsPerSecond: + (componentRenderCalls / sampleDuration) * 1_000, + cellRendererRates, + componentRenderRates, + domMutationsPerSecond: + (runtime.domMutationsInSample / sampleDuration) * 1_000, + profilerCommitsPerSecond: + (profilerSamples.length / sampleDuration) * 1_000, + profilerAverageActualMs: + profilerSamples.length === 0 + ? 0 + : profilerSamples.reduce( + (sum, sample) => sum + sample.actualDuration, + 0, + ) / profilerSamples.length, + profilerP95ActualMs: sortedProfilerSamples[profilerP95Index] ?? 0, + profilerAverageBaseMs: + profilerSamples.length === 0 + ? 0 + : profilerSamples.reduce( + (sum, sample) => sum + sample.baseDuration, + 0, + ) / profilerSamples.length, + rowModelCallsPerSecond: (rowModelCalls / sampleDuration) * 1_000, + rowModelAverageMs: + rowModelCalls === 0 ? 0 : rowModelDuration / rowModelCalls, + rowModelMaxMs: rowModelDiagnostics.maxDurationMs, + visibleRows: rowModelDiagnostics.lastRowCount, + } + + runtime.sampleStartedAt = now + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.profilerSamples = [] + runtime.previousRowModelCalls = rowModelDiagnostics.calls + runtime.previousRowModelDuration = rowModelDiagnostics.totalDurationMs + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.tableCommitsInSample = 0 + return metrics + } + + reset(): void { + const runtime = this.#runtime + runtime.sessionStartedAt = performance.now() + runtime.sampleStartedAt = runtime.sessionStartedAt + runtime.pendingCommitStartedAt = null + runtime.commitLatencySamples = [] + runtime.slowCommitCount = 0 + runtime.profilerSamples = [] + runtime.totalTicks = 0 + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.lastBatchSize = 0 + runtime.lastUpdateCount = 0 + runtime.workerMessages = 0 + runtime.frameTrackingStartedAt = runtime.sampleStartedAt + runtime.frameTimestamps = [] + runtime.tableCommitsInSample = 0 + runtime.longAnimationFrameCount = 0 + runtime.worstLongAnimationFrameMs = 0 + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.previousRowModelCalls = rowModelDiagnostics.calls + runtime.previousRowModelDuration = rowModelDiagnostics.totalDurationMs + rowModelDiagnostics.maxDurationMs = 0 + } +} + +export const longAnimationFramesSupported = + PerformanceObserver.supportedEntryTypes.includes('long-animation-frame') + +function readHeapSizeMb(): number | null { + const memory = ( + performance as Performance & { + memory?: { usedJSHeapSize: number } + } + ).memory + return memory ? memory.usedJSHeapSize / 1_048_576 : null +} + +function calculateInvocationRates( + current: Record, + previous: Record, + sampleDuration: number, +): ReadonlyArray { + return Object.entries(current).map(([name, calls]) => ({ + name, + callsPerSecond: + sampleDuration === 0 + ? 0 + : ((calls - (previous[name] ?? 0)) / sampleDuration) * 1_000, + })) +} + +function pruneLatencySamples( + samples: Array, + now: number, +): void { + const cutoff = now - percentileLatencyWindowMs + const firstRetainedIndex = samples.findIndex( + (sample) => sample.recordedAt >= cutoff, + ) + if (firstRetainedIndex > 0) samples.splice(0, firstRetainedIndex) + else if (firstRetainedIndex === -1) samples.length = 0 +} + +function pruneFrameTimestamps(timestamps: Array, now: number): void { + const cutoff = now - frameRateWindowMs + const firstRetainedIndex = timestamps.findIndex( + (timestamp) => timestamp >= cutoff, + ) + if (firstRetainedIndex > 0) timestamps.splice(0, firstRetainedIndex) + else if (firstRetainedIndex === -1) timestamps.length = 0 +} + +function calculateFrameRate( + timestamps: ReadonlyArray, + trackingStartedAt: number, + now: number, +): number { + const observedWindowMs = Math.min( + frameRateWindowMs, + Math.max(1, now - trackingStartedAt), + ) + return (timestamps.length / observedWindowMs) * 1_000 +} diff --git a/examples/react/realtime-trading/src/benchmark/trading-benchmark-controller.ts b/examples/react/realtime-trading/src/benchmark/trading-benchmark-controller.ts new file mode 100644 index 0000000000..995d87ff5c --- /dev/null +++ b/examples/react/realtime-trading/src/benchmark/trading-benchmark-controller.ts @@ -0,0 +1,154 @@ +import { batch, createAtom, createStore } from '@tanstack/react-store' +import { TRADING_COLUMN_COUNT } from '../table/trading-table' +import { FORCED_VIRTUALIZATION_ROW_COUNT } from '../table/trading-row-virtualizer' +import { + BenchmarkMonitor, + initialMetrics, + longAnimationFramesSupported, +} from './benchmark-monitor' +import type { FeedMetrics } from './benchmark-monitor' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { RendererMode } from '../table/trading-table' +import type { VirtualScrollPreference } from '../table/trading-row-virtualizer' + +export interface TradingBenchmarkState { + requestedVirtualScrollMode: VirtualScrollPreference + metrics: FeedMetrics + mountedCells: number + liveComponents: number + longAnimationFramesSupported: boolean +} + +export interface TradingBenchmarkActions { + resetViewState: () => void + setRendererMode: (mode: RendererMode) => void + setVirtualScrollEnabled: (enabled: boolean) => void + setRenderedRowCount: (count: number) => void + selectSymbol: (symbol: string | null) => void + resetMarket: () => void +} + +const initialState: TradingBenchmarkState = { + requestedVirtualScrollMode: 'auto', + metrics: initialMetrics, + mountedCells: 0, + liveComponents: 0, + longAnimationFramesSupported, +} + +export class TradingBenchmarkController { + readonly store = createStore(initialState) + readonly renderAtoms = { + selectedSymbol: createAtom(null), + rendererMode: createAtom('stable'), + } + readonly monitor = new BenchmarkMonitor() + readonly feed: MarketFeedController + readonly actions: TradingBenchmarkActions + + readonly #runtime = { + animationFrameId: 0, + longAnimationFrameObserver: null as PerformanceObserver | null, + stopObservingFeed: null as (() => void) | null, + } + + constructor(feed: MarketFeedController) { + this.feed = feed + this.actions = { + resetViewState: () => { + this.renderAtoms.selectedSymbol.set(null) + this.#patch({ requestedVirtualScrollMode: 'auto' }) + }, + setRendererMode: (mode) => { + this.renderAtoms.rendererMode.set(mode) + }, + setVirtualScrollEnabled: (enabled) => { + if ( + this.feed.instrumentCount.get() >= FORCED_VIRTUALIZATION_ROW_COUNT + ) { + return + } + this.#patch({ + requestedVirtualScrollMode: enabled ? 'tanstack' : 'none', + }) + }, + setRenderedRowCount: (count) => { + const mountedCells = count * TRADING_COLUMN_COUNT + if (mountedCells !== this.store.get().mountedCells) { + this.#patch({ mountedCells }) + } + }, + selectSymbol: (symbol) => { + this.renderAtoms.selectedSymbol.set(symbol) + }, + resetMarket: () => { + batch(() => { + this.monitor.reset() + this.store.setState((state) => ({ + ...state, + metrics: { ...initialMetrics }, + mountedCells: 0, + liveComponents: 0, + })) + this.renderAtoms.selectedSymbol.set(null) + this.feed.actions.reset() + }) + }, + } + } + + start(): () => void { + const longAnimationFrameObserver = longAnimationFramesSupported + ? new PerformanceObserver((entries) => { + for (const entry of entries.getEntries()) { + this.monitor.recordLongAnimationFrame( + entry.duration, + entry.startTime, + ) + } + }) + : null + + this.#runtime.longAnimationFrameObserver = longAnimationFrameObserver + this.#runtime.stopObservingFeed = this.feed.observe({ + messageReceived: () => this.monitor.recordWorkerMessage(), + mutationStarted: () => this.monitor.markCommitPending(), + batchApplied: ({ tickCount, updateCount, supersededUpdateCount }) => + this.monitor.recordBatch(tickCount, updateCount, supersededUpdateCount), + renderCommitted: () => this.monitor.recordDomCommit(), + }) + longAnimationFrameObserver?.observe({ + type: 'long-animation-frame', + }) + this.#runtime.animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + + return () => this.stop() + } + + stop(): void { + cancelAnimationFrame(this.#runtime.animationFrameId) + this.#runtime.longAnimationFrameObserver?.disconnect() + this.#runtime.stopObservingFeed?.() + this.#runtime.longAnimationFrameObserver = null + this.#runtime.stopObservingFeed = null + } + + readonly #benchmarkFrame = (now: number): void => { + this.monitor.recordAnimationFrame(now) + if (this.monitor.shouldPublish(now)) { + this.#publishMetrics(this.monitor.publish(now)) + } + this.#runtime.animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + } + + #patch(patch: Partial): void { + this.store.setState((state) => ({ ...state, ...patch })) + } + + #publishMetrics(metrics: FeedMetrics): void { + this.#patch({ + metrics, + liveComponents: metrics.componentsCreated - metrics.componentsDestroyed, + }) + } +} diff --git a/examples/react/realtime-trading/src/benchmark/use-table-benchmark.ts b/examples/react/realtime-trading/src/benchmark/use-table-benchmark.ts new file mode 100644 index 0000000000..bc335d2477 --- /dev/null +++ b/examples/react/realtime-trading/src/benchmark/use-table-benchmark.ts @@ -0,0 +1,28 @@ +import { useEffect } from 'react' +import type { TradingBenchmarkController } from './trading-benchmark-controller' + +export function useTableBenchmark( + controller: TradingBenchmarkController, +): void { + useEffect(() => { + const tableBody = document.querySelector( + '.market-panel [data-trading-table] tbody', + ) + if (!tableBody) { + return + } + + controller.monitor.resetDomMutations() + const observer = new MutationObserver((records) => { + controller.monitor.recordDomMutations(records.length) + }) + observer.observe(tableBody, { + attributes: true, + attributeFilter: ['class', 'style'], + characterData: true, + childList: true, + subtree: true, + }) + return () => observer.disconnect() + }, [controller]) +} diff --git a/examples/react/realtime-trading/src/benchmark/use-trading-benchmark-controller.ts b/examples/react/realtime-trading/src/benchmark/use-trading-benchmark-controller.ts new file mode 100644 index 0000000000..b163778419 --- /dev/null +++ b/examples/react/realtime-trading/src/benchmark/use-trading-benchmark-controller.ts @@ -0,0 +1,13 @@ +import { useEffect, useState } from 'react' +import { TradingBenchmarkController } from './trading-benchmark-controller' +import type { MarketFeedController } from '../feed/market-feed-controller' + +export function useTradingBenchmarkController(feed: MarketFeedController) { + const [controller] = useState(() => new TradingBenchmarkController(feed)) + + useEffect(() => controller.start(), [controller]) + + return controller +} + +export type { TradingBenchmarkController } from './trading-benchmark-controller' diff --git a/examples/react/realtime-trading/src/feed/feed-sample-rates.ts b/examples/react/realtime-trading/src/feed/feed-sample-rates.ts new file mode 100644 index 0000000000..17dc2015a6 --- /dev/null +++ b/examples/react/realtime-trading/src/feed/feed-sample-rates.ts @@ -0,0 +1,33 @@ +export const feedSampleRateOptions = [ + { label: '100', value: 100 }, + { label: '250', value: 250 }, + { label: '500', value: 500 }, + { label: '1K', value: 1_000 }, + { label: '2.5K', value: 2_500 }, + { label: '5K', value: 5_000 }, + { label: '10K', value: 10_000 }, + { label: '25K', value: 25_000 }, + { label: '50K', value: 50_000 }, + { label: '100K', value: 100_000 }, +] as const + +export function feedSampleRateIndex(rate: number): number { + return feedSampleRateOptions.reduce((closestIndex, candidate, index) => { + const closest = feedSampleRateOptions[closestIndex] + return Math.abs(candidate.value - rate) < Math.abs(closest.value - rate) + ? index + : closestIndex + }, 0) +} + +export function feedSampleRateAt(stepIndex: number): number { + const index = Math.min( + feedSampleRateOptions.length - 1, + Math.max(0, Math.round(stepIndex)), + ) + return feedSampleRateOptions[index].value +} + +export function normalizeFeedSampleRate(rate: number): number { + return feedSampleRateAt(feedSampleRateIndex(rate)) +} diff --git a/examples/react/realtime-trading/src/feed/market-data.ts b/examples/react/realtime-trading/src/feed/market-data.ts new file mode 100644 index 0000000000..6231865d3f --- /dev/null +++ b/examples/react/realtime-trading/src/feed/market-data.ts @@ -0,0 +1,38 @@ +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './worker/market-feed-protocol' + +export interface MarketQuote extends Omit { + history: ReadonlyArray +} + +export function hydrateMarketQuotes( + snapshots: Array, +): Array { + return snapshots.map((quote) => ({ + ...quote, + history: [...quote.history], + })) +} + +export function applyMarketUpdates( + quotes: Array, + updates: Array, +): Array { + const nextQuotes = [...quotes] + + for (const update of updates) { + const { index, history, ...values } = update + const previousQuote = quotes.at(index) + if (!previousQuote) continue + + nextQuotes[index] = { + ...previousQuote, + ...values, + history: history ?? previousQuote.history, + } + } + + return nextQuotes +} diff --git a/examples/react/realtime-trading/src/feed/market-feed-config.ts b/examples/react/realtime-trading/src/feed/market-feed-config.ts new file mode 100644 index 0000000000..9d477ed663 --- /dev/null +++ b/examples/react/realtime-trading/src/feed/market-feed-config.ts @@ -0,0 +1,15 @@ +export interface MarketFeedConfig { + readonly instrumentCount: number + readonly targetSamplesPerSecond: number + readonly publishIntervalMs: number + readonly updateSparklines: boolean + readonly sparklineSampleIntervalMs: number +} + +export const initialMarketFeedConfig: MarketFeedConfig = { + instrumentCount: 100, + targetSamplesPerSecond: 10_000, + publishIntervalMs: 20, + updateSparklines: true, + sparklineSampleIntervalMs: 16, +} diff --git a/examples/react/realtime-trading/src/feed/market-feed-controller.ts b/examples/react/realtime-trading/src/feed/market-feed-controller.ts new file mode 100644 index 0000000000..bcfc6c012f --- /dev/null +++ b/examples/react/realtime-trading/src/feed/market-feed-controller.ts @@ -0,0 +1,227 @@ +import { batch, createAtom } from '@tanstack/react-store' +import { normalizeFeedSampleRate } from './feed-sample-rates' +import { initialMarketFeedConfig } from './market-feed-config' +import { applyMarketUpdates, hydrateMarketQuotes } from './market-data' +import type { + MarketFeedCommand, + MarketFeedEvent, +} from './worker/market-feed-protocol' +import type { MarketQuote } from './market-data' + +export interface MarketFeedBatch { + tickCount: number + updateCount: number + supersededUpdateCount: number +} + +export interface MarketFeedObserver { + messageReceived?: () => void + mutationStarted?: () => void + batchApplied?: (batch: MarketFeedBatch) => void + renderCommitted?: () => void +} + +export interface MarketFeedActions { + toggle: () => void + setInstrumentCount: (count: number) => void + setTargetRate: (rate: number) => void + setPublishInterval: (intervalMs: number) => void + setSparklineUpdates: (enabled: boolean) => void + setSparklineSampleInterval: (intervalMs: number) => void + runBurst: () => void + reset: () => void +} + +export class MarketFeedController { + readonly workerReady = createAtom(false) + readonly running = createAtom( + !new URLSearchParams(location.search).has('paused'), + ) + readonly instrumentCount = createAtom(initialMarketFeedConfig.instrumentCount) + readonly targetTicksPerSecond = createAtom( + initialMarketFeedConfig.targetSamplesPerSecond, + ) + readonly publishIntervalMs = createAtom( + initialMarketFeedConfig.publishIntervalMs, + ) + readonly updateSparklines = createAtom( + initialMarketFeedConfig.updateSparklines, + ) + readonly sparklineSampleIntervalMs = createAtom( + initialMarketFeedConfig.sparklineSampleIntervalMs, + ) + readonly quotes = createAtom>([]) + readonly actions: MarketFeedActions + readonly #observers = new Set() + readonly #runtime = { + worker: null as Worker | null, + feedSessionId: 0, + renderPending: false, + resetWaitingForCommit: false, + resetSnapshotReady: false, + quoteIndexBySymbol: new Map(), + } + + constructor() { + this.actions = { + toggle: () => { + const running = !this.running.get() + this.running.set(running) + this.#post({ type: 'set-running', running }) + }, + setInstrumentCount: (count) => { + this.instrumentCount.set(count) + this.#resetWorker(count) + }, + setTargetRate: (rate) => { + const sampleRate = normalizeFeedSampleRate(rate) + this.targetTicksPerSecond.set(sampleRate) + this.#post({ type: 'set-rate', ticksPerSecond: sampleRate }) + }, + setPublishInterval: (publishIntervalMs) => { + this.publishIntervalMs.set(publishIntervalMs) + this.#post({ + type: 'set-publish-interval', + intervalMs: publishIntervalMs, + }) + }, + setSparklineUpdates: (enabled) => { + this.updateSparklines.set(enabled) + this.#post({ type: 'set-sparklines', enabled }) + }, + setSparklineSampleInterval: (intervalMs) => { + this.sparklineSampleIntervalMs.set(intervalMs) + this.#post({ type: 'set-sparkline-interval', intervalMs }) + }, + runBurst: () => this.#post({ type: 'burst', tickCount: 25_000 }), + reset: () => this.#resetWorker(this.instrumentCount.get()), + } + } + + start(): () => void { + const worker = new Worker( + new URL('./worker/market-feed.worker.ts', import.meta.url), + { type: 'module' }, + ) + this.#runtime.worker = worker + worker.addEventListener('message', this.#handleWorkerMessage) + worker.addEventListener('error', this.#handleWorkerError) + this.#post({ + type: 'start', + rowCount: this.instrumentCount.get(), + running: this.running.get(), + ticksPerSecond: this.targetTicksPerSecond.get(), + publishIntervalMs: this.publishIntervalMs.get(), + updateSparklines: this.updateSparklines.get(), + sparklineSampleIntervalMs: this.sparklineSampleIntervalMs.get(), + }) + return () => this.stop() + } + + stop(): void { + this.#runtime.worker?.removeEventListener( + 'message', + this.#handleWorkerMessage, + ) + this.#runtime.worker?.removeEventListener('error', this.#handleWorkerError) + this.#runtime.worker?.terminate() + this.#runtime.worker = null + this.#observers.clear() + } + + observe(observer: MarketFeedObserver): () => void { + this.#observers.add(observer) + return () => this.#observers.delete(observer) + } + + getQuoteBySymbol( + quotes: Array, + symbol: string | null, + ): MarketQuote | null { + if (symbol === null) return null + + const index = this.#runtime.quoteIndexBySymbol.get(symbol) + return index === undefined ? null : (quotes[index] ?? null) + } + + completeRender(): void { + if (!this.#runtime.renderPending) return + + this.#runtime.renderPending = false + for (const observer of this.#observers) { + observer.renderCommitted?.() + } + if ( + this.#runtime.resetWaitingForCommit && + this.#runtime.resetSnapshotReady + ) { + this.#runtime.resetWaitingForCommit = false + this.#runtime.resetSnapshotReady = false + this.#post({ type: 'set-running', running: this.running.get() }) + } + } + + readonly #handleWorkerMessage = ({ + data, + }: MessageEvent): void => { + if (data.type === 'snapshot') { + this.#runtime.feedSessionId = data.sessionId + if (this.#runtime.resetWaitingForCommit) { + this.#runtime.resetSnapshotReady = true + } + this.#startMutation() + const quotes = hydrateMarketQuotes(data.quotes) + this.#runtime.quoteIndexBySymbol = new Map( + quotes.map((quote, index) => [quote.symbol, index]), + ) + batch(() => { + this.quotes.set(quotes) + this.workerReady.set(true) + }) + return + } + + if (data.sessionId !== this.#runtime.feedSessionId) return + + for (const observer of this.#observers) { + observer.messageReceived?.() + } + this.#startMutation() + this.quotes.set(applyMarketUpdates(this.quotes.get(), data.updates)) + const feedBatch = { + tickCount: data.tickCount, + updateCount: data.updates.length, + supersededUpdateCount: data.coalescedUpdateCount, + } + for (const observer of this.#observers) { + observer.batchApplied?.(feedBatch) + } + } + + readonly #handleWorkerError = (error: ErrorEvent): void => { + batch(() => { + this.workerReady.set(false) + this.running.set(false) + }) + console.error('Market feed worker failed', error) + } + + #resetWorker(rowCount: number): void { + this.workerReady.set(false) + this.#runtime.resetWaitingForCommit = true + this.#runtime.resetSnapshotReady = false + this.#post({ type: 'set-running', running: false }) + this.#post({ type: 'reset', rowCount }) + } + + #startMutation(): void { + this.#runtime.renderPending = true + for (const observer of this.#observers) { + observer.mutationStarted?.() + } + } + + #post(command: MarketFeedCommand): void { + this.#runtime.worker?.postMessage(command) + } +} diff --git a/examples/react/realtime-trading/src/feed/market-instruments.ts b/examples/react/realtime-trading/src/feed/market-instruments.ts new file mode 100644 index 0000000000..ac18d14ea9 --- /dev/null +++ b/examples/react/realtime-trading/src/feed/market-instruments.ts @@ -0,0 +1,742 @@ +export type MarketCode = + | 'US' + | 'NL' + | 'DE' + | 'FR' + | 'IT' + | 'ES' + | 'CH' + | 'DK' + | 'SE' + | 'FI' + | 'GB' + | 'KR' + | 'JP' + | 'HK' + | 'CA' + | 'AU' + +export type BaseInstrument = readonly [ + symbol: string, + company: string, + market: MarketCode, +] + +/** + * Current S&P 500 constituent universe used by the realtime trading examples. + * + * Source snapshot: https://github.com/datasets/s-and-p-500-companies + * Retrieved: 2026-08-15. + * Multiple share classes are intentionally represented as separate instruments. + */ +export const marketInstruments = Object.freeze([ + ['MMM', '3M', 'US'], + ['AOS', 'A. O. Smith', 'US'], + ['ABT', 'Abbott Laboratories', 'US'], + ['ABBV', 'AbbVie', 'US'], + ['ACN', 'Accenture', 'US'], + ['ADBE', 'Adobe Inc.', 'US'], + ['AMD', 'Advanced Micro Devices', 'US'], + ['AES', 'AES Corporation', 'US'], + ['AFL', 'Aflac', 'US'], + ['A', 'Agilent Technologies', 'US'], + ['APD', 'Air Products', 'US'], + ['ABNB', 'Airbnb', 'US'], + ['AKAM', 'Akamai Technologies', 'US'], + ['ALB', 'Albemarle Corporation', 'US'], + ['ARE', 'Alexandria Real Estate Equities', 'US'], + ['ALGN', 'Align Technology', 'US'], + ['ALLE', 'Allegion', 'US'], + ['LNT', 'Alliant Energy', 'US'], + ['ALL', 'Allstate', 'US'], + ['GOOGL', 'Alphabet Inc. (Class A)', 'US'], + ['GOOG', 'Alphabet Inc. (Class C)', 'US'], + ['MO', 'Altria', 'US'], + ['AMZN', 'Amazon', 'US'], + ['AMCR', 'Amcor', 'US'], + ['AEE', 'Ameren', 'US'], + ['AEP', 'American Electric Power', 'US'], + ['AXP', 'American Express', 'US'], + ['AIG', 'American International Group', 'US'], + ['AMT', 'American Tower', 'US'], + ['AWK', 'American Water Works', 'US'], + ['AMP', 'Ameriprise Financial', 'US'], + ['AME', 'Ametek', 'US'], + ['AMGN', 'Amgen', 'US'], + ['APH', 'Amphenol', 'US'], + ['ADI', 'Analog Devices', 'US'], + ['AON', 'Aon plc', 'US'], + ['APA', 'APA Corporation', 'US'], + ['APO', 'Apollo Global Management', 'US'], + ['AAPL', 'Apple Inc.', 'US'], + ['AMAT', 'Applied Materials', 'US'], + ['APP', 'AppLovin', 'US'], + ['APTV', 'Aptiv', 'US'], + ['ACGL', 'Arch Capital Group', 'US'], + ['ADM', 'Archer Daniels Midland', 'US'], + ['ARES', 'Ares Management', 'US'], + ['ANET', 'Arista Networks', 'US'], + ['AJG', 'Arthur J. Gallagher & Co.', 'US'], + ['AIZ', 'Assurant', 'US'], + ['T', 'AT&T', 'US'], + ['ATO', 'Atmos Energy', 'US'], + ['ADSK', 'Autodesk', 'US'], + ['ADP', 'Automatic Data Processing', 'US'], + ['AZO', 'AutoZone', 'US'], + ['AVB', 'AvalonBay Communities', 'US'], + ['AVY', 'Avery Dennison', 'US'], + ['AXON', 'Axon Enterprise', 'US'], + ['BKR', 'Baker Hughes', 'US'], + ['BALL', 'Ball Corporation', 'US'], + ['BAC', 'Bank of America', 'US'], + ['BAX', 'Baxter International', 'US'], + ['BDX', 'Becton Dickinson', 'US'], + ['BRK.B', 'Berkshire Hathaway', 'US'], + ['BBY', 'Best Buy', 'US'], + ['TECH', 'Bio-Techne', 'US'], + ['BIIB', 'Biogen', 'US'], + ['BLK', 'BlackRock', 'US'], + ['BX', 'Blackstone Inc.', 'US'], + ['XYZ', 'Block, Inc.', 'US'], + ['BNY', 'BNY Mellon', 'US'], + ['BA', 'Boeing', 'US'], + ['BKNG', 'Booking Holdings', 'US'], + ['BSX', 'Boston Scientific', 'US'], + ['BMY', 'Bristol Myers Squibb', 'US'], + ['AVGO', 'Broadcom', 'US'], + ['BR', 'Broadridge Financial Solutions', 'US'], + ['BRO', 'Brown & Brown', 'US'], + ['BF.B', 'Brown–Forman', 'US'], + ['BLDR', 'Builders FirstSource', 'US'], + ['BG', 'Bunge Global', 'US'], + ['BXP', 'BXP, Inc.', 'US'], + ['CHRW', 'C.H. Robinson', 'US'], + ['CDNS', 'Cadence Design Systems', 'US'], + ['CPT', 'Camden Property Trust', 'US'], + ['COF', 'Capital One', 'US'], + ['CAH', 'Cardinal Health', 'US'], + ['CCL', 'Carnival Corporation', 'US'], + ['CARR', 'Carrier Global', 'US'], + ['CVNA', 'Carvana', 'US'], + ['CASY', "Casey's", 'US'], + ['CAT', 'Caterpillar Inc.', 'US'], + ['CBOE', 'Cboe Global Markets', 'US'], + ['CBRE', 'CBRE Group', 'US'], + ['CDW', 'CDW Corporation', 'US'], + ['COR', 'Cencora', 'US'], + ['CNC', 'Centene Corporation', 'US'], + ['CNP', 'CenterPoint Energy', 'US'], + ['CF', 'CF Industries', 'US'], + ['CRL', 'Charles River Laboratories', 'US'], + ['SCHW', 'Charles Schwab Corporation', 'US'], + ['CHTR', 'Charter Communications', 'US'], + ['CVX', 'Chevron Corporation', 'US'], + ['CMG', 'Chipotle Mexican Grill', 'US'], + ['CB', 'Chubb Limited', 'US'], + ['CHD', 'Church & Dwight', 'US'], + ['CIEN', 'Ciena', 'US'], + ['CI', 'Cigna', 'US'], + ['CINF', 'Cincinnati Financial', 'US'], + ['CTAS', 'Cintas', 'US'], + ['CSCO', 'Cisco', 'US'], + ['C', 'Citigroup', 'US'], + ['CFG', 'Citizens Financial Group', 'US'], + ['CLX', 'Clorox', 'US'], + ['CME', 'CME Group', 'US'], + ['CMS', 'CMS Energy', 'US'], + ['KO', 'Coca-Cola Company (The)', 'US'], + ['CTSH', 'Cognizant', 'US'], + ['COHR', 'Coherent Corp.', 'US'], + ['COIN', 'Coinbase', 'US'], + ['CL', 'Colgate-Palmolive', 'US'], + ['CMCSA', 'Comcast', 'US'], + ['FIX', 'Comfort Systems USA', 'US'], + ['COP', 'ConocoPhillips', 'US'], + ['ED', 'Consolidated Edison', 'US'], + ['STZ', 'Constellation Brands', 'US'], + ['CEG', 'Constellation Energy', 'US'], + ['COO', 'Cooper Companies (The)', 'US'], + ['CPRT', 'Copart', 'US'], + ['GLW', 'Corning Inc.', 'US'], + ['CPAY', 'Corpay', 'US'], + ['CTVA', 'Corteva', 'US'], + ['CSGP', 'CoStar Group', 'US'], + ['COST', 'Costco', 'US'], + ['CRH', 'CRH plc', 'US'], + ['CRWD', 'CrowdStrike', 'US'], + ['CCI', 'Crown Castle', 'US'], + ['CSX', 'CSX Corporation', 'US'], + ['CMI', 'Cummins', 'US'], + ['CVS', 'CVS Health', 'US'], + ['DHR', 'Danaher Corporation', 'US'], + ['DRI', 'Darden Restaurants', 'US'], + ['DDOG', 'Datadog', 'US'], + ['DVA', 'DaVita', 'US'], + ['DECK', 'Deckers Brands', 'US'], + ['DE', 'Deere & Company', 'US'], + ['DELL', 'Dell Technologies', 'US'], + ['DAL', 'Delta Air Lines', 'US'], + ['DVN', 'Devon Energy', 'US'], + ['DXCM', 'Dexcom', 'US'], + ['FANG', 'Diamondback Energy', 'US'], + ['DLR', 'Digital Realty', 'US'], + ['DG', 'Dollar General', 'US'], + ['DLTR', 'Dollar Tree', 'US'], + ['D', 'Dominion Energy', 'US'], + ['DPZ', "Domino's", 'US'], + ['DASH', 'DoorDash', 'US'], + ['DOV', 'Dover Corporation', 'US'], + ['DOW', 'Dow Inc.', 'US'], + ['DHI', 'D. R. Horton', 'US'], + ['DTE', 'DTE Energy', 'US'], + ['DUK', 'Duke Energy', 'US'], + ['DD', 'DuPont', 'US'], + ['ETN', 'Eaton Corporation', 'US'], + ['EBAY', 'eBay Inc.', 'US'], + ['ECHO', 'EchoStar', 'US'], + ['ECL', 'Ecolab', 'US'], + ['EIX', 'Edison International', 'US'], + ['EW', 'Edwards Lifesciences', 'US'], + ['ELV', 'Elevance Health', 'US'], + ['EME', 'Emcor', 'US'], + ['EMR', 'Emerson Electric', 'US'], + ['ETR', 'Entergy', 'US'], + ['EOG', 'EOG Resources', 'US'], + ['EQT', 'EQT Corporation', 'US'], + ['EFX', 'Equifax', 'US'], + ['EQIX', 'Equinix', 'US'], + ['EQR', 'Equity Residential', 'US'], + ['ERIE', 'Erie Indemnity', 'US'], + ['ESS', 'Essex Property Trust', 'US'], + ['EL', 'Estée Lauder Companies (The)', 'US'], + ['EG', 'Everest Group', 'US'], + ['EVRG', 'Evergy', 'US'], + ['ES', 'Eversource Energy', 'US'], + ['EXC', 'Exelon', 'US'], + ['EXE', 'Expand Energy', 'US'], + ['EXPE', 'Expedia Group', 'US'], + ['EXPD', 'Expeditors International', 'US'], + ['EXR', 'Extra Space Storage', 'US'], + ['XOM', 'ExxonMobil', 'US'], + ['FFIV', 'F5, Inc.', 'US'], + ['FDS', 'FactSet', 'US'], + ['FICO', 'Fair Isaac', 'US'], + ['FAST', 'Fastenal', 'US'], + ['FRT', 'Federal Realty Investment Trust', 'US'], + ['FDX', 'FedEx', 'US'], + ['FDXF', 'FedEx Freight', 'US'], + ['FERG', 'Ferguson Enterprises', 'US'], + ['FIS', 'Fidelity National Information Services', 'US'], + ['FITB', 'Fifth Third Bancorp', 'US'], + ['FSLR', 'First Solar', 'US'], + ['FE', 'FirstEnergy', 'US'], + ['FISV', 'Fiserv', 'US'], + ['FLEX', 'Flex Ltd.', 'US'], + ['F', 'Ford Motor Company', 'US'], + ['FTNT', 'Fortinet', 'US'], + ['FTV', 'Fortive', 'US'], + ['FOXA', 'Fox Corporation (Class A)', 'US'], + ['FOX', 'Fox Corporation (Class B)', 'US'], + ['BEN', 'Franklin Resources', 'US'], + ['FCX', 'Freeport-McMoRan', 'US'], + ['GRMN', 'Garmin', 'US'], + ['IT', 'Gartner', 'US'], + ['GE', 'GE Aerospace', 'US'], + ['GEHC', 'GE HealthCare', 'US'], + ['GEV', 'GE Vernova', 'US'], + ['GEN', 'Gen Digital', 'US'], + ['GNRC', 'Generac', 'US'], + ['GD', 'General Dynamics', 'US'], + ['GIS', 'General Mills', 'US'], + ['GM', 'General Motors', 'US'], + ['GPC', 'Genuine Parts Company', 'US'], + ['GILD', 'Gilead Sciences', 'US'], + ['GPN', 'Global Payments', 'US'], + ['GL', 'Globe Life', 'US'], + ['GDDY', 'GoDaddy', 'US'], + ['GS', 'Goldman Sachs', 'US'], + ['HAL', 'Halliburton', 'US'], + ['HIG', 'Hartford (The)', 'US'], + ['HAS', 'Hasbro', 'US'], + ['HCA', 'HCA Healthcare', 'US'], + ['DOC', 'Healthpeak Properties', 'US'], + ['HSIC', 'Henry Schein', 'US'], + ['HSY', 'Hershey Company (The)', 'US'], + ['HPE', 'Hewlett Packard Enterprise', 'US'], + ['HLT', 'Hilton Worldwide', 'US'], + ['HD', 'Home Depot (The)', 'US'], + ['HONA', 'Honeywell Aerospace', 'US'], + ['HON', 'Honeywell Technologies', 'US'], + ['HRL', 'Hormel Foods', 'US'], + ['HST', 'Host Hotels & Resorts', 'US'], + ['HWM', 'Howmet Aerospace', 'US'], + ['HPQ', 'HP Inc.', 'US'], + ['HUBB', 'Hubbell Incorporated', 'US'], + ['HUM', 'Humana', 'US'], + ['HBAN', 'Huntington Bancshares', 'US'], + ['HII', 'Huntington Ingalls Industries', 'US'], + ['IBM', 'IBM', 'US'], + ['IEX', 'IDEX Corporation', 'US'], + ['IDXX', 'Idexx Laboratories', 'US'], + ['ITW', 'Illinois Tool Works', 'US'], + ['INCY', 'Incyte', 'US'], + ['IR', 'Ingersoll Rand', 'US'], + ['PODD', 'Insulet Corporation', 'US'], + ['INTC', 'Intel', 'US'], + ['IBKR', 'Interactive Brokers', 'US'], + ['ICE', 'Intercontinental Exchange', 'US'], + ['IFF', 'International Flavors & Fragrances', 'US'], + ['IP', 'International Paper', 'US'], + ['INTU', 'Intuit', 'US'], + ['ISRG', 'Intuitive Surgical', 'US'], + ['IVZ', 'Invesco', 'US'], + ['INVH', 'Invitation Homes', 'US'], + ['IQV', 'IQVIA', 'US'], + ['IRM', 'Iron Mountain', 'US'], + ['JBHT', 'J.B. Hunt', 'US'], + ['JBL', 'Jabil', 'US'], + ['JKHY', 'Jack Henry & Associates', 'US'], + ['J', 'Jacobs Solutions', 'US'], + ['JNJ', 'Johnson & Johnson', 'US'], + ['JCI', 'Johnson Controls', 'US'], + ['JPM', 'JPMorgan Chase', 'US'], + ['KVUE', 'Kenvue', 'US'], + ['KDP', 'Keurig Dr Pepper', 'US'], + ['KEY', 'KeyCorp', 'US'], + ['KEYS', 'Keysight Technologies', 'US'], + ['KMB', 'Kimberly-Clark', 'US'], + ['KIM', 'Kimco Realty', 'US'], + ['KMI', 'Kinder Morgan', 'US'], + ['KKR', 'KKR & Co.', 'US'], + ['KLAC', 'KLA Corporation', 'US'], + ['KHC', 'Kraft Heinz', 'US'], + ['KR', 'Kroger', 'US'], + ['LHX', 'L3Harris', 'US'], + ['LH', 'Labcorp', 'US'], + ['LRCX', 'Lam Research', 'US'], + ['LVS', 'Las Vegas Sands', 'US'], + ['LDOS', 'Leidos', 'US'], + ['LEN', 'Lennar', 'US'], + ['LII', 'Lennox International', 'US'], + ['LLY', 'Lilly (Eli)', 'US'], + ['LIN', 'Linde plc', 'US'], + ['LYV', 'Live Nation Entertainment', 'US'], + ['LMT', 'Lockheed Martin', 'US'], + ['L', 'Loews Corporation', 'US'], + ['LOW', "Lowe's", 'US'], + ['LULU', 'Lululemon Athletica', 'US'], + ['LITE', 'Lumentum', 'US'], + ['LYB', 'LyondellBasell', 'US'], + ['MTB', 'M&T Bank', 'US'], + ['MPC', 'Marathon Petroleum', 'US'], + ['MAR', 'Marriott International', 'US'], + ['MRSH', 'Marsh McLennan', 'US'], + ['MLM', 'Martin Marietta Materials', 'US'], + ['MRVL', 'Marvell Technology', 'US'], + ['MAS', 'Masco', 'US'], + ['MA', 'Mastercard', 'US'], + ['MKC', 'McCormick & Company', 'US'], + ['MCD', "McDonald's", 'US'], + ['MCK', 'McKesson Corporation', 'US'], + ['MDT', 'Medtronic', 'US'], + ['MRK', 'Merck & Co.', 'US'], + ['META', 'Meta Platforms', 'US'], + ['MET', 'MetLife', 'US'], + ['MTD', 'Mettler Toledo', 'US'], + ['MGM', 'MGM Resorts', 'US'], + ['MCHP', 'Microchip Technology', 'US'], + ['MU', 'Micron Technology', 'US'], + ['MSFT', 'Microsoft', 'US'], + ['MAA', 'Mid-America Apartment Communities', 'US'], + ['MRNA', 'Moderna', 'US'], + ['TAP', 'Molson Coors Beverage Company', 'US'], + ['MDLZ', 'Mondelez International', 'US'], + ['MPWR', 'Monolithic Power Systems', 'US'], + ['MNST', 'Monster Beverage', 'US'], + ['MCO', "Moody's Corporation", 'US'], + ['MS', 'Morgan Stanley', 'US'], + ['MOS', 'Mosaic Company (The)', 'US'], + ['MSI', 'Motorola Solutions', 'US'], + ['MSCI', 'MSCI', 'US'], + ['NDAQ', 'Nasdaq, Inc.', 'US'], + ['NTAP', 'NetApp', 'US'], + ['NFLX', 'Netflix', 'US'], + ['NEM', 'Newmont', 'US'], + ['NWSA', 'News Corp (Class A)', 'US'], + ['NWS', 'News Corp (Class B)', 'US'], + ['NEE', 'NextEra Energy', 'US'], + ['NKE', 'Nike, Inc.', 'US'], + ['NI', 'NiSource', 'US'], + ['NDSN', 'Nordson Corporation', 'US'], + ['NSC', 'Norfolk Southern', 'US'], + ['NTRS', 'Northern Trust', 'US'], + ['NOC', 'Northrop Grumman', 'US'], + ['NCLH', 'Norwegian Cruise Line Holdings', 'US'], + ['NRG', 'NRG Energy', 'US'], + ['NUE', 'Nucor', 'US'], + ['NVDA', 'Nvidia', 'US'], + ['NVR', 'NVR, Inc.', 'US'], + ['NXPI', 'NXP Semiconductors', 'US'], + ['ORLY', "O'Reilly Automotive", 'US'], + ['OXY', 'Occidental Petroleum', 'US'], + ['ODFL', 'Old Dominion', 'US'], + ['OMC', 'Omnicom Group', 'US'], + ['ON', 'ON Semiconductor', 'US'], + ['OKE', 'Oneok', 'US'], + ['ORCL', 'Oracle Corporation', 'US'], + ['OTIS', 'Otis Worldwide', 'US'], + ['PCAR', 'Paccar', 'US'], + ['PKG', 'Packaging Corporation of America', 'US'], + ['PLTR', 'Palantir Technologies', 'US'], + ['PANW', 'Palo Alto Networks', 'US'], + ['PSKY', 'Paramount Skydance Corporation', 'US'], + ['PH', 'Parker Hannifin', 'US'], + ['PAYX', 'Paychex', 'US'], + ['PYPL', 'PayPal', 'US'], + ['PNR', 'Pentair', 'US'], + ['PEP', 'PepsiCo', 'US'], + ['PFE', 'Pfizer', 'US'], + ['PCG', 'PG&E Corporation', 'US'], + ['PM', 'Philip Morris International', 'US'], + ['PSX', 'Phillips 66', 'US'], + ['PNW', 'Pinnacle West Capital', 'US'], + ['PNC', 'PNC Financial Services', 'US'], + ['PPG', 'PPG Industries', 'US'], + ['PPL', 'PPL Corporation', 'US'], + ['PFG', 'Principal Financial Group', 'US'], + ['PG', 'Procter & Gamble', 'US'], + ['PGR', 'Progressive Corporation', 'US'], + ['PLD', 'Prologis', 'US'], + ['PRU', 'Prudential Financial', 'US'], + ['PEG', 'Public Service Enterprise Group', 'US'], + ['PTC', 'PTC Inc.', 'US'], + ['PSA', 'Public Storage', 'US'], + ['PHM', 'PulteGroup', 'US'], + ['PWR', 'Quanta Services', 'US'], + ['QCOM', 'Qualcomm', 'US'], + ['DGX', 'Quest Diagnostics', 'US'], + ['Q', 'Qnity Electronics', 'US'], + ['RL', 'Ralph Lauren Corporation', 'US'], + ['RJF', 'Raymond James Financial', 'US'], + ['RTX', 'RTX Corporation', 'US'], + ['O', 'Realty Income', 'US'], + ['REG', 'Regency Centers', 'US'], + ['REGN', 'Regeneron Pharmaceuticals', 'US'], + ['RF', 'Regions Financial Corporation', 'US'], + ['RSG', 'Republic Services', 'US'], + ['RMD', 'ResMed|', 'US'], + ['RVTY', 'Revvity', 'US'], + ['HOOD', 'Robinhood Markets', 'US'], + ['ROK', 'Rockwell Automation', 'US'], + ['ROL', 'Rollins, Inc.', 'US'], + ['ROP', 'Roper Technologies', 'US'], + ['ROST', 'Ross Stores', 'US'], + ['RCL', 'Royal Caribbean Group', 'US'], + ['SPGI', 'S&P Global', 'US'], + ['CRM', 'Salesforce', 'US'], + ['SNDK', 'Sandisk', 'US'], + ['SBAC', 'SBA Communications', 'US'], + ['SLB', 'Schlumberger', 'US'], + ['STX', 'Seagate Technology', 'US'], + ['SRE', 'Sempra', 'US'], + ['NOW', 'ServiceNow', 'US'], + ['SHW', 'Sherwin-Williams', 'US'], + ['SPG', 'Simon Property Group', 'US'], + ['SWKS', 'Skyworks Solutions', 'US'], + ['SJM', 'J.M. Smucker Company (The)', 'US'], + ['SW', 'Smurfit Westrock', 'US'], + ['SNA', 'Snap-on', 'US'], + ['SOLV', 'Solventum', 'US'], + ['SO', 'Southern Company', 'US'], + ['LUV', 'Southwest Airlines', 'US'], + ['SWK', 'Stanley Black & Decker', 'US'], + ['SBUX', 'Starbucks', 'US'], + ['STT', 'State Street Corporation', 'US'], + ['STLD', 'Steel Dynamics', 'US'], + ['STE', 'Steris', 'US'], + ['SYK', 'Stryker Corporation', 'US'], + ['SMCI', 'Supermicro', 'US'], + ['SYF', 'Synchrony Financial', 'US'], + ['SNPS', 'Synopsys', 'US'], + ['SYY', 'Sysco', 'US'], + ['TMUS', 'T-Mobile US', 'US'], + ['TROW', 'T. Rowe Price', 'US'], + ['TTWO', 'Take-Two Interactive', 'US'], + ['TPR', 'Tapestry, Inc.', 'US'], + ['TRGP', 'Targa Resources', 'US'], + ['TGT', 'Target Corporation', 'US'], + ['TEL', 'TE Connectivity', 'US'], + ['TDY', 'Teledyne Technologies', 'US'], + ['TER', 'Teradyne', 'US'], + ['TSLA', 'Tesla, Inc.', 'US'], + ['TXN', 'Texas Instruments', 'US'], + ['TPL', 'Texas Pacific Land Corporation', 'US'], + ['TXT', 'Textron', 'US'], + ['TMO', 'Thermo Fisher Scientific', 'US'], + ['TJX', 'TJX Companies', 'US'], + ['TKO', 'TKO Group Holdings', 'US'], + ['TTD', 'Trade Desk (The)', 'US'], + ['TSCO', 'Tractor Supply', 'US'], + ['TT', 'Trane Technologies', 'US'], + ['TDG', 'TransDigm Group', 'US'], + ['TRV', 'Travelers Companies (The)', 'US'], + ['TRMB', 'Trimble Inc.', 'US'], + ['TFC', 'Truist Financial', 'US'], + ['TYL', 'Tyler Technologies', 'US'], + ['TSN', 'Tyson Foods', 'US'], + ['USB', 'U.S. Bancorp', 'US'], + ['UBER', 'Uber', 'US'], + ['UDR', 'UDR, Inc.', 'US'], + ['ULTA', 'Ulta Beauty', 'US'], + ['UNP', 'Union Pacific Corporation', 'US'], + ['UAL', 'United Airlines Holdings', 'US'], + ['UPS', 'United Parcel Service', 'US'], + ['URI', 'United Rentals', 'US'], + ['UNH', 'UnitedHealth Group', 'US'], + ['UHS', 'Universal Health Services', 'US'], + ['VLO', 'Valero Energy', 'US'], + ['VEEV', 'Veeva Systems', 'US'], + ['VTR', 'Ventas', 'US'], + ['VLTO', 'Veralto', 'US'], + ['VRSN', 'Verisign', 'US'], + ['VRSK', 'Verisk Analytics', 'US'], + ['VZ', 'Verizon', 'US'], + ['VRTX', 'Vertex Pharmaceuticals', 'US'], + ['VRT', 'Vertiv', 'US'], + ['VTRS', 'Viatris', 'US'], + ['VICI', 'Vici Properties', 'US'], + ['V', 'Visa Inc.', 'US'], + ['VST', 'Vistra Corp.', 'US'], + ['VMC', 'Vulcan Materials Company', 'US'], + ['WRB', 'W. R. Berkley Corporation', 'US'], + ['GWW', 'W. W. Grainger', 'US'], + ['WAB', 'Wabtec', 'US'], + ['WMT', 'Walmart', 'US'], + ['DIS', 'Walt Disney Company (The)', 'US'], + ['WBD', 'Warner Bros. Discovery', 'US'], + ['WM', 'Waste Management', 'US'], + ['WAT', 'Waters Corporation', 'US'], + ['WEC', 'WEC Energy Group', 'US'], + ['WFC', 'Wells Fargo', 'US'], + ['WELL', 'Welltower', 'US'], + ['WST', 'West Pharmaceutical Services', 'US'], + ['WDC', 'Western Digital', 'US'], + ['WY', 'Weyerhaeuser', 'US'], + ['WSM', 'Williams-Sonoma, Inc.', 'US'], + ['WMB', 'Williams Companies', 'US'], + ['WTW', 'Willis Towers Watson', 'US'], + ['WDAY', 'Workday, Inc.', 'US'], + ['WYNN', 'Wynn Resorts', 'US'], + ['XEL', 'Xcel Energy', 'US'], + ['XYL', 'Xylem Inc.', 'US'], + ['YUM', 'Yum! Brands', 'US'], + ['ZBRA', 'Zebra Technologies', 'US'], + ['ZBH', 'Zimmer Biomet', 'US'], + ['ZTS', 'Zoetis', 'US'], +]) + +/** + * Representative liquid international listings used to diversify the fixture. + * Symbols use their local-market form and the third tuple value is an ISO-style + * country/market code, rather than a trading currency or exchange MIC. + * + * References checked 2026-08-15: STOXX Europe 50, KRX KOSPI market, + * JPX TOPIX Core30, and HKEX index constituent materials. + */ +const europeanInstruments = Object.freeze([ + ['ASML', 'ASML Holding', 'NL'], + ['INGA', 'ING Group', 'NL'], + ['ADYEN', 'Adyen', 'NL'], + ['PHIA', 'Philips', 'NL'], + ['HEIA', 'Heineken', 'NL'], + ['SAP', 'SAP', 'DE'], + ['SIE', 'Siemens', 'DE'], + ['ALV', 'Allianz', 'DE'], + ['DTE', 'Deutsche Telekom', 'DE'], + ['MBG', 'Mercedes-Benz Group', 'DE'], + ['BMW', 'BMW', 'DE'], + ['BAS', 'BASF', 'DE'], + ['MUV2', 'Munich Re', 'DE'], + ['VOW3', 'Volkswagen Preference', 'DE'], + ['IFX', 'Infineon Technologies', 'DE'], + ['MC', 'LVMH', 'FR'], + ['OR', "L'Oréal", 'FR'], + ['AIR', 'Airbus', 'FR'], + ['SU', 'Schneider Electric', 'FR'], + ['TTE', 'TotalEnergies', 'FR'], + ['SAN', 'Sanofi', 'FR'], + ['BNP', 'BNP Paribas', 'FR'], + ['CS', 'AXA', 'FR'], + ['DG', 'Vinci', 'FR'], + ['ENEL', 'Enel', 'IT'], + ['ENI', 'Eni', 'IT'], + ['ISP', 'Intesa Sanpaolo', 'IT'], + ['UCG', 'UniCredit', 'IT'], + ['STLAM', 'Stellantis', 'IT'], + ['SAN', 'Banco Santander', 'ES'], + ['IBE', 'Iberdrola', 'ES'], + ['ITX', 'Inditex', 'ES'], + ['BBVA', 'BBVA', 'ES'], + ['NESN', 'Nestlé', 'CH'], + ['ROG', 'Roche Holding', 'CH'], + ['NOVN', 'Novartis', 'CH'], + ['UBSG', 'UBS Group', 'CH'], + ['NOVO-B', 'Novo Nordisk', 'DK'], + ['MAERSK-B', 'A.P. Moller - Maersk', 'DK'], + ['VOLV-B', 'Volvo', 'SE'], + ['ERIC-B', 'Ericsson', 'SE'], + ['NOKIA', 'Nokia', 'FI'], + ['SHEL', 'Shell', 'GB'], + ['AZN', 'AstraZeneca', 'GB'], + ['HSBA', 'HSBC Holdings', 'GB'], + ['ULVR', 'Unilever', 'GB'], + ['LSEG', 'London Stock Exchange Group', 'GB'], +]) + +const europeanMarketCodes = Object.freeze([ + 'NL', + 'DE', + 'FR', + 'IT', + 'ES', + 'CH', + 'DK', + 'SE', + 'FI', + 'GB', +]) + +const europeanMarketGroups = Object.freeze( + europeanMarketCodes.map((market) => + europeanInstruments.filter(([, , instrumentMarket]) => + Object.is(instrumentMarket, market), + ), + ), +) + +const interleavedEuropeanInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...europeanMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + europeanMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const southKoreanInstruments = Object.freeze([ + ['005930', 'Samsung Electronics', 'KR'], + ['000660', 'SK hynix', 'KR'], + ['373220', 'LG Energy Solution', 'KR'], + ['207940', 'Samsung Biologics', 'KR'], + ['005380', 'Hyundai Motor', 'KR'], + ['000270', 'Kia', 'KR'], + ['068270', 'Celltrion', 'KR'], + ['105560', 'KB Financial Group', 'KR'], + ['055550', 'Shinhan Financial Group', 'KR'], + ['035420', 'NAVER', 'KR'], + ['035720', 'Kakao', 'KR'], + ['006400', 'Samsung SDI', 'KR'], + ['051910', 'LG Chem', 'KR'], + ['012330', 'Hyundai Mobis', 'KR'], + ['066570', 'LG Electronics', 'KR'], +]) + +const japaneseInstruments = Object.freeze([ + ['8306', 'Mitsubishi UFJ Financial Group', 'JP'], + ['7203', 'Toyota Motor', 'JP'], + ['6501', 'Hitachi', 'JP'], + ['8316', 'Sumitomo Mitsui Financial Group', 'JP'], + ['6758', 'Sony Group', 'JP'], + ['8058', 'Mitsubishi Corporation', 'JP'], + ['9984', 'SoftBank Group', 'JP'], + ['8035', 'Tokyo Electron', 'JP'], + ['8411', 'Mizuho Financial Group', 'JP'], + ['8031', 'Mitsui & Co.', 'JP'], + ['6861', 'Keyence', 'JP'], + ['7974', 'Nintendo', 'JP'], + ['6098', 'Recruit Holdings', 'JP'], + ['9432', 'Nippon Telegraph and Telephone', 'JP'], + ['4063', 'Shin-Etsu Chemical', 'JP'], +]) + +const hongKongInstruments = Object.freeze([ + ['0700', 'Tencent Holdings', 'HK'], + ['9988', 'Alibaba Group', 'HK'], + ['1810', 'Xiaomi', 'HK'], + ['3690', 'Meituan', 'HK'], + ['0941', 'China Mobile', 'HK'], + ['1211', 'BYD Company', 'HK'], + ['1299', 'AIA Group', 'HK'], + ['0388', 'Hong Kong Exchanges and Clearing', 'HK'], + ['0005', 'HSBC Holdings', 'HK'], + ['2318', 'Ping An Insurance', 'HK'], +]) + +const canadianInstruments = Object.freeze([ + ['RY', 'Royal Bank of Canada', 'CA'], + ['TD', 'Toronto-Dominion Bank', 'CA'], + ['SHOP', 'Shopify', 'CA'], + ['ENB', 'Enbridge', 'CA'], + ['CNR', 'Canadian National Railway', 'CA'], + ['CP', 'Canadian Pacific Kansas City', 'CA'], + ['BMO', 'Bank of Montreal', 'CA'], + ['CSU', 'Constellation Software', 'CA'], +]) + +const australianInstruments = Object.freeze([ + ['BHP', 'BHP Group', 'AU'], + ['CBA', 'Commonwealth Bank of Australia', 'AU'], + ['CSL', 'CSL', 'AU'], + ['NAB', 'National Australia Bank', 'AU'], + ['WBC', 'Westpac Banking Corporation', 'AU'], + ['ANZ', 'ANZ Group Holdings', 'AU'], + ['WES', 'Wesfarmers', 'AU'], + ['MQG', 'Macquarie Group', 'AU'], +]) + +const internationalMarketGroups = Object.freeze([ + interleavedEuropeanInstruments, + southKoreanInstruments, + japaneseInstruments, + hongKongInstruments, + canadianInstruments, + australianInstruments, +]) + +export const internationalInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...internationalMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + internationalMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const INTERNATIONAL_INSERTION_INTERVAL = 3 + +/** + * U.S. and international instruments are interleaved so ordinary benchmark + * sizes exercise multiple symbol formats and market labels. + */ +export const globalInstruments = Object.freeze( + marketInstruments.flatMap((instrument, index) => { + const internationalInstrument = + index % INTERNATIONAL_INSERTION_INTERVAL === 0 + ? internationalInstruments[index / INTERNATIONAL_INSERTION_INTERVAL] + : undefined + + return internationalInstrument + ? [instrument, internationalInstrument] + : [instrument] + }), +) as unknown as ReadonlyArray diff --git a/examples/react/realtime-trading/src/feed/use-market-feed-controller.ts b/examples/react/realtime-trading/src/feed/use-market-feed-controller.ts new file mode 100644 index 0000000000..74c5208f38 --- /dev/null +++ b/examples/react/realtime-trading/src/feed/use-market-feed-controller.ts @@ -0,0 +1,10 @@ +import { useEffect, useState } from 'react' +import { MarketFeedController } from './market-feed-controller' + +export function useMarketFeedController(): MarketFeedController { + const [controller] = useState(() => new MarketFeedController()) + + useEffect(() => controller.start(), [controller]) + + return controller +} diff --git a/examples/react/realtime-trading/src/feed/worker/market-feed-engine.ts b/examples/react/realtime-trading/src/feed/worker/market-feed-engine.ts new file mode 100644 index 0000000000..fbd9c369c0 --- /dev/null +++ b/examples/react/realtime-trading/src/feed/worker/market-feed-engine.ts @@ -0,0 +1,177 @@ +import { globalInstruments } from '../market-instruments.ts' +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const INITIAL_MARKET_SEED = 0x4d41524b +const LIVE_FEED_SEED = 0x5449434b + +export class MarketFeedEngine { + #quotes: Array = [] + #lastHistorySampledAt = new Uint32Array(0) + #random = createRandom(2_026) + #rowCursor = 0 + #tickIndex = 0 + + reset(count: number): Array { + const random = createRandom(INITIAL_MARKET_SEED ^ count) + const createdAt = Date.now() + + this.#quotes = Array.from({ length: count }, (_, index) => { + const [baseSymbol, company, market] = + globalInstruments[index % globalInstruments.length] + const series = Math.floor(index / globalInstruments.length) + const symbol = series === 0 ? baseSymbol : `${baseSymbol}${series}` + const previousClose = roundPrice(20 + random() * 480) + const open = roundPrice(previousClose * (1 + (random() - 0.5) * 0.016)) + const spread = Math.max(0.01, open * (0.0002 + random() * 0.0004)) + const history = Array.from({ length: 24 }, (_, historyIndex) => + roundPrice( + open * + (1 + Math.sin(historyIndex / 4) * 0.002 + (random() - 0.5) * 0.001), + ), + ) + const volume = Math.floor(50_000 + random() * 2_000_000) + const lastSize = Math.floor(10 + random() * 5_000) + + return { + id: `instrument-${index}`, + symbol, + company, + venue: market, + previousClose, + open, + high: open, + low: open, + price: open, + bid: roundPrice(open - spread / 2), + ask: roundPrice(open + spread / 2), + bidSize: Math.floor(100 + random() * 25_000), + askSize: Math.floor(100 + random() * 25_000), + lastSize, + lastMove: 0, + lastUpdatedAt: createdAt, + volume, + turnover: roundMoney(open * volume), + history, + } + }) + + this.#random = createRandom(LIVE_FEED_SEED ^ count) + this.#rowCursor = 0 + this.#lastHistorySampledAt = new Uint32Array(count) + this.#lastHistorySampledAt.fill(createdAt >>> 0) + + return this.#quotes.map((quote) => ({ + ...quote, + history: [...quote.history], + })) + } + + applyTicks( + tickCount: number, + updateSparklines: boolean, + sparklineSampleIntervalMs: number, + ): Array { + if (this.#quotes.length === 0 || tickCount <= 0) return [] + + const updatedAt = Date.now() + const sampledAt = updatedAt >>> 0 + const sampleIntervalMs = Math.max(16, sparklineSampleIntervalMs) + const updatedQuotes = new Map() + const stride = 97 + + this.#tickIndex = 0 + while (this.#tickIndex < tickCount) { + this.#rowCursor = (this.#rowCursor + stride) % this.#quotes.length + const quote = this.#quotes[this.#rowCursor] + const lastSampledAt = this.#lastHistorySampledAt[this.#rowCursor] + const shouldUpdateHistory = + updateSparklines && + (sampledAt - lastSampledAt) >>> 0 >= sampleIntervalMs + + if (shouldUpdateHistory) { + this.#lastHistorySampledAt[this.#rowCursor] = sampledAt + } + + this.#applyTick(quote, shouldUpdateHistory, updatedAt) + + const previousUpdate = updatedQuotes.get(this.#rowCursor) + updatedQuotes.set(this.#rowCursor, { + index: this.#rowCursor, + price: quote.price, + bid: quote.bid, + ask: quote.ask, + bidSize: quote.bidSize, + askSize: quote.askSize, + lastSize: quote.lastSize, + lastMove: quote.lastMove, + lastUpdatedAt: quote.lastUpdatedAt, + high: quote.high, + low: quote.low, + volume: quote.volume, + turnover: quote.turnover, + ...(shouldUpdateHistory || previousUpdate?.history + ? { history: [...quote.history] } + : {}), + }) + this.#tickIndex++ + } + + return [...updatedQuotes.values()] + } + + #applyTick( + quote: MarketQuoteSnapshot, + updateHistory: boolean, + updatedAt: number, + ): void { + const previousPrice = quote.price + const volatility = 0.00015 + this.#random() * 0.0012 + const move = previousPrice * (this.#random() - 0.495) * volatility + const nextPrice = roundPrice(Math.max(0.1, previousPrice + move)) + const spread = Math.max( + 0.01, + nextPrice * (0.00015 + this.#random() * 0.0005), + ) + + quote.lastMove = nextPrice - previousPrice + quote.price = nextPrice + quote.high = Math.max(quote.high, nextPrice) + quote.low = Math.min(quote.low, nextPrice) + quote.bid = roundPrice(nextPrice - spread / 2) + quote.ask = roundPrice(nextPrice + spread / 2) + quote.bidSize = Math.floor(100 + this.#random() * 25_000) + quote.askSize = Math.floor(100 + this.#random() * 25_000) + quote.lastSize = Math.floor(10 + this.#random() * 5_000) + quote.lastUpdatedAt = updatedAt + quote.volume += quote.lastSize + quote.turnover = roundMoney(quote.turnover + nextPrice * quote.lastSize) + + if (updateHistory) { + quote.history = [...quote.history.slice(-23), nextPrice] + } + } +} + +function createRandom(seed: number): () => number { + const runtime = { state: seed >>> 0 } + return () => { + runtime.state += 0x6d2b79f5 + const stateValue = runtime.state + const firstMix = Math.imul(stateValue ^ (stateValue >>> 15), stateValue | 1) + const secondMix = + firstMix + Math.imul(firstMix ^ (firstMix >>> 7), firstMix | 61) + const value = firstMix ^ secondMix + return ((value ^ (value >>> 14)) >>> 0) / 4_294_967_296 + } +} + +function roundPrice(value: number): number { + return Math.round(value * 100) / 100 +} + +function roundMoney(value: number): number { + return Math.round(value * 100) / 100 +} diff --git a/examples/react/realtime-trading/src/feed/worker/market-feed-protocol.ts b/examples/react/realtime-trading/src/feed/worker/market-feed-protocol.ts new file mode 100644 index 0000000000..21997ec89c --- /dev/null +++ b/examples/react/realtime-trading/src/feed/worker/market-feed-protocol.ts @@ -0,0 +1,70 @@ +export interface MarketQuoteSnapshot { + id: string + symbol: string + company: string + venue: string + previousClose: number + open: number + high: number + low: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + volume: number + turnover: number + history: Array +} + +export interface MarketQuoteUpdate { + index: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + high: number + low: number + volume: number + turnover: number + history?: Array +} + +export type MarketFeedCommand = + | { + type: 'start' + rowCount: number + running: boolean + ticksPerSecond: number + publishIntervalMs: number + updateSparklines: boolean + sparklineSampleIntervalMs: number + } + | { type: 'set-running'; running: boolean } + | { type: 'set-rate'; ticksPerSecond: number } + | { type: 'set-publish-interval'; intervalMs: number } + | { type: 'set-sparklines'; enabled: boolean } + | { type: 'set-sparkline-interval'; intervalMs: number } + | { type: 'reset'; rowCount: number } + | { type: 'burst'; tickCount: number } + +export type MarketFeedEvent = + | { + type: 'snapshot' + sessionId: number + quotes: Array + } + | { + type: 'updates' + sessionId: number + tickCount: number + coalescedUpdateCount: number + updates: Array + } diff --git a/examples/react/realtime-trading/src/feed/worker/market-feed.worker.ts b/examples/react/realtime-trading/src/feed/worker/market-feed.worker.ts new file mode 100644 index 0000000000..2b7a642fd9 --- /dev/null +++ b/examples/react/realtime-trading/src/feed/worker/market-feed.worker.ts @@ -0,0 +1,143 @@ +import { initialMarketFeedConfig } from '../market-feed-config' +import { MarketFeedEngine } from './market-feed-engine' +import type { + MarketFeedCommand, + MarketFeedEvent, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const engine = new MarketFeedEngine() +const pendingUpdates = new Map() +const runtime = { + sessionId: 0, + pendingTickCount: 0, + pendingCoalescedUpdateCount: 0, + initialized: false, + running: true, + ticksPerSecond: initialMarketFeedConfig.targetSamplesPerSecond, + publishIntervalMs: initialMarketFeedConfig.publishIntervalMs, + publishTimerId: null as ReturnType | null, + updateSparklines: initialMarketFeedConfig.updateSparklines, + sparklineSampleIntervalMs: initialMarketFeedConfig.sparklineSampleIntervalMs, + tickBudget: 0, + lastTickAt: performance.now(), +} + +addEventListener('message', ({ data }: MessageEvent) => { + switch (data.type) { + case 'start': + runtime.running = data.running + runtime.ticksPerSecond = data.ticksPerSecond + runtime.publishIntervalMs = data.publishIntervalMs + runtime.updateSparklines = data.updateSparklines + runtime.sparklineSampleIntervalMs = data.sparklineSampleIntervalMs + restartPublishTimer() + reset(data.rowCount) + break + case 'set-running': + runtime.running = data.running + break + case 'set-rate': + runtime.ticksPerSecond = data.ticksPerSecond + break + case 'set-publish-interval': + runtime.publishIntervalMs = Math.max(4, data.intervalMs) + restartPublishTimer() + break + case 'set-sparklines': + runtime.updateSparklines = data.enabled + break + case 'set-sparkline-interval': + runtime.sparklineSampleIntervalMs = Math.max(16, data.intervalMs) + break + case 'reset': + reset(data.rowCount) + break + case 'burst': + produceTicks(data.tickCount) + flush() + break + } +}) + +setInterval(() => { + const now = performance.now() + const elapsed = Math.min(100, Math.max(0, now - runtime.lastTickAt)) + runtime.lastTickAt = now + + if (runtime.initialized && runtime.running) { + runtime.tickBudget += (runtime.ticksPerSecond * elapsed) / 1_000 + const tickCount = Math.floor(runtime.tickBudget) + runtime.tickBudget -= tickCount + produceTicks(tickCount) + } +}, 16) + +restartPublishTimer() + +function reset(rowCount: number): void { + runtime.initialized = true + runtime.sessionId++ + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + runtime.tickBudget = 0 + runtime.lastTickAt = performance.now() + + post({ + type: 'snapshot', + sessionId: runtime.sessionId, + quotes: engine.reset(rowCount), + }) +} + +function produceTicks(tickCount: number): void { + if (!runtime.initialized || tickCount <= 0) return + + runtime.pendingTickCount += tickCount + for (const update of engine.applyTicks( + tickCount, + runtime.updateSparklines, + runtime.sparklineSampleIntervalMs, + )) { + const previousUpdate = pendingUpdates.get(update.index) + if (previousUpdate) runtime.pendingCoalescedUpdateCount++ + pendingUpdates.set(update.index, { + ...update, + ...(update.history || !previousUpdate?.history + ? {} + : { history: previousUpdate.history }), + }) + } +} + +function flush(): void { + if (runtime.pendingTickCount === 0) return + + const message: MarketFeedEvent = { + type: 'updates', + sessionId: runtime.sessionId, + tickCount: runtime.pendingTickCount, + coalescedUpdateCount: runtime.pendingCoalescedUpdateCount, + updates: [...pendingUpdates.values()], + } + + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + post(message) +} + +function restartPublishTimer(): void { + if (runtime.publishTimerId !== null) { + clearInterval(runtime.publishTimerId) + } + runtime.publishTimerId = setInterval( + flush, + Math.max(4, runtime.publishIntervalMs), + ) +} + +function post(event: MarketFeedEvent): void { + postMessage(event) +} diff --git a/examples/react/realtime-trading/src/index.css b/examples/react/realtime-trading/src/index.css new file mode 100644 index 0000000000..397c86fc54 --- /dev/null +++ b/examples/react/realtime-trading/src/index.css @@ -0,0 +1,1058 @@ +:root { + color-scheme: dark; + --font-ui: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + 'Segoe UI', sans-serif; + --font-mono: 'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace; + font-family: var(--font-ui); + font-synthesis: none; + --background: #050505; + --panel: #080808; + --panel-raised: #111111; + --panel-hover: #181818; + --surface-bar: #080808; + --surface-toolbar: #0d0d0d; + --surface-table: #050505; + --surface-header: #101010; + --surface-control: #151515; + --border: #303030; + --border-soft: #242424; + --border-strong: #4a4a4a; + --text: #e7ebf0; + --text-strong: #ffffff; + --text-inverse: #f7f9fb; + --muted: #737982; + --blue: #62a9ff; + --blue-soft: #a9d0ff; + --green: #42e488; + --red: #ff646b; + --amber: #dfb465; + --depth-bid: #315774; + --depth-ask: #634049; + --row-alt: rgb(255 255 255 / 1.8%); + --row-selected: rgb(66 132 214 / 16%); + --control-border: #354456; + --control-hover: #192431; + --sidebar-width: 18rem; + --shell-bar-height: 2.625rem; + --metrics-height: 3.5rem; + --statusbar-height: 1.625rem; + --virtual-footer-height: 2.125rem; + --table-header-height: 2rem; + --table-row-height: 2rem; + --shell-inline-padding: 0.75rem; + --table-cell-inline-padding: 0.6rem; + --control-radius: 1px; +} + +* { + box-sizing: border-box; +} + +html, +body { + min-width: 320px; + min-height: 100%; + margin: 0; + background: var(--background); +} + +body { + color: var(--text); +} + +button, +select, +input { + font: inherit; +} + +button, +select { + color: var(--text); + background: var(--panel-raised); + border: 1px solid var(--control-border); + border-radius: var(--control-radius); +} + +button { + padding: 0.5rem 0.65rem; + cursor: pointer; + font-size: 0.72rem; + font-weight: 650; + letter-spacing: 0.025em; +} + +button:hover { + background: var(--control-hover); + border-color: var(--border-strong); +} + +button:focus-visible, +select:focus-visible, +input:focus-visible { + outline: 1px solid var(--blue); + outline-offset: 1px; +} + +select { + width: 100%; + padding: 0.45rem 0.55rem; + font-size: 0.75rem; +} + +.trading-terminal { + --active-sidebar-width: var(--sidebar-width); + display: grid; + width: 100%; + height: 100dvh; + min-height: 0; + overflow: hidden; + background: var(--background); + grid-template-areas: + 'header sidebar' + 'content sidebar' + 'footer sidebar'; + grid-template-columns: minmax(0, 1fr) var(--active-sidebar-width); + grid-template-rows: auto minmax(0, 1fr) auto; + transition: grid-template-columns 160ms ease; +} + +.trading-terminal.is-sidebar-collapsed { + --active-sidebar-width: 0px; +} + +.shell-header { + display: flex; + min-width: 0; + flex-direction: column; + grid-area: header; +} + +.app-bar { + display: flex; + min-height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + background: var(--surface-bar); + border-bottom: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.68rem; + letter-spacing: 0.045em; +} + +.brand, +.header-actions, +.feed-status { + display: flex; + align-items: center; +} + +.brand { + gap: 0.65rem; + color: var(--text-strong); +} + +.header-actions { + gap: 0.75rem; +} + +.sidebar-toggle { + display: grid; + width: 1.9rem; + height: 1.9rem; + padding: 0; + place-items: center; + color: var(--muted); + background: transparent; + border-color: transparent; +} + +.sidebar-toggle:hover { + color: var(--text-strong); + background: var(--surface-control); + border-color: var(--border); +} + +.sidebar-toggle svg { + width: 1rem; + height: 1rem; + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-width: 1.4; +} + +.feed-status { + gap: 0.4rem; + color: var(--muted); +} + +.feed-status.is-running { + color: var(--green); +} + +.status-dot { + width: 6px; + height: 6px; + background: var(--muted); + border-radius: 50%; +} + +.feed-status.is-running .status-dot { + background: var(--green); +} + +.development-warning { + flex: 0 0 auto; + padding: 0.3rem 0.75rem; + color: var(--amber); + background: color-mix(in srgb, var(--amber) 8%, var(--background)); + border-bottom: 1px solid color-mix(in srgb, var(--amber) 24%, var(--border)); + font-family: var(--font-mono); + font-size: 0.62rem; + letter-spacing: 0.04em; +} + +.market-panel { + display: flex; + min-width: 0; + min-height: 0; + flex-direction: column; + background: var(--panel); + grid-area: content; +} + +.metrics-strip { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + background: var(--border); + border-bottom: 1px solid var(--border); + gap: 1px; +} + +.metrics-strip h2 { + margin: 0; + padding: 0.65rem var(--shell-inline-padding) 0.45rem; + color: var(--muted); + background: var(--surface-table); + font-size: 0.58rem; + grid-column: 1 / -1; + letter-spacing: 0.075em; +} + +.metrics-strip article { + min-width: 0; + min-height: 4.25rem; + padding: 0.5rem var(--shell-inline-padding); + background: var(--surface-bar); +} + +.metrics-strip span, +.metrics-strip small { + display: block; + color: var(--muted); + font-size: 0.56rem; + letter-spacing: 0.045em; + line-height: 1.35; +} + +.metrics-strip strong { + display: block; + margin: 0.12rem 0 0.08rem; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.88rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +.metrics-strip strong.metric-alert { + color: var(--amber); +} + +.table-scroll { + flex: 1; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +.virtual-scroll-footer { + display: flex; + flex: 0 0 auto; + align-items: center; + justify-content: space-between; + min-height: var(--virtual-footer-height); + padding: 0 var(--shell-inline-padding); + color: var(--muted); + background: var(--surface-toolbar); + border-top: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.68rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +table { + min-width: 100%; + border-spacing: 0; + table-layout: fixed; + font-family: var(--font-ui); + font-size: 0.78rem; + font-variant-numeric: tabular-nums; +} + +.virtual-table { + display: grid; +} + +.virtual-table thead { + display: grid; +} + +.virtual-table thead tr, +.virtual-table-row { + display: flex; + width: 100%; +} + +.virtual-table th, +.virtual-table-row > td { + flex: 0 0 auto; +} + +.virtual-table-body { + position: relative; + display: grid; +} + +.virtual-table-row { + position: absolute; + left: 0; + height: var(--table-row-height); +} + +.virtual-table-row > td { + display: block; +} + +.trading-data-grid { + display: grid; +} + +.trading-data-grid thead, +.trading-data-grid tbody { + display: grid; +} + +.trading-data-grid tbody { + -webkit-user-select: none; + user-select: none; +} + +.trading-data-grid thead > tr, +.trading-data-grid tbody > tr { + display: flex; + width: 100%; +} + +.trading-data-grid tbody > tr { + min-height: var(--table-row-height); + content-visibility: auto; + contain-intrinsic-block-size: var(--table-row-height); +} + +.trading-data-grid th, +.trading-data-grid td { + flex: 0 0 auto; +} + +thead { + position: sticky; + z-index: 2; + top: 0; +} + +th { + height: var(--table-header-height); + padding: 0 var(--table-cell-inline-padding); + color: var(--muted); + background: var(--surface-header); + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border); + font-size: 0.7rem; + font-weight: 500; + letter-spacing: 0.005em; + text-align: left; + white-space: nowrap; +} + +th.column-group-header { + color: #666b72; + font-size: 0.72rem; + font-weight: 500; + text-align: center; +} + +thead tr:first-child th.column-group-header { + color: #777d85; + font-size: 0.76rem; +} + +th.numeric-header { + text-align: right; +} + +td { + height: var(--table-row-height); + padding: 0 var(--table-cell-inline-padding); + overflow: hidden; + color: #eef1f5; + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border-soft); + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +th:last-child, +td:last-child { + border-right: 0; +} + +td[data-column-id='market'], +td[data-column-id='name'], +td[data-column-id='symbol'] { + text-align: left; +} + +td[data-column-id='market'] { + color: var(--blue); + font-weight: 550; +} + +td[data-column-id='name'] { + color: var(--text-strong); +} + +td[data-column-id='symbol'] { + color: #d8dde4; + font-weight: 600; +} + +tbody tr:nth-child(even) { + background: var(--row-alt); +} + +tbody tr:hover { + background: var(--panel-hover); +} + +tbody tr[data-symbol-selected='true'] { + background: var(--row-selected); + box-shadow: inset 2px 0 0 var(--blue); +} + +.table-scroll:focus { + outline: none; +} + +th { + position: relative; +} + +.leaf-header-content { + display: flex; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + height: 100%; + align-items: stretch; + margin-inline: calc(-1 * var(--table-cell-inline-padding)); +} + +.column-drag-handle, +.sort-header-button { + min-width: 0; + height: 100%; + padding: 0; + color: inherit; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-weight: inherit; + letter-spacing: inherit; +} + +.column-drag-handle { + flex: 0 0 1.05rem; + color: var(--muted); + cursor: grab; + opacity: 0.35; + font-size: 0.56rem; + letter-spacing: -0.32rem; + text-align: center; +} + +.column-drag-handle:active { + cursor: grabbing; +} + +th:hover .column-drag-handle, +.column-drag-handle:focus-visible { + opacity: 0.9; +} + +.column-drag-handle:hover, +.sort-header-button:hover { + background: rgb(255 255 255 / 4%); + border-color: transparent; +} + +th.is-column-dragging { + opacity: 0.45; +} + +th.is-column-drop-target { + background: rgb(50 139 255 / 16%); + box-shadow: inset 4px 0 0 var(--blue); +} + +th.is-column-drop-target::before { + position: absolute; + z-index: 6; + top: -1px; + bottom: -1px; + left: -2px; + width: 4px; + background: #62a9ff; + box-shadow: + 0 0 0 1px rgb(0 0 0 / 55%), + 0 0 12px rgb(70 151 255 / 90%); + content: ''; + pointer-events: none; +} + +.sort-header-button { + display: flex; + min-width: 0; + flex: 1; + align-items: center; + justify-content: flex-start; + gap: 0.3rem; + padding-inline: 0.25rem var(--table-cell-inline-padding); + cursor: default; + text-align: inherit; +} + +.numeric-header .sort-header-button { + justify-content: flex-end; +} + +.sort-header-button.is-sortable { + cursor: pointer; +} + +.sort-header-button:disabled { + opacity: 1; +} + +.header-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.sort-indicator { + flex: 0 0 auto; + color: #66717e; + font-size: 0.72rem; +} + +.sort-indicator.is-active { + color: var(--blue-soft); +} + +.column-resize-handle { + position: absolute; + z-index: 3; + top: 0; + right: -3px; + width: 7px; + height: 100%; + cursor: col-resize; + touch-action: none; + user-select: none; +} + +.column-resize-handle::after { + position: absolute; + top: 20%; + right: 3px; + width: 1px; + height: 60%; + background: var(--border-strong); + content: ''; + opacity: 0; +} + +th:hover > .column-resize-handle::after, +.column-resize-handle.is-resizing::after { + background: var(--blue); + opacity: 1; +} + +tbody tr[aria-selected='true'] { + background: rgb(76 145 228 / 13%); +} + +td[aria-selected='true'] { + position: relative; + background: rgb(70 139 222 / 12%); +} + +td[data-cell-focused='true'] { + background: rgb(70 139 222 / 21%); +} + +td[aria-selected='true']::after { + position: absolute; + z-index: 1; + inset: 0; + border: 1px solid transparent; + content: ''; + pointer-events: none; +} + +td[data-selection-top='true']::after { + border-top-color: var(--blue); +} + +td[data-selection-right='true']::after { + border-right-color: var(--blue); +} + +td[data-selection-bottom='true']::after { + border-bottom-color: var(--blue); +} + +td[data-selection-left='true']::after { + border-left-color: var(--blue); +} + +.price-button { + min-width: 4.5rem; + padding: 0; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-variant-numeric: tabular-nums; + font-weight: 600; + text-align: right; +} + +.price-button:hover { + background: transparent; + text-decoration: underline; + text-underline-offset: 2px; +} + +.move-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.move-cell.quote-up, +.percent-change-cell.quote-up { + background: color-mix(in srgb, var(--green) 7%, transparent); +} + +.move-cell.quote-down, +.percent-change-cell.quote-down { + background: color-mix(in srgb, var(--red) 7%, transparent); +} + +.percent-change-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.spread-cell { + display: flex; + align-items: baseline; + justify-content: flex-end; + gap: 0.35rem; + color: var(--text); +} + +.spread-cell small { + min-width: 2.8rem; + color: var(--muted); + font-size: 0.55rem; +} + +.spread-cell.spread-wide, +.spread-cell.spread-wide small { + color: var(--amber); +} + +.depth-cell { + position: relative; + display: flex; + height: 17px; + overflow: hidden; + background: var(--surface-control); +} + +.depth-bid, +.depth-ask { + height: 100%; + opacity: 0.78; +} + +.depth-bid { + background: var(--depth-bid); + border-right: 1px solid var(--panel); +} + +.depth-ask { + background: var(--depth-ask); +} + +.depth-values { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 0.28rem; + color: var(--text-strong); + font-size: 0.57rem; + text-shadow: 0 1px var(--background); +} + +.quote-age { + color: var(--muted); +} + +.quote-age-warm { + color: var(--amber); +} + +.quote-age-stale { + color: var(--red); +} + +.quote-up { + color: var(--green); +} + +.quote-down { + color: var(--red); +} + +.sparkline { + display: block; + width: 100%; + height: 1.35rem; + margin-left: auto; + color: var(--blue-soft); + overflow: visible; +} + +.sparkline.quote-up { + color: var(--green); +} + +.sparkline.quote-down { + color: var(--red); +} + +.sparkline polyline { + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-linejoin: miter; + stroke-width: 1.25; + vector-effect: non-scaling-stroke; +} + +.market-statusbar { + display: flex; + flex: 0 0 var(--statusbar-height); + min-height: var(--statusbar-height); + gap: 1.1rem; + align-items: center; + padding: 0 0.65rem; + color: var(--muted); + background: var(--surface-bar); + border-top: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.56rem; + grid-area: footer; + letter-spacing: 0.035em; +} + +.market-statusbar strong { + margin-left: 0.25rem; + color: var(--text); + font-weight: 500; +} + +.sidebar-slot { + width: var(--sidebar-width); + min-width: 0; + min-height: 0; + overflow: hidden; + background: var(--surface-table); + border-left: 1px solid var(--border); + grid-area: sidebar; + transition: + opacity 120ms ease, + transform 160ms ease, + visibility 160ms; +} + +.is-sidebar-collapsed .sidebar-slot { + visibility: hidden; + opacity: 0; + pointer-events: none; + transform: translateX(100%); +} + +.configurator { + width: 100%; + height: 100%; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +.configurator > header { + display: flex; + height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + color: var(--text-strong); + background: var(--surface-toolbar); + border-bottom: 1px solid var(--border); + font-size: 0.65rem; + font-weight: 700; + letter-spacing: 0.055em; +} + +.configurator > header small { + color: var(--muted); + font-size: 0.54rem; + font-weight: 500; +} + +.config-section { + display: grid; + gap: 0.7rem; + padding: 0.8rem var(--shell-inline-padding); + border-bottom: 1px solid var(--border); +} + +.config-section h2 { + margin: 0; + color: var(--muted); + font-size: 0.58rem; + letter-spacing: 0.075em; +} + +.primary-action { + width: 100%; + color: var(--text-inverse); + background: var(--blue); + border-color: var(--blue-soft); +} + +.primary-action:hover { + background: var(--blue-soft); + border-color: var(--text-strong); +} + +.field { + display: grid; + gap: 0.35rem; + color: var(--text); + font-size: 0.66rem; +} + +.rate-field > span { + display: flex; + justify-content: space-between; +} + +.rate-field strong { + color: var(--text); + font-family: var(--font-mono); + font-weight: 500; +} + +.field small { + color: var(--muted); + font-family: var(--font-mono); + font-size: 0.55rem; +} + +input[type='range'] { + width: 100%; + margin: 0; + accent-color: var(--blue); +} + +.toggle-field { + display: flex; + gap: 0.5rem; + align-items: flex-start; + color: var(--text); + font-size: 0.66rem; + line-height: 1.3; +} + +.toggle-field input { + margin: 0.12rem 0 0; + accent-color: var(--blue); +} + +.toggle-field small { + display: block; + margin-top: 0.14rem; + color: var(--muted); + font-size: 0.57rem; +} + +.action-grid { + display: grid; + grid-template-columns: 1fr; + gap: 0.4rem; +} + +.diagnostics dl, +.selected-instrument dl { + display: grid; + gap: 0; + margin: 0; +} + +.diagnostics dl > div, +.selected-instrument dl > div { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 24px; + border-bottom: 1px solid var(--border-soft); +} + +.diagnostics dl > div:last-child, +.selected-instrument dl > div:last-child { + border-bottom: 0; +} + +.diagnostics dl > div:has(dd[data-testid$='-breakdown']) { + display: grid; + grid-template-columns: minmax(0, 1fr); + align-content: center; + padding-block: 0.28rem; +} + +.diagnostics dd[data-testid$='-breakdown'] { + width: 100%; + overflow-x: auto; + padding-block: 0.12rem; + white-space: nowrap; + scrollbar-width: thin; +} + +dt { + color: var(--muted); + font-size: 0.61rem; +} + +dd { + margin: 0; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.62rem; +} + +.selection { + display: flex; + align-items: flex-start; + justify-content: space-between; +} + +.selection div { + display: grid; + gap: 0.18rem; +} + +.selection strong { + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.85rem; +} + +.selection span, +.selection small, +.selected-instrument p { + color: var(--muted); + font-size: 0.61rem; +} + +.selected-instrument p { + margin: 0; + line-height: 1.45; +} + +@media (max-width: 980px) { + :root { + --sidebar-width: 15.625rem; + } +} + +@media (max-width: 720px) { + .trading-terminal { + --active-sidebar-width: 0px; + height: 100dvh; + min-height: 0; + overflow: hidden; + } + + .market-panel { + min-height: 0; + } + + .table-scroll { + min-height: 0; + } + + .sidebar-slot { + position: fixed; + z-index: 20; + top: 0; + right: 0; + bottom: 0; + width: min(var(--sidebar-width), calc(100vw - 2.75rem)); + box-shadow: -18px 0 42px rgb(0 0 0 / 48%); + } + + .is-sidebar-collapsed .sidebar-slot { + box-shadow: none; + } +} diff --git a/examples/react/realtime-trading/src/main.tsx b/examples/react/realtime-trading/src/main.tsx new file mode 100644 index 0000000000..27b3622c66 --- /dev/null +++ b/examples/react/realtime-trading/src/main.tsx @@ -0,0 +1,48 @@ +import { createRoot } from 'react-dom/client' +import { App } from './App' +import './index.css' + +if (import.meta.env.DEV) { + const nativeMeasure = performance.measure.bind(performance) + const allowedMeasures = new Set([ + 'react-profiler-commit', + 'tanstack-row-model', + 'market-update-to-dom-commit', + ]) + performance.measure = (( + name: string, + startOrOptions?: string | PerformanceMeasureOptions, + endMark?: string, + ) => { + // React 19 DEV records a User Timing measure per component. Combined with + // this live feed that path freezes Chromium, so keep only benchmark marks. + if (!allowedMeasures.has(name)) { + return undefined as unknown as PerformanceMeasure + } + try { + if ( + startOrOptions && + typeof startOrOptions === 'object' && + 'detail' in startOrOptions + ) { + const { detail: _detail, ...rest } = startOrOptions + return nativeMeasure(name, rest, endMark) + } + return nativeMeasure(name, startOrOptions as string, endMark) + } catch { + return undefined as unknown as PerformanceMeasure + } + }) as typeof performance.measure + + const reactScan = document.createElement('script') + reactScan.src = 'https://unpkg.com/react-scan/dist/auto.global.js' + reactScan.async = true + document.head.append(reactScan) +} + +const rootElement = document.getElementById('root') +if (!rootElement) throw new Error('Failed to find the root element') + +// StrictMode is intentionally omitted: its development-only mount replay would +// contaminate the component lifecycle counters used by this benchmark. +createRoot(rootElement).render() diff --git a/examples/react/realtime-trading/src/shell/TradingShell.tsx b/examples/react/realtime-trading/src/shell/TradingShell.tsx new file mode 100644 index 0000000000..ce9275a03c --- /dev/null +++ b/examples/react/realtime-trading/src/shell/TradingShell.tsx @@ -0,0 +1,688 @@ +import { shallow, useSelector } from '@tanstack/react-store' +import { useState } from 'react' +import { + feedSampleRateAt, + feedSampleRateIndex, + feedSampleRateOptions, +} from '../feed/feed-sample-rates' +import { + FORCED_VIRTUALIZATION_ROW_COUNT, + resolveVirtualScrollMode, +} from '../table/trading-row-virtualizer' +import { + useMarketFeedController, + useTradingShellController, + useTradingShellState, +} from './trading-shell-context' +import { configuratorOptions } from './configurator-options' +import type { ReactNode } from 'react' +import type { FeedMetrics } from '../benchmark/benchmark-monitor' + +const integerFormatter = new Intl.NumberFormat('en-US', { + maximumFractionDigits: 0, +}) +const rateFormatter = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +export function TradingShell(props: { children: ReactNode }) { + const [sidebarOpen, setSidebarOpen] = useState(true) + const toggleSidebar = () => setSidebarOpen((open) => !open) + + return ( +
+
+ + + {import.meta.env.DEV && ( + + )} + + {import.meta.env.MODE === 'production' && ( + + )} +
+ +
+ {props.children} +
+ +
{sidebarOpen && }
+
+ ) +} + +function AppHeader(props: { + sidebarOpen: boolean + onSidebarToggle: () => void +}) { + const feed = useMarketFeedController() + const workerReady = useSelector(feed.workerReady) + const running = useSelector(feed.running) + return ( +
+
+ MARKET MONITOR +
+
+ + + +
+
+ ) +} + +function MarketStatusbar() { + const { lastBatchSize, lastUpdateCount, mountedCells, liveComponents } = + useTradingShellState( + (state) => ({ + lastBatchSize: state.metrics.lastBatchSize, + lastUpdateCount: state.metrics.lastUpdateCount, + mountedCells: state.mountedCells, + liveComponents: state.liveComponents, + }), + { compare: shallow }, + ) + return ( +
+ + MESSAGE SAMPLES {formatInteger(lastBatchSize)} + + + CHANGED ROWS {formatInteger(lastUpdateCount)} + + + HOSTS {formatInteger(mountedCells)} + + + COMPONENTS {formatInteger(liveComponents)} + +
+ ) +} + +function Configurator() { + const benchmarkState = useTradingShellState( + (storeState) => ({ + requestedVirtualScrollMode: storeState.requestedVirtualScrollMode, + }), + { compare: shallow }, + ) + const controller = useTradingShellController() + const feed = useMarketFeedController() + const running = useSelector(feed.running) + const instrumentCount = useSelector(feed.instrumentCount) + const targetTicksPerSecond = useSelector(feed.targetTicksPerSecond) + const publishIntervalMs = useSelector(feed.publishIntervalMs) + const updateSparklines = useSelector(feed.updateSparklines) + const sparklineSampleIntervalMs = useSelector(feed.sparklineSampleIntervalMs) + const rendererMode = useSelector(controller.renderAtoms.rendererMode) + const { actions } = controller + const feedActions = feed.actions + const { requestedVirtualScrollMode } = benchmarkState + const { setRendererMode, setVirtualScrollEnabled, resetMarket } = actions + const { + toggle, + setInstrumentCount, + setTargetRate, + setPublishInterval, + setSparklineUpdates, + setSparklineSampleInterval, + runBurst, + } = feedActions + const virtualScrollForced = instrumentCount >= FORCED_VIRTUALIZATION_ROW_COUNT + const virtualScrollMode = resolveVirtualScrollMode( + requestedVirtualScrollMode, + instrumentCount, + ) + + return ( + + ) +} + +function LiveHealth() { + const { metrics, longAnimationFramesSupported } = useTradingShellState( + (state) => ({ + metrics: state.metrics, + longAnimationFramesSupported: state.longAnimationFramesSupported, + }), + { compare: shallow }, + ) + return ( +
+

LIVE HEALTH

+
+ FRAME RATE (EST.) + + {metrics.estimatedFrameRate.toFixed(1)} + + rAF callbacks/s · rolling 1 s +
+
+ AVG COMMIT + + {formatMs(metrics.averageCommitLatencyMs)} + + snapshot → DOM · rolling 3 s +
+
+ LONG FRAMES + {longAnimationFramesSupported ? ( + <> + 0 ? 'metric-alert' : ''} + > + {metrics.longAnimationFrames} + + + since reset · worst {formatMs(metrics.worstLongAnimationFrameMs)} + + + ) : ( + <> + N/A + unsupported + + )} +
+
+ THROUGHPUT + + {formatRate(metrics.rowUpdatesPerSecond)} rows/s + + + {metrics.stateApplicationsPerSecond.toFixed(1)} snapshots/s · rows + deduplicated per snapshot + +
+
+ ) +} + +function Diagnostics() { + const { + metrics, + mountedCells, + liveComponents, + longAnimationFramesSupported, + } = useTradingShellState( + (state) => ({ + metrics: state.metrics, + mountedCells: state.mountedCells, + liveComponents: state.liveComponents, + longAnimationFramesSupported: state.longAnimationFramesSupported, + }), + { compare: shallow }, + ) + const profilerEnabled = + import.meta.env.DEV || import.meta.env.MODE === 'profile' + return ( +
+

DIAGNOSTICS

+
+
+
Worker samples / s
+
+ {formatRate(metrics.actualTicksPerSecond)} +
+
+
+
Changed rows / s
+
+ {formatRate(metrics.rowUpdatesPerSecond)} +
+
+
+
Worker messages / s
+
+ {metrics.workerMessagesPerSecond.toFixed(1)} +
+
+
+
State applies / s
+
+ {metrics.stateApplicationsPerSecond.toFixed(1)} +
+
+
+
Table DOM commits / s
+
+ {metrics.tableCommitsPerSecond.toFixed(1)} +
+
+
+
Commit latency p95 / max
+
+ {formatMs(metrics.p95CommitLatencyMs)} /{' '} + {formatMs(metrics.maxCommitLatencyMs)} +
+
+
+
Mounted cells
+
{formatInteger(mountedCells)}
+
+
+
Live components
+
{formatInteger(liveComponents)}
+
+
+
Created / destroyed
+
+ {formatInteger(metrics.componentsCreated)} /{' '} + {formatInteger(metrics.componentsDestroyed)} +
+
+
+
Renderer callbacks / s
+
+ {formatRate(metrics.cellRendererCallsPerSecond)} +
+
+
+
Component executions / s
+
+ {formatRate(metrics.componentRenderCallsPerSecond)} +
+
+
+
Executions by component / s
+
+ {formatInvocationRates(metrics.componentRenderRates)} +
+
+
+
Callbacks by column / s
+
+ {formatInvocationRates(metrics.cellRendererRates)} +
+
+
+
Observed MutationRecords / s
+
+ {formatRate(metrics.domMutationsPerSecond)} +
+
+
+
React Profiler commits / s
+
+ {profilerEnabled + ? metrics.profilerCommitsPerSecond.toFixed(1) + : 'PROFILE BUILD REQUIRED'} +
+
+
+
Profiler actual avg / p95
+
+ {profilerEnabled + ? `${formatMs(metrics.profilerAverageActualMs)} / ${formatMs( + metrics.profilerP95ActualMs, + )}` + : 'N/A'} +
+
+
+
Profiler base avg
+
+ {profilerEnabled ? formatMs(metrics.profilerAverageBaseMs) : 'N/A'} +
+
+
+
Core row model calls / s
+
+ {metrics.rowModelCallsPerSecond.toFixed(1)} +
+
+
+
Core row model avg / max
+
+ {formatMs(metrics.rowModelAverageMs)} /{' '} + {formatMs(metrics.rowModelMaxMs)} +
+
+
+
Visible rows
+
+ {formatInteger(metrics.visibleRows)} +
+
+
+
Worker messages
+
+ {formatInteger(metrics.workerMessages)} +
+
+
+
Worker-coalesced updates / s
+
+ {formatRate(metrics.supersededUpdatesPerSecond)} +
+
+
+
Last message samples / updated rows
+
+ {formatInteger(metrics.lastBatchSize)} /{' '} + {formatInteger(metrics.lastUpdateCount)} +
+
+
+
Commits > 16.7 ms since reset
+
{metrics.slowCommits}
+
+
+
Long animation frames
+
+ {longAnimationFramesSupported + ? formatInteger(metrics.longAnimationFrames) + : 'Unsupported'} +
+
+
+
+ JS heap (GC-sensitive) +
+
+ {metrics.heapMb === null + ? 'N/A' + : `${metrics.heapMb.toFixed(1)} MB`} +
+
+
+
+ ) +} + +function SelectedInstrument() { + const controller = useTradingShellController() + const feed = useMarketFeedController() + const selectedSymbol = useSelector(controller.renderAtoms.selectedSymbol) + const quotes = useSelector(feed.quotes) + const selectedQuote = feed.getQuoteBySymbol(quotes, selectedSymbol) + return ( +
+

SELECTED INSTRUMENT

+ {selectedQuote ? ( + <> +
+
+ {selectedQuote.symbol} + {selectedQuote.company} +
+ {selectedQuote.venue} +
+
+
+
Last
+
{selectedQuote.price.toFixed(2)}
+
+
+
Bid / ask
+
+ {selectedQuote.bid.toFixed(2)} / {selectedQuote.ask.toFixed(2)} +
+
+
+ + ) : ( +

+ Click or begin a cell selection in any row to inspect its instrument. +

+ )} +
+ ) +} + +function formatInteger(value: number): string { + return integerFormatter.format(value) +} + +function formatRate(value: number): string { + return rateFormatter.format(value) +} + +function formatMs(value: number): string { + return `${value.toFixed(2)} ms` +} + +function formatInvocationRates( + rates: FeedMetrics['componentRenderRates'], +): string { + const activeRates = rates + .filter((rate) => rate.callsPerSecond > 0) + .sort((left, right) => right.callsPerSecond - left.callsPerSecond) + return activeRates.length === 0 + ? 'No calls in sample' + : activeRates + .map((rate) => `${rate.name} ${formatRate(rate.callsPerSecond)}`) + .join(' · ') +} diff --git a/examples/react/realtime-trading/src/shell/configurator-options.ts b/examples/react/realtime-trading/src/shell/configurator-options.ts new file mode 100644 index 0000000000..49a9566fe7 --- /dev/null +++ b/examples/react/realtime-trading/src/shell/configurator-options.ts @@ -0,0 +1,55 @@ +export interface ConfiguratorOption { + readonly label: string + readonly value: TValue +} + +const instrumentCountOptions = [ + { label: '50', value: 50 }, + { label: '100', value: 100 }, + { label: '150', value: 150 }, + { label: '250', value: 250 }, + { label: '350', value: 350 }, + { label: '500', value: 500 }, + { label: '750', value: 750 }, + { label: '1,000', value: 1_000 }, + { label: '1,500', value: 1_500 }, + { label: '2,500', value: 2_500 }, + { label: '5,000', value: 5_000 }, + { label: '1,000,000', value: 1_000_000 }, + { label: '10,000,000', value: 10_000_000 }, +] as const satisfies ReadonlyArray> + +const workerDeliveryOptions = [ + { label: '8 ms · 125 msg/s', value: 8 }, + { label: '16 ms · 62.5 msg/s', value: 16 }, + { label: '20 ms · 50 msg/s', value: 20 }, + { label: '33 ms · 30 msg/s', value: 33 }, + { label: '50 ms · 20 msg/s', value: 50 }, + { label: '100 ms · 10 msg/s', value: 100 }, + { label: '250 ms · 4 msg/s', value: 250 }, + { label: '500 ms · 2 msg/s', value: 500 }, + { label: '1,000 ms · 1 msg/s', value: 1_000 }, +] as const satisfies ReadonlyArray> + +const rowRenderingOptions = [ + { label: 'Full DOM · render every row', value: 'none' }, + { label: 'TanStack Virtual · visible rows only', value: 'tanstack' }, +] as const satisfies ReadonlyArray> + +const intradaySamplingOptions = [ + { label: '16 ms · fastest', value: 16 }, + { label: '33 ms · very fast', value: 33 }, + { label: '50 ms · fast', value: 50 }, + { label: '100 ms', value: 100 }, + { label: '250 ms', value: 250 }, + { label: '500 ms', value: 500 }, + { label: '1,000 ms', value: 1_000 }, + { label: '2,000 ms', value: 2_000 }, +] as const satisfies ReadonlyArray> + +export const configuratorOptions = { + instrumentCounts: instrumentCountOptions, + workerDeliveryIntervals: workerDeliveryOptions, + rowRenderingModes: rowRenderingOptions, + intradaySamplingIntervals: intradaySamplingOptions, +} as const diff --git a/examples/react/realtime-trading/src/shell/trading-shell-context.tsx b/examples/react/realtime-trading/src/shell/trading-shell-context.tsx new file mode 100644 index 0000000000..1c876ec374 --- /dev/null +++ b/examples/react/realtime-trading/src/shell/trading-shell-context.tsx @@ -0,0 +1,50 @@ +import { createStoreContext, useSelector } from '@tanstack/react-store' +import type { ReactNode } from 'react' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { TradingBenchmarkController } from '../benchmark/use-trading-benchmark-controller' +import type { TradingBenchmarkState } from '../benchmark/trading-benchmark-controller' +import type { UseSelectorOptions } from '@tanstack/react-store' + +const { + StoreProvider: TradingStoreProvider, + useStoreContext: useTradingShellController, +} = createStoreContext() + +const { + StoreProvider: MarketFeedStoreProvider, + useStoreContext: useMarketFeedController, +} = createStoreContext() + +export function MarketFeedProvider(props: { + controller: MarketFeedController + children: ReactNode +}) { + return ( + + {props.children} + + ) +} + +export function TradingShellProvider(props: { + controller: TradingBenchmarkController + children: ReactNode +}) { + return ( + + + {props.children} + + + ) +} + +export { useMarketFeedController, useTradingShellController } + +export function useTradingShellState( + selector: (state: TradingBenchmarkState) => TSelected, + options?: UseSelectorOptions, +): TSelected { + const controller = useTradingShellController() + return useSelector(controller.store, selector, options) +} diff --git a/examples/react/realtime-trading/src/table/table-config/quote-cells.tsx b/examples/react/realtime-trading/src/table/table-config/quote-cells.tsx new file mode 100644 index 0000000000..1c5ff4523d --- /dev/null +++ b/examples/react/realtime-trading/src/table/table-config/quote-cells.tsx @@ -0,0 +1,219 @@ +import { useEffect } from 'react' + +const compactNumber = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) + +export const quoteCellLifecycle = { + created: 0, + destroyed: 0, +} + +export const quoteCellRendererNames = [ + 'Market', + 'Name', + 'Symbol', + 'Last', + 'Change', + 'ChangePercent', + 'Bid', + 'BidVolume', + 'Ask', + 'AskVolume', + 'Open', + 'High', + 'Low', + 'Intraday', +] as const + +export const quoteComponentNames = [ + 'PriceCell', + 'StableMoveCell', + 'UpMoveCell', + 'DownMoveCell', + 'PercentChangeCell', + 'SpreadCell', + 'DepthCell', + 'QuoteAgeCell', + 'SparklineCell', +] as const + +export type QuoteCellRendererName = (typeof quoteCellRendererNames)[number] +export type QuoteComponentName = (typeof quoteComponentNames)[number] + +const createCounterMap = ( + names: ReadonlyArray, +): Record => + Object.fromEntries(names.map((name) => [name, 0])) as Record + +export const quoteRenderDiagnostics = { + cellRendererCalls: 0, + componentRenderCalls: 0, + cellRendererCallsByName: createCounterMap(quoteCellRendererNames), + componentRenderCallsByName: createCounterMap(quoteComponentNames), +} + +export function recordCellRender(name: QuoteCellRendererName, value: T): T { + 'use no memo' + // Benchmark instrumentation is intentionally impure and must run per call. + quoteRenderDiagnostics.cellRendererCalls++ + quoteRenderDiagnostics.cellRendererCallsByName[name]++ + return value +} + +function useLifecycleCounter(componentName: QuoteComponentName): void { + 'use no memo' + // This diagnostic mutation measures component-function invocation itself. + quoteRenderDiagnostics.componentRenderCalls++ + quoteRenderDiagnostics.componentRenderCallsByName[componentName]++ + useEffect(() => { + quoteCellLifecycle.created++ + return () => { + quoteCellLifecycle.destroyed++ + } + }, []) +} + +export function PriceCell(props: { + price: number + move: number + onSelect: () => void +}) { + useLifecycleCounter('PriceCell') + return ( + + ) +} + +export function StableMoveCell({ move }: { move: number }) { + useLifecycleCounter('StableMoveCell') + return ( + = 0 ? 'quote-up' : 'quote-down'}`}> + {formatSigned(move)} + + ) +} + +export function UpMoveCell({ move }: { move: number }) { + useLifecycleCounter('UpMoveCell') + return ▲ {formatSigned(move)} +} + +export function DownMoveCell({ move }: { move: number }) { + useLifecycleCounter('DownMoveCell') + return ▼ {formatSigned(move)} +} + +export function PercentChangeCell({ value }: { value: number }) { + useLifecycleCounter('PercentChangeCell') + return ( + = 0 ? 'quote-up' : 'quote-down'}`} + > + {value >= 0 ? '+' : ''} + {value.toFixed(2)}% + + ) +} + +export function SpreadCell({ bid, ask }: { bid: number; ask: number }) { + useLifecycleCounter('SpreadCell') + const spread = Math.max(0, ask - bid) + const midpoint = (bid + ask) / 2 + const basisPoints = midpoint === 0 ? 0 : (spread / midpoint) * 10_000 + + return ( + = 4 ? 'spread-wide' : ''}`}> + {spread.toFixed(2)} + {basisPoints.toFixed(1)} bp + + ) +} + +export function DepthCell(props: { bidSize: number; askSize: number }) { + useLifecycleCounter('DepthCell') + const total = props.bidSize + props.askSize + const bidShare = total === 0 ? 50 : (props.bidSize / total) * 100 + + return ( +
+ + + + {compactNumber.format(props.bidSize)} + {compactNumber.format(props.askSize)} + +
+ ) +} + +export function QuoteAgeCell({ ageMs }: { ageMs: number }) { + useLifecycleCounter('QuoteAgeCell') + const className = + ageMs >= 1_500 + ? 'quote-age quote-age-stale' + : ageMs >= 500 + ? 'quote-age quote-age-warm' + : 'quote-age' + + return ( + + {ageMs < 1_000 + ? `${Math.round(ageMs)} ms` + : `${(ageMs / 1_000).toFixed(1)} s`} + + ) +} + +export function SparklineCell({ values }: { values: ReadonlyArray }) { + useLifecycleCounter('SparklineCell') + const rising = (values.at(-1) ?? 0) >= (values[0] ?? 0) + const { min, max } = findRange(values) + const range = max - min || 1 + const denominator = Math.max(1, values.length - 1) + const points = values + .map((value, index) => { + const x = (index / denominator) * 100 + const y = 22 - ((value - min) / range) * 20 + return `${x.toFixed(1)},${y.toFixed(1)}` + }) + .join(' ') + + return ( + + + + ) +} + +function formatSigned(value: number): string { + return `${value >= 0 ? '+' : ''}${value.toFixed(2)}` +} + +function findRange(values: ReadonlyArray): { + min: number + max: number +} { + const first = values[0] ?? 0 + return values.reduce( + (range, value) => { + range.min = Math.min(range.min, value) + range.max = Math.max(range.max, value) + return range + }, + { min: first, max: first }, + ) +} diff --git a/examples/react/realtime-trading/src/table/table-config/trading-table-config.tsx b/examples/react/realtime-trading/src/table/table-config/trading-table-config.tsx new file mode 100644 index 0000000000..8b89f56f6a --- /dev/null +++ b/examples/react/realtime-trading/src/table/table-config/trading-table-config.tsx @@ -0,0 +1,267 @@ +import { createColumnHelper } from '@tanstack/react-table' +import { useSelector } from '@tanstack/react-store' +import { useTradingShellController } from '../../shell/trading-shell-context' +import { tradingFeatures } from '../trading-features' +import { + DownMoveCell, + PercentChangeCell, + PriceCell, + SparklineCell, + StableMoveCell, + UpMoveCell, + recordCellRender, +} from './quote-cells' +import type { ReactNode } from 'react' +import type { MarketQuote } from '../../feed/market-data' + +export type RendererMode = 'stable' | 'swap' +export interface CoreTableState { + sorting: Array<{ id: string; desc: boolean }> + columnFilters: Array<{ id: string; value: unknown }> +} + +const compactFormatter = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +const columnHelper = createColumnHelper() + +export const tradingColumns = columnHelper.columns([ + columnHelper.group({ + id: 'instrument', + header: 'Instrument', + columns: columnHelper.columns([ + columnHelper.accessor('venue', { + id: 'market', + header: 'Market', + size: 72, + cell: (info) => recordCellRender('Market', info.getValue()), + }), + columnHelper.accessor('company', { + id: 'name', + header: 'Name', + size: 180, + cell: (info) => recordCellRender('Name', info.getValue()), + }), + columnHelper.accessor('symbol', { + header: 'Symbol', + size: 92, + filterFn: 'includesString', + cell: (info) => recordCellRender('Symbol', info.getValue()), + }), + ]), + }), + columnHelper.group({ + id: 'priceAndChange', + header: 'Price & Change', + columns: columnHelper.columns([ + columnHelper.accessor('price', { + header: 'Price', + size: 96, + sortFn: 'basic', + cell: (info) => + recordCellRender('Last', ), + }), + columnHelper.accessor((row) => getDayChange(row), { + id: 'change', + header: 'Chg', + size: 94, + cell: (info) => + recordCellRender( + 'Change', + , + ), + }), + columnHelper.accessor((row) => getDayChangePercent(row), { + id: 'changePercent', + header: 'Chg%', + size: 90, + cell: (info) => + recordCellRender( + 'ChangePercent', + , + ), + }), + ]), + }), + columnHelper.group({ + id: 'orderBook', + header: 'Order Book', + columns: columnHelper.columns([ + columnHelper.accessor('bid', { + header: 'Bid', + size: 90, + cell: (info) => recordCellRender('Bid', info.getValue().toFixed(2)), + }), + columnHelper.accessor('bidSize', { + header: 'Bid Vol', + size: 100, + cell: (info) => + recordCellRender( + 'BidVolume', + compactFormatter.format(info.getValue()), + ), + }), + columnHelper.accessor('ask', { + header: 'Ask', + size: 90, + cell: (info) => recordCellRender('Ask', info.getValue().toFixed(2)), + }), + columnHelper.accessor('askSize', { + header: 'Ask Vol', + size: 100, + cell: (info) => + recordCellRender( + 'AskVolume', + compactFormatter.format(info.getValue()), + ), + }), + ]), + }), + columnHelper.group({ + id: 'session', + header: 'Session', + columns: columnHelper.columns([ + columnHelper.accessor('open', { + header: 'Open', + size: 90, + cell: (info) => recordCellRender('Open', info.getValue().toFixed(2)), + }), + columnHelper.accessor('high', { + header: 'High', + size: 90, + cell: (info) => recordCellRender('High', info.getValue().toFixed(2)), + }), + columnHelper.accessor('low', { + header: 'Low', + size: 90, + cell: (info) => recordCellRender('Low', info.getValue().toFixed(2)), + }), + ]), + }), + columnHelper.group({ + id: 'chart', + header: 'Chart', + columns: columnHelper.columns([ + columnHelper.accessor('history', { + header: 'Intraday', + size: 150, + enableSorting: false, + cell: (info) => + recordCellRender( + 'Intraday', + , + ), + }), + ]), + }), +]) + +export const rowModelDiagnostics = { + hasMeasurement: false, + calls: 0, + totalDurationMs: 0, + maxDurationMs: 0, + lastRowCount: 0, +} + +export const TRADING_COLUMN_COUNT = 14 + +export function readMeasuredRows(readRows: () => Array): Array { + const start = performance.now() + const rows = readRows() + const end = performance.now() + const duration = end - start + + rowModelDiagnostics.calls++ + rowModelDiagnostics.hasMeasurement = true + rowModelDiagnostics.totalDurationMs += duration + rowModelDiagnostics.maxDurationMs = Math.max( + rowModelDiagnostics.maxDurationMs, + duration, + ) + rowModelDiagnostics.lastRowCount = rows.length + + if (rowModelDiagnostics.calls % 1_000 === 0) { + performance.clearMeasures('tanstack-row-model') + } + if ((rowModelDiagnostics.calls - 1) % 20 === 0) { + try { + performance.measure('tanstack-row-model', { + start, + end, + detail: { rowCount: rows.length }, + }) + } catch { + // User Timing Level 3 detail is not implemented in every browser. + } + } + + return rows +} + +function LastPriceCell(props: { quote: MarketQuote }) { + const { selectSymbol } = useTradingShellController().actions + return ( + selectSymbol(props.quote.symbol)} + /> + ) +} + +function DayChangeCell(props: { quote: MarketQuote }) { + const { rendererMode } = useTradingShellController().renderAtoms + const mode = useSelector(rendererMode) + const change = getDayChange(props.quote) + if (mode === 'stable') { + return + } + return change >= 0 ? ( + + ) : ( + + ) +} + +export function TradingRow(props: { + quote: MarketQuote + children: ReactNode + rowSelected: boolean + virtualRow?: { index: number; start: number } +}) { + const { selectedSymbol } = useTradingShellController().renderAtoms + const selected = useSelector( + selectedSymbol, + (symbol) => symbol === props.quote.symbol, + ) + return ( + + {props.children} + + ) +} + +function getDayChange(quote: MarketQuote): number { + return quote.price - quote.previousClose +} + +function getDayChangePercent(quote: MarketQuote): number { + return quote.previousClose === 0 + ? 0 + : (getDayChange(quote) / quote.previousClose) * 100 +} diff --git a/examples/react/realtime-trading/src/table/table-interactions.ts b/examples/react/realtime-trading/src/table/table-interactions.ts new file mode 100644 index 0000000000..a7458f73ff --- /dev/null +++ b/examples/react/realtime-trading/src/table/table-interactions.ts @@ -0,0 +1,147 @@ +import type { AriaAttributes, KeyboardEvent as ReactKeyboardEvent } from 'react' + +export type CellDirection = 'up' | 'down' | 'left' | 'right' + +interface RowSelectionTable { + resetRowSelection: (defaultState?: boolean) => void +} + +interface SelectableRow { + getIsSelected: () => boolean + getToggleSelectedHandler: (options?: { + selectChildren?: boolean + }) => (event: unknown) => void +} + +interface SelectableGridCell { + row: SelectableGridRow + getSelectionStartHandler: ( + contextDocument?: Document, + ) => (event: unknown) => void + getSelectionExtendHandler: () => (event: unknown) => void +} + +interface SelectableGridRow extends SelectableRow { + original: { symbol: string } + getAllCellsByColumnId: () => Partial> +} + +export interface TradingGridTable extends RowSelectionTable { + getRowModel: () => { + rowsById: Partial> + } +} + +export interface SelectionCellTarget { + element: HTMLTableCellElement + cell: SelectableGridCell +} + +interface CellNavigationTable { + extendCellSelection: (direction: CellDirection) => void + moveCellSelection: (direction: CellDirection) => void + resetCellSelection: (defaultState?: boolean) => void + selectAllCells: () => void +} + +const keyDirections: Partial> = { + ArrowUp: 'up', + ArrowDown: 'down', + ArrowLeft: 'left', + ArrowRight: 'right', +} + +export function reorderColumnIds( + columnIds: Array, + sourceId: string, + targetId: string, +): Array { + if (sourceId === targetId || !columnIds.includes(sourceId)) return columnIds + + const withoutSource = columnIds.filter((id) => id !== sourceId) + const targetIndex = withoutSource.indexOf(targetId) + if (targetIndex < 0) return columnIds + + return [ + ...withoutSource.slice(0, targetIndex), + sourceId, + ...withoutSource.slice(targetIndex), + ] +} + +export function selectRowFromPointer( + table: RowSelectionTable, + row: SelectableRow, + event: MouseEvent, +): void { + const additive = event.ctrlKey || event.metaKey + const checked = additive ? !row.getIsSelected() : true + + if (!event.shiftKey && !additive) table.resetRowSelection(true) + + row.getToggleSelectedHandler({ selectChildren: false })({ + target: { checked }, + shiftKey: event.shiftKey, + ctrlKey: event.ctrlKey, + metaKey: event.metaKey, + nativeEvent: event, + }) +} + +export function findTradingGridCellTarget( + table: TradingGridTable, + path: Array, +): SelectionCellTarget | null { + for (const target of path) { + if (!(target instanceof HTMLTableCellElement)) continue + + const columnId = target.dataset['columnId'] + const rowId = + target.closest('tr[data-row-id]')?.dataset['rowId'] + if (!columnId || !rowId) return null + + const row = table.getRowModel().rowsById[rowId] + const cell = row?.getAllCellsByColumnId()[columnId] + return row && cell ? { element: target, cell } : null + } + + return null +} + +export function handleCellNavigation( + table: CellNavigationTable, + event: ReactKeyboardEvent, +): void { + if (event.key === 'Escape') { + event.preventDefault() + table.resetCellSelection(true) + return + } + + if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'a') { + event.preventDefault() + table.selectAllCells() + return + } + + const direction = keyDirections[event.key] + if (!direction) return + + event.preventDefault() + if (event.shiftKey) table.extendCellSelection(direction) + else table.moveCellSelection(direction) +} + +export function sortIndicator(direction: false | 'asc' | 'desc'): string { + if (direction === 'asc') return '↑' + if (direction === 'desc') return '↓' + return '↕' +} + +export function sortAriaValue( + direction: false | 'asc' | 'desc', +): AriaAttributes['aria-sort'] { + if (direction === 'asc') return 'ascending' + if (direction === 'desc') return 'descending' + return 'none' +} diff --git a/examples/react/realtime-trading/src/table/trading-features.ts b/examples/react/realtime-trading/src/table/trading-features.ts new file mode 100644 index 0000000000..7ee77afd06 --- /dev/null +++ b/examples/react/realtime-trading/src/table/trading-features.ts @@ -0,0 +1,16 @@ +import { + createFilteredRowModel, + createSortedRowModel, + filterFn_includesString, + sortFn_basic, + stockFeatures, + tableFeatures, +} from '@tanstack/react-table' + +export const tradingFeatures = tableFeatures({ + ...stockFeatures, + filteredRowModel: createFilteredRowModel(), + sortedRowModel: createSortedRowModel(), + filterFns: { includesString: filterFn_includesString }, + sortFns: { basic: sortFn_basic }, +}) diff --git a/examples/react/realtime-trading/src/table/trading-row-virtualizer.ts b/examples/react/realtime-trading/src/table/trading-row-virtualizer.ts new file mode 100644 index 0000000000..bc4b34b528 --- /dev/null +++ b/examples/react/realtime-trading/src/table/trading-row-virtualizer.ts @@ -0,0 +1,18 @@ +export const TRADING_ROW_HEIGHT = 32 +export const TRADING_ROW_OVERSCAN = 10 +export const DEFAULT_VIRTUALIZATION_ROW_COUNT = 200 +export const FORCED_VIRTUALIZATION_ROW_COUNT = 1_500 + +export type VirtualScrollMode = 'tanstack' | 'none' +export type VirtualScrollPreference = VirtualScrollMode | 'auto' + +export function resolveVirtualScrollMode( + requestedMode: VirtualScrollPreference, + instrumentCount: number, +): VirtualScrollMode { + if (instrumentCount >= FORCED_VIRTUALIZATION_ROW_COUNT) return 'tanstack' + if (requestedMode !== 'auto') return requestedMode + return instrumentCount >= DEFAULT_VIRTUALIZATION_ROW_COUNT + ? 'tanstack' + : 'none' +} diff --git a/examples/react/realtime-trading/src/table/trading-table.tsx b/examples/react/realtime-trading/src/table/trading-table.tsx new file mode 100644 index 0000000000..46298f5abd --- /dev/null +++ b/examples/react/realtime-trading/src/table/trading-table.tsx @@ -0,0 +1,588 @@ +import { FlexRender, useTable } from '@tanstack/react-table' +import { useVirtualizer } from '@tanstack/react-virtual' +import { useSelector } from '@tanstack/react-store' +import { useLayoutEffect, useRef } from 'react' +import { useTableBenchmark } from '../benchmark/use-table-benchmark' +import { + useMarketFeedController, + useTradingShellController, + useTradingShellState, +} from '../shell/trading-shell-context' +import { + TradingRow, + readMeasuredRows, + tradingColumns, +} from './table-config/trading-table-config' +import { + handleCellNavigation, + reorderColumnIds, + sortAriaValue, + sortIndicator, +} from './table-interactions' +import { useTradingGridPointer } from './use-trading-grid-pointer' +import { tradingFeatures } from './trading-features' +import { + TRADING_ROW_HEIGHT, + TRADING_ROW_OVERSCAN, + resolveVirtualScrollMode, +} from './trading-row-virtualizer' +import type { VirtualScrollMode } from './trading-row-virtualizer' +import type { + CellSelectionBounds, + CellSelectionState, +} from '@tanstack/react-table' +import type { VirtualItem } from '@tanstack/react-virtual' +import type { MarketQuote } from '../feed/market-data' +import type { CoreTableState } from './table-config/trading-table-config' + +export { + TRADING_COLUMN_COUNT, + rowModelDiagnostics, +} from './table-config/trading-table-config' +export type { + CoreTableState, + RendererMode, +} from './table-config/trading-table-config' +export type { VirtualScrollMode } from './trading-row-virtualizer' + +export function TradingTable() { + const controller = useTradingShellController() + const feed = useMarketFeedController() + const quotes = useSelector(feed.quotes) + const requestedVirtualScrollMode = useTradingShellState( + (state) => state.requestedVirtualScrollMode, + ) + const instrumentCount = useSelector(feed.instrumentCount) + const virtualScrollMode = resolveVirtualScrollMode( + requestedVirtualScrollMode, + instrumentCount, + ) + + useLayoutEffect(() => feed.completeRender()) + useTableBenchmark(controller) + const table = useTradingTable({ quotes }) + const layoutRefs = useTradingTableLayout(table) + + return ( + ({ + sorting: state.sorting, + columnFilters: state.columnFilters, + columnOrder: state.columnOrder, + })} + > + {(coreState) => ( + + )} + + ) +} + +type TradingTableInstance = ReturnType + +interface ColumnDragRuntime { + columnId: string | null + sourceElement: HTMLTableCellElement | null + targetElement: HTMLTableCellElement | null +} + +function clearColumnDrag(runtime: ColumnDragRuntime): void { + runtime.sourceElement?.classList.remove('is-column-dragging') + runtime.targetElement?.classList.remove('is-column-drop-target') + runtime.columnId = null + runtime.sourceElement = null + runtime.targetElement = null +} + +function showColumnDropTarget( + runtime: ColumnDragRuntime, + targetColumnId: string, + targetElement: HTMLTableCellElement | null, +): void { + runtime.targetElement?.classList.remove('is-column-drop-target') + runtime.targetElement = null + if (runtime.columnId === targetColumnId || !targetElement) return + targetElement.classList.add('is-column-drop-target') + runtime.targetElement = targetElement +} + +function useTradingTableLayout(table: TradingTableInstance) { + const scrollRef = useRef(null) + const tableRef = useRef(null) + const fitRuntime = useRef({ manuallyResized: false }) + const tableRuntime = useRef(table) + tableRuntime.current = table + + useLayoutEffect(() => { + const writeColumnSizes = () => { + const currentTable = tableRuntime.current + const tableElement = tableRef.current + if (!tableElement) return + for (const header of currentTable.getFlatHeaders()) { + tableElement.style.setProperty( + `--header-${header.id}-size`, + String(header.getSize()), + ) + tableElement.style.setProperty( + `--col-${header.column.id}-size`, + String(header.column.getSize()), + ) + } + tableElement.style.width = `${currentTable.getTotalSize()}px` + } + + writeColumnSizes() + const sizingSubscription = + tableRuntime.current.atoms.columnSizing.subscribe(writeColumnSizes) + const orderSubscription = + tableRuntime.current.atoms.columnOrder.subscribe(writeColumnSizes) + const fitAvailableWidth = () => { + const currentTable = tableRuntime.current + const scrollElement = scrollRef.current + if (!scrollElement || fitRuntime.current.manuallyResized) return + const currentWidth = currentTable.getTotalSize() + const availableWidth = scrollElement.clientWidth + if (availableWidth <= currentWidth + 1 || currentWidth <= 0) return + + const ratio = availableWidth / currentWidth + currentTable.setColumnSizing( + Object.fromEntries( + currentTable + .getVisibleLeafColumns() + .map((column) => [column.id, column.getSize() * ratio]), + ), + ) + } + const resizeObserver = new ResizeObserver(fitAvailableWidth) + const resizingSubscription = + tableRuntime.current.atoms.columnResizing.subscribe((state) => { + if (state.isResizingColumn !== false) { + fitRuntime.current.manuallyResized = true + } + }) + if (scrollRef.current) resizeObserver.observe(scrollRef.current) + fitAvailableWidth() + + return () => { + sizingSubscription.unsubscribe() + orderSubscription.unsubscribe() + resizingSubscription.unsubscribe() + resizeObserver.disconnect() + } + }, []) + + return { scrollRef, tableRef } +} + +function TradingTableHeader(props: { table: TradingTableInstance }) { + const dragRuntime = useRef({ + columnId: null, + sourceElement: null, + targetElement: null, + }) + + return ( + ({ + columnOrder: state.columnOrder, + sorting: state.sorting, + })} + > + {() => ( + + {props.table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + const isLeaf = header.subHeaders.length === 0 + const sorted = header.column.getIsSorted() + return ( + + {!header.isPlaceholder && + (isLeaf ? ( + <> +
{ + event.preventDefault() + showColumnDropTarget( + dragRuntime.current, + header.column.id, + event.currentTarget.closest('th'), + ) + }} + onDrop={(event) => { + event.preventDefault() + const sourceId = + event.dataTransfer.getData('text/plain') || + dragRuntime.current.columnId + if (sourceId) { + props.table.setColumnOrder( + reorderColumnIds( + props.table + .getVisibleLeafColumns() + .map((column) => column.id), + sourceId, + header.column.id, + ), + ) + } + clearColumnDrag(dragRuntime.current) + }} + > + + +
+ {header.column.getCanResize() && ( + + state.columnResizing.isResizingColumn === + header.column.id + } + > + {(isResizing) => ( +
+ header.column.resetSize() + } + onMouseDown={header.getResizeHandler()} + onTouchStart={header.getResizeHandler()} + /> + )} + + )} + + ) : ( + + ))} + + ) + })} + + ))} + + )} + + ) +} + +function useTradingTable(props: { quotes: Array }) { + return useTable( + { + key: 'react-realtime-trading', + features: tradingFeatures, + columns: tradingColumns, + data: props.quotes, + getRowId: (row) => row.id, + columnResizeMode: 'onChange', + defaultColumn: { minSize: 56, maxSize: 800 }, + autoResetCellSelection: false, + }, + () => null, + ) +} + +function TradingTableViewport(props: { + table: ReturnType + rows: ReturnType['getRowModel']>['rows'] + sourceRowCount: number + layoutRefs: ReturnType + virtualScrollMode: VirtualScrollMode + reportRenderedRowCount: (count: number) => void +}) { + const rowVirtualizer = useVirtualizer({ + count: props.rows.length, + estimateSize: () => TRADING_ROW_HEIGHT, + getScrollElement: () => props.layoutRefs.scrollRef.current, + getItemKey: (index) => props.rows[index]?.id ?? index, + overscan: TRADING_ROW_OVERSCAN, + enabled: props.virtualScrollMode === 'tanstack', + }) + const virtualRows = rowVirtualizer.getVirtualItems() + const renderedRowCount = + props.virtualScrollMode === 'tanstack' + ? virtualRows.length + : props.rows.length + const visibleRange = readVisibleRange( + rowVirtualizer.range, + props.rows.length, + props.virtualScrollMode, + ) + + useLayoutEffect(() => { + props.reportRenderedRowCount(renderedRowCount) + }, [props.reportRenderedRowCount, renderedRowCount]) + + return ( + <> +
handleCellNavigation(props.table, event)} + > + + + +
+
+ {props.virtualScrollMode === 'tanstack' && ( +
+ + TanStack · Total · {props.rows.length} rows ·{' '} + {props.table.getVisibleLeafColumns().length} columns + + + {visibleRange + ? `Current · rows ${visibleRange.start}..${visibleRange.end}` + : 'Current · rows —'} + +
+ )} + + ) +} + +function TradingRows(props: { + table: ReturnType + rows: ReturnType['getRowModel']>['rows'] + sourceRowCount: number + virtualRows: Array + virtualScrollMode: VirtualScrollMode +}) { + const { selectSymbol } = useTradingShellController().actions + const pointerInteractions = useTradingGridPointer(props.table, selectSymbol) + + return ( + + {props.virtualScrollMode === 'tanstack' + ? props.virtualRows.map((virtualRow) => { + const row = props.rows[virtualRow.index] + return ( + + ) + }) + : props.rows.map((row) => ( + + ))} + + ) +} + +type TradingTableRow = ReturnType< + ReturnType['getRowModel'] +>['rows'][number] + +function TradingRowBoundary(props: { + table: ReturnType + row: TradingTableRow + virtualRow?: VirtualItem +}) { + const { row, table, virtualRow } = props + + return ( + + `${row.id in state.rowSelection ? 1 : 0}:${cellSelectionRowKey( + state.cellSelection, + table.getCellSelectionBounds(), + row.getDisplayIndex(), + row.id, + )}` + } + > + {() => ( + + {row.getVisibleCells().map((cell) => { + const edges = cell.getSelectionEdges() + + return ( + + + + ) + })} + + )} + + ) +} + +function getHeaderClassName(header: { + subHeaders: ReadonlyArray + column: { id: string } +}): string | undefined { + if (header.subHeaders.length > 0) return 'column-group-header' + return isTextColumn(header.column.id) ? undefined : 'numeric-header' +} + +function isTextColumn(columnId: string): boolean { + return columnId === 'market' || columnId === 'name' || columnId === 'symbol' +} + +function readVisibleRange( + range: { startIndex: number; endIndex: number } | null, + rowCount: number, + virtualScrollMode: VirtualScrollMode, +): { start: number; end: number } | null { + if (virtualScrollMode !== 'tanstack' || rowCount === 0 || range === null) { + return null + } + + const lastRowIndex = rowCount - 1 + const start = Math.min(range.startIndex, lastRowIndex) + return { + start, + end: Math.min(Math.max(start, range.endIndex), lastRowIndex), + } +} + +function readRows( + table: ReturnType, + quoteSnapshot: Array, + coreState: CoreTableState, +) { + void quoteSnapshot + void coreState + return readMeasuredRows(() => table.getRowModel().rows) +} + +function cellSelectionRowKey( + ranges: CellSelectionState, + bounds: Array, + rowIndex: number, + rowId: string, +): string { + const active = ranges.at(-1) + const initial = + active?.anchorRowId === rowId ? `f${active.anchorColumnId}` : '' + + return bounds.reduce((key, bound) => { + const self = rowIndex >= bound.minRowIndex && rowIndex <= bound.maxRowIndex + const above = + rowIndex - 1 >= bound.minRowIndex && rowIndex - 1 <= bound.maxRowIndex + const below = + rowIndex + 1 >= bound.minRowIndex && rowIndex + 1 <= bound.maxRowIndex + if (!self && !above && !below) return key + return `${key}|${self ? 1 : 0}${above ? 1 : 0}${below ? 1 : 0}:${bound.minColumnIndex}-${bound.maxColumnIndex}` + }, initial) +} diff --git a/examples/react/realtime-trading/src/table/use-trading-grid-pointer.ts b/examples/react/realtime-trading/src/table/use-trading-grid-pointer.ts new file mode 100644 index 0000000000..a2209c3d7c --- /dev/null +++ b/examples/react/realtime-trading/src/table/use-trading-grid-pointer.ts @@ -0,0 +1,76 @@ +import { useRef } from 'react' +import { + findTradingGridCellTarget, + selectRowFromPointer, +} from './table-interactions' +import type { + MouseEvent as ReactMouseEvent, + PointerEvent as ReactPointerEvent, +} from 'react' +import type { TradingGridTable } from './table-interactions' + +export interface TradingGridPointerHandlers { + readonly onMouseDown: ( + event: ReactMouseEvent, + ) => void + readonly onPointerOver: ( + event: ReactPointerEvent, + ) => void + readonly onMouseLeave: () => void + readonly onClick: (event: ReactMouseEvent) => void +} + +export function useTradingGridPointer( + table: TradingGridTable, + selectSymbol: (symbol: string) => void, +): TradingGridPointerHandlers { + const lastPointerCell = useRef(null) + + return { + onMouseDown(event) { + if (event.button !== 0) return + + const nativeEvent = event.nativeEvent + const target = findTradingGridCellTarget( + table, + nativeEvent.composedPath(), + ) + if (!target) return + + nativeEvent.preventDefault() + lastPointerCell.current = target.element + selectSymbol(target.cell.row.original.symbol) + target.cell.getSelectionStartHandler(target.element.ownerDocument)( + nativeEvent, + ) + }, + onPointerOver(event) { + const nativeEvent = event.nativeEvent + if ((nativeEvent.buttons & 1) === 0) { + lastPointerCell.current = null + return + } + + const target = findTradingGridCellTarget( + table, + nativeEvent.composedPath(), + ) + if (!target || target.element === lastPointerCell.current) return + + lastPointerCell.current = target.element + target.cell.getSelectionExtendHandler()(nativeEvent) + }, + onMouseLeave() { + lastPointerCell.current = null + }, + onClick(event) { + const nativeEvent = event.nativeEvent + const target = findTradingGridCellTarget( + table, + nativeEvent.composedPath(), + ) + if (!target) return + selectRowFromPointer(table, target.cell.row, nativeEvent) + }, + } +} diff --git a/examples/react/realtime-trading/src/vite-env.d.ts b/examples/react/realtime-trading/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/react/realtime-trading/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/react/realtime-trading/tests/e2e/smoke.spec.ts b/examples/react/realtime-trading/tests/e2e/smoke.spec.ts new file mode 100644 index 0000000000..5045105428 --- /dev/null +++ b/examples/react/realtime-trading/tests/e2e/smoke.spec.ts @@ -0,0 +1,160 @@ +import path from 'node:path' +import { expect, test } from '@playwright/test' +import { startExampleServer } from '../../../../../tests/e2e/helpers/startExampleServer' +import { + setRangeValue, + scrollTradingTable, + pausedFeedUrl, +} from '../../../../../tests/e2e/helpers/setRangeValue' +import type { Page } from '@playwright/test' + +const exampleDir = path.resolve() + +function collectPageErrors(page: Page) { + const errors: Array = [] + page.on('pageerror', (error) => errors.push(error.message)) + page.on('console', (message) => { + if (message.type() === 'error') errors.push(message.text()) + }) + return errors +} + +test('runs the React realtime trading workload', async ({ page }) => { + test.setTimeout(120_000) + const server = await startExampleServer(exampleDir) + const errors = collectPageErrors(page) + + try { + await page.route( + 'https://unpkg.com/react-scan/dist/auto.global.js', + (route) => + route.fulfill({ + contentType: 'application/javascript', + body: '', + }), + ) + + await page.goto(pausedFeedUrl(server.url)) + + const table = page.getByTestId('trading-table') + const instrumentCount = page.getByTestId('instrument-count-select') + const virtualScrollSelect = page.getByTestId('virtual-scroll-select') + await expect(table).toBeVisible() + await expect(instrumentCount).toHaveValue('100') + await expect(page.locator('.brand')).toHaveText('MARKET MONITOR') + await expect(virtualScrollSelect).toHaveValue('none') + await expect(virtualScrollSelect).toBeEnabled() + await expect(table.locator('tbody tr')).toHaveCount(100) + const firstRow = table.locator('tbody tr').first() + const selectedSymbol = await firstRow.getAttribute('data-symbol') + await firstRow.getByRole('button').click() + await expect(page.getByTestId('selected-instrument')).toContainText( + selectedSymbol ?? '', + ) + await expect(table.locator('tbody')).toHaveCSS('user-select', 'none') + await expect(table.locator('tbody tr').first()).toHaveCSS( + 'content-visibility', + 'auto', + ) + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await instrumentCount.selectOption('250') + await expect(virtualScrollSelect).toHaveValue('tanstack') + await expect(virtualScrollSelect).toBeEnabled() + await expect.poll(() => table.locator('tbody tr').count()).toBeLessThan(250) + await expect(page.getByTestId('virtual-scroll-footer')).toBeVisible() + await instrumentCount.selectOption('100') + await expect(virtualScrollSelect).toHaveValue('none') + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await virtualScrollSelect.selectOption('tanstack') + await expect.poll(() => table.locator('tbody tr').count()).toBeLessThan(100) + await expect(table.locator('tbody tr').first()).toHaveCSS( + 'content-visibility', + 'auto', + ) + await expect(page.getByTestId('virtual-scroll-footer')).toBeVisible() + await virtualScrollSelect.selectOption('none') + await expect(table.locator('tbody tr')).toHaveCount(100) + await instrumentCount.selectOption('1500') + await expect(virtualScrollSelect).toHaveValue('tanstack') + await expect(virtualScrollSelect).toBeDisabled() + await expect + .poll(() => table.locator('tbody tr').count()) + .toBeLessThan(1500) + await expect(page.getByTestId('virtual-scroll-footer')).toContainText( + 'Total · 1500 rows · 14 columns', + ) + await expect(page.getByTestId('visible-row-range')).toHaveText( + /^\s*Current · rows 0\.\.\d+\s*$/, + ) + await scrollTradingTable(page, 2_000) + await expect + .poll(async () => + Number( + await table + .locator('tbody tr') + .first() + .getAttribute('data-virtual-index'), + ), + ) + .toBeGreaterThan(0) + await expect(page.getByTestId('visible-row-range')).toHaveText( + /^\s*Current · rows [1-9]\d*\.\.\d+\s*$/, + ) + await instrumentCount.selectOption('100') + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await expect(virtualScrollSelect).toHaveValue('none') + await expect(virtualScrollSelect).toBeEnabled() + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(table.locator('thead tr')).toHaveCount(2) + await expect(table.locator('thead tr').last().locator('th')).toHaveCount(14) + await expect(table.locator('thead')).not.toContainText('Identity') + await expect(table.locator('thead')).not.toContainText('Market Data') + await expect(table.locator('thead')).toContainText('Market') + await expect(table.locator('thead')).toContainText('Bid Vol') + await expect(table.locator('thead')).toContainText('Intraday') + await expect(page.getByTestId('feed-status')).toHaveText('FEED PAUSED') + await expect(instrumentCount.locator('option[value="150"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="350"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="750"]')).toHaveCount(1) + + const targetRateSlider = page.getByTestId('target-rate-slider') + await expect(targetRateSlider).toHaveAttribute('min', '0') + await expect(targetRateSlider).toHaveAttribute('max', '9') + await expect(targetRateSlider).toHaveAttribute('step', '1') + await expect(targetRateSlider).toHaveValue('6') + await setRangeValue(targetRateSlider, '7') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '25K samples/s', + ) + await setRangeValue(targetRateSlider, '8') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '50K samples/s', + ) + await setRangeValue(targetRateSlider, '6') + + const sparklineInterval = page.getByTestId( + 'sparkline-sample-interval-select', + ) + await expect(sparklineInterval).toHaveValue('16') + await sparklineInterval.selectOption('100') + await expect(sparklineInterval).toHaveValue('100') + await sparklineInterval.selectOption('16') + + const publishInterval = page.getByTestId('publish-interval-select') + await expect(publishInterval.locator('option[value="500"]')).toHaveCount(1) + await expect(publishInterval.locator('option[value="1000"]')).toHaveCount(1) + + await instrumentCount.selectOption('750') + await expect.poll(() => table.locator('tbody tr').count()).toBeLessThan(750) + expect( + await page.evaluate( + () => performance.getEntriesByName('tanstack-row-model').length > 0, + ), + ).toBe(true) + + expect(errors).toEqual([]) + } finally { + await server.close() + } +}) diff --git a/examples/react/realtime-trading/tsconfig.json b/examples/react/realtime-trading/tsconfig.json new file mode 100644 index 0000000000..6bb83b8604 --- /dev/null +++ b/examples/react/realtime-trading/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src", "tests/e2e", "vite.config.ts"] +} diff --git a/examples/react/realtime-trading/vite.config.ts b/examples/react/realtime-trading/vite.config.ts new file mode 100644 index 0000000000..aa2c490a08 --- /dev/null +++ b/examples/react/realtime-trading/vite.config.ts @@ -0,0 +1,46 @@ +import react, { reactCompilerPreset } from '@vitejs/plugin-react' +import babel from '@rolldown/plugin-babel' +import rollupReplace from '@rollup/plugin-replace' +import { defineConfig } from 'vite' + +export default defineConfig(({ command, mode }) => { + const development = mode === 'development' + const profiling = mode === 'profile' + + return { + server: { + port: 7777, + allowedHosts: true, + }, + plugins: [ + rollupReplace({ + preventAssignment: true, + values: { + __DEV__: JSON.stringify(development), + 'process.env.NODE_ENV': JSON.stringify( + development ? 'development' : 'production', + ), + }, + }), + react(), + ...(command === 'build' + ? [ + babel({ + presets: [reactCompilerPreset()], + include: [/\/src\/.*\.[jt]sx?$/], + }), + ] + : []), + ], + resolve: { + alias: profiling + ? [ + { + find: /^react-dom\/client$/, + replacement: 'react-dom/profiling', + }, + ] + : [], + }, + } +}) diff --git a/examples/react/row-dnd/package.json b/examples/react/row-dnd/package.json index bfb8a612e9..a43543bca6 100644 --- a/examples/react/row-dnd/package.json +++ b/examples/react/row-dnd/package.json @@ -16,19 +16,20 @@ "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/row-pinning/package.json b/examples/react/row-pinning/package.json index cdc74f267c..c920efeb21 100644 --- a/examples/react/row-pinning/package.json +++ b/examples/react/row-pinning/package.json @@ -12,20 +12,21 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/row-selection/package.json b/examples/react/row-selection/package.json index d2a521dd31..66b4681efa 100644 --- a/examples/react/row-selection/package.json +++ b/examples/react/row-selection/package.json @@ -12,8 +12,8 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/react-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-store": "^0.11.1", "@tanstack/react-table": "^9.2.3", @@ -22,13 +22,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/sorting/package.json b/examples/react/sorting/package.json index 4ed23cdabc..0c936277e5 100644 --- a/examples/react/sorting/package.json +++ b/examples/react/sorting/package.json @@ -12,19 +12,20 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/spreadsheet/package.json b/examples/react/spreadsheet/package.json index a5dcac0d66..f122aa0595 100644 --- a/examples/react/spreadsheet/package.json +++ b/examples/react/spreadsheet/package.json @@ -12,22 +12,23 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-hotkeys": "^0.10.0", "@tanstack/react-store": "^0.11.1", "@tanstack/react-table": "^9.2.3", - "@tanstack/react-virtual": "^3.14.9", + "@tanstack/react-virtual": "^3.14.10", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/sub-components/package.json b/examples/react/sub-components/package.json index d90feadeca..46585eeb47 100644 --- a/examples/react/sub-components/package.json +++ b/examples/react/sub-components/package.json @@ -12,19 +12,20 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/virtualized-columns-experimental/package.json b/examples/react/virtualized-columns-experimental/package.json index 3dedd16e86..5aa55264d3 100644 --- a/examples/react/virtualized-columns-experimental/package.json +++ b/examples/react/virtualized-columns-experimental/package.json @@ -11,20 +11,21 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", - "@tanstack/react-virtual": "^3.14.9", + "@tanstack/react-virtual": "^3.14.10", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/virtualized-columns/package.json b/examples/react/virtualized-columns/package.json index 083524e8b3..d105ca954c 100644 --- a/examples/react/virtualized-columns/package.json +++ b/examples/react/virtualized-columns/package.json @@ -12,20 +12,21 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", - "@tanstack/react-virtual": "^3.14.9", + "@tanstack/react-virtual": "^3.14.10", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/virtualized-infinite-scrolling/package.json b/examples/react/virtualized-infinite-scrolling/package.json index 1267ce0346..d2d1e5da23 100644 --- a/examples/react/virtualized-infinite-scrolling/package.json +++ b/examples/react/virtualized-infinite-scrolling/package.json @@ -12,21 +12,22 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-query": "^5.101.4", "@tanstack/react-table": "^9.2.3", - "@tanstack/react-virtual": "^3.14.9", + "@tanstack/react-virtual": "^3.14.10", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/virtualized-rows-experimental/package.json b/examples/react/virtualized-rows-experimental/package.json index 61874693f2..4b10a640b8 100644 --- a/examples/react/virtualized-rows-experimental/package.json +++ b/examples/react/virtualized-rows-experimental/package.json @@ -11,20 +11,21 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", - "@tanstack/react-virtual": "^3.14.9", + "@tanstack/react-virtual": "^3.14.10", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/virtualized-rows/package.json b/examples/react/virtualized-rows/package.json index c8532f81fb..3218960c7b 100644 --- a/examples/react/virtualized-rows/package.json +++ b/examples/react/virtualized-rows/package.json @@ -12,20 +12,21 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/react-table": "^9.2.3", - "@tanstack/react-virtual": "^3.14.9", + "@tanstack/react-virtual": "^3.14.10", "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/web-worker-row-models/package.json b/examples/react/web-worker-row-models/package.json index 05b815e70e..69e8466e2d 100644 --- a/examples/react/web-worker-row-models/package.json +++ b/examples/react/web-worker-row-models/package.json @@ -12,10 +12,10 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/react-devtools": "^0.10.10", - "@tanstack/react-router": "^1.170.27", - "@tanstack/react-start": "^1.168.44", + "@faker-js/faker": "^10.6.0", + "@tanstack/react-devtools": "^0.10.12", + "@tanstack/react-router": "^1.170.32", + "@tanstack/react-start": "^1.168.49", "@tanstack/react-store": "^0.11.1", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", @@ -23,13 +23,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@types/node": "^26.2.0", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/with-tanstack-form/package.json b/examples/react/with-tanstack-form/package.json index 08508cc13e..0d51f7a93a 100644 --- a/examples/react/with-tanstack-form/package.json +++ b/examples/react/with-tanstack-form/package.json @@ -12,8 +12,8 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/react-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-form": "^1.33.5", "@tanstack/react-form-devtools": "^0.2.34", "@tanstack/react-pacer": "^0.23.0", @@ -25,13 +25,14 @@ "zod": "^4.4.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/with-tanstack-query/package.json b/examples/react/with-tanstack-query/package.json index b949be1b03..737e916fa8 100644 --- a/examples/react/with-tanstack-query/package.json +++ b/examples/react/with-tanstack-query/package.json @@ -12,8 +12,8 @@ "test:types": "tsc" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/react-devtools": "^0.10.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-query": "^5.101.4", "@tanstack/react-query-devtools": "^5.101.4", "@tanstack/react-table": "^9.2.3", @@ -22,13 +22,14 @@ "react-dom": "^19.2.8" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/react/with-tanstack-router/package.json b/examples/react/with-tanstack-router/package.json index ca81c1eacf..95091dbafe 100644 --- a/examples/react/with-tanstack-router/package.json +++ b/examples/react/with-tanstack-router/package.json @@ -12,12 +12,12 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/react-devtools": "^0.10.10", + "@tanstack/react-devtools": "^0.10.12", "@tanstack/react-pacer": "^0.23.0", "@tanstack/react-pacer-devtools": "0.8.0", "@tanstack/react-query": "^5.101.4", "@tanstack/react-query-devtools": "^5.101.4", - "@tanstack/react-router": "^1.170.27", + "@tanstack/react-router": "^1.170.32", "@tanstack/react-router-devtools": "^1.167.1", "@tanstack/react-table": "^9.2.3", "@tanstack/react-table-devtools": "^9.2.0", @@ -25,15 +25,16 @@ "react-dom": "^19.2.8" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rolldown/plugin-babel": "^0.2.3", "@rollup/plugin-replace": "^6.0.3", - "@tanstack/router-vite-plugin": "^1.167.30", + "@tanstack/router-vite-plugin": "^1.167.35", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "babel-plugin-react-compiler": "^1.0.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/solid/aggregation/package.json b/examples/solid/aggregation/package.json index cbef91cd43..40016aee17 100644 --- a/examples/solid/aggregation/package.json +++ b/examples/solid/aggregation/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/basic-app-table/package.json b/examples/solid/basic-app-table/package.json index f51495bfa1..4191a461e2 100644 --- a/examples/solid/basic-app-table/package.json +++ b/examples/solid/basic-app-table/package.json @@ -13,15 +13,16 @@ }, "license": "MIT", "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/solid-devtools": "^0.8.10", + "@faker-js/faker": "^10.6.0", + "@tanstack/solid-devtools": "^0.8.12", "@tanstack/solid-table": "^9.2.3", "@tanstack/solid-table-devtools": "^9.2.0", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/basic-dynamic-columns/package.json b/examples/solid/basic-dynamic-columns/package.json index 679fb51b07..25c37fc69b 100644 --- a/examples/solid/basic-dynamic-columns/package.json +++ b/examples/solid/basic-dynamic-columns/package.json @@ -13,14 +13,15 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-pacer": "^0.22.0", "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/basic-external-atoms/package.json b/examples/solid/basic-external-atoms/package.json index 71e439587b..64f9dc18b5 100644 --- a/examples/solid/basic-external-atoms/package.json +++ b/examples/solid/basic-external-atoms/package.json @@ -13,16 +13,17 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { - "@tanstack/solid-devtools": "^0.8.10", + "@tanstack/solid-devtools": "^0.8.12", "@tanstack/solid-store": "^0.11.1", "@tanstack/solid-table": "^9.2.3", "@tanstack/solid-table-devtools": "^9.2.0", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/basic-external-state/package.json b/examples/solid/basic-external-state/package.json index 7baa68d573..392cadccbe 100644 --- a/examples/solid/basic-external-state/package.json +++ b/examples/solid/basic-external-state/package.json @@ -13,15 +13,16 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { - "@tanstack/solid-devtools": "^0.8.10", + "@tanstack/solid-devtools": "^0.8.12", "@tanstack/solid-table": "^9.2.3", "@tanstack/solid-table-devtools": "^9.2.0", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/basic-use-table/package.json b/examples/solid/basic-use-table/package.json index 7132b91941..02287015cf 100644 --- a/examples/solid/basic-use-table/package.json +++ b/examples/solid/basic-use-table/package.json @@ -13,14 +13,15 @@ }, "license": "MIT", "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { - "@tanstack/solid-devtools": "^0.8.10", + "@tanstack/solid-devtools": "^0.8.12", "@tanstack/solid-table": "^9.2.3", "@tanstack/solid-table-devtools": "^9.2.0", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/cell-selection/package.json b/examples/solid/cell-selection/package.json index 1cdeca80d9..88209eb35d 100644 --- a/examples/solid/cell-selection/package.json +++ b/examples/solid/cell-selection/package.json @@ -13,16 +13,17 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { - "@tanstack/solid-devtools": "^0.8.10", + "@tanstack/solid-devtools": "^0.8.12", "@tanstack/solid-hotkeys": "^0.10.0", "@tanstack/solid-table": "^9.2.3", "@tanstack/solid-table-devtools": "^9.2.0", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/cell-spanning/package.json b/examples/solid/cell-spanning/package.json index 6aa6cccdbf..7d8681a1c9 100644 --- a/examples/solid/cell-spanning/package.json +++ b/examples/solid/cell-spanning/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/column-ordering/package.json b/examples/solid/column-ordering/package.json index 132bc00d20..80495b1b64 100644 --- a/examples/solid/column-ordering/package.json +++ b/examples/solid/column-ordering/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/column-pinning-split/package.json b/examples/solid/column-pinning-split/package.json index d065feee81..09b0bdd08d 100644 --- a/examples/solid/column-pinning-split/package.json +++ b/examples/solid/column-pinning-split/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/column-pinning-sticky/package.json b/examples/solid/column-pinning-sticky/package.json index ea6d5a408c..7b97595d6a 100644 --- a/examples/solid/column-pinning-sticky/package.json +++ b/examples/solid/column-pinning-sticky/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/column-pinning/package.json b/examples/solid/column-pinning/package.json index 3727a2fa41..3c673ba19a 100644 --- a/examples/solid/column-pinning/package.json +++ b/examples/solid/column-pinning/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/column-resizing-performant/package.json b/examples/solid/column-resizing-performant/package.json index 9176d6d9e5..070ae41cbc 100644 --- a/examples/solid/column-resizing-performant/package.json +++ b/examples/solid/column-resizing-performant/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/column-resizing/package.json b/examples/solid/column-resizing/package.json index 3f7e73dd39..574d951482 100644 --- a/examples/solid/column-resizing/package.json +++ b/examples/solid/column-resizing/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/column-sizing/package.json b/examples/solid/column-sizing/package.json index 0f63de9287..7b761173e7 100644 --- a/examples/solid/column-sizing/package.json +++ b/examples/solid/column-sizing/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/column-visibility/package.json b/examples/solid/column-visibility/package.json index 7fed7ed351..53bc8ded6c 100644 --- a/examples/solid/column-visibility/package.json +++ b/examples/solid/column-visibility/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/composable-tables/package.json b/examples/solid/composable-tables/package.json index 8a6977d39c..3057314091 100644 --- a/examples/solid/composable-tables/package.json +++ b/examples/solid/composable-tables/package.json @@ -13,14 +13,15 @@ }, "license": "MIT", "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { - "@tanstack/solid-devtools": "^0.8.10", + "@tanstack/solid-devtools": "^0.8.12", "@tanstack/solid-table": "^9.2.3", "@tanstack/solid-table-devtools": "^9.2.0", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/expanding/package.json b/examples/solid/expanding/package.json index 2525a4435c..22654d1be6 100644 --- a/examples/solid/expanding/package.json +++ b/examples/solid/expanding/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/filters-faceted-bucketed/package.json b/examples/solid/filters-faceted-bucketed/package.json index d72cb5120e..7f78236a35 100644 --- a/examples/solid/filters-faceted-bucketed/package.json +++ b/examples/solid/filters-faceted-bucketed/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/filters-faceted/package.json b/examples/solid/filters-faceted/package.json index a687ddb508..262d4d566a 100644 --- a/examples/solid/filters-faceted/package.json +++ b/examples/solid/filters-faceted/package.json @@ -13,14 +13,15 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-pacer": "^0.22.0", "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/filters-fuzzy/package.json b/examples/solid/filters-fuzzy/package.json index 529193303d..8e2dbcafbd 100644 --- a/examples/solid/filters-fuzzy/package.json +++ b/examples/solid/filters-fuzzy/package.json @@ -13,15 +13,16 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/solid-pacer": "^0.22.0", "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/filters/package.json b/examples/solid/filters/package.json index c362f3f4b4..389e112e4f 100644 --- a/examples/solid/filters/package.json +++ b/examples/solid/filters/package.json @@ -13,14 +13,15 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-pacer": "^0.22.0", "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/grouped-aggregation/package.json b/examples/solid/grouped-aggregation/package.json index 7f061dfd4d..639bf9562e 100644 --- a/examples/solid/grouped-aggregation/package.json +++ b/examples/solid/grouped-aggregation/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/grouping/package.json b/examples/solid/grouping/package.json index 949ffbcf65..e14a7de224 100644 --- a/examples/solid/grouping/package.json +++ b/examples/solid/grouping/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/header-groups/package.json b/examples/solid/header-groups/package.json index e85fbcfaa9..ce51d8c068 100644 --- a/examples/solid/header-groups/package.json +++ b/examples/solid/header-groups/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/kitchen-sink/package.json b/examples/solid/kitchen-sink/package.json index 7474d7d416..a811bf947b 100644 --- a/examples/solid/kitchen-sink/package.json +++ b/examples/solid/kitchen-sink/package.json @@ -13,16 +13,17 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/match-sorter-utils": "^9.1.2", - "@tanstack/solid-devtools": "^0.8.10", + "@tanstack/solid-devtools": "^0.8.12", "@tanstack/solid-table": "^9.2.3", "@tanstack/solid-table-devtools": "^9.2.0", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/pagination/package.json b/examples/solid/pagination/package.json index a24d3f5ec5..77cd20f0b5 100644 --- a/examples/solid/pagination/package.json +++ b/examples/solid/pagination/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/realtime-trading/README.md b/examples/solid/realtime-trading/README.md new file mode 100644 index 0000000000..1d899e91b5 --- /dev/null +++ b/examples/solid/realtime-trading/README.md @@ -0,0 +1,195 @@ +# Solid realtime trading benchmark + +This standalone example exercises the current TanStack Solid Table adapter +with a high-frequency worker feed, immutable snapshots, fine-grained reactive +cells, table interactions, virtual rows, and browser diagnostics. It is a +repeatable UI workload, not an exchange or network benchmark. + +## Run and verify + +```bash +pnpm --dir examples/solid/realtime-trading dev +``` + +Open `http://localhost:7777`. + +```bash +pnpm --dir examples/solid/realtime-trading test:types +pnpm --dir examples/solid/realtime-trading lint +pnpm --dir examples/solid/realtime-trading build +pnpm --dir examples/solid/realtime-trading test:e2e +``` + +Record performance against the production build; development checks distort +absolute timings. + +## Structure and ownership + +| Path | Responsibility | +| ------------------------- | -------------------------------------------------------------------------------------------------- | +| `src/feed/` | Market model, instrument universe, feed config, immutable update logic, and Solid feed controller. | +| `src/feed/worker/` | Protocol, deterministic market engine, and module worker. | +| `src/benchmark/` | Benchmark monitor and the controller that exposes benchmark signals/actions. | +| `src/shell/` | Contexts, viewport shell, header, metrics, configurator, diagnostics, and selected instrument. | +| `src/table/table-config/` | Declarative columns, named cell renderers, component props, and quote value calculations. | +| `src/table/` | Table model primitive, view components, interactions, layout, and virtualization. | +| `src/App.tsx` | Creates feed/benchmark controllers and composes their providers with the table. | + +`createMarketFeedController` and `createTradingBenchmarkController` are +separate. The feed owns worker state and quotes; the benchmark observes feed +events and owns only diagnostic/view state. Solid contexts provide controller +objects, and consumers read individual accessors rather than one global state +snapshot. + +## Feed and worker pipeline + +The initial setup is 100 instruments, 10K generated samples/s, 20 ms delivery, +enabled intraday charts, and 16 ms chart sampling. + +Mutable quotes never leave the worker. A deterministic generator and a 16 ms +budget loop create samples, while a row-indexed `Map` coalesces repeated changes. +A separate timer publishes the latest unique updates. On the main thread the +outer quote array is new, changed rows are new, and untouched rows keep their +references. History arrays change only at their own sampling cadence. Session +IDs prevent stale batches from an old configuration from being applied. + +- **Synthetic quote workload** is generated worker samples/s, not messages or + framework updates. +- **Worker delivery interval** controls coalesced messages; 20 ms targets about + 50 messages/s. +- **Row updates** is the unique immutable rows applied by a message. +- **Message samples** is the worker work represented by the latest message. + +The 25K burst immediately generates and flushes an intentionally heavy batch. +The worker is a local stand-in for an upstream stream; network latency is not +part of the test. + +## Solid table architecture + +The table has 14 leaf columns grouped into Instrument, Price & Change, Order +Book, Session, and Chart. It supports sorting/filtering, on-change resizing, +double-click reset, drag ordering, row selection, drag cell ranges, keyboard +navigation, and component-based Price/Move/Percent/Sparkline cells. + +The table reads the feed's quote accessor directly from context; `App` does not +subscribe to or forward quote snapshots. `TradingTable` is only the composition +root for `createTradingTableModel`, row virtualization, layout and commit +effects, plus `TradingTableHeader`, `TradingTableBody`, and +`TradingTableFooter`. Stable instrument IDs back `getRowId`. Full-DOM rows use +Solid's position-owned `` scopes and a dedicated `TradingTableRow` +boundary. Each position receives the current TanStack `Row`. One row-level memo +keeps its render cells while the row ID, column configuration, and cell order +are unchanged. A small Solid context exposes an `Accessor` for that +row, so named renderers and their component props update without replacing the +mounted `FlexRender`. It is a normal accessor, not a proxy or mutable registry. + +Row and cell DOM attributes are written directly in JSX. Every cell slot also +receives the current row-model cell at the same visible-column index; selection +edges, focus, selected state, and roving tabindex are computed from that current +cell. This avoids stale selection geometry without `getAllCellsByColumnId()` or +per-cell row/column ID memos. Grid-level pointer interaction remains delegated +to the table body. + +`` is intentionally not used for the immutable TanStack row model. Solid +keys `` by item identity, while TanStack creates new `Row` objects after a +new data array. Stable `getRowId` values preserve table state, but do not change +Solid's identity comparison; `` would therefore treat every new row object +as a replacement. `` keeps the DOM/component slot mounted while replacing +the current `Row` and selection `Cell` props at that position. The separate +render-cell memo changes only for a new row ID, column definition/order, or row +moving into the slot, so quote snapshots update component props without +remounting `FlexRender`. Sorting updates the affected positions as expected. + +The column configuration is memoized by renderer mode. Changing Stable to A/B +therefore refreshes the column definition once, while normal quote batches do +not rebuild columns. `trading-columns.tsx` contains only the declarative schema; +named renderers, component prop interfaces, and market calculations live in +focused colocated modules. In A/B mode the Move renderer selects the direction +component when that row changes, intentionally testing mount/unmount churn. + +`createTradingGridSelectionHandlers` creates one delegated body handler object +and resolves cells from `composedPath()` plus identity data attributes. No +pointer listener is added per cell, and hover remains CSS-only. Header drag, +grid attributes, and body attributes use focused reusable prop factories; the +hot row/cell path stays as direct JSX. Column dimensions live in CSS variables +and update only for column sizing/order; a `ResizeObserver` performs the initial +fit until the user resizes manually. + +## Virtualization + +- Below 200 rows, automatic mode chooses Full DOM, but Virtual is selectable. +- From 200 through 1,499 rows, automatic mode chooses TanStack Virtual and the + user may still choose Full DOM. +- At 1,500 rows or more, Virtual is forced and the control is disabled. + +`createVirtualizer` uses 32 px row estimates, 10-row overscan, stable row IDs, +transformed rows, and a spacer body. Its range drives the current-row footer. +Both rendering paths use `content-visibility: auto`; in Full DOM it can skip +some browser rendering but does not avoid creating every Solid row/cell. + +## Performance decisions + +- market work and coalescing happen before crossing to the main thread; +- immutable snapshots preserve unchanged row/history references; +- fine-grained signals avoid broad shell or root invalidation; +- position-owned rows/cells preserve DOM slots and render-cell identity while + an accessor updates the current immutable quote; +- delegated grid interaction avoids per-cell handlers; +- CSS variables isolate width changes from quote updates; +- dynamic component churn and sparkline frequency are explicit controls; +- virtualization limits mounted DOM for larger data; +- metrics publish at a lower cadence than feed updates. + +A new outer array is part of the immutable contract. Structural sharing helps +cell rendering, but table sorting/filtering can still rebuild a row model when +the data accessor changes. + +## Diagnostics and interpretation + +The sidebar starts with four cross-framework health signals: estimated rAF +callbacks/s over one second, average snapshot-to-DOM-commit latency over three +seconds, long animation frames accumulated since reset, and throughput as +changed rows/s plus applied snapshots/s. “Changed rows” is deduplicated within +each snapshot; the same instrument can count again in a later snapshot. The +advanced diagnostics retain worker samples/messages, DOM commits, a rolling +10-second p95/max commit latency, slow commits, lifecycle/execution rates, DOM +mutation records, and optional heap information. + +The frame figure is deliberately labeled estimated: it counts this page's rAF +callbacks, is capped by the display refresh rate, and falls when a tab is +throttled. It is a portable responsiveness signal, not compositor-presented +FPS. + +Solid applies reactive DOM writes synchronously, but the quote-tracking effect +queues one coalesced microtask before closing a pending commit measurement. This +prevents an effect scheduled early in the reactive graph from reporting a +commit before child bindings have settled. User Timing timeline entries are +sampled at one in 20 commits; the in-memory latency calculation still records +every commit. + +Renderer callbacks are not equivalent to DOM mutations. With this example's +immutable outer array, TanStack can produce new row/cell instances, but the +row-ID equality boundary keeps `FlexRender` stable across quote snapshots. +Column mode/order changes, sorting, and virtual-slot reuse replace the relevant +render cell. A/B mode additionally replaces the direction component when the +sign changes. A rising heap during +component swapping is not proof of a leak without stable post-GC retention. +The heap value is Chromium-only, represents the current GC-sensitive JS heap, +and is not a retained-size measurement. The DOM rate counts `MutationRecord` +objects, not individual browser operations; records may be coalesced. Its +observer watches text/child changes and only `class`/`style` attributes to +reduce, but not eliminate, observer overhead. Non-feed text/child changes and +interaction-driven `class`/`style` changes (including virtual scrolling) are +included, so do not interpret the rate as feed-only work. Use a production +build, identical controls, Chrome Performance, and Solid DevTools for meaningful +comparisons. + +## Standalone policy + +This directory intentionally owns copies of the feed, worker, instruments, +benchmark code, UI, and styles. That makes it independent and StackBlitz-ready; +shared code and explanatory README sections are duplicated across adapters by +design. + +The workspace resolves the pinned `@tanstack/solid-table` dependency to the +local adapter package while keeping the manifest release-like. diff --git a/examples/solid/realtime-trading/index.html b/examples/solid/realtime-trading/index.html new file mode 100644 index 0000000000..bddd49c0fd --- /dev/null +++ b/examples/solid/realtime-trading/index.html @@ -0,0 +1,17 @@ + + + + + + + + Solid Real-time Trading flexRender Lab + + +
+ + + diff --git a/examples/solid/realtime-trading/package.json b/examples/solid/realtime-trading/package.json new file mode 100644 index 0000000000..b1c7cee6d8 --- /dev/null +++ b/examples/solid/realtime-trading/package.json @@ -0,0 +1,25 @@ +{ + "name": "tanstack-solid-table-example-realtime-trading", + "private": true, + "type": "module", + "scripts": { + "start": "vite", + "dev": "vite", + "build": "vite build", + "serve": "vite preview", + "lint": "eslint ./src", + "test:types": "tsc --noEmit", + "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" + }, + "dependencies": { + "@tanstack/solid-table": "^9.2.3", + "@tanstack/solid-virtual": "^3.13.37", + "solid-js": "^1.9.15" + }, + "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", + "typescript": "6.0.3", + "vite": "^8.2.2", + "vite-plugin-solid": "^2.11.14" + } +} diff --git a/examples/solid/realtime-trading/src/App.tsx b/examples/solid/realtime-trading/src/App.tsx new file mode 100644 index 0000000000..1dfc26f920 --- /dev/null +++ b/examples/solid/realtime-trading/src/App.tsx @@ -0,0 +1,17 @@ +import { createTradingBenchmarkController } from './benchmark/trading-benchmark-controller' +import { createMarketFeedController } from './feed/market-feed-controller' +import { TradingShell } from './shell/TradingShell' +import { TradingShellProvider } from './shell/trading-shell-context' +import { TradingTable } from './table/trading-table' + +export default function App() { + const feed = createMarketFeedController() + const controller = createTradingBenchmarkController(feed) + return ( + + + + + + ) +} diff --git a/examples/solid/realtime-trading/src/benchmark/benchmark-monitor.ts b/examples/solid/realtime-trading/src/benchmark/benchmark-monitor.ts new file mode 100644 index 0000000000..02925f3da5 --- /dev/null +++ b/examples/solid/realtime-trading/src/benchmark/benchmark-monitor.ts @@ -0,0 +1,383 @@ +import { + quoteCellLifecycle, + quoteRenderDiagnostics, +} from '../table/table-config/quote-cells' + +export interface NamedInvocationRate { + name: string + callsPerSecond: number +} + +interface TimedLatencySample { + recordedAt: number + duration: number +} + +const averageLatencyWindowMs = 3_000 +const percentileLatencyWindowMs = 10_000 +const frameRateWindowMs = 1_000 + +export interface FeedMetrics { + actualTicksPerSecond: number + rowUpdatesPerSecond: number + workerMessagesPerSecond: number + stateApplicationsPerSecond: number + supersededUpdatesPerSecond: number + totalTicks: number + rafCallbacksPerSecond: number + tableCommitsPerSecond: number + lastBatchSize: number + averageCommitLatencyMs: number + p95CommitLatencyMs: number + maxCommitLatencyMs: number + slowCommits: number + longAnimationFrames: number + worstLongAnimationFrameMs: number + heapMb: number | null + componentsCreated: number + componentsDestroyed: number + workerMessages: number + lastUpdateCount: number + cellRendererCallsPerSecond: number + componentRenderCallsPerSecond: number + cellRendererRates: ReadonlyArray + componentRenderRates: ReadonlyArray + domMutationsPerSecond: number +} + +export const initialMetrics: FeedMetrics = { + actualTicksPerSecond: 0, + rowUpdatesPerSecond: 0, + workerMessagesPerSecond: 0, + stateApplicationsPerSecond: 0, + supersededUpdatesPerSecond: 0, + totalTicks: 0, + rafCallbacksPerSecond: 0, + tableCommitsPerSecond: 0, + lastBatchSize: 0, + averageCommitLatencyMs: 0, + p95CommitLatencyMs: 0, + maxCommitLatencyMs: 0, + slowCommits: 0, + longAnimationFrames: 0, + worstLongAnimationFrameMs: 0, + heapMb: null, + componentsCreated: 0, + componentsDestroyed: 0, + workerMessages: 0, + lastUpdateCount: 0, + cellRendererCallsPerSecond: 0, + componentRenderCallsPerSecond: 0, + cellRendererRates: [], + componentRenderRates: [], + domMutationsPerSecond: 0, +} + +const userTiming = { entryCount: 0, measureCalls: 0 } + +function recordCommitMeasure(start: number, end: number): void { + userTiming.measureCalls++ + if (userTiming.measureCalls % 20 !== 0) return + try { + performance.measure('market-update-to-dom-commit', { start, end }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMeasures('market-update-to-dom-commit') + } + } catch { + // User Timing Level 3 options are not implemented in every browser. + } +} + +export class BenchmarkMonitor { + readonly #runtime = { + sampleStartedAt: performance.now(), + sessionStartedAt: performance.now(), + pendingMutationStartedAt: null as number | null, + commitLatencySamples: [] as Array, + slowCommitCount: 0, + totalTicks: 0, + ticksInSample: 0, + rowUpdatesInSample: 0, + workerMessagesInSample: 0, + stateApplicationsInSample: 0, + supersededUpdatesInSample: 0, + lastBatchSize: 0, + lastUpdateCount: 0, + workerMessages: 0, + frameTrackingStartedAt: performance.now(), + frameTimestamps: [] as Array, + tableCommitsInSample: 0, + longAnimationFrameCount: 0, + worstLongAnimationFrameMs: 0, + previousCellRendererCalls: 0, + previousComponentRenderCalls: 0, + previousCellRendererCallsByName: { + ...quoteRenderDiagnostics.cellRendererCallsByName, + }, + previousComponentRenderCallsByName: { + ...quoteRenderDiagnostics.componentRenderCallsByName, + }, + domMutationsInSample: 0, + } + + markCommitPending(): void { + this.#runtime.pendingMutationStartedAt ??= performance.now() + } + + recordDomCommit(): void { + const runtime = this.#runtime + if (runtime.pendingMutationStartedAt !== null) { + const commitEndedAt = performance.now() + const duration = commitEndedAt - runtime.pendingMutationStartedAt + runtime.commitLatencySamples.push({ recordedAt: commitEndedAt, duration }) + if (duration > 16.7) runtime.slowCommitCount++ + recordCommitMeasure(runtime.pendingMutationStartedAt, commitEndedAt) + runtime.pendingMutationStartedAt = null + runtime.tableCommitsInSample++ + } + } + + recordWorkerMessage(): void { + this.#runtime.workerMessages++ + this.#runtime.workerMessagesInSample++ + } + + recordBatch( + tickCount: number, + updateCount: number, + supersededUpdateCount: number, + ): void { + const runtime = this.#runtime + runtime.lastBatchSize = tickCount + runtime.lastUpdateCount = updateCount + runtime.ticksInSample += tickCount + runtime.totalTicks += tickCount + runtime.rowUpdatesInSample += updateCount + runtime.stateApplicationsInSample++ + runtime.supersededUpdatesInSample += supersededUpdateCount + } + + recordAnimationFrame(now: number): void { + const timestamps = this.#runtime.frameTimestamps + timestamps.push(now) + pruneFrameTimestamps(timestamps, now) + } + + recordLongAnimationFrame(duration: number, startTime: number): void { + const runtime = this.#runtime + if (startTime < runtime.sessionStartedAt) return + runtime.longAnimationFrameCount++ + runtime.worstLongAnimationFrameMs = Math.max( + runtime.worstLongAnimationFrameMs, + duration, + ) + } + + recordDomMutations(count: number): void { + this.#runtime.domMutationsInSample += count + } + + resetDomMutations(): void { + this.#runtime.domMutationsInSample = 0 + } + + shouldPublish(now: number): boolean { + return now - this.#runtime.sampleStartedAt >= 500 + } + + publish(now: number): FeedMetrics { + const runtime = this.#runtime + const sampleDuration = now - runtime.sampleStartedAt + const cellRendererCalls = + quoteRenderDiagnostics.cellRendererCalls - + runtime.previousCellRendererCalls + const componentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls - + runtime.previousComponentRenderCalls + const cellRendererRates = calculateInvocationRates( + quoteRenderDiagnostics.cellRendererCallsByName, + runtime.previousCellRendererCallsByName, + sampleDuration, + ) + const componentRenderRates = calculateInvocationRates( + quoteRenderDiagnostics.componentRenderCallsByName, + runtime.previousComponentRenderCallsByName, + sampleDuration, + ) + pruneLatencySamples(runtime.commitLatencySamples, now) + pruneFrameTimestamps(runtime.frameTimestamps, now) + const averageCommitLatencySamples = runtime.commitLatencySamples + .filter((sample) => sample.recordedAt >= now - averageLatencyWindowMs) + .map((sample) => sample.duration) + const percentileCommitLatencySamples = runtime.commitLatencySamples.map( + (sample) => sample.duration, + ) + const sortedCommitLatencySamples = [...percentileCommitLatencySamples].sort( + (left, right) => left - right, + ) + const averageCommitLatencyMs = + averageCommitLatencySamples.length === 0 + ? 0 + : averageCommitLatencySamples.reduce((sum, value) => sum + value, 0) / + averageCommitLatencySamples.length + const p95Index = Math.max( + 0, + Math.ceil(sortedCommitLatencySamples.length * 0.95) - 1, + ) + const metrics: FeedMetrics = { + actualTicksPerSecond: + sampleDuration === 0 + ? 0 + : (runtime.ticksInSample / sampleDuration) * 1_000, + rowUpdatesPerSecond: + (runtime.rowUpdatesInSample / sampleDuration) * 1_000, + workerMessagesPerSecond: + (runtime.workerMessagesInSample / sampleDuration) * 1_000, + stateApplicationsPerSecond: + (runtime.stateApplicationsInSample / sampleDuration) * 1_000, + supersededUpdatesPerSecond: + (runtime.supersededUpdatesInSample / sampleDuration) * 1_000, + totalTicks: runtime.totalTicks, + rafCallbacksPerSecond: calculateFrameRate( + runtime.frameTimestamps, + runtime.frameTrackingStartedAt, + now, + ), + tableCommitsPerSecond: + sampleDuration === 0 + ? 0 + : (runtime.tableCommitsInSample / sampleDuration) * 1_000, + lastBatchSize: runtime.lastBatchSize, + averageCommitLatencyMs, + p95CommitLatencyMs: sortedCommitLatencySamples[p95Index] ?? 0, + maxCommitLatencyMs: sortedCommitLatencySamples.at(-1) ?? 0, + slowCommits: runtime.slowCommitCount, + longAnimationFrames: runtime.longAnimationFrameCount, + worstLongAnimationFrameMs: runtime.worstLongAnimationFrameMs, + heapMb: readHeapSizeMb(), + componentsCreated: quoteCellLifecycle.created, + componentsDestroyed: quoteCellLifecycle.destroyed, + workerMessages: runtime.workerMessages, + lastUpdateCount: runtime.lastUpdateCount, + cellRendererCallsPerSecond: (cellRendererCalls / sampleDuration) * 1_000, + componentRenderCallsPerSecond: + (componentRenderCalls / sampleDuration) * 1_000, + cellRendererRates, + componentRenderRates, + domMutationsPerSecond: + (runtime.domMutationsInSample / sampleDuration) * 1_000, + } + + runtime.sampleStartedAt = now + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.tableCommitsInSample = 0 + return metrics + } + + reset(): void { + const runtime = this.#runtime + runtime.sampleStartedAt = performance.now() + runtime.sessionStartedAt = runtime.sampleStartedAt + runtime.pendingMutationStartedAt = null + runtime.commitLatencySamples = [] + runtime.slowCommitCount = 0 + runtime.totalTicks = 0 + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.lastBatchSize = 0 + runtime.lastUpdateCount = 0 + runtime.workerMessages = 0 + runtime.frameTrackingStartedAt = runtime.sampleStartedAt + runtime.frameTimestamps = [] + runtime.tableCommitsInSample = 0 + runtime.longAnimationFrameCount = 0 + runtime.worstLongAnimationFrameMs = 0 + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + } +} + +export const longAnimationFramesSupported = + PerformanceObserver.supportedEntryTypes.includes('long-animation-frame') + +function readHeapSizeMb(): number | null { + const memory = ( + performance as Performance & { + memory?: { usedJSHeapSize: number } + } + ).memory + return memory ? memory.usedJSHeapSize / 1_048_576 : null +} + +function calculateInvocationRates( + current: Record, + previous: Record, + sampleDuration: number, +): ReadonlyArray { + return Object.entries(current).map(([name, calls]) => ({ + name, + callsPerSecond: + sampleDuration === 0 + ? 0 + : ((calls - (previous[name] ?? 0)) / sampleDuration) * 1_000, + })) +} + +function pruneLatencySamples( + samples: Array, + now: number, +): void { + const cutoff = now - percentileLatencyWindowMs + const firstRetainedIndex = samples.findIndex( + (sample) => sample.recordedAt >= cutoff, + ) + if (firstRetainedIndex > 0) samples.splice(0, firstRetainedIndex) + else if (firstRetainedIndex === -1) samples.length = 0 +} + +function pruneFrameTimestamps(timestamps: Array, now: number): void { + const cutoff = now - frameRateWindowMs + const firstRetainedIndex = timestamps.findIndex( + (timestamp) => timestamp >= cutoff, + ) + if (firstRetainedIndex > 0) timestamps.splice(0, firstRetainedIndex) + else if (firstRetainedIndex === -1) timestamps.length = 0 +} + +function calculateFrameRate( + timestamps: ReadonlyArray, + trackingStartedAt: number, + now: number, +): number { + const observedWindowMs = Math.min( + frameRateWindowMs, + Math.max(1, now - trackingStartedAt), + ) + return (timestamps.length / observedWindowMs) * 1_000 +} diff --git a/examples/solid/realtime-trading/src/benchmark/trading-benchmark-controller.ts b/examples/solid/realtime-trading/src/benchmark/trading-benchmark-controller.ts new file mode 100644 index 0000000000..8815f00d3b --- /dev/null +++ b/examples/solid/realtime-trading/src/benchmark/trading-benchmark-controller.ts @@ -0,0 +1,148 @@ +import { createMemo, createSignal, onCleanup, onMount } from 'solid-js' +import { TRADING_COLUMN_COUNT } from '../table/table-config/trading-columns' +import { + FORCED_VIRTUALIZATION_ROW_COUNT, + resolveVirtualScrollMode, +} from '../table/trading-row-virtualizer' +import { + BenchmarkMonitor, + initialMetrics, + longAnimationFramesSupported, +} from './benchmark-monitor' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { RendererMode } from '../table/table-config/trading-columns' +import type { VirtualScrollPreference } from '../table/trading-row-virtualizer' + +export function createTradingBenchmarkController(feed: MarketFeedController) { + const [rendererMode, setRendererMode] = createSignal('stable') + const [requestedVirtualScrollMode, setRequestedVirtualScrollMode] = + createSignal('auto') + const [renderedRowCount, setRenderedRowCount] = createSignal(0) + const [selectedSymbol, setSelectedSymbol] = createSignal(null) + const [metrics, setMetrics] = createSignal(initialMetrics) + const monitor = new BenchmarkMonitor() + const runtime = { + animationFrameId: 0, + longAnimationFrameObserver: null as PerformanceObserver | null, + mutationObserver: null as MutationObserver | null, + } + + const stopObservingFeed = feed.observe({ + messageReceived: () => monitor.recordWorkerMessage(), + mutationStarted: () => monitor.markCommitPending(), + batchApplied: ({ tickCount, updateCount, supersededUpdateCount }) => + monitor.recordBatch(tickCount, updateCount, supersededUpdateCount), + renderCommitted: () => monitor.recordDomCommit(), + }) + + const observeTableMutations = (): void => { + const tableBody = document.querySelector( + '.market-panel [data-trading-table] tbody', + ) + if (!tableBody) return + + monitor.resetDomMutations() + runtime.mutationObserver = new MutationObserver((records) => { + monitor.recordDomMutations(records.length) + }) + runtime.mutationObserver.observe(tableBody, { + attributes: true, + attributeFilter: ['class', 'style'], + characterData: true, + childList: true, + subtree: true, + }) + } + + const benchmarkFrame = (now: number): void => { + monitor.recordAnimationFrame(now) + if (monitor.shouldPublish(now)) { + setMetrics(monitor.publish(now)) + } + runtime.animationFrameId = requestAnimationFrame(benchmarkFrame) + } + + onMount(() => { + observeTableMutations() + if (longAnimationFramesSupported) { + runtime.longAnimationFrameObserver = new PerformanceObserver( + (entries) => { + for (const entry of entries.getEntries()) { + monitor.recordLongAnimationFrame(entry.duration, entry.startTime) + } + }, + ) + runtime.longAnimationFrameObserver.observe({ + type: 'long-animation-frame', + }) + } + runtime.animationFrameId = requestAnimationFrame(benchmarkFrame) + }) + + onCleanup(() => { + stopObservingFeed() + cancelAnimationFrame(runtime.animationFrameId) + runtime.longAnimationFrameObserver?.disconnect() + runtime.mutationObserver?.disconnect() + }) + + const resetViewState = (): void => { + setSelectedSymbol(null) + setRequestedVirtualScrollMode('auto') + } + + const actions = { + resetViewState, + setRendererMode, + setVirtualScrollEnabled(enabled: boolean): void { + if (feed.state.instrumentCount() >= FORCED_VIRTUALIZATION_ROW_COUNT) + return + setRequestedVirtualScrollMode(enabled ? 'tanstack' : 'none') + }, + setRenderedRowCount, + selectSymbol: setSelectedSymbol, + resetMarket(): void { + monitor.reset() + resetViewState() + setMetrics({ ...initialMetrics }) + feed.actions.reset() + }, + } + + const virtualScrollForced = createMemo( + () => feed.state.instrumentCount() >= FORCED_VIRTUALIZATION_ROW_COUNT, + ) + const virtualScrollMode = createMemo(() => + resolveVirtualScrollMode( + requestedVirtualScrollMode(), + feed.state.instrumentCount(), + ), + ) + const mountedCells = createMemo( + () => renderedRowCount() * TRADING_COLUMN_COUNT, + ) + const liveComponents = createMemo( + () => metrics().componentsCreated - metrics().componentsDestroyed, + ) + + return { + feed, + state: { + rendererMode, + requestedVirtualScrollMode, + virtualScrollForced, + virtualScrollMode, + renderedRowCount, + selectedSymbol, + metrics, + mountedCells, + liveComponents, + }, + actions, + monitor, + } +} + +export type TradingBenchmarkController = ReturnType< + typeof createTradingBenchmarkController +> diff --git a/examples/solid/realtime-trading/src/feed/feed-sample-rates.ts b/examples/solid/realtime-trading/src/feed/feed-sample-rates.ts new file mode 100644 index 0000000000..17dc2015a6 --- /dev/null +++ b/examples/solid/realtime-trading/src/feed/feed-sample-rates.ts @@ -0,0 +1,33 @@ +export const feedSampleRateOptions = [ + { label: '100', value: 100 }, + { label: '250', value: 250 }, + { label: '500', value: 500 }, + { label: '1K', value: 1_000 }, + { label: '2.5K', value: 2_500 }, + { label: '5K', value: 5_000 }, + { label: '10K', value: 10_000 }, + { label: '25K', value: 25_000 }, + { label: '50K', value: 50_000 }, + { label: '100K', value: 100_000 }, +] as const + +export function feedSampleRateIndex(rate: number): number { + return feedSampleRateOptions.reduce((closestIndex, candidate, index) => { + const closest = feedSampleRateOptions[closestIndex] + return Math.abs(candidate.value - rate) < Math.abs(closest.value - rate) + ? index + : closestIndex + }, 0) +} + +export function feedSampleRateAt(stepIndex: number): number { + const index = Math.min( + feedSampleRateOptions.length - 1, + Math.max(0, Math.round(stepIndex)), + ) + return feedSampleRateOptions[index].value +} + +export function normalizeFeedSampleRate(rate: number): number { + return feedSampleRateAt(feedSampleRateIndex(rate)) +} diff --git a/examples/solid/realtime-trading/src/feed/market-data.ts b/examples/solid/realtime-trading/src/feed/market-data.ts new file mode 100644 index 0000000000..6231865d3f --- /dev/null +++ b/examples/solid/realtime-trading/src/feed/market-data.ts @@ -0,0 +1,38 @@ +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './worker/market-feed-protocol' + +export interface MarketQuote extends Omit { + history: ReadonlyArray +} + +export function hydrateMarketQuotes( + snapshots: Array, +): Array { + return snapshots.map((quote) => ({ + ...quote, + history: [...quote.history], + })) +} + +export function applyMarketUpdates( + quotes: Array, + updates: Array, +): Array { + const nextQuotes = [...quotes] + + for (const update of updates) { + const { index, history, ...values } = update + const previousQuote = quotes.at(index) + if (!previousQuote) continue + + nextQuotes[index] = { + ...previousQuote, + ...values, + history: history ?? previousQuote.history, + } + } + + return nextQuotes +} diff --git a/examples/solid/realtime-trading/src/feed/market-feed-config.ts b/examples/solid/realtime-trading/src/feed/market-feed-config.ts new file mode 100644 index 0000000000..9d477ed663 --- /dev/null +++ b/examples/solid/realtime-trading/src/feed/market-feed-config.ts @@ -0,0 +1,15 @@ +export interface MarketFeedConfig { + readonly instrumentCount: number + readonly targetSamplesPerSecond: number + readonly publishIntervalMs: number + readonly updateSparklines: boolean + readonly sparklineSampleIntervalMs: number +} + +export const initialMarketFeedConfig: MarketFeedConfig = { + instrumentCount: 100, + targetSamplesPerSecond: 10_000, + publishIntervalMs: 20, + updateSparklines: true, + sparklineSampleIntervalMs: 16, +} diff --git a/examples/solid/realtime-trading/src/feed/market-feed-controller.ts b/examples/solid/realtime-trading/src/feed/market-feed-controller.ts new file mode 100644 index 0000000000..4c93721c8c --- /dev/null +++ b/examples/solid/realtime-trading/src/feed/market-feed-controller.ts @@ -0,0 +1,199 @@ +import { createSignal, onCleanup, onMount } from 'solid-js' +import { normalizeFeedSampleRate } from './feed-sample-rates' +import { initialMarketFeedConfig } from './market-feed-config' +import { applyMarketUpdates, hydrateMarketQuotes } from './market-data' +import type { + MarketFeedCommand, + MarketFeedEvent, +} from './worker/market-feed-protocol' +import type { MarketQuote } from './market-data' + +export interface MarketFeedBatch { + tickCount: number + updateCount: number + supersededUpdateCount: number +} + +export interface MarketFeedObserver { + messageReceived?: () => void + mutationStarted?: () => void + batchApplied?: (batch: MarketFeedBatch) => void + renderCommitted?: () => void +} + +export function createMarketFeedController() { + const [workerReady, setWorkerReady] = createSignal(false) + const [running, setRunning] = createSignal(true) + const [instrumentCount, setInstrumentCount] = createSignal( + initialMarketFeedConfig.instrumentCount, + ) + const [targetTicksPerSecond, setTargetTicksPerSecond] = createSignal( + initialMarketFeedConfig.targetSamplesPerSecond, + ) + const [publishIntervalMs, setPublishIntervalMsState] = createSignal( + initialMarketFeedConfig.publishIntervalMs, + ) + const [updateSparklines, setUpdateSparklines] = createSignal( + initialMarketFeedConfig.updateSparklines, + ) + const [sparklineSampleIntervalMs, setSparklineSampleIntervalMs] = + createSignal(initialMarketFeedConfig.sparklineSampleIntervalMs) + const [quotes, setQuotes] = createSignal>([]) + const observers = new Set() + const runtime = { + worker: null as Worker | null, + feedSessionId: 0, + renderPending: false, + quoteIndexBySymbol: new Map(), + } + + const post = (command: MarketFeedCommand): void => + runtime.worker?.postMessage(command) + + const startMutation = (): void => { + runtime.renderPending = true + for (const observer of observers) { + observer.mutationStarted?.() + } + } + + const completeRender = (): void => { + if (!runtime.renderPending) return + + runtime.renderPending = false + for (const observer of observers) { + observer.renderCommitted?.() + } + } + + const handleWorkerMessage = ({ + data, + }: MessageEvent): void => { + if (data.type === 'snapshot') { + runtime.feedSessionId = data.sessionId + startMutation() + const nextQuotes = hydrateMarketQuotes(data.quotes) + runtime.quoteIndexBySymbol = new Map( + nextQuotes.map((quote, index) => [quote.symbol, index]), + ) + setQuotes(nextQuotes) + setWorkerReady(true) + return + } + + if (data.sessionId !== runtime.feedSessionId) return + + for (const observer of observers) { + observer.messageReceived?.() + } + startMutation() + setQuotes((currentQuotes) => + applyMarketUpdates(currentQuotes, data.updates), + ) + const batch = { + tickCount: data.tickCount, + updateCount: data.updates.length, + supersededUpdateCount: data.coalescedUpdateCount, + } + for (const observer of observers) { + observer.batchApplied?.(batch) + } + } + + const handleWorkerError = (error: ErrorEvent): void => { + setWorkerReady(false) + setRunning(false) + console.error('Market feed worker failed', error) + } + + const reset = (): void => { + setWorkerReady(false) + post({ type: 'reset', rowCount: instrumentCount() }) + } + + onMount(() => { + runtime.worker = new Worker( + new URL('./worker/market-feed.worker.ts', import.meta.url), + { type: 'module' }, + ) + runtime.worker.addEventListener('message', handleWorkerMessage) + runtime.worker.addEventListener('error', handleWorkerError) + post({ + type: 'start', + rowCount: instrumentCount(), + running: running(), + ticksPerSecond: targetTicksPerSecond(), + publishIntervalMs: publishIntervalMs(), + updateSparklines: updateSparklines(), + sparklineSampleIntervalMs: sparklineSampleIntervalMs(), + }) + }) + + onCleanup(() => { + runtime.worker?.removeEventListener('message', handleWorkerMessage) + runtime.worker?.removeEventListener('error', handleWorkerError) + runtime.worker?.terminate() + runtime.worker = null + observers.clear() + }) + + const actions = { + toggle(): void { + const nextRunning = !running() + setRunning(nextRunning) + post({ type: 'set-running', running: nextRunning }) + }, + setInstrumentCount(count: number): void { + setInstrumentCount(count) + reset() + }, + setTargetRate(rate: number): void { + const sampleRate = normalizeFeedSampleRate(rate) + setTargetTicksPerSecond(sampleRate) + post({ type: 'set-rate', ticksPerSecond: sampleRate }) + }, + setPublishInterval(intervalMs: number): void { + setPublishIntervalMsState(intervalMs) + post({ type: 'set-publish-interval', intervalMs }) + }, + setSparklineUpdates(enabled: boolean): void { + setUpdateSparklines(enabled) + post({ type: 'set-sparklines', enabled }) + }, + setSparklineSampleInterval(intervalMs: number): void { + setSparklineSampleIntervalMs(intervalMs) + post({ type: 'set-sparkline-interval', intervalMs }) + }, + runBurst(): void { + post({ type: 'burst', tickCount: 25_000 }) + }, + reset, + } + + return { + state: { + workerReady, + running, + instrumentCount, + targetTicksPerSecond, + publishIntervalMs, + updateSparklines, + sparklineSampleIntervalMs, + quotes, + }, + actions, + observe(observer: MarketFeedObserver): () => void { + observers.add(observer) + return () => observers.delete(observer) + }, + getQuoteBySymbol(symbol: string | null): MarketQuote | null { + if (symbol === null) return null + + const index = runtime.quoteIndexBySymbol.get(symbol) + return index === undefined ? null : (quotes()[index] ?? null) + }, + completeRender, + } +} + +export type MarketFeedController = ReturnType diff --git a/examples/solid/realtime-trading/src/feed/market-instruments.ts b/examples/solid/realtime-trading/src/feed/market-instruments.ts new file mode 100644 index 0000000000..ac18d14ea9 --- /dev/null +++ b/examples/solid/realtime-trading/src/feed/market-instruments.ts @@ -0,0 +1,742 @@ +export type MarketCode = + | 'US' + | 'NL' + | 'DE' + | 'FR' + | 'IT' + | 'ES' + | 'CH' + | 'DK' + | 'SE' + | 'FI' + | 'GB' + | 'KR' + | 'JP' + | 'HK' + | 'CA' + | 'AU' + +export type BaseInstrument = readonly [ + symbol: string, + company: string, + market: MarketCode, +] + +/** + * Current S&P 500 constituent universe used by the realtime trading examples. + * + * Source snapshot: https://github.com/datasets/s-and-p-500-companies + * Retrieved: 2026-08-15. + * Multiple share classes are intentionally represented as separate instruments. + */ +export const marketInstruments = Object.freeze([ + ['MMM', '3M', 'US'], + ['AOS', 'A. O. Smith', 'US'], + ['ABT', 'Abbott Laboratories', 'US'], + ['ABBV', 'AbbVie', 'US'], + ['ACN', 'Accenture', 'US'], + ['ADBE', 'Adobe Inc.', 'US'], + ['AMD', 'Advanced Micro Devices', 'US'], + ['AES', 'AES Corporation', 'US'], + ['AFL', 'Aflac', 'US'], + ['A', 'Agilent Technologies', 'US'], + ['APD', 'Air Products', 'US'], + ['ABNB', 'Airbnb', 'US'], + ['AKAM', 'Akamai Technologies', 'US'], + ['ALB', 'Albemarle Corporation', 'US'], + ['ARE', 'Alexandria Real Estate Equities', 'US'], + ['ALGN', 'Align Technology', 'US'], + ['ALLE', 'Allegion', 'US'], + ['LNT', 'Alliant Energy', 'US'], + ['ALL', 'Allstate', 'US'], + ['GOOGL', 'Alphabet Inc. (Class A)', 'US'], + ['GOOG', 'Alphabet Inc. (Class C)', 'US'], + ['MO', 'Altria', 'US'], + ['AMZN', 'Amazon', 'US'], + ['AMCR', 'Amcor', 'US'], + ['AEE', 'Ameren', 'US'], + ['AEP', 'American Electric Power', 'US'], + ['AXP', 'American Express', 'US'], + ['AIG', 'American International Group', 'US'], + ['AMT', 'American Tower', 'US'], + ['AWK', 'American Water Works', 'US'], + ['AMP', 'Ameriprise Financial', 'US'], + ['AME', 'Ametek', 'US'], + ['AMGN', 'Amgen', 'US'], + ['APH', 'Amphenol', 'US'], + ['ADI', 'Analog Devices', 'US'], + ['AON', 'Aon plc', 'US'], + ['APA', 'APA Corporation', 'US'], + ['APO', 'Apollo Global Management', 'US'], + ['AAPL', 'Apple Inc.', 'US'], + ['AMAT', 'Applied Materials', 'US'], + ['APP', 'AppLovin', 'US'], + ['APTV', 'Aptiv', 'US'], + ['ACGL', 'Arch Capital Group', 'US'], + ['ADM', 'Archer Daniels Midland', 'US'], + ['ARES', 'Ares Management', 'US'], + ['ANET', 'Arista Networks', 'US'], + ['AJG', 'Arthur J. Gallagher & Co.', 'US'], + ['AIZ', 'Assurant', 'US'], + ['T', 'AT&T', 'US'], + ['ATO', 'Atmos Energy', 'US'], + ['ADSK', 'Autodesk', 'US'], + ['ADP', 'Automatic Data Processing', 'US'], + ['AZO', 'AutoZone', 'US'], + ['AVB', 'AvalonBay Communities', 'US'], + ['AVY', 'Avery Dennison', 'US'], + ['AXON', 'Axon Enterprise', 'US'], + ['BKR', 'Baker Hughes', 'US'], + ['BALL', 'Ball Corporation', 'US'], + ['BAC', 'Bank of America', 'US'], + ['BAX', 'Baxter International', 'US'], + ['BDX', 'Becton Dickinson', 'US'], + ['BRK.B', 'Berkshire Hathaway', 'US'], + ['BBY', 'Best Buy', 'US'], + ['TECH', 'Bio-Techne', 'US'], + ['BIIB', 'Biogen', 'US'], + ['BLK', 'BlackRock', 'US'], + ['BX', 'Blackstone Inc.', 'US'], + ['XYZ', 'Block, Inc.', 'US'], + ['BNY', 'BNY Mellon', 'US'], + ['BA', 'Boeing', 'US'], + ['BKNG', 'Booking Holdings', 'US'], + ['BSX', 'Boston Scientific', 'US'], + ['BMY', 'Bristol Myers Squibb', 'US'], + ['AVGO', 'Broadcom', 'US'], + ['BR', 'Broadridge Financial Solutions', 'US'], + ['BRO', 'Brown & Brown', 'US'], + ['BF.B', 'Brown–Forman', 'US'], + ['BLDR', 'Builders FirstSource', 'US'], + ['BG', 'Bunge Global', 'US'], + ['BXP', 'BXP, Inc.', 'US'], + ['CHRW', 'C.H. Robinson', 'US'], + ['CDNS', 'Cadence Design Systems', 'US'], + ['CPT', 'Camden Property Trust', 'US'], + ['COF', 'Capital One', 'US'], + ['CAH', 'Cardinal Health', 'US'], + ['CCL', 'Carnival Corporation', 'US'], + ['CARR', 'Carrier Global', 'US'], + ['CVNA', 'Carvana', 'US'], + ['CASY', "Casey's", 'US'], + ['CAT', 'Caterpillar Inc.', 'US'], + ['CBOE', 'Cboe Global Markets', 'US'], + ['CBRE', 'CBRE Group', 'US'], + ['CDW', 'CDW Corporation', 'US'], + ['COR', 'Cencora', 'US'], + ['CNC', 'Centene Corporation', 'US'], + ['CNP', 'CenterPoint Energy', 'US'], + ['CF', 'CF Industries', 'US'], + ['CRL', 'Charles River Laboratories', 'US'], + ['SCHW', 'Charles Schwab Corporation', 'US'], + ['CHTR', 'Charter Communications', 'US'], + ['CVX', 'Chevron Corporation', 'US'], + ['CMG', 'Chipotle Mexican Grill', 'US'], + ['CB', 'Chubb Limited', 'US'], + ['CHD', 'Church & Dwight', 'US'], + ['CIEN', 'Ciena', 'US'], + ['CI', 'Cigna', 'US'], + ['CINF', 'Cincinnati Financial', 'US'], + ['CTAS', 'Cintas', 'US'], + ['CSCO', 'Cisco', 'US'], + ['C', 'Citigroup', 'US'], + ['CFG', 'Citizens Financial Group', 'US'], + ['CLX', 'Clorox', 'US'], + ['CME', 'CME Group', 'US'], + ['CMS', 'CMS Energy', 'US'], + ['KO', 'Coca-Cola Company (The)', 'US'], + ['CTSH', 'Cognizant', 'US'], + ['COHR', 'Coherent Corp.', 'US'], + ['COIN', 'Coinbase', 'US'], + ['CL', 'Colgate-Palmolive', 'US'], + ['CMCSA', 'Comcast', 'US'], + ['FIX', 'Comfort Systems USA', 'US'], + ['COP', 'ConocoPhillips', 'US'], + ['ED', 'Consolidated Edison', 'US'], + ['STZ', 'Constellation Brands', 'US'], + ['CEG', 'Constellation Energy', 'US'], + ['COO', 'Cooper Companies (The)', 'US'], + ['CPRT', 'Copart', 'US'], + ['GLW', 'Corning Inc.', 'US'], + ['CPAY', 'Corpay', 'US'], + ['CTVA', 'Corteva', 'US'], + ['CSGP', 'CoStar Group', 'US'], + ['COST', 'Costco', 'US'], + ['CRH', 'CRH plc', 'US'], + ['CRWD', 'CrowdStrike', 'US'], + ['CCI', 'Crown Castle', 'US'], + ['CSX', 'CSX Corporation', 'US'], + ['CMI', 'Cummins', 'US'], + ['CVS', 'CVS Health', 'US'], + ['DHR', 'Danaher Corporation', 'US'], + ['DRI', 'Darden Restaurants', 'US'], + ['DDOG', 'Datadog', 'US'], + ['DVA', 'DaVita', 'US'], + ['DECK', 'Deckers Brands', 'US'], + ['DE', 'Deere & Company', 'US'], + ['DELL', 'Dell Technologies', 'US'], + ['DAL', 'Delta Air Lines', 'US'], + ['DVN', 'Devon Energy', 'US'], + ['DXCM', 'Dexcom', 'US'], + ['FANG', 'Diamondback Energy', 'US'], + ['DLR', 'Digital Realty', 'US'], + ['DG', 'Dollar General', 'US'], + ['DLTR', 'Dollar Tree', 'US'], + ['D', 'Dominion Energy', 'US'], + ['DPZ', "Domino's", 'US'], + ['DASH', 'DoorDash', 'US'], + ['DOV', 'Dover Corporation', 'US'], + ['DOW', 'Dow Inc.', 'US'], + ['DHI', 'D. R. Horton', 'US'], + ['DTE', 'DTE Energy', 'US'], + ['DUK', 'Duke Energy', 'US'], + ['DD', 'DuPont', 'US'], + ['ETN', 'Eaton Corporation', 'US'], + ['EBAY', 'eBay Inc.', 'US'], + ['ECHO', 'EchoStar', 'US'], + ['ECL', 'Ecolab', 'US'], + ['EIX', 'Edison International', 'US'], + ['EW', 'Edwards Lifesciences', 'US'], + ['ELV', 'Elevance Health', 'US'], + ['EME', 'Emcor', 'US'], + ['EMR', 'Emerson Electric', 'US'], + ['ETR', 'Entergy', 'US'], + ['EOG', 'EOG Resources', 'US'], + ['EQT', 'EQT Corporation', 'US'], + ['EFX', 'Equifax', 'US'], + ['EQIX', 'Equinix', 'US'], + ['EQR', 'Equity Residential', 'US'], + ['ERIE', 'Erie Indemnity', 'US'], + ['ESS', 'Essex Property Trust', 'US'], + ['EL', 'Estée Lauder Companies (The)', 'US'], + ['EG', 'Everest Group', 'US'], + ['EVRG', 'Evergy', 'US'], + ['ES', 'Eversource Energy', 'US'], + ['EXC', 'Exelon', 'US'], + ['EXE', 'Expand Energy', 'US'], + ['EXPE', 'Expedia Group', 'US'], + ['EXPD', 'Expeditors International', 'US'], + ['EXR', 'Extra Space Storage', 'US'], + ['XOM', 'ExxonMobil', 'US'], + ['FFIV', 'F5, Inc.', 'US'], + ['FDS', 'FactSet', 'US'], + ['FICO', 'Fair Isaac', 'US'], + ['FAST', 'Fastenal', 'US'], + ['FRT', 'Federal Realty Investment Trust', 'US'], + ['FDX', 'FedEx', 'US'], + ['FDXF', 'FedEx Freight', 'US'], + ['FERG', 'Ferguson Enterprises', 'US'], + ['FIS', 'Fidelity National Information Services', 'US'], + ['FITB', 'Fifth Third Bancorp', 'US'], + ['FSLR', 'First Solar', 'US'], + ['FE', 'FirstEnergy', 'US'], + ['FISV', 'Fiserv', 'US'], + ['FLEX', 'Flex Ltd.', 'US'], + ['F', 'Ford Motor Company', 'US'], + ['FTNT', 'Fortinet', 'US'], + ['FTV', 'Fortive', 'US'], + ['FOXA', 'Fox Corporation (Class A)', 'US'], + ['FOX', 'Fox Corporation (Class B)', 'US'], + ['BEN', 'Franklin Resources', 'US'], + ['FCX', 'Freeport-McMoRan', 'US'], + ['GRMN', 'Garmin', 'US'], + ['IT', 'Gartner', 'US'], + ['GE', 'GE Aerospace', 'US'], + ['GEHC', 'GE HealthCare', 'US'], + ['GEV', 'GE Vernova', 'US'], + ['GEN', 'Gen Digital', 'US'], + ['GNRC', 'Generac', 'US'], + ['GD', 'General Dynamics', 'US'], + ['GIS', 'General Mills', 'US'], + ['GM', 'General Motors', 'US'], + ['GPC', 'Genuine Parts Company', 'US'], + ['GILD', 'Gilead Sciences', 'US'], + ['GPN', 'Global Payments', 'US'], + ['GL', 'Globe Life', 'US'], + ['GDDY', 'GoDaddy', 'US'], + ['GS', 'Goldman Sachs', 'US'], + ['HAL', 'Halliburton', 'US'], + ['HIG', 'Hartford (The)', 'US'], + ['HAS', 'Hasbro', 'US'], + ['HCA', 'HCA Healthcare', 'US'], + ['DOC', 'Healthpeak Properties', 'US'], + ['HSIC', 'Henry Schein', 'US'], + ['HSY', 'Hershey Company (The)', 'US'], + ['HPE', 'Hewlett Packard Enterprise', 'US'], + ['HLT', 'Hilton Worldwide', 'US'], + ['HD', 'Home Depot (The)', 'US'], + ['HONA', 'Honeywell Aerospace', 'US'], + ['HON', 'Honeywell Technologies', 'US'], + ['HRL', 'Hormel Foods', 'US'], + ['HST', 'Host Hotels & Resorts', 'US'], + ['HWM', 'Howmet Aerospace', 'US'], + ['HPQ', 'HP Inc.', 'US'], + ['HUBB', 'Hubbell Incorporated', 'US'], + ['HUM', 'Humana', 'US'], + ['HBAN', 'Huntington Bancshares', 'US'], + ['HII', 'Huntington Ingalls Industries', 'US'], + ['IBM', 'IBM', 'US'], + ['IEX', 'IDEX Corporation', 'US'], + ['IDXX', 'Idexx Laboratories', 'US'], + ['ITW', 'Illinois Tool Works', 'US'], + ['INCY', 'Incyte', 'US'], + ['IR', 'Ingersoll Rand', 'US'], + ['PODD', 'Insulet Corporation', 'US'], + ['INTC', 'Intel', 'US'], + ['IBKR', 'Interactive Brokers', 'US'], + ['ICE', 'Intercontinental Exchange', 'US'], + ['IFF', 'International Flavors & Fragrances', 'US'], + ['IP', 'International Paper', 'US'], + ['INTU', 'Intuit', 'US'], + ['ISRG', 'Intuitive Surgical', 'US'], + ['IVZ', 'Invesco', 'US'], + ['INVH', 'Invitation Homes', 'US'], + ['IQV', 'IQVIA', 'US'], + ['IRM', 'Iron Mountain', 'US'], + ['JBHT', 'J.B. Hunt', 'US'], + ['JBL', 'Jabil', 'US'], + ['JKHY', 'Jack Henry & Associates', 'US'], + ['J', 'Jacobs Solutions', 'US'], + ['JNJ', 'Johnson & Johnson', 'US'], + ['JCI', 'Johnson Controls', 'US'], + ['JPM', 'JPMorgan Chase', 'US'], + ['KVUE', 'Kenvue', 'US'], + ['KDP', 'Keurig Dr Pepper', 'US'], + ['KEY', 'KeyCorp', 'US'], + ['KEYS', 'Keysight Technologies', 'US'], + ['KMB', 'Kimberly-Clark', 'US'], + ['KIM', 'Kimco Realty', 'US'], + ['KMI', 'Kinder Morgan', 'US'], + ['KKR', 'KKR & Co.', 'US'], + ['KLAC', 'KLA Corporation', 'US'], + ['KHC', 'Kraft Heinz', 'US'], + ['KR', 'Kroger', 'US'], + ['LHX', 'L3Harris', 'US'], + ['LH', 'Labcorp', 'US'], + ['LRCX', 'Lam Research', 'US'], + ['LVS', 'Las Vegas Sands', 'US'], + ['LDOS', 'Leidos', 'US'], + ['LEN', 'Lennar', 'US'], + ['LII', 'Lennox International', 'US'], + ['LLY', 'Lilly (Eli)', 'US'], + ['LIN', 'Linde plc', 'US'], + ['LYV', 'Live Nation Entertainment', 'US'], + ['LMT', 'Lockheed Martin', 'US'], + ['L', 'Loews Corporation', 'US'], + ['LOW', "Lowe's", 'US'], + ['LULU', 'Lululemon Athletica', 'US'], + ['LITE', 'Lumentum', 'US'], + ['LYB', 'LyondellBasell', 'US'], + ['MTB', 'M&T Bank', 'US'], + ['MPC', 'Marathon Petroleum', 'US'], + ['MAR', 'Marriott International', 'US'], + ['MRSH', 'Marsh McLennan', 'US'], + ['MLM', 'Martin Marietta Materials', 'US'], + ['MRVL', 'Marvell Technology', 'US'], + ['MAS', 'Masco', 'US'], + ['MA', 'Mastercard', 'US'], + ['MKC', 'McCormick & Company', 'US'], + ['MCD', "McDonald's", 'US'], + ['MCK', 'McKesson Corporation', 'US'], + ['MDT', 'Medtronic', 'US'], + ['MRK', 'Merck & Co.', 'US'], + ['META', 'Meta Platforms', 'US'], + ['MET', 'MetLife', 'US'], + ['MTD', 'Mettler Toledo', 'US'], + ['MGM', 'MGM Resorts', 'US'], + ['MCHP', 'Microchip Technology', 'US'], + ['MU', 'Micron Technology', 'US'], + ['MSFT', 'Microsoft', 'US'], + ['MAA', 'Mid-America Apartment Communities', 'US'], + ['MRNA', 'Moderna', 'US'], + ['TAP', 'Molson Coors Beverage Company', 'US'], + ['MDLZ', 'Mondelez International', 'US'], + ['MPWR', 'Monolithic Power Systems', 'US'], + ['MNST', 'Monster Beverage', 'US'], + ['MCO', "Moody's Corporation", 'US'], + ['MS', 'Morgan Stanley', 'US'], + ['MOS', 'Mosaic Company (The)', 'US'], + ['MSI', 'Motorola Solutions', 'US'], + ['MSCI', 'MSCI', 'US'], + ['NDAQ', 'Nasdaq, Inc.', 'US'], + ['NTAP', 'NetApp', 'US'], + ['NFLX', 'Netflix', 'US'], + ['NEM', 'Newmont', 'US'], + ['NWSA', 'News Corp (Class A)', 'US'], + ['NWS', 'News Corp (Class B)', 'US'], + ['NEE', 'NextEra Energy', 'US'], + ['NKE', 'Nike, Inc.', 'US'], + ['NI', 'NiSource', 'US'], + ['NDSN', 'Nordson Corporation', 'US'], + ['NSC', 'Norfolk Southern', 'US'], + ['NTRS', 'Northern Trust', 'US'], + ['NOC', 'Northrop Grumman', 'US'], + ['NCLH', 'Norwegian Cruise Line Holdings', 'US'], + ['NRG', 'NRG Energy', 'US'], + ['NUE', 'Nucor', 'US'], + ['NVDA', 'Nvidia', 'US'], + ['NVR', 'NVR, Inc.', 'US'], + ['NXPI', 'NXP Semiconductors', 'US'], + ['ORLY', "O'Reilly Automotive", 'US'], + ['OXY', 'Occidental Petroleum', 'US'], + ['ODFL', 'Old Dominion', 'US'], + ['OMC', 'Omnicom Group', 'US'], + ['ON', 'ON Semiconductor', 'US'], + ['OKE', 'Oneok', 'US'], + ['ORCL', 'Oracle Corporation', 'US'], + ['OTIS', 'Otis Worldwide', 'US'], + ['PCAR', 'Paccar', 'US'], + ['PKG', 'Packaging Corporation of America', 'US'], + ['PLTR', 'Palantir Technologies', 'US'], + ['PANW', 'Palo Alto Networks', 'US'], + ['PSKY', 'Paramount Skydance Corporation', 'US'], + ['PH', 'Parker Hannifin', 'US'], + ['PAYX', 'Paychex', 'US'], + ['PYPL', 'PayPal', 'US'], + ['PNR', 'Pentair', 'US'], + ['PEP', 'PepsiCo', 'US'], + ['PFE', 'Pfizer', 'US'], + ['PCG', 'PG&E Corporation', 'US'], + ['PM', 'Philip Morris International', 'US'], + ['PSX', 'Phillips 66', 'US'], + ['PNW', 'Pinnacle West Capital', 'US'], + ['PNC', 'PNC Financial Services', 'US'], + ['PPG', 'PPG Industries', 'US'], + ['PPL', 'PPL Corporation', 'US'], + ['PFG', 'Principal Financial Group', 'US'], + ['PG', 'Procter & Gamble', 'US'], + ['PGR', 'Progressive Corporation', 'US'], + ['PLD', 'Prologis', 'US'], + ['PRU', 'Prudential Financial', 'US'], + ['PEG', 'Public Service Enterprise Group', 'US'], + ['PTC', 'PTC Inc.', 'US'], + ['PSA', 'Public Storage', 'US'], + ['PHM', 'PulteGroup', 'US'], + ['PWR', 'Quanta Services', 'US'], + ['QCOM', 'Qualcomm', 'US'], + ['DGX', 'Quest Diagnostics', 'US'], + ['Q', 'Qnity Electronics', 'US'], + ['RL', 'Ralph Lauren Corporation', 'US'], + ['RJF', 'Raymond James Financial', 'US'], + ['RTX', 'RTX Corporation', 'US'], + ['O', 'Realty Income', 'US'], + ['REG', 'Regency Centers', 'US'], + ['REGN', 'Regeneron Pharmaceuticals', 'US'], + ['RF', 'Regions Financial Corporation', 'US'], + ['RSG', 'Republic Services', 'US'], + ['RMD', 'ResMed|', 'US'], + ['RVTY', 'Revvity', 'US'], + ['HOOD', 'Robinhood Markets', 'US'], + ['ROK', 'Rockwell Automation', 'US'], + ['ROL', 'Rollins, Inc.', 'US'], + ['ROP', 'Roper Technologies', 'US'], + ['ROST', 'Ross Stores', 'US'], + ['RCL', 'Royal Caribbean Group', 'US'], + ['SPGI', 'S&P Global', 'US'], + ['CRM', 'Salesforce', 'US'], + ['SNDK', 'Sandisk', 'US'], + ['SBAC', 'SBA Communications', 'US'], + ['SLB', 'Schlumberger', 'US'], + ['STX', 'Seagate Technology', 'US'], + ['SRE', 'Sempra', 'US'], + ['NOW', 'ServiceNow', 'US'], + ['SHW', 'Sherwin-Williams', 'US'], + ['SPG', 'Simon Property Group', 'US'], + ['SWKS', 'Skyworks Solutions', 'US'], + ['SJM', 'J.M. Smucker Company (The)', 'US'], + ['SW', 'Smurfit Westrock', 'US'], + ['SNA', 'Snap-on', 'US'], + ['SOLV', 'Solventum', 'US'], + ['SO', 'Southern Company', 'US'], + ['LUV', 'Southwest Airlines', 'US'], + ['SWK', 'Stanley Black & Decker', 'US'], + ['SBUX', 'Starbucks', 'US'], + ['STT', 'State Street Corporation', 'US'], + ['STLD', 'Steel Dynamics', 'US'], + ['STE', 'Steris', 'US'], + ['SYK', 'Stryker Corporation', 'US'], + ['SMCI', 'Supermicro', 'US'], + ['SYF', 'Synchrony Financial', 'US'], + ['SNPS', 'Synopsys', 'US'], + ['SYY', 'Sysco', 'US'], + ['TMUS', 'T-Mobile US', 'US'], + ['TROW', 'T. Rowe Price', 'US'], + ['TTWO', 'Take-Two Interactive', 'US'], + ['TPR', 'Tapestry, Inc.', 'US'], + ['TRGP', 'Targa Resources', 'US'], + ['TGT', 'Target Corporation', 'US'], + ['TEL', 'TE Connectivity', 'US'], + ['TDY', 'Teledyne Technologies', 'US'], + ['TER', 'Teradyne', 'US'], + ['TSLA', 'Tesla, Inc.', 'US'], + ['TXN', 'Texas Instruments', 'US'], + ['TPL', 'Texas Pacific Land Corporation', 'US'], + ['TXT', 'Textron', 'US'], + ['TMO', 'Thermo Fisher Scientific', 'US'], + ['TJX', 'TJX Companies', 'US'], + ['TKO', 'TKO Group Holdings', 'US'], + ['TTD', 'Trade Desk (The)', 'US'], + ['TSCO', 'Tractor Supply', 'US'], + ['TT', 'Trane Technologies', 'US'], + ['TDG', 'TransDigm Group', 'US'], + ['TRV', 'Travelers Companies (The)', 'US'], + ['TRMB', 'Trimble Inc.', 'US'], + ['TFC', 'Truist Financial', 'US'], + ['TYL', 'Tyler Technologies', 'US'], + ['TSN', 'Tyson Foods', 'US'], + ['USB', 'U.S. Bancorp', 'US'], + ['UBER', 'Uber', 'US'], + ['UDR', 'UDR, Inc.', 'US'], + ['ULTA', 'Ulta Beauty', 'US'], + ['UNP', 'Union Pacific Corporation', 'US'], + ['UAL', 'United Airlines Holdings', 'US'], + ['UPS', 'United Parcel Service', 'US'], + ['URI', 'United Rentals', 'US'], + ['UNH', 'UnitedHealth Group', 'US'], + ['UHS', 'Universal Health Services', 'US'], + ['VLO', 'Valero Energy', 'US'], + ['VEEV', 'Veeva Systems', 'US'], + ['VTR', 'Ventas', 'US'], + ['VLTO', 'Veralto', 'US'], + ['VRSN', 'Verisign', 'US'], + ['VRSK', 'Verisk Analytics', 'US'], + ['VZ', 'Verizon', 'US'], + ['VRTX', 'Vertex Pharmaceuticals', 'US'], + ['VRT', 'Vertiv', 'US'], + ['VTRS', 'Viatris', 'US'], + ['VICI', 'Vici Properties', 'US'], + ['V', 'Visa Inc.', 'US'], + ['VST', 'Vistra Corp.', 'US'], + ['VMC', 'Vulcan Materials Company', 'US'], + ['WRB', 'W. R. Berkley Corporation', 'US'], + ['GWW', 'W. W. Grainger', 'US'], + ['WAB', 'Wabtec', 'US'], + ['WMT', 'Walmart', 'US'], + ['DIS', 'Walt Disney Company (The)', 'US'], + ['WBD', 'Warner Bros. Discovery', 'US'], + ['WM', 'Waste Management', 'US'], + ['WAT', 'Waters Corporation', 'US'], + ['WEC', 'WEC Energy Group', 'US'], + ['WFC', 'Wells Fargo', 'US'], + ['WELL', 'Welltower', 'US'], + ['WST', 'West Pharmaceutical Services', 'US'], + ['WDC', 'Western Digital', 'US'], + ['WY', 'Weyerhaeuser', 'US'], + ['WSM', 'Williams-Sonoma, Inc.', 'US'], + ['WMB', 'Williams Companies', 'US'], + ['WTW', 'Willis Towers Watson', 'US'], + ['WDAY', 'Workday, Inc.', 'US'], + ['WYNN', 'Wynn Resorts', 'US'], + ['XEL', 'Xcel Energy', 'US'], + ['XYL', 'Xylem Inc.', 'US'], + ['YUM', 'Yum! Brands', 'US'], + ['ZBRA', 'Zebra Technologies', 'US'], + ['ZBH', 'Zimmer Biomet', 'US'], + ['ZTS', 'Zoetis', 'US'], +]) + +/** + * Representative liquid international listings used to diversify the fixture. + * Symbols use their local-market form and the third tuple value is an ISO-style + * country/market code, rather than a trading currency or exchange MIC. + * + * References checked 2026-08-15: STOXX Europe 50, KRX KOSPI market, + * JPX TOPIX Core30, and HKEX index constituent materials. + */ +const europeanInstruments = Object.freeze([ + ['ASML', 'ASML Holding', 'NL'], + ['INGA', 'ING Group', 'NL'], + ['ADYEN', 'Adyen', 'NL'], + ['PHIA', 'Philips', 'NL'], + ['HEIA', 'Heineken', 'NL'], + ['SAP', 'SAP', 'DE'], + ['SIE', 'Siemens', 'DE'], + ['ALV', 'Allianz', 'DE'], + ['DTE', 'Deutsche Telekom', 'DE'], + ['MBG', 'Mercedes-Benz Group', 'DE'], + ['BMW', 'BMW', 'DE'], + ['BAS', 'BASF', 'DE'], + ['MUV2', 'Munich Re', 'DE'], + ['VOW3', 'Volkswagen Preference', 'DE'], + ['IFX', 'Infineon Technologies', 'DE'], + ['MC', 'LVMH', 'FR'], + ['OR', "L'Oréal", 'FR'], + ['AIR', 'Airbus', 'FR'], + ['SU', 'Schneider Electric', 'FR'], + ['TTE', 'TotalEnergies', 'FR'], + ['SAN', 'Sanofi', 'FR'], + ['BNP', 'BNP Paribas', 'FR'], + ['CS', 'AXA', 'FR'], + ['DG', 'Vinci', 'FR'], + ['ENEL', 'Enel', 'IT'], + ['ENI', 'Eni', 'IT'], + ['ISP', 'Intesa Sanpaolo', 'IT'], + ['UCG', 'UniCredit', 'IT'], + ['STLAM', 'Stellantis', 'IT'], + ['SAN', 'Banco Santander', 'ES'], + ['IBE', 'Iberdrola', 'ES'], + ['ITX', 'Inditex', 'ES'], + ['BBVA', 'BBVA', 'ES'], + ['NESN', 'Nestlé', 'CH'], + ['ROG', 'Roche Holding', 'CH'], + ['NOVN', 'Novartis', 'CH'], + ['UBSG', 'UBS Group', 'CH'], + ['NOVO-B', 'Novo Nordisk', 'DK'], + ['MAERSK-B', 'A.P. Moller - Maersk', 'DK'], + ['VOLV-B', 'Volvo', 'SE'], + ['ERIC-B', 'Ericsson', 'SE'], + ['NOKIA', 'Nokia', 'FI'], + ['SHEL', 'Shell', 'GB'], + ['AZN', 'AstraZeneca', 'GB'], + ['HSBA', 'HSBC Holdings', 'GB'], + ['ULVR', 'Unilever', 'GB'], + ['LSEG', 'London Stock Exchange Group', 'GB'], +]) + +const europeanMarketCodes = Object.freeze([ + 'NL', + 'DE', + 'FR', + 'IT', + 'ES', + 'CH', + 'DK', + 'SE', + 'FI', + 'GB', +]) + +const europeanMarketGroups = Object.freeze( + europeanMarketCodes.map((market) => + europeanInstruments.filter(([, , instrumentMarket]) => + Object.is(instrumentMarket, market), + ), + ), +) + +const interleavedEuropeanInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...europeanMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + europeanMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const southKoreanInstruments = Object.freeze([ + ['005930', 'Samsung Electronics', 'KR'], + ['000660', 'SK hynix', 'KR'], + ['373220', 'LG Energy Solution', 'KR'], + ['207940', 'Samsung Biologics', 'KR'], + ['005380', 'Hyundai Motor', 'KR'], + ['000270', 'Kia', 'KR'], + ['068270', 'Celltrion', 'KR'], + ['105560', 'KB Financial Group', 'KR'], + ['055550', 'Shinhan Financial Group', 'KR'], + ['035420', 'NAVER', 'KR'], + ['035720', 'Kakao', 'KR'], + ['006400', 'Samsung SDI', 'KR'], + ['051910', 'LG Chem', 'KR'], + ['012330', 'Hyundai Mobis', 'KR'], + ['066570', 'LG Electronics', 'KR'], +]) + +const japaneseInstruments = Object.freeze([ + ['8306', 'Mitsubishi UFJ Financial Group', 'JP'], + ['7203', 'Toyota Motor', 'JP'], + ['6501', 'Hitachi', 'JP'], + ['8316', 'Sumitomo Mitsui Financial Group', 'JP'], + ['6758', 'Sony Group', 'JP'], + ['8058', 'Mitsubishi Corporation', 'JP'], + ['9984', 'SoftBank Group', 'JP'], + ['8035', 'Tokyo Electron', 'JP'], + ['8411', 'Mizuho Financial Group', 'JP'], + ['8031', 'Mitsui & Co.', 'JP'], + ['6861', 'Keyence', 'JP'], + ['7974', 'Nintendo', 'JP'], + ['6098', 'Recruit Holdings', 'JP'], + ['9432', 'Nippon Telegraph and Telephone', 'JP'], + ['4063', 'Shin-Etsu Chemical', 'JP'], +]) + +const hongKongInstruments = Object.freeze([ + ['0700', 'Tencent Holdings', 'HK'], + ['9988', 'Alibaba Group', 'HK'], + ['1810', 'Xiaomi', 'HK'], + ['3690', 'Meituan', 'HK'], + ['0941', 'China Mobile', 'HK'], + ['1211', 'BYD Company', 'HK'], + ['1299', 'AIA Group', 'HK'], + ['0388', 'Hong Kong Exchanges and Clearing', 'HK'], + ['0005', 'HSBC Holdings', 'HK'], + ['2318', 'Ping An Insurance', 'HK'], +]) + +const canadianInstruments = Object.freeze([ + ['RY', 'Royal Bank of Canada', 'CA'], + ['TD', 'Toronto-Dominion Bank', 'CA'], + ['SHOP', 'Shopify', 'CA'], + ['ENB', 'Enbridge', 'CA'], + ['CNR', 'Canadian National Railway', 'CA'], + ['CP', 'Canadian Pacific Kansas City', 'CA'], + ['BMO', 'Bank of Montreal', 'CA'], + ['CSU', 'Constellation Software', 'CA'], +]) + +const australianInstruments = Object.freeze([ + ['BHP', 'BHP Group', 'AU'], + ['CBA', 'Commonwealth Bank of Australia', 'AU'], + ['CSL', 'CSL', 'AU'], + ['NAB', 'National Australia Bank', 'AU'], + ['WBC', 'Westpac Banking Corporation', 'AU'], + ['ANZ', 'ANZ Group Holdings', 'AU'], + ['WES', 'Wesfarmers', 'AU'], + ['MQG', 'Macquarie Group', 'AU'], +]) + +const internationalMarketGroups = Object.freeze([ + interleavedEuropeanInstruments, + southKoreanInstruments, + japaneseInstruments, + hongKongInstruments, + canadianInstruments, + australianInstruments, +]) + +export const internationalInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...internationalMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + internationalMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const INTERNATIONAL_INSERTION_INTERVAL = 3 + +/** + * U.S. and international instruments are interleaved so ordinary benchmark + * sizes exercise multiple symbol formats and market labels. + */ +export const globalInstruments = Object.freeze( + marketInstruments.flatMap((instrument, index) => { + const internationalInstrument = + index % INTERNATIONAL_INSERTION_INTERVAL === 0 + ? internationalInstruments[index / INTERNATIONAL_INSERTION_INTERVAL] + : undefined + + return internationalInstrument + ? [instrument, internationalInstrument] + : [instrument] + }), +) as unknown as ReadonlyArray diff --git a/examples/solid/realtime-trading/src/feed/worker/market-feed-engine.ts b/examples/solid/realtime-trading/src/feed/worker/market-feed-engine.ts new file mode 100644 index 0000000000..fbd9c369c0 --- /dev/null +++ b/examples/solid/realtime-trading/src/feed/worker/market-feed-engine.ts @@ -0,0 +1,177 @@ +import { globalInstruments } from '../market-instruments.ts' +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const INITIAL_MARKET_SEED = 0x4d41524b +const LIVE_FEED_SEED = 0x5449434b + +export class MarketFeedEngine { + #quotes: Array = [] + #lastHistorySampledAt = new Uint32Array(0) + #random = createRandom(2_026) + #rowCursor = 0 + #tickIndex = 0 + + reset(count: number): Array { + const random = createRandom(INITIAL_MARKET_SEED ^ count) + const createdAt = Date.now() + + this.#quotes = Array.from({ length: count }, (_, index) => { + const [baseSymbol, company, market] = + globalInstruments[index % globalInstruments.length] + const series = Math.floor(index / globalInstruments.length) + const symbol = series === 0 ? baseSymbol : `${baseSymbol}${series}` + const previousClose = roundPrice(20 + random() * 480) + const open = roundPrice(previousClose * (1 + (random() - 0.5) * 0.016)) + const spread = Math.max(0.01, open * (0.0002 + random() * 0.0004)) + const history = Array.from({ length: 24 }, (_, historyIndex) => + roundPrice( + open * + (1 + Math.sin(historyIndex / 4) * 0.002 + (random() - 0.5) * 0.001), + ), + ) + const volume = Math.floor(50_000 + random() * 2_000_000) + const lastSize = Math.floor(10 + random() * 5_000) + + return { + id: `instrument-${index}`, + symbol, + company, + venue: market, + previousClose, + open, + high: open, + low: open, + price: open, + bid: roundPrice(open - spread / 2), + ask: roundPrice(open + spread / 2), + bidSize: Math.floor(100 + random() * 25_000), + askSize: Math.floor(100 + random() * 25_000), + lastSize, + lastMove: 0, + lastUpdatedAt: createdAt, + volume, + turnover: roundMoney(open * volume), + history, + } + }) + + this.#random = createRandom(LIVE_FEED_SEED ^ count) + this.#rowCursor = 0 + this.#lastHistorySampledAt = new Uint32Array(count) + this.#lastHistorySampledAt.fill(createdAt >>> 0) + + return this.#quotes.map((quote) => ({ + ...quote, + history: [...quote.history], + })) + } + + applyTicks( + tickCount: number, + updateSparklines: boolean, + sparklineSampleIntervalMs: number, + ): Array { + if (this.#quotes.length === 0 || tickCount <= 0) return [] + + const updatedAt = Date.now() + const sampledAt = updatedAt >>> 0 + const sampleIntervalMs = Math.max(16, sparklineSampleIntervalMs) + const updatedQuotes = new Map() + const stride = 97 + + this.#tickIndex = 0 + while (this.#tickIndex < tickCount) { + this.#rowCursor = (this.#rowCursor + stride) % this.#quotes.length + const quote = this.#quotes[this.#rowCursor] + const lastSampledAt = this.#lastHistorySampledAt[this.#rowCursor] + const shouldUpdateHistory = + updateSparklines && + (sampledAt - lastSampledAt) >>> 0 >= sampleIntervalMs + + if (shouldUpdateHistory) { + this.#lastHistorySampledAt[this.#rowCursor] = sampledAt + } + + this.#applyTick(quote, shouldUpdateHistory, updatedAt) + + const previousUpdate = updatedQuotes.get(this.#rowCursor) + updatedQuotes.set(this.#rowCursor, { + index: this.#rowCursor, + price: quote.price, + bid: quote.bid, + ask: quote.ask, + bidSize: quote.bidSize, + askSize: quote.askSize, + lastSize: quote.lastSize, + lastMove: quote.lastMove, + lastUpdatedAt: quote.lastUpdatedAt, + high: quote.high, + low: quote.low, + volume: quote.volume, + turnover: quote.turnover, + ...(shouldUpdateHistory || previousUpdate?.history + ? { history: [...quote.history] } + : {}), + }) + this.#tickIndex++ + } + + return [...updatedQuotes.values()] + } + + #applyTick( + quote: MarketQuoteSnapshot, + updateHistory: boolean, + updatedAt: number, + ): void { + const previousPrice = quote.price + const volatility = 0.00015 + this.#random() * 0.0012 + const move = previousPrice * (this.#random() - 0.495) * volatility + const nextPrice = roundPrice(Math.max(0.1, previousPrice + move)) + const spread = Math.max( + 0.01, + nextPrice * (0.00015 + this.#random() * 0.0005), + ) + + quote.lastMove = nextPrice - previousPrice + quote.price = nextPrice + quote.high = Math.max(quote.high, nextPrice) + quote.low = Math.min(quote.low, nextPrice) + quote.bid = roundPrice(nextPrice - spread / 2) + quote.ask = roundPrice(nextPrice + spread / 2) + quote.bidSize = Math.floor(100 + this.#random() * 25_000) + quote.askSize = Math.floor(100 + this.#random() * 25_000) + quote.lastSize = Math.floor(10 + this.#random() * 5_000) + quote.lastUpdatedAt = updatedAt + quote.volume += quote.lastSize + quote.turnover = roundMoney(quote.turnover + nextPrice * quote.lastSize) + + if (updateHistory) { + quote.history = [...quote.history.slice(-23), nextPrice] + } + } +} + +function createRandom(seed: number): () => number { + const runtime = { state: seed >>> 0 } + return () => { + runtime.state += 0x6d2b79f5 + const stateValue = runtime.state + const firstMix = Math.imul(stateValue ^ (stateValue >>> 15), stateValue | 1) + const secondMix = + firstMix + Math.imul(firstMix ^ (firstMix >>> 7), firstMix | 61) + const value = firstMix ^ secondMix + return ((value ^ (value >>> 14)) >>> 0) / 4_294_967_296 + } +} + +function roundPrice(value: number): number { + return Math.round(value * 100) / 100 +} + +function roundMoney(value: number): number { + return Math.round(value * 100) / 100 +} diff --git a/examples/solid/realtime-trading/src/feed/worker/market-feed-protocol.ts b/examples/solid/realtime-trading/src/feed/worker/market-feed-protocol.ts new file mode 100644 index 0000000000..21997ec89c --- /dev/null +++ b/examples/solid/realtime-trading/src/feed/worker/market-feed-protocol.ts @@ -0,0 +1,70 @@ +export interface MarketQuoteSnapshot { + id: string + symbol: string + company: string + venue: string + previousClose: number + open: number + high: number + low: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + volume: number + turnover: number + history: Array +} + +export interface MarketQuoteUpdate { + index: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + high: number + low: number + volume: number + turnover: number + history?: Array +} + +export type MarketFeedCommand = + | { + type: 'start' + rowCount: number + running: boolean + ticksPerSecond: number + publishIntervalMs: number + updateSparklines: boolean + sparklineSampleIntervalMs: number + } + | { type: 'set-running'; running: boolean } + | { type: 'set-rate'; ticksPerSecond: number } + | { type: 'set-publish-interval'; intervalMs: number } + | { type: 'set-sparklines'; enabled: boolean } + | { type: 'set-sparkline-interval'; intervalMs: number } + | { type: 'reset'; rowCount: number } + | { type: 'burst'; tickCount: number } + +export type MarketFeedEvent = + | { + type: 'snapshot' + sessionId: number + quotes: Array + } + | { + type: 'updates' + sessionId: number + tickCount: number + coalescedUpdateCount: number + updates: Array + } diff --git a/examples/solid/realtime-trading/src/feed/worker/market-feed.worker.ts b/examples/solid/realtime-trading/src/feed/worker/market-feed.worker.ts new file mode 100644 index 0000000000..2b7a642fd9 --- /dev/null +++ b/examples/solid/realtime-trading/src/feed/worker/market-feed.worker.ts @@ -0,0 +1,143 @@ +import { initialMarketFeedConfig } from '../market-feed-config' +import { MarketFeedEngine } from './market-feed-engine' +import type { + MarketFeedCommand, + MarketFeedEvent, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const engine = new MarketFeedEngine() +const pendingUpdates = new Map() +const runtime = { + sessionId: 0, + pendingTickCount: 0, + pendingCoalescedUpdateCount: 0, + initialized: false, + running: true, + ticksPerSecond: initialMarketFeedConfig.targetSamplesPerSecond, + publishIntervalMs: initialMarketFeedConfig.publishIntervalMs, + publishTimerId: null as ReturnType | null, + updateSparklines: initialMarketFeedConfig.updateSparklines, + sparklineSampleIntervalMs: initialMarketFeedConfig.sparklineSampleIntervalMs, + tickBudget: 0, + lastTickAt: performance.now(), +} + +addEventListener('message', ({ data }: MessageEvent) => { + switch (data.type) { + case 'start': + runtime.running = data.running + runtime.ticksPerSecond = data.ticksPerSecond + runtime.publishIntervalMs = data.publishIntervalMs + runtime.updateSparklines = data.updateSparklines + runtime.sparklineSampleIntervalMs = data.sparklineSampleIntervalMs + restartPublishTimer() + reset(data.rowCount) + break + case 'set-running': + runtime.running = data.running + break + case 'set-rate': + runtime.ticksPerSecond = data.ticksPerSecond + break + case 'set-publish-interval': + runtime.publishIntervalMs = Math.max(4, data.intervalMs) + restartPublishTimer() + break + case 'set-sparklines': + runtime.updateSparklines = data.enabled + break + case 'set-sparkline-interval': + runtime.sparklineSampleIntervalMs = Math.max(16, data.intervalMs) + break + case 'reset': + reset(data.rowCount) + break + case 'burst': + produceTicks(data.tickCount) + flush() + break + } +}) + +setInterval(() => { + const now = performance.now() + const elapsed = Math.min(100, Math.max(0, now - runtime.lastTickAt)) + runtime.lastTickAt = now + + if (runtime.initialized && runtime.running) { + runtime.tickBudget += (runtime.ticksPerSecond * elapsed) / 1_000 + const tickCount = Math.floor(runtime.tickBudget) + runtime.tickBudget -= tickCount + produceTicks(tickCount) + } +}, 16) + +restartPublishTimer() + +function reset(rowCount: number): void { + runtime.initialized = true + runtime.sessionId++ + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + runtime.tickBudget = 0 + runtime.lastTickAt = performance.now() + + post({ + type: 'snapshot', + sessionId: runtime.sessionId, + quotes: engine.reset(rowCount), + }) +} + +function produceTicks(tickCount: number): void { + if (!runtime.initialized || tickCount <= 0) return + + runtime.pendingTickCount += tickCount + for (const update of engine.applyTicks( + tickCount, + runtime.updateSparklines, + runtime.sparklineSampleIntervalMs, + )) { + const previousUpdate = pendingUpdates.get(update.index) + if (previousUpdate) runtime.pendingCoalescedUpdateCount++ + pendingUpdates.set(update.index, { + ...update, + ...(update.history || !previousUpdate?.history + ? {} + : { history: previousUpdate.history }), + }) + } +} + +function flush(): void { + if (runtime.pendingTickCount === 0) return + + const message: MarketFeedEvent = { + type: 'updates', + sessionId: runtime.sessionId, + tickCount: runtime.pendingTickCount, + coalescedUpdateCount: runtime.pendingCoalescedUpdateCount, + updates: [...pendingUpdates.values()], + } + + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + post(message) +} + +function restartPublishTimer(): void { + if (runtime.publishTimerId !== null) { + clearInterval(runtime.publishTimerId) + } + runtime.publishTimerId = setInterval( + flush, + Math.max(4, runtime.publishIntervalMs), + ) +} + +function post(event: MarketFeedEvent): void { + postMessage(event) +} diff --git a/examples/solid/realtime-trading/src/index.css b/examples/solid/realtime-trading/src/index.css new file mode 100644 index 0000000000..397c86fc54 --- /dev/null +++ b/examples/solid/realtime-trading/src/index.css @@ -0,0 +1,1058 @@ +:root { + color-scheme: dark; + --font-ui: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + 'Segoe UI', sans-serif; + --font-mono: 'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace; + font-family: var(--font-ui); + font-synthesis: none; + --background: #050505; + --panel: #080808; + --panel-raised: #111111; + --panel-hover: #181818; + --surface-bar: #080808; + --surface-toolbar: #0d0d0d; + --surface-table: #050505; + --surface-header: #101010; + --surface-control: #151515; + --border: #303030; + --border-soft: #242424; + --border-strong: #4a4a4a; + --text: #e7ebf0; + --text-strong: #ffffff; + --text-inverse: #f7f9fb; + --muted: #737982; + --blue: #62a9ff; + --blue-soft: #a9d0ff; + --green: #42e488; + --red: #ff646b; + --amber: #dfb465; + --depth-bid: #315774; + --depth-ask: #634049; + --row-alt: rgb(255 255 255 / 1.8%); + --row-selected: rgb(66 132 214 / 16%); + --control-border: #354456; + --control-hover: #192431; + --sidebar-width: 18rem; + --shell-bar-height: 2.625rem; + --metrics-height: 3.5rem; + --statusbar-height: 1.625rem; + --virtual-footer-height: 2.125rem; + --table-header-height: 2rem; + --table-row-height: 2rem; + --shell-inline-padding: 0.75rem; + --table-cell-inline-padding: 0.6rem; + --control-radius: 1px; +} + +* { + box-sizing: border-box; +} + +html, +body { + min-width: 320px; + min-height: 100%; + margin: 0; + background: var(--background); +} + +body { + color: var(--text); +} + +button, +select, +input { + font: inherit; +} + +button, +select { + color: var(--text); + background: var(--panel-raised); + border: 1px solid var(--control-border); + border-radius: var(--control-radius); +} + +button { + padding: 0.5rem 0.65rem; + cursor: pointer; + font-size: 0.72rem; + font-weight: 650; + letter-spacing: 0.025em; +} + +button:hover { + background: var(--control-hover); + border-color: var(--border-strong); +} + +button:focus-visible, +select:focus-visible, +input:focus-visible { + outline: 1px solid var(--blue); + outline-offset: 1px; +} + +select { + width: 100%; + padding: 0.45rem 0.55rem; + font-size: 0.75rem; +} + +.trading-terminal { + --active-sidebar-width: var(--sidebar-width); + display: grid; + width: 100%; + height: 100dvh; + min-height: 0; + overflow: hidden; + background: var(--background); + grid-template-areas: + 'header sidebar' + 'content sidebar' + 'footer sidebar'; + grid-template-columns: minmax(0, 1fr) var(--active-sidebar-width); + grid-template-rows: auto minmax(0, 1fr) auto; + transition: grid-template-columns 160ms ease; +} + +.trading-terminal.is-sidebar-collapsed { + --active-sidebar-width: 0px; +} + +.shell-header { + display: flex; + min-width: 0; + flex-direction: column; + grid-area: header; +} + +.app-bar { + display: flex; + min-height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + background: var(--surface-bar); + border-bottom: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.68rem; + letter-spacing: 0.045em; +} + +.brand, +.header-actions, +.feed-status { + display: flex; + align-items: center; +} + +.brand { + gap: 0.65rem; + color: var(--text-strong); +} + +.header-actions { + gap: 0.75rem; +} + +.sidebar-toggle { + display: grid; + width: 1.9rem; + height: 1.9rem; + padding: 0; + place-items: center; + color: var(--muted); + background: transparent; + border-color: transparent; +} + +.sidebar-toggle:hover { + color: var(--text-strong); + background: var(--surface-control); + border-color: var(--border); +} + +.sidebar-toggle svg { + width: 1rem; + height: 1rem; + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-width: 1.4; +} + +.feed-status { + gap: 0.4rem; + color: var(--muted); +} + +.feed-status.is-running { + color: var(--green); +} + +.status-dot { + width: 6px; + height: 6px; + background: var(--muted); + border-radius: 50%; +} + +.feed-status.is-running .status-dot { + background: var(--green); +} + +.development-warning { + flex: 0 0 auto; + padding: 0.3rem 0.75rem; + color: var(--amber); + background: color-mix(in srgb, var(--amber) 8%, var(--background)); + border-bottom: 1px solid color-mix(in srgb, var(--amber) 24%, var(--border)); + font-family: var(--font-mono); + font-size: 0.62rem; + letter-spacing: 0.04em; +} + +.market-panel { + display: flex; + min-width: 0; + min-height: 0; + flex-direction: column; + background: var(--panel); + grid-area: content; +} + +.metrics-strip { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + background: var(--border); + border-bottom: 1px solid var(--border); + gap: 1px; +} + +.metrics-strip h2 { + margin: 0; + padding: 0.65rem var(--shell-inline-padding) 0.45rem; + color: var(--muted); + background: var(--surface-table); + font-size: 0.58rem; + grid-column: 1 / -1; + letter-spacing: 0.075em; +} + +.metrics-strip article { + min-width: 0; + min-height: 4.25rem; + padding: 0.5rem var(--shell-inline-padding); + background: var(--surface-bar); +} + +.metrics-strip span, +.metrics-strip small { + display: block; + color: var(--muted); + font-size: 0.56rem; + letter-spacing: 0.045em; + line-height: 1.35; +} + +.metrics-strip strong { + display: block; + margin: 0.12rem 0 0.08rem; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.88rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +.metrics-strip strong.metric-alert { + color: var(--amber); +} + +.table-scroll { + flex: 1; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +.virtual-scroll-footer { + display: flex; + flex: 0 0 auto; + align-items: center; + justify-content: space-between; + min-height: var(--virtual-footer-height); + padding: 0 var(--shell-inline-padding); + color: var(--muted); + background: var(--surface-toolbar); + border-top: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.68rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +table { + min-width: 100%; + border-spacing: 0; + table-layout: fixed; + font-family: var(--font-ui); + font-size: 0.78rem; + font-variant-numeric: tabular-nums; +} + +.virtual-table { + display: grid; +} + +.virtual-table thead { + display: grid; +} + +.virtual-table thead tr, +.virtual-table-row { + display: flex; + width: 100%; +} + +.virtual-table th, +.virtual-table-row > td { + flex: 0 0 auto; +} + +.virtual-table-body { + position: relative; + display: grid; +} + +.virtual-table-row { + position: absolute; + left: 0; + height: var(--table-row-height); +} + +.virtual-table-row > td { + display: block; +} + +.trading-data-grid { + display: grid; +} + +.trading-data-grid thead, +.trading-data-grid tbody { + display: grid; +} + +.trading-data-grid tbody { + -webkit-user-select: none; + user-select: none; +} + +.trading-data-grid thead > tr, +.trading-data-grid tbody > tr { + display: flex; + width: 100%; +} + +.trading-data-grid tbody > tr { + min-height: var(--table-row-height); + content-visibility: auto; + contain-intrinsic-block-size: var(--table-row-height); +} + +.trading-data-grid th, +.trading-data-grid td { + flex: 0 0 auto; +} + +thead { + position: sticky; + z-index: 2; + top: 0; +} + +th { + height: var(--table-header-height); + padding: 0 var(--table-cell-inline-padding); + color: var(--muted); + background: var(--surface-header); + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border); + font-size: 0.7rem; + font-weight: 500; + letter-spacing: 0.005em; + text-align: left; + white-space: nowrap; +} + +th.column-group-header { + color: #666b72; + font-size: 0.72rem; + font-weight: 500; + text-align: center; +} + +thead tr:first-child th.column-group-header { + color: #777d85; + font-size: 0.76rem; +} + +th.numeric-header { + text-align: right; +} + +td { + height: var(--table-row-height); + padding: 0 var(--table-cell-inline-padding); + overflow: hidden; + color: #eef1f5; + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border-soft); + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +th:last-child, +td:last-child { + border-right: 0; +} + +td[data-column-id='market'], +td[data-column-id='name'], +td[data-column-id='symbol'] { + text-align: left; +} + +td[data-column-id='market'] { + color: var(--blue); + font-weight: 550; +} + +td[data-column-id='name'] { + color: var(--text-strong); +} + +td[data-column-id='symbol'] { + color: #d8dde4; + font-weight: 600; +} + +tbody tr:nth-child(even) { + background: var(--row-alt); +} + +tbody tr:hover { + background: var(--panel-hover); +} + +tbody tr[data-symbol-selected='true'] { + background: var(--row-selected); + box-shadow: inset 2px 0 0 var(--blue); +} + +.table-scroll:focus { + outline: none; +} + +th { + position: relative; +} + +.leaf-header-content { + display: flex; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + height: 100%; + align-items: stretch; + margin-inline: calc(-1 * var(--table-cell-inline-padding)); +} + +.column-drag-handle, +.sort-header-button { + min-width: 0; + height: 100%; + padding: 0; + color: inherit; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-weight: inherit; + letter-spacing: inherit; +} + +.column-drag-handle { + flex: 0 0 1.05rem; + color: var(--muted); + cursor: grab; + opacity: 0.35; + font-size: 0.56rem; + letter-spacing: -0.32rem; + text-align: center; +} + +.column-drag-handle:active { + cursor: grabbing; +} + +th:hover .column-drag-handle, +.column-drag-handle:focus-visible { + opacity: 0.9; +} + +.column-drag-handle:hover, +.sort-header-button:hover { + background: rgb(255 255 255 / 4%); + border-color: transparent; +} + +th.is-column-dragging { + opacity: 0.45; +} + +th.is-column-drop-target { + background: rgb(50 139 255 / 16%); + box-shadow: inset 4px 0 0 var(--blue); +} + +th.is-column-drop-target::before { + position: absolute; + z-index: 6; + top: -1px; + bottom: -1px; + left: -2px; + width: 4px; + background: #62a9ff; + box-shadow: + 0 0 0 1px rgb(0 0 0 / 55%), + 0 0 12px rgb(70 151 255 / 90%); + content: ''; + pointer-events: none; +} + +.sort-header-button { + display: flex; + min-width: 0; + flex: 1; + align-items: center; + justify-content: flex-start; + gap: 0.3rem; + padding-inline: 0.25rem var(--table-cell-inline-padding); + cursor: default; + text-align: inherit; +} + +.numeric-header .sort-header-button { + justify-content: flex-end; +} + +.sort-header-button.is-sortable { + cursor: pointer; +} + +.sort-header-button:disabled { + opacity: 1; +} + +.header-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.sort-indicator { + flex: 0 0 auto; + color: #66717e; + font-size: 0.72rem; +} + +.sort-indicator.is-active { + color: var(--blue-soft); +} + +.column-resize-handle { + position: absolute; + z-index: 3; + top: 0; + right: -3px; + width: 7px; + height: 100%; + cursor: col-resize; + touch-action: none; + user-select: none; +} + +.column-resize-handle::after { + position: absolute; + top: 20%; + right: 3px; + width: 1px; + height: 60%; + background: var(--border-strong); + content: ''; + opacity: 0; +} + +th:hover > .column-resize-handle::after, +.column-resize-handle.is-resizing::after { + background: var(--blue); + opacity: 1; +} + +tbody tr[aria-selected='true'] { + background: rgb(76 145 228 / 13%); +} + +td[aria-selected='true'] { + position: relative; + background: rgb(70 139 222 / 12%); +} + +td[data-cell-focused='true'] { + background: rgb(70 139 222 / 21%); +} + +td[aria-selected='true']::after { + position: absolute; + z-index: 1; + inset: 0; + border: 1px solid transparent; + content: ''; + pointer-events: none; +} + +td[data-selection-top='true']::after { + border-top-color: var(--blue); +} + +td[data-selection-right='true']::after { + border-right-color: var(--blue); +} + +td[data-selection-bottom='true']::after { + border-bottom-color: var(--blue); +} + +td[data-selection-left='true']::after { + border-left-color: var(--blue); +} + +.price-button { + min-width: 4.5rem; + padding: 0; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-variant-numeric: tabular-nums; + font-weight: 600; + text-align: right; +} + +.price-button:hover { + background: transparent; + text-decoration: underline; + text-underline-offset: 2px; +} + +.move-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.move-cell.quote-up, +.percent-change-cell.quote-up { + background: color-mix(in srgb, var(--green) 7%, transparent); +} + +.move-cell.quote-down, +.percent-change-cell.quote-down { + background: color-mix(in srgb, var(--red) 7%, transparent); +} + +.percent-change-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.spread-cell { + display: flex; + align-items: baseline; + justify-content: flex-end; + gap: 0.35rem; + color: var(--text); +} + +.spread-cell small { + min-width: 2.8rem; + color: var(--muted); + font-size: 0.55rem; +} + +.spread-cell.spread-wide, +.spread-cell.spread-wide small { + color: var(--amber); +} + +.depth-cell { + position: relative; + display: flex; + height: 17px; + overflow: hidden; + background: var(--surface-control); +} + +.depth-bid, +.depth-ask { + height: 100%; + opacity: 0.78; +} + +.depth-bid { + background: var(--depth-bid); + border-right: 1px solid var(--panel); +} + +.depth-ask { + background: var(--depth-ask); +} + +.depth-values { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 0.28rem; + color: var(--text-strong); + font-size: 0.57rem; + text-shadow: 0 1px var(--background); +} + +.quote-age { + color: var(--muted); +} + +.quote-age-warm { + color: var(--amber); +} + +.quote-age-stale { + color: var(--red); +} + +.quote-up { + color: var(--green); +} + +.quote-down { + color: var(--red); +} + +.sparkline { + display: block; + width: 100%; + height: 1.35rem; + margin-left: auto; + color: var(--blue-soft); + overflow: visible; +} + +.sparkline.quote-up { + color: var(--green); +} + +.sparkline.quote-down { + color: var(--red); +} + +.sparkline polyline { + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-linejoin: miter; + stroke-width: 1.25; + vector-effect: non-scaling-stroke; +} + +.market-statusbar { + display: flex; + flex: 0 0 var(--statusbar-height); + min-height: var(--statusbar-height); + gap: 1.1rem; + align-items: center; + padding: 0 0.65rem; + color: var(--muted); + background: var(--surface-bar); + border-top: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.56rem; + grid-area: footer; + letter-spacing: 0.035em; +} + +.market-statusbar strong { + margin-left: 0.25rem; + color: var(--text); + font-weight: 500; +} + +.sidebar-slot { + width: var(--sidebar-width); + min-width: 0; + min-height: 0; + overflow: hidden; + background: var(--surface-table); + border-left: 1px solid var(--border); + grid-area: sidebar; + transition: + opacity 120ms ease, + transform 160ms ease, + visibility 160ms; +} + +.is-sidebar-collapsed .sidebar-slot { + visibility: hidden; + opacity: 0; + pointer-events: none; + transform: translateX(100%); +} + +.configurator { + width: 100%; + height: 100%; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +.configurator > header { + display: flex; + height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + color: var(--text-strong); + background: var(--surface-toolbar); + border-bottom: 1px solid var(--border); + font-size: 0.65rem; + font-weight: 700; + letter-spacing: 0.055em; +} + +.configurator > header small { + color: var(--muted); + font-size: 0.54rem; + font-weight: 500; +} + +.config-section { + display: grid; + gap: 0.7rem; + padding: 0.8rem var(--shell-inline-padding); + border-bottom: 1px solid var(--border); +} + +.config-section h2 { + margin: 0; + color: var(--muted); + font-size: 0.58rem; + letter-spacing: 0.075em; +} + +.primary-action { + width: 100%; + color: var(--text-inverse); + background: var(--blue); + border-color: var(--blue-soft); +} + +.primary-action:hover { + background: var(--blue-soft); + border-color: var(--text-strong); +} + +.field { + display: grid; + gap: 0.35rem; + color: var(--text); + font-size: 0.66rem; +} + +.rate-field > span { + display: flex; + justify-content: space-between; +} + +.rate-field strong { + color: var(--text); + font-family: var(--font-mono); + font-weight: 500; +} + +.field small { + color: var(--muted); + font-family: var(--font-mono); + font-size: 0.55rem; +} + +input[type='range'] { + width: 100%; + margin: 0; + accent-color: var(--blue); +} + +.toggle-field { + display: flex; + gap: 0.5rem; + align-items: flex-start; + color: var(--text); + font-size: 0.66rem; + line-height: 1.3; +} + +.toggle-field input { + margin: 0.12rem 0 0; + accent-color: var(--blue); +} + +.toggle-field small { + display: block; + margin-top: 0.14rem; + color: var(--muted); + font-size: 0.57rem; +} + +.action-grid { + display: grid; + grid-template-columns: 1fr; + gap: 0.4rem; +} + +.diagnostics dl, +.selected-instrument dl { + display: grid; + gap: 0; + margin: 0; +} + +.diagnostics dl > div, +.selected-instrument dl > div { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 24px; + border-bottom: 1px solid var(--border-soft); +} + +.diagnostics dl > div:last-child, +.selected-instrument dl > div:last-child { + border-bottom: 0; +} + +.diagnostics dl > div:has(dd[data-testid$='-breakdown']) { + display: grid; + grid-template-columns: minmax(0, 1fr); + align-content: center; + padding-block: 0.28rem; +} + +.diagnostics dd[data-testid$='-breakdown'] { + width: 100%; + overflow-x: auto; + padding-block: 0.12rem; + white-space: nowrap; + scrollbar-width: thin; +} + +dt { + color: var(--muted); + font-size: 0.61rem; +} + +dd { + margin: 0; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.62rem; +} + +.selection { + display: flex; + align-items: flex-start; + justify-content: space-between; +} + +.selection div { + display: grid; + gap: 0.18rem; +} + +.selection strong { + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.85rem; +} + +.selection span, +.selection small, +.selected-instrument p { + color: var(--muted); + font-size: 0.61rem; +} + +.selected-instrument p { + margin: 0; + line-height: 1.45; +} + +@media (max-width: 980px) { + :root { + --sidebar-width: 15.625rem; + } +} + +@media (max-width: 720px) { + .trading-terminal { + --active-sidebar-width: 0px; + height: 100dvh; + min-height: 0; + overflow: hidden; + } + + .market-panel { + min-height: 0; + } + + .table-scroll { + min-height: 0; + } + + .sidebar-slot { + position: fixed; + z-index: 20; + top: 0; + right: 0; + bottom: 0; + width: min(var(--sidebar-width), calc(100vw - 2.75rem)); + box-shadow: -18px 0 42px rgb(0 0 0 / 48%); + } + + .is-sidebar-collapsed .sidebar-slot { + box-shadow: none; + } +} diff --git a/examples/solid/realtime-trading/src/index.tsx b/examples/solid/realtime-trading/src/index.tsx new file mode 100644 index 0000000000..3b0ef7f19f --- /dev/null +++ b/examples/solid/realtime-trading/src/index.tsx @@ -0,0 +1,8 @@ +import { render } from 'solid-js/web' +import App from './App' +import './index.css' + +const rootElement = document.getElementById('root') +if (!rootElement) throw new Error('Failed to find the root element') + +render(() => , rootElement) diff --git a/examples/solid/realtime-trading/src/shell/TradingShell.tsx b/examples/solid/realtime-trading/src/shell/TradingShell.tsx new file mode 100644 index 0000000000..8fdf1b60a9 --- /dev/null +++ b/examples/solid/realtime-trading/src/shell/TradingShell.tsx @@ -0,0 +1,601 @@ +import { For, Show, createMemo, createSignal } from 'solid-js' +import { longAnimationFramesSupported } from '../benchmark/benchmark-monitor' +import { + feedSampleRateAt, + feedSampleRateIndex, + feedSampleRateOptions, +} from '../feed/feed-sample-rates' +import { FORCED_VIRTUALIZATION_ROW_COUNT } from '../table/trading-row-virtualizer' +import { + useMarketFeedController, + useTradingShellController, +} from './trading-shell-context' +import { configuratorOptions } from './configurator-options' +import type { JSX } from 'solid-js' +import type { FeedMetrics } from '../benchmark/benchmark-monitor' + +const integerFormatter = new Intl.NumberFormat('en-US', { + maximumFractionDigits: 0, +}) +const rateFormatter = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +export function TradingShell(props: { children: JSX.Element }) { + const [sidebarOpen, setSidebarOpen] = createSignal(true) + const toggleSidebar = () => setSidebarOpen((open) => !open) + + return ( +
+
+ + + + + +
+ +
+ {props.children} +
+ + +
+ ) +} + +function AppHeader(props: { + sidebarOpen: boolean + onSidebarToggle: () => void +}) { + const { workerReady, running } = useMarketFeedController().state + return ( +
+
+ MARKET MONITOR +
+
+ + + +
+
+ ) +} + +function MarketStatusbar() { + const { metrics, mountedCells, liveComponents } = + useTradingShellController().state + return ( +
+ + MESSAGE SAMPLES{' '} + {formatInteger(metrics().lastBatchSize)} + + + CHANGED ROWS {formatInteger(metrics().lastUpdateCount)} + + + HOSTS {formatInteger(mountedCells())} + + + COMPONENTS {formatInteger(liveComponents())} + +
+ ) +} + +function Configurator() { + const { state, actions } = useTradingShellController() + const feed = useMarketFeedController() + const { rendererMode, virtualScrollForced, virtualScrollMode } = state + const { + running, + instrumentCount, + targetTicksPerSecond, + publishIntervalMs, + updateSparklines, + sparklineSampleIntervalMs, + } = feed.state + const { + resetViewState, + setRendererMode, + setVirtualScrollEnabled, + resetMarket, + } = actions + const { + toggle, + setInstrumentCount, + setTargetRate, + setPublishInterval, + setSparklineUpdates, + setSparklineSampleInterval, + runBurst, + } = feed.actions + return ( + + ) +} + +function MetricsStrip() { + const { metrics } = useTradingShellController().state + return ( +
+

LIVE HEALTH

+
+ FRAME RATE (EST.) + + {metrics().rafCallbacksPerSecond.toFixed(1)} + + rAF callbacks/s · rolling 1 s +
+
+ AVG COMMIT + + {formatMs(metrics().averageCommitLatencyMs)} + + snapshot → DOM · rolling 3 s +
+
+ LONG FRAMES + + N/A + unsupported by this browser + + } + > + 0, + }} + > + {metrics().longAnimationFrames} + + + since reset · worst {formatMs(metrics().worstLongAnimationFrameMs)} + + +
+
+ THROUGHPUT + + {formatRate(metrics().rowUpdatesPerSecond)} rows/s + + + {metrics().stateApplicationsPerSecond.toFixed(1)} + snapshots/s · rows deduplicated per snapshot + +
+
+ ) +} + +function Diagnostics() { + const { metrics, mountedCells, liveComponents } = + useTradingShellController().state + return ( +
+

DIAGNOSTICS

+
+
+
Worker samples / s
+
+ {formatRate(metrics().actualTicksPerSecond)} +
+
+
+
Worker messages / s
+
+ {metrics().workerMessagesPerSecond.toFixed(1)} +
+
+
+
Changed rows / s
+
+ {formatRate(metrics().rowUpdatesPerSecond)} +
+
+
+
Snapshots applied / s
+
+ {metrics().stateApplicationsPerSecond.toFixed(1)} +
+
+
+
DOM commits / s
+
+ {metrics().tableCommitsPerSecond.toFixed(1)} +
+
+
+
P95 / max commit latency
+
+ {formatMs(metrics().p95CommitLatencyMs)} /{' '} + {formatMs(metrics().maxCommitLatencyMs)} +
+
+
+
Mounted cells
+
{formatInteger(mountedCells())}
+
+
+
Live components
+
{formatInteger(liveComponents())}
+
+
+
Created / destroyed
+
+ {formatInteger(metrics().componentsCreated)} /{' '} + {formatInteger(metrics().componentsDestroyed)} +
+
+
+
Renderer callbacks / s
+
+ {formatRate(metrics().cellRendererCallsPerSecond)} +
+
+
+
Component executions / s
+
+ {formatRate(metrics().componentRenderCallsPerSecond)} +
+
+
+
Executions by component / s
+
+ {formatInvocationRates(metrics().componentRenderRates)} +
+
+
+
Callbacks by column / s
+
+ {formatInvocationRates(metrics().cellRendererRates)} +
+
+
+
Observed MutationRecords / s
+
+ {formatRate(metrics().domMutationsPerSecond)} +
+
+
+
Worker messages
+
+ {formatInteger(metrics().workerMessages)} +
+
+
+
Worker-coalesced updates / s
+
+ {formatRate(metrics().supersededUpdatesPerSecond)} +
+
+
+
Last message samples / updated rows
+
+ {formatInteger(metrics().lastBatchSize)} /{' '} + {formatInteger(metrics().lastUpdateCount)} +
+
+
+
Commits > 16.7 ms
+
{metrics().slowCommits}
+
+
+
Long animation frames
+
+ {longAnimationFramesSupported + ? formatInteger(metrics().longAnimationFrames) + : 'Unsupported'} +
+
+
+
JS heap (GC-sensitive)
+
+ {metrics().heapMb === null + ? 'N/A' + : `${metrics().heapMb?.toFixed(1)} MB`} +
+
+
+
+ ) +} + +function SelectedInstrument() { + const feed = useMarketFeedController() + const { selectedSymbol } = useTradingShellController().state + const selectedQuote = createMemo(() => + feed.getQuoteBySymbol(selectedSymbol()), + ) + return ( +
+

SELECTED INSTRUMENT

+ + Click or begin a cell selection in any row to inspect its + instrument. +

+ } + > + {(quote) => ( + <> +
+
+ {quote().symbol} + {quote().company} +
+ {quote().venue} +
+
+
+
Last
+
{quote().price.toFixed(2)}
+
+
+
Bid / ask
+
+ {quote().bid.toFixed(2)} / {quote().ask.toFixed(2)} +
+
+
+ + )} +
+
+ ) +} + +function formatInteger(value: number): string { + return integerFormatter.format(value) +} + +function formatRate(value: number): string { + return rateFormatter.format(value) +} + +function formatMs(value: number): string { + return `${value.toFixed(2)} ms` +} + +function formatInvocationRates( + rates: FeedMetrics['componentRenderRates'], +): string { + const activeRates = rates + .filter((rate) => rate.callsPerSecond > 0) + .sort((left, right) => right.callsPerSecond - left.callsPerSecond) + return activeRates.length === 0 + ? 'No calls in sample' + : activeRates + .map((rate) => `${rate.name} ${formatRate(rate.callsPerSecond)}`) + .join(' · ') +} diff --git a/examples/solid/realtime-trading/src/shell/configurator-options.ts b/examples/solid/realtime-trading/src/shell/configurator-options.ts new file mode 100644 index 0000000000..49a9566fe7 --- /dev/null +++ b/examples/solid/realtime-trading/src/shell/configurator-options.ts @@ -0,0 +1,55 @@ +export interface ConfiguratorOption { + readonly label: string + readonly value: TValue +} + +const instrumentCountOptions = [ + { label: '50', value: 50 }, + { label: '100', value: 100 }, + { label: '150', value: 150 }, + { label: '250', value: 250 }, + { label: '350', value: 350 }, + { label: '500', value: 500 }, + { label: '750', value: 750 }, + { label: '1,000', value: 1_000 }, + { label: '1,500', value: 1_500 }, + { label: '2,500', value: 2_500 }, + { label: '5,000', value: 5_000 }, + { label: '1,000,000', value: 1_000_000 }, + { label: '10,000,000', value: 10_000_000 }, +] as const satisfies ReadonlyArray> + +const workerDeliveryOptions = [ + { label: '8 ms · 125 msg/s', value: 8 }, + { label: '16 ms · 62.5 msg/s', value: 16 }, + { label: '20 ms · 50 msg/s', value: 20 }, + { label: '33 ms · 30 msg/s', value: 33 }, + { label: '50 ms · 20 msg/s', value: 50 }, + { label: '100 ms · 10 msg/s', value: 100 }, + { label: '250 ms · 4 msg/s', value: 250 }, + { label: '500 ms · 2 msg/s', value: 500 }, + { label: '1,000 ms · 1 msg/s', value: 1_000 }, +] as const satisfies ReadonlyArray> + +const rowRenderingOptions = [ + { label: 'Full DOM · render every row', value: 'none' }, + { label: 'TanStack Virtual · visible rows only', value: 'tanstack' }, +] as const satisfies ReadonlyArray> + +const intradaySamplingOptions = [ + { label: '16 ms · fastest', value: 16 }, + { label: '33 ms · very fast', value: 33 }, + { label: '50 ms · fast', value: 50 }, + { label: '100 ms', value: 100 }, + { label: '250 ms', value: 250 }, + { label: '500 ms', value: 500 }, + { label: '1,000 ms', value: 1_000 }, + { label: '2,000 ms', value: 2_000 }, +] as const satisfies ReadonlyArray> + +export const configuratorOptions = { + instrumentCounts: instrumentCountOptions, + workerDeliveryIntervals: workerDeliveryOptions, + rowRenderingModes: rowRenderingOptions, + intradaySamplingIntervals: intradaySamplingOptions, +} as const diff --git a/examples/solid/realtime-trading/src/shell/trading-shell-context.tsx b/examples/solid/realtime-trading/src/shell/trading-shell-context.tsx new file mode 100644 index 0000000000..906f35e52e --- /dev/null +++ b/examples/solid/realtime-trading/src/shell/trading-shell-context.tsx @@ -0,0 +1,51 @@ +import { createContext, useContext } from 'solid-js' +import type { JSX } from 'solid-js' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' + +const TradingShellContext = createContext() +const MarketFeedContext = createContext() + +export function MarketFeedProvider(props: { + controller: MarketFeedController + children: JSX.Element +}) { + return ( + + {props.children} + + ) +} + +export function TradingShellProvider(props: { + controller: TradingBenchmarkController + children: JSX.Element +}) { + return ( + + + {props.children} + + + ) +} + +export function useMarketFeedController(): MarketFeedController { + const controller = useContext(MarketFeedContext) + if (!controller) { + throw new Error( + 'Market data consumers must be rendered inside MarketFeedProvider', + ) + } + return controller +} + +export function useTradingShellController(): TradingBenchmarkController { + const controller = useContext(TradingShellContext) + if (!controller) { + throw new Error( + 'Trading shell components must be rendered inside TradingShellProvider', + ) + } + return controller +} diff --git a/examples/solid/realtime-trading/src/table/create-column-drag.ts b/examples/solid/realtime-trading/src/table/create-column-drag.ts new file mode 100644 index 0000000000..2acf3b96ba --- /dev/null +++ b/examples/solid/realtime-trading/src/table/create-column-drag.ts @@ -0,0 +1,66 @@ +import { createSignal } from 'solid-js' +import { reorderColumnIds } from './table-interactions' +import type { JSX } from 'solid-js' +import type { TradingTableInstance } from './trading-table-features' + +export function createColumnDrag(table: TradingTableInstance) { + const [sourceColumnId, setSourceColumnId] = createSignal(null) + const [targetColumnId, setTargetColumnId] = createSignal(null) + + const clear = (): void => { + setSourceColumnId(null) + setTargetColumnId(null) + } + + const createDropZoneProps = ( + columnId: string, + ): Pick => ({ + onDragOver(event) { + event.preventDefault() + setTargetColumnId(sourceColumnId() === columnId ? null : columnId) + }, + onDrop(event) { + event.preventDefault() + const sourceId = + event.dataTransfer?.getData('text/plain') || sourceColumnId() + if (sourceId) { + table.setColumnOrder( + reorderColumnIds( + table.getVisibleLeafColumns().map((column) => column.id), + sourceId, + columnId, + ), + ) + } + clear() + }, + }) + + const createHandleProps = ( + columnId: string, + ): Pick< + JSX.IntrinsicElements['button'], + 'draggable' | 'aria-label' | 'onDragStart' | 'onDragEnd' + > => ({ + draggable: true, + 'aria-label': `Move ${columnId} column`, + onDragStart(event) { + setSourceColumnId(columnId) + const dataTransfer = event.dataTransfer + if (!dataTransfer) return + + dataTransfer.effectAllowed = 'move' + dataTransfer.setData('text/plain', columnId) + }, + onDragEnd: clear, + }) + + return { + createDropZoneProps, + createHandleProps, + isDragging: (columnId: string) => sourceColumnId() === columnId, + isDropTarget: (columnId: string) => targetColumnId() === columnId, + } +} + +export type ColumnDrag = ReturnType diff --git a/examples/solid/realtime-trading/src/table/create-trading-table-model.ts b/examples/solid/realtime-trading/src/table/create-trading-table-model.ts new file mode 100644 index 0000000000..0c890ae800 --- /dev/null +++ b/examples/solid/realtime-trading/src/table/create-trading-table-model.ts @@ -0,0 +1,60 @@ +import { createTable } from '@tanstack/solid-table' +import { createMemo } from 'solid-js' +import { createTradingColumns } from './table-config/trading-columns' +import { tradingTableFeatures } from './trading-table-features' +import type { Accessor } from 'solid-js' +import type { MarketQuote } from '../feed/market-data' +import type { RendererMode } from './table-config/trading-columns' + +export interface CreateTradingTableModelOptions { + quotes: Accessor> + rendererMode: Accessor + onSelectSymbol: (symbol: string) => void +} + +/** + * Owns the TanStack Table model and the computations derived from table atoms. + * Consumers can subscribe to rows, columns, or layout independently. + */ +export function createTradingTableModel( + options: CreateTradingTableModelOptions, +) { + const columns = createMemo(() => + createTradingColumns({ + rendererMode: options.rendererMode(), + onSelectSymbol: options.onSelectSymbol, + }), + ) + const table = createTable({ + key: 'solid-realtime-trading', + features: tradingTableFeatures, + columnResizeMode: 'onChange', + defaultColumn: { minSize: 56, maxSize: 800 }, + autoResetCellSelection: false, + get columns() { + return columns() + }, + get data() { + return options.quotes() + }, + getRowId: (row) => row.id, + }) + const rows = createMemo(() => table.getRowModel().rows) + const tableStyle = createMemo(() => { + void table.atoms.columnSizing.get() + void table.atoms.columnOrder.get() + + const style: Record = { + width: `${table.getTotalSize()}px`, + } + for (const header of table.getFlatHeaders()) { + style[`--header-${header.id}-size`] = `${header.getSize()}` + style[`--col-${header.column.id}-size`] = `${header.column.getSize()}` + } + return style + }) + + return { columns, rows, table, tableStyle } +} + +export type TradingTableModel = ReturnType diff --git a/examples/solid/realtime-trading/src/table/jsx-attributes.ts b/examples/solid/realtime-trading/src/table/jsx-attributes.ts new file mode 100644 index 0000000000..b67d9c7ad2 --- /dev/null +++ b/examples/solid/realtime-trading/src/table/jsx-attributes.ts @@ -0,0 +1,4 @@ +/** Solid's intrinsic element types intentionally omit open-ended data-* keys. */ +export type WithDataAttributes = Attributes & { + [attribute: `data-${string}`]: string | number | boolean | undefined +} diff --git a/examples/solid/realtime-trading/src/table/table-config/market-quote-values.ts b/examples/solid/realtime-trading/src/table/table-config/market-quote-values.ts new file mode 100644 index 0000000000..4e2b5a21b1 --- /dev/null +++ b/examples/solid/realtime-trading/src/table/table-config/market-quote-values.ts @@ -0,0 +1,11 @@ +import type { MarketQuote } from '../../feed/market-data' + +export function getDayChange(quote: MarketQuote): number { + return quote.price - quote.previousClose +} + +export function getDayChangePercent(quote: MarketQuote): number { + return quote.previousClose === 0 + ? 0 + : (getDayChange(quote) / quote.previousClose) * 100 +} diff --git a/examples/solid/realtime-trading/src/table/table-config/quote-cell-props.ts b/examples/solid/realtime-trading/src/table/table-config/quote-cell-props.ts new file mode 100644 index 0000000000..eb0e12d911 --- /dev/null +++ b/examples/solid/realtime-trading/src/table/table-config/quote-cell-props.ts @@ -0,0 +1,31 @@ +export interface PriceCellProps { + price: number + move: number + onSelect: () => void +} + +export interface MoveCellProps { + move: number +} + +export interface PercentChangeCellProps { + value: number +} + +export interface SpreadCellProps { + bid: number + ask: number +} + +export interface DepthCellProps { + bidSize: number + askSize: number +} + +export interface QuoteAgeCellProps { + ageMs: number +} + +export interface SparklineCellProps { + values: ReadonlyArray +} diff --git a/examples/solid/realtime-trading/src/table/table-config/quote-cell-renderers.tsx b/examples/solid/realtime-trading/src/table/table-config/quote-cell-renderers.tsx new file mode 100644 index 0000000000..c83c2bf561 --- /dev/null +++ b/examples/solid/realtime-trading/src/table/table-config/quote-cell-renderers.tsx @@ -0,0 +1,119 @@ +import { Show } from 'solid-js' +import { useTradingRowData } from '../trading-row-data-context' +import { + DownMoveCell, + PercentChangeCell, + PriceCell, + SparklineCell, + StableMoveCell, + UpMoveCell, + recordCellRender, +} from './quote-cells' +import { getDayChange, getDayChangePercent } from './market-quote-values' + +const compactFormatter = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) + +export function createPriceCellRenderer( + onSelectSymbol: (symbol: string) => void, +) { + return function PriceCellRenderer() { + const quote = useTradingRowData() + return recordCellRender('Last', () => ( + onSelectSymbol(quote().symbol)} + /> + )) + } +} + +export function StableMoveCellRenderer() { + const quote = useTradingRowData() + return recordCellRender('Change', () => ( + + )) +} + +export function SwappingMoveCellRenderer() { + const quote = useTradingRowData() + return recordCellRender('Change', () => ( + = 0} + fallback={} + > + + + )) +} + +export function PercentChangeCellRenderer() { + const quote = useTradingRowData() + return recordCellRender('ChangePercent', () => ( + + )) +} + +export function SparklineCellRenderer() { + const quote = useTradingRowData() + return recordCellRender('Intraday', () => ( + + )) +} + +export function MarketCellRenderer() { + const quote = useTradingRowData() + return recordCellRender('Market', () => <>{quote().venue}) +} + +export function NameCellRenderer() { + const quote = useTradingRowData() + return recordCellRender('Name', () => <>{quote().company}) +} + +export function SymbolCellRenderer() { + const quote = useTradingRowData() + return recordCellRender('Symbol', () => <>{quote().symbol}) +} + +export function BidCellRenderer() { + const quote = useTradingRowData() + return recordCellRender('Bid', () => <>{quote().bid.toFixed(2)}) +} + +export function BidVolumeCellRenderer() { + const quote = useTradingRowData() + return recordCellRender('BidVolume', () => ( + <>{compactFormatter.format(quote().bidSize)} + )) +} + +export function AskCellRenderer() { + const quote = useTradingRowData() + return recordCellRender('Ask', () => <>{quote().ask.toFixed(2)}) +} + +export function AskVolumeCellRenderer() { + const quote = useTradingRowData() + return recordCellRender('AskVolume', () => ( + <>{compactFormatter.format(quote().askSize)} + )) +} + +export function OpenCellRenderer() { + const quote = useTradingRowData() + return recordCellRender('Open', () => <>{quote().open.toFixed(2)}) +} + +export function HighCellRenderer() { + const quote = useTradingRowData() + return recordCellRender('High', () => <>{quote().high.toFixed(2)}) +} + +export function LowCellRenderer() { + const quote = useTradingRowData() + return recordCellRender('Low', () => <>{quote().low.toFixed(2)}) +} diff --git a/examples/solid/realtime-trading/src/table/table-config/quote-cells.tsx b/examples/solid/realtime-trading/src/table/table-config/quote-cells.tsx new file mode 100644 index 0000000000..510246103b --- /dev/null +++ b/examples/solid/realtime-trading/src/table/table-config/quote-cells.tsx @@ -0,0 +1,245 @@ +import { createMemo, onCleanup, onMount } from 'solid-js' +import type { + DepthCellProps, + MoveCellProps, + PercentChangeCellProps, + PriceCellProps, + QuoteAgeCellProps, + SparklineCellProps, + SpreadCellProps, +} from './quote-cell-props' + +const compactNumber = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) + +export const quoteCellLifecycle = { + created: 0, + destroyed: 0, +} + +export const quoteCellRendererNames = [ + 'Market', + 'Name', + 'Symbol', + 'Last', + 'Change', + 'ChangePercent', + 'Bid', + 'BidVolume', + 'Ask', + 'AskVolume', + 'Open', + 'High', + 'Low', + 'Intraday', +] as const + +export const quoteComponentNames = [ + 'PriceCell', + 'StableMoveCell', + 'UpMoveCell', + 'DownMoveCell', + 'PercentChangeCell', + 'SpreadCell', + 'DepthCell', + 'QuoteAgeCell', + 'SparklineCell', +] as const + +export type QuoteCellRendererName = (typeof quoteCellRendererNames)[number] +export type QuoteComponentName = (typeof quoteComponentNames)[number] + +const createCounterMap = ( + names: ReadonlyArray, +): Record => + Object.fromEntries(names.map((name) => [name, 0])) as Record + +export const quoteRenderDiagnostics = { + cellRendererCalls: 0, + componentRenderCalls: 0, + cellRendererCallsByName: createCounterMap(quoteCellRendererNames), + componentRenderCallsByName: createCounterMap(quoteComponentNames), +} + +export function recordCellRender( + name: QuoteCellRendererName, + value: () => T, +): T { + quoteRenderDiagnostics.cellRendererCalls++ + quoteRenderDiagnostics.cellRendererCallsByName[name]++ + return value() +} + +function trackLifecycle(componentName: QuoteComponentName): void { + quoteRenderDiagnostics.componentRenderCalls++ + quoteRenderDiagnostics.componentRenderCallsByName[componentName]++ + onMount(() => { + quoteCellLifecycle.created++ + }) + onCleanup(() => { + quoteCellLifecycle.destroyed++ + }) +} + +export function PriceCell(props: PriceCellProps) { + trackLifecycle('PriceCell') + return ( + + ) +} + +export function StableMoveCell(props: MoveCellProps) { + trackLifecycle('StableMoveCell') + return ( + = 0, + 'quote-down': props.move < 0, + }} + > + {formatSigned(props.move)} + + ) +} + +export function UpMoveCell(props: MoveCellProps) { + trackLifecycle('UpMoveCell') + return ▲ {formatSigned(props.move)} +} + +export function DownMoveCell(props: MoveCellProps) { + trackLifecycle('DownMoveCell') + return ▼ {formatSigned(props.move)} +} + +export function PercentChangeCell(props: PercentChangeCellProps) { + trackLifecycle('PercentChangeCell') + return ( + = 0, + 'quote-down': props.value < 0, + }} + > + {props.value >= 0 ? '+' : ''} + {props.value.toFixed(2)}% + + ) +} + +export function SpreadCell(props: SpreadCellProps) { + trackLifecycle('SpreadCell') + const spread = createMemo(() => Math.max(0, props.ask - props.bid)) + const basisPoints = createMemo(() => { + const midpoint = (props.bid + props.ask) / 2 + return midpoint === 0 ? 0 : (spread() / midpoint) * 10_000 + }) + + return ( + = 4 }}> + {spread().toFixed(2)} + {basisPoints().toFixed(1)} bp + + ) +} + +export function DepthCell(props: DepthCellProps) { + trackLifecycle('DepthCell') + const bidShare = createMemo(() => { + const total = props.bidSize + props.askSize + return total === 0 ? 50 : (props.bidSize / total) * 100 + }) + + return ( +
+ + + + {compactNumber.format(props.bidSize)} + {compactNumber.format(props.askSize)} + +
+ ) +} + +export function QuoteAgeCell(props: QuoteAgeCellProps) { + trackLifecycle('QuoteAgeCell') + return ( + = 500, + 'quote-age-stale': props.ageMs >= 1_500, + }} + > + {props.ageMs < 1_000 + ? `${Math.round(props.ageMs)} ms` + : `${(props.ageMs / 1_000).toFixed(1)} s`} + + ) +} + +export function SparklineCell(props: SparklineCellProps) { + trackLifecycle('SparklineCell') + const rising = createMemo( + () => (props.values.at(-1) ?? 0) >= (props.values[0] ?? 0), + ) + const points = createMemo(() => { + const { min, max } = findRange(props.values) + const range = max - min || 1 + const denominator = Math.max(1, props.values.length - 1) + return props.values + .map((value, index) => { + const x = (index / denominator) * 100 + const y = 22 - ((value - min) / range) * 20 + return `${x.toFixed(1)},${y.toFixed(1)}` + }) + .join(' ') + }) + + return ( + + + + ) +} + +function formatSigned(value: number): string { + return `${value >= 0 ? '+' : ''}${value.toFixed(2)}` +} + +function findRange(values: ReadonlyArray): { + min: number + max: number +} { + const first = values[0] ?? 0 + return values.reduce( + (range, value) => { + range.min = Math.min(range.min, value) + range.max = Math.max(range.max, value) + return range + }, + { min: first, max: first }, + ) +} diff --git a/examples/solid/realtime-trading/src/table/table-config/trading-columns.tsx b/examples/solid/realtime-trading/src/table/table-config/trading-columns.tsx new file mode 100644 index 0000000000..9cf09e5174 --- /dev/null +++ b/examples/solid/realtime-trading/src/table/table-config/trading-columns.tsx @@ -0,0 +1,153 @@ +import { createColumnHelper } from '@tanstack/solid-table' +import { + AskCellRenderer, + AskVolumeCellRenderer, + BidCellRenderer, + BidVolumeCellRenderer, + HighCellRenderer, + LowCellRenderer, + MarketCellRenderer, + NameCellRenderer, + OpenCellRenderer, + PercentChangeCellRenderer, + SparklineCellRenderer, + StableMoveCellRenderer, + SwappingMoveCellRenderer, + SymbolCellRenderer, + createPriceCellRenderer, +} from './quote-cell-renderers' +import { getDayChange, getDayChangePercent } from './market-quote-values' +import { tradingTableFeatures } from '../trading-table-features' +import type { MarketQuote } from '../../feed/market-data' + +export type RendererMode = 'stable' | 'swap' + +export interface TradingColumnOptions { + rendererMode: RendererMode + onSelectSymbol: (symbol: string) => void +} + +const columnHelper = createColumnHelper< + typeof tradingTableFeatures, + MarketQuote +>() + +export function createTradingColumns(options: TradingColumnOptions) { + const priceCell = createPriceCellRenderer(options.onSelectSymbol) + const changeCell = + options.rendererMode === 'stable' + ? StableMoveCellRenderer + : SwappingMoveCellRenderer + + return columnHelper.columns([ + columnHelper.group({ + id: 'instrument', + header: 'Instrument', + columns: columnHelper.columns([ + columnHelper.accessor('venue', { + id: 'market', + header: 'Market', + size: 72, + cell: MarketCellRenderer, + }), + columnHelper.accessor('company', { + id: 'name', + header: 'Name', + size: 180, + cell: NameCellRenderer, + }), + columnHelper.accessor('symbol', { + header: 'Symbol', + size: 92, + cell: SymbolCellRenderer, + }), + ]), + }), + columnHelper.group({ + id: 'priceAndChange', + header: 'Price & Change', + columns: columnHelper.columns([ + columnHelper.accessor('price', { + header: 'Price', + size: 96, + cell: priceCell, + }), + columnHelper.accessor((row) => getDayChange(row), { + id: 'change', + header: 'Chg', + size: 94, + cell: changeCell, + }), + columnHelper.accessor((row) => getDayChangePercent(row), { + id: 'changePercent', + header: 'Chg%', + size: 90, + cell: PercentChangeCellRenderer, + }), + ]), + }), + columnHelper.group({ + id: 'orderBook', + header: 'Order Book', + columns: columnHelper.columns([ + columnHelper.accessor('bid', { + header: 'Bid', + size: 90, + cell: BidCellRenderer, + }), + columnHelper.accessor('bidSize', { + header: 'Bid Vol', + size: 100, + cell: BidVolumeCellRenderer, + }), + columnHelper.accessor('ask', { + header: 'Ask', + size: 90, + cell: AskCellRenderer, + }), + columnHelper.accessor('askSize', { + header: 'Ask Vol', + size: 100, + cell: AskVolumeCellRenderer, + }), + ]), + }), + columnHelper.group({ + id: 'session', + header: 'Session', + columns: columnHelper.columns([ + columnHelper.accessor('open', { + header: 'Open', + size: 90, + cell: OpenCellRenderer, + }), + columnHelper.accessor('high', { + header: 'High', + size: 90, + cell: HighCellRenderer, + }), + columnHelper.accessor('low', { + header: 'Low', + size: 90, + cell: LowCellRenderer, + }), + ]), + }), + columnHelper.group({ + id: 'chart', + header: 'Chart', + columns: columnHelper.columns([ + columnHelper.accessor('history', { + header: 'Intraday', + size: 150, + enableSorting: false, + cell: SparklineCellRenderer, + }), + ]), + }), + ]) +} + +export type TradingColumnSet = ReturnType + +export const TRADING_COLUMN_COUNT = 14 diff --git a/examples/solid/realtime-trading/src/table/table-interactions.ts b/examples/solid/realtime-trading/src/table/table-interactions.ts new file mode 100644 index 0000000000..6ed8912743 --- /dev/null +++ b/examples/solid/realtime-trading/src/table/table-interactions.ts @@ -0,0 +1,194 @@ +import type { JSX } from 'solid-js' + +export type CellDirection = 'up' | 'down' | 'left' | 'right' + +interface RowSelectionTable { + resetRowSelection: (defaultState?: boolean) => void +} + +interface SelectableRow { + getIsSelected: () => boolean + getToggleSelectedHandler: (options?: { + selectChildren?: boolean + }) => (event: unknown) => void +} + +interface SelectableGridCell { + row: SelectableGridRow + getSelectionStartHandler: ( + contextDocument?: Document, + ) => (event: unknown) => void + getSelectionExtendHandler: () => (event: unknown) => void +} + +interface SelectableGridRow extends SelectableRow { + original: { symbol: string } + getAllCellsByColumnId: () => Record +} + +interface TradingGridTable extends RowSelectionTable { + getRowModel: () => { + rowsById: Record + } +} + +interface SelectionCellTarget { + element: HTMLTableCellElement + cell: SelectableGridCell +} + +interface CellNavigationTable { + extendCellSelection: (direction: CellDirection) => void + moveCellSelection: (direction: CellDirection) => void + resetCellSelection: (defaultState?: boolean) => void + selectAllCells: () => void +} + +const keyDirections: Partial> = { + ArrowUp: 'up', + ArrowDown: 'down', + ArrowLeft: 'left', + ArrowRight: 'right', +} + +export function reorderColumnIds( + columnIds: Array, + sourceId: string, + targetId: string, +): Array { + if (sourceId === targetId || !columnIds.includes(sourceId)) return columnIds + + const withoutSource = columnIds.filter((id) => id !== sourceId) + const targetIndex = withoutSource.indexOf(targetId) + if (targetIndex < 0) return columnIds + + return [ + ...withoutSource.slice(0, targetIndex), + sourceId, + ...withoutSource.slice(targetIndex), + ] +} + +export function selectRowFromPointer( + table: RowSelectionTable, + row: SelectableRow, + event: MouseEvent, +): void { + const additive = event.ctrlKey || event.metaKey + const checked = additive ? !row.getIsSelected() : true + + if (!event.shiftKey && !additive) table.resetRowSelection(true) + + row.getToggleSelectedHandler({ selectChildren: false })({ + target: { checked }, + shiftKey: event.shiftKey, + ctrlKey: event.ctrlKey, + metaKey: event.metaKey, + }) +} + +/** + * Creates the only pointer listeners used by the table body. Cells expose just + * identity data; delegated events resolve the current TanStack cell on demand. + */ +export function createTradingGridSelectionHandlers( + table: TradingGridTable, + selectSymbol: (symbol: string) => void, +) { + const runtime = { lastCell: null as HTMLTableCellElement | null } + + return { + onMouseDown(event) { + if (event.button !== 0) return + + const target = findCellTarget(table, event.composedPath()) + if (!target) return + + event.preventDefault() + runtime.lastCell = target.element + selectSymbol(target.cell.row.original.symbol) + target.cell.getSelectionStartHandler(target.element.ownerDocument)(event) + }, + onMouseOver(event) { + if ((event.buttons & 1) === 0) { + runtime.lastCell = null + return + } + + const target = findCellTarget(table, event.composedPath()) + if (!target || target.element === runtime.lastCell) return + + runtime.lastCell = target.element + target.cell.getSelectionExtendHandler()(event) + }, + onMouseLeave() { + runtime.lastCell = null + }, + onClick(event) { + const target = findCellTarget(table, event.composedPath()) + if (!target) return + selectRowFromPointer(table, target.cell.row, event) + }, + } satisfies Pick< + JSX.IntrinsicElements['tbody'], + 'onMouseDown' | 'onMouseOver' | 'onMouseLeave' | 'onClick' + > +} + +function findCellTarget( + table: TradingGridTable, + path: Array, +): SelectionCellTarget | null { + for (const target of path) { + if (!(target instanceof HTMLTableCellElement)) continue + + const columnId = target.dataset['columnId'] + const rowId = + target.closest('tr[data-row-id]')?.dataset['rowId'] + if (!columnId || !rowId) return null + + const row = table.getRowModel().rowsById[rowId] + const cell = row.getAllCellsByColumnId()[columnId] + return { element: target, cell } + } + + return null +} + +export function handleCellNavigation( + table: CellNavigationTable, + event: KeyboardEvent, +): void { + if (event.key === 'Escape') { + event.preventDefault() + table.resetCellSelection(true) + return + } + + if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'a') { + event.preventDefault() + table.selectAllCells() + return + } + + const direction = keyDirections[event.key] + if (!direction) return + + event.preventDefault() + if (event.shiftKey) table.extendCellSelection(direction) + else table.moveCellSelection(direction) +} + +export function sortIndicator(direction: false | 'asc' | 'desc'): string { + if (direction === 'asc') return '↑' + if (direction === 'desc') return '↓' + return '↕' +} + +export function sortAriaValue( + direction: false | 'asc' | 'desc', +): 'ascending' | 'descending' | 'none' { + if (direction === 'asc') return 'ascending' + if (direction === 'desc') return 'descending' + return 'none' +} diff --git a/examples/solid/realtime-trading/src/table/trading-grid-props.ts b/examples/solid/realtime-trading/src/table/trading-grid-props.ts new file mode 100644 index 0000000000..b4cac193e0 --- /dev/null +++ b/examples/solid/realtime-trading/src/table/trading-grid-props.ts @@ -0,0 +1,41 @@ +import { handleCellNavigation } from './table-interactions' +import type { Accessor, JSX } from 'solid-js' +import type { WithDataAttributes } from './jsx-attributes' +import type { TradingTableInstance } from './trading-table-features' + +export interface TradingGridPropsOptions { + table: TradingTableInstance + virtualized: Accessor +} + +export function createTradingGridProps( + options: TradingGridPropsOptions, +): WithDataAttributes { + return { + class: 'table-scroll', + get classList() { + return { 'is-virtualized': options.virtualized() } + }, + 'data-trading-table': true, + tabindex: 0, + onKeyDown: (event) => handleCellNavigation(options.table, event), + } +} + +export function createTradingTableElementProps( + options: TradingGridPropsOptions, + style: Accessor>, +): WithDataAttributes { + return { + class: 'trading-data-grid', + get classList() { + return { 'virtual-table': options.virtualized() } + }, + 'data-testid': 'trading-table', + role: 'grid', + 'aria-multiselectable': true, + get style() { + return style() + }, + } +} diff --git a/examples/solid/realtime-trading/src/table/trading-row-data-context.tsx b/examples/solid/realtime-trading/src/table/trading-row-data-context.tsx new file mode 100644 index 0000000000..593c084a93 --- /dev/null +++ b/examples/solid/realtime-trading/src/table/trading-row-data-context.tsx @@ -0,0 +1,26 @@ +import { createContext, useContext } from 'solid-js' +import type { Accessor, JSX } from 'solid-js' +import type { MarketQuote } from '../feed/market-data' + +export interface TradingRowDataProviderProps { + quote: Accessor + children?: JSX.Element +} + +const TradingRowDataContext = createContext>() + +export function TradingRowDataProvider(props: TradingRowDataProviderProps) { + return ( + + {props.children} + + ) +} + +export function useTradingRowData(): Accessor { + const quote = useContext(TradingRowDataContext) + if (!quote) { + throw new Error('Trading cell renderers require TradingRowDataProvider') + } + return quote +} diff --git a/examples/solid/realtime-trading/src/table/trading-row-virtualizer.ts b/examples/solid/realtime-trading/src/table/trading-row-virtualizer.ts new file mode 100644 index 0000000000..ded27acb4e --- /dev/null +++ b/examples/solid/realtime-trading/src/table/trading-row-virtualizer.ts @@ -0,0 +1,77 @@ +import { createVirtualizer } from '@tanstack/solid-virtual' +import { createEffect, createMemo } from 'solid-js' +import type { Accessor } from 'solid-js' +import type { TradingRow } from './trading-table-features' + +export const TRADING_ROW_HEIGHT = 32 +export const TRADING_ROW_OVERSCAN = 10 +export const DEFAULT_VIRTUALIZATION_ROW_COUNT = 200 +export const FORCED_VIRTUALIZATION_ROW_COUNT = 1_500 + +export type VirtualScrollMode = 'tanstack' | 'none' +export type VirtualScrollPreference = VirtualScrollMode | 'auto' + +export interface TradingRowVirtualizationOptions { + rows: Accessor> + scrollElement: Accessor + enabled: Accessor + onRenderedRowCount: (count: number) => void +} + +export function createTradingRowVirtualization( + options: TradingRowVirtualizationOptions, +) { + const virtualizer = createVirtualizer({ + get count() { + return options.rows().length + }, + estimateSize: () => TRADING_ROW_HEIGHT, + getScrollElement: options.scrollElement, + getItemKey: (index) => options.rows()[index]?.id ?? index, + overscan: TRADING_ROW_OVERSCAN, + get enabled() { + return options.enabled() + }, + }) + const virtualRows = virtualizer.getVirtualItems + const visibleRange = createMemo(() => { + const items = virtualRows() + const rowCount = options.rows().length + if (!options.enabled() || rowCount === 0 || items.length === 0) return null + + const lastRowIndex = rowCount - 1 + const start = Math.min(items[0]!.index, lastRowIndex) + return { + start, + end: Math.min(items[items.length - 1]!.index, lastRowIndex), + } + }) + const bodyHeight = createMemo(() => + options.enabled() + ? `${options.rows().length * TRADING_ROW_HEIGHT}px` + : undefined, + ) + + createEffect(() => { + options.onRenderedRowCount( + options.enabled() ? virtualRows().length : options.rows().length, + ) + }) + + return { bodyHeight, virtualizer, virtualRows, visibleRange } +} + +export type TradingRowVirtualization = ReturnType< + typeof createTradingRowVirtualization +> + +export function resolveVirtualScrollMode( + requestedMode: VirtualScrollPreference, + instrumentCount: number, +): VirtualScrollMode { + if (instrumentCount >= FORCED_VIRTUALIZATION_ROW_COUNT) return 'tanstack' + if (requestedMode !== 'auto') return requestedMode + return instrumentCount >= DEFAULT_VIRTUALIZATION_ROW_COUNT + ? 'tanstack' + : 'none' +} diff --git a/examples/solid/realtime-trading/src/table/trading-table-body.tsx b/examples/solid/realtime-trading/src/table/trading-table-body.tsx new file mode 100644 index 0000000000..3a074634b3 --- /dev/null +++ b/examples/solid/realtime-trading/src/table/trading-table-body.tsx @@ -0,0 +1,81 @@ +import { Index, Show, createMemo } from 'solid-js' +import { createTradingGridSelectionHandlers } from './table-interactions' +import { TradingTableRow } from './trading-table-row' +import type { Accessor, JSX } from 'solid-js' +import type { TradingColumnSet } from './table-config/trading-columns' +import type { TradingRowVirtualization } from './trading-row-virtualizer' +import type { TradingRow, TradingTableInstance } from './trading-table-features' + +export interface TradingTableBodyProps { + table: TradingTableInstance + rows: Accessor> + columnVersion: Accessor + selectedSymbol: Accessor + virtualized: Accessor + virtualization: TradingRowVirtualization + selectSymbol: (symbol: string) => void +} + +export function TradingTableBody(props: TradingTableBodyProps) { + const bodyProps = createTradingTableBodyProps(props) + + return ( + + }> + + + + ) +} + +function FullTableRows(props: TradingTableBodyProps) { + return ( + + {(row) => ( + + )} + + ) +} + +function VirtualTableRows(props: TradingTableBodyProps) { + return ( + + {(virtualRow) => { + const row = createMemo(() => props.rows()[virtualRow().index]) + return ( + + ) + }} + + ) +} + +function createTradingTableBodyProps( + options: TradingTableBodyProps, +): JSX.IntrinsicElements['tbody'] { + const selectionHandlers = createTradingGridSelectionHandlers( + options.table, + options.selectSymbol, + ) + + return { + ...selectionHandlers, + get classList() { + return { 'virtual-table-body': options.virtualized() } + }, + get style() { + const height = options.virtualization.bodyHeight() + return height === undefined ? undefined : { height } + }, + } +} diff --git a/examples/solid/realtime-trading/src/table/trading-table-effects.ts b/examples/solid/realtime-trading/src/table/trading-table-effects.ts new file mode 100644 index 0000000000..d106818ba1 --- /dev/null +++ b/examples/solid/realtime-trading/src/table/trading-table-effects.ts @@ -0,0 +1,68 @@ +import { createEffect, onCleanup, onMount } from 'solid-js' +import type { Accessor } from 'solid-js' +import type { TradingTableInstance } from './trading-table-features' + +export function createFeedCommitTracking( + quotes: Accessor, + completeCommit: () => void, +): void { + const runtime = { queued: false, disposed: false } + + createEffect(() => { + quotes() + if (runtime.queued) return + + runtime.queued = true + queueMicrotask(() => { + runtime.queued = false + if (!runtime.disposed) completeCommit() + }) + }) + + onCleanup(() => { + runtime.disposed = true + }) +} + +export function createTableAutoFit( + table: TradingTableInstance, + scrollElement: Accessor, +): void { + const runtime = { manuallyResized: false } + + onMount(() => { + const fitAvailableWidth = (): void => { + const element = scrollElement() + if (!element || runtime.manuallyResized) return + + const currentWidth = table.getTotalSize() + const availableWidth = element.clientWidth + if (availableWidth <= currentWidth + 1 || currentWidth <= 0) return + + const ratio = availableWidth / currentWidth + table.setColumnSizing( + Object.fromEntries( + table + .getVisibleLeafColumns() + .map((column) => [column.id, column.getSize() * ratio]), + ), + ) + } + const resizeObserver = new ResizeObserver(fitAvailableWidth) + const resizingSubscription = table.atoms.columnResizing.subscribe( + (state) => { + if (state.isResizingColumn !== false) { + runtime.manuallyResized = true + } + }, + ) + const element = scrollElement() + if (element) resizeObserver.observe(element) + fitAvailableWidth() + + onCleanup(() => { + resizeObserver.disconnect() + resizingSubscription.unsubscribe() + }) + }) +} diff --git a/examples/solid/realtime-trading/src/table/trading-table-features.ts b/examples/solid/realtime-trading/src/table/trading-table-features.ts new file mode 100644 index 0000000000..0af9b8983b --- /dev/null +++ b/examples/solid/realtime-trading/src/table/trading-table-features.ts @@ -0,0 +1,19 @@ +import { + createSortedRowModel, + stockFeatures, + tableFeatures, +} from '@tanstack/solid-table' +import type { Cell, Header, Row, SolidTable } from '@tanstack/solid-table' +import type { MarketQuote } from '../feed/market-data' + +export const tradingTableFeatures = tableFeatures({ + ...stockFeatures, + sortedRowModel: createSortedRowModel(), +}) + +export type TradingTableFeatures = typeof tradingTableFeatures +export type TradingTableInstance = SolidTable +export type TradingRow = Row +export type TradingCell = Cell +export type TradingCellContext = ReturnType +export type TradingHeader = Header diff --git a/examples/solid/realtime-trading/src/table/trading-table-footer.tsx b/examples/solid/realtime-trading/src/table/trading-table-footer.tsx new file mode 100644 index 0000000000..22bdc6ab9a --- /dev/null +++ b/examples/solid/realtime-trading/src/table/trading-table-footer.tsx @@ -0,0 +1,33 @@ +import { Show } from 'solid-js' +import type { Accessor } from 'solid-js' +import type { TradingRowVirtualization } from './trading-row-virtualizer' +import type { TradingRow, TradingTableInstance } from './trading-table-features' + +export interface TradingTableFooterProps { + table: TradingTableInstance + rows: Accessor> + virtualized: Accessor + virtualization: TradingRowVirtualization +} + +function visibleRangeLabel(virtualization: TradingRowVirtualization): string { + const items = virtualization.virtualRows() + if (items.length === 0) return 'Current · rows —' + return `Current · rows ${items[0]!.index}..${items[items.length - 1]!.index}` +} + +export function TradingTableFooter(props: TradingTableFooterProps) { + return ( + +
+ + TanStack · Total · {props.rows().length} rows ·{' '} + {props.table.getVisibleLeafColumns().length} columns + + + {visibleRangeLabel(props.virtualization)} + +
+
+ ) +} diff --git a/examples/solid/realtime-trading/src/table/trading-table-header.tsx b/examples/solid/realtime-trading/src/table/trading-table-header.tsx new file mode 100644 index 0000000000..6a0f1ae86c --- /dev/null +++ b/examples/solid/realtime-trading/src/table/trading-table-header.tsx @@ -0,0 +1,166 @@ +import { FlexRender } from '@tanstack/solid-table' +import { For, Show } from 'solid-js' +import { createColumnDrag } from './create-column-drag' +import { sortAriaValue, sortIndicator } from './table-interactions' +import type { JSX } from 'solid-js' +import type { ColumnDrag } from './create-column-drag' +import type { + TradingHeader, + TradingTableInstance, +} from './trading-table-features' + +export interface TradingTableHeaderProps { + table: TradingTableInstance +} + +export function TradingTableHeader(props: TradingTableHeaderProps) { + const columnDrag = createColumnDrag(props.table) + + return ( + + + {(headerGroup) => ( + + + {(header) => ( + + )} + + + )} + + + ) +} + +interface TradingHeaderCellProps { + header: TradingHeader + columnDrag: ColumnDrag +} + +function TradingHeaderCell(props: TradingHeaderCellProps) { + const isLeaf = () => props.header.subHeaders.length === 0 + const headerCellProps = createHeaderCellProps( + () => props.header, + isLeaf, + props.columnDrag, + ) + + return ( + + + }> + + + + + ) +} + +function TradingLeafHeader(props: TradingHeaderCellProps) { + const dropZoneProps = props.columnDrag.createDropZoneProps( + props.header.column.id, + ) + const dragHandleProps = props.columnDrag.createHandleProps( + props.header.column.id, + ) + const sortButtonProps = createSortButtonProps(() => props.header) + const resizeHandleProps = createResizeHandleProps(() => props.header) + + return ( + <> +
+ + +
+ +
+ + + ) +} + +function createHeaderCellProps( + header: () => TradingHeader, + isLeaf: () => boolean, + columnDrag: ColumnDrag, +): JSX.IntrinsicElements['th'] { + return { + get colSpan() { + return header().colSpan + }, + get style() { + return { + width: `calc(var(--header-${header().id}-size) * 1px)`, + } + }, + get ['aria-sort']() { + return isLeaf() ? sortAriaValue(header().column.getIsSorted()) : undefined + }, + get classList() { + const columnId = header().column.id + return { + 'column-group-header': !isLeaf(), + 'numeric-header': isLeaf() && !isTextColumn(columnId), + 'is-column-dragging': columnDrag.isDragging(columnId), + 'is-column-drop-target': columnDrag.isDropTarget(columnId), + } + }, + } +} + +function createSortButtonProps( + header: () => TradingHeader, +): JSX.IntrinsicElements['button'] { + return { + type: 'button', + class: 'sort-header-button', + get classList() { + return { 'is-sortable': header().column.getCanSort() } + }, + get disabled() { + return !header().column.getCanSort() + }, + onClick: header().column.getToggleSortingHandler(), + } +} + +function createResizeHandleProps( + header: () => TradingHeader, +): JSX.IntrinsicElements['div'] { + return { + class: 'column-resize-handle', + get classList() { + return { 'is-resizing': header().column.getIsResizing() } + }, + role: 'separator', + 'aria-orientation': 'vertical', + onDblClick: () => header().column.resetSize(), + onMouseDown: header().getResizeHandler(), + onTouchStart: header().getResizeHandler(), + } +} + +function isTextColumn(columnId: string): boolean { + return columnId === 'market' || columnId === 'name' || columnId === 'symbol' +} diff --git a/examples/solid/realtime-trading/src/table/trading-table-row.tsx b/examples/solid/realtime-trading/src/table/trading-table-row.tsx new file mode 100644 index 0000000000..6d25d8258a --- /dev/null +++ b/examples/solid/realtime-trading/src/table/trading-table-row.tsx @@ -0,0 +1,105 @@ +import { FlexRender } from '@tanstack/solid-table' +import { Index, createMemo } from 'solid-js' +import { TradingRowDataProvider } from './trading-row-data-context' +import type { VirtualItem } from '@tanstack/solid-virtual' +import type { TradingColumnSet } from './table-config/trading-columns' +import type { TradingCell, TradingRow } from './trading-table-features' + +export interface TradingTableRowProps { + row: TradingRow + columnVersion: TradingColumnSet + selectedSymbol: string | null + virtualItem?: VirtualItem +} + +interface TradingTableCellProps { + cell: TradingCell + renderCell: TradingCell +} + +export function TradingTableRow(props: TradingTableRowProps) { + const currentCells = createMemo(() => props.row.getVisibleCells()) + const renderState = createMemo( + () => ({ + rowId: props.row.id, + columns: props.columnVersion, + cells: currentCells(), + }), + undefined, + { + equals: (previous, next) => + previous.rowId === next.rowId && + previous.columns === next.columns && + haveSameCellOrder(previous.cells, next.cells), + }, + ) + + return ( + props.row.original}> + + + {(cell, index) => ( + + )} + + + + ) +} + +function TradingTableCell(props: TradingTableCellProps) { + const selection = createMemo(() => ({ + edges: props.cell.getSelectionEdges(), + focused: props.cell.getIsFocused(), + selected: props.cell.getIsSelected(), + tabIndex: props.cell.getTabIndex(), + })) + + return ( + + + + ) +} + +function haveSameCellOrder( + previous: ReadonlyArray, + next: ReadonlyArray, +): boolean { + return ( + previous.length === next.length && + previous.every((cell, index) => cell.column.id === next[index]?.column.id) + ) +} diff --git a/examples/solid/realtime-trading/src/table/trading-table.tsx b/examples/solid/realtime-trading/src/table/trading-table.tsx new file mode 100644 index 0000000000..6c19ecfbeb --- /dev/null +++ b/examples/solid/realtime-trading/src/table/trading-table.tsx @@ -0,0 +1,77 @@ +import { createSignal } from 'solid-js' +import { + useMarketFeedController, + useTradingShellController, +} from '../shell/trading-shell-context' +import { createTradingTableModel } from './create-trading-table-model' +import { + createTradingGridProps, + createTradingTableElementProps, +} from './trading-grid-props' +import { + createFeedCommitTracking, + createTableAutoFit, +} from './trading-table-effects' +import { createTradingRowVirtualization } from './trading-row-virtualizer' +import { TradingTableBody } from './trading-table-body' +import { TradingTableFooter } from './trading-table-footer' +import { TradingTableHeader } from './trading-table-header' + +export function TradingTable() { + const feed = useMarketFeedController() + const { state, actions } = useTradingShellController() + const [scrollElement, setScrollElement] = createSignal( + null, + ) + const virtualized = () => state.virtualScrollMode() === 'tanstack' + const model = createTradingTableModel({ + quotes: feed.state.quotes, + rendererMode: state.rendererMode, + onSelectSymbol: actions.selectSymbol, + }) + const virtualization = createTradingRowVirtualization({ + rows: model.rows, + scrollElement, + enabled: virtualized, + onRenderedRowCount: actions.setRenderedRowCount, + }) + const elementOptions = { table: model.table, virtualized } + const gridProps = createTradingGridProps(elementOptions) + const tableProps = createTradingTableElementProps( + elementOptions, + model.tableStyle, + ) + + createFeedCommitTracking(feed.state.quotes, feed.completeRender) + createTableAutoFit(model.table, scrollElement) + + return ( + <> +
{ + setScrollElement(element) + }} + > + + + +
+
+ + + ) +} diff --git a/examples/solid/realtime-trading/src/vite-env.d.ts b/examples/solid/realtime-trading/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/solid/realtime-trading/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/solid/realtime-trading/tests/e2e/smoke.spec.ts b/examples/solid/realtime-trading/tests/e2e/smoke.spec.ts new file mode 100644 index 0000000000..1a6c2a43a7 --- /dev/null +++ b/examples/solid/realtime-trading/tests/e2e/smoke.spec.ts @@ -0,0 +1,213 @@ +import path from 'node:path' +import { expect, test } from '@playwright/test' +import { startExampleServer } from '../../../../../tests/e2e/helpers/startExampleServer' +import { + setRangeValue, + scrollTradingTable, +} from '../../../../../tests/e2e/helpers/setRangeValue' +import type { Page } from '@playwright/test' + +const exampleDir = path.resolve() + +function collectPageErrors(page: Page) { + const errors: Array = [] + page.on('pageerror', (error) => errors.push(error.message)) + page.on('console', (message) => { + if (message.type() === 'error') errors.push(message.text()) + }) + return errors +} + +test('runs the Solid realtime trading workload', async ({ page }) => { + test.setTimeout(120_000) + const server = await startExampleServer(exampleDir) + const errors = collectPageErrors(page) + + try { + await page.goto(server.url) + + const table = page.getByTestId('trading-table') + const instrumentCount = page.getByTestId('instrument-count-select') + const virtualScrollSelect = page.getByTestId('virtual-scroll-select') + await expect(table).toBeVisible() + await expect(instrumentCount).toHaveValue('100') + await expect(page.locator('.brand')).toHaveText('MARKET MONITOR') + await expect(virtualScrollSelect).toHaveValue('none') + await expect(virtualScrollSelect).toBeEnabled() + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(table.locator('tbody')).toHaveCSS('user-select', 'none') + const livePrice = table.locator('tbody tr').first().locator('td').nth(3) + const initialPrice = await livePrice.textContent() + await expect.poll(() => livePrice.textContent()).not.toBe(initialPrice) + await expect(table.locator('tbody tr').first()).toHaveCSS( + 'content-visibility', + 'auto', + ) + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await instrumentCount.selectOption('250') + await expect(virtualScrollSelect).toHaveValue('tanstack') + await expect(virtualScrollSelect).toBeEnabled() + await expect.poll(() => table.locator('tbody tr').count()).toBeLessThan(250) + await expect(page.getByTestId('virtual-scroll-footer')).toBeVisible() + await instrumentCount.selectOption('100') + await expect(virtualScrollSelect).toHaveValue('none') + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await virtualScrollSelect.selectOption('tanstack') + await expect.poll(() => table.locator('tbody tr').count()).toBeLessThan(100) + await expect(table.locator('tbody tr').first()).toHaveCSS( + 'content-visibility', + 'auto', + ) + await expect(page.getByTestId('virtual-scroll-footer')).toBeVisible() + await virtualScrollSelect.selectOption('none') + await expect(table.locator('tbody tr')).toHaveCount(100) + await instrumentCount.selectOption('1500') + await expect(virtualScrollSelect).toHaveValue('tanstack') + await expect(virtualScrollSelect).toBeDisabled() + await expect + .poll(() => table.locator('tbody tr').count()) + .toBeLessThan(1500) + await expect(page.getByTestId('virtual-scroll-footer')).toContainText( + 'Total · 1500 rows · 14 columns', + ) + await expect(page.getByTestId('visible-row-range')).toHaveText( + /^\s*Current · rows 0\.\.\d+\s*$/, + ) + await scrollTradingTable(page, 2_000) + await expect + .poll(async () => + Number( + await table + .locator('tbody tr') + .first() + .getAttribute('data-virtual-index'), + ), + ) + .toBeGreaterThan(0) + await expect(page.getByTestId('visible-row-range')).toHaveText( + /^\s*Current · rows [1-9]\d*\.\.\d+\s*$/, + ) + await instrumentCount.selectOption('100') + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await expect(virtualScrollSelect).toHaveValue('none') + await expect(virtualScrollSelect).toBeEnabled() + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(table.locator('thead tr')).toHaveCount(2) + await expect(table.locator('thead tr').last().locator('th')).toHaveCount(14) + await expect(table.locator('thead')).not.toContainText('Identity') + await expect(table.locator('thead')).not.toContainText('Market Data') + await expect(table.locator('thead')).toContainText('Market') + await expect(table.locator('thead')).toContainText('Bid Vol') + await expect(table.locator('thead')).toContainText('Intraday') + const selectedRow = table.locator('tbody tr').first() + const selectedSymbol = await selectedRow.getAttribute('data-symbol') + await selectedRow.locator('td').nth(1).click() + await expect(page.getByTestId('selected-instrument')).toContainText( + selectedSymbol ?? '', + ) + + await page.getByTestId('feed-toggle').click() + await expect(page.getByTestId('feed-toggle')).toHaveText('START FEED') + const dragStart = table.locator('tbody tr').nth(0).locator('td').nth(1) + const dragEnd = table.locator('tbody tr').nth(2).locator('td').nth(4) + const dragStartBox = await dragStart.boundingBox() + const dragEndBox = await dragEnd.boundingBox() + expect(dragStartBox).not.toBeNull() + expect(dragEndBox).not.toBeNull() + if (dragStartBox && dragEndBox) { + await page.mouse.move( + dragStartBox.x + dragStartBox.width / 2, + dragStartBox.y + dragStartBox.height / 2, + ) + await page.mouse.down() + await page.mouse.move( + dragEndBox.x + dragEndBox.width / 2, + dragEndBox.y + dragEndBox.height / 2, + { steps: 12 }, + ) + await page.mouse.up() + } + await expect(table.locator('td[aria-selected="true"]')).toHaveCount(12) + await expect(table.locator('td[data-cell-focused="true"]')).toHaveCount(1) + await expect(table.locator('td[data-selection-top="true"]')).toHaveCount(4) + await expect(table.locator('td[data-selection-right="true"]')).toHaveCount( + 3, + ) + await expect(table.locator('td[data-selection-bottom="true"]')).toHaveCount( + 4, + ) + await expect(table.locator('td[data-selection-left="true"]')).toHaveCount(3) + await page.getByTestId('feed-toggle').click() + + await expect(page.getByTestId('feed-status')).toHaveText('FEED LIVE') + await expect(instrumentCount.locator('option[value="150"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="350"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="750"]')).toHaveCount(1) + + const targetRateSlider = page.getByTestId('target-rate-slider') + await expect(targetRateSlider).toHaveAttribute('min', '0') + await expect(targetRateSlider).toHaveAttribute('max', '9') + await expect(targetRateSlider).toHaveAttribute('step', '1') + await expect(targetRateSlider).toHaveValue('6') + await setRangeValue(targetRateSlider, '7') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '25K samples/s', + ) + await setRangeValue(targetRateSlider, '8') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '50K samples/s', + ) + await setRangeValue(targetRateSlider, '6') + + const sparklineInterval = page.getByTestId( + 'sparkline-sample-interval-select', + ) + await expect(sparklineInterval).toHaveValue('16') + await sparklineInterval.selectOption('100') + await expect(sparklineInterval).toHaveValue('100') + await sparklineInterval.selectOption('16') + + const publishInterval = page.getByTestId('publish-interval-select') + await expect(publishInterval.locator('option[value="500"]')).toHaveCount(1) + await expect(publishInterval.locator('option[value="1000"]')).toHaveCount(1) + + await expect + .poll(async () => { + const text = await page.getByTestId('row-update-rate').textContent() + return Number(text?.replace(/\D/g, '') ?? 0) + }) + .toBeGreaterThan(0) + await expect + .poll(async () => { + const text = await page.getByTestId('worker-messages').textContent() + return Number(text?.replace(/\D/g, '') ?? 0) + }) + .toBeGreaterThan(0) + await expect + .poll(async () => + Number(await page.getByTestId('message-rate').textContent()), + ) + .toBeGreaterThan(0) + await expect + .poll(async () => + Number(await page.getByTestId('table-render-rate').textContent()), + ) + .toBeGreaterThan(0) + + const firstPrice = page.locator('tbody tr').first().getByRole('button') + const priceBeforeUpdate = await firstPrice.textContent() + await expect + .poll(() => firstPrice.textContent()) + .not.toBe(priceBeforeUpdate) + + await page.locator('.config-section input[type="checkbox"]').first().check() + await page.getByTestId('feed-toggle').click() + await expect(page.getByTestId('feed-toggle')).toHaveText('START FEED') + await expect(page.getByTestId('feed-status')).toHaveText('FEED PAUSED') + + expect(errors).toEqual([]) + } finally { + await server.close() + } +}) diff --git a/examples/solid/realtime-trading/tsconfig.json b/examples/solid/realtime-trading/tsconfig.json new file mode 100644 index 0000000000..24795ad41a --- /dev/null +++ b/examples/solid/realtime-trading/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src", "tests/e2e", "vite.config.ts"] +} diff --git a/examples/solid/realtime-trading/vite.config.ts b/examples/solid/realtime-trading/vite.config.ts new file mode 100644 index 0000000000..7352cff5df --- /dev/null +++ b/examples/solid/realtime-trading/vite.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'vite' +import solidPlugin from 'vite-plugin-solid' + +export default defineConfig({ + server: { + port: 7777, + allowedHosts: true, + }, + plugins: [solidPlugin()], + build: { + target: 'esnext', + }, +}) diff --git a/examples/solid/row-pinning/package.json b/examples/solid/row-pinning/package.json index 7c4a1e03c5..5b4a976956 100644 --- a/examples/solid/row-pinning/package.json +++ b/examples/solid/row-pinning/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/row-selection/package.json b/examples/solid/row-selection/package.json index eb8e9d3e59..94db75791d 100644 --- a/examples/solid/row-selection/package.json +++ b/examples/solid/row-selection/package.json @@ -13,15 +13,16 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { - "@tanstack/solid-devtools": "^0.8.10", + "@tanstack/solid-devtools": "^0.8.12", "@tanstack/solid-table": "^9.2.3", "@tanstack/solid-table-devtools": "^9.2.0", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/sorting/package.json b/examples/solid/sorting/package.json index c4a49d6934..067d3f0524 100644 --- a/examples/solid/sorting/package.json +++ b/examples/solid/sorting/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/spreadsheet/package.json b/examples/solid/spreadsheet/package.json index de282e4c6e..184f0093b8 100644 --- a/examples/solid/spreadsheet/package.json +++ b/examples/solid/spreadsheet/package.json @@ -12,15 +12,16 @@ "test:types": "tsc --noEmit" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/solid-hotkeys": "^0.10.0", "@tanstack/solid-table": "^9.2.3", - "@tanstack/solid-virtual": "^3.13.36", - "solid-js": "^1.9.14" + "@tanstack/solid-virtual": "^3.13.37", + "solid-js": "^1.9.15" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" } } diff --git a/examples/solid/sub-components/package.json b/examples/solid/sub-components/package.json index 2401d849af..aa735e6c48 100644 --- a/examples/solid/sub-components/package.json +++ b/examples/solid/sub-components/package.json @@ -13,13 +13,14 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-table": "^9.2.3", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/virtualized-columns/package.json b/examples/solid/virtualized-columns/package.json index 29b9aa5ffe..32deb8cd9d 100644 --- a/examples/solid/virtualized-columns/package.json +++ b/examples/solid/virtualized-columns/package.json @@ -13,14 +13,15 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-table": "^9.2.3", - "@tanstack/solid-virtual": "^3.13.36", - "solid-js": "^1.9.14" + "@tanstack/solid-virtual": "^3.13.37", + "solid-js": "^1.9.15" } } diff --git a/examples/solid/virtualized-infinite-scrolling/package.json b/examples/solid/virtualized-infinite-scrolling/package.json index 2e6bc2afda..c6c2057ba4 100644 --- a/examples/solid/virtualized-infinite-scrolling/package.json +++ b/examples/solid/virtualized-infinite-scrolling/package.json @@ -13,16 +13,17 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-query": "^5.101.4", "@tanstack/solid-store": "^0.11.1", "@tanstack/solid-table": "^9.2.3", - "@tanstack/solid-virtual": "^3.13.36", - "solid-js": "^1.9.14" + "@tanstack/solid-virtual": "^3.13.37", + "solid-js": "^1.9.15" } } diff --git a/examples/solid/virtualized-rows/package.json b/examples/solid/virtualized-rows/package.json index 1cd654b4df..c6d986d598 100644 --- a/examples/solid/virtualized-rows/package.json +++ b/examples/solid/virtualized-rows/package.json @@ -13,14 +13,15 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { "@tanstack/solid-table": "^9.2.3", - "@tanstack/solid-virtual": "^3.13.36", - "solid-js": "^1.9.14" + "@tanstack/solid-virtual": "^3.13.37", + "solid-js": "^1.9.15" } } diff --git a/examples/solid/with-tanstack-form/package.json b/examples/solid/with-tanstack-form/package.json index cca65186fc..bf34b3b2ce 100644 --- a/examples/solid/with-tanstack-form/package.json +++ b/examples/solid/with-tanstack-form/package.json @@ -13,18 +13,19 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { - "@tanstack/solid-devtools": "^0.8.10", + "@tanstack/solid-devtools": "^0.8.12", "@tanstack/solid-form": "^1.33.5", "@tanstack/solid-form-devtools": "^0.2.34", "@tanstack/solid-table": "^9.2.3", "@tanstack/solid-table-devtools": "^9.2.0", - "solid-js": "^1.9.14", + "solid-js": "^1.9.15", "zod": "^4.4.3" } } diff --git a/examples/solid/with-tanstack-query/package.json b/examples/solid/with-tanstack-query/package.json index 1d3106a0c1..0e6a1090a0 100644 --- a/examples/solid/with-tanstack-query/package.json +++ b/examples/solid/with-tanstack-query/package.json @@ -13,17 +13,18 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { - "@tanstack/solid-devtools": "^0.8.10", + "@tanstack/solid-devtools": "^0.8.12", "@tanstack/solid-query": "^5.101.4", "@tanstack/solid-query-devtools": "^5.101.4", "@tanstack/solid-table": "^9.2.3", "@tanstack/solid-table-devtools": "^9.2.0", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/solid/with-tanstack-router/package.json b/examples/solid/with-tanstack-router/package.json index 535ba08732..321468e4c2 100644 --- a/examples/solid/with-tanstack-router/package.json +++ b/examples/solid/with-tanstack-router/package.json @@ -13,22 +13,23 @@ }, "license": "MIT", "devDependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/router-vite-plugin": "^1.167.30", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", + "@tanstack/router-vite-plugin": "^1.167.35", "typescript": "6.0.3", - "vite": "^8.2.1", + "vite": "^8.2.2", "vite-plugin-solid": "^2.11.14" }, "dependencies": { - "@tanstack/solid-devtools": "^0.8.10", + "@tanstack/solid-devtools": "^0.8.12", "@tanstack/solid-pacer": "^0.22.0", "@tanstack/solid-pacer-devtools": "0.7.0", "@tanstack/solid-query": "^5.101.4", "@tanstack/solid-query-devtools": "^5.101.4", - "@tanstack/solid-router": "^1.170.25", + "@tanstack/solid-router": "^1.170.30", "@tanstack/solid-router-devtools": "^1.167.1", "@tanstack/solid-table": "^9.2.3", "@tanstack/solid-table-devtools": "^9.2.0", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" } } diff --git a/examples/svelte/aggregation/package.json b/examples/svelte/aggregation/package.json index 3604995b1c..4774267e7e 100644 --- a/examples/svelte/aggregation/package.json +++ b/examples/svelte/aggregation/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/basic-app-table/package.json b/examples/svelte/basic-app-table/package.json index 730bac69eb..88deb8be38 100644 --- a/examples/svelte/basic-app-table/package.json +++ b/examples/svelte/basic-app-table/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/basic-create-table/package.json b/examples/svelte/basic-create-table/package.json index 0ad49a87c6..7617d20ca6 100644 --- a/examples/svelte/basic-create-table/package.json +++ b/examples/svelte/basic-create-table/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/basic-dynamic-columns/package.json b/examples/svelte/basic-dynamic-columns/package.json index 417e35d526..7cbe95085d 100644 --- a/examples/svelte/basic-dynamic-columns/package.json +++ b/examples/svelte/basic-dynamic-columns/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/basic-external-atoms/package.json b/examples/svelte/basic-external-atoms/package.json index 75517bebb7..aecb7db685 100644 --- a/examples/svelte/basic-external-atoms/package.json +++ b/examples/svelte/basic-external-atoms/package.json @@ -14,14 +14,15 @@ "@tanstack/svelte-store": "^0.12.1" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/basic-external-state/package.json b/examples/svelte/basic-external-state/package.json index b05a347c3f..c2b6cd6996 100644 --- a/examples/svelte/basic-external-state/package.json +++ b/examples/svelte/basic-external-state/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/basic-snippets/package.json b/examples/svelte/basic-snippets/package.json index e7a574c1f5..fd99c0307e 100644 --- a/examples/svelte/basic-snippets/package.json +++ b/examples/svelte/basic-snippets/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/cell-selection/package.json b/examples/svelte/cell-selection/package.json index b5a287fc17..17436a29aa 100644 --- a/examples/svelte/cell-selection/package.json +++ b/examples/svelte/cell-selection/package.json @@ -11,15 +11,16 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-hotkeys": "^0.10.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/cell-spanning/package.json b/examples/svelte/cell-spanning/package.json index d779cce0ab..2243ec6bd9 100644 --- a/examples/svelte/cell-spanning/package.json +++ b/examples/svelte/cell-spanning/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/column-ordering/package.json b/examples/svelte/column-ordering/package.json index 71666d093e..e919a7bb16 100644 --- a/examples/svelte/column-ordering/package.json +++ b/examples/svelte/column-ordering/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/column-pinning-split/package.json b/examples/svelte/column-pinning-split/package.json index 8d49b58c40..568aa0e55e 100644 --- a/examples/svelte/column-pinning-split/package.json +++ b/examples/svelte/column-pinning-split/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/column-pinning-sticky/package.json b/examples/svelte/column-pinning-sticky/package.json index 6bddc86031..b725dabbd6 100644 --- a/examples/svelte/column-pinning-sticky/package.json +++ b/examples/svelte/column-pinning-sticky/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/column-pinning/package.json b/examples/svelte/column-pinning/package.json index 0ca9dfe6a8..dbb244560a 100644 --- a/examples/svelte/column-pinning/package.json +++ b/examples/svelte/column-pinning/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/column-resizing-performant/package.json b/examples/svelte/column-resizing-performant/package.json index 1f27e1e405..6f1a6d6f55 100644 --- a/examples/svelte/column-resizing-performant/package.json +++ b/examples/svelte/column-resizing-performant/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/column-resizing/package.json b/examples/svelte/column-resizing/package.json index a709b67317..578f81ddd2 100644 --- a/examples/svelte/column-resizing/package.json +++ b/examples/svelte/column-resizing/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/column-sizing/package.json b/examples/svelte/column-sizing/package.json index d0ecaa7d4a..7e7969b3ab 100644 --- a/examples/svelte/column-sizing/package.json +++ b/examples/svelte/column-sizing/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/column-visibility/package.json b/examples/svelte/column-visibility/package.json index b91f03250d..263cb15566 100644 --- a/examples/svelte/column-visibility/package.json +++ b/examples/svelte/column-visibility/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/composable-tables/package.json b/examples/svelte/composable-tables/package.json index 30f498b446..b6f6699745 100644 --- a/examples/svelte/composable-tables/package.json +++ b/examples/svelte/composable-tables/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/expanding/package.json b/examples/svelte/expanding/package.json index 782c91cc6a..0dcdc3d828 100644 --- a/examples/svelte/expanding/package.json +++ b/examples/svelte/expanding/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/filtering/package.json b/examples/svelte/filtering/package.json index 7267f41b92..c7adeaba32 100644 --- a/examples/svelte/filtering/package.json +++ b/examples/svelte/filtering/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/filters-faceted-bucketed/package.json b/examples/svelte/filters-faceted-bucketed/package.json index 62d5f8d787..5a34a8f894 100644 --- a/examples/svelte/filters-faceted-bucketed/package.json +++ b/examples/svelte/filters-faceted-bucketed/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/filters-faceted/package.json b/examples/svelte/filters-faceted/package.json index 88b8dd4f7c..532e40ab05 100644 --- a/examples/svelte/filters-faceted/package.json +++ b/examples/svelte/filters-faceted/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/filters-fuzzy/package.json b/examples/svelte/filters-fuzzy/package.json index a2716b1629..e798bc0d83 100644 --- a/examples/svelte/filters-fuzzy/package.json +++ b/examples/svelte/filters-fuzzy/package.json @@ -11,15 +11,16 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/grouped-aggregation/package.json b/examples/svelte/grouped-aggregation/package.json index 24d58a9081..5fa0415d68 100644 --- a/examples/svelte/grouped-aggregation/package.json +++ b/examples/svelte/grouped-aggregation/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/grouping/package.json b/examples/svelte/grouping/package.json index ffca8959b1..e675d91950 100644 --- a/examples/svelte/grouping/package.json +++ b/examples/svelte/grouping/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/header-groups/package.json b/examples/svelte/header-groups/package.json index 7b47eac425..ef98df01be 100644 --- a/examples/svelte/header-groups/package.json +++ b/examples/svelte/header-groups/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/kitchen-sink-shadcn/package.json b/examples/svelte/kitchen-sink-shadcn/package.json index 93a69f1c0f..cc3e349f53 100644 --- a/examples/svelte/kitchen-sink-shadcn/package.json +++ b/examples/svelte/kitchen-sink-shadcn/package.json @@ -15,9 +15,10 @@ "@dnd-kit-svelte/svelte": "^0.1.6", "@dnd-kit/abstract": "^0.2.3", "@dnd-kit/helpers": "^0.2.3", - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@internationalized/date": "^3.12.3", - "@lucide/svelte": "^1.31.0", + "@lucide/svelte": "^1.34.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tailwindcss/vite": "^4.3.3", @@ -26,15 +27,15 @@ "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", "@types/node": "^26.2.0", - "bits-ui": "^2.18.1", + "bits-ui": "^2.19.0", "clsx": "^2.1.1", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "tailwind-merge": "^3.6.0", "tailwind-variants": "^3.3.1", "tailwindcss": "^4.3.3", "tw-animate-css": "^1.4.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/kitchen-sink/package.json b/examples/svelte/kitchen-sink/package.json index e4b3f646ee..82d2d88439 100644 --- a/examples/svelte/kitchen-sink/package.json +++ b/examples/svelte/kitchen-sink/package.json @@ -11,15 +11,16 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/lib-shadcn/package.json b/examples/svelte/lib-shadcn/package.json index 209c8656bf..65e02d1e77 100644 --- a/examples/svelte/lib-shadcn/package.json +++ b/examples/svelte/lib-shadcn/package.json @@ -11,8 +11,9 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", - "@lucide/svelte": "^1.31.0", + "@faker-js/faker": "^10.6.0", + "@lucide/svelte": "^1.34.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tailwindcss/vite": "^4.3.3", @@ -20,15 +21,15 @@ "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", "@types/node": "^26.2.0", - "bits-ui": "^2.18.1", + "bits-ui": "^2.19.0", "clsx": "^2.1.1", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "tailwind-merge": "^3.6.0", "tailwind-variants": "^3.3.1", "tailwindcss": "^4.3.3", "tw-animate-css": "^1.4.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/pagination/package.json b/examples/svelte/pagination/package.json index 1cd65a277f..d9cf6bd56f 100644 --- a/examples/svelte/pagination/package.json +++ b/examples/svelte/pagination/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/realtime-trading/.gitignore b/examples/svelte/realtime-trading/.gitignore new file mode 100644 index 0000000000..a2ae9ce43f --- /dev/null +++ b/examples/svelte/realtime-trading/.gitignore @@ -0,0 +1,4 @@ +dist +node_modules +.svelte-kit + diff --git a/examples/svelte/realtime-trading/README.md b/examples/svelte/realtime-trading/README.md new file mode 100644 index 0000000000..191c3b2898 --- /dev/null +++ b/examples/svelte/realtime-trading/README.md @@ -0,0 +1,152 @@ +# Svelte realtime trading benchmark + +This standalone example exercises the current TanStack Svelte Table adapter +with a high-frequency worker feed, immutable market snapshots, interactive +columns, custom Svelte cells, virtual rows, and browser diagnostics. It is a +repeatable rendering workload rather than an exchange/network simulator. + +## Run and verify + +```bash +pnpm --dir examples/svelte/realtime-trading dev +``` + +Open `http://localhost:7777`. + +```bash +pnpm --dir examples/svelte/realtime-trading test:types +pnpm --dir examples/svelte/realtime-trading lint +pnpm --dir examples/svelte/realtime-trading build +pnpm --dir examples/svelte/realtime-trading test:e2e +``` + +Use a production build for performance recordings. + +## Structure and ownership + +| Path | Responsibility | +| ------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| `src/feed/` | Market model, instrument universe, feed config, immutable updates, and feed controller. | +| `src/feed/worker/` | Typed worker protocol, deterministic engine, and module worker. | +| `src/benchmark/` | Browser monitor, benchmark controller, table observer, and row-model timing. | +| `src/shell/` | Svelte context plus separate header, metrics, configurator, diagnostics, selected-instrument, and status components. | +| `src/table/table-config/` | Grouped columns and dedicated Price/Move/Percent/Sparkline Svelte components. | +| `src/table/` | Svelte Table setup, table view, delegated interactions, column layout, and Svelte Virtual integration. | +| `src/App.svelte` | Creates/provides controllers and starts/stops them with the app lifecycle. | + +The feed and benchmark are separate controllers. The feed owns worker state and +quotes; the benchmark registers observers and owns metrics/view controls. +Svelte context passes those controllers without routing the quote array through +the root component. `quotes` is a dedicated high-frequency TanStack atom, and +each feed status/configuration value is a separate atom. Shell pieces subscribe +only to the atoms they display; benchmark metrics remain a coherent snapshot +store. + +## Feed and worker pipeline + +The default is 100 instruments, 10K generated samples/s, 20 ms delivery, +enabled intraday charts, and 16 ms chart sampling. + +Worker-private mutable quotes are changed by a deterministic 16 ms budget loop. +A row-indexed `Map` coalesces repeated instrument changes. An independent timer +publishes the latest unique rows at the selected cadence. Applying a message +creates a new outer array and new objects only for changed rows; untouched rows +and unsampled histories retain their references. Session IDs prevent late +messages from an old reset/row-count session from entering current state. + +- **Synthetic quote workload** is worker-side generated samples/s, not messages + or Svelte updates. +- **Worker delivery interval** controls coalesced messages; 20 ms targets around + 50 messages/s. +- **Row updates** counts unique immutable row objects applied. +- **Message samples** is the generated work represented by the latest message. + +Intraday history sampling is independent. The 25K burst deliberately publishes +one heavy batch. This resembles an upstream stream but excludes network delay. + +## Svelte table architecture + +The 14 leaf columns are grouped into Instrument, Price & Change, Order Book, +Session, and Chart. Sorting/filtering, on-change resizing, double-click reset, +drag column ordering, row selection, drag cell ranges, keyboard navigation, +CSS-only hover, and component-based quote cells are included. + +`TradingTable.svelte` owns the view, while `trading-table.ts` and +`table-config/` isolate table construction and columns. Stable instrument IDs +back row identity. The custom quote components make component executions and +lifecycle churn measurable; the A/B move mode intentionally changes component +type and is not the normal rendering baseline. + +Selection uses one delegated body-level interaction controller and resolves +cells from `composedPath()` plus data attributes. Column dimensions are CSS +custom properties updated only for sizing/order. A `ResizeObserver` performs +initial fitting and yields after the user resizes. + +## Virtualization + +- Below 200 rows, automatic mode chooses Full DOM, but Virtual can be enabled. +- From 200 through 1,499 rows, automatic mode chooses TanStack Virtual and Full + DOM remains selectable. +- At 1,500 rows or more, Virtual is forced and the control is disabled. + +Svelte Virtual uses a 32 px estimate, 10-row overscan, row IDs for item keys, +transformed rows, and a spacer body. The virtualizer range feeds the current-row +footer. Both modes use `content-visibility: auto`; Full DOM still creates every +Svelte row/cell even if the browser skips offscreen paint/layout work. + +## Performance decisions + +- worker generation and pre-message coalescing; +- immutable structural sharing for unchanged rows/history; +- controller context instead of root-level data prop drilling; +- stable keyed row identity; +- table/config/cell component boundaries with localized atom/store reads; +- delegated pointer selection and CSS hover; +- CSS variables for column width propagation; +- configurable chart frequency and opt-in component churn; +- virtual mounting for larger row sets; +- low-frequency metric publication relative to feed updates. + +Publishing immutable state necessarily changes the outer array. Stable inner +references reduce downstream work, but sorting/filtering can still require a +new table row-model pass. + +## Diagnostics and interpretation + +The sidebar starts with four cross-framework health signals: estimated rAF +callbacks/s over one second, average snapshot-to-DOM-commit latency over three +seconds, long animation frames accumulated since reset, and throughput as +changed rows/s plus applied snapshots/s. “Changed rows” is deduplicated within +each snapshot; the same instrument can count again in a later snapshot. The +advanced diagnostics retain worker samples/messages, DOM commits, a rolling +10-second p95/max commit latency, slow commits, lifecycle/execution rates, +row-model timing, DOM mutation records, and optional heap information. + +The frame figure is deliberately labeled estimated: it counts this page's rAF +callbacks, is capped by the display refresh rate, and falls when a tab is +throttled. It is a portable responsiveness signal, not compositor-presented +FPS. + +Svelte waits for `tick()` before closing a pending DOM-commit measurement. User +Timing entries for commits and row-model work are sampled at one in 20 calls; +the in-memory counters and latency windows still measure every call. + +Renderer callbacks and DOM mutations measure different layers. Heap growth is +not automatically a leak; verify retained objects after GC. The heap value is +Chromium-only and GC-sensitive, not retained size. The DOM rate counts +`MutationRecord` objects rather than browser operations, and records may be +coalesced; the observer watches text/child changes plus only `class`/`style` +attributes to reduce its own overhead. Non-feed text/child changes and +interaction-driven `class`/`style` changes (including virtual scrolling) are +included, so this is not a feed-only rate. Use identical production settings, +Chrome Performance, and Svelte DevTools when comparing runs. + +## Standalone policy + +This directory deliberately contains copies of the feed, worker, instruments, +benchmark, shell, styles, and table code. It can run independently or be copied +to StackBlitz, so shared code and README sections are repeated across adapters +by design. + +The workspace resolves the pinned `@tanstack/svelte-table` dependency to the +local adapter package while preserving a release-like manifest. diff --git a/examples/svelte/realtime-trading/index.html b/examples/svelte/realtime-trading/index.html new file mode 100644 index 0000000000..fa207c8adc --- /dev/null +++ b/examples/svelte/realtime-trading/index.html @@ -0,0 +1,2 @@ +
+ diff --git a/examples/svelte/realtime-trading/package.json b/examples/svelte/realtime-trading/package.json new file mode 100644 index 0000000000..a4ab579a33 --- /dev/null +++ b/examples/svelte/realtime-trading/package.json @@ -0,0 +1,29 @@ +{ + "name": "tanstack-svelte-table-example-realtime-trading", + "private": true, + "type": "module", + "scripts": { + "start": "vite", + "dev": "vite", + "build": "vite build", + "serve": "vite preview", + "lint": "eslint ./src", + "test:types": "svelte-check --tsconfig ./tsconfig.json", + "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" + }, + "dependencies": { + "@tanstack/store": "^0.11.1", + "@tanstack/svelte-store": "^0.12.1", + "@tanstack/svelte-table": "^9.2.3", + "@tanstack/svelte-virtual": "^3.13.36", + "svelte": "^5.56.10" + }, + "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", + "@sveltejs/vite-plugin-svelte": "^7.3.0", + "@tsconfig/svelte": "^5.0.8", + "svelte-check": "^4.7.6", + "typescript": "6.0.3", + "vite": "^8.2.2" + } +} diff --git a/examples/svelte/realtime-trading/src/App.svelte b/examples/svelte/realtime-trading/src/App.svelte new file mode 100644 index 0000000000..2464cea6b1 --- /dev/null +++ b/examples/svelte/realtime-trading/src/App.svelte @@ -0,0 +1,20 @@ + + + diff --git a/examples/svelte/realtime-trading/src/benchmark/benchmark-monitor.ts b/examples/svelte/realtime-trading/src/benchmark/benchmark-monitor.ts new file mode 100644 index 0000000000..8c3fb49821 --- /dev/null +++ b/examples/svelte/realtime-trading/src/benchmark/benchmark-monitor.ts @@ -0,0 +1,434 @@ +import { + quoteCellLifecycle, + quoteRenderDiagnostics, +} from '../table/table-config/quote-cells' +import { rowModelDiagnostics } from '../table/trading-table' + +export interface NamedInvocationRate { + name: string + callsPerSecond: number +} + +interface TimedLatencySample { + recordedAt: number + duration: number +} + +const averageLatencyWindowMs = 3_000 +const percentileLatencyWindowMs = 10_000 +const frameRateWindowMs = 1_000 + +export interface FeedMetrics { + actualTicksPerSecond: number + rowUpdatesPerSecond: number + workerMessagesPerSecond: number + stateApplicationsPerSecond: number + supersededUpdatesPerSecond: number + totalTicks: number + rafCallbacksPerSecond: number + tableCommitsPerSecond: number + lastBatchSize: number + averageCommitLatencyMs: number + p95CommitLatencyMs: number + maxCommitLatencyMs: number + slowCommits: number + longAnimationFrames: number + worstLongAnimationFrameMs: number + heapMb: number | null + componentsCreated: number + componentsDestroyed: number + workerMessages: number + lastUpdateCount: number + cellRendererCallsPerSecond: number + componentRenderCallsPerSecond: number + cellRendererRates: ReadonlyArray + componentRenderRates: ReadonlyArray + domMutationsPerSecond: number + rowModelCallsPerSecond: number + rowModelAverageMs: number + rowModelMaxMs: number + visibleRows: number +} + +export const initialMetrics: FeedMetrics = { + actualTicksPerSecond: 0, + rowUpdatesPerSecond: 0, + workerMessagesPerSecond: 0, + stateApplicationsPerSecond: 0, + supersededUpdatesPerSecond: 0, + totalTicks: 0, + rafCallbacksPerSecond: 0, + tableCommitsPerSecond: 0, + lastBatchSize: 0, + averageCommitLatencyMs: 0, + p95CommitLatencyMs: 0, + maxCommitLatencyMs: 0, + slowCommits: 0, + longAnimationFrames: 0, + worstLongAnimationFrameMs: 0, + heapMb: null, + componentsCreated: 0, + componentsDestroyed: 0, + workerMessages: 0, + lastUpdateCount: 0, + cellRendererCallsPerSecond: 0, + componentRenderCallsPerSecond: 0, + cellRendererRates: [], + componentRenderRates: [], + domMutationsPerSecond: 0, + rowModelCallsPerSecond: 0, + rowModelAverageMs: 0, + rowModelMaxMs: 0, + visibleRows: 0, +} + +const userTiming = { entryCount: 0, measureCalls: 0 } + +export function recordMeasure( + name: string, + start: number, + end: number, + detail: Record, +): void { + userTiming.measureCalls++ + if (userTiming.measureCalls % 20 !== 0) return + try { + performance.measure(name, { start, end, detail }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMeasures('market-update-to-dom-commit') + } + } catch { + // User Timing Level 3 options are not implemented in every browser. + } +} + +export function markBenchmarkAction( + name: string, + detail: Record = {}, +): void { + try { + performance.mark(`benchmark:${name}`, { detail }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMarks() + } + } catch { + // User Timing Level 3 detail is not implemented in every browser. + } +} + +export class BenchmarkMonitor { + readonly #runtime = { + sampleStartedAt: performance.now(), + sessionStartedAt: performance.now(), + pendingMutationStartedAt: null as number | null, + commitLatencySamples: [] as Array, + slowCommitCount: 0, + totalTicks: 0, + ticksInSample: 0, + rowUpdatesInSample: 0, + workerMessagesInSample: 0, + stateApplicationsInSample: 0, + supersededUpdatesInSample: 0, + lastBatchSize: 0, + lastUpdateCount: 0, + workerMessages: 0, + frameTrackingStartedAt: performance.now(), + frameTimestamps: [] as Array, + tableCommitsInSample: 0, + longAnimationFrameCount: 0, + worstLongAnimationFrameMs: 0, + previousCellRendererCalls: 0, + previousComponentRenderCalls: 0, + previousCellRendererCallsByName: { + ...quoteRenderDiagnostics.cellRendererCallsByName, + }, + previousComponentRenderCallsByName: { + ...quoteRenderDiagnostics.componentRenderCallsByName, + }, + domMutationsInSample: 0, + previousRowModelCalls: 0, + previousRowModelDuration: 0, + } + + markCommitPending(): void { + this.#runtime.pendingMutationStartedAt ??= performance.now() + } + + recordDomCommit(): void { + const runtime = this.#runtime + if (runtime.pendingMutationStartedAt !== null) { + const commitEndedAt = performance.now() + const duration = commitEndedAt - runtime.pendingMutationStartedAt + runtime.commitLatencySamples.push({ + recordedAt: commitEndedAt, + duration, + }) + if (duration > 16.7) runtime.slowCommitCount++ + recordMeasure( + 'market-update-to-dom-commit', + runtime.pendingMutationStartedAt, + commitEndedAt, + {}, + ) + runtime.pendingMutationStartedAt = null + runtime.tableCommitsInSample++ + } + } + + recordWorkerMessage(): void { + this.#runtime.workerMessages++ + this.#runtime.workerMessagesInSample++ + } + + recordBatch( + tickCount: number, + updateCount: number, + supersededUpdateCount: number, + ): void { + const runtime = this.#runtime + runtime.lastBatchSize = tickCount + runtime.lastUpdateCount = updateCount + runtime.ticksInSample += tickCount + runtime.totalTicks += tickCount + runtime.rowUpdatesInSample += updateCount + runtime.stateApplicationsInSample++ + runtime.supersededUpdatesInSample += supersededUpdateCount + } + + recordAnimationFrame(now: number): void { + const timestamps = this.#runtime.frameTimestamps + timestamps.push(now) + pruneFrameTimestamps(timestamps, now) + } + + recordLongAnimationFrame(duration: number, startTime: number): void { + const runtime = this.#runtime + if (startTime < runtime.sessionStartedAt) return + runtime.longAnimationFrameCount++ + runtime.worstLongAnimationFrameMs = Math.max( + runtime.worstLongAnimationFrameMs, + duration, + ) + } + + recordDomMutations(count: number): void { + this.#runtime.domMutationsInSample += count + } + + resetDomMutations(): void { + this.#runtime.domMutationsInSample = 0 + } + + shouldPublish(now: number): boolean { + return now - this.#runtime.sampleStartedAt >= 500 + } + + publish(now: number): FeedMetrics { + const runtime = this.#runtime + const sampleDuration = now - runtime.sampleStartedAt + pruneLatencySamples(runtime.commitLatencySamples, now) + pruneFrameTimestamps(runtime.frameTimestamps, now) + const averageCommitLatencySamples = runtime.commitLatencySamples + .filter((sample) => sample.recordedAt >= now - averageLatencyWindowMs) + .map((sample) => sample.duration) + const percentileCommitLatencySamples = runtime.commitLatencySamples.map( + (sample) => sample.duration, + ) + const sortedCommitLatencySamples = [...percentileCommitLatencySamples].sort( + (left, right) => left - right, + ) + const rowModelCalls = + rowModelDiagnostics.calls - runtime.previousRowModelCalls + const rowModelDuration = + rowModelDiagnostics.totalDurationMs - runtime.previousRowModelDuration + const cellRendererCalls = + quoteRenderDiagnostics.cellRendererCalls - + runtime.previousCellRendererCalls + const componentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls - + runtime.previousComponentRenderCalls + const cellRendererRates = calculateInvocationRates( + quoteRenderDiagnostics.cellRendererCallsByName, + runtime.previousCellRendererCallsByName, + sampleDuration, + ) + const componentRenderRates = calculateInvocationRates( + quoteRenderDiagnostics.componentRenderCallsByName, + runtime.previousComponentRenderCallsByName, + sampleDuration, + ) + const averageCommitLatencyMs = + averageCommitLatencySamples.length === 0 + ? 0 + : averageCommitLatencySamples.reduce((sum, value) => sum + value, 0) / + averageCommitLatencySamples.length + const p95Index = Math.max( + 0, + Math.ceil(sortedCommitLatencySamples.length * 0.95) - 1, + ) + const metrics: FeedMetrics = { + actualTicksPerSecond: + sampleDuration === 0 + ? 0 + : (runtime.ticksInSample / sampleDuration) * 1_000, + rowUpdatesPerSecond: + (runtime.rowUpdatesInSample / sampleDuration) * 1_000, + workerMessagesPerSecond: + (runtime.workerMessagesInSample / sampleDuration) * 1_000, + stateApplicationsPerSecond: + (runtime.stateApplicationsInSample / sampleDuration) * 1_000, + supersededUpdatesPerSecond: + (runtime.supersededUpdatesInSample / sampleDuration) * 1_000, + totalTicks: runtime.totalTicks, + rafCallbacksPerSecond: calculateFrameRate( + runtime.frameTimestamps, + runtime.frameTrackingStartedAt, + now, + ), + tableCommitsPerSecond: + (runtime.tableCommitsInSample / sampleDuration) * 1_000, + lastBatchSize: runtime.lastBatchSize, + averageCommitLatencyMs, + p95CommitLatencyMs: sortedCommitLatencySamples[p95Index] ?? 0, + maxCommitLatencyMs: sortedCommitLatencySamples.at(-1) ?? 0, + slowCommits: runtime.slowCommitCount, + longAnimationFrames: runtime.longAnimationFrameCount, + worstLongAnimationFrameMs: runtime.worstLongAnimationFrameMs, + heapMb: readHeapSizeMb(), + componentsCreated: quoteCellLifecycle.created, + componentsDestroyed: quoteCellLifecycle.destroyed, + workerMessages: runtime.workerMessages, + lastUpdateCount: runtime.lastUpdateCount, + cellRendererCallsPerSecond: (cellRendererCalls / sampleDuration) * 1_000, + componentRenderCallsPerSecond: + (componentRenderCalls / sampleDuration) * 1_000, + cellRendererRates, + componentRenderRates, + domMutationsPerSecond: + (runtime.domMutationsInSample / sampleDuration) * 1_000, + rowModelCallsPerSecond: (rowModelCalls / sampleDuration) * 1_000, + rowModelAverageMs: + rowModelCalls === 0 ? 0 : rowModelDuration / rowModelCalls, + rowModelMaxMs: rowModelDiagnostics.maxDurationMs, + visibleRows: rowModelDiagnostics.lastRowCount, + } + + runtime.sampleStartedAt = now + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.previousRowModelCalls = rowModelDiagnostics.calls + runtime.previousRowModelDuration = rowModelDiagnostics.totalDurationMs + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.tableCommitsInSample = 0 + return metrics + } + + reset(): void { + const runtime = this.#runtime + runtime.sampleStartedAt = performance.now() + runtime.sessionStartedAt = runtime.sampleStartedAt + runtime.pendingMutationStartedAt = null + runtime.commitLatencySamples = [] + runtime.slowCommitCount = 0 + runtime.totalTicks = 0 + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.lastBatchSize = 0 + runtime.lastUpdateCount = 0 + runtime.workerMessages = 0 + runtime.frameTrackingStartedAt = runtime.sampleStartedAt + runtime.frameTimestamps = [] + runtime.tableCommitsInSample = 0 + runtime.longAnimationFrameCount = 0 + runtime.worstLongAnimationFrameMs = 0 + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.previousRowModelCalls = rowModelDiagnostics.calls + runtime.previousRowModelDuration = rowModelDiagnostics.totalDurationMs + rowModelDiagnostics.maxDurationMs = 0 + } +} + +export const longAnimationFramesSupported = + PerformanceObserver.supportedEntryTypes.includes('long-animation-frame') + +function readHeapSizeMb(): number | null { + const memory = ( + performance as Performance & { + memory?: { usedJSHeapSize: number } + } + ).memory + return memory ? memory.usedJSHeapSize / 1_048_576 : null +} + +function calculateInvocationRates( + current: Record, + previous: Record, + sampleDuration: number, +): ReadonlyArray { + return Object.entries(current).map(([name, calls]) => ({ + name, + callsPerSecond: + sampleDuration === 0 + ? 0 + : ((calls - (previous[name] ?? 0)) / sampleDuration) * 1_000, + })) +} + +function pruneLatencySamples( + samples: Array, + now: number, +): void { + const cutoff = now - percentileLatencyWindowMs + const firstRetainedIndex = samples.findIndex( + (sample) => sample.recordedAt >= cutoff, + ) + if (firstRetainedIndex > 0) samples.splice(0, firstRetainedIndex) + else if (firstRetainedIndex === -1) samples.length = 0 +} + +function pruneFrameTimestamps(timestamps: Array, now: number): void { + const cutoff = now - frameRateWindowMs + const firstRetainedIndex = timestamps.findIndex( + (timestamp) => timestamp >= cutoff, + ) + if (firstRetainedIndex > 0) timestamps.splice(0, firstRetainedIndex) + else if (firstRetainedIndex === -1) timestamps.length = 0 +} + +function calculateFrameRate( + timestamps: ReadonlyArray, + trackingStartedAt: number, + now: number, +): number { + const observedWindowMs = Math.min( + frameRateWindowMs, + Math.max(1, now - trackingStartedAt), + ) + return (timestamps.length / observedWindowMs) * 1_000 +} diff --git a/examples/svelte/realtime-trading/src/benchmark/table-benchmark.ts b/examples/svelte/realtime-trading/src/benchmark/table-benchmark.ts new file mode 100644 index 0000000000..346a6cdc0c --- /dev/null +++ b/examples/svelte/realtime-trading/src/benchmark/table-benchmark.ts @@ -0,0 +1,23 @@ +import type { TradingBenchmarkController } from './trading-benchmark-controller' + +export function startTableBenchmark( + controller: TradingBenchmarkController, +): () => void { + const tableBody = document.querySelector( + '.market-panel [data-trading-table] tbody', + ) + if (!tableBody) return () => undefined + + controller.monitor.resetDomMutations() + const observer = new MutationObserver((records) => { + controller.monitor.recordDomMutations(records.length) + }) + observer.observe(tableBody, { + attributes: true, + attributeFilter: ['class', 'style'], + characterData: true, + childList: true, + subtree: true, + }) + return () => observer.disconnect() +} diff --git a/examples/svelte/realtime-trading/src/benchmark/trading-benchmark-controller.ts b/examples/svelte/realtime-trading/src/benchmark/trading-benchmark-controller.ts new file mode 100644 index 0000000000..bcb84f2fa8 --- /dev/null +++ b/examples/svelte/realtime-trading/src/benchmark/trading-benchmark-controller.ts @@ -0,0 +1,154 @@ +import { batch, createAtom, createStore } from '@tanstack/store' +import { TRADING_COLUMN_COUNT } from '../table/trading-table' +import { FORCED_VIRTUALIZATION_ROW_COUNT } from '../table/trading-row-virtualizer' +import { + BenchmarkMonitor, + initialMetrics, + longAnimationFramesSupported, +} from './benchmark-monitor' +import type { FeedMetrics } from './benchmark-monitor' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { RendererMode } from '../table/trading-table' +import type { VirtualScrollPreference } from '../table/trading-row-virtualizer' + +export interface TradingBenchmarkState { + requestedVirtualScrollMode: VirtualScrollPreference + metrics: FeedMetrics + mountedCells: number + liveComponents: number + longAnimationFramesSupported: boolean +} + +export interface TradingBenchmarkActions { + resetViewState: () => void + setRendererMode: (mode: RendererMode) => void + setVirtualScrollEnabled: (enabled: boolean) => void + setRenderedRowCount: (count: number) => void + selectSymbol: (symbol: string | null) => void + resetMarket: () => void +} + +const initialState: TradingBenchmarkState = { + requestedVirtualScrollMode: 'auto', + metrics: initialMetrics, + mountedCells: 0, + liveComponents: 0, + longAnimationFramesSupported, +} + +export class TradingBenchmarkController { + readonly store = createStore(initialState) + readonly renderAtoms = { + selectedSymbol: createAtom(null), + rendererMode: createAtom('stable'), + } + readonly monitor = new BenchmarkMonitor() + readonly feed: MarketFeedController + readonly actions: TradingBenchmarkActions + + readonly #runtime = { + animationFrameId: 0, + longAnimationFrameObserver: null as PerformanceObserver | null, + stopObservingFeed: null as (() => void) | null, + } + + constructor(feed: MarketFeedController) { + this.feed = feed + this.actions = { + resetViewState: () => { + this.renderAtoms.selectedSymbol.set(null) + this.#patch({ requestedVirtualScrollMode: 'auto' }) + }, + setRendererMode: (mode) => { + this.renderAtoms.rendererMode.set(mode) + }, + setVirtualScrollEnabled: (enabled) => { + if ( + this.feed.instrumentCount.get() >= FORCED_VIRTUALIZATION_ROW_COUNT + ) { + return + } + this.#patch({ + requestedVirtualScrollMode: enabled ? 'tanstack' : 'none', + }) + }, + setRenderedRowCount: (count) => { + const mountedCells = count * TRADING_COLUMN_COUNT + if (mountedCells !== this.store.get().mountedCells) { + this.#patch({ mountedCells }) + } + }, + selectSymbol: (symbol) => { + this.renderAtoms.selectedSymbol.set(symbol) + }, + resetMarket: () => { + batch(() => { + this.monitor.reset() + this.store.setState((state) => ({ + ...state, + metrics: { ...initialMetrics }, + mountedCells: 0, + liveComponents: 0, + })) + this.renderAtoms.selectedSymbol.set(null) + this.feed.actions.reset() + }) + }, + } + } + + start(): () => void { + const longAnimationFrameObserver = longAnimationFramesSupported + ? new PerformanceObserver((entries) => { + for (const entry of entries.getEntries()) { + this.monitor.recordLongAnimationFrame( + entry.duration, + entry.startTime, + ) + } + }) + : null + + this.#runtime.longAnimationFrameObserver = longAnimationFrameObserver + this.#runtime.stopObservingFeed = this.feed.observe({ + messageReceived: () => this.monitor.recordWorkerMessage(), + mutationStarted: () => this.monitor.markCommitPending(), + batchApplied: ({ tickCount, updateCount, supersededUpdateCount }) => + this.monitor.recordBatch(tickCount, updateCount, supersededUpdateCount), + renderCommitted: () => this.monitor.recordDomCommit(), + }) + longAnimationFrameObserver?.observe({ + type: 'long-animation-frame', + }) + this.#runtime.animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + + return () => this.stop() + } + + stop(): void { + cancelAnimationFrame(this.#runtime.animationFrameId) + this.#runtime.longAnimationFrameObserver?.disconnect() + this.#runtime.stopObservingFeed?.() + this.#runtime.longAnimationFrameObserver = null + this.#runtime.stopObservingFeed = null + } + + readonly #benchmarkFrame = (now: number): void => { + this.monitor.recordAnimationFrame(now) + if (this.monitor.shouldPublish(now)) { + this.#publishMetrics(this.monitor.publish(now)) + } + this.#runtime.animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + } + + #patch(patch: Partial): void { + this.store.setState((state) => ({ ...state, ...patch })) + } + + #publishMetrics(metrics: FeedMetrics): void { + this.#patch({ + metrics, + liveComponents: metrics.componentsCreated - metrics.componentsDestroyed, + }) + } +} diff --git a/examples/svelte/realtime-trading/src/feed/feed-sample-rates.ts b/examples/svelte/realtime-trading/src/feed/feed-sample-rates.ts new file mode 100644 index 0000000000..17dc2015a6 --- /dev/null +++ b/examples/svelte/realtime-trading/src/feed/feed-sample-rates.ts @@ -0,0 +1,33 @@ +export const feedSampleRateOptions = [ + { label: '100', value: 100 }, + { label: '250', value: 250 }, + { label: '500', value: 500 }, + { label: '1K', value: 1_000 }, + { label: '2.5K', value: 2_500 }, + { label: '5K', value: 5_000 }, + { label: '10K', value: 10_000 }, + { label: '25K', value: 25_000 }, + { label: '50K', value: 50_000 }, + { label: '100K', value: 100_000 }, +] as const + +export function feedSampleRateIndex(rate: number): number { + return feedSampleRateOptions.reduce((closestIndex, candidate, index) => { + const closest = feedSampleRateOptions[closestIndex] + return Math.abs(candidate.value - rate) < Math.abs(closest.value - rate) + ? index + : closestIndex + }, 0) +} + +export function feedSampleRateAt(stepIndex: number): number { + const index = Math.min( + feedSampleRateOptions.length - 1, + Math.max(0, Math.round(stepIndex)), + ) + return feedSampleRateOptions[index].value +} + +export function normalizeFeedSampleRate(rate: number): number { + return feedSampleRateAt(feedSampleRateIndex(rate)) +} diff --git a/examples/svelte/realtime-trading/src/feed/market-data.ts b/examples/svelte/realtime-trading/src/feed/market-data.ts new file mode 100644 index 0000000000..6231865d3f --- /dev/null +++ b/examples/svelte/realtime-trading/src/feed/market-data.ts @@ -0,0 +1,38 @@ +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './worker/market-feed-protocol' + +export interface MarketQuote extends Omit { + history: ReadonlyArray +} + +export function hydrateMarketQuotes( + snapshots: Array, +): Array { + return snapshots.map((quote) => ({ + ...quote, + history: [...quote.history], + })) +} + +export function applyMarketUpdates( + quotes: Array, + updates: Array, +): Array { + const nextQuotes = [...quotes] + + for (const update of updates) { + const { index, history, ...values } = update + const previousQuote = quotes.at(index) + if (!previousQuote) continue + + nextQuotes[index] = { + ...previousQuote, + ...values, + history: history ?? previousQuote.history, + } + } + + return nextQuotes +} diff --git a/examples/svelte/realtime-trading/src/feed/market-feed-config.ts b/examples/svelte/realtime-trading/src/feed/market-feed-config.ts new file mode 100644 index 0000000000..9d477ed663 --- /dev/null +++ b/examples/svelte/realtime-trading/src/feed/market-feed-config.ts @@ -0,0 +1,15 @@ +export interface MarketFeedConfig { + readonly instrumentCount: number + readonly targetSamplesPerSecond: number + readonly publishIntervalMs: number + readonly updateSparklines: boolean + readonly sparklineSampleIntervalMs: number +} + +export const initialMarketFeedConfig: MarketFeedConfig = { + instrumentCount: 100, + targetSamplesPerSecond: 10_000, + publishIntervalMs: 20, + updateSparklines: true, + sparklineSampleIntervalMs: 16, +} diff --git a/examples/svelte/realtime-trading/src/feed/market-feed-controller.ts b/examples/svelte/realtime-trading/src/feed/market-feed-controller.ts new file mode 100644 index 0000000000..157c577821 --- /dev/null +++ b/examples/svelte/realtime-trading/src/feed/market-feed-controller.ts @@ -0,0 +1,229 @@ +import { batch, createAtom } from '@tanstack/store' +import { normalizeFeedSampleRate } from './feed-sample-rates' +import { initialMarketFeedConfig } from './market-feed-config' +import { applyMarketUpdates, hydrateMarketQuotes } from './market-data' +import type { + MarketFeedCommand, + MarketFeedEvent, +} from './worker/market-feed-protocol' +import type { MarketQuote } from './market-data' + +export interface MarketFeedBatch { + tickCount: number + updateCount: number + supersededUpdateCount: number +} + +export interface MarketFeedObserver { + messageReceived?: () => void + mutationStarted?: () => void + batchApplied?: (batch: MarketFeedBatch) => void + renderCommitted?: () => void +} + +export interface MarketFeedActions { + toggle: () => void + setInstrumentCount: (count: number) => void + setTargetRate: (rate: number) => void + setPublishInterval: (intervalMs: number) => void + setSparklineUpdates: (enabled: boolean) => void + setSparklineSampleInterval: (intervalMs: number) => void + runBurst: () => void + reset: () => void +} + +export class MarketFeedController { + readonly workerReady = createAtom(false) + readonly running = createAtom( + !new URLSearchParams(location.search).has('paused'), + ) + readonly instrumentCount = createAtom(initialMarketFeedConfig.instrumentCount) + readonly targetTicksPerSecond = createAtom( + initialMarketFeedConfig.targetSamplesPerSecond, + ) + readonly publishIntervalMs = createAtom( + initialMarketFeedConfig.publishIntervalMs, + ) + readonly updateSparklines = createAtom( + initialMarketFeedConfig.updateSparklines, + ) + readonly sparklineSampleIntervalMs = createAtom( + initialMarketFeedConfig.sparklineSampleIntervalMs, + ) + readonly quotes = createAtom>([]) + readonly actions: MarketFeedActions + readonly #observers = new Set() + readonly #runtime = { + worker: null as Worker | null, + feedSessionId: 0, + renderPending: false, + resetWaitingForCommit: false, + resetSnapshotReady: false, + quoteIndexBySymbol: new Map(), + } + + constructor() { + this.actions = { + toggle: () => { + const running = !this.running.get() + this.running.set(running) + this.#post({ type: 'set-running', running }) + }, + setInstrumentCount: (count) => { + this.instrumentCount.set(count) + this.#resetWorker(count) + }, + setTargetRate: (rate) => { + const sampleRate = normalizeFeedSampleRate(rate) + this.targetTicksPerSecond.set(sampleRate) + this.#post({ type: 'set-rate', ticksPerSecond: sampleRate }) + }, + setPublishInterval: (publishIntervalMs) => { + this.publishIntervalMs.set(publishIntervalMs) + this.#post({ + type: 'set-publish-interval', + intervalMs: publishIntervalMs, + }) + }, + setSparklineUpdates: (enabled) => { + this.updateSparklines.set(enabled) + this.#post({ type: 'set-sparklines', enabled }) + }, + setSparklineSampleInterval: (intervalMs) => { + this.sparklineSampleIntervalMs.set(intervalMs) + this.#post({ type: 'set-sparkline-interval', intervalMs }) + }, + runBurst: () => this.#post({ type: 'burst', tickCount: 25_000 }), + reset: () => this.#resetWorker(this.instrumentCount.get()), + } + } + + start(): () => void { + const worker = new Worker( + new URL('./worker/market-feed.worker.ts', import.meta.url), + { type: 'module' }, + ) + this.#runtime.worker = worker + worker.addEventListener('message', this.#handleWorkerMessage) + worker.addEventListener('error', this.#handleWorkerError) + this.#post({ + type: 'start', + rowCount: this.instrumentCount.get(), + running: this.running.get(), + ticksPerSecond: this.targetTicksPerSecond.get(), + publishIntervalMs: this.publishIntervalMs.get(), + updateSparklines: this.updateSparklines.get(), + sparklineSampleIntervalMs: this.sparklineSampleIntervalMs.get(), + }) + return () => this.stop() + } + + stop(): void { + this.#runtime.worker?.removeEventListener( + 'message', + this.#handleWorkerMessage, + ) + this.#runtime.worker?.removeEventListener('error', this.#handleWorkerError) + this.#runtime.worker?.terminate() + this.#runtime.worker = null + this.#observers.clear() + } + + observe(observer: MarketFeedObserver): () => void { + this.#observers.add(observer) + return () => this.#observers.delete(observer) + } + + getQuoteBySymbol( + quotes: Array, + symbol: string | null, + ): MarketQuote | null { + if (symbol === null) return null + + const index = this.#runtime.quoteIndexBySymbol.get(symbol) + return index === undefined ? null : (quotes[index] ?? null) + } + + completeRender(): void { + if (!this.#runtime.renderPending) return + + this.#runtime.renderPending = false + for (const observer of this.#observers) { + observer.renderCommitted?.() + } + if ( + this.#runtime.resetWaitingForCommit && + this.#runtime.resetSnapshotReady + ) { + this.#runtime.resetWaitingForCommit = false + this.#runtime.resetSnapshotReady = false + this.#post({ type: 'set-running', running: this.running.get() }) + } + } + + readonly #handleWorkerMessage = ({ + data, + }: MessageEvent): void => { + if (data.type === 'snapshot') { + this.#runtime.feedSessionId = data.sessionId + if (this.#runtime.resetWaitingForCommit) { + this.#runtime.resetSnapshotReady = true + } + this.#startMutation() + const quotes = hydrateMarketQuotes(data.quotes) + this.#runtime.quoteIndexBySymbol = new Map( + quotes.map((quote, index) => [quote.symbol, index]), + ) + batch(() => { + this.quotes.set(quotes) + this.workerReady.set(true) + }) + return + } + + if (data.sessionId !== this.#runtime.feedSessionId) return + + for (const observer of this.#observers) { + observer.messageReceived?.() + } + this.#startMutation() + this.quotes.set(applyMarketUpdates(this.quotes.get(), data.updates)) + const feedBatch = { + tickCount: data.tickCount, + updateCount: data.updates.length, + supersededUpdateCount: data.coalescedUpdateCount, + } + for (const observer of this.#observers) { + observer.batchApplied?.(feedBatch) + } + } + + readonly #handleWorkerError = (error: ErrorEvent): void => { + batch(() => { + this.workerReady.set(false) + this.running.set(false) + }) + console.error('Market feed worker failed', error) + } + + #resetWorker(rowCount: number): void { + this.workerReady.set(false) + if (this.running.get()) { + this.#runtime.resetWaitingForCommit = true + this.#runtime.resetSnapshotReady = false + this.#post({ type: 'set-running', running: false }) + } + this.#post({ type: 'reset', rowCount }) + } + + #startMutation(): void { + this.#runtime.renderPending = true + for (const observer of this.#observers) { + observer.mutationStarted?.() + } + } + + #post(command: MarketFeedCommand): void { + this.#runtime.worker?.postMessage(command) + } +} diff --git a/examples/svelte/realtime-trading/src/feed/market-instruments.ts b/examples/svelte/realtime-trading/src/feed/market-instruments.ts new file mode 100644 index 0000000000..ac18d14ea9 --- /dev/null +++ b/examples/svelte/realtime-trading/src/feed/market-instruments.ts @@ -0,0 +1,742 @@ +export type MarketCode = + | 'US' + | 'NL' + | 'DE' + | 'FR' + | 'IT' + | 'ES' + | 'CH' + | 'DK' + | 'SE' + | 'FI' + | 'GB' + | 'KR' + | 'JP' + | 'HK' + | 'CA' + | 'AU' + +export type BaseInstrument = readonly [ + symbol: string, + company: string, + market: MarketCode, +] + +/** + * Current S&P 500 constituent universe used by the realtime trading examples. + * + * Source snapshot: https://github.com/datasets/s-and-p-500-companies + * Retrieved: 2026-08-15. + * Multiple share classes are intentionally represented as separate instruments. + */ +export const marketInstruments = Object.freeze([ + ['MMM', '3M', 'US'], + ['AOS', 'A. O. Smith', 'US'], + ['ABT', 'Abbott Laboratories', 'US'], + ['ABBV', 'AbbVie', 'US'], + ['ACN', 'Accenture', 'US'], + ['ADBE', 'Adobe Inc.', 'US'], + ['AMD', 'Advanced Micro Devices', 'US'], + ['AES', 'AES Corporation', 'US'], + ['AFL', 'Aflac', 'US'], + ['A', 'Agilent Technologies', 'US'], + ['APD', 'Air Products', 'US'], + ['ABNB', 'Airbnb', 'US'], + ['AKAM', 'Akamai Technologies', 'US'], + ['ALB', 'Albemarle Corporation', 'US'], + ['ARE', 'Alexandria Real Estate Equities', 'US'], + ['ALGN', 'Align Technology', 'US'], + ['ALLE', 'Allegion', 'US'], + ['LNT', 'Alliant Energy', 'US'], + ['ALL', 'Allstate', 'US'], + ['GOOGL', 'Alphabet Inc. (Class A)', 'US'], + ['GOOG', 'Alphabet Inc. (Class C)', 'US'], + ['MO', 'Altria', 'US'], + ['AMZN', 'Amazon', 'US'], + ['AMCR', 'Amcor', 'US'], + ['AEE', 'Ameren', 'US'], + ['AEP', 'American Electric Power', 'US'], + ['AXP', 'American Express', 'US'], + ['AIG', 'American International Group', 'US'], + ['AMT', 'American Tower', 'US'], + ['AWK', 'American Water Works', 'US'], + ['AMP', 'Ameriprise Financial', 'US'], + ['AME', 'Ametek', 'US'], + ['AMGN', 'Amgen', 'US'], + ['APH', 'Amphenol', 'US'], + ['ADI', 'Analog Devices', 'US'], + ['AON', 'Aon plc', 'US'], + ['APA', 'APA Corporation', 'US'], + ['APO', 'Apollo Global Management', 'US'], + ['AAPL', 'Apple Inc.', 'US'], + ['AMAT', 'Applied Materials', 'US'], + ['APP', 'AppLovin', 'US'], + ['APTV', 'Aptiv', 'US'], + ['ACGL', 'Arch Capital Group', 'US'], + ['ADM', 'Archer Daniels Midland', 'US'], + ['ARES', 'Ares Management', 'US'], + ['ANET', 'Arista Networks', 'US'], + ['AJG', 'Arthur J. Gallagher & Co.', 'US'], + ['AIZ', 'Assurant', 'US'], + ['T', 'AT&T', 'US'], + ['ATO', 'Atmos Energy', 'US'], + ['ADSK', 'Autodesk', 'US'], + ['ADP', 'Automatic Data Processing', 'US'], + ['AZO', 'AutoZone', 'US'], + ['AVB', 'AvalonBay Communities', 'US'], + ['AVY', 'Avery Dennison', 'US'], + ['AXON', 'Axon Enterprise', 'US'], + ['BKR', 'Baker Hughes', 'US'], + ['BALL', 'Ball Corporation', 'US'], + ['BAC', 'Bank of America', 'US'], + ['BAX', 'Baxter International', 'US'], + ['BDX', 'Becton Dickinson', 'US'], + ['BRK.B', 'Berkshire Hathaway', 'US'], + ['BBY', 'Best Buy', 'US'], + ['TECH', 'Bio-Techne', 'US'], + ['BIIB', 'Biogen', 'US'], + ['BLK', 'BlackRock', 'US'], + ['BX', 'Blackstone Inc.', 'US'], + ['XYZ', 'Block, Inc.', 'US'], + ['BNY', 'BNY Mellon', 'US'], + ['BA', 'Boeing', 'US'], + ['BKNG', 'Booking Holdings', 'US'], + ['BSX', 'Boston Scientific', 'US'], + ['BMY', 'Bristol Myers Squibb', 'US'], + ['AVGO', 'Broadcom', 'US'], + ['BR', 'Broadridge Financial Solutions', 'US'], + ['BRO', 'Brown & Brown', 'US'], + ['BF.B', 'Brown–Forman', 'US'], + ['BLDR', 'Builders FirstSource', 'US'], + ['BG', 'Bunge Global', 'US'], + ['BXP', 'BXP, Inc.', 'US'], + ['CHRW', 'C.H. Robinson', 'US'], + ['CDNS', 'Cadence Design Systems', 'US'], + ['CPT', 'Camden Property Trust', 'US'], + ['COF', 'Capital One', 'US'], + ['CAH', 'Cardinal Health', 'US'], + ['CCL', 'Carnival Corporation', 'US'], + ['CARR', 'Carrier Global', 'US'], + ['CVNA', 'Carvana', 'US'], + ['CASY', "Casey's", 'US'], + ['CAT', 'Caterpillar Inc.', 'US'], + ['CBOE', 'Cboe Global Markets', 'US'], + ['CBRE', 'CBRE Group', 'US'], + ['CDW', 'CDW Corporation', 'US'], + ['COR', 'Cencora', 'US'], + ['CNC', 'Centene Corporation', 'US'], + ['CNP', 'CenterPoint Energy', 'US'], + ['CF', 'CF Industries', 'US'], + ['CRL', 'Charles River Laboratories', 'US'], + ['SCHW', 'Charles Schwab Corporation', 'US'], + ['CHTR', 'Charter Communications', 'US'], + ['CVX', 'Chevron Corporation', 'US'], + ['CMG', 'Chipotle Mexican Grill', 'US'], + ['CB', 'Chubb Limited', 'US'], + ['CHD', 'Church & Dwight', 'US'], + ['CIEN', 'Ciena', 'US'], + ['CI', 'Cigna', 'US'], + ['CINF', 'Cincinnati Financial', 'US'], + ['CTAS', 'Cintas', 'US'], + ['CSCO', 'Cisco', 'US'], + ['C', 'Citigroup', 'US'], + ['CFG', 'Citizens Financial Group', 'US'], + ['CLX', 'Clorox', 'US'], + ['CME', 'CME Group', 'US'], + ['CMS', 'CMS Energy', 'US'], + ['KO', 'Coca-Cola Company (The)', 'US'], + ['CTSH', 'Cognizant', 'US'], + ['COHR', 'Coherent Corp.', 'US'], + ['COIN', 'Coinbase', 'US'], + ['CL', 'Colgate-Palmolive', 'US'], + ['CMCSA', 'Comcast', 'US'], + ['FIX', 'Comfort Systems USA', 'US'], + ['COP', 'ConocoPhillips', 'US'], + ['ED', 'Consolidated Edison', 'US'], + ['STZ', 'Constellation Brands', 'US'], + ['CEG', 'Constellation Energy', 'US'], + ['COO', 'Cooper Companies (The)', 'US'], + ['CPRT', 'Copart', 'US'], + ['GLW', 'Corning Inc.', 'US'], + ['CPAY', 'Corpay', 'US'], + ['CTVA', 'Corteva', 'US'], + ['CSGP', 'CoStar Group', 'US'], + ['COST', 'Costco', 'US'], + ['CRH', 'CRH plc', 'US'], + ['CRWD', 'CrowdStrike', 'US'], + ['CCI', 'Crown Castle', 'US'], + ['CSX', 'CSX Corporation', 'US'], + ['CMI', 'Cummins', 'US'], + ['CVS', 'CVS Health', 'US'], + ['DHR', 'Danaher Corporation', 'US'], + ['DRI', 'Darden Restaurants', 'US'], + ['DDOG', 'Datadog', 'US'], + ['DVA', 'DaVita', 'US'], + ['DECK', 'Deckers Brands', 'US'], + ['DE', 'Deere & Company', 'US'], + ['DELL', 'Dell Technologies', 'US'], + ['DAL', 'Delta Air Lines', 'US'], + ['DVN', 'Devon Energy', 'US'], + ['DXCM', 'Dexcom', 'US'], + ['FANG', 'Diamondback Energy', 'US'], + ['DLR', 'Digital Realty', 'US'], + ['DG', 'Dollar General', 'US'], + ['DLTR', 'Dollar Tree', 'US'], + ['D', 'Dominion Energy', 'US'], + ['DPZ', "Domino's", 'US'], + ['DASH', 'DoorDash', 'US'], + ['DOV', 'Dover Corporation', 'US'], + ['DOW', 'Dow Inc.', 'US'], + ['DHI', 'D. R. Horton', 'US'], + ['DTE', 'DTE Energy', 'US'], + ['DUK', 'Duke Energy', 'US'], + ['DD', 'DuPont', 'US'], + ['ETN', 'Eaton Corporation', 'US'], + ['EBAY', 'eBay Inc.', 'US'], + ['ECHO', 'EchoStar', 'US'], + ['ECL', 'Ecolab', 'US'], + ['EIX', 'Edison International', 'US'], + ['EW', 'Edwards Lifesciences', 'US'], + ['ELV', 'Elevance Health', 'US'], + ['EME', 'Emcor', 'US'], + ['EMR', 'Emerson Electric', 'US'], + ['ETR', 'Entergy', 'US'], + ['EOG', 'EOG Resources', 'US'], + ['EQT', 'EQT Corporation', 'US'], + ['EFX', 'Equifax', 'US'], + ['EQIX', 'Equinix', 'US'], + ['EQR', 'Equity Residential', 'US'], + ['ERIE', 'Erie Indemnity', 'US'], + ['ESS', 'Essex Property Trust', 'US'], + ['EL', 'Estée Lauder Companies (The)', 'US'], + ['EG', 'Everest Group', 'US'], + ['EVRG', 'Evergy', 'US'], + ['ES', 'Eversource Energy', 'US'], + ['EXC', 'Exelon', 'US'], + ['EXE', 'Expand Energy', 'US'], + ['EXPE', 'Expedia Group', 'US'], + ['EXPD', 'Expeditors International', 'US'], + ['EXR', 'Extra Space Storage', 'US'], + ['XOM', 'ExxonMobil', 'US'], + ['FFIV', 'F5, Inc.', 'US'], + ['FDS', 'FactSet', 'US'], + ['FICO', 'Fair Isaac', 'US'], + ['FAST', 'Fastenal', 'US'], + ['FRT', 'Federal Realty Investment Trust', 'US'], + ['FDX', 'FedEx', 'US'], + ['FDXF', 'FedEx Freight', 'US'], + ['FERG', 'Ferguson Enterprises', 'US'], + ['FIS', 'Fidelity National Information Services', 'US'], + ['FITB', 'Fifth Third Bancorp', 'US'], + ['FSLR', 'First Solar', 'US'], + ['FE', 'FirstEnergy', 'US'], + ['FISV', 'Fiserv', 'US'], + ['FLEX', 'Flex Ltd.', 'US'], + ['F', 'Ford Motor Company', 'US'], + ['FTNT', 'Fortinet', 'US'], + ['FTV', 'Fortive', 'US'], + ['FOXA', 'Fox Corporation (Class A)', 'US'], + ['FOX', 'Fox Corporation (Class B)', 'US'], + ['BEN', 'Franklin Resources', 'US'], + ['FCX', 'Freeport-McMoRan', 'US'], + ['GRMN', 'Garmin', 'US'], + ['IT', 'Gartner', 'US'], + ['GE', 'GE Aerospace', 'US'], + ['GEHC', 'GE HealthCare', 'US'], + ['GEV', 'GE Vernova', 'US'], + ['GEN', 'Gen Digital', 'US'], + ['GNRC', 'Generac', 'US'], + ['GD', 'General Dynamics', 'US'], + ['GIS', 'General Mills', 'US'], + ['GM', 'General Motors', 'US'], + ['GPC', 'Genuine Parts Company', 'US'], + ['GILD', 'Gilead Sciences', 'US'], + ['GPN', 'Global Payments', 'US'], + ['GL', 'Globe Life', 'US'], + ['GDDY', 'GoDaddy', 'US'], + ['GS', 'Goldman Sachs', 'US'], + ['HAL', 'Halliburton', 'US'], + ['HIG', 'Hartford (The)', 'US'], + ['HAS', 'Hasbro', 'US'], + ['HCA', 'HCA Healthcare', 'US'], + ['DOC', 'Healthpeak Properties', 'US'], + ['HSIC', 'Henry Schein', 'US'], + ['HSY', 'Hershey Company (The)', 'US'], + ['HPE', 'Hewlett Packard Enterprise', 'US'], + ['HLT', 'Hilton Worldwide', 'US'], + ['HD', 'Home Depot (The)', 'US'], + ['HONA', 'Honeywell Aerospace', 'US'], + ['HON', 'Honeywell Technologies', 'US'], + ['HRL', 'Hormel Foods', 'US'], + ['HST', 'Host Hotels & Resorts', 'US'], + ['HWM', 'Howmet Aerospace', 'US'], + ['HPQ', 'HP Inc.', 'US'], + ['HUBB', 'Hubbell Incorporated', 'US'], + ['HUM', 'Humana', 'US'], + ['HBAN', 'Huntington Bancshares', 'US'], + ['HII', 'Huntington Ingalls Industries', 'US'], + ['IBM', 'IBM', 'US'], + ['IEX', 'IDEX Corporation', 'US'], + ['IDXX', 'Idexx Laboratories', 'US'], + ['ITW', 'Illinois Tool Works', 'US'], + ['INCY', 'Incyte', 'US'], + ['IR', 'Ingersoll Rand', 'US'], + ['PODD', 'Insulet Corporation', 'US'], + ['INTC', 'Intel', 'US'], + ['IBKR', 'Interactive Brokers', 'US'], + ['ICE', 'Intercontinental Exchange', 'US'], + ['IFF', 'International Flavors & Fragrances', 'US'], + ['IP', 'International Paper', 'US'], + ['INTU', 'Intuit', 'US'], + ['ISRG', 'Intuitive Surgical', 'US'], + ['IVZ', 'Invesco', 'US'], + ['INVH', 'Invitation Homes', 'US'], + ['IQV', 'IQVIA', 'US'], + ['IRM', 'Iron Mountain', 'US'], + ['JBHT', 'J.B. Hunt', 'US'], + ['JBL', 'Jabil', 'US'], + ['JKHY', 'Jack Henry & Associates', 'US'], + ['J', 'Jacobs Solutions', 'US'], + ['JNJ', 'Johnson & Johnson', 'US'], + ['JCI', 'Johnson Controls', 'US'], + ['JPM', 'JPMorgan Chase', 'US'], + ['KVUE', 'Kenvue', 'US'], + ['KDP', 'Keurig Dr Pepper', 'US'], + ['KEY', 'KeyCorp', 'US'], + ['KEYS', 'Keysight Technologies', 'US'], + ['KMB', 'Kimberly-Clark', 'US'], + ['KIM', 'Kimco Realty', 'US'], + ['KMI', 'Kinder Morgan', 'US'], + ['KKR', 'KKR & Co.', 'US'], + ['KLAC', 'KLA Corporation', 'US'], + ['KHC', 'Kraft Heinz', 'US'], + ['KR', 'Kroger', 'US'], + ['LHX', 'L3Harris', 'US'], + ['LH', 'Labcorp', 'US'], + ['LRCX', 'Lam Research', 'US'], + ['LVS', 'Las Vegas Sands', 'US'], + ['LDOS', 'Leidos', 'US'], + ['LEN', 'Lennar', 'US'], + ['LII', 'Lennox International', 'US'], + ['LLY', 'Lilly (Eli)', 'US'], + ['LIN', 'Linde plc', 'US'], + ['LYV', 'Live Nation Entertainment', 'US'], + ['LMT', 'Lockheed Martin', 'US'], + ['L', 'Loews Corporation', 'US'], + ['LOW', "Lowe's", 'US'], + ['LULU', 'Lululemon Athletica', 'US'], + ['LITE', 'Lumentum', 'US'], + ['LYB', 'LyondellBasell', 'US'], + ['MTB', 'M&T Bank', 'US'], + ['MPC', 'Marathon Petroleum', 'US'], + ['MAR', 'Marriott International', 'US'], + ['MRSH', 'Marsh McLennan', 'US'], + ['MLM', 'Martin Marietta Materials', 'US'], + ['MRVL', 'Marvell Technology', 'US'], + ['MAS', 'Masco', 'US'], + ['MA', 'Mastercard', 'US'], + ['MKC', 'McCormick & Company', 'US'], + ['MCD', "McDonald's", 'US'], + ['MCK', 'McKesson Corporation', 'US'], + ['MDT', 'Medtronic', 'US'], + ['MRK', 'Merck & Co.', 'US'], + ['META', 'Meta Platforms', 'US'], + ['MET', 'MetLife', 'US'], + ['MTD', 'Mettler Toledo', 'US'], + ['MGM', 'MGM Resorts', 'US'], + ['MCHP', 'Microchip Technology', 'US'], + ['MU', 'Micron Technology', 'US'], + ['MSFT', 'Microsoft', 'US'], + ['MAA', 'Mid-America Apartment Communities', 'US'], + ['MRNA', 'Moderna', 'US'], + ['TAP', 'Molson Coors Beverage Company', 'US'], + ['MDLZ', 'Mondelez International', 'US'], + ['MPWR', 'Monolithic Power Systems', 'US'], + ['MNST', 'Monster Beverage', 'US'], + ['MCO', "Moody's Corporation", 'US'], + ['MS', 'Morgan Stanley', 'US'], + ['MOS', 'Mosaic Company (The)', 'US'], + ['MSI', 'Motorola Solutions', 'US'], + ['MSCI', 'MSCI', 'US'], + ['NDAQ', 'Nasdaq, Inc.', 'US'], + ['NTAP', 'NetApp', 'US'], + ['NFLX', 'Netflix', 'US'], + ['NEM', 'Newmont', 'US'], + ['NWSA', 'News Corp (Class A)', 'US'], + ['NWS', 'News Corp (Class B)', 'US'], + ['NEE', 'NextEra Energy', 'US'], + ['NKE', 'Nike, Inc.', 'US'], + ['NI', 'NiSource', 'US'], + ['NDSN', 'Nordson Corporation', 'US'], + ['NSC', 'Norfolk Southern', 'US'], + ['NTRS', 'Northern Trust', 'US'], + ['NOC', 'Northrop Grumman', 'US'], + ['NCLH', 'Norwegian Cruise Line Holdings', 'US'], + ['NRG', 'NRG Energy', 'US'], + ['NUE', 'Nucor', 'US'], + ['NVDA', 'Nvidia', 'US'], + ['NVR', 'NVR, Inc.', 'US'], + ['NXPI', 'NXP Semiconductors', 'US'], + ['ORLY', "O'Reilly Automotive", 'US'], + ['OXY', 'Occidental Petroleum', 'US'], + ['ODFL', 'Old Dominion', 'US'], + ['OMC', 'Omnicom Group', 'US'], + ['ON', 'ON Semiconductor', 'US'], + ['OKE', 'Oneok', 'US'], + ['ORCL', 'Oracle Corporation', 'US'], + ['OTIS', 'Otis Worldwide', 'US'], + ['PCAR', 'Paccar', 'US'], + ['PKG', 'Packaging Corporation of America', 'US'], + ['PLTR', 'Palantir Technologies', 'US'], + ['PANW', 'Palo Alto Networks', 'US'], + ['PSKY', 'Paramount Skydance Corporation', 'US'], + ['PH', 'Parker Hannifin', 'US'], + ['PAYX', 'Paychex', 'US'], + ['PYPL', 'PayPal', 'US'], + ['PNR', 'Pentair', 'US'], + ['PEP', 'PepsiCo', 'US'], + ['PFE', 'Pfizer', 'US'], + ['PCG', 'PG&E Corporation', 'US'], + ['PM', 'Philip Morris International', 'US'], + ['PSX', 'Phillips 66', 'US'], + ['PNW', 'Pinnacle West Capital', 'US'], + ['PNC', 'PNC Financial Services', 'US'], + ['PPG', 'PPG Industries', 'US'], + ['PPL', 'PPL Corporation', 'US'], + ['PFG', 'Principal Financial Group', 'US'], + ['PG', 'Procter & Gamble', 'US'], + ['PGR', 'Progressive Corporation', 'US'], + ['PLD', 'Prologis', 'US'], + ['PRU', 'Prudential Financial', 'US'], + ['PEG', 'Public Service Enterprise Group', 'US'], + ['PTC', 'PTC Inc.', 'US'], + ['PSA', 'Public Storage', 'US'], + ['PHM', 'PulteGroup', 'US'], + ['PWR', 'Quanta Services', 'US'], + ['QCOM', 'Qualcomm', 'US'], + ['DGX', 'Quest Diagnostics', 'US'], + ['Q', 'Qnity Electronics', 'US'], + ['RL', 'Ralph Lauren Corporation', 'US'], + ['RJF', 'Raymond James Financial', 'US'], + ['RTX', 'RTX Corporation', 'US'], + ['O', 'Realty Income', 'US'], + ['REG', 'Regency Centers', 'US'], + ['REGN', 'Regeneron Pharmaceuticals', 'US'], + ['RF', 'Regions Financial Corporation', 'US'], + ['RSG', 'Republic Services', 'US'], + ['RMD', 'ResMed|', 'US'], + ['RVTY', 'Revvity', 'US'], + ['HOOD', 'Robinhood Markets', 'US'], + ['ROK', 'Rockwell Automation', 'US'], + ['ROL', 'Rollins, Inc.', 'US'], + ['ROP', 'Roper Technologies', 'US'], + ['ROST', 'Ross Stores', 'US'], + ['RCL', 'Royal Caribbean Group', 'US'], + ['SPGI', 'S&P Global', 'US'], + ['CRM', 'Salesforce', 'US'], + ['SNDK', 'Sandisk', 'US'], + ['SBAC', 'SBA Communications', 'US'], + ['SLB', 'Schlumberger', 'US'], + ['STX', 'Seagate Technology', 'US'], + ['SRE', 'Sempra', 'US'], + ['NOW', 'ServiceNow', 'US'], + ['SHW', 'Sherwin-Williams', 'US'], + ['SPG', 'Simon Property Group', 'US'], + ['SWKS', 'Skyworks Solutions', 'US'], + ['SJM', 'J.M. Smucker Company (The)', 'US'], + ['SW', 'Smurfit Westrock', 'US'], + ['SNA', 'Snap-on', 'US'], + ['SOLV', 'Solventum', 'US'], + ['SO', 'Southern Company', 'US'], + ['LUV', 'Southwest Airlines', 'US'], + ['SWK', 'Stanley Black & Decker', 'US'], + ['SBUX', 'Starbucks', 'US'], + ['STT', 'State Street Corporation', 'US'], + ['STLD', 'Steel Dynamics', 'US'], + ['STE', 'Steris', 'US'], + ['SYK', 'Stryker Corporation', 'US'], + ['SMCI', 'Supermicro', 'US'], + ['SYF', 'Synchrony Financial', 'US'], + ['SNPS', 'Synopsys', 'US'], + ['SYY', 'Sysco', 'US'], + ['TMUS', 'T-Mobile US', 'US'], + ['TROW', 'T. Rowe Price', 'US'], + ['TTWO', 'Take-Two Interactive', 'US'], + ['TPR', 'Tapestry, Inc.', 'US'], + ['TRGP', 'Targa Resources', 'US'], + ['TGT', 'Target Corporation', 'US'], + ['TEL', 'TE Connectivity', 'US'], + ['TDY', 'Teledyne Technologies', 'US'], + ['TER', 'Teradyne', 'US'], + ['TSLA', 'Tesla, Inc.', 'US'], + ['TXN', 'Texas Instruments', 'US'], + ['TPL', 'Texas Pacific Land Corporation', 'US'], + ['TXT', 'Textron', 'US'], + ['TMO', 'Thermo Fisher Scientific', 'US'], + ['TJX', 'TJX Companies', 'US'], + ['TKO', 'TKO Group Holdings', 'US'], + ['TTD', 'Trade Desk (The)', 'US'], + ['TSCO', 'Tractor Supply', 'US'], + ['TT', 'Trane Technologies', 'US'], + ['TDG', 'TransDigm Group', 'US'], + ['TRV', 'Travelers Companies (The)', 'US'], + ['TRMB', 'Trimble Inc.', 'US'], + ['TFC', 'Truist Financial', 'US'], + ['TYL', 'Tyler Technologies', 'US'], + ['TSN', 'Tyson Foods', 'US'], + ['USB', 'U.S. Bancorp', 'US'], + ['UBER', 'Uber', 'US'], + ['UDR', 'UDR, Inc.', 'US'], + ['ULTA', 'Ulta Beauty', 'US'], + ['UNP', 'Union Pacific Corporation', 'US'], + ['UAL', 'United Airlines Holdings', 'US'], + ['UPS', 'United Parcel Service', 'US'], + ['URI', 'United Rentals', 'US'], + ['UNH', 'UnitedHealth Group', 'US'], + ['UHS', 'Universal Health Services', 'US'], + ['VLO', 'Valero Energy', 'US'], + ['VEEV', 'Veeva Systems', 'US'], + ['VTR', 'Ventas', 'US'], + ['VLTO', 'Veralto', 'US'], + ['VRSN', 'Verisign', 'US'], + ['VRSK', 'Verisk Analytics', 'US'], + ['VZ', 'Verizon', 'US'], + ['VRTX', 'Vertex Pharmaceuticals', 'US'], + ['VRT', 'Vertiv', 'US'], + ['VTRS', 'Viatris', 'US'], + ['VICI', 'Vici Properties', 'US'], + ['V', 'Visa Inc.', 'US'], + ['VST', 'Vistra Corp.', 'US'], + ['VMC', 'Vulcan Materials Company', 'US'], + ['WRB', 'W. R. Berkley Corporation', 'US'], + ['GWW', 'W. W. Grainger', 'US'], + ['WAB', 'Wabtec', 'US'], + ['WMT', 'Walmart', 'US'], + ['DIS', 'Walt Disney Company (The)', 'US'], + ['WBD', 'Warner Bros. Discovery', 'US'], + ['WM', 'Waste Management', 'US'], + ['WAT', 'Waters Corporation', 'US'], + ['WEC', 'WEC Energy Group', 'US'], + ['WFC', 'Wells Fargo', 'US'], + ['WELL', 'Welltower', 'US'], + ['WST', 'West Pharmaceutical Services', 'US'], + ['WDC', 'Western Digital', 'US'], + ['WY', 'Weyerhaeuser', 'US'], + ['WSM', 'Williams-Sonoma, Inc.', 'US'], + ['WMB', 'Williams Companies', 'US'], + ['WTW', 'Willis Towers Watson', 'US'], + ['WDAY', 'Workday, Inc.', 'US'], + ['WYNN', 'Wynn Resorts', 'US'], + ['XEL', 'Xcel Energy', 'US'], + ['XYL', 'Xylem Inc.', 'US'], + ['YUM', 'Yum! Brands', 'US'], + ['ZBRA', 'Zebra Technologies', 'US'], + ['ZBH', 'Zimmer Biomet', 'US'], + ['ZTS', 'Zoetis', 'US'], +]) + +/** + * Representative liquid international listings used to diversify the fixture. + * Symbols use their local-market form and the third tuple value is an ISO-style + * country/market code, rather than a trading currency or exchange MIC. + * + * References checked 2026-08-15: STOXX Europe 50, KRX KOSPI market, + * JPX TOPIX Core30, and HKEX index constituent materials. + */ +const europeanInstruments = Object.freeze([ + ['ASML', 'ASML Holding', 'NL'], + ['INGA', 'ING Group', 'NL'], + ['ADYEN', 'Adyen', 'NL'], + ['PHIA', 'Philips', 'NL'], + ['HEIA', 'Heineken', 'NL'], + ['SAP', 'SAP', 'DE'], + ['SIE', 'Siemens', 'DE'], + ['ALV', 'Allianz', 'DE'], + ['DTE', 'Deutsche Telekom', 'DE'], + ['MBG', 'Mercedes-Benz Group', 'DE'], + ['BMW', 'BMW', 'DE'], + ['BAS', 'BASF', 'DE'], + ['MUV2', 'Munich Re', 'DE'], + ['VOW3', 'Volkswagen Preference', 'DE'], + ['IFX', 'Infineon Technologies', 'DE'], + ['MC', 'LVMH', 'FR'], + ['OR', "L'Oréal", 'FR'], + ['AIR', 'Airbus', 'FR'], + ['SU', 'Schneider Electric', 'FR'], + ['TTE', 'TotalEnergies', 'FR'], + ['SAN', 'Sanofi', 'FR'], + ['BNP', 'BNP Paribas', 'FR'], + ['CS', 'AXA', 'FR'], + ['DG', 'Vinci', 'FR'], + ['ENEL', 'Enel', 'IT'], + ['ENI', 'Eni', 'IT'], + ['ISP', 'Intesa Sanpaolo', 'IT'], + ['UCG', 'UniCredit', 'IT'], + ['STLAM', 'Stellantis', 'IT'], + ['SAN', 'Banco Santander', 'ES'], + ['IBE', 'Iberdrola', 'ES'], + ['ITX', 'Inditex', 'ES'], + ['BBVA', 'BBVA', 'ES'], + ['NESN', 'Nestlé', 'CH'], + ['ROG', 'Roche Holding', 'CH'], + ['NOVN', 'Novartis', 'CH'], + ['UBSG', 'UBS Group', 'CH'], + ['NOVO-B', 'Novo Nordisk', 'DK'], + ['MAERSK-B', 'A.P. Moller - Maersk', 'DK'], + ['VOLV-B', 'Volvo', 'SE'], + ['ERIC-B', 'Ericsson', 'SE'], + ['NOKIA', 'Nokia', 'FI'], + ['SHEL', 'Shell', 'GB'], + ['AZN', 'AstraZeneca', 'GB'], + ['HSBA', 'HSBC Holdings', 'GB'], + ['ULVR', 'Unilever', 'GB'], + ['LSEG', 'London Stock Exchange Group', 'GB'], +]) + +const europeanMarketCodes = Object.freeze([ + 'NL', + 'DE', + 'FR', + 'IT', + 'ES', + 'CH', + 'DK', + 'SE', + 'FI', + 'GB', +]) + +const europeanMarketGroups = Object.freeze( + europeanMarketCodes.map((market) => + europeanInstruments.filter(([, , instrumentMarket]) => + Object.is(instrumentMarket, market), + ), + ), +) + +const interleavedEuropeanInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...europeanMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + europeanMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const southKoreanInstruments = Object.freeze([ + ['005930', 'Samsung Electronics', 'KR'], + ['000660', 'SK hynix', 'KR'], + ['373220', 'LG Energy Solution', 'KR'], + ['207940', 'Samsung Biologics', 'KR'], + ['005380', 'Hyundai Motor', 'KR'], + ['000270', 'Kia', 'KR'], + ['068270', 'Celltrion', 'KR'], + ['105560', 'KB Financial Group', 'KR'], + ['055550', 'Shinhan Financial Group', 'KR'], + ['035420', 'NAVER', 'KR'], + ['035720', 'Kakao', 'KR'], + ['006400', 'Samsung SDI', 'KR'], + ['051910', 'LG Chem', 'KR'], + ['012330', 'Hyundai Mobis', 'KR'], + ['066570', 'LG Electronics', 'KR'], +]) + +const japaneseInstruments = Object.freeze([ + ['8306', 'Mitsubishi UFJ Financial Group', 'JP'], + ['7203', 'Toyota Motor', 'JP'], + ['6501', 'Hitachi', 'JP'], + ['8316', 'Sumitomo Mitsui Financial Group', 'JP'], + ['6758', 'Sony Group', 'JP'], + ['8058', 'Mitsubishi Corporation', 'JP'], + ['9984', 'SoftBank Group', 'JP'], + ['8035', 'Tokyo Electron', 'JP'], + ['8411', 'Mizuho Financial Group', 'JP'], + ['8031', 'Mitsui & Co.', 'JP'], + ['6861', 'Keyence', 'JP'], + ['7974', 'Nintendo', 'JP'], + ['6098', 'Recruit Holdings', 'JP'], + ['9432', 'Nippon Telegraph and Telephone', 'JP'], + ['4063', 'Shin-Etsu Chemical', 'JP'], +]) + +const hongKongInstruments = Object.freeze([ + ['0700', 'Tencent Holdings', 'HK'], + ['9988', 'Alibaba Group', 'HK'], + ['1810', 'Xiaomi', 'HK'], + ['3690', 'Meituan', 'HK'], + ['0941', 'China Mobile', 'HK'], + ['1211', 'BYD Company', 'HK'], + ['1299', 'AIA Group', 'HK'], + ['0388', 'Hong Kong Exchanges and Clearing', 'HK'], + ['0005', 'HSBC Holdings', 'HK'], + ['2318', 'Ping An Insurance', 'HK'], +]) + +const canadianInstruments = Object.freeze([ + ['RY', 'Royal Bank of Canada', 'CA'], + ['TD', 'Toronto-Dominion Bank', 'CA'], + ['SHOP', 'Shopify', 'CA'], + ['ENB', 'Enbridge', 'CA'], + ['CNR', 'Canadian National Railway', 'CA'], + ['CP', 'Canadian Pacific Kansas City', 'CA'], + ['BMO', 'Bank of Montreal', 'CA'], + ['CSU', 'Constellation Software', 'CA'], +]) + +const australianInstruments = Object.freeze([ + ['BHP', 'BHP Group', 'AU'], + ['CBA', 'Commonwealth Bank of Australia', 'AU'], + ['CSL', 'CSL', 'AU'], + ['NAB', 'National Australia Bank', 'AU'], + ['WBC', 'Westpac Banking Corporation', 'AU'], + ['ANZ', 'ANZ Group Holdings', 'AU'], + ['WES', 'Wesfarmers', 'AU'], + ['MQG', 'Macquarie Group', 'AU'], +]) + +const internationalMarketGroups = Object.freeze([ + interleavedEuropeanInstruments, + southKoreanInstruments, + japaneseInstruments, + hongKongInstruments, + canadianInstruments, + australianInstruments, +]) + +export const internationalInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...internationalMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + internationalMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const INTERNATIONAL_INSERTION_INTERVAL = 3 + +/** + * U.S. and international instruments are interleaved so ordinary benchmark + * sizes exercise multiple symbol formats and market labels. + */ +export const globalInstruments = Object.freeze( + marketInstruments.flatMap((instrument, index) => { + const internationalInstrument = + index % INTERNATIONAL_INSERTION_INTERVAL === 0 + ? internationalInstruments[index / INTERNATIONAL_INSERTION_INTERVAL] + : undefined + + return internationalInstrument + ? [instrument, internationalInstrument] + : [instrument] + }), +) as unknown as ReadonlyArray diff --git a/examples/svelte/realtime-trading/src/feed/worker/market-feed-engine.ts b/examples/svelte/realtime-trading/src/feed/worker/market-feed-engine.ts new file mode 100644 index 0000000000..fbd9c369c0 --- /dev/null +++ b/examples/svelte/realtime-trading/src/feed/worker/market-feed-engine.ts @@ -0,0 +1,177 @@ +import { globalInstruments } from '../market-instruments.ts' +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const INITIAL_MARKET_SEED = 0x4d41524b +const LIVE_FEED_SEED = 0x5449434b + +export class MarketFeedEngine { + #quotes: Array = [] + #lastHistorySampledAt = new Uint32Array(0) + #random = createRandom(2_026) + #rowCursor = 0 + #tickIndex = 0 + + reset(count: number): Array { + const random = createRandom(INITIAL_MARKET_SEED ^ count) + const createdAt = Date.now() + + this.#quotes = Array.from({ length: count }, (_, index) => { + const [baseSymbol, company, market] = + globalInstruments[index % globalInstruments.length] + const series = Math.floor(index / globalInstruments.length) + const symbol = series === 0 ? baseSymbol : `${baseSymbol}${series}` + const previousClose = roundPrice(20 + random() * 480) + const open = roundPrice(previousClose * (1 + (random() - 0.5) * 0.016)) + const spread = Math.max(0.01, open * (0.0002 + random() * 0.0004)) + const history = Array.from({ length: 24 }, (_, historyIndex) => + roundPrice( + open * + (1 + Math.sin(historyIndex / 4) * 0.002 + (random() - 0.5) * 0.001), + ), + ) + const volume = Math.floor(50_000 + random() * 2_000_000) + const lastSize = Math.floor(10 + random() * 5_000) + + return { + id: `instrument-${index}`, + symbol, + company, + venue: market, + previousClose, + open, + high: open, + low: open, + price: open, + bid: roundPrice(open - spread / 2), + ask: roundPrice(open + spread / 2), + bidSize: Math.floor(100 + random() * 25_000), + askSize: Math.floor(100 + random() * 25_000), + lastSize, + lastMove: 0, + lastUpdatedAt: createdAt, + volume, + turnover: roundMoney(open * volume), + history, + } + }) + + this.#random = createRandom(LIVE_FEED_SEED ^ count) + this.#rowCursor = 0 + this.#lastHistorySampledAt = new Uint32Array(count) + this.#lastHistorySampledAt.fill(createdAt >>> 0) + + return this.#quotes.map((quote) => ({ + ...quote, + history: [...quote.history], + })) + } + + applyTicks( + tickCount: number, + updateSparklines: boolean, + sparklineSampleIntervalMs: number, + ): Array { + if (this.#quotes.length === 0 || tickCount <= 0) return [] + + const updatedAt = Date.now() + const sampledAt = updatedAt >>> 0 + const sampleIntervalMs = Math.max(16, sparklineSampleIntervalMs) + const updatedQuotes = new Map() + const stride = 97 + + this.#tickIndex = 0 + while (this.#tickIndex < tickCount) { + this.#rowCursor = (this.#rowCursor + stride) % this.#quotes.length + const quote = this.#quotes[this.#rowCursor] + const lastSampledAt = this.#lastHistorySampledAt[this.#rowCursor] + const shouldUpdateHistory = + updateSparklines && + (sampledAt - lastSampledAt) >>> 0 >= sampleIntervalMs + + if (shouldUpdateHistory) { + this.#lastHistorySampledAt[this.#rowCursor] = sampledAt + } + + this.#applyTick(quote, shouldUpdateHistory, updatedAt) + + const previousUpdate = updatedQuotes.get(this.#rowCursor) + updatedQuotes.set(this.#rowCursor, { + index: this.#rowCursor, + price: quote.price, + bid: quote.bid, + ask: quote.ask, + bidSize: quote.bidSize, + askSize: quote.askSize, + lastSize: quote.lastSize, + lastMove: quote.lastMove, + lastUpdatedAt: quote.lastUpdatedAt, + high: quote.high, + low: quote.low, + volume: quote.volume, + turnover: quote.turnover, + ...(shouldUpdateHistory || previousUpdate?.history + ? { history: [...quote.history] } + : {}), + }) + this.#tickIndex++ + } + + return [...updatedQuotes.values()] + } + + #applyTick( + quote: MarketQuoteSnapshot, + updateHistory: boolean, + updatedAt: number, + ): void { + const previousPrice = quote.price + const volatility = 0.00015 + this.#random() * 0.0012 + const move = previousPrice * (this.#random() - 0.495) * volatility + const nextPrice = roundPrice(Math.max(0.1, previousPrice + move)) + const spread = Math.max( + 0.01, + nextPrice * (0.00015 + this.#random() * 0.0005), + ) + + quote.lastMove = nextPrice - previousPrice + quote.price = nextPrice + quote.high = Math.max(quote.high, nextPrice) + quote.low = Math.min(quote.low, nextPrice) + quote.bid = roundPrice(nextPrice - spread / 2) + quote.ask = roundPrice(nextPrice + spread / 2) + quote.bidSize = Math.floor(100 + this.#random() * 25_000) + quote.askSize = Math.floor(100 + this.#random() * 25_000) + quote.lastSize = Math.floor(10 + this.#random() * 5_000) + quote.lastUpdatedAt = updatedAt + quote.volume += quote.lastSize + quote.turnover = roundMoney(quote.turnover + nextPrice * quote.lastSize) + + if (updateHistory) { + quote.history = [...quote.history.slice(-23), nextPrice] + } + } +} + +function createRandom(seed: number): () => number { + const runtime = { state: seed >>> 0 } + return () => { + runtime.state += 0x6d2b79f5 + const stateValue = runtime.state + const firstMix = Math.imul(stateValue ^ (stateValue >>> 15), stateValue | 1) + const secondMix = + firstMix + Math.imul(firstMix ^ (firstMix >>> 7), firstMix | 61) + const value = firstMix ^ secondMix + return ((value ^ (value >>> 14)) >>> 0) / 4_294_967_296 + } +} + +function roundPrice(value: number): number { + return Math.round(value * 100) / 100 +} + +function roundMoney(value: number): number { + return Math.round(value * 100) / 100 +} diff --git a/examples/svelte/realtime-trading/src/feed/worker/market-feed-protocol.ts b/examples/svelte/realtime-trading/src/feed/worker/market-feed-protocol.ts new file mode 100644 index 0000000000..21997ec89c --- /dev/null +++ b/examples/svelte/realtime-trading/src/feed/worker/market-feed-protocol.ts @@ -0,0 +1,70 @@ +export interface MarketQuoteSnapshot { + id: string + symbol: string + company: string + venue: string + previousClose: number + open: number + high: number + low: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + volume: number + turnover: number + history: Array +} + +export interface MarketQuoteUpdate { + index: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + high: number + low: number + volume: number + turnover: number + history?: Array +} + +export type MarketFeedCommand = + | { + type: 'start' + rowCount: number + running: boolean + ticksPerSecond: number + publishIntervalMs: number + updateSparklines: boolean + sparklineSampleIntervalMs: number + } + | { type: 'set-running'; running: boolean } + | { type: 'set-rate'; ticksPerSecond: number } + | { type: 'set-publish-interval'; intervalMs: number } + | { type: 'set-sparklines'; enabled: boolean } + | { type: 'set-sparkline-interval'; intervalMs: number } + | { type: 'reset'; rowCount: number } + | { type: 'burst'; tickCount: number } + +export type MarketFeedEvent = + | { + type: 'snapshot' + sessionId: number + quotes: Array + } + | { + type: 'updates' + sessionId: number + tickCount: number + coalescedUpdateCount: number + updates: Array + } diff --git a/examples/svelte/realtime-trading/src/feed/worker/market-feed.worker.ts b/examples/svelte/realtime-trading/src/feed/worker/market-feed.worker.ts new file mode 100644 index 0000000000..2b7a642fd9 --- /dev/null +++ b/examples/svelte/realtime-trading/src/feed/worker/market-feed.worker.ts @@ -0,0 +1,143 @@ +import { initialMarketFeedConfig } from '../market-feed-config' +import { MarketFeedEngine } from './market-feed-engine' +import type { + MarketFeedCommand, + MarketFeedEvent, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const engine = new MarketFeedEngine() +const pendingUpdates = new Map() +const runtime = { + sessionId: 0, + pendingTickCount: 0, + pendingCoalescedUpdateCount: 0, + initialized: false, + running: true, + ticksPerSecond: initialMarketFeedConfig.targetSamplesPerSecond, + publishIntervalMs: initialMarketFeedConfig.publishIntervalMs, + publishTimerId: null as ReturnType | null, + updateSparklines: initialMarketFeedConfig.updateSparklines, + sparklineSampleIntervalMs: initialMarketFeedConfig.sparklineSampleIntervalMs, + tickBudget: 0, + lastTickAt: performance.now(), +} + +addEventListener('message', ({ data }: MessageEvent) => { + switch (data.type) { + case 'start': + runtime.running = data.running + runtime.ticksPerSecond = data.ticksPerSecond + runtime.publishIntervalMs = data.publishIntervalMs + runtime.updateSparklines = data.updateSparklines + runtime.sparklineSampleIntervalMs = data.sparklineSampleIntervalMs + restartPublishTimer() + reset(data.rowCount) + break + case 'set-running': + runtime.running = data.running + break + case 'set-rate': + runtime.ticksPerSecond = data.ticksPerSecond + break + case 'set-publish-interval': + runtime.publishIntervalMs = Math.max(4, data.intervalMs) + restartPublishTimer() + break + case 'set-sparklines': + runtime.updateSparklines = data.enabled + break + case 'set-sparkline-interval': + runtime.sparklineSampleIntervalMs = Math.max(16, data.intervalMs) + break + case 'reset': + reset(data.rowCount) + break + case 'burst': + produceTicks(data.tickCount) + flush() + break + } +}) + +setInterval(() => { + const now = performance.now() + const elapsed = Math.min(100, Math.max(0, now - runtime.lastTickAt)) + runtime.lastTickAt = now + + if (runtime.initialized && runtime.running) { + runtime.tickBudget += (runtime.ticksPerSecond * elapsed) / 1_000 + const tickCount = Math.floor(runtime.tickBudget) + runtime.tickBudget -= tickCount + produceTicks(tickCount) + } +}, 16) + +restartPublishTimer() + +function reset(rowCount: number): void { + runtime.initialized = true + runtime.sessionId++ + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + runtime.tickBudget = 0 + runtime.lastTickAt = performance.now() + + post({ + type: 'snapshot', + sessionId: runtime.sessionId, + quotes: engine.reset(rowCount), + }) +} + +function produceTicks(tickCount: number): void { + if (!runtime.initialized || tickCount <= 0) return + + runtime.pendingTickCount += tickCount + for (const update of engine.applyTicks( + tickCount, + runtime.updateSparklines, + runtime.sparklineSampleIntervalMs, + )) { + const previousUpdate = pendingUpdates.get(update.index) + if (previousUpdate) runtime.pendingCoalescedUpdateCount++ + pendingUpdates.set(update.index, { + ...update, + ...(update.history || !previousUpdate?.history + ? {} + : { history: previousUpdate.history }), + }) + } +} + +function flush(): void { + if (runtime.pendingTickCount === 0) return + + const message: MarketFeedEvent = { + type: 'updates', + sessionId: runtime.sessionId, + tickCount: runtime.pendingTickCount, + coalescedUpdateCount: runtime.pendingCoalescedUpdateCount, + updates: [...pendingUpdates.values()], + } + + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + post(message) +} + +function restartPublishTimer(): void { + if (runtime.publishTimerId !== null) { + clearInterval(runtime.publishTimerId) + } + runtime.publishTimerId = setInterval( + flush, + Math.max(4, runtime.publishIntervalMs), + ) +} + +function post(event: MarketFeedEvent): void { + postMessage(event) +} diff --git a/examples/svelte/realtime-trading/src/index.css b/examples/svelte/realtime-trading/src/index.css new file mode 100644 index 0000000000..397c86fc54 --- /dev/null +++ b/examples/svelte/realtime-trading/src/index.css @@ -0,0 +1,1058 @@ +:root { + color-scheme: dark; + --font-ui: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + 'Segoe UI', sans-serif; + --font-mono: 'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace; + font-family: var(--font-ui); + font-synthesis: none; + --background: #050505; + --panel: #080808; + --panel-raised: #111111; + --panel-hover: #181818; + --surface-bar: #080808; + --surface-toolbar: #0d0d0d; + --surface-table: #050505; + --surface-header: #101010; + --surface-control: #151515; + --border: #303030; + --border-soft: #242424; + --border-strong: #4a4a4a; + --text: #e7ebf0; + --text-strong: #ffffff; + --text-inverse: #f7f9fb; + --muted: #737982; + --blue: #62a9ff; + --blue-soft: #a9d0ff; + --green: #42e488; + --red: #ff646b; + --amber: #dfb465; + --depth-bid: #315774; + --depth-ask: #634049; + --row-alt: rgb(255 255 255 / 1.8%); + --row-selected: rgb(66 132 214 / 16%); + --control-border: #354456; + --control-hover: #192431; + --sidebar-width: 18rem; + --shell-bar-height: 2.625rem; + --metrics-height: 3.5rem; + --statusbar-height: 1.625rem; + --virtual-footer-height: 2.125rem; + --table-header-height: 2rem; + --table-row-height: 2rem; + --shell-inline-padding: 0.75rem; + --table-cell-inline-padding: 0.6rem; + --control-radius: 1px; +} + +* { + box-sizing: border-box; +} + +html, +body { + min-width: 320px; + min-height: 100%; + margin: 0; + background: var(--background); +} + +body { + color: var(--text); +} + +button, +select, +input { + font: inherit; +} + +button, +select { + color: var(--text); + background: var(--panel-raised); + border: 1px solid var(--control-border); + border-radius: var(--control-radius); +} + +button { + padding: 0.5rem 0.65rem; + cursor: pointer; + font-size: 0.72rem; + font-weight: 650; + letter-spacing: 0.025em; +} + +button:hover { + background: var(--control-hover); + border-color: var(--border-strong); +} + +button:focus-visible, +select:focus-visible, +input:focus-visible { + outline: 1px solid var(--blue); + outline-offset: 1px; +} + +select { + width: 100%; + padding: 0.45rem 0.55rem; + font-size: 0.75rem; +} + +.trading-terminal { + --active-sidebar-width: var(--sidebar-width); + display: grid; + width: 100%; + height: 100dvh; + min-height: 0; + overflow: hidden; + background: var(--background); + grid-template-areas: + 'header sidebar' + 'content sidebar' + 'footer sidebar'; + grid-template-columns: minmax(0, 1fr) var(--active-sidebar-width); + grid-template-rows: auto minmax(0, 1fr) auto; + transition: grid-template-columns 160ms ease; +} + +.trading-terminal.is-sidebar-collapsed { + --active-sidebar-width: 0px; +} + +.shell-header { + display: flex; + min-width: 0; + flex-direction: column; + grid-area: header; +} + +.app-bar { + display: flex; + min-height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + background: var(--surface-bar); + border-bottom: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.68rem; + letter-spacing: 0.045em; +} + +.brand, +.header-actions, +.feed-status { + display: flex; + align-items: center; +} + +.brand { + gap: 0.65rem; + color: var(--text-strong); +} + +.header-actions { + gap: 0.75rem; +} + +.sidebar-toggle { + display: grid; + width: 1.9rem; + height: 1.9rem; + padding: 0; + place-items: center; + color: var(--muted); + background: transparent; + border-color: transparent; +} + +.sidebar-toggle:hover { + color: var(--text-strong); + background: var(--surface-control); + border-color: var(--border); +} + +.sidebar-toggle svg { + width: 1rem; + height: 1rem; + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-width: 1.4; +} + +.feed-status { + gap: 0.4rem; + color: var(--muted); +} + +.feed-status.is-running { + color: var(--green); +} + +.status-dot { + width: 6px; + height: 6px; + background: var(--muted); + border-radius: 50%; +} + +.feed-status.is-running .status-dot { + background: var(--green); +} + +.development-warning { + flex: 0 0 auto; + padding: 0.3rem 0.75rem; + color: var(--amber); + background: color-mix(in srgb, var(--amber) 8%, var(--background)); + border-bottom: 1px solid color-mix(in srgb, var(--amber) 24%, var(--border)); + font-family: var(--font-mono); + font-size: 0.62rem; + letter-spacing: 0.04em; +} + +.market-panel { + display: flex; + min-width: 0; + min-height: 0; + flex-direction: column; + background: var(--panel); + grid-area: content; +} + +.metrics-strip { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + background: var(--border); + border-bottom: 1px solid var(--border); + gap: 1px; +} + +.metrics-strip h2 { + margin: 0; + padding: 0.65rem var(--shell-inline-padding) 0.45rem; + color: var(--muted); + background: var(--surface-table); + font-size: 0.58rem; + grid-column: 1 / -1; + letter-spacing: 0.075em; +} + +.metrics-strip article { + min-width: 0; + min-height: 4.25rem; + padding: 0.5rem var(--shell-inline-padding); + background: var(--surface-bar); +} + +.metrics-strip span, +.metrics-strip small { + display: block; + color: var(--muted); + font-size: 0.56rem; + letter-spacing: 0.045em; + line-height: 1.35; +} + +.metrics-strip strong { + display: block; + margin: 0.12rem 0 0.08rem; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.88rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +.metrics-strip strong.metric-alert { + color: var(--amber); +} + +.table-scroll { + flex: 1; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +.virtual-scroll-footer { + display: flex; + flex: 0 0 auto; + align-items: center; + justify-content: space-between; + min-height: var(--virtual-footer-height); + padding: 0 var(--shell-inline-padding); + color: var(--muted); + background: var(--surface-toolbar); + border-top: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.68rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +table { + min-width: 100%; + border-spacing: 0; + table-layout: fixed; + font-family: var(--font-ui); + font-size: 0.78rem; + font-variant-numeric: tabular-nums; +} + +.virtual-table { + display: grid; +} + +.virtual-table thead { + display: grid; +} + +.virtual-table thead tr, +.virtual-table-row { + display: flex; + width: 100%; +} + +.virtual-table th, +.virtual-table-row > td { + flex: 0 0 auto; +} + +.virtual-table-body { + position: relative; + display: grid; +} + +.virtual-table-row { + position: absolute; + left: 0; + height: var(--table-row-height); +} + +.virtual-table-row > td { + display: block; +} + +.trading-data-grid { + display: grid; +} + +.trading-data-grid thead, +.trading-data-grid tbody { + display: grid; +} + +.trading-data-grid tbody { + -webkit-user-select: none; + user-select: none; +} + +.trading-data-grid thead > tr, +.trading-data-grid tbody > tr { + display: flex; + width: 100%; +} + +.trading-data-grid tbody > tr { + min-height: var(--table-row-height); + content-visibility: auto; + contain-intrinsic-block-size: var(--table-row-height); +} + +.trading-data-grid th, +.trading-data-grid td { + flex: 0 0 auto; +} + +thead { + position: sticky; + z-index: 2; + top: 0; +} + +th { + height: var(--table-header-height); + padding: 0 var(--table-cell-inline-padding); + color: var(--muted); + background: var(--surface-header); + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border); + font-size: 0.7rem; + font-weight: 500; + letter-spacing: 0.005em; + text-align: left; + white-space: nowrap; +} + +th.column-group-header { + color: #666b72; + font-size: 0.72rem; + font-weight: 500; + text-align: center; +} + +thead tr:first-child th.column-group-header { + color: #777d85; + font-size: 0.76rem; +} + +th.numeric-header { + text-align: right; +} + +td { + height: var(--table-row-height); + padding: 0 var(--table-cell-inline-padding); + overflow: hidden; + color: #eef1f5; + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border-soft); + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +th:last-child, +td:last-child { + border-right: 0; +} + +td[data-column-id='market'], +td[data-column-id='name'], +td[data-column-id='symbol'] { + text-align: left; +} + +td[data-column-id='market'] { + color: var(--blue); + font-weight: 550; +} + +td[data-column-id='name'] { + color: var(--text-strong); +} + +td[data-column-id='symbol'] { + color: #d8dde4; + font-weight: 600; +} + +tbody tr:nth-child(even) { + background: var(--row-alt); +} + +tbody tr:hover { + background: var(--panel-hover); +} + +tbody tr[data-symbol-selected='true'] { + background: var(--row-selected); + box-shadow: inset 2px 0 0 var(--blue); +} + +.table-scroll:focus { + outline: none; +} + +th { + position: relative; +} + +.leaf-header-content { + display: flex; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + height: 100%; + align-items: stretch; + margin-inline: calc(-1 * var(--table-cell-inline-padding)); +} + +.column-drag-handle, +.sort-header-button { + min-width: 0; + height: 100%; + padding: 0; + color: inherit; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-weight: inherit; + letter-spacing: inherit; +} + +.column-drag-handle { + flex: 0 0 1.05rem; + color: var(--muted); + cursor: grab; + opacity: 0.35; + font-size: 0.56rem; + letter-spacing: -0.32rem; + text-align: center; +} + +.column-drag-handle:active { + cursor: grabbing; +} + +th:hover .column-drag-handle, +.column-drag-handle:focus-visible { + opacity: 0.9; +} + +.column-drag-handle:hover, +.sort-header-button:hover { + background: rgb(255 255 255 / 4%); + border-color: transparent; +} + +th.is-column-dragging { + opacity: 0.45; +} + +th.is-column-drop-target { + background: rgb(50 139 255 / 16%); + box-shadow: inset 4px 0 0 var(--blue); +} + +th.is-column-drop-target::before { + position: absolute; + z-index: 6; + top: -1px; + bottom: -1px; + left: -2px; + width: 4px; + background: #62a9ff; + box-shadow: + 0 0 0 1px rgb(0 0 0 / 55%), + 0 0 12px rgb(70 151 255 / 90%); + content: ''; + pointer-events: none; +} + +.sort-header-button { + display: flex; + min-width: 0; + flex: 1; + align-items: center; + justify-content: flex-start; + gap: 0.3rem; + padding-inline: 0.25rem var(--table-cell-inline-padding); + cursor: default; + text-align: inherit; +} + +.numeric-header .sort-header-button { + justify-content: flex-end; +} + +.sort-header-button.is-sortable { + cursor: pointer; +} + +.sort-header-button:disabled { + opacity: 1; +} + +.header-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.sort-indicator { + flex: 0 0 auto; + color: #66717e; + font-size: 0.72rem; +} + +.sort-indicator.is-active { + color: var(--blue-soft); +} + +.column-resize-handle { + position: absolute; + z-index: 3; + top: 0; + right: -3px; + width: 7px; + height: 100%; + cursor: col-resize; + touch-action: none; + user-select: none; +} + +.column-resize-handle::after { + position: absolute; + top: 20%; + right: 3px; + width: 1px; + height: 60%; + background: var(--border-strong); + content: ''; + opacity: 0; +} + +th:hover > .column-resize-handle::after, +.column-resize-handle.is-resizing::after { + background: var(--blue); + opacity: 1; +} + +tbody tr[aria-selected='true'] { + background: rgb(76 145 228 / 13%); +} + +td[aria-selected='true'] { + position: relative; + background: rgb(70 139 222 / 12%); +} + +td[data-cell-focused='true'] { + background: rgb(70 139 222 / 21%); +} + +td[aria-selected='true']::after { + position: absolute; + z-index: 1; + inset: 0; + border: 1px solid transparent; + content: ''; + pointer-events: none; +} + +td[data-selection-top='true']::after { + border-top-color: var(--blue); +} + +td[data-selection-right='true']::after { + border-right-color: var(--blue); +} + +td[data-selection-bottom='true']::after { + border-bottom-color: var(--blue); +} + +td[data-selection-left='true']::after { + border-left-color: var(--blue); +} + +.price-button { + min-width: 4.5rem; + padding: 0; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-variant-numeric: tabular-nums; + font-weight: 600; + text-align: right; +} + +.price-button:hover { + background: transparent; + text-decoration: underline; + text-underline-offset: 2px; +} + +.move-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.move-cell.quote-up, +.percent-change-cell.quote-up { + background: color-mix(in srgb, var(--green) 7%, transparent); +} + +.move-cell.quote-down, +.percent-change-cell.quote-down { + background: color-mix(in srgb, var(--red) 7%, transparent); +} + +.percent-change-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.spread-cell { + display: flex; + align-items: baseline; + justify-content: flex-end; + gap: 0.35rem; + color: var(--text); +} + +.spread-cell small { + min-width: 2.8rem; + color: var(--muted); + font-size: 0.55rem; +} + +.spread-cell.spread-wide, +.spread-cell.spread-wide small { + color: var(--amber); +} + +.depth-cell { + position: relative; + display: flex; + height: 17px; + overflow: hidden; + background: var(--surface-control); +} + +.depth-bid, +.depth-ask { + height: 100%; + opacity: 0.78; +} + +.depth-bid { + background: var(--depth-bid); + border-right: 1px solid var(--panel); +} + +.depth-ask { + background: var(--depth-ask); +} + +.depth-values { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 0.28rem; + color: var(--text-strong); + font-size: 0.57rem; + text-shadow: 0 1px var(--background); +} + +.quote-age { + color: var(--muted); +} + +.quote-age-warm { + color: var(--amber); +} + +.quote-age-stale { + color: var(--red); +} + +.quote-up { + color: var(--green); +} + +.quote-down { + color: var(--red); +} + +.sparkline { + display: block; + width: 100%; + height: 1.35rem; + margin-left: auto; + color: var(--blue-soft); + overflow: visible; +} + +.sparkline.quote-up { + color: var(--green); +} + +.sparkline.quote-down { + color: var(--red); +} + +.sparkline polyline { + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-linejoin: miter; + stroke-width: 1.25; + vector-effect: non-scaling-stroke; +} + +.market-statusbar { + display: flex; + flex: 0 0 var(--statusbar-height); + min-height: var(--statusbar-height); + gap: 1.1rem; + align-items: center; + padding: 0 0.65rem; + color: var(--muted); + background: var(--surface-bar); + border-top: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.56rem; + grid-area: footer; + letter-spacing: 0.035em; +} + +.market-statusbar strong { + margin-left: 0.25rem; + color: var(--text); + font-weight: 500; +} + +.sidebar-slot { + width: var(--sidebar-width); + min-width: 0; + min-height: 0; + overflow: hidden; + background: var(--surface-table); + border-left: 1px solid var(--border); + grid-area: sidebar; + transition: + opacity 120ms ease, + transform 160ms ease, + visibility 160ms; +} + +.is-sidebar-collapsed .sidebar-slot { + visibility: hidden; + opacity: 0; + pointer-events: none; + transform: translateX(100%); +} + +.configurator { + width: 100%; + height: 100%; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +.configurator > header { + display: flex; + height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + color: var(--text-strong); + background: var(--surface-toolbar); + border-bottom: 1px solid var(--border); + font-size: 0.65rem; + font-weight: 700; + letter-spacing: 0.055em; +} + +.configurator > header small { + color: var(--muted); + font-size: 0.54rem; + font-weight: 500; +} + +.config-section { + display: grid; + gap: 0.7rem; + padding: 0.8rem var(--shell-inline-padding); + border-bottom: 1px solid var(--border); +} + +.config-section h2 { + margin: 0; + color: var(--muted); + font-size: 0.58rem; + letter-spacing: 0.075em; +} + +.primary-action { + width: 100%; + color: var(--text-inverse); + background: var(--blue); + border-color: var(--blue-soft); +} + +.primary-action:hover { + background: var(--blue-soft); + border-color: var(--text-strong); +} + +.field { + display: grid; + gap: 0.35rem; + color: var(--text); + font-size: 0.66rem; +} + +.rate-field > span { + display: flex; + justify-content: space-between; +} + +.rate-field strong { + color: var(--text); + font-family: var(--font-mono); + font-weight: 500; +} + +.field small { + color: var(--muted); + font-family: var(--font-mono); + font-size: 0.55rem; +} + +input[type='range'] { + width: 100%; + margin: 0; + accent-color: var(--blue); +} + +.toggle-field { + display: flex; + gap: 0.5rem; + align-items: flex-start; + color: var(--text); + font-size: 0.66rem; + line-height: 1.3; +} + +.toggle-field input { + margin: 0.12rem 0 0; + accent-color: var(--blue); +} + +.toggle-field small { + display: block; + margin-top: 0.14rem; + color: var(--muted); + font-size: 0.57rem; +} + +.action-grid { + display: grid; + grid-template-columns: 1fr; + gap: 0.4rem; +} + +.diagnostics dl, +.selected-instrument dl { + display: grid; + gap: 0; + margin: 0; +} + +.diagnostics dl > div, +.selected-instrument dl > div { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 24px; + border-bottom: 1px solid var(--border-soft); +} + +.diagnostics dl > div:last-child, +.selected-instrument dl > div:last-child { + border-bottom: 0; +} + +.diagnostics dl > div:has(dd[data-testid$='-breakdown']) { + display: grid; + grid-template-columns: minmax(0, 1fr); + align-content: center; + padding-block: 0.28rem; +} + +.diagnostics dd[data-testid$='-breakdown'] { + width: 100%; + overflow-x: auto; + padding-block: 0.12rem; + white-space: nowrap; + scrollbar-width: thin; +} + +dt { + color: var(--muted); + font-size: 0.61rem; +} + +dd { + margin: 0; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.62rem; +} + +.selection { + display: flex; + align-items: flex-start; + justify-content: space-between; +} + +.selection div { + display: grid; + gap: 0.18rem; +} + +.selection strong { + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.85rem; +} + +.selection span, +.selection small, +.selected-instrument p { + color: var(--muted); + font-size: 0.61rem; +} + +.selected-instrument p { + margin: 0; + line-height: 1.45; +} + +@media (max-width: 980px) { + :root { + --sidebar-width: 15.625rem; + } +} + +@media (max-width: 720px) { + .trading-terminal { + --active-sidebar-width: 0px; + height: 100dvh; + min-height: 0; + overflow: hidden; + } + + .market-panel { + min-height: 0; + } + + .table-scroll { + min-height: 0; + } + + .sidebar-slot { + position: fixed; + z-index: 20; + top: 0; + right: 0; + bottom: 0; + width: min(var(--sidebar-width), calc(100vw - 2.75rem)); + box-shadow: -18px 0 42px rgb(0 0 0 / 48%); + } + + .is-sidebar-collapsed .sidebar-slot { + box-shadow: none; + } +} diff --git a/examples/svelte/realtime-trading/src/main.ts b/examples/svelte/realtime-trading/src/main.ts new file mode 100644 index 0000000000..acece3d643 --- /dev/null +++ b/examples/svelte/realtime-trading/src/main.ts @@ -0,0 +1,5 @@ +import { mount } from 'svelte' +import App from './App.svelte' +import './index.css' + +mount(App, { target: document.getElementById('app')! }) diff --git a/examples/svelte/realtime-trading/src/shell/AppHeader.svelte b/examples/svelte/realtime-trading/src/shell/AppHeader.svelte new file mode 100644 index 0000000000..1c8553316a --- /dev/null +++ b/examples/svelte/realtime-trading/src/shell/AppHeader.svelte @@ -0,0 +1,18 @@ + + +
+
MARKET MONITOR
+
+ {!workerReady.current ? 'FEED CONNECTING' : running.current ? 'FEED LIVE' : 'FEED PAUSED'} + +
+
diff --git a/examples/svelte/realtime-trading/src/shell/Configurator.svelte b/examples/svelte/realtime-trading/src/shell/Configurator.svelte new file mode 100644 index 0000000000..f2fb024885 --- /dev/null +++ b/examples/svelte/realtime-trading/src/shell/Configurator.svelte @@ -0,0 +1,48 @@ + + + diff --git a/examples/svelte/realtime-trading/src/shell/Diagnostics.svelte b/examples/svelte/realtime-trading/src/shell/Diagnostics.svelte new file mode 100644 index 0000000000..8faf513bd6 --- /dev/null +++ b/examples/svelte/realtime-trading/src/shell/Diagnostics.svelte @@ -0,0 +1,43 @@ + + +

DIAGNOSTICS

+ {#each items as item (item[0])}
{item[0]}
{item[1]}
{/each} +
diff --git a/examples/svelte/realtime-trading/src/shell/MarketStatusbar.svelte b/examples/svelte/realtime-trading/src/shell/MarketStatusbar.svelte new file mode 100644 index 0000000000..21032c6d14 --- /dev/null +++ b/examples/svelte/realtime-trading/src/shell/MarketStatusbar.svelte @@ -0,0 +1,13 @@ + + +
+ MESSAGE SAMPLES {integer.format(state.current.metrics.lastBatchSize)} + CHANGED ROWS {integer.format(state.current.metrics.lastUpdateCount)} + HOSTS {integer.format(state.current.mountedCells)} + COMPONENTS {integer.format(state.current.liveComponents)} +
diff --git a/examples/svelte/realtime-trading/src/shell/MetricsStrip.svelte b/examples/svelte/realtime-trading/src/shell/MetricsStrip.svelte new file mode 100644 index 0000000000..3ab0f30117 --- /dev/null +++ b/examples/svelte/realtime-trading/src/shell/MetricsStrip.svelte @@ -0,0 +1,19 @@ + + +
+

LIVE HEALTH

+ {#each items as item (item.label)}
{item.label}{item.value}{item.detail}
{/each} +
THROUGHPUT{rate.format(metrics.rowUpdatesPerSecond)} rows/s{metrics.stateApplicationsPerSecond.toFixed(1)} snapshots/s · rows deduplicated per snapshot
+
diff --git a/examples/svelte/realtime-trading/src/shell/SelectedInstrument.svelte b/examples/svelte/realtime-trading/src/shell/SelectedInstrument.svelte new file mode 100644 index 0000000000..dbf747480e --- /dev/null +++ b/examples/svelte/realtime-trading/src/shell/SelectedInstrument.svelte @@ -0,0 +1,16 @@ + + +
+

SELECTED INSTRUMENT

+ {#if selectedQuote} +
{selectedQuote.symbol}{selectedQuote.company}
{selectedQuote.venue}
+
Last
{selectedQuote.price.toFixed(2)}
Bid / ask
{selectedQuote.bid.toFixed(2)} / {selectedQuote.ask.toFixed(2)}
+ {:else}

Click or begin a cell selection in any row to inspect its instrument.

{/if} +
diff --git a/examples/svelte/realtime-trading/src/shell/TradingShell.svelte b/examples/svelte/realtime-trading/src/shell/TradingShell.svelte new file mode 100644 index 0000000000..6406fa8b71 --- /dev/null +++ b/examples/svelte/realtime-trading/src/shell/TradingShell.svelte @@ -0,0 +1,15 @@ + + +
+
{ layout.sidebarOpen = !layout.sidebarOpen }} />{#if import.meta.env.DEV}{/if}
+
{@render children()}
+ + +
diff --git a/examples/svelte/realtime-trading/src/shell/configurator-options.ts b/examples/svelte/realtime-trading/src/shell/configurator-options.ts new file mode 100644 index 0000000000..49a9566fe7 --- /dev/null +++ b/examples/svelte/realtime-trading/src/shell/configurator-options.ts @@ -0,0 +1,55 @@ +export interface ConfiguratorOption { + readonly label: string + readonly value: TValue +} + +const instrumentCountOptions = [ + { label: '50', value: 50 }, + { label: '100', value: 100 }, + { label: '150', value: 150 }, + { label: '250', value: 250 }, + { label: '350', value: 350 }, + { label: '500', value: 500 }, + { label: '750', value: 750 }, + { label: '1,000', value: 1_000 }, + { label: '1,500', value: 1_500 }, + { label: '2,500', value: 2_500 }, + { label: '5,000', value: 5_000 }, + { label: '1,000,000', value: 1_000_000 }, + { label: '10,000,000', value: 10_000_000 }, +] as const satisfies ReadonlyArray> + +const workerDeliveryOptions = [ + { label: '8 ms · 125 msg/s', value: 8 }, + { label: '16 ms · 62.5 msg/s', value: 16 }, + { label: '20 ms · 50 msg/s', value: 20 }, + { label: '33 ms · 30 msg/s', value: 33 }, + { label: '50 ms · 20 msg/s', value: 50 }, + { label: '100 ms · 10 msg/s', value: 100 }, + { label: '250 ms · 4 msg/s', value: 250 }, + { label: '500 ms · 2 msg/s', value: 500 }, + { label: '1,000 ms · 1 msg/s', value: 1_000 }, +] as const satisfies ReadonlyArray> + +const rowRenderingOptions = [ + { label: 'Full DOM · render every row', value: 'none' }, + { label: 'TanStack Virtual · visible rows only', value: 'tanstack' }, +] as const satisfies ReadonlyArray> + +const intradaySamplingOptions = [ + { label: '16 ms · fastest', value: 16 }, + { label: '33 ms · very fast', value: 33 }, + { label: '50 ms · fast', value: 50 }, + { label: '100 ms', value: 100 }, + { label: '250 ms', value: 250 }, + { label: '500 ms', value: 500 }, + { label: '1,000 ms', value: 1_000 }, + { label: '2,000 ms', value: 2_000 }, +] as const satisfies ReadonlyArray> + +export const configuratorOptions = { + instrumentCounts: instrumentCountOptions, + workerDeliveryIntervals: workerDeliveryOptions, + rowRenderingModes: rowRenderingOptions, + intradaySamplingIntervals: intradaySamplingOptions, +} as const diff --git a/examples/svelte/realtime-trading/src/shell/trading-shell-context.ts b/examples/svelte/realtime-trading/src/shell/trading-shell-context.ts new file mode 100644 index 0000000000..25ab35c22c --- /dev/null +++ b/examples/svelte/realtime-trading/src/shell/trading-shell-context.ts @@ -0,0 +1,35 @@ +import { getContext, setContext } from 'svelte' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' + +interface TradingControllers { + benchmark: TradingBenchmarkController + feed: MarketFeedController +} + +const tradingControllersKey = Symbol('trading-controllers') + +export function provideTradingControllers( + benchmark: TradingBenchmarkController, +): void { + setContext(tradingControllersKey, { + benchmark, + feed: benchmark.feed, + }) +} + +export function useTradingShellController(): TradingBenchmarkController { + const controllers = getContext( + tradingControllersKey, + ) + if (!controllers) throw new Error('Missing trading controllers') + return controllers.benchmark +} + +export function useMarketFeedController(): MarketFeedController { + const controllers = getContext( + tradingControllersKey, + ) + if (!controllers) throw new Error('Missing trading controllers') + return controllers.feed +} diff --git a/examples/svelte/realtime-trading/src/table/TradingTable.svelte b/examples/svelte/realtime-trading/src/table/TradingTable.svelte new file mode 100644 index 0000000000..0c9e18b5e2 --- /dev/null +++ b/examples/svelte/realtime-trading/src/table/TradingTable.svelte @@ -0,0 +1,175 @@ + + +{#snippet renderRow(row: (typeof rows)[number], virtualRow?: VirtualItem)} + + {#each row.getVisibleCells() as cell (cell.id)}{@const edges = cell.getSelectionEdges()}{/each} + +{/snippet} + +
+ handleCellNavigation(table, event)}> + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + {#each headerGroup.headers as header (header.id)} + {@const isLeaf = header.subHeaders.length === 0}{@const sorted = header.column.getIsSorted()} + + {/each} + {/each} + + + + + pointerInteractions.handleMouseDown(table, event, controller.actions.selectSymbol)} onpointerover={(event) => pointerInteractions.handlePointerOver(table, event)} onmouseleave={() => pointerInteractions.resetPointerCell()} onclick={(event) => pointerInteractions.handleClick(table, event)}> + {#if virtualScrollMode === 'tanstack'} + {#each virtualRows as virtualRow (virtualRow.key)}{@render renderRow(rows[virtualRow.index], virtualRow)}{/each} + {:else} + {#each rows as row (row.id)}{@render renderRow(row)}{/each} + {/if} + +
+ {#if !header.isPlaceholder} + {#if isLeaf} +
{ event.preventDefault(); showColumnDropTarget(header.column.id, (event.currentTarget as HTMLElement).closest('th')) }} ondrop={(event) => { event.preventDefault(); const sourceId = event.dataTransfer?.getData('text/plain') || drag.columnId; if (sourceId) table.setColumnOrder(reorderColumnIds(table.getVisibleLeafColumns().map((column) => column.id), sourceId, header.column.id)); clearColumnDrag() }}> + + +
+ {#if header.column.getCanResize()}{/if} + {:else}{/if} + {/if} +
+
+{#if virtualScrollMode === 'tanstack'}
TanStack · Total · {rows.length} rows · {table.getVisibleLeafColumns().length} columns{visibleRange ? `Current · rows ${visibleRange.start}..${visibleRange.end}` : 'Current · rows —'}
{/if} diff --git a/examples/svelte/realtime-trading/src/table/table-config/DayChangeCell.svelte b/examples/svelte/realtime-trading/src/table/table-config/DayChangeCell.svelte new file mode 100644 index 0000000000..ac9fd4210c --- /dev/null +++ b/examples/svelte/realtime-trading/src/table/table-config/DayChangeCell.svelte @@ -0,0 +1,19 @@ + + +{#if mode.current === 'stable'} + +{:else if change >= 0} + +{:else} + +{/if} diff --git a/examples/svelte/realtime-trading/src/table/table-config/LastPriceCell.svelte b/examples/svelte/realtime-trading/src/table/table-config/LastPriceCell.svelte new file mode 100644 index 0000000000..2fe41997c7 --- /dev/null +++ b/examples/svelte/realtime-trading/src/table/table-config/LastPriceCell.svelte @@ -0,0 +1,11 @@ + + + selectSymbol(quote.symbol)} /> diff --git a/examples/svelte/realtime-trading/src/table/table-config/MoveCell.svelte b/examples/svelte/realtime-trading/src/table/table-config/MoveCell.svelte new file mode 100644 index 0000000000..0ecf1544b2 --- /dev/null +++ b/examples/svelte/realtime-trading/src/table/table-config/MoveCell.svelte @@ -0,0 +1,17 @@ + + +{indicator}{formatSigned(move)} diff --git a/examples/svelte/realtime-trading/src/table/table-config/PercentChangeCell.svelte b/examples/svelte/realtime-trading/src/table/table-config/PercentChangeCell.svelte new file mode 100644 index 0000000000..d108a65007 --- /dev/null +++ b/examples/svelte/realtime-trading/src/table/table-config/PercentChangeCell.svelte @@ -0,0 +1,10 @@ + + += 0} class:quote-down={value < 0} class="percent-change-cell">{value >= 0 ? '+' : ''}{value.toFixed(2)}% diff --git a/examples/svelte/realtime-trading/src/table/table-config/PriceCell.svelte b/examples/svelte/realtime-trading/src/table/table-config/PriceCell.svelte new file mode 100644 index 0000000000..4f25bd5fd5 --- /dev/null +++ b/examples/svelte/realtime-trading/src/table/table-config/PriceCell.svelte @@ -0,0 +1,10 @@ + + + diff --git a/examples/svelte/realtime-trading/src/table/table-config/SparklineCell.svelte b/examples/svelte/realtime-trading/src/table/table-config/SparklineCell.svelte new file mode 100644 index 0000000000..bee2789d9d --- /dev/null +++ b/examples/svelte/realtime-trading/src/table/table-config/SparklineCell.svelte @@ -0,0 +1,12 @@ + + + diff --git a/examples/svelte/realtime-trading/src/table/table-config/quote-cells.ts b/examples/svelte/realtime-trading/src/table/table-config/quote-cells.ts new file mode 100644 index 0000000000..ddc96e7296 --- /dev/null +++ b/examples/svelte/realtime-trading/src/table/table-config/quote-cells.ts @@ -0,0 +1,75 @@ +export const quoteCellLifecycle = { created: 0, destroyed: 0 } + +export const quoteCellRendererNames = [ + 'Market', + 'Name', + 'Symbol', + 'Last', + 'Change', + 'ChangePercent', + 'Bid', + 'BidVolume', + 'Ask', + 'AskVolume', + 'Open', + 'High', + 'Low', + 'Intraday', +] as const + +export const quoteComponentNames = [ + 'PriceCell', + 'StableMoveCell', + 'UpMoveCell', + 'DownMoveCell', + 'PercentChangeCell', + 'SparklineCell', +] as const + +export type QuoteCellRendererName = (typeof quoteCellRendererNames)[number] +export type QuoteComponentName = (typeof quoteComponentNames)[number] + +const createCounterMap = (names: ReadonlyArray) => + Object.fromEntries(names.map((name) => [name, 0])) as Record + +export const quoteRenderDiagnostics = { + cellRendererCalls: 0, + componentRenderCalls: 0, + cellRendererCallsByName: createCounterMap(quoteCellRendererNames), + componentRenderCallsByName: createCounterMap(quoteComponentNames), +} + +export function recordCellRender(name: QuoteCellRendererName, value: T): T { + quoteRenderDiagnostics.cellRendererCalls++ + quoteRenderDiagnostics.cellRendererCallsByName[name]++ + return value +} + +export function recordComponentRender(name: QuoteComponentName): void { + quoteRenderDiagnostics.componentRenderCalls++ + quoteRenderDiagnostics.componentRenderCallsByName[name]++ +} + +export function formatSigned(value: number): string { + return `${value >= 0 ? '+' : ''}${value.toFixed(2)}` +} + +export function sparklinePoints(values: ReadonlyArray): string { + const first = values[0] ?? 0 + const range = values.reduce( + (current, value) => ({ + min: Math.min(current.min, value), + max: Math.max(current.max, value), + }), + { min: first, max: first }, + ) + const height = range.max - range.min || 1 + const denominator = Math.max(1, values.length - 1) + return values + .map((value, index) => { + const x = (index / denominator) * 100 + const y = 22 - ((value - range.min) / height) * 20 + return `${x.toFixed(1)},${y.toFixed(1)}` + }) + .join(' ') +} diff --git a/examples/svelte/realtime-trading/src/table/table-config/trading-columns.ts b/examples/svelte/realtime-trading/src/table/table-config/trading-columns.ts new file mode 100644 index 0000000000..27461145be --- /dev/null +++ b/examples/svelte/realtime-trading/src/table/table-config/trading-columns.ts @@ -0,0 +1,202 @@ +import { createColumnHelper, renderComponent } from '@tanstack/svelte-table' +import { tradingFeatures } from '../trading-features' +import DayChangeCell from './DayChangeCell.svelte' +import LastPriceCell from './LastPriceCell.svelte' +import PercentChangeCell from './PercentChangeCell.svelte' +import SparklineCell from './SparklineCell.svelte' +import { recordCellRender } from './quote-cells' +import type { MarketQuote } from '../../feed/market-data' + +export type RendererMode = 'stable' | 'swap' +export interface CoreTableState { + sorting: Array<{ id: string; desc: boolean }> + columnFilters: Array<{ id: string; value: unknown }> +} + +const compactFormatter = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +const columnHelper = createColumnHelper() + +export const tradingColumns = columnHelper.columns([ + columnHelper.group({ + id: 'instrument', + header: 'Instrument', + columns: columnHelper.columns([ + columnHelper.accessor('venue', { + id: 'market', + header: 'Market', + size: 72, + cell: (info) => recordCellRender('Market', info.getValue()), + }), + columnHelper.accessor('company', { + id: 'name', + header: 'Name', + size: 180, + cell: (info) => recordCellRender('Name', info.getValue()), + }), + columnHelper.accessor('symbol', { + header: 'Symbol', + size: 92, + filterFn: 'includesString', + cell: (info) => recordCellRender('Symbol', info.getValue()), + }), + ]), + }), + columnHelper.group({ + id: 'priceAndChange', + header: 'Price & Change', + columns: columnHelper.columns([ + columnHelper.accessor('price', { + header: 'Price', + size: 96, + sortFn: 'basic', + cell: (info) => + recordCellRender( + 'Last', + renderComponent(LastPriceCell, { quote: info.row.original }), + ), + }), + columnHelper.accessor(getDayChange, { + id: 'change', + header: 'Chg', + size: 94, + cell: (info) => + recordCellRender( + 'Change', + renderComponent(DayChangeCell, { quote: info.row.original }), + ), + }), + columnHelper.accessor(getDayChangePercent, { + id: 'changePercent', + header: 'Chg%', + size: 90, + cell: (info) => + recordCellRender( + 'ChangePercent', + renderComponent(PercentChangeCell, { value: info.getValue() }), + ), + }), + ]), + }), + columnHelper.group({ + id: 'orderBook', + header: 'Order Book', + columns: columnHelper.columns([ + columnHelper.accessor('bid', { + header: 'Bid', + size: 90, + cell: (info) => recordCellRender('Bid', info.getValue().toFixed(2)), + }), + columnHelper.accessor('bidSize', { + header: 'Bid Vol', + size: 100, + cell: (info) => + recordCellRender( + 'BidVolume', + compactFormatter.format(info.getValue()), + ), + }), + columnHelper.accessor('ask', { + header: 'Ask', + size: 90, + cell: (info) => recordCellRender('Ask', info.getValue().toFixed(2)), + }), + columnHelper.accessor('askSize', { + header: 'Ask Vol', + size: 100, + cell: (info) => + recordCellRender( + 'AskVolume', + compactFormatter.format(info.getValue()), + ), + }), + ]), + }), + columnHelper.group({ + id: 'session', + header: 'Session', + columns: columnHelper.columns([ + columnHelper.accessor('open', { + header: 'Open', + size: 90, + cell: (info) => recordCellRender('Open', info.getValue().toFixed(2)), + }), + columnHelper.accessor('high', { + header: 'High', + size: 90, + cell: (info) => recordCellRender('High', info.getValue().toFixed(2)), + }), + columnHelper.accessor('low', { + header: 'Low', + size: 90, + cell: (info) => recordCellRender('Low', info.getValue().toFixed(2)), + }), + ]), + }), + columnHelper.group({ + id: 'chart', + header: 'Chart', + columns: columnHelper.columns([ + columnHelper.accessor('history', { + header: 'Intraday', + size: 150, + enableSorting: false, + cell: (info) => + recordCellRender( + 'Intraday', + renderComponent(SparklineCell, { values: info.getValue() }), + ), + }), + ]), + }), +]) + +export const rowModelDiagnostics = { + hasMeasurement: false, + calls: 0, + totalDurationMs: 0, + maxDurationMs: 0, + lastRowCount: 0, +} +export const TRADING_COLUMN_COUNT = 14 + +export function readMeasuredRows(readRows: () => Array): Array { + const start = performance.now() + const rows = readRows() + const end = performance.now() + const duration = end - start + rowModelDiagnostics.calls++ + rowModelDiagnostics.hasMeasurement = true + rowModelDiagnostics.totalDurationMs += duration + rowModelDiagnostics.maxDurationMs = Math.max( + rowModelDiagnostics.maxDurationMs, + duration, + ) + rowModelDiagnostics.lastRowCount = rows.length + if ((rowModelDiagnostics.calls - 1) % 20 === 0) { + try { + performance.measure('tanstack-row-model', { + start, + end, + detail: { rowCount: rows.length }, + }) + if (rowModelDiagnostics.calls % 20_000 === 0) { + performance.clearMeasures('tanstack-row-model') + } + } catch { + /* User Timing Level 3 is optional. */ + } + } + return rows +} + +export function getDayChange(quote: MarketQuote): number { + return quote.price - quote.previousClose +} +export function getDayChangePercent(quote: MarketQuote): number { + return quote.previousClose === 0 + ? 0 + : (getDayChange(quote) / quote.previousClose) * 100 +} diff --git a/examples/svelte/realtime-trading/src/table/table-interactions.ts b/examples/svelte/realtime-trading/src/table/table-interactions.ts new file mode 100644 index 0000000000..99649a40bd --- /dev/null +++ b/examples/svelte/realtime-trading/src/table/table-interactions.ts @@ -0,0 +1,187 @@ +export type CellDirection = 'up' | 'down' | 'left' | 'right' + +interface RowSelectionTable { + resetRowSelection: (defaultState?: boolean) => void +} + +interface SelectableRow { + getIsSelected: () => boolean + getToggleSelectedHandler: (options?: { + selectChildren?: boolean + }) => (event: unknown) => void +} + +interface SelectableGridCell { + row: SelectableGridRow + getSelectionStartHandler: ( + contextDocument?: Document, + ) => (event: unknown) => void + getSelectionExtendHandler: () => (event: unknown) => void +} + +interface SelectableGridRow extends SelectableRow { + original: { symbol: string } + getAllCellsByColumnId: () => Record +} + +interface TradingGridTable extends RowSelectionTable { + getRowModel: () => { + rowsById: Record + } +} + +interface SelectionCellTarget { + element: HTMLTableCellElement + cell: SelectableGridCell +} + +interface CellNavigationTable { + extendCellSelection: (direction: CellDirection) => void + moveCellSelection: (direction: CellDirection) => void + resetCellSelection: (defaultState?: boolean) => void + selectAllCells: () => void +} + +const keyDirections: Partial> = { + ArrowUp: 'up', + ArrowDown: 'down', + ArrowLeft: 'left', + ArrowRight: 'right', +} + +export function reorderColumnIds( + columnIds: Array, + sourceId: string, + targetId: string, +): Array { + if (sourceId === targetId || !columnIds.includes(sourceId)) return columnIds + + const withoutSource = columnIds.filter((id) => id !== sourceId) + const targetIndex = withoutSource.indexOf(targetId) + if (targetIndex < 0) return columnIds + + return [ + ...withoutSource.slice(0, targetIndex), + sourceId, + ...withoutSource.slice(targetIndex), + ] +} + +export function selectRowFromPointer( + table: RowSelectionTable, + row: SelectableRow, + event: MouseEvent, +): void { + const additive = event.ctrlKey || event.metaKey + const checked = additive ? !row.getIsSelected() : true + + if (!event.shiftKey && !additive) table.resetRowSelection(true) + + row.getToggleSelectedHandler({ selectChildren: false })({ + target: { checked }, + shiftKey: event.shiftKey, + ctrlKey: event.ctrlKey, + metaKey: event.metaKey, + }) +} + +export class TradingGridPointerController { + #lastPointerCell: HTMLTableCellElement | null = null + + handleMouseDown( + table: TradingGridTable, + event: MouseEvent, + selectSymbol: (symbol: string) => void, + ): void { + if (event.button !== 0) return + + const target = this.#findCellTarget(table, event.composedPath()) + if (!target) return + + event.preventDefault() + this.#lastPointerCell = target.element + selectSymbol(target.cell.row.original.symbol) + target.cell.getSelectionStartHandler(target.element.ownerDocument)(event) + } + + handlePointerOver(table: TradingGridTable, event: MouseEvent): void { + if ((event.buttons & 1) === 0) { + this.resetPointerCell() + return + } + + const target = this.#findCellTarget(table, event.composedPath()) + if (!target || target.element === this.#lastPointerCell) return + + this.#lastPointerCell = target.element + target.cell.getSelectionExtendHandler()(event) + } + + handleClick(table: TradingGridTable, event: MouseEvent): void { + const target = this.#findCellTarget(table, event.composedPath()) + if (!target) return + selectRowFromPointer(table, target.cell.row, event) + } + + resetPointerCell(): void { + this.#lastPointerCell = null + } + + #findCellTarget( + table: TradingGridTable, + path: Array, + ): SelectionCellTarget | null { + for (const target of path) { + if (!(target instanceof HTMLTableCellElement)) continue + + const columnId = target.dataset['columnId'] + const rowId = + target.closest('tr[data-row-id]')?.dataset['rowId'] + if (!columnId || !rowId) return null + + const row = table.getRowModel().rowsById[rowId] + const cell = row.getAllCellsByColumnId()[columnId] + return { element: target, cell } + } + + return null + } +} + +export function handleCellNavigation( + table: CellNavigationTable, + event: KeyboardEvent, +): void { + if (event.key === 'Escape') { + event.preventDefault() + table.resetCellSelection(true) + return + } + + if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'a') { + event.preventDefault() + table.selectAllCells() + return + } + + const direction = keyDirections[event.key] + if (!direction) return + + event.preventDefault() + if (event.shiftKey) table.extendCellSelection(direction) + else table.moveCellSelection(direction) +} + +export function sortIndicator(direction: false | 'asc' | 'desc'): string { + if (direction === 'asc') return '↑' + if (direction === 'desc') return '↓' + return '↕' +} + +export function sortAriaValue( + direction: false | 'asc' | 'desc', +): 'ascending' | 'descending' | 'none' { + if (direction === 'asc') return 'ascending' + if (direction === 'desc') return 'descending' + return 'none' +} diff --git a/examples/svelte/realtime-trading/src/table/trading-features.ts b/examples/svelte/realtime-trading/src/table/trading-features.ts new file mode 100644 index 0000000000..dedf4d1c5e --- /dev/null +++ b/examples/svelte/realtime-trading/src/table/trading-features.ts @@ -0,0 +1,16 @@ +import { + createFilteredRowModel, + createSortedRowModel, + filterFn_includesString, + sortFn_basic, + stockFeatures, + tableFeatures, +} from '@tanstack/svelte-table' + +export const tradingFeatures = tableFeatures({ + ...stockFeatures, + filteredRowModel: createFilteredRowModel(), + sortedRowModel: createSortedRowModel(), + filterFns: { includesString: filterFn_includesString }, + sortFns: { basic: sortFn_basic }, +}) diff --git a/examples/svelte/realtime-trading/src/table/trading-row-virtualizer.ts b/examples/svelte/realtime-trading/src/table/trading-row-virtualizer.ts new file mode 100644 index 0000000000..bc4b34b528 --- /dev/null +++ b/examples/svelte/realtime-trading/src/table/trading-row-virtualizer.ts @@ -0,0 +1,18 @@ +export const TRADING_ROW_HEIGHT = 32 +export const TRADING_ROW_OVERSCAN = 10 +export const DEFAULT_VIRTUALIZATION_ROW_COUNT = 200 +export const FORCED_VIRTUALIZATION_ROW_COUNT = 1_500 + +export type VirtualScrollMode = 'tanstack' | 'none' +export type VirtualScrollPreference = VirtualScrollMode | 'auto' + +export function resolveVirtualScrollMode( + requestedMode: VirtualScrollPreference, + instrumentCount: number, +): VirtualScrollMode { + if (instrumentCount >= FORCED_VIRTUALIZATION_ROW_COUNT) return 'tanstack' + if (requestedMode !== 'auto') return requestedMode + return instrumentCount >= DEFAULT_VIRTUALIZATION_ROW_COUNT + ? 'tanstack' + : 'none' +} diff --git a/examples/svelte/realtime-trading/src/table/trading-table.ts b/examples/svelte/realtime-trading/src/table/trading-table.ts new file mode 100644 index 0000000000..77e4e6bee1 --- /dev/null +++ b/examples/svelte/realtime-trading/src/table/trading-table.ts @@ -0,0 +1,9 @@ +export { + TRADING_COLUMN_COUNT, + rowModelDiagnostics, +} from './table-config/trading-columns' +export type { + CoreTableState, + RendererMode, +} from './table-config/trading-columns' +export type { VirtualScrollMode } from './trading-row-virtualizer' diff --git a/examples/svelte/realtime-trading/src/vite-env.d.ts b/examples/svelte/realtime-trading/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/svelte/realtime-trading/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/svelte/realtime-trading/tests/e2e/smoke.spec.ts b/examples/svelte/realtime-trading/tests/e2e/smoke.spec.ts new file mode 100644 index 0000000000..4c1aeb6251 --- /dev/null +++ b/examples/svelte/realtime-trading/tests/e2e/smoke.spec.ts @@ -0,0 +1,189 @@ +import path from 'node:path' +import { expect, test } from '@playwright/test' +import { startExampleServer } from '../../../../../tests/e2e/helpers/startExampleServer' +import { + setRangeValue, + scrollTradingTable, + resumeTradingFeed, + pausedFeedUrl, +} from '../../../../../tests/e2e/helpers/setRangeValue' +import type { Page } from '@playwright/test' + +const exampleDir = path.resolve() + +function collectPageErrors(page: Page) { + const errors: Array = [] + page.on('pageerror', (error) => errors.push(error.message)) + page.on('console', (message) => { + if (message.type() === 'error') errors.push(message.text()) + }) + return errors +} + +test('runs the Svelte realtime trading workload', async ({ page }) => { + test.setTimeout(120_000) + const server = await startExampleServer(exampleDir) + const errors = collectPageErrors(page) + + try { + await page.goto(pausedFeedUrl(server.url)) + + const table = page.getByTestId('trading-table') + const instrumentCount = page.getByTestId('instrument-count-select') + const virtualScrollSelect = page.getByTestId('virtual-scroll-select') + await expect(table).toBeVisible() + await expect(instrumentCount).toHaveValue('100') + await expect(page.locator('.brand')).toHaveText('MARKET MONITOR') + await expect(virtualScrollSelect).toHaveValue('none') + await expect(virtualScrollSelect).toBeEnabled() + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(table.locator('tbody')).toHaveCSS('user-select', 'none') + await expect(table.locator('tbody tr').first()).toHaveCSS( + 'content-visibility', + 'auto', + ) + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await instrumentCount.selectOption('250') + await expect(virtualScrollSelect).toHaveValue('tanstack') + await expect(virtualScrollSelect).toBeEnabled() + await expect.poll(() => table.locator('tbody tr').count()).toBeLessThan(250) + await expect(page.getByTestId('virtual-scroll-footer')).toBeVisible() + await instrumentCount.selectOption('100') + await expect(virtualScrollSelect).toHaveValue('none') + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await virtualScrollSelect.selectOption('tanstack') + await expect.poll(() => table.locator('tbody tr').count()).toBeLessThan(100) + await expect(table.locator('tbody tr').first()).toHaveCSS( + 'content-visibility', + 'auto', + ) + await expect(page.getByTestId('virtual-scroll-footer')).toBeVisible() + await virtualScrollSelect.selectOption('none') + await expect(table.locator('tbody tr')).toHaveCount(100) + await instrumentCount.selectOption('1500') + await expect(virtualScrollSelect).toHaveValue('tanstack') + await expect(virtualScrollSelect).toBeDisabled() + await expect + .poll(() => table.locator('tbody tr').count()) + .toBeLessThan(1500) + await expect(page.getByTestId('virtual-scroll-footer')).toContainText( + 'Total · 1500 rows · 14 columns', + ) + await expect(page.getByTestId('visible-row-range')).toHaveText( + /^\s*Current · rows 0\.\.\d+\s*$/, + ) + await scrollTradingTable(page, 2_000) + await expect + .poll(async () => + Number( + await table + .locator('tbody tr') + .first() + .getAttribute('data-virtual-index'), + ), + ) + .toBeGreaterThan(0) + await expect(page.getByTestId('visible-row-range')).toHaveText( + /^\s*Current · rows [1-9]\d*\.\.\d+\s*$/, + ) + await instrumentCount.selectOption('100') + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await expect(virtualScrollSelect).toHaveValue('none') + await expect(virtualScrollSelect).toBeEnabled() + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(table.locator('thead tr')).toHaveCount(2) + await expect(table.locator('thead tr').last().locator('th')).toHaveCount(14) + await expect(table.locator('thead')).not.toContainText('Identity') + await expect(table.locator('thead')).not.toContainText('Market Data') + await expect(table.locator('thead')).toContainText('Market') + await expect(table.locator('thead')).toContainText('Bid Vol') + await expect(table.locator('thead')).toContainText('Intraday') + const selectedRow = table.locator('tbody tr').first() + const selectedSymbol = await selectedRow.getAttribute('data-symbol') + await selectedRow.locator('td').nth(1).click() + await expect(page.getByTestId('selected-instrument')).toContainText( + selectedSymbol ?? '', + ) + await expect(page.getByTestId('feed-status')).toHaveText('FEED PAUSED') + await expect(instrumentCount.locator('option[value="150"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="350"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="750"]')).toHaveCount(1) + + const targetRateSlider = page.getByTestId('target-rate-slider') + await expect(targetRateSlider).toHaveAttribute('min', '0') + await expect(targetRateSlider).toHaveAttribute('max', '9') + await expect(targetRateSlider).toHaveAttribute('step', '1') + await expect(targetRateSlider).toHaveValue('6') + await setRangeValue(targetRateSlider, '7') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '25K samples/s', + ) + await setRangeValue(targetRateSlider, '8') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '50K samples/s', + ) + await setRangeValue(targetRateSlider, '6') + + const sparklineInterval = page.getByTestId( + 'sparkline-sample-interval-select', + ) + await expect(sparklineInterval).toHaveValue('16') + await sparklineInterval.selectOption('100') + await expect(sparklineInterval).toHaveValue('100') + await sparklineInterval.selectOption('16') + + const publishInterval = page.getByTestId('publish-interval-select') + await expect(publishInterval.locator('option[value="500"]')).toHaveCount(1) + await expect(publishInterval.locator('option[value="1000"]')).toHaveCount(1) + await publishInterval.selectOption('100') + + await resumeTradingFeed(page) + + await expect + .poll(async () => { + const text = await page.getByTestId('row-update-rate').textContent() + return Number(text?.replace(/\D/g, '') ?? 0) + }) + .toBeGreaterThan(0) + await expect + .poll(async () => { + const text = await page.getByTestId('worker-messages').textContent() + return Number(text?.replace(/\D/g, '') ?? 0) + }) + .toBeGreaterThan(0) + await expect + .poll(async () => + Number(await page.getByTestId('message-rate').textContent()), + ) + .toBeGreaterThan(0) + await expect + .poll(async () => + Number(await page.getByTestId('table-render-rate').textContent()), + ) + .toBeGreaterThan(0) + + const firstPrice = page.locator('tbody tr').first().getByRole('button') + const priceBeforeUpdate = await firstPrice.textContent() + await expect + .poll(() => firstPrice.textContent()) + .not.toBe(priceBeforeUpdate) + + await page.locator('.config-section input[type="checkbox"]').first().check() + await page.getByTestId('feed-toggle').click() + await expect(page.getByTestId('feed-toggle')).toHaveText('START FEED') + await expect(page.getByTestId('feed-status')).toHaveText('FEED PAUSED') + + await instrumentCount.selectOption('750') + await expect.poll(() => table.locator('tbody tr').count()).toBeLessThan(750) + expect( + await page.evaluate( + () => performance.getEntriesByName('tanstack-row-model').length > 0, + ), + ).toBe(true) + + expect(errors).toEqual([]) + } finally { + await server.close() + } +}) diff --git a/examples/svelte/realtime-trading/tsconfig.json b/examples/svelte/realtime-trading/tsconfig.json new file mode 100644 index 0000000000..f5abb31723 --- /dev/null +++ b/examples/svelte/realtime-trading/tsconfig.json @@ -0,0 +1,25 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["svelte", "vite/client"] + }, + "include": [ + "src/**/*.d.ts", + "src/**/*.ts", + "src/**/*.svelte", + "tests/**/*.ts", + "vite.config.ts" + ] +} diff --git a/examples/svelte/realtime-trading/vite.config.ts b/examples/svelte/realtime-trading/vite.config.ts new file mode 100644 index 0000000000..476cc68e22 --- /dev/null +++ b/examples/svelte/realtime-trading/vite.config.ts @@ -0,0 +1,7 @@ +import { svelte } from '@sveltejs/vite-plugin-svelte' +import { defineConfig } from 'vite' + +export default defineConfig({ + server: { port: 7777, allowedHosts: true }, + plugins: [svelte()], +}) diff --git a/examples/svelte/row-pinning/package.json b/examples/svelte/row-pinning/package.json index 9735c3478d..cbf76f2750 100644 --- a/examples/svelte/row-pinning/package.json +++ b/examples/svelte/row-pinning/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/row-selection/package.json b/examples/svelte/row-selection/package.json index b9c49a2479..8a09990fd8 100644 --- a/examples/svelte/row-selection/package.json +++ b/examples/svelte/row-selection/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/sorting/package.json b/examples/svelte/sorting/package.json index 3bd34e208d..aff266988e 100644 --- a/examples/svelte/sorting/package.json +++ b/examples/svelte/sorting/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/spreadsheet/package.json b/examples/svelte/spreadsheet/package.json index 83eff5d638..e8b799a762 100644 --- a/examples/svelte/spreadsheet/package.json +++ b/examples/svelte/spreadsheet/package.json @@ -12,16 +12,17 @@ "test:types": "svelte-check --tsconfig ./tsconfig.json" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-hotkeys": "^0.10.0", "@tanstack/svelte-table": "^9.2.3", - "@tanstack/svelte-virtual": "^3.13.35", + "@tanstack/svelte-virtual": "^3.13.36", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/sub-components/package.json b/examples/svelte/sub-components/package.json index 1ef9671379..a8727388c2 100644 --- a/examples/svelte/sub-components/package.json +++ b/examples/svelte/sub-components/package.json @@ -11,14 +11,15 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/virtualized-columns/package.json b/examples/svelte/virtualized-columns/package.json index 0afdc9cf95..81f317f154 100644 --- a/examples/svelte/virtualized-columns/package.json +++ b/examples/svelte/virtualized-columns/package.json @@ -11,15 +11,16 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", - "@tanstack/svelte-virtual": "^3.13.35", + "@tanstack/svelte-virtual": "^3.13.36", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/virtualized-infinite-scrolling/package.json b/examples/svelte/virtualized-infinite-scrolling/package.json index 0810322040..a157cfb5b8 100644 --- a/examples/svelte/virtualized-infinite-scrolling/package.json +++ b/examples/svelte/virtualized-infinite-scrolling/package.json @@ -11,16 +11,17 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-query": "^6.1.38", "@tanstack/svelte-table": "^9.2.3", - "@tanstack/svelte-virtual": "^3.13.35", + "@tanstack/svelte-virtual": "^3.13.36", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/virtualized-rows/package.json b/examples/svelte/virtualized-rows/package.json index 9fd10b576c..95917cfbeb 100644 --- a/examples/svelte/virtualized-rows/package.json +++ b/examples/svelte/virtualized-rows/package.json @@ -11,15 +11,16 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tanstack/svelte-table": "^9.2.3", - "@tanstack/svelte-virtual": "^3.13.35", + "@tanstack/svelte-virtual": "^3.13.36", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" } } diff --git a/examples/svelte/with-tanstack-form/package.json b/examples/svelte/with-tanstack-form/package.json index f8c5e433c8..2b1c637220 100644 --- a/examples/svelte/with-tanstack-form/package.json +++ b/examples/svelte/with-tanstack-form/package.json @@ -11,18 +11,19 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "dependencies": { "@tanstack/form-core": "^1.33.5", - "@tanstack/svelte-devtools": "^0.1.3", + "@tanstack/svelte-devtools": "^0.1.6", "@tanstack/svelte-form": "^1.33.5", "@tanstack/svelte-table": "^9.2.3", "@tanstack/table-devtools": "^9.2.0", diff --git a/examples/svelte/with-tanstack-query/package.json b/examples/svelte/with-tanstack-query/package.json index e2d928ae99..4b0bfa86f6 100644 --- a/examples/svelte/with-tanstack-query/package.json +++ b/examples/svelte/with-tanstack-query/package.json @@ -11,18 +11,19 @@ "lint": "eslint ./src" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "dependencies": { "@tanstack/query-devtools": "^5.101.4", - "@tanstack/svelte-devtools": "^0.1.3", + "@tanstack/svelte-devtools": "^0.1.6", "@tanstack/svelte-query": "^6.1.38", "@tanstack/svelte-query-devtools": "^6.1.38", "@tanstack/svelte-table": "^9.2.3", diff --git a/examples/vanilla/aggregation/package.json b/examples/vanilla/aggregation/package.json index 558c3133eb..d4581c8c23 100644 --- a/examples/vanilla/aggregation/package.json +++ b/examples/vanilla/aggregation/package.json @@ -11,11 +11,12 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/node": "^26.2.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "dependencies": { "@tanstack/table-core": "^9.2.3" diff --git a/examples/vanilla/basic/package.json b/examples/vanilla/basic/package.json index d838232704..6756e6d48a 100644 --- a/examples/vanilla/basic/package.json +++ b/examples/vanilla/basic/package.json @@ -11,11 +11,12 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/node": "^26.2.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "dependencies": { "@tanstack/table-core": "^9.2.3" diff --git a/examples/vanilla/pagination/package.json b/examples/vanilla/pagination/package.json index bc70629a6d..9276326b84 100644 --- a/examples/vanilla/pagination/package.json +++ b/examples/vanilla/pagination/package.json @@ -11,11 +11,12 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/node": "^26.2.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "dependencies": { "@tanstack/table-core": "^9.2.3" diff --git a/examples/vanilla/sorting/package.json b/examples/vanilla/sorting/package.json index 507359dc1c..b14f2550c4 100644 --- a/examples/vanilla/sorting/package.json +++ b/examples/vanilla/sorting/package.json @@ -11,11 +11,12 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "devDependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@rollup/plugin-replace": "^6.0.3", "@types/node": "^26.2.0", "typescript": "6.0.3", - "vite": "^8.2.1" + "vite": "^8.2.2" }, "dependencies": { "@tanstack/table-core": "^9.2.3" diff --git a/examples/vue/aggregation/package.json b/examples/vue/aggregation/package.json index df43ab2430..dd9bac1585 100644 --- a/examples/vue/aggregation/package.json +++ b/examples/vue/aggregation/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/basic-dynamic-columns/package.json b/examples/vue/basic-dynamic-columns/package.json index b4366863f1..beeb56b71c 100644 --- a/examples/vue/basic-dynamic-columns/package.json +++ b/examples/vue/basic-dynamic-columns/package.json @@ -10,18 +10,19 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/vue-devtools": "^0.2.24", + "@faker-js/faker": "^10.6.0", + "@tanstack/vue-devtools": "^0.2.26", "@tanstack/vue-table": "^9.2.3", "@tanstack/vue-table-devtools": "^9.2.0", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/basic-external-atoms/package.json b/examples/vue/basic-external-atoms/package.json index ff6eea33df..6c18cfc7bb 100644 --- a/examples/vue/basic-external-atoms/package.json +++ b/examples/vue/basic-external-atoms/package.json @@ -10,19 +10,20 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/vue-devtools": "^0.2.24", + "@faker-js/faker": "^10.6.0", + "@tanstack/vue-devtools": "^0.2.26", "@tanstack/vue-store": "^0.11.1", "@tanstack/vue-table": "^9.2.3", "@tanstack/vue-table-devtools": "^9.2.0", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/basic-external-state/package.json b/examples/vue/basic-external-state/package.json index 5c8abd350f..4255b9bccd 100644 --- a/examples/vue/basic-external-state/package.json +++ b/examples/vue/basic-external-state/package.json @@ -10,18 +10,19 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/vue-devtools": "^0.2.24", + "@faker-js/faker": "^10.6.0", + "@tanstack/vue-devtools": "^0.2.26", "@tanstack/vue-table": "^9.2.3", "@tanstack/vue-table-devtools": "^9.2.0", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/basic-use-app-table/package.json b/examples/vue/basic-use-app-table/package.json index 686d1991c5..1fdd52e090 100644 --- a/examples/vue/basic-use-app-table/package.json +++ b/examples/vue/basic-use-app-table/package.json @@ -10,17 +10,18 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@tanstack/vue-devtools": "^0.2.24", + "@tanstack/vue-devtools": "^0.2.26", "@tanstack/vue-table": "^9.2.3", "@tanstack/vue-table-devtools": "^9.2.0", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/basic-use-table/package.json b/examples/vue/basic-use-table/package.json index 7d622a460a..c625194ff4 100644 --- a/examples/vue/basic-use-table/package.json +++ b/examples/vue/basic-use-table/package.json @@ -10,17 +10,18 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@tanstack/vue-devtools": "^0.2.24", + "@tanstack/vue-devtools": "^0.2.26", "@tanstack/vue-table": "^9.2.3", "@tanstack/vue-table-devtools": "^9.2.0", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/cell-selection/package.json b/examples/vue/cell-selection/package.json index 3b840fcd2d..687582b73b 100644 --- a/examples/vue/cell-selection/package.json +++ b/examples/vue/cell-selection/package.json @@ -10,19 +10,20 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/vue-devtools": "^0.2.24", + "@faker-js/faker": "^10.6.0", + "@tanstack/vue-devtools": "^0.2.26", "@tanstack/vue-hotkeys": "^0.10.0", "@tanstack/vue-table": "^9.2.3", "@tanstack/vue-table-devtools": "^9.2.0", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/cell-spanning/package.json b/examples/vue/cell-spanning/package.json index eb2d27b222..89b7a3db60 100644 --- a/examples/vue/cell-spanning/package.json +++ b/examples/vue/cell-spanning/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/column-ordering/package.json b/examples/vue/column-ordering/package.json index 5c286c9176..15a2ce22e6 100644 --- a/examples/vue/column-ordering/package.json +++ b/examples/vue/column-ordering/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/column-pinning-split/package.json b/examples/vue/column-pinning-split/package.json index e1bb81e9da..5231432f02 100644 --- a/examples/vue/column-pinning-split/package.json +++ b/examples/vue/column-pinning-split/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/column-pinning-sticky/package.json b/examples/vue/column-pinning-sticky/package.json index 2cf780adfd..2565a5694f 100644 --- a/examples/vue/column-pinning-sticky/package.json +++ b/examples/vue/column-pinning-sticky/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/column-pinning/package.json b/examples/vue/column-pinning/package.json index cbd7f32d84..95de5da2de 100644 --- a/examples/vue/column-pinning/package.json +++ b/examples/vue/column-pinning/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/column-resizing-performant/package.json b/examples/vue/column-resizing-performant/package.json index 985edc3530..46fe0b4fd5 100644 --- a/examples/vue/column-resizing-performant/package.json +++ b/examples/vue/column-resizing-performant/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/column-resizing/package.json b/examples/vue/column-resizing/package.json index 753943ae2c..07a7e9bd6a 100644 --- a/examples/vue/column-resizing/package.json +++ b/examples/vue/column-resizing/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/column-sizing/package.json b/examples/vue/column-sizing/package.json index 2706a7270a..4cada59a75 100644 --- a/examples/vue/column-sizing/package.json +++ b/examples/vue/column-sizing/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/column-visibility/package.json b/examples/vue/column-visibility/package.json index 85105d757c..ce915de9ee 100644 --- a/examples/vue/column-visibility/package.json +++ b/examples/vue/column-visibility/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/composable-tables/package.json b/examples/vue/composable-tables/package.json index 9ad5dd1c21..890220dee0 100644 --- a/examples/vue/composable-tables/package.json +++ b/examples/vue/composable-tables/package.json @@ -10,18 +10,19 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@tanstack/vue-devtools": "^0.2.24", + "@tanstack/vue-devtools": "^0.2.26", "@tanstack/vue-store": "^0.11.1", "@tanstack/vue-table": "^9.2.3", "@tanstack/vue-table-devtools": "^9.2.0", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/expanding/package.json b/examples/vue/expanding/package.json index 56d73273ac..b15b4aac50 100644 --- a/examples/vue/expanding/package.json +++ b/examples/vue/expanding/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/filters-faceted-bucketed/package.json b/examples/vue/filters-faceted-bucketed/package.json index 24e665ec78..a7736e7615 100644 --- a/examples/vue/filters-faceted-bucketed/package.json +++ b/examples/vue/filters-faceted-bucketed/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/filters-faceted/package.json b/examples/vue/filters-faceted/package.json index 0a5c0b8b42..64831d4fcf 100644 --- a/examples/vue/filters-faceted/package.json +++ b/examples/vue/filters-faceted/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/filters-fuzzy/package.json b/examples/vue/filters-fuzzy/package.json index 471046c193..e0abb41e34 100644 --- a/examples/vue/filters-fuzzy/package.json +++ b/examples/vue/filters-fuzzy/package.json @@ -10,17 +10,18 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/filters/package.json b/examples/vue/filters/package.json index 645d65c09b..b160351304 100644 --- a/examples/vue/filters/package.json +++ b/examples/vue/filters/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/grouped-aggregation/package.json b/examples/vue/grouped-aggregation/package.json index 8d1a6b7912..b6ab4c3919 100644 --- a/examples/vue/grouped-aggregation/package.json +++ b/examples/vue/grouped-aggregation/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/grouping/package.json b/examples/vue/grouping/package.json index 115b55dc4f..ed6aab7a52 100644 --- a/examples/vue/grouping/package.json +++ b/examples/vue/grouping/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/header-groups/package.json b/examples/vue/header-groups/package.json index c3f3aaccfd..fcc01bbb96 100644 --- a/examples/vue/header-groups/package.json +++ b/examples/vue/header-groups/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/kitchen-sink-shadcn/package.json b/examples/vue/kitchen-sink-shadcn/package.json index 9d1aa91af9..d9f5b79a0f 100644 --- a/examples/vue/kitchen-sink-shadcn/package.json +++ b/examples/vue/kitchen-sink-shadcn/package.json @@ -12,31 +12,32 @@ "shadcn": "pnpm dlx shadcn-vue@latest" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@internationalized/date": "^3.12.3", - "@lucide/vue": "^1.31.0", + "@lucide/vue": "^1.34.0", "@tailwindcss/vite": "^4.3.3", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/pacer": "^0.22.0", - "@tanstack/vue-devtools": "^0.2.24", + "@tanstack/vue-devtools": "^0.2.26", "@tanstack/vue-table": "^9.2.3", "@tanstack/vue-table-devtools": "^9.2.0", "@vueuse/core": "^14.4.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "dnd-kit-vue": "^0.0.2", - "reka-ui": "^2.10.3", + "reka-ui": "^2.10.4", "tailwind-merge": "^3.6.0", "tailwindcss": "^4.3.3", "tw-animate-css": "^1.4.0", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/kitchen-sink/package.json b/examples/vue/kitchen-sink/package.json index 30c3dbe1ed..131ba657dd 100644 --- a/examples/vue/kitchen-sink/package.json +++ b/examples/vue/kitchen-sink/package.json @@ -10,19 +10,20 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/match-sorter-utils": "^9.1.2", - "@tanstack/vue-devtools": "^0.2.24", + "@tanstack/vue-devtools": "^0.2.26", "@tanstack/vue-table": "^9.2.3", "@tanstack/vue-table-devtools": "^9.2.0", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/lib-shadcn/package.json b/examples/vue/lib-shadcn/package.json index 464fc885d4..fd2f195f37 100644 --- a/examples/vue/lib-shadcn/package.json +++ b/examples/vue/lib-shadcn/package.json @@ -11,26 +11,27 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@lucide/vue": "^1.31.0", + "@faker-js/faker": "^10.6.0", + "@lucide/vue": "^1.34.0", "@tailwindcss/vite": "^4.3.3", "@tanstack/pacer": "^0.22.0", "@tanstack/vue-table": "^9.2.3", "@vueuse/core": "^14.4.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "reka-ui": "^2.10.3", + "reka-ui": "^2.10.4", "tailwind-merge": "^3.6.0", "tailwindcss": "^4.3.3", "tw-animate-css": "^1.4.0", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/pagination/package.json b/examples/vue/pagination/package.json index 330a410721..a440e21252 100644 --- a/examples/vue/pagination/package.json +++ b/examples/vue/pagination/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/realtime-trading/README.md b/examples/vue/realtime-trading/README.md new file mode 100644 index 0000000000..b7c8583d22 --- /dev/null +++ b/examples/vue/realtime-trading/README.md @@ -0,0 +1,156 @@ +# Vue realtime trading benchmark + +This standalone example exercises the current TanStack Vue Table adapter with +a high-frequency worker feed, immutable quote snapshots, interactive columns, +custom Vue cells, optional virtualization, and browser diagnostics. It is a +repeatable UI stress workload, not an exchange or network benchmark. + +## Run and verify + +```bash +pnpm --dir examples/vue/realtime-trading dev +``` + +Open `http://localhost:7777`. + +```bash +pnpm --dir examples/vue/realtime-trading test:types +pnpm --dir examples/vue/realtime-trading lint +pnpm --dir examples/vue/realtime-trading build +pnpm --dir examples/vue/realtime-trading test:e2e +``` + +Use the production build for recordings; Vue development checks add overhead. + +## Structure and ownership + +| Path | Responsibility | +| ------------------------- | ---------------------------------------------------------------------------------------------- | +| `src/feed/` | Market model, instrument universe, feed configuration, immutable updates, and feed controller. | +| `src/feed/worker/` | Typed protocol, deterministic market engine, and module worker. | +| `src/benchmark/` | Browser monitor, benchmark controller, table timing, lifecycle, and mutation observers. | +| `src/shell/` | Controller injection, viewport shell, controls, metrics, selected instrument, and diagnostics. | +| `src/table/table-config/` | Grouped columns and custom Vue quote cells. | +| `src/table/` | Vue Table instance, delegated interactions, column layout, and Vue Virtual integration. | +| `src/App.tsx` | Creates/starts controllers, provides them, and composes shell plus table. | + +`MarketFeedController` owns worker/feed state; `TradingBenchmarkController` +observes it and owns benchmark/view state. Vue `provide`/`inject` distributes +stable controller objects. The controllers use Vue primitives directly: +`quotes` and metrics are independent `shallowRef` values, while feed status, +configuration, selection, and view state use focused `ref` values. Consumers +read only the refs they need, and the root never consumes the quote stream. +Cleanup stops both controllers on application unmount. + +## Feed and worker pipeline + +The default run uses 100 instruments, 10K generated samples/s, 20 ms delivery, +enabled intraday charts, and 16 ms chart sampling. + +The worker keeps mutable market state private. Its deterministic generator runs +from a 16 ms accrued budget, while a row-indexed `Map` coalesces repeated +updates. A separate publication timer sends the latest unique rows. The main +thread publishes a new quote array but replaces only changed row objects; +untouched rows and unsampled history arrays keep their references. Session IDs +discard messages from an obsolete reset/instrument configuration. + +- **Synthetic quote workload** is generated samples/s in the worker, not Vue + renders or `postMessage` calls. +- **Worker delivery interval** is the target coalesced-message cadence; 20 ms + targets roughly 50 messages/s. +- **Row updates** counts unique immutable rows applied by a message. +- **Message samples** is the generated work represented by the latest batch. + +Chart sampling is independent of price sampling. The 25K burst immediately +creates and publishes one heavy batch. Worker messaging approximates an +upstream stream, but actual network latency is outside the benchmark. + +## Vue table architecture + +The grid has 14 leaf columns grouped into Instrument, Price & Change, Order +Book, Session, and Chart. It supports sorting/filtering, on-change resizing, +double-click reset, drag ordering, CSS row hover, row selection, drag cell +ranges, keyboard navigation, and component-based Price/Move/Percent/Sparkline +cells. + +The table accepts the dedicated quotes `shallowRef` directly and uses the +instrument ID for `getRowId`. TanStack Vue Table's state atoms are Vue-backed, +so row-model computations and layout watchers read only the required atoms from +native `computed`/`watch` boundaries. Dedicated row views keep row markup and +selected-instrument state below the whole-table boundary. + +A single `TradingGridPointerController` handles body pointer events. It maps +`event.composedPath()` and data attributes back to the TanStack cell, avoiding +one handler per cell. Column sizes are CSS variables updated only when sizing +or order changes. `ResizeObserver` performs initial fit until manual resizing. +The A/B Move renderer is an explicit component lifecycle stress mode. + +## Virtualization + +- Below 200 rows, automatic mode uses Full DOM, but Virtual is selectable. +- From 200 through 1,499 rows, automatic mode uses TanStack Virtual, while Full + DOM remains selectable. +- At 1,500 rows or more, Virtual is forced and its control is locked. + +Vue Virtual uses 32 px row estimates, 10-row overscan, instrument IDs as item +keys, transformed rows, and a spacer body. The visible-range footer reads the +virtualizer range. Both paths apply `content-visibility: auto`; in Full DOM it +can reduce browser rendering but cannot prevent Vue from creating all rows. + +## Performance decisions + +- market generation/coalescing is moved off the main thread; +- immutable structural sharing preserves untouched rows/histories; +- focused Vue refs and computed values narrow reactive invalidation; +- stable row and virtual item keys preserve identity; +- row rendering is componentized without subscribing the app root to data; +- pointer selection is delegated once; +- CSS variables separate width changes from quote updates; +- component swapping and chart frequency are opt-in stress controls; +- virtualization limits framework and DOM mounts; +- metrics are published more slowly than the feed. + +The immutable outer array must change for a batch. Structural sharing can reduce +cell work, but sorted/filtered row models may still run when the data input +changes. + +## Diagnostics and interpretation + +The sidebar starts with four cross-framework health signals: estimated rAF +callbacks/s over one second, average snapshot-to-DOM-commit latency over three +seconds, long animation frames accumulated since reset, and throughput as +changed rows/s plus applied snapshots/s. “Changed rows” is deduplicated within +each snapshot; the same instrument can count again in a later snapshot. The +advanced diagnostics retain worker samples/messages, DOM commits, a rolling +10-second p95/max commit latency, slow commits, lifecycle/execution rates, +row-model timing, DOM mutation records, and optional heap data. + +The frame figure is deliberately labeled estimated: it counts this page's rAF +callbacks, is capped by the display refresh rate, and falls when a tab is +throttled. It is a portable responsiveness signal, not compositor-presented +FPS. + +Vue closes the pending measurement from the table's mounted/updated commit +hooks. User Timing entries for commits and row-model work are sampled at one in +20 calls; the in-memory counters and latency windows still measure every call. + +Callback counts are not DOM mutation counts. Temporary heap growth during the +swap workload is not a leak unless post-GC snapshots retain instances. The heap +value is Chromium-only and GC-sensitive, not retained size. The DOM rate counts +`MutationRecord` objects rather than browser operations, and records may be +coalesced; the observer watches text/child changes plus only `class`/`style` +attributes to limit its own overhead. Non-feed text/child changes and +interaction-driven `class`/`style` changes (including virtual scrolling) are +included, so this is not a feed-only rate. Compare identical production +configurations and use Chrome Performance plus Vue DevTools for call stacks and +component detail. + +## Standalone policy + +The instruments, feed, worker, benchmark, shell, styles, and table code are +intentionally copied into this folder. This keeps the example independently +runnable and StackBlitz-ready, so shared implementation and README explanations +are duplicated across adapters by design. + +The workspace resolves the pinned `@tanstack/vue-table` dependency to the local +adapter package while retaining a release-like manifest. diff --git a/examples/vue/realtime-trading/index.html b/examples/vue/realtime-trading/index.html new file mode 100644 index 0000000000..3a941cafa2 --- /dev/null +++ b/examples/vue/realtime-trading/index.html @@ -0,0 +1,17 @@ + + + + + + + + Vue Real-time Trading FlexRender Lab + + +
+ + + diff --git a/examples/vue/realtime-trading/package.json b/examples/vue/realtime-trading/package.json new file mode 100644 index 0000000000..908ac64d23 --- /dev/null +++ b/examples/vue/realtime-trading/package.json @@ -0,0 +1,28 @@ +{ + "name": "tanstack-vue-table-example-realtime-trading", + "private": true, + "type": "module", + "scripts": { + "start": "vite", + "dev": "vite", + "build": "vite build", + "serve": "vite preview", + "lint": "eslint ./src", + "test:types": "vue-tsc --noEmit", + "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" + }, + "dependencies": { + "@tanstack/vue-table": "^9.2.3", + "@tanstack/vue-virtual": "^3.13.36", + "vue": "^3.5.41" + }, + "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", + "@types/node": "^26.2.0", + "@vitejs/plugin-vue": "^6.0.8", + "@vitejs/plugin-vue-jsx": "^5.1.6", + "typescript": "6.0.3", + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" + } +} diff --git a/examples/vue/realtime-trading/src/App.tsx b/examples/vue/realtime-trading/src/App.tsx new file mode 100644 index 0000000000..d8346b2c66 --- /dev/null +++ b/examples/vue/realtime-trading/src/App.tsx @@ -0,0 +1,26 @@ +import { defineComponent, onBeforeUnmount } from 'vue' +import { TradingBenchmarkController } from './benchmark/trading-benchmark-controller' +import { MarketFeedController } from './feed/market-feed-controller' +import { TradingShell } from './shell/TradingShell' +import { provideTradingControllers } from './shell/trading-shell-context' +import { TradingTable } from './table/trading-table' + +export const App = defineComponent({ + name: 'RealtimeTradingApp', + setup() { + const feed = new MarketFeedController() + const benchmark = new TradingBenchmarkController(feed) + provideTradingControllers(benchmark) + + const stopFeed = feed.start() + const stopBenchmark = benchmark.start() + onBeforeUnmount(() => { + stopBenchmark() + stopFeed() + }) + + return () => ( + {{ default: () => }} + ) + }, +}) diff --git a/examples/vue/realtime-trading/src/benchmark/benchmark-monitor.ts b/examples/vue/realtime-trading/src/benchmark/benchmark-monitor.ts new file mode 100644 index 0000000000..8c3fb49821 --- /dev/null +++ b/examples/vue/realtime-trading/src/benchmark/benchmark-monitor.ts @@ -0,0 +1,434 @@ +import { + quoteCellLifecycle, + quoteRenderDiagnostics, +} from '../table/table-config/quote-cells' +import { rowModelDiagnostics } from '../table/trading-table' + +export interface NamedInvocationRate { + name: string + callsPerSecond: number +} + +interface TimedLatencySample { + recordedAt: number + duration: number +} + +const averageLatencyWindowMs = 3_000 +const percentileLatencyWindowMs = 10_000 +const frameRateWindowMs = 1_000 + +export interface FeedMetrics { + actualTicksPerSecond: number + rowUpdatesPerSecond: number + workerMessagesPerSecond: number + stateApplicationsPerSecond: number + supersededUpdatesPerSecond: number + totalTicks: number + rafCallbacksPerSecond: number + tableCommitsPerSecond: number + lastBatchSize: number + averageCommitLatencyMs: number + p95CommitLatencyMs: number + maxCommitLatencyMs: number + slowCommits: number + longAnimationFrames: number + worstLongAnimationFrameMs: number + heapMb: number | null + componentsCreated: number + componentsDestroyed: number + workerMessages: number + lastUpdateCount: number + cellRendererCallsPerSecond: number + componentRenderCallsPerSecond: number + cellRendererRates: ReadonlyArray + componentRenderRates: ReadonlyArray + domMutationsPerSecond: number + rowModelCallsPerSecond: number + rowModelAverageMs: number + rowModelMaxMs: number + visibleRows: number +} + +export const initialMetrics: FeedMetrics = { + actualTicksPerSecond: 0, + rowUpdatesPerSecond: 0, + workerMessagesPerSecond: 0, + stateApplicationsPerSecond: 0, + supersededUpdatesPerSecond: 0, + totalTicks: 0, + rafCallbacksPerSecond: 0, + tableCommitsPerSecond: 0, + lastBatchSize: 0, + averageCommitLatencyMs: 0, + p95CommitLatencyMs: 0, + maxCommitLatencyMs: 0, + slowCommits: 0, + longAnimationFrames: 0, + worstLongAnimationFrameMs: 0, + heapMb: null, + componentsCreated: 0, + componentsDestroyed: 0, + workerMessages: 0, + lastUpdateCount: 0, + cellRendererCallsPerSecond: 0, + componentRenderCallsPerSecond: 0, + cellRendererRates: [], + componentRenderRates: [], + domMutationsPerSecond: 0, + rowModelCallsPerSecond: 0, + rowModelAverageMs: 0, + rowModelMaxMs: 0, + visibleRows: 0, +} + +const userTiming = { entryCount: 0, measureCalls: 0 } + +export function recordMeasure( + name: string, + start: number, + end: number, + detail: Record, +): void { + userTiming.measureCalls++ + if (userTiming.measureCalls % 20 !== 0) return + try { + performance.measure(name, { start, end, detail }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMeasures('market-update-to-dom-commit') + } + } catch { + // User Timing Level 3 options are not implemented in every browser. + } +} + +export function markBenchmarkAction( + name: string, + detail: Record = {}, +): void { + try { + performance.mark(`benchmark:${name}`, { detail }) + userTiming.entryCount++ + if (userTiming.entryCount % 1_000 === 0) { + performance.clearMarks() + } + } catch { + // User Timing Level 3 detail is not implemented in every browser. + } +} + +export class BenchmarkMonitor { + readonly #runtime = { + sampleStartedAt: performance.now(), + sessionStartedAt: performance.now(), + pendingMutationStartedAt: null as number | null, + commitLatencySamples: [] as Array, + slowCommitCount: 0, + totalTicks: 0, + ticksInSample: 0, + rowUpdatesInSample: 0, + workerMessagesInSample: 0, + stateApplicationsInSample: 0, + supersededUpdatesInSample: 0, + lastBatchSize: 0, + lastUpdateCount: 0, + workerMessages: 0, + frameTrackingStartedAt: performance.now(), + frameTimestamps: [] as Array, + tableCommitsInSample: 0, + longAnimationFrameCount: 0, + worstLongAnimationFrameMs: 0, + previousCellRendererCalls: 0, + previousComponentRenderCalls: 0, + previousCellRendererCallsByName: { + ...quoteRenderDiagnostics.cellRendererCallsByName, + }, + previousComponentRenderCallsByName: { + ...quoteRenderDiagnostics.componentRenderCallsByName, + }, + domMutationsInSample: 0, + previousRowModelCalls: 0, + previousRowModelDuration: 0, + } + + markCommitPending(): void { + this.#runtime.pendingMutationStartedAt ??= performance.now() + } + + recordDomCommit(): void { + const runtime = this.#runtime + if (runtime.pendingMutationStartedAt !== null) { + const commitEndedAt = performance.now() + const duration = commitEndedAt - runtime.pendingMutationStartedAt + runtime.commitLatencySamples.push({ + recordedAt: commitEndedAt, + duration, + }) + if (duration > 16.7) runtime.slowCommitCount++ + recordMeasure( + 'market-update-to-dom-commit', + runtime.pendingMutationStartedAt, + commitEndedAt, + {}, + ) + runtime.pendingMutationStartedAt = null + runtime.tableCommitsInSample++ + } + } + + recordWorkerMessage(): void { + this.#runtime.workerMessages++ + this.#runtime.workerMessagesInSample++ + } + + recordBatch( + tickCount: number, + updateCount: number, + supersededUpdateCount: number, + ): void { + const runtime = this.#runtime + runtime.lastBatchSize = tickCount + runtime.lastUpdateCount = updateCount + runtime.ticksInSample += tickCount + runtime.totalTicks += tickCount + runtime.rowUpdatesInSample += updateCount + runtime.stateApplicationsInSample++ + runtime.supersededUpdatesInSample += supersededUpdateCount + } + + recordAnimationFrame(now: number): void { + const timestamps = this.#runtime.frameTimestamps + timestamps.push(now) + pruneFrameTimestamps(timestamps, now) + } + + recordLongAnimationFrame(duration: number, startTime: number): void { + const runtime = this.#runtime + if (startTime < runtime.sessionStartedAt) return + runtime.longAnimationFrameCount++ + runtime.worstLongAnimationFrameMs = Math.max( + runtime.worstLongAnimationFrameMs, + duration, + ) + } + + recordDomMutations(count: number): void { + this.#runtime.domMutationsInSample += count + } + + resetDomMutations(): void { + this.#runtime.domMutationsInSample = 0 + } + + shouldPublish(now: number): boolean { + return now - this.#runtime.sampleStartedAt >= 500 + } + + publish(now: number): FeedMetrics { + const runtime = this.#runtime + const sampleDuration = now - runtime.sampleStartedAt + pruneLatencySamples(runtime.commitLatencySamples, now) + pruneFrameTimestamps(runtime.frameTimestamps, now) + const averageCommitLatencySamples = runtime.commitLatencySamples + .filter((sample) => sample.recordedAt >= now - averageLatencyWindowMs) + .map((sample) => sample.duration) + const percentileCommitLatencySamples = runtime.commitLatencySamples.map( + (sample) => sample.duration, + ) + const sortedCommitLatencySamples = [...percentileCommitLatencySamples].sort( + (left, right) => left - right, + ) + const rowModelCalls = + rowModelDiagnostics.calls - runtime.previousRowModelCalls + const rowModelDuration = + rowModelDiagnostics.totalDurationMs - runtime.previousRowModelDuration + const cellRendererCalls = + quoteRenderDiagnostics.cellRendererCalls - + runtime.previousCellRendererCalls + const componentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls - + runtime.previousComponentRenderCalls + const cellRendererRates = calculateInvocationRates( + quoteRenderDiagnostics.cellRendererCallsByName, + runtime.previousCellRendererCallsByName, + sampleDuration, + ) + const componentRenderRates = calculateInvocationRates( + quoteRenderDiagnostics.componentRenderCallsByName, + runtime.previousComponentRenderCallsByName, + sampleDuration, + ) + const averageCommitLatencyMs = + averageCommitLatencySamples.length === 0 + ? 0 + : averageCommitLatencySamples.reduce((sum, value) => sum + value, 0) / + averageCommitLatencySamples.length + const p95Index = Math.max( + 0, + Math.ceil(sortedCommitLatencySamples.length * 0.95) - 1, + ) + const metrics: FeedMetrics = { + actualTicksPerSecond: + sampleDuration === 0 + ? 0 + : (runtime.ticksInSample / sampleDuration) * 1_000, + rowUpdatesPerSecond: + (runtime.rowUpdatesInSample / sampleDuration) * 1_000, + workerMessagesPerSecond: + (runtime.workerMessagesInSample / sampleDuration) * 1_000, + stateApplicationsPerSecond: + (runtime.stateApplicationsInSample / sampleDuration) * 1_000, + supersededUpdatesPerSecond: + (runtime.supersededUpdatesInSample / sampleDuration) * 1_000, + totalTicks: runtime.totalTicks, + rafCallbacksPerSecond: calculateFrameRate( + runtime.frameTimestamps, + runtime.frameTrackingStartedAt, + now, + ), + tableCommitsPerSecond: + (runtime.tableCommitsInSample / sampleDuration) * 1_000, + lastBatchSize: runtime.lastBatchSize, + averageCommitLatencyMs, + p95CommitLatencyMs: sortedCommitLatencySamples[p95Index] ?? 0, + maxCommitLatencyMs: sortedCommitLatencySamples.at(-1) ?? 0, + slowCommits: runtime.slowCommitCount, + longAnimationFrames: runtime.longAnimationFrameCount, + worstLongAnimationFrameMs: runtime.worstLongAnimationFrameMs, + heapMb: readHeapSizeMb(), + componentsCreated: quoteCellLifecycle.created, + componentsDestroyed: quoteCellLifecycle.destroyed, + workerMessages: runtime.workerMessages, + lastUpdateCount: runtime.lastUpdateCount, + cellRendererCallsPerSecond: (cellRendererCalls / sampleDuration) * 1_000, + componentRenderCallsPerSecond: + (componentRenderCalls / sampleDuration) * 1_000, + cellRendererRates, + componentRenderRates, + domMutationsPerSecond: + (runtime.domMutationsInSample / sampleDuration) * 1_000, + rowModelCallsPerSecond: (rowModelCalls / sampleDuration) * 1_000, + rowModelAverageMs: + rowModelCalls === 0 ? 0 : rowModelDuration / rowModelCalls, + rowModelMaxMs: rowModelDiagnostics.maxDurationMs, + visibleRows: rowModelDiagnostics.lastRowCount, + } + + runtime.sampleStartedAt = now + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.previousRowModelCalls = rowModelDiagnostics.calls + runtime.previousRowModelDuration = rowModelDiagnostics.totalDurationMs + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.tableCommitsInSample = 0 + return metrics + } + + reset(): void { + const runtime = this.#runtime + runtime.sampleStartedAt = performance.now() + runtime.sessionStartedAt = runtime.sampleStartedAt + runtime.pendingMutationStartedAt = null + runtime.commitLatencySamples = [] + runtime.slowCommitCount = 0 + runtime.totalTicks = 0 + runtime.ticksInSample = 0 + runtime.rowUpdatesInSample = 0 + runtime.workerMessagesInSample = 0 + runtime.stateApplicationsInSample = 0 + runtime.supersededUpdatesInSample = 0 + runtime.lastBatchSize = 0 + runtime.lastUpdateCount = 0 + runtime.workerMessages = 0 + runtime.frameTrackingStartedAt = runtime.sampleStartedAt + runtime.frameTimestamps = [] + runtime.tableCommitsInSample = 0 + runtime.longAnimationFrameCount = 0 + runtime.worstLongAnimationFrameMs = 0 + runtime.previousCellRendererCalls = quoteRenderDiagnostics.cellRendererCalls + runtime.previousComponentRenderCalls = + quoteRenderDiagnostics.componentRenderCalls + runtime.previousCellRendererCallsByName = { + ...quoteRenderDiagnostics.cellRendererCallsByName, + } + runtime.previousComponentRenderCallsByName = { + ...quoteRenderDiagnostics.componentRenderCallsByName, + } + runtime.domMutationsInSample = 0 + runtime.previousRowModelCalls = rowModelDiagnostics.calls + runtime.previousRowModelDuration = rowModelDiagnostics.totalDurationMs + rowModelDiagnostics.maxDurationMs = 0 + } +} + +export const longAnimationFramesSupported = + PerformanceObserver.supportedEntryTypes.includes('long-animation-frame') + +function readHeapSizeMb(): number | null { + const memory = ( + performance as Performance & { + memory?: { usedJSHeapSize: number } + } + ).memory + return memory ? memory.usedJSHeapSize / 1_048_576 : null +} + +function calculateInvocationRates( + current: Record, + previous: Record, + sampleDuration: number, +): ReadonlyArray { + return Object.entries(current).map(([name, calls]) => ({ + name, + callsPerSecond: + sampleDuration === 0 + ? 0 + : ((calls - (previous[name] ?? 0)) / sampleDuration) * 1_000, + })) +} + +function pruneLatencySamples( + samples: Array, + now: number, +): void { + const cutoff = now - percentileLatencyWindowMs + const firstRetainedIndex = samples.findIndex( + (sample) => sample.recordedAt >= cutoff, + ) + if (firstRetainedIndex > 0) samples.splice(0, firstRetainedIndex) + else if (firstRetainedIndex === -1) samples.length = 0 +} + +function pruneFrameTimestamps(timestamps: Array, now: number): void { + const cutoff = now - frameRateWindowMs + const firstRetainedIndex = timestamps.findIndex( + (timestamp) => timestamp >= cutoff, + ) + if (firstRetainedIndex > 0) timestamps.splice(0, firstRetainedIndex) + else if (firstRetainedIndex === -1) timestamps.length = 0 +} + +function calculateFrameRate( + timestamps: ReadonlyArray, + trackingStartedAt: number, + now: number, +): number { + const observedWindowMs = Math.min( + frameRateWindowMs, + Math.max(1, now - trackingStartedAt), + ) + return (timestamps.length / observedWindowMs) * 1_000 +} diff --git a/examples/vue/realtime-trading/src/benchmark/trading-benchmark-controller.ts b/examples/vue/realtime-trading/src/benchmark/trading-benchmark-controller.ts new file mode 100644 index 0000000000..55257ffba9 --- /dev/null +++ b/examples/vue/realtime-trading/src/benchmark/trading-benchmark-controller.ts @@ -0,0 +1,128 @@ +import { ref, shallowRef } from 'vue' +import { TRADING_COLUMN_COUNT } from '../table/trading-table' +import { FORCED_VIRTUALIZATION_ROW_COUNT } from '../table/trading-row-virtualizer' +import { + BenchmarkMonitor, + initialMetrics, + longAnimationFramesSupported, +} from './benchmark-monitor' +import type { FeedMetrics } from './benchmark-monitor' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { RendererMode } from '../table/trading-table' +import type { VirtualScrollPreference } from '../table/trading-row-virtualizer' + +export interface TradingBenchmarkActions { + resetViewState: () => void + setRendererMode: (mode: RendererMode) => void + setVirtualScrollEnabled: (enabled: boolean) => void + setRenderedRowCount: (count: number) => void + selectSymbol: (symbol: string | null) => void + resetMarket: () => void +} + +export class TradingBenchmarkController { + readonly requestedVirtualScrollMode = ref('auto') + readonly metrics = shallowRef(initialMetrics) + readonly mountedCells = ref(0) + readonly liveComponents = ref(0) + readonly selectedSymbol = ref(null) + readonly rendererMode = ref('stable') + readonly longAnimationFramesSupported = longAnimationFramesSupported + readonly monitor = new BenchmarkMonitor() + readonly feed: MarketFeedController + readonly actions: TradingBenchmarkActions + + readonly #runtime = { + animationFrameId: 0, + longAnimationFrameObserver: null as PerformanceObserver | null, + stopObservingFeed: null as (() => void) | null, + } + + constructor(feed: MarketFeedController) { + this.feed = feed + this.actions = { + resetViewState: () => { + this.selectedSymbol.value = null + this.requestedVirtualScrollMode.value = 'auto' + }, + setRendererMode: (mode) => { + this.rendererMode.value = mode + }, + setVirtualScrollEnabled: (enabled) => { + if ( + this.feed.instrumentCount.value >= FORCED_VIRTUALIZATION_ROW_COUNT + ) { + return + } + this.requestedVirtualScrollMode.value = enabled ? 'tanstack' : 'none' + }, + setRenderedRowCount: (count) => { + const mountedCells = count * TRADING_COLUMN_COUNT + if (mountedCells !== this.mountedCells.value) { + this.mountedCells.value = mountedCells + } + }, + selectSymbol: (symbol) => { + this.selectedSymbol.value = symbol + }, + resetMarket: () => { + this.monitor.reset() + this.metrics.value = { ...initialMetrics } + this.mountedCells.value = 0 + this.liveComponents.value = 0 + this.selectedSymbol.value = null + this.feed.actions.reset() + }, + } + } + + start(): () => void { + const longAnimationFrameObserver = longAnimationFramesSupported + ? new PerformanceObserver((entries) => { + for (const entry of entries.getEntries()) { + this.monitor.recordLongAnimationFrame( + entry.duration, + entry.startTime, + ) + } + }) + : null + + this.#runtime.longAnimationFrameObserver = longAnimationFrameObserver + this.#runtime.stopObservingFeed = this.feed.observe({ + messageReceived: () => this.monitor.recordWorkerMessage(), + mutationStarted: () => this.monitor.markCommitPending(), + batchApplied: ({ tickCount, updateCount, supersededUpdateCount }) => + this.monitor.recordBatch(tickCount, updateCount, supersededUpdateCount), + renderCommitted: () => this.monitor.recordDomCommit(), + }) + longAnimationFrameObserver?.observe({ + type: 'long-animation-frame', + }) + this.#runtime.animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + + return () => this.stop() + } + + stop(): void { + cancelAnimationFrame(this.#runtime.animationFrameId) + this.#runtime.longAnimationFrameObserver?.disconnect() + this.#runtime.stopObservingFeed?.() + this.#runtime.longAnimationFrameObserver = null + this.#runtime.stopObservingFeed = null + } + + readonly #benchmarkFrame = (now: number): void => { + this.monitor.recordAnimationFrame(now) + if (this.monitor.shouldPublish(now)) { + this.#publishMetrics(this.monitor.publish(now)) + } + this.#runtime.animationFrameId = requestAnimationFrame(this.#benchmarkFrame) + } + + #publishMetrics(metrics: FeedMetrics): void { + this.metrics.value = metrics + this.liveComponents.value = + metrics.componentsCreated - metrics.componentsDestroyed + } +} diff --git a/examples/vue/realtime-trading/src/benchmark/use-table-benchmark.ts b/examples/vue/realtime-trading/src/benchmark/use-table-benchmark.ts new file mode 100644 index 0000000000..2b8a862c06 --- /dev/null +++ b/examples/vue/realtime-trading/src/benchmark/use-table-benchmark.ts @@ -0,0 +1,29 @@ +import { onBeforeUnmount, onMounted } from 'vue' +import type { TradingBenchmarkController } from './trading-benchmark-controller' + +export function useTableBenchmark( + controller: TradingBenchmarkController, +): void { + const runtime = { mutationObserver: null as MutationObserver | null } + + onMounted(() => { + const tableBody = document.querySelector( + '.market-panel [data-trading-table] tbody', + ) + if (!tableBody) return + + controller.monitor.resetDomMutations() + runtime.mutationObserver = new MutationObserver((records) => { + controller.monitor.recordDomMutations(records.length) + }) + runtime.mutationObserver.observe(tableBody, { + attributes: true, + attributeFilter: ['class', 'style'], + characterData: true, + childList: true, + subtree: true, + }) + }) + + onBeforeUnmount(() => runtime.mutationObserver?.disconnect()) +} diff --git a/examples/vue/realtime-trading/src/feed/feed-sample-rates.ts b/examples/vue/realtime-trading/src/feed/feed-sample-rates.ts new file mode 100644 index 0000000000..17dc2015a6 --- /dev/null +++ b/examples/vue/realtime-trading/src/feed/feed-sample-rates.ts @@ -0,0 +1,33 @@ +export const feedSampleRateOptions = [ + { label: '100', value: 100 }, + { label: '250', value: 250 }, + { label: '500', value: 500 }, + { label: '1K', value: 1_000 }, + { label: '2.5K', value: 2_500 }, + { label: '5K', value: 5_000 }, + { label: '10K', value: 10_000 }, + { label: '25K', value: 25_000 }, + { label: '50K', value: 50_000 }, + { label: '100K', value: 100_000 }, +] as const + +export function feedSampleRateIndex(rate: number): number { + return feedSampleRateOptions.reduce((closestIndex, candidate, index) => { + const closest = feedSampleRateOptions[closestIndex] + return Math.abs(candidate.value - rate) < Math.abs(closest.value - rate) + ? index + : closestIndex + }, 0) +} + +export function feedSampleRateAt(stepIndex: number): number { + const index = Math.min( + feedSampleRateOptions.length - 1, + Math.max(0, Math.round(stepIndex)), + ) + return feedSampleRateOptions[index].value +} + +export function normalizeFeedSampleRate(rate: number): number { + return feedSampleRateAt(feedSampleRateIndex(rate)) +} diff --git a/examples/vue/realtime-trading/src/feed/market-data.ts b/examples/vue/realtime-trading/src/feed/market-data.ts new file mode 100644 index 0000000000..6231865d3f --- /dev/null +++ b/examples/vue/realtime-trading/src/feed/market-data.ts @@ -0,0 +1,38 @@ +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './worker/market-feed-protocol' + +export interface MarketQuote extends Omit { + history: ReadonlyArray +} + +export function hydrateMarketQuotes( + snapshots: Array, +): Array { + return snapshots.map((quote) => ({ + ...quote, + history: [...quote.history], + })) +} + +export function applyMarketUpdates( + quotes: Array, + updates: Array, +): Array { + const nextQuotes = [...quotes] + + for (const update of updates) { + const { index, history, ...values } = update + const previousQuote = quotes.at(index) + if (!previousQuote) continue + + nextQuotes[index] = { + ...previousQuote, + ...values, + history: history ?? previousQuote.history, + } + } + + return nextQuotes +} diff --git a/examples/vue/realtime-trading/src/feed/market-feed-config.ts b/examples/vue/realtime-trading/src/feed/market-feed-config.ts new file mode 100644 index 0000000000..9d477ed663 --- /dev/null +++ b/examples/vue/realtime-trading/src/feed/market-feed-config.ts @@ -0,0 +1,15 @@ +export interface MarketFeedConfig { + readonly instrumentCount: number + readonly targetSamplesPerSecond: number + readonly publishIntervalMs: number + readonly updateSparklines: boolean + readonly sparklineSampleIntervalMs: number +} + +export const initialMarketFeedConfig: MarketFeedConfig = { + instrumentCount: 100, + targetSamplesPerSecond: 10_000, + publishIntervalMs: 20, + updateSparklines: true, + sparklineSampleIntervalMs: 16, +} diff --git a/examples/vue/realtime-trading/src/feed/market-feed-controller.ts b/examples/vue/realtime-trading/src/feed/market-feed-controller.ts new file mode 100644 index 0000000000..27e2a8493b --- /dev/null +++ b/examples/vue/realtime-trading/src/feed/market-feed-controller.ts @@ -0,0 +1,217 @@ +import { ref, shallowRef } from 'vue' +import { normalizeFeedSampleRate } from './feed-sample-rates' +import { initialMarketFeedConfig } from './market-feed-config' +import { applyMarketUpdates, hydrateMarketQuotes } from './market-data' +import type { + MarketFeedCommand, + MarketFeedEvent, +} from './worker/market-feed-protocol' +import type { MarketQuote } from './market-data' + +export interface MarketFeedBatch { + tickCount: number + updateCount: number + supersededUpdateCount: number +} + +export interface MarketFeedObserver { + messageReceived?: () => void + mutationStarted?: () => void + batchApplied?: (batch: MarketFeedBatch) => void + renderCommitted?: () => void +} + +export interface MarketFeedActions { + toggle: () => void + setInstrumentCount: (count: number) => void + setTargetRate: (rate: number) => void + setPublishInterval: (intervalMs: number) => void + setSparklineUpdates: (enabled: boolean) => void + setSparklineSampleInterval: (intervalMs: number) => void + runBurst: () => void + reset: () => void +} + +export class MarketFeedController { + readonly workerReady = ref(false) + readonly running = ref(true) + readonly instrumentCount = ref(initialMarketFeedConfig.instrumentCount) + readonly targetTicksPerSecond = ref( + initialMarketFeedConfig.targetSamplesPerSecond, + ) + readonly publishIntervalMs = ref(initialMarketFeedConfig.publishIntervalMs) + readonly updateSparklines = ref(initialMarketFeedConfig.updateSparklines) + readonly sparklineSampleIntervalMs = ref( + initialMarketFeedConfig.sparklineSampleIntervalMs, + ) + readonly quotes = shallowRef>([]) + readonly actions: MarketFeedActions + readonly #observers = new Set() + readonly #runtime = { + worker: null as Worker | null, + feedSessionId: 0, + renderPending: false, + resetWaitingForCommit: false, + resetSnapshotReady: false, + quoteIndexBySymbol: new Map(), + } + + constructor() { + this.actions = { + toggle: () => { + const running = !this.running.value + this.running.value = running + this.#post({ type: 'set-running', running }) + }, + setInstrumentCount: (count) => { + this.instrumentCount.value = count + this.#resetWorker(count) + }, + setTargetRate: (rate) => { + const sampleRate = normalizeFeedSampleRate(rate) + this.targetTicksPerSecond.value = sampleRate + this.#post({ type: 'set-rate', ticksPerSecond: sampleRate }) + }, + setPublishInterval: (publishIntervalMs) => { + this.publishIntervalMs.value = publishIntervalMs + this.#post({ + type: 'set-publish-interval', + intervalMs: publishIntervalMs, + }) + }, + setSparklineUpdates: (enabled) => { + this.updateSparklines.value = enabled + this.#post({ type: 'set-sparklines', enabled }) + }, + setSparklineSampleInterval: (intervalMs) => { + this.sparklineSampleIntervalMs.value = intervalMs + this.#post({ type: 'set-sparkline-interval', intervalMs }) + }, + runBurst: () => this.#post({ type: 'burst', tickCount: 25_000 }), + reset: () => this.#resetWorker(this.instrumentCount.value), + } + } + + start(): () => void { + const worker = new Worker( + new URL('./worker/market-feed.worker.ts', import.meta.url), + { type: 'module' }, + ) + this.#runtime.worker = worker + worker.addEventListener('message', this.#handleWorkerMessage) + worker.addEventListener('error', this.#handleWorkerError) + this.#post({ + type: 'start', + rowCount: this.instrumentCount.value, + running: this.running.value, + ticksPerSecond: this.targetTicksPerSecond.value, + publishIntervalMs: this.publishIntervalMs.value, + updateSparklines: this.updateSparklines.value, + sparklineSampleIntervalMs: this.sparklineSampleIntervalMs.value, + }) + return () => this.stop() + } + + stop(): void { + this.#runtime.worker?.removeEventListener( + 'message', + this.#handleWorkerMessage, + ) + this.#runtime.worker?.removeEventListener('error', this.#handleWorkerError) + this.#runtime.worker?.terminate() + this.#runtime.worker = null + this.#observers.clear() + } + + observe(observer: MarketFeedObserver): () => void { + this.#observers.add(observer) + return () => this.#observers.delete(observer) + } + + getQuoteBySymbol( + quotes: Array, + symbol: string | null, + ): MarketQuote | null { + if (symbol === null) return null + + const index = this.#runtime.quoteIndexBySymbol.get(symbol) + return index === undefined ? null : (quotes[index] ?? null) + } + + completeRender(): void { + if (!this.#runtime.renderPending) return + + this.#runtime.renderPending = false + for (const observer of this.#observers) { + observer.renderCommitted?.() + } + if ( + this.#runtime.resetWaitingForCommit && + this.#runtime.resetSnapshotReady + ) { + this.#runtime.resetWaitingForCommit = false + this.#runtime.resetSnapshotReady = false + this.#post({ type: 'set-running', running: this.running.value }) + } + } + + readonly #handleWorkerMessage = ({ + data, + }: MessageEvent): void => { + if (data.type === 'snapshot') { + this.#runtime.feedSessionId = data.sessionId + if (this.#runtime.resetWaitingForCommit) { + this.#runtime.resetSnapshotReady = true + } + this.#startMutation() + const quotes = hydrateMarketQuotes(data.quotes) + this.#runtime.quoteIndexBySymbol = new Map( + quotes.map((quote, index) => [quote.symbol, index]), + ) + this.quotes.value = quotes + this.workerReady.value = true + return + } + + if (data.sessionId !== this.#runtime.feedSessionId) return + + for (const observer of this.#observers) { + observer.messageReceived?.() + } + this.#startMutation() + this.quotes.value = applyMarketUpdates(this.quotes.value, data.updates) + const feedBatch = { + tickCount: data.tickCount, + updateCount: data.updates.length, + supersededUpdateCount: data.coalescedUpdateCount, + } + for (const observer of this.#observers) { + observer.batchApplied?.(feedBatch) + } + } + + readonly #handleWorkerError = (error: ErrorEvent): void => { + this.workerReady.value = false + this.running.value = false + console.error('Market feed worker failed', error) + } + + #resetWorker(rowCount: number): void { + this.workerReady.value = false + this.#runtime.resetWaitingForCommit = true + this.#runtime.resetSnapshotReady = false + this.#post({ type: 'set-running', running: false }) + this.#post({ type: 'reset', rowCount }) + } + + #startMutation(): void { + this.#runtime.renderPending = true + for (const observer of this.#observers) { + observer.mutationStarted?.() + } + } + + #post(command: MarketFeedCommand): void { + this.#runtime.worker?.postMessage(command) + } +} diff --git a/examples/vue/realtime-trading/src/feed/market-instruments.ts b/examples/vue/realtime-trading/src/feed/market-instruments.ts new file mode 100644 index 0000000000..ac18d14ea9 --- /dev/null +++ b/examples/vue/realtime-trading/src/feed/market-instruments.ts @@ -0,0 +1,742 @@ +export type MarketCode = + | 'US' + | 'NL' + | 'DE' + | 'FR' + | 'IT' + | 'ES' + | 'CH' + | 'DK' + | 'SE' + | 'FI' + | 'GB' + | 'KR' + | 'JP' + | 'HK' + | 'CA' + | 'AU' + +export type BaseInstrument = readonly [ + symbol: string, + company: string, + market: MarketCode, +] + +/** + * Current S&P 500 constituent universe used by the realtime trading examples. + * + * Source snapshot: https://github.com/datasets/s-and-p-500-companies + * Retrieved: 2026-08-15. + * Multiple share classes are intentionally represented as separate instruments. + */ +export const marketInstruments = Object.freeze([ + ['MMM', '3M', 'US'], + ['AOS', 'A. O. Smith', 'US'], + ['ABT', 'Abbott Laboratories', 'US'], + ['ABBV', 'AbbVie', 'US'], + ['ACN', 'Accenture', 'US'], + ['ADBE', 'Adobe Inc.', 'US'], + ['AMD', 'Advanced Micro Devices', 'US'], + ['AES', 'AES Corporation', 'US'], + ['AFL', 'Aflac', 'US'], + ['A', 'Agilent Technologies', 'US'], + ['APD', 'Air Products', 'US'], + ['ABNB', 'Airbnb', 'US'], + ['AKAM', 'Akamai Technologies', 'US'], + ['ALB', 'Albemarle Corporation', 'US'], + ['ARE', 'Alexandria Real Estate Equities', 'US'], + ['ALGN', 'Align Technology', 'US'], + ['ALLE', 'Allegion', 'US'], + ['LNT', 'Alliant Energy', 'US'], + ['ALL', 'Allstate', 'US'], + ['GOOGL', 'Alphabet Inc. (Class A)', 'US'], + ['GOOG', 'Alphabet Inc. (Class C)', 'US'], + ['MO', 'Altria', 'US'], + ['AMZN', 'Amazon', 'US'], + ['AMCR', 'Amcor', 'US'], + ['AEE', 'Ameren', 'US'], + ['AEP', 'American Electric Power', 'US'], + ['AXP', 'American Express', 'US'], + ['AIG', 'American International Group', 'US'], + ['AMT', 'American Tower', 'US'], + ['AWK', 'American Water Works', 'US'], + ['AMP', 'Ameriprise Financial', 'US'], + ['AME', 'Ametek', 'US'], + ['AMGN', 'Amgen', 'US'], + ['APH', 'Amphenol', 'US'], + ['ADI', 'Analog Devices', 'US'], + ['AON', 'Aon plc', 'US'], + ['APA', 'APA Corporation', 'US'], + ['APO', 'Apollo Global Management', 'US'], + ['AAPL', 'Apple Inc.', 'US'], + ['AMAT', 'Applied Materials', 'US'], + ['APP', 'AppLovin', 'US'], + ['APTV', 'Aptiv', 'US'], + ['ACGL', 'Arch Capital Group', 'US'], + ['ADM', 'Archer Daniels Midland', 'US'], + ['ARES', 'Ares Management', 'US'], + ['ANET', 'Arista Networks', 'US'], + ['AJG', 'Arthur J. Gallagher & Co.', 'US'], + ['AIZ', 'Assurant', 'US'], + ['T', 'AT&T', 'US'], + ['ATO', 'Atmos Energy', 'US'], + ['ADSK', 'Autodesk', 'US'], + ['ADP', 'Automatic Data Processing', 'US'], + ['AZO', 'AutoZone', 'US'], + ['AVB', 'AvalonBay Communities', 'US'], + ['AVY', 'Avery Dennison', 'US'], + ['AXON', 'Axon Enterprise', 'US'], + ['BKR', 'Baker Hughes', 'US'], + ['BALL', 'Ball Corporation', 'US'], + ['BAC', 'Bank of America', 'US'], + ['BAX', 'Baxter International', 'US'], + ['BDX', 'Becton Dickinson', 'US'], + ['BRK.B', 'Berkshire Hathaway', 'US'], + ['BBY', 'Best Buy', 'US'], + ['TECH', 'Bio-Techne', 'US'], + ['BIIB', 'Biogen', 'US'], + ['BLK', 'BlackRock', 'US'], + ['BX', 'Blackstone Inc.', 'US'], + ['XYZ', 'Block, Inc.', 'US'], + ['BNY', 'BNY Mellon', 'US'], + ['BA', 'Boeing', 'US'], + ['BKNG', 'Booking Holdings', 'US'], + ['BSX', 'Boston Scientific', 'US'], + ['BMY', 'Bristol Myers Squibb', 'US'], + ['AVGO', 'Broadcom', 'US'], + ['BR', 'Broadridge Financial Solutions', 'US'], + ['BRO', 'Brown & Brown', 'US'], + ['BF.B', 'Brown–Forman', 'US'], + ['BLDR', 'Builders FirstSource', 'US'], + ['BG', 'Bunge Global', 'US'], + ['BXP', 'BXP, Inc.', 'US'], + ['CHRW', 'C.H. Robinson', 'US'], + ['CDNS', 'Cadence Design Systems', 'US'], + ['CPT', 'Camden Property Trust', 'US'], + ['COF', 'Capital One', 'US'], + ['CAH', 'Cardinal Health', 'US'], + ['CCL', 'Carnival Corporation', 'US'], + ['CARR', 'Carrier Global', 'US'], + ['CVNA', 'Carvana', 'US'], + ['CASY', "Casey's", 'US'], + ['CAT', 'Caterpillar Inc.', 'US'], + ['CBOE', 'Cboe Global Markets', 'US'], + ['CBRE', 'CBRE Group', 'US'], + ['CDW', 'CDW Corporation', 'US'], + ['COR', 'Cencora', 'US'], + ['CNC', 'Centene Corporation', 'US'], + ['CNP', 'CenterPoint Energy', 'US'], + ['CF', 'CF Industries', 'US'], + ['CRL', 'Charles River Laboratories', 'US'], + ['SCHW', 'Charles Schwab Corporation', 'US'], + ['CHTR', 'Charter Communications', 'US'], + ['CVX', 'Chevron Corporation', 'US'], + ['CMG', 'Chipotle Mexican Grill', 'US'], + ['CB', 'Chubb Limited', 'US'], + ['CHD', 'Church & Dwight', 'US'], + ['CIEN', 'Ciena', 'US'], + ['CI', 'Cigna', 'US'], + ['CINF', 'Cincinnati Financial', 'US'], + ['CTAS', 'Cintas', 'US'], + ['CSCO', 'Cisco', 'US'], + ['C', 'Citigroup', 'US'], + ['CFG', 'Citizens Financial Group', 'US'], + ['CLX', 'Clorox', 'US'], + ['CME', 'CME Group', 'US'], + ['CMS', 'CMS Energy', 'US'], + ['KO', 'Coca-Cola Company (The)', 'US'], + ['CTSH', 'Cognizant', 'US'], + ['COHR', 'Coherent Corp.', 'US'], + ['COIN', 'Coinbase', 'US'], + ['CL', 'Colgate-Palmolive', 'US'], + ['CMCSA', 'Comcast', 'US'], + ['FIX', 'Comfort Systems USA', 'US'], + ['COP', 'ConocoPhillips', 'US'], + ['ED', 'Consolidated Edison', 'US'], + ['STZ', 'Constellation Brands', 'US'], + ['CEG', 'Constellation Energy', 'US'], + ['COO', 'Cooper Companies (The)', 'US'], + ['CPRT', 'Copart', 'US'], + ['GLW', 'Corning Inc.', 'US'], + ['CPAY', 'Corpay', 'US'], + ['CTVA', 'Corteva', 'US'], + ['CSGP', 'CoStar Group', 'US'], + ['COST', 'Costco', 'US'], + ['CRH', 'CRH plc', 'US'], + ['CRWD', 'CrowdStrike', 'US'], + ['CCI', 'Crown Castle', 'US'], + ['CSX', 'CSX Corporation', 'US'], + ['CMI', 'Cummins', 'US'], + ['CVS', 'CVS Health', 'US'], + ['DHR', 'Danaher Corporation', 'US'], + ['DRI', 'Darden Restaurants', 'US'], + ['DDOG', 'Datadog', 'US'], + ['DVA', 'DaVita', 'US'], + ['DECK', 'Deckers Brands', 'US'], + ['DE', 'Deere & Company', 'US'], + ['DELL', 'Dell Technologies', 'US'], + ['DAL', 'Delta Air Lines', 'US'], + ['DVN', 'Devon Energy', 'US'], + ['DXCM', 'Dexcom', 'US'], + ['FANG', 'Diamondback Energy', 'US'], + ['DLR', 'Digital Realty', 'US'], + ['DG', 'Dollar General', 'US'], + ['DLTR', 'Dollar Tree', 'US'], + ['D', 'Dominion Energy', 'US'], + ['DPZ', "Domino's", 'US'], + ['DASH', 'DoorDash', 'US'], + ['DOV', 'Dover Corporation', 'US'], + ['DOW', 'Dow Inc.', 'US'], + ['DHI', 'D. R. Horton', 'US'], + ['DTE', 'DTE Energy', 'US'], + ['DUK', 'Duke Energy', 'US'], + ['DD', 'DuPont', 'US'], + ['ETN', 'Eaton Corporation', 'US'], + ['EBAY', 'eBay Inc.', 'US'], + ['ECHO', 'EchoStar', 'US'], + ['ECL', 'Ecolab', 'US'], + ['EIX', 'Edison International', 'US'], + ['EW', 'Edwards Lifesciences', 'US'], + ['ELV', 'Elevance Health', 'US'], + ['EME', 'Emcor', 'US'], + ['EMR', 'Emerson Electric', 'US'], + ['ETR', 'Entergy', 'US'], + ['EOG', 'EOG Resources', 'US'], + ['EQT', 'EQT Corporation', 'US'], + ['EFX', 'Equifax', 'US'], + ['EQIX', 'Equinix', 'US'], + ['EQR', 'Equity Residential', 'US'], + ['ERIE', 'Erie Indemnity', 'US'], + ['ESS', 'Essex Property Trust', 'US'], + ['EL', 'Estée Lauder Companies (The)', 'US'], + ['EG', 'Everest Group', 'US'], + ['EVRG', 'Evergy', 'US'], + ['ES', 'Eversource Energy', 'US'], + ['EXC', 'Exelon', 'US'], + ['EXE', 'Expand Energy', 'US'], + ['EXPE', 'Expedia Group', 'US'], + ['EXPD', 'Expeditors International', 'US'], + ['EXR', 'Extra Space Storage', 'US'], + ['XOM', 'ExxonMobil', 'US'], + ['FFIV', 'F5, Inc.', 'US'], + ['FDS', 'FactSet', 'US'], + ['FICO', 'Fair Isaac', 'US'], + ['FAST', 'Fastenal', 'US'], + ['FRT', 'Federal Realty Investment Trust', 'US'], + ['FDX', 'FedEx', 'US'], + ['FDXF', 'FedEx Freight', 'US'], + ['FERG', 'Ferguson Enterprises', 'US'], + ['FIS', 'Fidelity National Information Services', 'US'], + ['FITB', 'Fifth Third Bancorp', 'US'], + ['FSLR', 'First Solar', 'US'], + ['FE', 'FirstEnergy', 'US'], + ['FISV', 'Fiserv', 'US'], + ['FLEX', 'Flex Ltd.', 'US'], + ['F', 'Ford Motor Company', 'US'], + ['FTNT', 'Fortinet', 'US'], + ['FTV', 'Fortive', 'US'], + ['FOXA', 'Fox Corporation (Class A)', 'US'], + ['FOX', 'Fox Corporation (Class B)', 'US'], + ['BEN', 'Franklin Resources', 'US'], + ['FCX', 'Freeport-McMoRan', 'US'], + ['GRMN', 'Garmin', 'US'], + ['IT', 'Gartner', 'US'], + ['GE', 'GE Aerospace', 'US'], + ['GEHC', 'GE HealthCare', 'US'], + ['GEV', 'GE Vernova', 'US'], + ['GEN', 'Gen Digital', 'US'], + ['GNRC', 'Generac', 'US'], + ['GD', 'General Dynamics', 'US'], + ['GIS', 'General Mills', 'US'], + ['GM', 'General Motors', 'US'], + ['GPC', 'Genuine Parts Company', 'US'], + ['GILD', 'Gilead Sciences', 'US'], + ['GPN', 'Global Payments', 'US'], + ['GL', 'Globe Life', 'US'], + ['GDDY', 'GoDaddy', 'US'], + ['GS', 'Goldman Sachs', 'US'], + ['HAL', 'Halliburton', 'US'], + ['HIG', 'Hartford (The)', 'US'], + ['HAS', 'Hasbro', 'US'], + ['HCA', 'HCA Healthcare', 'US'], + ['DOC', 'Healthpeak Properties', 'US'], + ['HSIC', 'Henry Schein', 'US'], + ['HSY', 'Hershey Company (The)', 'US'], + ['HPE', 'Hewlett Packard Enterprise', 'US'], + ['HLT', 'Hilton Worldwide', 'US'], + ['HD', 'Home Depot (The)', 'US'], + ['HONA', 'Honeywell Aerospace', 'US'], + ['HON', 'Honeywell Technologies', 'US'], + ['HRL', 'Hormel Foods', 'US'], + ['HST', 'Host Hotels & Resorts', 'US'], + ['HWM', 'Howmet Aerospace', 'US'], + ['HPQ', 'HP Inc.', 'US'], + ['HUBB', 'Hubbell Incorporated', 'US'], + ['HUM', 'Humana', 'US'], + ['HBAN', 'Huntington Bancshares', 'US'], + ['HII', 'Huntington Ingalls Industries', 'US'], + ['IBM', 'IBM', 'US'], + ['IEX', 'IDEX Corporation', 'US'], + ['IDXX', 'Idexx Laboratories', 'US'], + ['ITW', 'Illinois Tool Works', 'US'], + ['INCY', 'Incyte', 'US'], + ['IR', 'Ingersoll Rand', 'US'], + ['PODD', 'Insulet Corporation', 'US'], + ['INTC', 'Intel', 'US'], + ['IBKR', 'Interactive Brokers', 'US'], + ['ICE', 'Intercontinental Exchange', 'US'], + ['IFF', 'International Flavors & Fragrances', 'US'], + ['IP', 'International Paper', 'US'], + ['INTU', 'Intuit', 'US'], + ['ISRG', 'Intuitive Surgical', 'US'], + ['IVZ', 'Invesco', 'US'], + ['INVH', 'Invitation Homes', 'US'], + ['IQV', 'IQVIA', 'US'], + ['IRM', 'Iron Mountain', 'US'], + ['JBHT', 'J.B. Hunt', 'US'], + ['JBL', 'Jabil', 'US'], + ['JKHY', 'Jack Henry & Associates', 'US'], + ['J', 'Jacobs Solutions', 'US'], + ['JNJ', 'Johnson & Johnson', 'US'], + ['JCI', 'Johnson Controls', 'US'], + ['JPM', 'JPMorgan Chase', 'US'], + ['KVUE', 'Kenvue', 'US'], + ['KDP', 'Keurig Dr Pepper', 'US'], + ['KEY', 'KeyCorp', 'US'], + ['KEYS', 'Keysight Technologies', 'US'], + ['KMB', 'Kimberly-Clark', 'US'], + ['KIM', 'Kimco Realty', 'US'], + ['KMI', 'Kinder Morgan', 'US'], + ['KKR', 'KKR & Co.', 'US'], + ['KLAC', 'KLA Corporation', 'US'], + ['KHC', 'Kraft Heinz', 'US'], + ['KR', 'Kroger', 'US'], + ['LHX', 'L3Harris', 'US'], + ['LH', 'Labcorp', 'US'], + ['LRCX', 'Lam Research', 'US'], + ['LVS', 'Las Vegas Sands', 'US'], + ['LDOS', 'Leidos', 'US'], + ['LEN', 'Lennar', 'US'], + ['LII', 'Lennox International', 'US'], + ['LLY', 'Lilly (Eli)', 'US'], + ['LIN', 'Linde plc', 'US'], + ['LYV', 'Live Nation Entertainment', 'US'], + ['LMT', 'Lockheed Martin', 'US'], + ['L', 'Loews Corporation', 'US'], + ['LOW', "Lowe's", 'US'], + ['LULU', 'Lululemon Athletica', 'US'], + ['LITE', 'Lumentum', 'US'], + ['LYB', 'LyondellBasell', 'US'], + ['MTB', 'M&T Bank', 'US'], + ['MPC', 'Marathon Petroleum', 'US'], + ['MAR', 'Marriott International', 'US'], + ['MRSH', 'Marsh McLennan', 'US'], + ['MLM', 'Martin Marietta Materials', 'US'], + ['MRVL', 'Marvell Technology', 'US'], + ['MAS', 'Masco', 'US'], + ['MA', 'Mastercard', 'US'], + ['MKC', 'McCormick & Company', 'US'], + ['MCD', "McDonald's", 'US'], + ['MCK', 'McKesson Corporation', 'US'], + ['MDT', 'Medtronic', 'US'], + ['MRK', 'Merck & Co.', 'US'], + ['META', 'Meta Platforms', 'US'], + ['MET', 'MetLife', 'US'], + ['MTD', 'Mettler Toledo', 'US'], + ['MGM', 'MGM Resorts', 'US'], + ['MCHP', 'Microchip Technology', 'US'], + ['MU', 'Micron Technology', 'US'], + ['MSFT', 'Microsoft', 'US'], + ['MAA', 'Mid-America Apartment Communities', 'US'], + ['MRNA', 'Moderna', 'US'], + ['TAP', 'Molson Coors Beverage Company', 'US'], + ['MDLZ', 'Mondelez International', 'US'], + ['MPWR', 'Monolithic Power Systems', 'US'], + ['MNST', 'Monster Beverage', 'US'], + ['MCO', "Moody's Corporation", 'US'], + ['MS', 'Morgan Stanley', 'US'], + ['MOS', 'Mosaic Company (The)', 'US'], + ['MSI', 'Motorola Solutions', 'US'], + ['MSCI', 'MSCI', 'US'], + ['NDAQ', 'Nasdaq, Inc.', 'US'], + ['NTAP', 'NetApp', 'US'], + ['NFLX', 'Netflix', 'US'], + ['NEM', 'Newmont', 'US'], + ['NWSA', 'News Corp (Class A)', 'US'], + ['NWS', 'News Corp (Class B)', 'US'], + ['NEE', 'NextEra Energy', 'US'], + ['NKE', 'Nike, Inc.', 'US'], + ['NI', 'NiSource', 'US'], + ['NDSN', 'Nordson Corporation', 'US'], + ['NSC', 'Norfolk Southern', 'US'], + ['NTRS', 'Northern Trust', 'US'], + ['NOC', 'Northrop Grumman', 'US'], + ['NCLH', 'Norwegian Cruise Line Holdings', 'US'], + ['NRG', 'NRG Energy', 'US'], + ['NUE', 'Nucor', 'US'], + ['NVDA', 'Nvidia', 'US'], + ['NVR', 'NVR, Inc.', 'US'], + ['NXPI', 'NXP Semiconductors', 'US'], + ['ORLY', "O'Reilly Automotive", 'US'], + ['OXY', 'Occidental Petroleum', 'US'], + ['ODFL', 'Old Dominion', 'US'], + ['OMC', 'Omnicom Group', 'US'], + ['ON', 'ON Semiconductor', 'US'], + ['OKE', 'Oneok', 'US'], + ['ORCL', 'Oracle Corporation', 'US'], + ['OTIS', 'Otis Worldwide', 'US'], + ['PCAR', 'Paccar', 'US'], + ['PKG', 'Packaging Corporation of America', 'US'], + ['PLTR', 'Palantir Technologies', 'US'], + ['PANW', 'Palo Alto Networks', 'US'], + ['PSKY', 'Paramount Skydance Corporation', 'US'], + ['PH', 'Parker Hannifin', 'US'], + ['PAYX', 'Paychex', 'US'], + ['PYPL', 'PayPal', 'US'], + ['PNR', 'Pentair', 'US'], + ['PEP', 'PepsiCo', 'US'], + ['PFE', 'Pfizer', 'US'], + ['PCG', 'PG&E Corporation', 'US'], + ['PM', 'Philip Morris International', 'US'], + ['PSX', 'Phillips 66', 'US'], + ['PNW', 'Pinnacle West Capital', 'US'], + ['PNC', 'PNC Financial Services', 'US'], + ['PPG', 'PPG Industries', 'US'], + ['PPL', 'PPL Corporation', 'US'], + ['PFG', 'Principal Financial Group', 'US'], + ['PG', 'Procter & Gamble', 'US'], + ['PGR', 'Progressive Corporation', 'US'], + ['PLD', 'Prologis', 'US'], + ['PRU', 'Prudential Financial', 'US'], + ['PEG', 'Public Service Enterprise Group', 'US'], + ['PTC', 'PTC Inc.', 'US'], + ['PSA', 'Public Storage', 'US'], + ['PHM', 'PulteGroup', 'US'], + ['PWR', 'Quanta Services', 'US'], + ['QCOM', 'Qualcomm', 'US'], + ['DGX', 'Quest Diagnostics', 'US'], + ['Q', 'Qnity Electronics', 'US'], + ['RL', 'Ralph Lauren Corporation', 'US'], + ['RJF', 'Raymond James Financial', 'US'], + ['RTX', 'RTX Corporation', 'US'], + ['O', 'Realty Income', 'US'], + ['REG', 'Regency Centers', 'US'], + ['REGN', 'Regeneron Pharmaceuticals', 'US'], + ['RF', 'Regions Financial Corporation', 'US'], + ['RSG', 'Republic Services', 'US'], + ['RMD', 'ResMed|', 'US'], + ['RVTY', 'Revvity', 'US'], + ['HOOD', 'Robinhood Markets', 'US'], + ['ROK', 'Rockwell Automation', 'US'], + ['ROL', 'Rollins, Inc.', 'US'], + ['ROP', 'Roper Technologies', 'US'], + ['ROST', 'Ross Stores', 'US'], + ['RCL', 'Royal Caribbean Group', 'US'], + ['SPGI', 'S&P Global', 'US'], + ['CRM', 'Salesforce', 'US'], + ['SNDK', 'Sandisk', 'US'], + ['SBAC', 'SBA Communications', 'US'], + ['SLB', 'Schlumberger', 'US'], + ['STX', 'Seagate Technology', 'US'], + ['SRE', 'Sempra', 'US'], + ['NOW', 'ServiceNow', 'US'], + ['SHW', 'Sherwin-Williams', 'US'], + ['SPG', 'Simon Property Group', 'US'], + ['SWKS', 'Skyworks Solutions', 'US'], + ['SJM', 'J.M. Smucker Company (The)', 'US'], + ['SW', 'Smurfit Westrock', 'US'], + ['SNA', 'Snap-on', 'US'], + ['SOLV', 'Solventum', 'US'], + ['SO', 'Southern Company', 'US'], + ['LUV', 'Southwest Airlines', 'US'], + ['SWK', 'Stanley Black & Decker', 'US'], + ['SBUX', 'Starbucks', 'US'], + ['STT', 'State Street Corporation', 'US'], + ['STLD', 'Steel Dynamics', 'US'], + ['STE', 'Steris', 'US'], + ['SYK', 'Stryker Corporation', 'US'], + ['SMCI', 'Supermicro', 'US'], + ['SYF', 'Synchrony Financial', 'US'], + ['SNPS', 'Synopsys', 'US'], + ['SYY', 'Sysco', 'US'], + ['TMUS', 'T-Mobile US', 'US'], + ['TROW', 'T. Rowe Price', 'US'], + ['TTWO', 'Take-Two Interactive', 'US'], + ['TPR', 'Tapestry, Inc.', 'US'], + ['TRGP', 'Targa Resources', 'US'], + ['TGT', 'Target Corporation', 'US'], + ['TEL', 'TE Connectivity', 'US'], + ['TDY', 'Teledyne Technologies', 'US'], + ['TER', 'Teradyne', 'US'], + ['TSLA', 'Tesla, Inc.', 'US'], + ['TXN', 'Texas Instruments', 'US'], + ['TPL', 'Texas Pacific Land Corporation', 'US'], + ['TXT', 'Textron', 'US'], + ['TMO', 'Thermo Fisher Scientific', 'US'], + ['TJX', 'TJX Companies', 'US'], + ['TKO', 'TKO Group Holdings', 'US'], + ['TTD', 'Trade Desk (The)', 'US'], + ['TSCO', 'Tractor Supply', 'US'], + ['TT', 'Trane Technologies', 'US'], + ['TDG', 'TransDigm Group', 'US'], + ['TRV', 'Travelers Companies (The)', 'US'], + ['TRMB', 'Trimble Inc.', 'US'], + ['TFC', 'Truist Financial', 'US'], + ['TYL', 'Tyler Technologies', 'US'], + ['TSN', 'Tyson Foods', 'US'], + ['USB', 'U.S. Bancorp', 'US'], + ['UBER', 'Uber', 'US'], + ['UDR', 'UDR, Inc.', 'US'], + ['ULTA', 'Ulta Beauty', 'US'], + ['UNP', 'Union Pacific Corporation', 'US'], + ['UAL', 'United Airlines Holdings', 'US'], + ['UPS', 'United Parcel Service', 'US'], + ['URI', 'United Rentals', 'US'], + ['UNH', 'UnitedHealth Group', 'US'], + ['UHS', 'Universal Health Services', 'US'], + ['VLO', 'Valero Energy', 'US'], + ['VEEV', 'Veeva Systems', 'US'], + ['VTR', 'Ventas', 'US'], + ['VLTO', 'Veralto', 'US'], + ['VRSN', 'Verisign', 'US'], + ['VRSK', 'Verisk Analytics', 'US'], + ['VZ', 'Verizon', 'US'], + ['VRTX', 'Vertex Pharmaceuticals', 'US'], + ['VRT', 'Vertiv', 'US'], + ['VTRS', 'Viatris', 'US'], + ['VICI', 'Vici Properties', 'US'], + ['V', 'Visa Inc.', 'US'], + ['VST', 'Vistra Corp.', 'US'], + ['VMC', 'Vulcan Materials Company', 'US'], + ['WRB', 'W. R. Berkley Corporation', 'US'], + ['GWW', 'W. W. Grainger', 'US'], + ['WAB', 'Wabtec', 'US'], + ['WMT', 'Walmart', 'US'], + ['DIS', 'Walt Disney Company (The)', 'US'], + ['WBD', 'Warner Bros. Discovery', 'US'], + ['WM', 'Waste Management', 'US'], + ['WAT', 'Waters Corporation', 'US'], + ['WEC', 'WEC Energy Group', 'US'], + ['WFC', 'Wells Fargo', 'US'], + ['WELL', 'Welltower', 'US'], + ['WST', 'West Pharmaceutical Services', 'US'], + ['WDC', 'Western Digital', 'US'], + ['WY', 'Weyerhaeuser', 'US'], + ['WSM', 'Williams-Sonoma, Inc.', 'US'], + ['WMB', 'Williams Companies', 'US'], + ['WTW', 'Willis Towers Watson', 'US'], + ['WDAY', 'Workday, Inc.', 'US'], + ['WYNN', 'Wynn Resorts', 'US'], + ['XEL', 'Xcel Energy', 'US'], + ['XYL', 'Xylem Inc.', 'US'], + ['YUM', 'Yum! Brands', 'US'], + ['ZBRA', 'Zebra Technologies', 'US'], + ['ZBH', 'Zimmer Biomet', 'US'], + ['ZTS', 'Zoetis', 'US'], +]) + +/** + * Representative liquid international listings used to diversify the fixture. + * Symbols use their local-market form and the third tuple value is an ISO-style + * country/market code, rather than a trading currency or exchange MIC. + * + * References checked 2026-08-15: STOXX Europe 50, KRX KOSPI market, + * JPX TOPIX Core30, and HKEX index constituent materials. + */ +const europeanInstruments = Object.freeze([ + ['ASML', 'ASML Holding', 'NL'], + ['INGA', 'ING Group', 'NL'], + ['ADYEN', 'Adyen', 'NL'], + ['PHIA', 'Philips', 'NL'], + ['HEIA', 'Heineken', 'NL'], + ['SAP', 'SAP', 'DE'], + ['SIE', 'Siemens', 'DE'], + ['ALV', 'Allianz', 'DE'], + ['DTE', 'Deutsche Telekom', 'DE'], + ['MBG', 'Mercedes-Benz Group', 'DE'], + ['BMW', 'BMW', 'DE'], + ['BAS', 'BASF', 'DE'], + ['MUV2', 'Munich Re', 'DE'], + ['VOW3', 'Volkswagen Preference', 'DE'], + ['IFX', 'Infineon Technologies', 'DE'], + ['MC', 'LVMH', 'FR'], + ['OR', "L'Oréal", 'FR'], + ['AIR', 'Airbus', 'FR'], + ['SU', 'Schneider Electric', 'FR'], + ['TTE', 'TotalEnergies', 'FR'], + ['SAN', 'Sanofi', 'FR'], + ['BNP', 'BNP Paribas', 'FR'], + ['CS', 'AXA', 'FR'], + ['DG', 'Vinci', 'FR'], + ['ENEL', 'Enel', 'IT'], + ['ENI', 'Eni', 'IT'], + ['ISP', 'Intesa Sanpaolo', 'IT'], + ['UCG', 'UniCredit', 'IT'], + ['STLAM', 'Stellantis', 'IT'], + ['SAN', 'Banco Santander', 'ES'], + ['IBE', 'Iberdrola', 'ES'], + ['ITX', 'Inditex', 'ES'], + ['BBVA', 'BBVA', 'ES'], + ['NESN', 'Nestlé', 'CH'], + ['ROG', 'Roche Holding', 'CH'], + ['NOVN', 'Novartis', 'CH'], + ['UBSG', 'UBS Group', 'CH'], + ['NOVO-B', 'Novo Nordisk', 'DK'], + ['MAERSK-B', 'A.P. Moller - Maersk', 'DK'], + ['VOLV-B', 'Volvo', 'SE'], + ['ERIC-B', 'Ericsson', 'SE'], + ['NOKIA', 'Nokia', 'FI'], + ['SHEL', 'Shell', 'GB'], + ['AZN', 'AstraZeneca', 'GB'], + ['HSBA', 'HSBC Holdings', 'GB'], + ['ULVR', 'Unilever', 'GB'], + ['LSEG', 'London Stock Exchange Group', 'GB'], +]) + +const europeanMarketCodes = Object.freeze([ + 'NL', + 'DE', + 'FR', + 'IT', + 'ES', + 'CH', + 'DK', + 'SE', + 'FI', + 'GB', +]) + +const europeanMarketGroups = Object.freeze( + europeanMarketCodes.map((market) => + europeanInstruments.filter(([, , instrumentMarket]) => + Object.is(instrumentMarket, market), + ), + ), +) + +const interleavedEuropeanInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...europeanMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + europeanMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const southKoreanInstruments = Object.freeze([ + ['005930', 'Samsung Electronics', 'KR'], + ['000660', 'SK hynix', 'KR'], + ['373220', 'LG Energy Solution', 'KR'], + ['207940', 'Samsung Biologics', 'KR'], + ['005380', 'Hyundai Motor', 'KR'], + ['000270', 'Kia', 'KR'], + ['068270', 'Celltrion', 'KR'], + ['105560', 'KB Financial Group', 'KR'], + ['055550', 'Shinhan Financial Group', 'KR'], + ['035420', 'NAVER', 'KR'], + ['035720', 'Kakao', 'KR'], + ['006400', 'Samsung SDI', 'KR'], + ['051910', 'LG Chem', 'KR'], + ['012330', 'Hyundai Mobis', 'KR'], + ['066570', 'LG Electronics', 'KR'], +]) + +const japaneseInstruments = Object.freeze([ + ['8306', 'Mitsubishi UFJ Financial Group', 'JP'], + ['7203', 'Toyota Motor', 'JP'], + ['6501', 'Hitachi', 'JP'], + ['8316', 'Sumitomo Mitsui Financial Group', 'JP'], + ['6758', 'Sony Group', 'JP'], + ['8058', 'Mitsubishi Corporation', 'JP'], + ['9984', 'SoftBank Group', 'JP'], + ['8035', 'Tokyo Electron', 'JP'], + ['8411', 'Mizuho Financial Group', 'JP'], + ['8031', 'Mitsui & Co.', 'JP'], + ['6861', 'Keyence', 'JP'], + ['7974', 'Nintendo', 'JP'], + ['6098', 'Recruit Holdings', 'JP'], + ['9432', 'Nippon Telegraph and Telephone', 'JP'], + ['4063', 'Shin-Etsu Chemical', 'JP'], +]) + +const hongKongInstruments = Object.freeze([ + ['0700', 'Tencent Holdings', 'HK'], + ['9988', 'Alibaba Group', 'HK'], + ['1810', 'Xiaomi', 'HK'], + ['3690', 'Meituan', 'HK'], + ['0941', 'China Mobile', 'HK'], + ['1211', 'BYD Company', 'HK'], + ['1299', 'AIA Group', 'HK'], + ['0388', 'Hong Kong Exchanges and Clearing', 'HK'], + ['0005', 'HSBC Holdings', 'HK'], + ['2318', 'Ping An Insurance', 'HK'], +]) + +const canadianInstruments = Object.freeze([ + ['RY', 'Royal Bank of Canada', 'CA'], + ['TD', 'Toronto-Dominion Bank', 'CA'], + ['SHOP', 'Shopify', 'CA'], + ['ENB', 'Enbridge', 'CA'], + ['CNR', 'Canadian National Railway', 'CA'], + ['CP', 'Canadian Pacific Kansas City', 'CA'], + ['BMO', 'Bank of Montreal', 'CA'], + ['CSU', 'Constellation Software', 'CA'], +]) + +const australianInstruments = Object.freeze([ + ['BHP', 'BHP Group', 'AU'], + ['CBA', 'Commonwealth Bank of Australia', 'AU'], + ['CSL', 'CSL', 'AU'], + ['NAB', 'National Australia Bank', 'AU'], + ['WBC', 'Westpac Banking Corporation', 'AU'], + ['ANZ', 'ANZ Group Holdings', 'AU'], + ['WES', 'Wesfarmers', 'AU'], + ['MQG', 'Macquarie Group', 'AU'], +]) + +const internationalMarketGroups = Object.freeze([ + interleavedEuropeanInstruments, + southKoreanInstruments, + japaneseInstruments, + hongKongInstruments, + canadianInstruments, + australianInstruments, +]) + +export const internationalInstruments = Object.freeze( + Array.from( + { + length: Math.max( + ...internationalMarketGroups.map((instruments) => instruments.length), + ), + }, + (_, index) => + internationalMarketGroups + .map((instruments) => instruments[index]) + .filter(Boolean), + ).flat(), +) + +const INTERNATIONAL_INSERTION_INTERVAL = 3 + +/** + * U.S. and international instruments are interleaved so ordinary benchmark + * sizes exercise multiple symbol formats and market labels. + */ +export const globalInstruments = Object.freeze( + marketInstruments.flatMap((instrument, index) => { + const internationalInstrument = + index % INTERNATIONAL_INSERTION_INTERVAL === 0 + ? internationalInstruments[index / INTERNATIONAL_INSERTION_INTERVAL] + : undefined + + return internationalInstrument + ? [instrument, internationalInstrument] + : [instrument] + }), +) as unknown as ReadonlyArray diff --git a/examples/vue/realtime-trading/src/feed/worker/market-feed-engine.ts b/examples/vue/realtime-trading/src/feed/worker/market-feed-engine.ts new file mode 100644 index 0000000000..fbd9c369c0 --- /dev/null +++ b/examples/vue/realtime-trading/src/feed/worker/market-feed-engine.ts @@ -0,0 +1,177 @@ +import { globalInstruments } from '../market-instruments.ts' +import type { + MarketQuoteSnapshot, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const INITIAL_MARKET_SEED = 0x4d41524b +const LIVE_FEED_SEED = 0x5449434b + +export class MarketFeedEngine { + #quotes: Array = [] + #lastHistorySampledAt = new Uint32Array(0) + #random = createRandom(2_026) + #rowCursor = 0 + #tickIndex = 0 + + reset(count: number): Array { + const random = createRandom(INITIAL_MARKET_SEED ^ count) + const createdAt = Date.now() + + this.#quotes = Array.from({ length: count }, (_, index) => { + const [baseSymbol, company, market] = + globalInstruments[index % globalInstruments.length] + const series = Math.floor(index / globalInstruments.length) + const symbol = series === 0 ? baseSymbol : `${baseSymbol}${series}` + const previousClose = roundPrice(20 + random() * 480) + const open = roundPrice(previousClose * (1 + (random() - 0.5) * 0.016)) + const spread = Math.max(0.01, open * (0.0002 + random() * 0.0004)) + const history = Array.from({ length: 24 }, (_, historyIndex) => + roundPrice( + open * + (1 + Math.sin(historyIndex / 4) * 0.002 + (random() - 0.5) * 0.001), + ), + ) + const volume = Math.floor(50_000 + random() * 2_000_000) + const lastSize = Math.floor(10 + random() * 5_000) + + return { + id: `instrument-${index}`, + symbol, + company, + venue: market, + previousClose, + open, + high: open, + low: open, + price: open, + bid: roundPrice(open - spread / 2), + ask: roundPrice(open + spread / 2), + bidSize: Math.floor(100 + random() * 25_000), + askSize: Math.floor(100 + random() * 25_000), + lastSize, + lastMove: 0, + lastUpdatedAt: createdAt, + volume, + turnover: roundMoney(open * volume), + history, + } + }) + + this.#random = createRandom(LIVE_FEED_SEED ^ count) + this.#rowCursor = 0 + this.#lastHistorySampledAt = new Uint32Array(count) + this.#lastHistorySampledAt.fill(createdAt >>> 0) + + return this.#quotes.map((quote) => ({ + ...quote, + history: [...quote.history], + })) + } + + applyTicks( + tickCount: number, + updateSparklines: boolean, + sparklineSampleIntervalMs: number, + ): Array { + if (this.#quotes.length === 0 || tickCount <= 0) return [] + + const updatedAt = Date.now() + const sampledAt = updatedAt >>> 0 + const sampleIntervalMs = Math.max(16, sparklineSampleIntervalMs) + const updatedQuotes = new Map() + const stride = 97 + + this.#tickIndex = 0 + while (this.#tickIndex < tickCount) { + this.#rowCursor = (this.#rowCursor + stride) % this.#quotes.length + const quote = this.#quotes[this.#rowCursor] + const lastSampledAt = this.#lastHistorySampledAt[this.#rowCursor] + const shouldUpdateHistory = + updateSparklines && + (sampledAt - lastSampledAt) >>> 0 >= sampleIntervalMs + + if (shouldUpdateHistory) { + this.#lastHistorySampledAt[this.#rowCursor] = sampledAt + } + + this.#applyTick(quote, shouldUpdateHistory, updatedAt) + + const previousUpdate = updatedQuotes.get(this.#rowCursor) + updatedQuotes.set(this.#rowCursor, { + index: this.#rowCursor, + price: quote.price, + bid: quote.bid, + ask: quote.ask, + bidSize: quote.bidSize, + askSize: quote.askSize, + lastSize: quote.lastSize, + lastMove: quote.lastMove, + lastUpdatedAt: quote.lastUpdatedAt, + high: quote.high, + low: quote.low, + volume: quote.volume, + turnover: quote.turnover, + ...(shouldUpdateHistory || previousUpdate?.history + ? { history: [...quote.history] } + : {}), + }) + this.#tickIndex++ + } + + return [...updatedQuotes.values()] + } + + #applyTick( + quote: MarketQuoteSnapshot, + updateHistory: boolean, + updatedAt: number, + ): void { + const previousPrice = quote.price + const volatility = 0.00015 + this.#random() * 0.0012 + const move = previousPrice * (this.#random() - 0.495) * volatility + const nextPrice = roundPrice(Math.max(0.1, previousPrice + move)) + const spread = Math.max( + 0.01, + nextPrice * (0.00015 + this.#random() * 0.0005), + ) + + quote.lastMove = nextPrice - previousPrice + quote.price = nextPrice + quote.high = Math.max(quote.high, nextPrice) + quote.low = Math.min(quote.low, nextPrice) + quote.bid = roundPrice(nextPrice - spread / 2) + quote.ask = roundPrice(nextPrice + spread / 2) + quote.bidSize = Math.floor(100 + this.#random() * 25_000) + quote.askSize = Math.floor(100 + this.#random() * 25_000) + quote.lastSize = Math.floor(10 + this.#random() * 5_000) + quote.lastUpdatedAt = updatedAt + quote.volume += quote.lastSize + quote.turnover = roundMoney(quote.turnover + nextPrice * quote.lastSize) + + if (updateHistory) { + quote.history = [...quote.history.slice(-23), nextPrice] + } + } +} + +function createRandom(seed: number): () => number { + const runtime = { state: seed >>> 0 } + return () => { + runtime.state += 0x6d2b79f5 + const stateValue = runtime.state + const firstMix = Math.imul(stateValue ^ (stateValue >>> 15), stateValue | 1) + const secondMix = + firstMix + Math.imul(firstMix ^ (firstMix >>> 7), firstMix | 61) + const value = firstMix ^ secondMix + return ((value ^ (value >>> 14)) >>> 0) / 4_294_967_296 + } +} + +function roundPrice(value: number): number { + return Math.round(value * 100) / 100 +} + +function roundMoney(value: number): number { + return Math.round(value * 100) / 100 +} diff --git a/examples/vue/realtime-trading/src/feed/worker/market-feed-protocol.ts b/examples/vue/realtime-trading/src/feed/worker/market-feed-protocol.ts new file mode 100644 index 0000000000..21997ec89c --- /dev/null +++ b/examples/vue/realtime-trading/src/feed/worker/market-feed-protocol.ts @@ -0,0 +1,70 @@ +export interface MarketQuoteSnapshot { + id: string + symbol: string + company: string + venue: string + previousClose: number + open: number + high: number + low: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + volume: number + turnover: number + history: Array +} + +export interface MarketQuoteUpdate { + index: number + price: number + bid: number + ask: number + bidSize: number + askSize: number + lastSize: number + lastMove: number + lastUpdatedAt: number + high: number + low: number + volume: number + turnover: number + history?: Array +} + +export type MarketFeedCommand = + | { + type: 'start' + rowCount: number + running: boolean + ticksPerSecond: number + publishIntervalMs: number + updateSparklines: boolean + sparklineSampleIntervalMs: number + } + | { type: 'set-running'; running: boolean } + | { type: 'set-rate'; ticksPerSecond: number } + | { type: 'set-publish-interval'; intervalMs: number } + | { type: 'set-sparklines'; enabled: boolean } + | { type: 'set-sparkline-interval'; intervalMs: number } + | { type: 'reset'; rowCount: number } + | { type: 'burst'; tickCount: number } + +export type MarketFeedEvent = + | { + type: 'snapshot' + sessionId: number + quotes: Array + } + | { + type: 'updates' + sessionId: number + tickCount: number + coalescedUpdateCount: number + updates: Array + } diff --git a/examples/vue/realtime-trading/src/feed/worker/market-feed.worker.ts b/examples/vue/realtime-trading/src/feed/worker/market-feed.worker.ts new file mode 100644 index 0000000000..2b7a642fd9 --- /dev/null +++ b/examples/vue/realtime-trading/src/feed/worker/market-feed.worker.ts @@ -0,0 +1,143 @@ +import { initialMarketFeedConfig } from '../market-feed-config' +import { MarketFeedEngine } from './market-feed-engine' +import type { + MarketFeedCommand, + MarketFeedEvent, + MarketQuoteUpdate, +} from './market-feed-protocol' + +const engine = new MarketFeedEngine() +const pendingUpdates = new Map() +const runtime = { + sessionId: 0, + pendingTickCount: 0, + pendingCoalescedUpdateCount: 0, + initialized: false, + running: true, + ticksPerSecond: initialMarketFeedConfig.targetSamplesPerSecond, + publishIntervalMs: initialMarketFeedConfig.publishIntervalMs, + publishTimerId: null as ReturnType | null, + updateSparklines: initialMarketFeedConfig.updateSparklines, + sparklineSampleIntervalMs: initialMarketFeedConfig.sparklineSampleIntervalMs, + tickBudget: 0, + lastTickAt: performance.now(), +} + +addEventListener('message', ({ data }: MessageEvent) => { + switch (data.type) { + case 'start': + runtime.running = data.running + runtime.ticksPerSecond = data.ticksPerSecond + runtime.publishIntervalMs = data.publishIntervalMs + runtime.updateSparklines = data.updateSparklines + runtime.sparklineSampleIntervalMs = data.sparklineSampleIntervalMs + restartPublishTimer() + reset(data.rowCount) + break + case 'set-running': + runtime.running = data.running + break + case 'set-rate': + runtime.ticksPerSecond = data.ticksPerSecond + break + case 'set-publish-interval': + runtime.publishIntervalMs = Math.max(4, data.intervalMs) + restartPublishTimer() + break + case 'set-sparklines': + runtime.updateSparklines = data.enabled + break + case 'set-sparkline-interval': + runtime.sparklineSampleIntervalMs = Math.max(16, data.intervalMs) + break + case 'reset': + reset(data.rowCount) + break + case 'burst': + produceTicks(data.tickCount) + flush() + break + } +}) + +setInterval(() => { + const now = performance.now() + const elapsed = Math.min(100, Math.max(0, now - runtime.lastTickAt)) + runtime.lastTickAt = now + + if (runtime.initialized && runtime.running) { + runtime.tickBudget += (runtime.ticksPerSecond * elapsed) / 1_000 + const tickCount = Math.floor(runtime.tickBudget) + runtime.tickBudget -= tickCount + produceTicks(tickCount) + } +}, 16) + +restartPublishTimer() + +function reset(rowCount: number): void { + runtime.initialized = true + runtime.sessionId++ + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + runtime.tickBudget = 0 + runtime.lastTickAt = performance.now() + + post({ + type: 'snapshot', + sessionId: runtime.sessionId, + quotes: engine.reset(rowCount), + }) +} + +function produceTicks(tickCount: number): void { + if (!runtime.initialized || tickCount <= 0) return + + runtime.pendingTickCount += tickCount + for (const update of engine.applyTicks( + tickCount, + runtime.updateSparklines, + runtime.sparklineSampleIntervalMs, + )) { + const previousUpdate = pendingUpdates.get(update.index) + if (previousUpdate) runtime.pendingCoalescedUpdateCount++ + pendingUpdates.set(update.index, { + ...update, + ...(update.history || !previousUpdate?.history + ? {} + : { history: previousUpdate.history }), + }) + } +} + +function flush(): void { + if (runtime.pendingTickCount === 0) return + + const message: MarketFeedEvent = { + type: 'updates', + sessionId: runtime.sessionId, + tickCount: runtime.pendingTickCount, + coalescedUpdateCount: runtime.pendingCoalescedUpdateCount, + updates: [...pendingUpdates.values()], + } + + runtime.pendingTickCount = 0 + runtime.pendingCoalescedUpdateCount = 0 + pendingUpdates.clear() + post(message) +} + +function restartPublishTimer(): void { + if (runtime.publishTimerId !== null) { + clearInterval(runtime.publishTimerId) + } + runtime.publishTimerId = setInterval( + flush, + Math.max(4, runtime.publishIntervalMs), + ) +} + +function post(event: MarketFeedEvent): void { + postMessage(event) +} diff --git a/examples/vue/realtime-trading/src/index.css b/examples/vue/realtime-trading/src/index.css new file mode 100644 index 0000000000..397c86fc54 --- /dev/null +++ b/examples/vue/realtime-trading/src/index.css @@ -0,0 +1,1058 @@ +:root { + color-scheme: dark; + --font-ui: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + 'Segoe UI', sans-serif; + --font-mono: 'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace; + font-family: var(--font-ui); + font-synthesis: none; + --background: #050505; + --panel: #080808; + --panel-raised: #111111; + --panel-hover: #181818; + --surface-bar: #080808; + --surface-toolbar: #0d0d0d; + --surface-table: #050505; + --surface-header: #101010; + --surface-control: #151515; + --border: #303030; + --border-soft: #242424; + --border-strong: #4a4a4a; + --text: #e7ebf0; + --text-strong: #ffffff; + --text-inverse: #f7f9fb; + --muted: #737982; + --blue: #62a9ff; + --blue-soft: #a9d0ff; + --green: #42e488; + --red: #ff646b; + --amber: #dfb465; + --depth-bid: #315774; + --depth-ask: #634049; + --row-alt: rgb(255 255 255 / 1.8%); + --row-selected: rgb(66 132 214 / 16%); + --control-border: #354456; + --control-hover: #192431; + --sidebar-width: 18rem; + --shell-bar-height: 2.625rem; + --metrics-height: 3.5rem; + --statusbar-height: 1.625rem; + --virtual-footer-height: 2.125rem; + --table-header-height: 2rem; + --table-row-height: 2rem; + --shell-inline-padding: 0.75rem; + --table-cell-inline-padding: 0.6rem; + --control-radius: 1px; +} + +* { + box-sizing: border-box; +} + +html, +body { + min-width: 320px; + min-height: 100%; + margin: 0; + background: var(--background); +} + +body { + color: var(--text); +} + +button, +select, +input { + font: inherit; +} + +button, +select { + color: var(--text); + background: var(--panel-raised); + border: 1px solid var(--control-border); + border-radius: var(--control-radius); +} + +button { + padding: 0.5rem 0.65rem; + cursor: pointer; + font-size: 0.72rem; + font-weight: 650; + letter-spacing: 0.025em; +} + +button:hover { + background: var(--control-hover); + border-color: var(--border-strong); +} + +button:focus-visible, +select:focus-visible, +input:focus-visible { + outline: 1px solid var(--blue); + outline-offset: 1px; +} + +select { + width: 100%; + padding: 0.45rem 0.55rem; + font-size: 0.75rem; +} + +.trading-terminal { + --active-sidebar-width: var(--sidebar-width); + display: grid; + width: 100%; + height: 100dvh; + min-height: 0; + overflow: hidden; + background: var(--background); + grid-template-areas: + 'header sidebar' + 'content sidebar' + 'footer sidebar'; + grid-template-columns: minmax(0, 1fr) var(--active-sidebar-width); + grid-template-rows: auto minmax(0, 1fr) auto; + transition: grid-template-columns 160ms ease; +} + +.trading-terminal.is-sidebar-collapsed { + --active-sidebar-width: 0px; +} + +.shell-header { + display: flex; + min-width: 0; + flex-direction: column; + grid-area: header; +} + +.app-bar { + display: flex; + min-height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + background: var(--surface-bar); + border-bottom: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.68rem; + letter-spacing: 0.045em; +} + +.brand, +.header-actions, +.feed-status { + display: flex; + align-items: center; +} + +.brand { + gap: 0.65rem; + color: var(--text-strong); +} + +.header-actions { + gap: 0.75rem; +} + +.sidebar-toggle { + display: grid; + width: 1.9rem; + height: 1.9rem; + padding: 0; + place-items: center; + color: var(--muted); + background: transparent; + border-color: transparent; +} + +.sidebar-toggle:hover { + color: var(--text-strong); + background: var(--surface-control); + border-color: var(--border); +} + +.sidebar-toggle svg { + width: 1rem; + height: 1rem; + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-width: 1.4; +} + +.feed-status { + gap: 0.4rem; + color: var(--muted); +} + +.feed-status.is-running { + color: var(--green); +} + +.status-dot { + width: 6px; + height: 6px; + background: var(--muted); + border-radius: 50%; +} + +.feed-status.is-running .status-dot { + background: var(--green); +} + +.development-warning { + flex: 0 0 auto; + padding: 0.3rem 0.75rem; + color: var(--amber); + background: color-mix(in srgb, var(--amber) 8%, var(--background)); + border-bottom: 1px solid color-mix(in srgb, var(--amber) 24%, var(--border)); + font-family: var(--font-mono); + font-size: 0.62rem; + letter-spacing: 0.04em; +} + +.market-panel { + display: flex; + min-width: 0; + min-height: 0; + flex-direction: column; + background: var(--panel); + grid-area: content; +} + +.metrics-strip { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + background: var(--border); + border-bottom: 1px solid var(--border); + gap: 1px; +} + +.metrics-strip h2 { + margin: 0; + padding: 0.65rem var(--shell-inline-padding) 0.45rem; + color: var(--muted); + background: var(--surface-table); + font-size: 0.58rem; + grid-column: 1 / -1; + letter-spacing: 0.075em; +} + +.metrics-strip article { + min-width: 0; + min-height: 4.25rem; + padding: 0.5rem var(--shell-inline-padding); + background: var(--surface-bar); +} + +.metrics-strip span, +.metrics-strip small { + display: block; + color: var(--muted); + font-size: 0.56rem; + letter-spacing: 0.045em; + line-height: 1.35; +} + +.metrics-strip strong { + display: block; + margin: 0.12rem 0 0.08rem; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.88rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +.metrics-strip strong.metric-alert { + color: var(--amber); +} + +.table-scroll { + flex: 1; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +.virtual-scroll-footer { + display: flex; + flex: 0 0 auto; + align-items: center; + justify-content: space-between; + min-height: var(--virtual-footer-height); + padding: 0 var(--shell-inline-padding); + color: var(--muted); + background: var(--surface-toolbar); + border-top: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.68rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +table { + min-width: 100%; + border-spacing: 0; + table-layout: fixed; + font-family: var(--font-ui); + font-size: 0.78rem; + font-variant-numeric: tabular-nums; +} + +.virtual-table { + display: grid; +} + +.virtual-table thead { + display: grid; +} + +.virtual-table thead tr, +.virtual-table-row { + display: flex; + width: 100%; +} + +.virtual-table th, +.virtual-table-row > td { + flex: 0 0 auto; +} + +.virtual-table-body { + position: relative; + display: grid; +} + +.virtual-table-row { + position: absolute; + left: 0; + height: var(--table-row-height); +} + +.virtual-table-row > td { + display: block; +} + +.trading-data-grid { + display: grid; +} + +.trading-data-grid thead, +.trading-data-grid tbody { + display: grid; +} + +.trading-data-grid tbody { + -webkit-user-select: none; + user-select: none; +} + +.trading-data-grid thead > tr, +.trading-data-grid tbody > tr { + display: flex; + width: 100%; +} + +.trading-data-grid tbody > tr { + min-height: var(--table-row-height); + content-visibility: auto; + contain-intrinsic-block-size: var(--table-row-height); +} + +.trading-data-grid th, +.trading-data-grid td { + flex: 0 0 auto; +} + +thead { + position: sticky; + z-index: 2; + top: 0; +} + +th { + height: var(--table-header-height); + padding: 0 var(--table-cell-inline-padding); + color: var(--muted); + background: var(--surface-header); + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border); + font-size: 0.7rem; + font-weight: 500; + letter-spacing: 0.005em; + text-align: left; + white-space: nowrap; +} + +th.column-group-header { + color: #666b72; + font-size: 0.72rem; + font-weight: 500; + text-align: center; +} + +thead tr:first-child th.column-group-header { + color: #777d85; + font-size: 0.76rem; +} + +th.numeric-header { + text-align: right; +} + +td { + height: var(--table-row-height); + padding: 0 var(--table-cell-inline-padding); + overflow: hidden; + color: #eef1f5; + border-right: 1px solid var(--border-soft); + border-bottom: 1px solid var(--border-soft); + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +th:last-child, +td:last-child { + border-right: 0; +} + +td[data-column-id='market'], +td[data-column-id='name'], +td[data-column-id='symbol'] { + text-align: left; +} + +td[data-column-id='market'] { + color: var(--blue); + font-weight: 550; +} + +td[data-column-id='name'] { + color: var(--text-strong); +} + +td[data-column-id='symbol'] { + color: #d8dde4; + font-weight: 600; +} + +tbody tr:nth-child(even) { + background: var(--row-alt); +} + +tbody tr:hover { + background: var(--panel-hover); +} + +tbody tr[data-symbol-selected='true'] { + background: var(--row-selected); + box-shadow: inset 2px 0 0 var(--blue); +} + +.table-scroll:focus { + outline: none; +} + +th { + position: relative; +} + +.leaf-header-content { + display: flex; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + height: 100%; + align-items: stretch; + margin-inline: calc(-1 * var(--table-cell-inline-padding)); +} + +.column-drag-handle, +.sort-header-button { + min-width: 0; + height: 100%; + padding: 0; + color: inherit; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-weight: inherit; + letter-spacing: inherit; +} + +.column-drag-handle { + flex: 0 0 1.05rem; + color: var(--muted); + cursor: grab; + opacity: 0.35; + font-size: 0.56rem; + letter-spacing: -0.32rem; + text-align: center; +} + +.column-drag-handle:active { + cursor: grabbing; +} + +th:hover .column-drag-handle, +.column-drag-handle:focus-visible { + opacity: 0.9; +} + +.column-drag-handle:hover, +.sort-header-button:hover { + background: rgb(255 255 255 / 4%); + border-color: transparent; +} + +th.is-column-dragging { + opacity: 0.45; +} + +th.is-column-drop-target { + background: rgb(50 139 255 / 16%); + box-shadow: inset 4px 0 0 var(--blue); +} + +th.is-column-drop-target::before { + position: absolute; + z-index: 6; + top: -1px; + bottom: -1px; + left: -2px; + width: 4px; + background: #62a9ff; + box-shadow: + 0 0 0 1px rgb(0 0 0 / 55%), + 0 0 12px rgb(70 151 255 / 90%); + content: ''; + pointer-events: none; +} + +.sort-header-button { + display: flex; + min-width: 0; + flex: 1; + align-items: center; + justify-content: flex-start; + gap: 0.3rem; + padding-inline: 0.25rem var(--table-cell-inline-padding); + cursor: default; + text-align: inherit; +} + +.numeric-header .sort-header-button { + justify-content: flex-end; +} + +.sort-header-button.is-sortable { + cursor: pointer; +} + +.sort-header-button:disabled { + opacity: 1; +} + +.header-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.sort-indicator { + flex: 0 0 auto; + color: #66717e; + font-size: 0.72rem; +} + +.sort-indicator.is-active { + color: var(--blue-soft); +} + +.column-resize-handle { + position: absolute; + z-index: 3; + top: 0; + right: -3px; + width: 7px; + height: 100%; + cursor: col-resize; + touch-action: none; + user-select: none; +} + +.column-resize-handle::after { + position: absolute; + top: 20%; + right: 3px; + width: 1px; + height: 60%; + background: var(--border-strong); + content: ''; + opacity: 0; +} + +th:hover > .column-resize-handle::after, +.column-resize-handle.is-resizing::after { + background: var(--blue); + opacity: 1; +} + +tbody tr[aria-selected='true'] { + background: rgb(76 145 228 / 13%); +} + +td[aria-selected='true'] { + position: relative; + background: rgb(70 139 222 / 12%); +} + +td[data-cell-focused='true'] { + background: rgb(70 139 222 / 21%); +} + +td[aria-selected='true']::after { + position: absolute; + z-index: 1; + inset: 0; + border: 1px solid transparent; + content: ''; + pointer-events: none; +} + +td[data-selection-top='true']::after { + border-top-color: var(--blue); +} + +td[data-selection-right='true']::after { + border-right-color: var(--blue); +} + +td[data-selection-bottom='true']::after { + border-bottom-color: var(--blue); +} + +td[data-selection-left='true']::after { + border-left-color: var(--blue); +} + +.price-button { + min-width: 4.5rem; + padding: 0; + background: transparent; + border: 0; + border-radius: 0; + font-family: inherit; + font-size: inherit; + font-variant-numeric: tabular-nums; + font-weight: 600; + text-align: right; +} + +.price-button:hover { + background: transparent; + text-decoration: underline; + text-underline-offset: 2px; +} + +.move-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.move-cell.quote-up, +.percent-change-cell.quote-up { + background: color-mix(in srgb, var(--green) 7%, transparent); +} + +.move-cell.quote-down, +.percent-change-cell.quote-down { + background: color-mix(in srgb, var(--red) 7%, transparent); +} + +.percent-change-cell { + display: block; + width: calc(100% + 2 * var(--table-cell-inline-padding)); + margin-inline: calc(-1 * var(--table-cell-inline-padding)); + padding-inline: var(--table-cell-inline-padding); + line-height: var(--table-row-height); + text-align: right; +} + +.spread-cell { + display: flex; + align-items: baseline; + justify-content: flex-end; + gap: 0.35rem; + color: var(--text); +} + +.spread-cell small { + min-width: 2.8rem; + color: var(--muted); + font-size: 0.55rem; +} + +.spread-cell.spread-wide, +.spread-cell.spread-wide small { + color: var(--amber); +} + +.depth-cell { + position: relative; + display: flex; + height: 17px; + overflow: hidden; + background: var(--surface-control); +} + +.depth-bid, +.depth-ask { + height: 100%; + opacity: 0.78; +} + +.depth-bid { + background: var(--depth-bid); + border-right: 1px solid var(--panel); +} + +.depth-ask { + background: var(--depth-ask); +} + +.depth-values { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 0.28rem; + color: var(--text-strong); + font-size: 0.57rem; + text-shadow: 0 1px var(--background); +} + +.quote-age { + color: var(--muted); +} + +.quote-age-warm { + color: var(--amber); +} + +.quote-age-stale { + color: var(--red); +} + +.quote-up { + color: var(--green); +} + +.quote-down { + color: var(--red); +} + +.sparkline { + display: block; + width: 100%; + height: 1.35rem; + margin-left: auto; + color: var(--blue-soft); + overflow: visible; +} + +.sparkline.quote-up { + color: var(--green); +} + +.sparkline.quote-down { + color: var(--red); +} + +.sparkline polyline { + fill: none; + stroke: currentColor; + stroke-linecap: square; + stroke-linejoin: miter; + stroke-width: 1.25; + vector-effect: non-scaling-stroke; +} + +.market-statusbar { + display: flex; + flex: 0 0 var(--statusbar-height); + min-height: var(--statusbar-height); + gap: 1.1rem; + align-items: center; + padding: 0 0.65rem; + color: var(--muted); + background: var(--surface-bar); + border-top: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.56rem; + grid-area: footer; + letter-spacing: 0.035em; +} + +.market-statusbar strong { + margin-left: 0.25rem; + color: var(--text); + font-weight: 500; +} + +.sidebar-slot { + width: var(--sidebar-width); + min-width: 0; + min-height: 0; + overflow: hidden; + background: var(--surface-table); + border-left: 1px solid var(--border); + grid-area: sidebar; + transition: + opacity 120ms ease, + transform 160ms ease, + visibility 160ms; +} + +.is-sidebar-collapsed .sidebar-slot { + visibility: hidden; + opacity: 0; + pointer-events: none; + transform: translateX(100%); +} + +.configurator { + width: 100%; + height: 100%; + min-height: 0; + overflow: auto; + background: var(--surface-table); +} + +.configurator > header { + display: flex; + height: var(--shell-bar-height); + align-items: center; + justify-content: space-between; + padding: 0 var(--shell-inline-padding); + color: var(--text-strong); + background: var(--surface-toolbar); + border-bottom: 1px solid var(--border); + font-size: 0.65rem; + font-weight: 700; + letter-spacing: 0.055em; +} + +.configurator > header small { + color: var(--muted); + font-size: 0.54rem; + font-weight: 500; +} + +.config-section { + display: grid; + gap: 0.7rem; + padding: 0.8rem var(--shell-inline-padding); + border-bottom: 1px solid var(--border); +} + +.config-section h2 { + margin: 0; + color: var(--muted); + font-size: 0.58rem; + letter-spacing: 0.075em; +} + +.primary-action { + width: 100%; + color: var(--text-inverse); + background: var(--blue); + border-color: var(--blue-soft); +} + +.primary-action:hover { + background: var(--blue-soft); + border-color: var(--text-strong); +} + +.field { + display: grid; + gap: 0.35rem; + color: var(--text); + font-size: 0.66rem; +} + +.rate-field > span { + display: flex; + justify-content: space-between; +} + +.rate-field strong { + color: var(--text); + font-family: var(--font-mono); + font-weight: 500; +} + +.field small { + color: var(--muted); + font-family: var(--font-mono); + font-size: 0.55rem; +} + +input[type='range'] { + width: 100%; + margin: 0; + accent-color: var(--blue); +} + +.toggle-field { + display: flex; + gap: 0.5rem; + align-items: flex-start; + color: var(--text); + font-size: 0.66rem; + line-height: 1.3; +} + +.toggle-field input { + margin: 0.12rem 0 0; + accent-color: var(--blue); +} + +.toggle-field small { + display: block; + margin-top: 0.14rem; + color: var(--muted); + font-size: 0.57rem; +} + +.action-grid { + display: grid; + grid-template-columns: 1fr; + gap: 0.4rem; +} + +.diagnostics dl, +.selected-instrument dl { + display: grid; + gap: 0; + margin: 0; +} + +.diagnostics dl > div, +.selected-instrument dl > div { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 24px; + border-bottom: 1px solid var(--border-soft); +} + +.diagnostics dl > div:last-child, +.selected-instrument dl > div:last-child { + border-bottom: 0; +} + +.diagnostics dl > div:has(dd[data-testid$='-breakdown']) { + display: grid; + grid-template-columns: minmax(0, 1fr); + align-content: center; + padding-block: 0.28rem; +} + +.diagnostics dd[data-testid$='-breakdown'] { + width: 100%; + overflow-x: auto; + padding-block: 0.12rem; + white-space: nowrap; + scrollbar-width: thin; +} + +dt { + color: var(--muted); + font-size: 0.61rem; +} + +dd { + margin: 0; + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.62rem; +} + +.selection { + display: flex; + align-items: flex-start; + justify-content: space-between; +} + +.selection div { + display: grid; + gap: 0.18rem; +} + +.selection strong { + color: var(--text-strong); + font-family: var(--font-mono); + font-size: 0.85rem; +} + +.selection span, +.selection small, +.selected-instrument p { + color: var(--muted); + font-size: 0.61rem; +} + +.selected-instrument p { + margin: 0; + line-height: 1.45; +} + +@media (max-width: 980px) { + :root { + --sidebar-width: 15.625rem; + } +} + +@media (max-width: 720px) { + .trading-terminal { + --active-sidebar-width: 0px; + height: 100dvh; + min-height: 0; + overflow: hidden; + } + + .market-panel { + min-height: 0; + } + + .table-scroll { + min-height: 0; + } + + .sidebar-slot { + position: fixed; + z-index: 20; + top: 0; + right: 0; + bottom: 0; + width: min(var(--sidebar-width), calc(100vw - 2.75rem)); + box-shadow: -18px 0 42px rgb(0 0 0 / 48%); + } + + .is-sidebar-collapsed .sidebar-slot { + box-shadow: none; + } +} diff --git a/examples/vue/realtime-trading/src/main.ts b/examples/vue/realtime-trading/src/main.ts new file mode 100644 index 0000000000..196e4d4b2c --- /dev/null +++ b/examples/vue/realtime-trading/src/main.ts @@ -0,0 +1,5 @@ +import { createApp } from 'vue' +import { App } from './App' +import './index.css' + +createApp(App).mount('#root') diff --git a/examples/vue/realtime-trading/src/shell/TradingShell.tsx b/examples/vue/realtime-trading/src/shell/TradingShell.tsx new file mode 100644 index 0000000000..450e2e7077 --- /dev/null +++ b/examples/vue/realtime-trading/src/shell/TradingShell.tsx @@ -0,0 +1,615 @@ +import { computed, defineComponent, ref } from 'vue' +import { + feedSampleRateAt, + feedSampleRateIndex, + feedSampleRateOptions, +} from '../feed/feed-sample-rates' +import { + FORCED_VIRTUALIZATION_ROW_COUNT, + resolveVirtualScrollMode, +} from '../table/trading-row-virtualizer' +import { + useMarketFeedController, + useTradingShellController, +} from './trading-shell-context' +import { configuratorOptions } from './configurator-options' +import type { FeedMetrics } from '../benchmark/benchmark-monitor' + +const integerFormatter = new Intl.NumberFormat('en-US', { + maximumFractionDigits: 0, +}) +const rateFormatter = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) + +export const TradingShell = defineComponent({ + name: 'TradingShell', + setup(_, { slots }) { + const sidebarOpen = ref(true) + return () => ( +
+
+ { + sidebarOpen.value = !sidebarOpen.value + }} + /> + {import.meta.env.DEV && ( + + )} +
+
+ {slots.default?.()} +
+ + +
+ ) + }, +}) + +const AppHeader = defineComponent({ + name: 'AppHeader', + props: { + sidebarOpen: { type: Boolean, required: true }, + onSidebarToggle: { type: Function, required: true }, + }, + setup(props) { + const feed = useMarketFeedController() + return () => ( +
+
+ MARKET MONITOR +
+
+ + + +
+
+ ) + }, +}) + +const MetricsStrip = defineComponent({ + name: 'MetricsStrip', + setup() { + const controller = useTradingShellController() + return () => { + const metrics = controller.metrics.value + return ( +
+

LIVE HEALTH

+ + + +
+ THROUGHPUT + + {formatRate(metrics.rowUpdatesPerSecond)} rows/s + + + {metrics.stateApplicationsPerSecond.toFixed(1)} snapshots/s · rows + deduplicated per snapshot + +
+
+ ) + } + }, +}) + +const Metric = defineComponent({ + name: 'Metric', + props: { + label: { type: String, required: true }, + value: { type: String, required: true }, + detail: { type: String, required: true }, + testId: String, + }, + setup(props) { + return () => ( +
+ {props.label} + {props.value} + {props.detail} +
+ ) + }, +}) + +const MarketStatusbar = defineComponent({ + name: 'MarketStatusbar', + setup() { + const controller = useTradingShellController() + return () => { + const metrics = controller.metrics.value + return ( +
+ + MESSAGE SAMPLES{' '} + {formatInteger(metrics.lastBatchSize)} + + + CHANGED ROWS{' '} + {formatInteger(metrics.lastUpdateCount)} + + + HOSTS{' '} + {formatInteger(controller.mountedCells.value)} + + + COMPONENTS{' '} + {formatInteger(controller.liveComponents.value)} + +
+ ) + } + }, +}) + +const Configurator = defineComponent({ + name: 'Configurator', + setup() { + const controller = useTradingShellController() + const feed = useMarketFeedController() + const virtualScrollForced = computed( + () => feed.instrumentCount.value >= FORCED_VIRTUALIZATION_ROW_COUNT, + ) + const virtualScrollMode = computed(() => + resolveVirtualScrollMode( + controller.requestedVirtualScrollMode.value, + feed.instrumentCount.value, + ), + ) + + return () => ( + + ) + }, +}) + +const Diagnostics = defineComponent({ + name: 'Diagnostics', + setup() { + const controller = useTradingShellController() + return () => { + const metrics = controller.metrics.value + return ( +
+

DIAGNOSTICS

+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ ) + } + }, +}) + +const Diagnostic = defineComponent({ + name: 'Diagnostic', + props: { + label: { type: String, required: true }, + value: { type: String, required: true }, + testId: String, + }, + setup(props) { + return () => ( +
+
{props.label}
+
{props.value}
+
+ ) + }, +}) + +const SelectedInstrument = defineComponent({ + name: 'SelectedInstrument', + setup() { + const controller = useTradingShellController() + const feed = useMarketFeedController() + const selectedQuote = computed(() => + feed.getQuoteBySymbol(feed.quotes.value, controller.selectedSymbol.value), + ) + return () => ( +
+

SELECTED INSTRUMENT

+ {selectedQuote.value ? ( + <> +
+
+ {selectedQuote.value.symbol} + {selectedQuote.value.company} +
+ {selectedQuote.value.venue} +
+
+
+
Last
+
{selectedQuote.value.price.toFixed(2)}
+
+
+
Bid / ask
+
+ {selectedQuote.value.bid.toFixed(2)} /{' '} + {selectedQuote.value.ask.toFixed(2)} +
+
+
+ + ) : ( +

+ Click or begin a cell selection in any row to inspect its + instrument. +

+ )} +
+ ) + }, +}) + +function optionNode(option: { + readonly label: string + readonly value: number | string +}) { + return ( + + ) +} + +function stringValue(event: Event): string { + return (event.target as HTMLInputElement | HTMLSelectElement).value +} + +function numberValue(event: Event): number { + return Number(stringValue(event)) +} + +function checkedValue(event: Event): boolean { + return (event.target as HTMLInputElement).checked +} + +function formatRate(value: number): string { + return rateFormatter.format(value) +} + +function formatInteger(value: number): string { + return integerFormatter.format(value) +} + +function formatMs(value: number): string { + return `${value.toFixed(2)} ms` +} + +function formatInvocationRates( + rates: FeedMetrics['cellRendererRates'], +): string { + const active = rates.filter((entry) => entry.callsPerSecond > 0) + return active.length === 0 + ? '—' + : active + .map((entry) => `${entry.name} ${formatRate(entry.callsPerSecond)}`) + .join(' · ') +} diff --git a/examples/vue/realtime-trading/src/shell/configurator-options.ts b/examples/vue/realtime-trading/src/shell/configurator-options.ts new file mode 100644 index 0000000000..49a9566fe7 --- /dev/null +++ b/examples/vue/realtime-trading/src/shell/configurator-options.ts @@ -0,0 +1,55 @@ +export interface ConfiguratorOption { + readonly label: string + readonly value: TValue +} + +const instrumentCountOptions = [ + { label: '50', value: 50 }, + { label: '100', value: 100 }, + { label: '150', value: 150 }, + { label: '250', value: 250 }, + { label: '350', value: 350 }, + { label: '500', value: 500 }, + { label: '750', value: 750 }, + { label: '1,000', value: 1_000 }, + { label: '1,500', value: 1_500 }, + { label: '2,500', value: 2_500 }, + { label: '5,000', value: 5_000 }, + { label: '1,000,000', value: 1_000_000 }, + { label: '10,000,000', value: 10_000_000 }, +] as const satisfies ReadonlyArray> + +const workerDeliveryOptions = [ + { label: '8 ms · 125 msg/s', value: 8 }, + { label: '16 ms · 62.5 msg/s', value: 16 }, + { label: '20 ms · 50 msg/s', value: 20 }, + { label: '33 ms · 30 msg/s', value: 33 }, + { label: '50 ms · 20 msg/s', value: 50 }, + { label: '100 ms · 10 msg/s', value: 100 }, + { label: '250 ms · 4 msg/s', value: 250 }, + { label: '500 ms · 2 msg/s', value: 500 }, + { label: '1,000 ms · 1 msg/s', value: 1_000 }, +] as const satisfies ReadonlyArray> + +const rowRenderingOptions = [ + { label: 'Full DOM · render every row', value: 'none' }, + { label: 'TanStack Virtual · visible rows only', value: 'tanstack' }, +] as const satisfies ReadonlyArray> + +const intradaySamplingOptions = [ + { label: '16 ms · fastest', value: 16 }, + { label: '33 ms · very fast', value: 33 }, + { label: '50 ms · fast', value: 50 }, + { label: '100 ms', value: 100 }, + { label: '250 ms', value: 250 }, + { label: '500 ms', value: 500 }, + { label: '1,000 ms', value: 1_000 }, + { label: '2,000 ms', value: 2_000 }, +] as const satisfies ReadonlyArray> + +export const configuratorOptions = { + instrumentCounts: instrumentCountOptions, + workerDeliveryIntervals: workerDeliveryOptions, + rowRenderingModes: rowRenderingOptions, + intradaySamplingIntervals: intradaySamplingOptions, +} as const diff --git a/examples/vue/realtime-trading/src/shell/trading-shell-context.ts b/examples/vue/realtime-trading/src/shell/trading-shell-context.ts new file mode 100644 index 0000000000..0a08f021bd --- /dev/null +++ b/examples/vue/realtime-trading/src/shell/trading-shell-context.ts @@ -0,0 +1,31 @@ +import { inject, provide } from 'vue' +import type { InjectionKey } from 'vue' +import type { MarketFeedController } from '../feed/market-feed-controller' +import type { TradingBenchmarkController } from '../benchmark/trading-benchmark-controller' + +interface TradingControllers { + benchmark: TradingBenchmarkController + feed: MarketFeedController +} + +const tradingControllersKey: InjectionKey = Symbol( + 'trading-controllers', +) + +export function provideTradingControllers( + benchmark: TradingBenchmarkController, +): void { + provide(tradingControllersKey, { benchmark, feed: benchmark.feed }) +} + +export function useTradingShellController(): TradingBenchmarkController { + const controllers = inject(tradingControllersKey) + if (!controllers) throw new Error('Missing trading controllers') + return controllers.benchmark +} + +export function useMarketFeedController(): MarketFeedController { + const controllers = inject(tradingControllersKey) + if (!controllers) throw new Error('Missing trading controllers') + return controllers.feed +} diff --git a/examples/vue/realtime-trading/src/table/table-config/quote-cells.tsx b/examples/vue/realtime-trading/src/table/table-config/quote-cells.tsx new file mode 100644 index 0000000000..810a7386bb --- /dev/null +++ b/examples/vue/realtime-trading/src/table/table-config/quote-cells.tsx @@ -0,0 +1,198 @@ +import { defineComponent, onMounted, onUnmounted } from 'vue' +import type { PropType } from 'vue' + +export const quoteCellLifecycle = { + created: 0, + destroyed: 0, +} + +export const quoteCellRendererNames = [ + 'Market', + 'Name', + 'Symbol', + 'Last', + 'Change', + 'ChangePercent', + 'Bid', + 'BidVolume', + 'Ask', + 'AskVolume', + 'Open', + 'High', + 'Low', + 'Intraday', +] as const + +export const quoteComponentNames = [ + 'PriceCell', + 'StableMoveCell', + 'UpMoveCell', + 'DownMoveCell', + 'PercentChangeCell', + 'SparklineCell', +] as const + +export type QuoteCellRendererName = (typeof quoteCellRendererNames)[number] +export type QuoteComponentName = (typeof quoteComponentNames)[number] + +const createCounterMap = ( + names: ReadonlyArray, +): Record => + Object.fromEntries(names.map((name) => [name, 0])) as Record + +export const quoteRenderDiagnostics = { + cellRendererCalls: 0, + componentRenderCalls: 0, + cellRendererCallsByName: createCounterMap(quoteCellRendererNames), + componentRenderCallsByName: createCounterMap(quoteComponentNames), +} + +export function recordCellRender(name: QuoteCellRendererName, value: T): T { + quoteRenderDiagnostics.cellRendererCalls++ + quoteRenderDiagnostics.cellRendererCallsByName[name]++ + return value +} + +function useLifecycleCounter(componentName: QuoteComponentName): () => void { + onMounted(() => { + quoteCellLifecycle.created++ + }) + onUnmounted(() => { + quoteCellLifecycle.destroyed++ + }) + return () => { + quoteRenderDiagnostics.componentRenderCalls++ + quoteRenderDiagnostics.componentRenderCallsByName[componentName]++ + } +} + +export const PriceCell = defineComponent({ + name: 'PriceCell', + props: { + price: { type: Number, required: true }, + move: { type: Number, required: true }, + onSelect: { + type: Function as PropType<() => void>, + required: true, + }, + }, + setup(props) { + const recordRender = useLifecycleCounter('PriceCell') + return () => { + recordRender() + return ( + + ) + } + }, +}) + +function createMoveCell( + name: 'StableMoveCell' | 'UpMoveCell' | 'DownMoveCell', + fixedDirection?: 'up' | 'down', +) { + return defineComponent({ + name, + props: { move: { type: Number, required: true } }, + setup(props) { + const recordRender = useLifecycleCounter(name) + return () => { + recordRender() + const direction = fixedDirection ?? (props.move >= 0 ? 'up' : 'down') + const indicator = + fixedDirection === 'up' ? '▲ ' : fixedDirection === 'down' ? '▼ ' : '' + return ( + + {indicator} + {formatSigned(props.move)} + + ) + } + }, + }) +} + +export const StableMoveCell = createMoveCell('StableMoveCell') +export const UpMoveCell = createMoveCell('UpMoveCell', 'up') +export const DownMoveCell = createMoveCell('DownMoveCell', 'down') + +export const PercentChangeCell = defineComponent({ + name: 'PercentChangeCell', + props: { value: { type: Number, required: true } }, + setup(props) { + const recordRender = useLifecycleCounter('PercentChangeCell') + return () => { + recordRender() + return ( + = 0 ? 'quote-up' : 'quote-down', + ]} + > + {props.value >= 0 ? '+' : ''} + {props.value.toFixed(2)}% + + ) + } + }, +}) + +export const SparklineCell = defineComponent({ + name: 'SparklineCell', + props: { + values: { + type: Array as PropType>, + required: true, + }, + }, + setup(props) { + const recordRender = useLifecycleCounter('SparklineCell') + return () => { + recordRender() + const rising = (props.values.at(-1) ?? 0) >= (props.values[0] ?? 0) + const { min, max } = findRange(props.values) + const range = max - min || 1 + const denominator = Math.max(1, props.values.length - 1) + const points = props.values + .map((value, index) => { + const x = (index / denominator) * 100 + const y = 22 - ((value - min) / range) * 20 + return `${x.toFixed(1)},${y.toFixed(1)}` + }) + .join(' ') + return ( + + + + ) + } + }, +}) + +function formatSigned(value: number): string { + return `${value >= 0 ? '+' : ''}${value.toFixed(2)}` +} + +function findRange(values: ReadonlyArray): { + min: number + max: number +} { + const first = values[0] ?? 0 + return values.reduce( + (range, value) => ({ + min: Math.min(range.min, value), + max: Math.max(range.max, value), + }), + { min: first, max: first }, + ) +} diff --git a/examples/vue/realtime-trading/src/table/table-config/trading-columns.tsx b/examples/vue/realtime-trading/src/table/table-config/trading-columns.tsx new file mode 100644 index 0000000000..91c33fbdb5 --- /dev/null +++ b/examples/vue/realtime-trading/src/table/table-config/trading-columns.tsx @@ -0,0 +1,244 @@ +import { defineComponent } from 'vue' +import { createColumnHelper } from '@tanstack/vue-table' +import { useTradingShellController } from '../../shell/trading-shell-context' +import { tradingFeatures } from '../trading-features' +import { + DownMoveCell, + PercentChangeCell, + PriceCell, + SparklineCell, + StableMoveCell, + UpMoveCell, + recordCellRender, +} from './quote-cells' +import type { PropType } from 'vue' +import type { MarketQuote } from '../../feed/market-data' + +export type RendererMode = 'stable' | 'swap' +export interface CoreTableState { + sorting: Array<{ id: string; desc: boolean }> + columnFilters: Array<{ id: string; value: unknown }> +} + +const compactFormatter = new Intl.NumberFormat('en-US', { + notation: 'compact', + maximumFractionDigits: 1, +}) +const columnHelper = createColumnHelper() + +export const tradingColumns = columnHelper.columns([ + columnHelper.group({ + id: 'instrument', + header: 'Instrument', + columns: columnHelper.columns([ + columnHelper.accessor('venue', { + id: 'market', + header: 'Market', + size: 72, + cell: (info) => recordCellRender('Market', info.getValue()), + }), + columnHelper.accessor('company', { + id: 'name', + header: 'Name', + size: 180, + cell: (info) => recordCellRender('Name', info.getValue()), + }), + columnHelper.accessor('symbol', { + header: 'Symbol', + size: 92, + filterFn: 'includesString', + cell: (info) => recordCellRender('Symbol', info.getValue()), + }), + ]), + }), + columnHelper.group({ + id: 'priceAndChange', + header: 'Price & Change', + columns: columnHelper.columns([ + columnHelper.accessor('price', { + header: 'Price', + size: 96, + sortFn: 'basic', + cell: (info) => + recordCellRender('Last', ), + }), + columnHelper.accessor((row) => getDayChange(row), { + id: 'change', + header: 'Chg', + size: 94, + cell: (info) => + recordCellRender( + 'Change', + , + ), + }), + columnHelper.accessor((row) => getDayChangePercent(row), { + id: 'changePercent', + header: 'Chg%', + size: 90, + cell: (info) => + recordCellRender( + 'ChangePercent', + , + ), + }), + ]), + }), + columnHelper.group({ + id: 'orderBook', + header: 'Order Book', + columns: columnHelper.columns([ + columnHelper.accessor('bid', { + header: 'Bid', + size: 90, + cell: (info) => recordCellRender('Bid', info.getValue().toFixed(2)), + }), + columnHelper.accessor('bidSize', { + header: 'Bid Vol', + size: 100, + cell: (info) => + recordCellRender( + 'BidVolume', + compactFormatter.format(info.getValue()), + ), + }), + columnHelper.accessor('ask', { + header: 'Ask', + size: 90, + cell: (info) => recordCellRender('Ask', info.getValue().toFixed(2)), + }), + columnHelper.accessor('askSize', { + header: 'Ask Vol', + size: 100, + cell: (info) => + recordCellRender( + 'AskVolume', + compactFormatter.format(info.getValue()), + ), + }), + ]), + }), + columnHelper.group({ + id: 'session', + header: 'Session', + columns: columnHelper.columns([ + columnHelper.accessor('open', { + header: 'Open', + size: 90, + cell: (info) => recordCellRender('Open', info.getValue().toFixed(2)), + }), + columnHelper.accessor('high', { + header: 'High', + size: 90, + cell: (info) => recordCellRender('High', info.getValue().toFixed(2)), + }), + columnHelper.accessor('low', { + header: 'Low', + size: 90, + cell: (info) => recordCellRender('Low', info.getValue().toFixed(2)), + }), + ]), + }), + columnHelper.group({ + id: 'chart', + header: 'Chart', + columns: columnHelper.columns([ + columnHelper.accessor('history', { + header: 'Intraday', + size: 150, + enableSorting: false, + cell: (info) => + recordCellRender( + 'Intraday', + , + ), + }), + ]), + }), +]) + +export const rowModelDiagnostics = { + hasMeasurement: false, + calls: 0, + totalDurationMs: 0, + maxDurationMs: 0, + lastRowCount: 0, +} + +export const TRADING_COLUMN_COUNT = 14 + +export function readMeasuredRows(readRows: () => Array): Array { + const start = performance.now() + const rows = readRows() + const end = performance.now() + const duration = end - start + rowModelDiagnostics.calls++ + rowModelDiagnostics.hasMeasurement = true + rowModelDiagnostics.totalDurationMs += duration + rowModelDiagnostics.maxDurationMs = Math.max( + rowModelDiagnostics.maxDurationMs, + duration, + ) + rowModelDiagnostics.lastRowCount = rows.length + if (rowModelDiagnostics.calls % 20 === 0) { + try { + performance.measure('tanstack-row-model', { + start, + end, + detail: { rowCount: rows.length }, + }) + if (rowModelDiagnostics.calls % 20_000 === 0) { + performance.clearMeasures('tanstack-row-model') + } + } catch { + // User Timing Level 3 options are not implemented in every browser. + } + } + return rows +} + +const LastPriceCell = defineComponent({ + name: 'LastPriceCell', + props: { + quote: { type: Object as PropType, required: true }, + }, + setup(props) { + const { selectSymbol } = useTradingShellController().actions + return () => ( + selectSymbol(props.quote.symbol)} + /> + ) + }, +}) + +const DayChangeCell = defineComponent({ + name: 'DayChangeCell', + props: { + quote: { type: Object as PropType, required: true }, + }, + setup(props) { + const mode = useTradingShellController().rendererMode + return () => { + const change = getDayChange(props.quote) + if (mode.value === 'stable') return + return change >= 0 ? ( + + ) : ( + + ) + } + }, +}) + +export function getDayChange(quote: MarketQuote): number { + return quote.price - quote.previousClose +} + +export function getDayChangePercent(quote: MarketQuote): number { + return quote.previousClose === 0 + ? 0 + : (getDayChange(quote) / quote.previousClose) * 100 +} diff --git a/examples/vue/realtime-trading/src/table/table-interactions.ts b/examples/vue/realtime-trading/src/table/table-interactions.ts new file mode 100644 index 0000000000..99649a40bd --- /dev/null +++ b/examples/vue/realtime-trading/src/table/table-interactions.ts @@ -0,0 +1,187 @@ +export type CellDirection = 'up' | 'down' | 'left' | 'right' + +interface RowSelectionTable { + resetRowSelection: (defaultState?: boolean) => void +} + +interface SelectableRow { + getIsSelected: () => boolean + getToggleSelectedHandler: (options?: { + selectChildren?: boolean + }) => (event: unknown) => void +} + +interface SelectableGridCell { + row: SelectableGridRow + getSelectionStartHandler: ( + contextDocument?: Document, + ) => (event: unknown) => void + getSelectionExtendHandler: () => (event: unknown) => void +} + +interface SelectableGridRow extends SelectableRow { + original: { symbol: string } + getAllCellsByColumnId: () => Record +} + +interface TradingGridTable extends RowSelectionTable { + getRowModel: () => { + rowsById: Record + } +} + +interface SelectionCellTarget { + element: HTMLTableCellElement + cell: SelectableGridCell +} + +interface CellNavigationTable { + extendCellSelection: (direction: CellDirection) => void + moveCellSelection: (direction: CellDirection) => void + resetCellSelection: (defaultState?: boolean) => void + selectAllCells: () => void +} + +const keyDirections: Partial> = { + ArrowUp: 'up', + ArrowDown: 'down', + ArrowLeft: 'left', + ArrowRight: 'right', +} + +export function reorderColumnIds( + columnIds: Array, + sourceId: string, + targetId: string, +): Array { + if (sourceId === targetId || !columnIds.includes(sourceId)) return columnIds + + const withoutSource = columnIds.filter((id) => id !== sourceId) + const targetIndex = withoutSource.indexOf(targetId) + if (targetIndex < 0) return columnIds + + return [ + ...withoutSource.slice(0, targetIndex), + sourceId, + ...withoutSource.slice(targetIndex), + ] +} + +export function selectRowFromPointer( + table: RowSelectionTable, + row: SelectableRow, + event: MouseEvent, +): void { + const additive = event.ctrlKey || event.metaKey + const checked = additive ? !row.getIsSelected() : true + + if (!event.shiftKey && !additive) table.resetRowSelection(true) + + row.getToggleSelectedHandler({ selectChildren: false })({ + target: { checked }, + shiftKey: event.shiftKey, + ctrlKey: event.ctrlKey, + metaKey: event.metaKey, + }) +} + +export class TradingGridPointerController { + #lastPointerCell: HTMLTableCellElement | null = null + + handleMouseDown( + table: TradingGridTable, + event: MouseEvent, + selectSymbol: (symbol: string) => void, + ): void { + if (event.button !== 0) return + + const target = this.#findCellTarget(table, event.composedPath()) + if (!target) return + + event.preventDefault() + this.#lastPointerCell = target.element + selectSymbol(target.cell.row.original.symbol) + target.cell.getSelectionStartHandler(target.element.ownerDocument)(event) + } + + handlePointerOver(table: TradingGridTable, event: MouseEvent): void { + if ((event.buttons & 1) === 0) { + this.resetPointerCell() + return + } + + const target = this.#findCellTarget(table, event.composedPath()) + if (!target || target.element === this.#lastPointerCell) return + + this.#lastPointerCell = target.element + target.cell.getSelectionExtendHandler()(event) + } + + handleClick(table: TradingGridTable, event: MouseEvent): void { + const target = this.#findCellTarget(table, event.composedPath()) + if (!target) return + selectRowFromPointer(table, target.cell.row, event) + } + + resetPointerCell(): void { + this.#lastPointerCell = null + } + + #findCellTarget( + table: TradingGridTable, + path: Array, + ): SelectionCellTarget | null { + for (const target of path) { + if (!(target instanceof HTMLTableCellElement)) continue + + const columnId = target.dataset['columnId'] + const rowId = + target.closest('tr[data-row-id]')?.dataset['rowId'] + if (!columnId || !rowId) return null + + const row = table.getRowModel().rowsById[rowId] + const cell = row.getAllCellsByColumnId()[columnId] + return { element: target, cell } + } + + return null + } +} + +export function handleCellNavigation( + table: CellNavigationTable, + event: KeyboardEvent, +): void { + if (event.key === 'Escape') { + event.preventDefault() + table.resetCellSelection(true) + return + } + + if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'a') { + event.preventDefault() + table.selectAllCells() + return + } + + const direction = keyDirections[event.key] + if (!direction) return + + event.preventDefault() + if (event.shiftKey) table.extendCellSelection(direction) + else table.moveCellSelection(direction) +} + +export function sortIndicator(direction: false | 'asc' | 'desc'): string { + if (direction === 'asc') return '↑' + if (direction === 'desc') return '↓' + return '↕' +} + +export function sortAriaValue( + direction: false | 'asc' | 'desc', +): 'ascending' | 'descending' | 'none' { + if (direction === 'asc') return 'ascending' + if (direction === 'desc') return 'descending' + return 'none' +} diff --git a/examples/vue/realtime-trading/src/table/trading-features.ts b/examples/vue/realtime-trading/src/table/trading-features.ts new file mode 100644 index 0000000000..3f76c6a391 --- /dev/null +++ b/examples/vue/realtime-trading/src/table/trading-features.ts @@ -0,0 +1,16 @@ +import { + createFilteredRowModel, + createSortedRowModel, + filterFn_includesString, + sortFn_basic, + stockFeatures, + tableFeatures, +} from '@tanstack/vue-table' + +export const tradingFeatures = tableFeatures({ + ...stockFeatures, + filteredRowModel: createFilteredRowModel(), + sortedRowModel: createSortedRowModel(), + filterFns: { includesString: filterFn_includesString }, + sortFns: { basic: sortFn_basic }, +}) diff --git a/examples/vue/realtime-trading/src/table/trading-row-virtualizer.ts b/examples/vue/realtime-trading/src/table/trading-row-virtualizer.ts new file mode 100644 index 0000000000..bc4b34b528 --- /dev/null +++ b/examples/vue/realtime-trading/src/table/trading-row-virtualizer.ts @@ -0,0 +1,18 @@ +export const TRADING_ROW_HEIGHT = 32 +export const TRADING_ROW_OVERSCAN = 10 +export const DEFAULT_VIRTUALIZATION_ROW_COUNT = 200 +export const FORCED_VIRTUALIZATION_ROW_COUNT = 1_500 + +export type VirtualScrollMode = 'tanstack' | 'none' +export type VirtualScrollPreference = VirtualScrollMode | 'auto' + +export function resolveVirtualScrollMode( + requestedMode: VirtualScrollPreference, + instrumentCount: number, +): VirtualScrollMode { + if (instrumentCount >= FORCED_VIRTUALIZATION_ROW_COUNT) return 'tanstack' + if (requestedMode !== 'auto') return requestedMode + return instrumentCount >= DEFAULT_VIRTUALIZATION_ROW_COUNT + ? 'tanstack' + : 'none' +} diff --git a/examples/vue/realtime-trading/src/table/trading-table.tsx b/examples/vue/realtime-trading/src/table/trading-table.tsx new file mode 100644 index 0000000000..188157cab4 --- /dev/null +++ b/examples/vue/realtime-trading/src/table/trading-table.tsx @@ -0,0 +1,489 @@ +import { + computed, + defineComponent, + nextTick, + onBeforeUnmount, + onMounted, + onUpdated, + ref, + watch, + watchEffect, +} from 'vue' +import { FlexRender, useTable } from '@tanstack/vue-table' +import { useVirtualizer } from '@tanstack/vue-virtual' +import { useTableBenchmark } from '../benchmark/use-table-benchmark' +import { + useMarketFeedController, + useTradingShellController, +} from '../shell/trading-shell-context' +import { tradingFeatures } from './trading-features' +import { + TRADING_COLUMN_COUNT, + readMeasuredRows, + rowModelDiagnostics, + tradingColumns, +} from './table-config/trading-columns' +import { + TradingGridPointerController, + handleCellNavigation, + reorderColumnIds, + sortAriaValue, + sortIndicator, +} from './table-interactions' +import { + TRADING_ROW_HEIGHT, + TRADING_ROW_OVERSCAN, + resolveVirtualScrollMode, +} from './trading-row-virtualizer' +import type { PropType } from 'vue' +import type { VirtualItem } from '@tanstack/vue-virtual' +import type { MarketQuote } from '../feed/market-data' + +export { TRADING_COLUMN_COUNT, rowModelDiagnostics } +export type { + CoreTableState, + RendererMode, +} from './table-config/trading-columns' +export type { VirtualScrollMode } from './trading-row-virtualizer' + +type TradingTableInstance = ReturnType< + typeof useTable +> +type TradingRow = ReturnType< + TradingTableInstance['getRowModel'] +>['rows'][number] + +interface ColumnDragRuntime { + columnId: string | null + sourceElement: HTMLTableCellElement | null + targetElement: HTMLTableCellElement | null +} + +const TradingRowView = defineComponent({ + name: 'TradingRowView', + props: { + row: { type: Object as PropType, required: true }, + virtualRow: Object as PropType, + }, + setup(props, { slots }) { + const selectedSymbol = useTradingShellController().selectedSymbol + return () => ( + + {slots.default?.()} + + ) + }, +}) + +export const TradingTable = defineComponent({ + name: 'TradingTable', + setup() { + const controller = useTradingShellController() + const feed = useMarketFeedController() + const virtualScrollMode = computed(() => + resolveVirtualScrollMode( + controller.requestedVirtualScrollMode.value, + feed.instrumentCount.value, + ), + ) + const table = useTable({ + key: 'vue-realtime-trading', + features: tradingFeatures, + columns: tradingColumns, + data: feed.quotes, + getRowId: (row: MarketQuote) => row.id, + columnResizeMode: 'onChange', + defaultColumn: { minSize: 56, maxSize: 800 }, + autoResetCellSelection: false, + }) + const rows = computed(() => { + void feed.quotes.value + void table.atoms.sorting.get() + void table.atoms.columnFilters.get() + void table.atoms.columnOrder.get() + return readMeasuredRows(() => table.getRowModel().rows) + }) + const scrollElement = ref(null) + const tableElement = ref(null) + const virtualizer = useVirtualizer( + computed(() => ({ + count: rows.value.length, + estimateSize: () => TRADING_ROW_HEIGHT, + getScrollElement: () => scrollElement.value, + getItemKey: (index: number) => rows.value[index]?.id ?? index, + overscan: TRADING_ROW_OVERSCAN, + enabled: virtualScrollMode.value === 'tanstack', + })), + ) + const virtualRows = computed(() => virtualizer.value.getVirtualItems()) + const visibleRange = computed(() => { + const range = virtualizer.value.range + if ( + virtualScrollMode.value !== 'tanstack' || + rows.value.length === 0 || + range === null + ) { + return null + } + const lastIndex = rows.value.length - 1 + const start = Math.min(range.startIndex, lastIndex) + return { + start, + end: Math.min(Math.max(start, range.endIndex), lastIndex), + } + }) + const pointerInteractions = new TradingGridPointerController() + const dragRuntime: ColumnDragRuntime = { + columnId: null, + sourceElement: null, + targetElement: null, + } + const layoutRuntime = { manuallyResized: false } + + useTableBenchmark(controller) + onUpdated(() => feed.completeRender()) + onMounted(() => feed.completeRender()) + + const writeColumnSizes = (): void => { + const element = tableElement.value + if (!element) return + for (const header of table.getFlatHeaders()) { + element.style.setProperty( + `--header-${header.id}-size`, + String(header.getSize()), + ) + element.style.setProperty( + `--col-${header.column.id}-size`, + String(header.column.getSize()), + ) + } + element.style.width = `${table.getTotalSize()}px` + } + const fitAvailableWidth = (): void => { + const container = scrollElement.value + if (!container || layoutRuntime.manuallyResized) return + const currentWidth = table.getTotalSize() + if (container.clientWidth <= currentWidth + 1 || currentWidth <= 0) return + const ratio = container.clientWidth / currentWidth + table.setColumnSizing( + Object.fromEntries( + table + .getVisibleLeafColumns() + .map((column) => [column.id, column.getSize() * ratio]), + ), + ) + } + const resizeObserver = new ResizeObserver(fitAvailableWidth) + const stopLayoutWatch = watch( + [ + () => table.atoms.columnSizing.get(), + () => table.atoms.columnOrder.get(), + ], + writeColumnSizes, + { flush: 'post' }, + ) + const stopResizingWatch = watch( + () => table.atoms.columnResizing.get().isResizingColumn, + (resizingColumn) => { + if (resizingColumn !== false) layoutRuntime.manuallyResized = true + }, + { flush: 'sync' }, + ) + onMounted(() => { + nextTick(() => { + writeColumnSizes() + fitAvailableWidth() + if (scrollElement.value) resizeObserver.observe(scrollElement.value) + }) + }) + onBeforeUnmount(() => { + stopLayoutWatch() + stopResizingWatch() + resizeObserver.disconnect() + }) + watchEffect(() => { + controller.actions.setRenderedRowCount( + virtualScrollMode.value === 'tanstack' + ? virtualRows.value.length + : rows.value.length, + ) + }) + + const clearColumnDrag = (): void => { + dragRuntime.sourceElement?.classList.remove('is-column-dragging') + dragRuntime.targetElement?.classList.remove('is-column-drop-target') + dragRuntime.columnId = null + dragRuntime.sourceElement = null + dragRuntime.targetElement = null + } + const showColumnDropTarget = ( + columnId: string, + element: HTMLTableCellElement | null, + ): void => { + dragRuntime.targetElement?.classList.remove('is-column-drop-target') + dragRuntime.targetElement = null + if (dragRuntime.columnId === columnId || !element) return + element.classList.add('is-column-drop-target') + dragRuntime.targetElement = element + } + + const renderRow = (row: TradingRow, virtualRow?: VirtualItem) => ( + + {{ + default: () => + row.getVisibleCells().map((cell) => { + const edges = cell.getSelectionEdges() + return ( + + + + ) + }), + }} + + ) + + return () => { + const currentRows = rows.value + const activeVirtualRows = virtualRows.value + return ( + <> +
handleCellNavigation(table, event)} + > + + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + const isLeaf = header.subHeaders.length === 0 + const sorted = header.column.getIsSorted() + return ( + + ) + })} + + ))} + + + pointerInteractions.handleMouseDown( + table, + event, + controller.actions.selectSymbol, + ) + } + onPointerover={(event) => + pointerInteractions.handlePointerOver(table, event) + } + onMouseleave={() => pointerInteractions.resetPointerCell()} + onClick={(event) => + pointerInteractions.handleClick(table, event) + } + > + {virtualScrollMode.value === 'tanstack' + ? activeVirtualRows.map((virtualRow) => + renderRow(currentRows[virtualRow.index], virtualRow), + ) + : currentRows.map((row) => renderRow(row))} + +
+ {!header.isPlaceholder && + (isLeaf ? ( + <> +
{ + event.preventDefault() + showColumnDropTarget( + header.column.id, + ( + event.currentTarget as HTMLElement + ).closest('th'), + ) + }} + onDrop={(event) => { + event.preventDefault() + const sourceId = + event.dataTransfer?.getData( + 'text/plain', + ) || dragRuntime.columnId + if (sourceId) { + table.setColumnOrder( + reorderColumnIds( + table + .getVisibleLeafColumns() + .map((column) => column.id), + sourceId, + header.column.id, + ), + ) + } + clearColumnDrag() + }} + > + + +
+ {header.column.getCanResize() && ( +
+
+ {virtualScrollMode.value === 'tanstack' && ( +
+ + TanStack · Total · {currentRows.length} rows ·{' '} + {table.getVisibleLeafColumns().length} columns + + + {visibleRange.value + ? `Current · rows ${visibleRange.value.start}..${visibleRange.value.end}` + : 'Current · rows —'} + +
+ )} + + ) + } + }, +}) + +function isTextColumn(columnId: string): boolean { + return columnId === 'market' || columnId === 'name' || columnId === 'symbol' +} diff --git a/examples/vue/realtime-trading/src/vite-env.d.ts b/examples/vue/realtime-trading/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/vue/realtime-trading/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/vue/realtime-trading/tests/e2e/smoke.spec.ts b/examples/vue/realtime-trading/tests/e2e/smoke.spec.ts new file mode 100644 index 0000000000..e285cc75f0 --- /dev/null +++ b/examples/vue/realtime-trading/tests/e2e/smoke.spec.ts @@ -0,0 +1,183 @@ +import path from 'node:path' +import { expect, test } from '@playwright/test' +import { startExampleServer } from '../../../../../tests/e2e/helpers/startExampleServer' +import { + setRangeValue, + scrollTradingTable, +} from '../../../../../tests/e2e/helpers/setRangeValue' +import type { Page } from '@playwright/test' + +const exampleDir = path.resolve() + +function collectPageErrors(page: Page) { + const errors: Array = [] + page.on('pageerror', (error) => errors.push(error.message)) + page.on('console', (message) => { + if (message.type() === 'error') errors.push(message.text()) + }) + return errors +} + +test('runs the Vue realtime trading workload', async ({ page }) => { + const server = await startExampleServer(exampleDir) + const errors = collectPageErrors(page) + + try { + await page.goto(server.url) + + const table = page.getByTestId('trading-table') + const instrumentCount = page.getByTestId('instrument-count-select') + const virtualScrollSelect = page.getByTestId('virtual-scroll-select') + await expect(table).toBeVisible() + await expect(instrumentCount).toHaveValue('100') + await expect(page.locator('.brand')).toHaveText('MARKET MONITOR') + await expect(virtualScrollSelect).toHaveValue('none') + await expect(virtualScrollSelect).toBeEnabled() + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(table.locator('tbody')).toHaveCSS('user-select', 'none') + await expect(table.locator('tbody tr').first()).toHaveCSS( + 'content-visibility', + 'auto', + ) + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await instrumentCount.selectOption('250') + await expect(virtualScrollSelect).toHaveValue('tanstack') + await expect(virtualScrollSelect).toBeEnabled() + await expect.poll(() => table.locator('tbody tr').count()).toBeLessThan(250) + await expect(page.getByTestId('virtual-scroll-footer')).toBeVisible() + await instrumentCount.selectOption('100') + await expect(virtualScrollSelect).toHaveValue('none') + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await virtualScrollSelect.selectOption('tanstack') + await expect.poll(() => table.locator('tbody tr').count()).toBeLessThan(100) + await expect(table.locator('tbody tr').first()).toHaveCSS( + 'content-visibility', + 'auto', + ) + await expect(page.getByTestId('virtual-scroll-footer')).toBeVisible() + await virtualScrollSelect.selectOption('none') + await expect(table.locator('tbody tr')).toHaveCount(100) + await instrumentCount.selectOption('1500') + await expect(virtualScrollSelect).toHaveValue('tanstack') + await expect(virtualScrollSelect).toBeDisabled() + await expect + .poll(() => table.locator('tbody tr').count()) + .toBeLessThan(1500) + await expect(page.getByTestId('virtual-scroll-footer')).toContainText( + 'Total · 1500 rows · 14 columns', + ) + await expect(page.getByTestId('visible-row-range')).toHaveText( + /^\s*Current · rows 0\.\.\d+\s*$/, + ) + await scrollTradingTable(page, 2_000) + await expect + .poll(async () => + Number( + await table + .locator('tbody tr') + .first() + .getAttribute('data-virtual-index'), + ), + ) + .toBeGreaterThan(0) + await expect(page.getByTestId('visible-row-range')).toHaveText( + /^\s*Current · rows [1-9]\d*\.\.\d+\s*$/, + ) + await instrumentCount.selectOption('100') + await expect(page.getByTestId('virtual-scroll-footer')).toHaveCount(0) + await expect(virtualScrollSelect).toHaveValue('none') + await expect(virtualScrollSelect).toBeEnabled() + await expect(table.locator('tbody tr')).toHaveCount(100) + await expect(table.locator('thead tr')).toHaveCount(2) + await expect(table.locator('thead tr').last().locator('th')).toHaveCount(14) + await expect(table.locator('thead')).not.toContainText('Identity') + await expect(table.locator('thead')).not.toContainText('Market Data') + await expect(table.locator('thead')).toContainText('Market') + await expect(table.locator('thead')).toContainText('Bid Vol') + await expect(table.locator('thead')).toContainText('Intraday') + const selectedRow = table.locator('tbody tr').first() + const selectedSymbol = await selectedRow.getAttribute('data-symbol') + await selectedRow.locator('td').nth(1).click() + await expect(page.getByTestId('selected-instrument')).toContainText( + selectedSymbol ?? '', + ) + await expect(page.getByTestId('feed-status')).toHaveText('FEED LIVE') + await expect(instrumentCount.locator('option[value="150"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="350"]')).toHaveCount(1) + await expect(instrumentCount.locator('option[value="750"]')).toHaveCount(1) + + const targetRateSlider = page.getByTestId('target-rate-slider') + await expect(targetRateSlider).toHaveAttribute('min', '0') + await expect(targetRateSlider).toHaveAttribute('max', '9') + await expect(targetRateSlider).toHaveAttribute('step', '1') + await expect(targetRateSlider).toHaveValue('6') + await setRangeValue(targetRateSlider, '7') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '25K samples/s', + ) + await setRangeValue(targetRateSlider, '8') + await expect(page.getByTestId('target-sample-rate')).toContainText( + '50K samples/s', + ) + await setRangeValue(targetRateSlider, '6') + + const sparklineInterval = page.getByTestId( + 'sparkline-sample-interval-select', + ) + await expect(sparklineInterval).toHaveValue('16') + await sparklineInterval.selectOption('100') + await expect(sparklineInterval).toHaveValue('100') + await sparklineInterval.selectOption('16') + + const publishInterval = page.getByTestId('publish-interval-select') + await expect(publishInterval.locator('option[value="500"]')).toHaveCount(1) + await expect(publishInterval.locator('option[value="1000"]')).toHaveCount(1) + + await expect + .poll(async () => { + const text = await page.getByTestId('row-update-rate').textContent() + return Number(text?.replace(/\D/g, '') ?? 0) + }) + .toBeGreaterThan(0) + await expect + .poll(async () => { + const text = await page.getByTestId('worker-messages').textContent() + return Number(text?.replace(/\D/g, '') ?? 0) + }) + .toBeGreaterThan(0) + await expect + .poll(async () => + Number(await page.getByTestId('message-rate').textContent()), + ) + .toBeGreaterThan(0) + await expect + .poll(async () => + Number(await page.getByTestId('table-render-rate').textContent()), + ) + .toBeGreaterThan(0) + + const firstPrice = page.locator('tbody tr').first().getByRole('button') + const priceBeforeUpdate = await firstPrice.textContent() + await expect + .poll(() => firstPrice.textContent()) + .not.toBe(priceBeforeUpdate) + + await page.locator('.config-section input[type="checkbox"]').first().check() + await page.getByTestId('feed-toggle').click() + await expect(page.getByTestId('feed-toggle')).toHaveText('START FEED') + await expect(page.getByTestId('feed-status')).toHaveText('FEED PAUSED') + + await instrumentCount.selectOption('750') + await expect.poll(() => table.locator('tbody tr').count()).toBeLessThan(750) + expect( + await page.evaluate( + () => performance.getEntriesByName('tanstack-row-model').length > 0, + ), + ).toBe(true) + + expect(errors).toEqual([]) + } finally { + await server.close() + } +}) diff --git a/examples/vue/realtime-trading/tsconfig.json b/examples/vue/realtime-trading/tsconfig.json new file mode 100644 index 0000000000..709980136e --- /dev/null +++ b/examples/vue/realtime-trading/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "vue", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vite/client"] + }, + "include": ["src", "tests/e2e", "vite.config.ts"] +} diff --git a/examples/vue/realtime-trading/vite.config.ts b/examples/vue/realtime-trading/vite.config.ts new file mode 100644 index 0000000000..004befbdd3 --- /dev/null +++ b/examples/vue/realtime-trading/vite.config.ts @@ -0,0 +1,11 @@ +import vue from '@vitejs/plugin-vue' +import vueJsx from '@vitejs/plugin-vue-jsx' +import { defineConfig } from 'vite' + +export default defineConfig({ + server: { + port: 7777, + allowedHosts: true, + }, + plugins: [vue(), vueJsx()], +}) diff --git a/examples/vue/row-pinning/package.json b/examples/vue/row-pinning/package.json index 80217663d0..3e577fd096 100644 --- a/examples/vue/row-pinning/package.json +++ b/examples/vue/row-pinning/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/row-selection/package.json b/examples/vue/row-selection/package.json index e029dc38cf..d19778f8e1 100644 --- a/examples/vue/row-selection/package.json +++ b/examples/vue/row-selection/package.json @@ -10,18 +10,19 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/vue-devtools": "^0.2.24", + "@faker-js/faker": "^10.6.0", + "@tanstack/vue-devtools": "^0.2.26", "@tanstack/vue-table": "^9.2.3", "@tanstack/vue-table-devtools": "^9.2.0", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/sorting/package.json b/examples/vue/sorting/package.json index 3944ac7b67..4df4cec6cd 100644 --- a/examples/vue/sorting/package.json +++ b/examples/vue/sorting/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/sub-components/package.json b/examples/vue/sub-components/package.json index 410df79a79..cd498e7d9c 100644 --- a/examples/vue/sub-components/package.json +++ b/examples/vue/sub-components/package.json @@ -10,16 +10,17 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/virtualized-columns/package.json b/examples/vue/virtualized-columns/package.json index 43d5877744..fe2cb1b17a 100644 --- a/examples/vue/virtualized-columns/package.json +++ b/examples/vue/virtualized-columns/package.json @@ -10,17 +10,18 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", - "@tanstack/vue-virtual": "^3.13.35", + "@tanstack/vue-virtual": "^3.13.36", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/virtualized-infinite-scrolling/package.json b/examples/vue/virtualized-infinite-scrolling/package.json index 0a123473fb..9e60bc581a 100644 --- a/examples/vue/virtualized-infinite-scrolling/package.json +++ b/examples/vue/virtualized-infinite-scrolling/package.json @@ -10,20 +10,21 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/match-sorter-utils": "^9.1.2", "@tanstack/vue-query": "^5.101.4", "@tanstack/vue-store": "^0.11.1", "@tanstack/vue-table": "^9.2.3", - "@tanstack/vue-virtual": "^3.13.35", + "@tanstack/vue-virtual": "^3.13.36", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/virtualized-rows/package.json b/examples/vue/virtualized-rows/package.json index 8562417b0c..72cb3b7803 100644 --- a/examples/vue/virtualized-rows/package.json +++ b/examples/vue/virtualized-rows/package.json @@ -10,17 +10,18 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/vue-table": "^9.2.3", - "@tanstack/vue-virtual": "^3.13.35", + "@tanstack/vue-virtual": "^3.13.36", "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/with-tanstack-form/package.json b/examples/vue/with-tanstack-form/package.json index fd9ba6c5c1..e856176317 100644 --- a/examples/vue/with-tanstack-form/package.json +++ b/examples/vue/with-tanstack-form/package.json @@ -10,8 +10,8 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", - "@tanstack/vue-devtools": "^0.2.24", + "@faker-js/faker": "^10.6.0", + "@tanstack/vue-devtools": "^0.2.26", "@tanstack/vue-form": "^1.33.5", "@tanstack/vue-table": "^9.2.3", "@tanstack/vue-table-devtools": "^9.2.0", @@ -19,11 +19,12 @@ "zod": "^4.4.3" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/examples/vue/with-tanstack-query/package.json b/examples/vue/with-tanstack-query/package.json index d6aa06011c..a508309ebe 100644 --- a/examples/vue/with-tanstack-query/package.json +++ b/examples/vue/with-tanstack-query/package.json @@ -10,9 +10,9 @@ "test:e2e": "PLAYWRIGHT_TEST_DIR=$PWD/tests/e2e playwright test --config ../../../playwright.config.ts" }, "dependencies": { - "@faker-js/faker": "^10.5.0", + "@faker-js/faker": "^10.6.0", "@tanstack/match-sorter-utils": "^9.1.2", - "@tanstack/vue-devtools": "^0.2.24", + "@tanstack/vue-devtools": "^0.2.26", "@tanstack/vue-query": "^5.101.4", "@tanstack/vue-query-devtools": "^6.1.38", "@tanstack/vue-table": "^9.2.3", @@ -20,11 +20,12 @@ "vue": "^3.5.41" }, "devDependencies": { + "@rolldown/binding-wasm32-wasi": "~1.2.4", "@types/node": "^26.2.0", "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.6", "typescript": "6.0.3", - "vite": "^8.2.1", - "vue-tsc": "^3.3.9" + "vite": "^8.2.2", + "vue-tsc": "^3.3.11" } } diff --git a/package.json b/package.json index 27cfd853a3..fc6a1dd77d 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "type": "git", "url": "git+https://github.com/TanStack/table.git" }, - "packageManager": "pnpm@11.21.0", + "packageManager": "pnpm@11.24.0", "engines": { "node": ">=20", "pnpm": ">=11.9.0" @@ -66,33 +66,33 @@ ], "devDependencies": { "@changesets/changelog-github": "^1.0.0", - "@changesets/cli": "^3.0.0", - "@faker-js/faker": "^10.5.0", + "@changesets/cli": "^3.0.1", + "@faker-js/faker": "^10.6.0", "@playwright/test": "^1.62.1", "@size-limit/preset-small-lib": "^13.0.3", "@tanstack/eslint-config": "0.4.0", - "@tanstack/intent": "^0.3.6", + "@tanstack/intent": "^0.3.7", "@tanstack/typedoc-config": "0.3.4", "@testing-library/jest-dom": "^7.0.1", "@types/node": "^26.2.0", - "@typescript-eslint/parser": "8.67.0", - "@vitest/coverage-v8": "4.1.10", - "eslint": "^10.8.1", + "@typescript-eslint/parser": "8.68.0", + "@vitest/coverage-v8": "4.1.11", + "eslint": "^10.9.1", "jsdom": "^30.0.1", - "knip": "^6.32.2", + "knip": "^6.32.3", "markdown-link-extractor": "^4.0.4", "nx": "^23.1.1", "prettier": "^3.9.6", - "prettier-plugin-ember-template-tag": "^2.1.7", + "prettier-plugin-ember-template-tag": "^2.1.8", "prettier-plugin-svelte": "^4.1.1", - "publint": "^0.3.23", + "publint": "^0.3.24", "rimraf": "^6.1.3", "sherif": "^1.13.0", "size-limit": "^13.0.3", "tinyglobby": "^0.2.17", "tsdown": "^0.22.14", "typescript": "6.0.3", - "vite": "^8.2.1", - "vitest": "^4.1.10" + "vite": "^8.2.2", + "vitest": "^4.1.11" } } diff --git a/packages/alpine-table/package.json b/packages/alpine-table/package.json index ce0059a983..cb85786cda 100644 --- a/packages/alpine-table/package.json +++ b/packages/alpine-table/package.json @@ -54,7 +54,7 @@ "devDependencies": { "@testing-library/dom": "^10.4.1", "@types/alpinejs": "^3.13.11", - "alpinejs": "^3.16.1" + "alpinejs": "^3.16.3" }, "peerDependencies": { "alpinejs": "^3.15.12" diff --git a/packages/angular-table-devtools/package.json b/packages/angular-table-devtools/package.json index 908ecd7988..c39d2a4555 100644 --- a/packages/angular-table-devtools/package.json +++ b/packages/angular-table-devtools/package.json @@ -45,7 +45,7 @@ "skills" ], "dependencies": { - "@tanstack/devtools-utils": "^0.6.0", + "@tanstack/devtools-utils": "^0.7.0", "@tanstack/table-core": "workspace:*", "@tanstack/table-devtools": "workspace:*" }, diff --git a/packages/angular-table/package.json b/packages/angular-table/package.json index b3595c9921..731d52239b 100644 --- a/packages/angular-table/package.json +++ b/packages/angular-table/package.json @@ -70,8 +70,8 @@ "tslib": "^2.8.1" }, "devDependencies": { - "@analogjs/vite-plugin-angular": "^2.7.0", - "@analogjs/vitest-angular": "^2.7.0", + "@analogjs/vite-plugin-angular": "^2.7.1", + "@analogjs/vitest-angular": "^2.7.1", "@angular/compiler": "^22.1.1", "@angular/core": "^22.1.1", "@angular/platform-browser": "^22.1.1", diff --git a/packages/angular-table/src/helpers/flexRenderCell.ts b/packages/angular-table/src/helpers/flexRenderCell.ts index 20f3a432f3..b96f02952d 100644 --- a/packages/angular-table/src/helpers/flexRenderCell.ts +++ b/packages/angular-table/src/helpers/flexRenderCell.ts @@ -130,12 +130,9 @@ export class FlexRenderCell< readonly #viewContainerRef = inject(ViewContainerRef) constructor() { - const content = computed(() => this.#renderData()[0]) - const props = computed(() => this.#renderData()[1]) - const renderer = new FlexViewRenderer({ - content: content, - props: props, + content: () => this.#renderData()[0], + props: () => this.#renderData()[1], injector: () => this.#injector, templateRef: this.#templateRef, viewContainerRef: this.#viewContainerRef, diff --git a/packages/ember-table/package.json b/packages/ember-table/package.json index a8e2b7c542..7f335dd40c 100644 --- a/packages/ember-table/package.json +++ b/packages/ember-table/package.json @@ -80,12 +80,12 @@ "@embroider/addon-dev": "^8.3.1", "@embroider/core": "4.6.3", "@embroider/macros": "1.20.6", - "@embroider/vite": "^1.7.9", + "@embroider/vite": "^1.7.10", "@eslint/js": "^10.0.1", "@glimmer/component": "2.1.1", - "@glint/ember-tsc": "1.10.0", + "@glint/ember-tsc": "1.11.0", "@glint/template": "1.8.0", - "@glint/tsserver-plugin": "2.7.0", + "@glint/tsserver-plugin": "2.7.3", "@rollup/plugin-babel": "7.1.0", "@types/qunit": "^2.19.14", "babel-plugin-ember-template-compilation": "4.0.0", @@ -98,9 +98,9 @@ "globals": "^17.11.0", "qunit": "^2.26.0", "qunit-dom": "^3.6.0", - "rollup": "^4.62.4", + "rollup": "^4.63.0", "testem": "^3.20.1", - "typescript-eslint": "^8.67.0" + "typescript-eslint": "^8.68.0" }, "ember": { "edition": "octane" diff --git a/packages/preact-table-devtools/package.json b/packages/preact-table-devtools/package.json index 7e0bcf8ae5..8804f24e3e 100644 --- a/packages/preact-table-devtools/package.json +++ b/packages/preact-table-devtools/package.json @@ -48,7 +48,7 @@ "skills" ], "dependencies": { - "@tanstack/devtools-utils": "^0.6.0", + "@tanstack/devtools-utils": "^0.7.0", "@tanstack/table-devtools": "workspace:*" }, "devDependencies": { diff --git a/packages/react-table-devtools/package.json b/packages/react-table-devtools/package.json index 73cce72b37..7733e5be78 100644 --- a/packages/react-table-devtools/package.json +++ b/packages/react-table-devtools/package.json @@ -48,14 +48,14 @@ "skills" ], "dependencies": { - "@tanstack/devtools-utils": "^0.6.0", + "@tanstack/devtools-utils": "^0.7.0", "@tanstack/table-devtools": "workspace:*" }, "devDependencies": { - "@eslint-react/eslint-plugin": "^5.18.1", + "@eslint-react/eslint-plugin": "^5.18.6", "@tanstack/table-core": "workspace:*", "@types/react": "^19.2.18", - "@vitejs/plugin-react": "^6.0.5", + "@vitejs/plugin-react": "^6.1.0", "eslint-plugin-react-compiler": "19.1.0-rc.2", "eslint-plugin-react-hooks": "^7.1.1", "react": "^19.2.8" diff --git a/packages/react-table/package.json b/packages/react-table/package.json index 4860d1a50e..7102638cb2 100644 --- a/packages/react-table/package.json +++ b/packages/react-table/package.json @@ -53,11 +53,11 @@ "@tanstack/table-core": "workspace:*" }, "devDependencies": { - "@eslint-react/eslint-plugin": "^5.18.1", + "@eslint-react/eslint-plugin": "^5.18.6", "@testing-library/react": "^16.3.2", "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", + "@types/react-dom": "^19.2.5", + "@vitejs/plugin-react": "^6.1.0", "eslint-plugin-react-compiler": "19.1.0-rc.2", "eslint-plugin-react-hooks": "^7.1.1", "react": "^19.2.8", diff --git a/packages/solid-table-devtools/package.json b/packages/solid-table-devtools/package.json index 5865baaca9..12a59a27a7 100644 --- a/packages/solid-table-devtools/package.json +++ b/packages/solid-table-devtools/package.json @@ -48,12 +48,12 @@ "skills" ], "dependencies": { - "@tanstack/devtools-utils": "^0.6.0", + "@tanstack/devtools-utils": "^0.7.0", "@tanstack/table-devtools": "workspace:*" }, "devDependencies": { "@tanstack/table-core": "workspace:*", - "solid-js": "^1.9.14", + "solid-js": "^1.9.15", "vite-plugin-solid": "^2.11.14" }, "peerDependencies": { diff --git a/packages/solid-table/package.json b/packages/solid-table/package.json index b1831a67a8..720a31f931 100644 --- a/packages/solid-table/package.json +++ b/packages/solid-table/package.json @@ -66,7 +66,7 @@ }, "devDependencies": { "@solidjs/testing-library": "^0.8.10", - "solid-js": "^1.9.14", + "solid-js": "^1.9.15", "vite-plugin-solid": "^2.11.14" }, "peerDependencies": { diff --git a/packages/svelte-table/package.json b/packages/svelte-table/package.json index 5eaf16b705..29ce927117 100644 --- a/packages/svelte-table/package.json +++ b/packages/svelte-table/package.json @@ -72,9 +72,9 @@ "@sveltejs/package": "^2.5.8", "@sveltejs/vite-plugin-svelte": "^7.3.0", "@testing-library/svelte": "^5.4.2", - "eslint-plugin-svelte": "^3.22.0", - "svelte": "^5.56.8", - "svelte-check": "^4.7.4" + "eslint-plugin-svelte": "^3.23.0", + "svelte": "^5.56.10", + "svelte-check": "^4.7.6" }, "peerDependencies": { "svelte": "^5.0.0" diff --git a/packages/table-core/src/worker/rebuildRowModel.ts b/packages/table-core/src/worker/rebuildRowModel.ts index 8122ef9d00..0c286893c1 100644 --- a/packages/table-core/src/worker/rebuildRowModel.ts +++ b/packages/table-core/src/worker/rebuildRowModel.ts @@ -83,15 +83,16 @@ export function rebuildRowModel< if (payload.kind === 'flat') { const { indices } = payload - const rows = new Array(indices.length) + const rows: Array = [] for (let i = 0; i < indices.length; i++) { - const row: any = core.flatRows[indices[i]!]! + const row: any = core.flatRows[indices[i]!] + if (!row) continue if (resetDepths) { row.depth = 0 row.parentId = undefined } applyFilterData(row, payload.filterData?.[i]) - rows[i] = row + rows.push(row) } return { rows, flatRows: rows, rowsById: core.rowsById } } @@ -110,7 +111,8 @@ export function rebuildRowModel< for (let i = 0; i < nodes.length; i++) { const node = nodes[i]! if (typeof node === 'number') { - const row: any = core.flatRows[node]! + const row: any = core.flatRows[node] + if (!row) continue row.depth = depth row.parentId = parentId flatRows.push(row) @@ -119,7 +121,8 @@ export function rebuildRowModel< } if (!('groupingColumnId' in node)) { - const coreRow: any = core.flatRows[node.index]! + const coreRow: any = core.flatRows[node.index] + if (!coreRow) continue const flatIndex = flattenParentsFirst ? flatRows.length : -1 if (flattenParentsFirst) { flatRows.push(undefined) @@ -203,7 +206,7 @@ export function rebuildRowModel< rowsById[node.id] = row rows[i] = row } - return rows + return rows.filter((row) => row != null) } const rows = rebuildRows(payload.children, 0, undefined) diff --git a/packages/table-devtools/package.json b/packages/table-devtools/package.json index c6c2a4952f..3701d37a01 100644 --- a/packages/table-devtools/package.json +++ b/packages/table-devtools/package.json @@ -47,11 +47,11 @@ "skills" ], "dependencies": { - "@tanstack/devtools-ui": "^0.7.0", - "@tanstack/devtools-utils": "^0.6.0", + "@tanstack/devtools-ui": "^0.7.1", + "@tanstack/devtools-utils": "^0.7.0", "@tanstack/solid-store": "^0.11.1", "goober": "^2.1.19", - "solid-js": "^1.9.14" + "solid-js": "^1.9.15" }, "peerDependencies": { "@tanstack/table-core": "^9.0.0" diff --git a/packages/vue-table-devtools/package.json b/packages/vue-table-devtools/package.json index 5785f16957..a7d57aeae9 100644 --- a/packages/vue-table-devtools/package.json +++ b/packages/vue-table-devtools/package.json @@ -48,7 +48,7 @@ "skills" ], "dependencies": { - "@tanstack/devtools-utils": "^0.6.0", + "@tanstack/devtools-utils": "^0.7.0", "@tanstack/table-devtools": "workspace:*" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 99d353cab2..29595e6c28 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,11 +35,11 @@ importers: specifier: ^1.0.0 version: 1.0.0 '@changesets/cli': - specifier: ^3.0.0 - version: 3.0.0 + specifier: ^3.0.1 + version: 3.0.1 '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@playwright/test': specifier: ^1.62.1 version: 1.62.1 @@ -48,34 +48,34 @@ importers: version: 13.0.3(size-limit@13.0.3) '@tanstack/eslint-config': specifier: 0.4.0 - version: 0.4.0(@typescript-eslint/utils@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@7.2.0))(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + version: 0.4.0(@typescript-eslint/utils@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@7.2.0))(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@tanstack/intent': - specifier: ^0.3.6 - version: 0.3.6 + specifier: ^0.3.7 + version: 0.3.7 '@tanstack/typedoc-config': specifier: 0.3.4 version: 0.3.4(typescript@6.0.3) '@testing-library/jest-dom': specifier: ^7.0.1 - version: 7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10) + version: 7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11) '@types/node': specifier: ^26.2.0 version: 26.2.0 '@typescript-eslint/parser': - specifier: 8.67.0 - version: 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + specifier: 8.68.0 + version: 8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@vitest/coverage-v8': - specifier: 4.1.10 - version: 4.1.10(vitest@4.1.10) + specifier: 4.1.11 + version: 4.1.11(vitest@4.1.11) eslint: - specifier: ^10.8.1 - version: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + specifier: ^10.9.1 + version: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) jsdom: specifier: ^30.0.1 version: 30.0.1(@noble/hashes@2.2.0) knip: - specifier: ^6.32.2 - version: 6.32.2 + specifier: ^6.32.3 + version: 6.32.3 markdown-link-extractor: specifier: ^4.0.4 version: 4.0.4 @@ -86,14 +86,14 @@ importers: specifier: ^3.9.6 version: 3.9.6 prettier-plugin-ember-template-tag: - specifier: ^2.1.7 - version: 2.1.7(prettier@3.9.6)(supports-color@7.2.0) + specifier: ^2.1.8 + version: 2.1.8(prettier@3.9.6)(supports-color@7.2.0) prettier-plugin-svelte: specifier: ^4.1.1 - version: 4.1.1(prettier@3.9.6)(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + version: 4.1.1(prettier@3.9.6)(svelte@5.56.10(@typescript-eslint/types@8.68.0)) publint: - specifier: ^0.3.23 - version: 0.3.23 + specifier: ^0.3.24 + version: 0.3.24 rimraf: specifier: ^6.1.3 version: 6.1.3 @@ -108,32 +108,35 @@ importers: version: 0.2.17 tsdown: specifier: ^0.22.14 - version: 0.22.14(@volar/typescript@2.4.28(typescript@6.0.3))(oxc-resolver@11.24.2)(publint@0.3.23)(typescript@6.0.3)(vue-tsc@3.3.9(typescript@6.0.3)) + version: 0.22.14(@volar/typescript@2.4.28(typescript@6.0.3))(oxc-resolver@11.24.2)(publint@0.3.24)(typescript@6.0.3)(vue-tsc@3.3.11(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vitest: - specifier: ^4.1.10 - version: 4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^4.1.11 + version: 4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/alpine/aggregation: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -141,8 +144,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/basic-app-table: dependencies: @@ -150,12 +153,15 @@ importers: specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -163,24 +169,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/basic-create-table: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -188,24 +197,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/basic-dynamic-columns: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -213,14 +225,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/basic-external-atoms: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table @@ -228,12 +240,15 @@ importers: specifier: ^0.11.1 version: 0.11.1 alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -241,24 +256,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/basic-external-state: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -266,14 +284,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/cell-selection: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table @@ -281,12 +299,15 @@ importers: specifier: ^0.8.0 version: 0.8.0 alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -294,24 +315,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/cell-spanning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -319,24 +343,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/column-ordering: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -344,24 +371,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/column-pinning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -369,24 +399,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/column-pinning-split: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -394,24 +427,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/column-pinning-sticky: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -419,24 +455,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/column-resizing: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -444,24 +483,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/column-resizing-performant: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -469,24 +511,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/column-sizing: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -494,24 +539,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/column-visibility: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -519,24 +567,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/custom-plugin: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -544,24 +595,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/expanding: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -569,24 +623,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/filters: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -594,24 +651,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/filters-faceted: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -619,24 +679,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/filters-faceted-bucketed: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -644,24 +707,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/grouped-aggregation: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -669,24 +735,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/grouping: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -694,24 +763,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/header-groups: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -719,24 +791,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/pagination: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -744,24 +819,52 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + + examples/alpine/realtime-trading: + dependencies: + '@tanstack/alpine-table': + specifier: workspace:* + version: link:../../../packages/alpine-table + '@tanstack/store': + specifier: ^0.11.1 + version: 0.11.1 + alpinejs: + specifier: ^3.16.3 + version: 3.16.3 + devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 + '@types/alpinejs': + specifier: ^3.13.11 + version: 3.13.11 + typescript: + specifier: 6.0.3 + version: 6.0.3 + vite: + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/row-pinning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -769,24 +872,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/row-selection: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -794,24 +900,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/sorting: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -819,24 +928,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/sorting-dynamic-data: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -844,24 +956,27 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/alpine/sub-components: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/alpine-table': specifier: workspace:* version: link:../../../packages/alpine-table alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/alpinejs': specifier: ^3.13.11 version: 3.13.11 @@ -869,8 +984,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/angular/aggregation: dependencies: @@ -893,8 +1008,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -906,11 +1021,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(273b611b619075aa5982f3d91848666a) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.1.2)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -936,11 +1051,11 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-devtools': - specifier: ^0.0.9 - version: 0.0.9(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.0.11 + version: 0.0.11(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -955,11 +1070,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -988,8 +1103,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-pacer': specifier: ^0.24.0 version: 0.24.0(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) @@ -1004,11 +1119,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1034,11 +1149,11 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-devtools': - specifier: ^0.0.9 - version: 0.0.9(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.0.11 + version: 0.0.11(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/angular-store': specifier: ^0.11.1 version: 0.11.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) @@ -1056,11 +1171,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1086,11 +1201,11 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-devtools': - specifier: ^0.0.9 - version: 0.0.9(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.0.11 + version: 0.0.11(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/angular-store': specifier: ^0.11.1 version: 0.11.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) @@ -1108,11 +1223,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1141,11 +1256,11 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-devtools': - specifier: ^0.0.9 - version: 0.0.9(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.0.11 + version: 0.0.11(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -1160,11 +1275,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1175,8 +1290,8 @@ importers: examples/angular/cell-selection: dependencies: '@angular/cdk': - specifier: ^22.1.0 - version: 22.1.0(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) + specifier: ^22.1.4 + version: 22.1.4(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@angular/common': specifier: ^22.1.1 version: 22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2) @@ -1196,11 +1311,11 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-devtools': - specifier: ^0.0.9 - version: 0.0.9(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.0.11 + version: 0.0.11(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/angular-hotkeys': specifier: ^0.10.0 version: 0.10.0(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) @@ -1218,11 +1333,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1251,8 +1366,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -1264,11 +1379,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1297,8 +1412,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -1310,11 +1425,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1343,8 +1458,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -1356,11 +1471,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1389,8 +1504,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -1402,11 +1517,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1435,8 +1550,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -1448,11 +1563,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1481,8 +1596,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -1494,11 +1609,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1527,8 +1642,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -1540,11 +1655,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1573,8 +1688,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -1586,11 +1701,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1619,8 +1734,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -1632,11 +1747,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1665,11 +1780,11 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-devtools': - specifier: ^0.0.9 - version: 0.0.9(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.0.11 + version: 0.0.11(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -1684,11 +1799,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1727,11 +1842,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1760,8 +1875,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -1773,11 +1888,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1806,8 +1921,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -1819,11 +1934,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1852,8 +1967,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-pacer': specifier: ^0.24.0 version: 0.24.0(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) @@ -1868,11 +1983,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1901,8 +2016,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-pacer': specifier: ^0.24.0 version: 0.24.0(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) @@ -1917,11 +2032,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1950,8 +2065,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -1963,11 +2078,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -1996,8 +2111,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-pacer': specifier: ^0.24.0 version: 0.24.0(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) @@ -2015,11 +2130,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2048,8 +2163,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -2061,11 +2176,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2094,8 +2209,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -2107,11 +2222,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2140,8 +2255,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -2153,11 +2268,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2186,11 +2301,11 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-devtools': - specifier: ^0.0.9 - version: 0.0.9(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.0.11 + version: 0.0.11(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -2208,11 +2323,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2241,8 +2356,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -2254,11 +2369,51 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + '@angular/compiler-cli': + specifier: ^22.1.1 + version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) + typescript: + specifier: 6.0.3 + version: 6.0.3 + + examples/angular/realtime-trading: + dependencies: + '@angular/common': + specifier: ^22.1.1 + version: 22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2) + '@angular/compiler': + specifier: ^22.1.1 + version: 22.1.1 + '@angular/core': + specifier: ^22.1.1 + version: 22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2) + '@angular/platform-browser': + specifier: ^22.1.1 + version: 22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) + '@tanstack/angular-table': + specifier: workspace:* + version: link:../../../packages/angular-table + '@tanstack/angular-virtual': + specifier: ^6.0.3 + version: 6.0.3(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) + rxjs: + specifier: ~7.8.2 + version: 7.8.2 + tslib: + specifier: ^2.8.1 + version: 2.8.1 + devDependencies: + '@angular/build': + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) + '@angular/cli': + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2293,8 +2448,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@angular/ssr': - specifier: ^22.1.2 - version: 22.1.2(874fc147373d2913205073a55aa65479) + specifier: ^22.1.6 + version: 22.1.6(874fc147373d2913205073a55aa65479) '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -2306,11 +2461,11 @@ importers: version: 7.8.2 devDependencies: '@angular-devkit/build-angular': - specifier: ^22.1.2 - version: 22.1.2(606360f3438ba79468f86dfc05103714) + specifier: ^22.1.6 + version: 22.1.6(35a4b302a500827ad46859b04c2b40f3) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2330,8 +2485,8 @@ importers: examples/angular/row-dnd: dependencies: '@angular/cdk': - specifier: ^22.1.0 - version: 22.1.0(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) + specifier: ^22.1.4 + version: 22.1.4(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@angular/common': specifier: ^22.1.1 version: 22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2) @@ -2351,8 +2506,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -2364,11 +2519,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2397,8 +2552,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -2410,11 +2565,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2425,8 +2580,8 @@ importers: examples/angular/row-selection: dependencies: '@angular/cdk': - specifier: ^22.1.0 - version: 22.1.0(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) + specifier: ^22.1.4 + version: 22.1.4(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@angular/common': specifier: ^22.1.1 version: 22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2) @@ -2446,11 +2601,11 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-devtools': - specifier: ^0.0.9 - version: 0.0.9(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.0.11 + version: 0.0.11(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -2465,11 +2620,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2501,11 +2656,11 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/compiler@22.1.1)(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-devtools': - specifier: ^0.0.9 - version: 0.0.9(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.0.11 + version: 0.0.11(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -2520,11 +2675,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2535,8 +2690,8 @@ importers: examples/angular/signal-input: dependencies: '@angular/cdk': - specifier: ^22.1.0 - version: 22.1.0(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) + specifier: ^22.1.4 + version: 22.1.4(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@angular/common': specifier: ^22.1.1 version: 22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2) @@ -2556,8 +2711,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -2569,11 +2724,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2602,8 +2757,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -2615,11 +2770,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2648,8 +2803,8 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table @@ -2661,11 +2816,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2694,14 +2849,14 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table '@tanstack/angular-virtual': - specifier: ^6.0.2 - version: 6.0.2(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) + specifier: ^6.0.3 + version: 6.0.3(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) rxjs: specifier: ~7.8.2 version: 7.8.2 @@ -2710,11 +2865,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2743,14 +2898,14 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table '@tanstack/angular-virtual': - specifier: ^6.0.2 - version: 6.0.2(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) + specifier: ^6.0.3 + version: 6.0.3(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) rxjs: specifier: ~7.8.2 version: 7.8.2 @@ -2759,11 +2914,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2792,14 +2947,14 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-table': specifier: workspace:* version: link:../../../packages/angular-table '@tanstack/angular-virtual': - specifier: ^6.0.2 - version: 6.0.2(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) + specifier: ^6.0.3 + version: 6.0.3(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) rxjs: specifier: ~7.8.2 version: 7.8.2 @@ -2808,11 +2963,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2841,11 +2996,11 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-devtools': - specifier: ^0.0.9 - version: 0.0.9(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.0.11 + version: 0.0.11(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/angular-form': specifier: ^1.33.5 version: 1.33.5(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) @@ -2866,11 +3021,11 @@ importers: version: 4.4.3 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2899,11 +3054,11 @@ importers: specifier: ^22.1.1 version: 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/angular-devtools': - specifier: ^0.0.9 - version: 0.0.9(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.0.11 + version: 0.0.11(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/angular-query-experimental': specifier: ^5.101.4 version: 5.101.4(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) @@ -2921,11 +3076,11 @@ importers: version: 2.8.1 devDependencies: '@angular/build': - specifier: ^22.1.2 - version: 22.1.2(c49ddd1db132d78553f0a5c28aa748f0) + specifier: ^22.1.6 + version: 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/cli': - specifier: ^22.1.2 - version: 22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) + specifier: ^22.1.6 + version: 22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1) '@angular/compiler-cli': specifier: ^22.1.1 version: 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) @@ -2942,8 +3097,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -2979,20 +3134,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -3000,8 +3158,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/basic-app-table: dependencies: @@ -3046,20 +3204,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -3067,8 +3228,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/basic-external-atoms: dependencies: @@ -3079,8 +3240,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -3116,20 +3277,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -3137,8 +3301,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/basic-external-state: dependencies: @@ -3149,8 +3313,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -3186,20 +3350,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -3207,8 +3374,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/basic-table: dependencies: @@ -3253,20 +3420,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -3274,8 +3444,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/cell-selection: dependencies: @@ -3286,8 +3456,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -3326,20 +3496,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -3347,8 +3520,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/cell-spanning: dependencies: @@ -3359,8 +3532,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -3396,20 +3569,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -3417,8 +3593,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/column-ordering: dependencies: @@ -3429,8 +3605,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -3466,20 +3642,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -3487,8 +3666,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/column-pinning: dependencies: @@ -3499,8 +3678,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -3536,20 +3715,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -3557,8 +3739,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/column-pinning-split: dependencies: @@ -3569,8 +3751,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -3606,20 +3788,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -3627,8 +3812,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/column-pinning-sticky: dependencies: @@ -3639,8 +3824,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -3676,20 +3861,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -3697,8 +3885,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/column-resizing: dependencies: @@ -3709,8 +3897,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -3746,20 +3934,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -3767,8 +3958,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/column-resizing-performant: dependencies: @@ -3779,8 +3970,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -3816,20 +4007,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -3837,8 +4031,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/column-sizing: dependencies: @@ -3849,8 +4043,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -3886,20 +4080,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -3907,8 +4104,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/column-visibility: dependencies: @@ -3919,8 +4116,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -3956,20 +4153,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -3977,8 +4177,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/custom-plugin: dependencies: @@ -3989,8 +4189,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -4029,20 +4229,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -4050,8 +4253,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/editable: dependencies: @@ -4062,8 +4265,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -4099,20 +4302,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -4120,8 +4326,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/expanding: dependencies: @@ -4132,8 +4338,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -4169,20 +4375,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -4190,8 +4399,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/filters: dependencies: @@ -4202,8 +4411,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -4239,20 +4448,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -4260,8 +4472,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/filters-faceted: dependencies: @@ -4272,8 +4484,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -4309,20 +4521,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -4330,8 +4545,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/filters-faceted-bucketed: dependencies: @@ -4342,8 +4557,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -4379,20 +4594,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -4400,8 +4618,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/filters-fuzzy: dependencies: @@ -4412,8 +4630,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -4452,20 +4670,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -4473,8 +4694,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/grouped-aggregation: dependencies: @@ -4485,8 +4706,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -4522,20 +4743,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -4543,8 +4767,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/grouping: dependencies: @@ -4555,8 +4779,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -4592,20 +4816,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -4613,8 +4840,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/header-groups: dependencies: @@ -4625,8 +4852,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -4662,20 +4889,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -4683,8 +4913,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/kitchen-sink: dependencies: @@ -4695,8 +4925,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -4735,20 +4965,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -4756,8 +4989,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/pagination: dependencies: @@ -4768,8 +5001,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -4805,20 +5038,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -4826,8 +5062,84 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + + examples/ember/realtime-trading: + dependencies: + '@embroider/macros': + specifier: 1.20.6 + version: 1.20.6(@babel/core@7.29.7(supports-color@8.1.1))(@glint/template@1.8.0)(supports-color@8.1.1) + '@embroider/router': + specifier: 3.0.6 + version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) + '@glimmer/component': + specifier: 2.1.1 + version: 2.1.1(supports-color@8.1.1) + '@tanstack/ember-table': + specifier: workspace:* + version: link:../../../packages/ember-table + '@tanstack/store': + specifier: ^0.11.1 + version: 0.11.1 + decorator-transforms: + specifier: 2.4.0 + version: 2.4.0(@babel/core@7.29.7(supports-color@8.1.1)) + ember-modifier: + specifier: ^4.3.0 + version: 4.3.0(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + ember-source: + specifier: 7.2.0 + version: 7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1) + ember-strict-application-resolver: + specifier: 0.1.1 + version: 0.1.1(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + devDependencies: + '@babel/core': + specifier: 7.29.7 + version: 7.29.7(supports-color@8.1.1) + '@babel/plugin-transform-runtime': + specifier: 7.29.7 + version: 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-typescript': + specifier: 7.29.7 + version: 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/runtime': + specifier: 7.29.7 + version: 7.29.7 + '@ember/app-tsconfig': + specifier: 2.0.0 + version: 2.0.0 + '@embroider/core': + specifier: 4.6.3 + version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) + '@glint/ember-tsc': + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@glint/template': + specifier: 1.8.0 + version: 1.8.0 + '@glint/tsserver-plugin': + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + '@nullvoxpopuli/ember-vite': + specifier: 1.1.0 + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 + '@rollup/plugin-babel': + specifier: 7.1.0 + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) + babel-plugin-ember-template-compilation: + specifier: 4.0.0 + version: 4.0.0 + typescript: + specifier: 6.0.3 + version: 6.0.3 + vite: + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/remote-data: dependencies: @@ -4838,8 +5150,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -4875,20 +5187,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -4896,8 +5211,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/row-dnd: dependencies: @@ -4908,8 +5223,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -4945,20 +5260,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -4966,8 +5284,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/row-pinning: dependencies: @@ -4978,8 +5296,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -5015,20 +5333,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -5036,8 +5357,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/row-selection: dependencies: @@ -5048,8 +5369,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -5085,20 +5406,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -5106,8 +5430,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/sorting: dependencies: @@ -5118,8 +5442,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -5155,20 +5479,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -5176,8 +5503,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/ember/sub-components: dependencies: @@ -5188,8 +5515,8 @@ importers: specifier: 3.0.6 version: 3.0.6(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(supports-color@8.1.1) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) @@ -5225,20 +5552,23 @@ importers: specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@nullvoxpopuli/ember-vite': specifier: 1.1.0 - version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) babel-plugin-ember-template-compilation: specifier: 4.0.0 version: 4.0.0 @@ -5246,14 +5576,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/aggregation: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5261,21 +5591,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/basic-app-table: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@lit/context': specifier: ^1.1.6 version: 1.1.6 @@ -5286,21 +5619,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/basic-dynamic-columns: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5308,21 +5644,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/basic-external-atoms: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5333,21 +5672,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/basic-external-state: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5355,21 +5697,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/basic-subscribe: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-store': specifier: ^0.14.1 version: 0.14.1(lit@3.3.3) @@ -5380,21 +5725,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/basic-table-controller: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5402,21 +5750,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/cell-selection: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-hotkeys': specifier: ^0.11.0 version: 0.11.0(lit@3.3.3) @@ -5427,21 +5778,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/cell-spanning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5449,21 +5803,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/column-ordering: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5471,21 +5828,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/column-pinning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5493,21 +5853,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/column-pinning-split: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5515,21 +5878,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/column-pinning-sticky: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5537,21 +5903,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/column-resizing: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5559,21 +5928,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/column-resizing-performant: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5581,21 +5953,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/column-sizing: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5603,21 +5978,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/column-visibility: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5625,21 +6003,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/composable-tables: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@lit/context': specifier: ^1.1.6 version: 1.1.6 @@ -5650,21 +6031,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/expanding: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5672,21 +6056,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/filters: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5694,21 +6081,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/filters-faceted: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5716,21 +6106,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/filters-faceted-bucketed: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5738,21 +6131,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/filters-fuzzy: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5763,21 +6159,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/grouped-aggregation: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5785,21 +6184,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/grouping: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5807,21 +6209,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/header-groups: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5829,21 +6234,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/kitchen-sink: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5854,21 +6262,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/pagination: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5876,21 +6287,49 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + + examples/lit/realtime-trading: + dependencies: + '@tanstack/lit-table': + specifier: workspace:* + version: link:../../../packages/lit-table + '@tanstack/lit-virtual': + specifier: ^3.13.37 + version: 3.13.37(lit@3.3.3) + '@tanstack/store': + specifier: ^0.11.1 + version: 0.11.1 + lit: + specifier: ^3.3.3 + version: 3.3.3 + devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 + typescript: + specifier: 6.0.3 + version: 6.0.3 + vite: + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/row-pinning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5898,21 +6337,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/row-selection: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5920,21 +6362,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/sorting: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5942,21 +6387,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/sorting-dynamic-data: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5964,21 +6412,24 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/sub-components: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table @@ -5986,209 +6437,236 @@ importers: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/virtualized-columns: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table '@tanstack/lit-virtual': - specifier: ^3.13.36 - version: 3.13.36(lit@3.3.3) + specifier: ^3.13.37 + version: 3.13.37(lit@3.3.3) lit: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/virtualized-infinite-scrolling: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table '@tanstack/lit-virtual': - specifier: ^3.13.36 - version: 3.13.36(lit@3.3.3) + specifier: ^3.13.37 + version: 3.13.37(lit@3.3.3) lit: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/lit/virtualized-rows: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/lit-table': specifier: workspace:* version: link:../../../packages/lit-table '@tanstack/lit-virtual': - specifier: ^3.13.36 - version: 3.13.36(lit@3.3.3) + specifier: ^3.13.37 + version: 3.13.37(lit@3.3.3) lit: specifier: ^3.3.3 version: 3.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/aggregation: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-store': specifier: ^0.12.2 - version: 0.12.2(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))) + version: 0.12.2(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))) '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/basic-dynamic-columns: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/basic-external-atoms: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-store': specifier: ^0.12.2 - version: 0.12.2(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))) + version: 0.12.2(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))) '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/basic-external-state: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/basic-subscribe: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-store': specifier: ^0.12.2 - version: 0.12.2(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))) + version: 0.12.2(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))) '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/basic-use-app-table: dependencies: @@ -6197,17 +6675,20 @@ importers: version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/basic-use-table: dependencies: @@ -6216,290 +6697,329 @@ importers: version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/cell-spanning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/column-ordering: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/column-pinning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/column-pinning-split: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/column-pinning-sticky: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/column-resizing: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/column-resizing-performant: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/column-sizing: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/column-visibility: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/composable-tables: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-store': specifier: ^0.12.2 - version: 0.12.2(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))) + version: 0.12.2(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))) '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/custom-plugin: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/expanding: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/filters: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -6508,23 +7028,26 @@ importers: version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/filters-faceted: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -6533,45 +7056,51 @@ importers: version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/filters-faceted-bucketed: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/filters-fuzzy: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -6580,89 +7109,101 @@ importers: version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/grouped-aggregation: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/grouping: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/header-groups: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/kitchen-sink: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -6671,139 +7212,182 @@ importers: version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/pagination: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@tanstack/octane-store': + specifier: ^0.12.2 + version: 0.12.2(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))) + '@tanstack/octane-table': + specifier: workspace:* + version: link:../../../packages/octane-table + octane: + specifier: 0.1.36 + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 + '@tsrx/typescript-plugin': + specifier: ^0.3.118 + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + typescript: + specifier: 6.0.3 + version: 6.0.3 + vite: + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + + examples/octane/realtime-trading: + dependencies: '@tanstack/octane-store': specifier: ^0.12.2 - version: 0.12.2(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))) + version: 0.12.2(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))) '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/row-pinning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/row-selection: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-store': specifier: ^0.12.2 - version: 0.12.2(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))) + version: 0.12.2(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))) '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/sorting: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/octane/sub-components: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/octane-table': specifier: workspace:* version: link:../../../packages/octane-table octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/aggregation: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-store': specifier: ^0.13.2 version: 0.13.2(preact@10.29.8) @@ -6816,22 +7400,25 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/basic-dynamic-columns: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.15) '@tanstack/preact-pacer': specifier: ^0.23.0 version: 0.23.0(preact@10.29.8) @@ -6847,22 +7434,25 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/basic-external-atoms: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.15) '@tanstack/preact-store': specifier: ^0.13.2 version: 0.13.2(preact@10.29.8) @@ -6878,22 +7468,25 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/basic-external-state: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.15) '@tanstack/preact-store': specifier: ^0.13.2 version: 0.13.2(preact@10.29.8) @@ -6909,22 +7502,25 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/basic-subscribe: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.15) '@tanstack/preact-store': specifier: ^0.13.2 version: 0.13.2(preact@10.29.8) @@ -6940,19 +7536,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/basic-use-app-table: dependencies: '@tanstack/preact-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.15) '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -6965,19 +7564,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/basic-use-table: dependencies: '@tanstack/preact-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.15) '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -6990,22 +7592,25 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/cell-selection: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.15) '@tanstack/preact-hotkeys': specifier: ^0.10.0 version: 0.10.0(preact@10.29.8) @@ -7024,19 +7629,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/cell-spanning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7046,19 +7654,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/column-ordering: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7068,19 +7679,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/column-pinning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7090,19 +7704,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/column-pinning-split: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7112,19 +7729,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/column-pinning-sticky: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7134,19 +7754,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/column-resizing: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7156,19 +7779,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/column-resizing-performant: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7178,19 +7804,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/column-sizing: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7200,19 +7829,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/column-visibility: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7222,22 +7854,25 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/composable-tables: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.15) '@tanstack/preact-store': specifier: ^0.13.2 version: 0.13.2(preact@10.29.8) @@ -7253,19 +7888,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/custom-plugin: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7275,19 +7913,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/expanding: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7297,19 +7938,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/filters: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -7325,19 +7969,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/filters-faceted: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -7353,19 +8000,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/filters-faceted-bucketed: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7375,19 +8025,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/filters-fuzzy: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -7403,19 +8056,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/grouped-aggregation: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7425,19 +8081,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/grouping: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7447,19 +8106,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/header-groups: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7469,25 +8131,28 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/kitchen-sink: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils '@tanstack/preact-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.15) '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7500,19 +8165,47 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/pagination: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@tanstack/preact-store': + specifier: ^0.13.2 + version: 0.13.2(preact@10.29.8) + '@tanstack/preact-table': + specifier: workspace:* + version: link:../../../packages/preact-table + preact: + specifier: ^10.29.8 + version: 10.29.8(preact-render-to-string@6.7.0) + devDependencies: + '@preact/preset-vite': + specifier: ^2.10.6 + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 + typescript: + specifier: 6.0.3 + version: 6.0.3 + vite: + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + + examples/preact/realtime-trading: + dependencies: '@tanstack/preact-store': specifier: ^0.13.2 version: 0.13.2(preact@10.29.8) @@ -7525,19 +8218,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/row-pinning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7547,22 +8243,25 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/row-selection: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.15) '@tanstack/preact-store': specifier: ^0.13.2 version: 0.13.2(preact@10.29.8) @@ -7578,19 +8277,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/sorting: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7600,19 +8302,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/sub-components: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7622,22 +8327,25 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/with-tanstack-form: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.15) '@tanstack/preact-form': specifier: ^1.30.5 version: 1.30.5(preact@10.29.8) @@ -7646,7 +8354,7 @@ importers: version: 0.23.0(preact@10.29.8) '@tanstack/preact-pacer-devtools': specifier: 0.7.0 - version: 0.7.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) + version: 0.7.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) '@tanstack/preact-table': specifier: workspace:* version: link:../../../packages/preact-table @@ -7655,7 +8363,7 @@ importers: version: link:../../../packages/preact-table-devtools '@tanstack/react-form-devtools': specifier: ^0.2.34 - version: 0.2.34(@types/react@19.2.18)(csstype@3.2.3)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(vue@3.5.41(typescript@6.0.3)) + version: 0.2.34(@types/react@19.2.18)(csstype@3.2.3)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(vue@3.5.41(typescript@6.0.3)) preact: specifier: ^10.29.8 version: 10.29.8(preact-render-to-string@6.7.0) @@ -7665,22 +8373,25 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/preact/with-tanstack-query: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/preact-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.15) '@tanstack/preact-query': specifier: ^5.101.4 version: 5.101.4(preact@10.29.8) @@ -7699,19 +8410,22 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/aggregation: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -7722,21 +8436,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -7744,17 +8461,17 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/basic-dynamic-columns: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -7771,21 +8488,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -7793,17 +8513,17 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/basic-external-atoms: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-store': specifier: ^0.11.1 version: 0.11.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -7820,21 +8540,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -7842,17 +8565,17 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/basic-external-state: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-store': specifier: ^0.11.1 version: 0.11.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -7869,21 +8592,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -7891,17 +8617,17 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/basic-subscribe: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -7921,21 +8647,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -7943,14 +8672,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/basic-use-app-table: dependencies: '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -7964,21 +8693,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -7986,17 +8718,17 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/basic-use-legacy-table: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -8013,21 +8745,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8035,14 +8770,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/basic-use-table: dependencies: '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -8056,21 +8791,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8078,17 +8816,17 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/cell-selection: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-hotkeys': specifier: ^0.10.0 version: 0.10.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -8108,21 +8846,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8130,14 +8871,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/cell-spanning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -8148,21 +8889,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8170,8 +8914,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/column-dnd: dependencies: @@ -8188,8 +8932,8 @@ importers: specifier: ^3.2.2 version: 3.2.2(react@19.2.8) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -8200,21 +8944,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8222,14 +8969,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/column-ordering: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -8240,21 +8987,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8262,14 +9012,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/column-pinning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -8280,21 +9030,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8302,14 +9055,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/column-pinning-split: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -8320,21 +9073,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8342,14 +9098,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/column-pinning-sticky: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -8360,21 +9116,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8382,14 +9141,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/column-resizing: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -8400,21 +9159,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8422,14 +9184,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/column-resizing-performant: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -8440,21 +9202,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8462,14 +9227,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/column-sizing: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -8480,21 +9245,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8502,14 +9270,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/column-visibility: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -8520,21 +9288,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8542,17 +9313,17 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/composable-tables: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-store': specifier: ^0.11.1 version: 0.11.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -8569,21 +9340,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8591,14 +9365,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/custom-plugin: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -8612,21 +9386,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8634,14 +9411,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/expanding: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -8655,21 +9432,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8677,14 +9457,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/filters: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -8701,21 +9481,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8723,14 +9506,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/filters-faceted: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -8747,21 +9530,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8769,14 +9555,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/filters-faceted-bucketed: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -8787,21 +9573,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8809,14 +9598,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/filters-fuzzy: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -8833,21 +9622,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8855,14 +9647,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/grouped-aggregation: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -8873,21 +9665,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8895,14 +9690,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/grouping: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -8913,21 +9708,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8935,14 +9733,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/header-groups: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -8953,21 +9751,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -8975,8 +9776,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/kitchen-sink: dependencies: @@ -8993,14 +9794,14 @@ importers: specifier: ^3.2.2 version: 3.2.2(react@19.2.8) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-hotkeys': specifier: ^0.10.0 version: 0.10.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -9008,11 +9809,11 @@ importers: specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tanstack/react-router': - specifier: ^1.170.27 - version: 1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^1.170.32 + version: 1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tanstack/react-start': - specifier: ^1.168.44 - version: 1.168.44(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) + specifier: ^1.168.49 + version: 1.168.49(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) '@tanstack/react-store': specifier: ^0.11.1 version: 0.11.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -9029,9 +9830,12 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@types/node': specifier: ^26.2.0 version: 26.2.0 @@ -9039,11 +9843,11 @@ importers: specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -9051,8 +9855,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/kitchen-sink-chakra-ui: dependencies: @@ -9075,8 +9879,8 @@ importers: specifier: ^11.14.0 version: 11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tabler/icons-react': specifier: ^3.46.0 version: 3.46.0(react@19.2.8) @@ -9084,8 +9888,8 @@ importers: specifier: workspace:* version: link:../../../packages/match-sorter-utils '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -9108,21 +9912,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -9130,8 +9937,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/kitchen-sink-hero-ui: dependencies: @@ -9148,23 +9955,23 @@ importers: specifier: ^3.2.2 version: 3.2.2(react@19.2.8) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@heroui/react': specifier: ^3.2.4 - version: 3.2.4(@react-aria/i18n@3.13.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-aria/ssr@3.10.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-aria/utils@3.34.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-spectrum/provider@3.11.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-aria-components@1.20.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-aria@3.51.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(tailwindcss@4.3.3) + version: 3.2.4(@react-aria/i18n@3.13.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-aria/ssr@3.10.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-aria/utils@3.34.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-spectrum/provider@3.11.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-aria-components@1.20.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-aria@3.51.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(tailwindcss@4.3.3) '@heroui/styles': specifier: ^3.2.4 version: 3.2.4(tailwind-merge@3.4.0)(tailwindcss@4.3.3) '@tailwindcss/vite': specifier: ^4.3.3 - version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 4.3.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -9187,21 +9994,24 @@ importers: specifier: ^4.3.3 version: 4.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -9209,8 +10019,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/kitchen-sink-mantine: dependencies: @@ -9227,14 +10037,14 @@ importers: specifier: ^3.2.2 version: 3.2.2(react@19.2.8) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@mantine/core': - specifier: ^9.5.1 - version: 9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^9.5.2 + version: 9.5.2(@mantine/hooks@9.5.2(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@mantine/hooks': - specifier: ^9.5.1 - version: 9.5.1(react@19.2.8) + specifier: ^9.5.2 + version: 9.5.2(react@19.2.8) '@tabler/icons-react': specifier: ^3.46.0 version: 3.46.0(react@19.2.8) @@ -9242,8 +10052,8 @@ importers: specifier: workspace:* version: link:../../../packages/match-sorter-utils '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -9263,21 +10073,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -9294,8 +10107,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/kitchen-sink-material-ui: dependencies: @@ -9318,8 +10131,8 @@ importers: specifier: ^11.14.1 version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@mui/icons-material': specifier: ^9.3.1 version: 9.3.1(@mui/material@9.3.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/react@19.2.18)(react@19.2.8) @@ -9330,8 +10143,8 @@ importers: specifier: workspace:* version: link:../../../packages/match-sorter-utils '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -9351,21 +10164,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -9373,8 +10189,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/kitchen-sink-react-aria: dependencies: @@ -9391,17 +10207,17 @@ importers: specifier: ^3.2.2 version: 3.2.2(react@19.2.8) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tailwindcss/vite': specifier: ^4.3.3 - version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 4.3.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -9427,21 +10243,24 @@ importers: specifier: ^4.3.3 version: 4.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -9449,8 +10268,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/kitchen-sink-shadcn-base: dependencies: @@ -9470,17 +10289,17 @@ importers: specifier: ^3.2.2 version: 3.2.2(react@19.2.8) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tailwindcss/vite': specifier: ^4.3.3 - version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 4.3.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -9498,13 +10317,13 @@ importers: version: 2.1.1 cmdk: specifier: 1.1.1 - version: 1.1.1(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.1.1(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) date-fns: specifier: ^4.4.0 version: 4.4.0 lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.34.0 + version: 1.34.0(react@19.2.8) react: specifier: ^19.2.8 version: 19.2.8 @@ -9524,21 +10343,24 @@ importers: specifier: ^1.4.0 version: 1.4.0 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -9546,8 +10368,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/kitchen-sink-shadcn-radix: dependencies: @@ -9564,17 +10386,17 @@ importers: specifier: ^3.2.2 version: 3.2.2(react@19.2.8) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tailwindcss/vite': specifier: ^4.3.3 - version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 4.3.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -9592,16 +10414,16 @@ importers: version: 2.1.1 cmdk: specifier: 1.1.1 - version: 1.1.1(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.1.1(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) date-fns: specifier: ^4.4.0 version: 4.4.0 lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.34.0 + version: 1.34.0(react@19.2.8) radix-ui: specifier: ^1.6.7 - version: 1.6.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.6.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: specifier: ^19.2.8 version: 19.2.8 @@ -9621,21 +10443,24 @@ importers: specifier: ^1.4.0 version: 1.4.0 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -9643,8 +10468,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/lib-chakra-ui: dependencies: @@ -9655,8 +10480,8 @@ importers: specifier: ^11.14.0 version: 11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tabler/icons-react': specifier: ^3.46.0 version: 3.46.0(react@19.2.8) @@ -9670,21 +10495,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -9692,23 +10520,23 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/lib-hero-ui: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@heroui/react': specifier: ^3.2.4 - version: 3.2.4(@react-aria/i18n@3.13.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-aria/ssr@3.10.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-aria/utils@3.34.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-spectrum/provider@3.11.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-aria-components@1.20.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-aria@3.51.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(tailwindcss@4.3.3) + version: 3.2.4(@react-aria/i18n@3.13.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-aria/ssr@3.10.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-aria/utils@3.34.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-spectrum/provider@3.11.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-aria-components@1.20.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-aria@3.51.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(tailwindcss@4.3.3) '@heroui/styles': specifier: ^3.2.4 version: 3.2.4(tailwind-merge@3.6.0)(tailwindcss@4.3.3) '@tailwindcss/vite': specifier: ^4.3.3 - version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 4.3.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -9722,21 +10550,24 @@ importers: specifier: ^4.3.3 version: 4.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -9744,20 +10575,20 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/lib-mantine: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@mantine/core': - specifier: ^9.5.1 - version: 9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^9.5.2 + version: 9.5.2(@mantine/hooks@9.5.2(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@mantine/hooks': - specifier: ^9.5.1 - version: 9.5.1(react@19.2.8) + specifier: ^9.5.2 + version: 9.5.2(react@19.2.8) '@tabler/icons-react': specifier: ^3.46.0 version: 3.46.0(react@19.2.8) @@ -9771,21 +10602,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -9802,8 +10636,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/lib-material-ui: dependencies: @@ -9814,8 +10648,8 @@ importers: specifier: ^11.14.1 version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@mui/icons-material': specifier: ^9.3.1 version: 9.3.1(@mui/material@9.3.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/react@19.2.18)(react@19.2.8) @@ -9832,21 +10666,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -9854,17 +10691,17 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/lib-react-aria: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tailwindcss/vite': specifier: ^4.3.3 - version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 4.3.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -9881,21 +10718,24 @@ importers: specifier: ^4.3.3 version: 4.3.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -9903,8 +10743,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/lib-shadcn-base: dependencies: @@ -9912,11 +10752,11 @@ importers: specifier: ^1.7.0 version: 1.7.0(@date-fns/tz@1.5.0)(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tailwindcss/vite': specifier: ^4.3.3 - version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 4.3.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -9930,8 +10770,8 @@ importers: specifier: ^2.1.1 version: 2.1.1 lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.34.0 + version: 1.34.0(react@19.2.8) react: specifier: ^19.2.8 version: 19.2.8 @@ -9948,21 +10788,24 @@ importers: specifier: ^1.4.0 version: 1.4.0 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -9970,17 +10813,17 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/lib-shadcn-radix: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tailwindcss/vite': specifier: ^4.3.3 - version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 4.3.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -9994,11 +10837,11 @@ importers: specifier: ^2.1.1 version: 2.1.1 lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.34.0 + version: 1.34.0(react@19.2.8) radix-ui: specifier: ^1.6.7 - version: 1.6.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.6.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: specifier: ^19.2.8 version: 19.2.8 @@ -10015,21 +10858,24 @@ importers: specifier: ^1.4.0 version: 1.4.0 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10037,23 +10883,23 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/mantine-react-table: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@mantine/core': - specifier: ^9.5.1 - version: 9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^9.5.2 + version: 9.5.2(@mantine/hooks@9.5.2(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@mantine/dates': - specifier: ^9.5.1 - version: 9.5.1(@mantine/core@9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mantine/hooks@9.5.1(react@19.2.8))(dayjs@1.11.21)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^9.5.2 + version: 9.5.2(@mantine/core@9.5.2(@mantine/hooks@9.5.2(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mantine/hooks@9.5.2(react@19.2.8))(dayjs@1.11.23)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@mantine/hooks': - specifier: ^9.5.1 - version: 9.5.1(react@19.2.8) + specifier: ^9.5.2 + version: 9.5.2(react@19.2.8) '@tabler/icons-react': specifier: ^3.46.0 version: 3.46.0(react@19.2.8) @@ -10067,14 +10913,14 @@ importers: specifier: workspace:* version: link:../../../packages/react-table '@tanstack/react-virtual': - specifier: ^3.14.9 - version: 3.14.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^3.14.10 + version: 3.14.10(react-dom@19.2.8(react@19.2.8))(react@19.2.8) clsx: specifier: ^2.1.1 version: 2.1.1 dayjs: - specifier: ^1.11.21 - version: 1.11.21 + specifier: ^1.11.23 + version: 1.11.23 react: specifier: ^19.2.8 version: 19.2.8 @@ -10082,21 +10928,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10113,8 +10962,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/material-react-table: dependencies: @@ -10125,8 +10974,8 @@ importers: specifier: ^11.14.1 version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@mui/icons-material': specifier: ^9.3.1 version: 9.3.1(@mui/material@9.3.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/react@19.2.18)(react@19.2.8) @@ -10134,8 +10983,8 @@ importers: specifier: ^9.3.1 version: 9.3.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@mui/x-date-pickers': - specifier: ^9.11.0 - version: 9.11.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@mui/material@9.3.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mui/system@9.3.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(date-fns@4.4.0)(dayjs@1.11.21)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^9.12.0 + version: 9.12.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@mui/material@9.3.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mui/system@9.3.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(date-fns@4.4.0)(dayjs@1.11.23)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -10149,8 +10998,8 @@ importers: specifier: workspace:* version: link:../../../packages/react-table '@tanstack/react-virtual': - specifier: ^3.14.9 - version: 3.14.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^3.14.10 + version: 3.14.10(react-dom@19.2.8(react@19.2.8))(react@19.2.8) highlight-words: specifier: ^2.0.0 version: 2.0.0 @@ -10161,21 +11010,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10183,20 +11035,66 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/pagination: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@tanstack/react-store': + specifier: ^0.11.1 + version: 0.11.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@tanstack/react-table': + specifier: workspace:* + version: link:../../../packages/react-table + react: + specifier: ^19.2.8 + version: 19.2.8 + react-dom: + specifier: ^19.2.8 + version: 19.2.8(react@19.2.8) + devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 + '@rolldown/plugin-babel': + specifier: ^0.2.3 + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rollup/plugin-replace': + specifier: ^6.0.3 + version: 6.0.3(rollup@4.63.0) + '@types/react': + specifier: ^19.2.18 + version: 19.2.18 + '@types/react-dom': + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) + '@vitejs/plugin-react': + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + babel-plugin-react-compiler: + specifier: ^1.0.0 + version: 1.0.0 + typescript: + specifier: 6.0.3 + version: 6.0.3 + vite: + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + + examples/react/realtime-trading: + dependencies: '@tanstack/react-store': specifier: ^0.11.1 version: 0.11.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table + '@tanstack/react-virtual': + specifier: ^3.14.10 + version: 3.14.10(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: specifier: ^19.2.8 version: 19.2.8 @@ -10204,21 +11102,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10226,8 +11127,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/row-dnd: dependencies: @@ -10244,8 +11145,8 @@ importers: specifier: ^3.2.2 version: 3.2.2(react@19.2.8) '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -10256,21 +11157,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10278,14 +11182,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/row-pinning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -10299,21 +11203,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10321,17 +11228,17 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/row-selection: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -10351,21 +11258,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10373,14 +11283,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/sorting: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -10391,21 +11301,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10413,14 +11326,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/spreadsheet: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-hotkeys': specifier: ^0.10.0 version: 0.10.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -10431,8 +11344,8 @@ importers: specifier: workspace:* version: link:../../../packages/react-table '@tanstack/react-virtual': - specifier: ^3.14.9 - version: 3.14.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^3.14.10 + version: 3.14.10(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: specifier: ^19.2.8 version: 19.2.8 @@ -10440,21 +11353,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10462,14 +11378,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/sub-components: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -10480,21 +11396,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10502,20 +11421,20 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/virtualized-columns: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table '@tanstack/react-virtual': - specifier: ^3.14.9 - version: 3.14.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^3.14.10 + version: 3.14.10(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: specifier: ^19.2.8 version: 19.2.8 @@ -10523,21 +11442,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10545,20 +11467,20 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/virtualized-columns-experimental: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table '@tanstack/react-virtual': - specifier: ^3.14.9 - version: 3.14.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^3.14.10 + version: 3.14.10(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: specifier: ^19.2.8 version: 19.2.8 @@ -10566,21 +11488,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10588,14 +11513,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/virtualized-infinite-scrolling: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-query': specifier: ^5.101.4 version: 5.101.4(react@19.2.8) @@ -10603,8 +11528,8 @@ importers: specifier: workspace:* version: link:../../../packages/react-table '@tanstack/react-virtual': - specifier: ^3.14.9 - version: 3.14.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^3.14.10 + version: 3.14.10(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: specifier: ^19.2.8 version: 19.2.8 @@ -10612,21 +11537,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10634,20 +11562,20 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/virtualized-rows: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table '@tanstack/react-virtual': - specifier: ^3.14.9 - version: 3.14.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^3.14.10 + version: 3.14.10(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: specifier: ^19.2.8 version: 19.2.8 @@ -10655,21 +11583,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10677,20 +11608,20 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/virtualized-rows-experimental: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table '@tanstack/react-virtual': - specifier: ^3.14.9 - version: 3.14.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^3.14.10 + version: 3.14.10(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: specifier: ^19.2.8 version: 19.2.8 @@ -10698,21 +11629,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10720,23 +11654,23 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/web-worker-row-models: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-router': - specifier: ^1.170.27 - version: 1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^1.170.32 + version: 1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tanstack/react-start': - specifier: ^1.168.44 - version: 1.168.44(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) + specifier: ^1.168.49 + version: 1.168.49(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) '@tanstack/react-store': specifier: ^0.11.1 version: 0.11.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -10753,9 +11687,12 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@types/node': specifier: ^26.2.0 version: 26.2.0 @@ -10763,11 +11700,11 @@ importers: specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10775,29 +11712,29 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/with-tanstack-form: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-form': specifier: ^1.33.5 - version: 1.33.5(@tanstack/react-start@1.168.44(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)))(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.33.5(@tanstack/react-start@1.168.49(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)))(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tanstack/react-form-devtools': specifier: ^0.2.34 - version: 0.2.34(@types/react@19.2.18)(csstype@3.2.3)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(vue@3.5.41(typescript@6.0.3)) + version: 0.2.34(@types/react@19.2.18)(csstype@3.2.3)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(vue@3.5.41(typescript@6.0.3)) '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tanstack/react-pacer-devtools': specifier: 0.8.0 - version: 0.8.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(preact@10.29.8)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) + version: 0.8.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(preact@10.29.8)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -10814,21 +11751,24 @@ importers: specifier: ^4.4.3 version: 4.4.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10836,17 +11776,17 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/with-tanstack-query: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-query': specifier: ^5.101.4 version: 5.101.4(react@19.2.8) @@ -10866,21 +11806,24 @@ importers: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10888,20 +11831,20 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/react/with-tanstack-router: dependencies: '@tanstack/react-devtools': - specifier: ^0.10.10 - version: 0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + specifier: ^0.10.12 + version: 0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/react-pacer': specifier: ^0.23.0 version: 0.23.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tanstack/react-pacer-devtools': specifier: 0.8.0 - version: 0.8.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(preact@10.29.8)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) + version: 0.8.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(preact@10.29.8)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) '@tanstack/react-query': specifier: ^5.101.4 version: 5.101.4(react@19.2.8) @@ -10909,11 +11852,11 @@ importers: specifier: ^5.101.4 version: 5.101.4(@tanstack/react-query@5.101.4(react@19.2.8))(react@19.2.8) '@tanstack/react-router': - specifier: ^1.170.27 - version: 1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^1.170.32 + version: 1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tanstack/react-router-devtools': specifier: ^1.167.1 - version: 1.167.1(@tanstack/react-router@1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@tanstack/router-core@1.171.22)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.167.1(@tanstack/react-router@1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@tanstack/router-core@1.171.27)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tanstack/react-table': specifier: workspace:* version: link:../../../packages/react-table @@ -10928,26 +11871,29 @@ importers: version: 19.2.8(react@19.2.8) devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@tanstack/router-vite-plugin': - specifier: ^1.167.30 - version: 1.167.30(@tanstack/react-router@1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) + specifier: ^1.167.35 + version: 1.167.35(@tanstack/react-router@1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -10955,8 +11901,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/solid/aggregation: dependencies: @@ -10964,30 +11910,33 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/basic-app-table: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/solid-devtools': - specifier: ^0.8.10 - version: 0.8.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.8.12 + version: 0.8.12(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table @@ -10995,52 +11944,58 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table-devtools solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/basic-dynamic-columns: dependencies: '@tanstack/solid-pacer': specifier: ^0.22.0 - version: 0.22.0(solid-js@1.9.14) + version: 0.22.0(solid-js@1.9.15) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/basic-external-atoms: dependencies: '@tanstack/solid-devtools': - specifier: ^0.8.10 - version: 0.8.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.8.12 + version: 0.8.12(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/solid-store': specifier: ^0.11.1 - version: 0.11.1(solid-js@1.9.14) + version: 0.11.1(solid-js@1.9.15) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table @@ -11048,27 +12003,30 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table-devtools solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/basic-external-state: dependencies: '@tanstack/solid-devtools': - specifier: ^0.8.10 - version: 0.8.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.8.12 + version: 0.8.12(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table @@ -11076,27 +12034,30 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table-devtools solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/basic-use-table: dependencies: '@tanstack/solid-devtools': - specifier: ^0.8.10 - version: 0.8.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.8.12 + version: 0.8.12(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table @@ -11104,27 +12065,30 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table-devtools solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/cell-selection: dependencies: '@tanstack/solid-devtools': - specifier: ^0.8.10 - version: 0.8.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.8.12 + version: 0.8.12(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/solid-hotkeys': specifier: ^0.10.0 - version: 0.10.0(solid-js@1.9.14) + version: 0.10.0(solid-js@1.9.15) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table @@ -11132,43 +12096,49 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table-devtools solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/cell-spanning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/column-ordering: dependencies: @@ -11176,21 +12146,24 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/column-pinning: dependencies: @@ -11198,21 +12171,24 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/column-pinning-split: dependencies: @@ -11220,21 +12196,24 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/column-pinning-sticky: dependencies: @@ -11242,43 +12221,49 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/column-resizing: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/column-resizing-performant: dependencies: @@ -11286,71 +12271,80 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/column-sizing: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/column-visibility: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/composable-tables: dependencies: '@tanstack/solid-devtools': - specifier: ^0.8.10 - version: 0.8.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.8.12 + version: 0.8.12(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table @@ -11358,18 +12352,21 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table-devtools solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/expanding: dependencies: @@ -11377,71 +12374,80 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/filters: dependencies: '@tanstack/solid-pacer': specifier: ^0.22.0 - version: 0.22.0(solid-js@1.9.14) + version: 0.22.0(solid-js@1.9.15) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/filters-faceted: dependencies: '@tanstack/solid-pacer': specifier: ^0.22.0 - version: 0.22.0(solid-js@1.9.14) + version: 0.22.0(solid-js@1.9.15) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/filters-faceted-bucketed: dependencies: @@ -11449,21 +12455,24 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/filters-fuzzy: dependencies: @@ -11472,26 +12481,29 @@ importers: version: link:../../../packages/match-sorter-utils '@tanstack/solid-pacer': specifier: ^0.22.0 - version: 0.22.0(solid-js@1.9.14) + version: 0.22.0(solid-js@1.9.15) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/grouped-aggregation: dependencies: @@ -11499,21 +12511,24 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/grouping: dependencies: @@ -11521,43 +12536,49 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/header-groups: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/kitchen-sink: dependencies: @@ -11565,8 +12586,8 @@ importers: specifier: workspace:* version: link:../../../packages/match-sorter-utils '@tanstack/solid-devtools': - specifier: ^0.8.10 - version: 0.8.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.8.12 + version: 0.8.12(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table @@ -11574,21 +12595,24 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table-devtools solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/pagination: dependencies: @@ -11596,21 +12620,49 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 + typescript: + specifier: 6.0.3 + version: 6.0.3 + vite: + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite-plugin-solid: + specifier: ^2.11.14 + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + + examples/solid/realtime-trading: + dependencies: + '@tanstack/solid-table': + specifier: workspace:* + version: link:../../../packages/solid-table + '@tanstack/solid-virtual': + specifier: ^3.13.37 + version: 3.13.37(solid-js@1.9.15) + solid-js: + specifier: ^1.9.15 + version: 1.9.15 + devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/row-pinning: dependencies: @@ -11618,27 +12670,30 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/row-selection: dependencies: '@tanstack/solid-devtools': - specifier: ^0.8.10 - version: 0.8.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.8.12 + version: 0.8.12(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table @@ -11646,21 +12701,24 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table-devtools solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/sorting: dependencies: @@ -11668,49 +12726,55 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/spreadsheet: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/solid-hotkeys': specifier: ^0.10.0 - version: 0.10.0(solid-js@1.9.14) + version: 0.10.0(solid-js@1.9.15) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table '@tanstack/solid-virtual': - specifier: ^3.13.36 - version: 3.13.36(solid-js@1.9.14) + specifier: ^3.13.37 + version: 3.13.37(solid-js@1.9.15) solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/sub-components: dependencies: @@ -11718,21 +12782,24 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/virtualized-columns: dependencies: @@ -11740,55 +12807,61 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table '@tanstack/solid-virtual': - specifier: ^3.13.36 - version: 3.13.36(solid-js@1.9.14) + specifier: ^3.13.37 + version: 3.13.37(solid-js@1.9.15) solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/virtualized-infinite-scrolling: dependencies: '@tanstack/solid-query': specifier: ^5.101.4 - version: 5.101.4(solid-js@1.9.14) + version: 5.101.4(solid-js@1.9.15) '@tanstack/solid-store': specifier: ^0.11.1 - version: 0.11.1(solid-js@1.9.14) + version: 0.11.1(solid-js@1.9.15) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table '@tanstack/solid-virtual': - specifier: ^3.13.36 - version: 3.13.36(solid-js@1.9.14) + specifier: ^3.13.37 + version: 3.13.37(solid-js@1.9.15) solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/virtualized-rows: dependencies: @@ -11796,36 +12869,39 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table '@tanstack/solid-virtual': - specifier: ^3.13.36 - version: 3.13.36(solid-js@1.9.14) + specifier: ^3.13.37 + version: 3.13.37(solid-js@1.9.15) solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/with-tanstack-form: dependencies: '@tanstack/solid-devtools': - specifier: ^0.8.10 - version: 0.8.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.8.12 + version: 0.8.12(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/solid-form': specifier: ^1.33.5 - version: 1.33.5(solid-js@1.9.14) + version: 1.33.5(solid-js@1.9.15) '@tanstack/solid-form-devtools': specifier: ^0.2.34 - version: 0.2.34(@types/react@19.2.18)(csstype@3.2.3)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(vue@3.5.41(typescript@6.0.3)) + version: 0.2.34(@types/react@19.2.18)(csstype@3.2.3)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(vue@3.5.41(typescript@6.0.3)) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table @@ -11833,36 +12909,39 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table-devtools solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 zod: specifier: ^4.4.3 version: 4.4.3 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/with-tanstack-query: dependencies: '@tanstack/solid-devtools': - specifier: ^0.8.10 - version: 0.8.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.8.12 + version: 0.8.12(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/solid-query': specifier: ^5.101.4 - version: 5.101.4(solid-js@1.9.14) + version: 5.101.4(solid-js@1.9.15) '@tanstack/solid-query-devtools': specifier: ^5.101.4 - version: 5.101.4(@tanstack/solid-query@5.101.4(solid-js@1.9.14))(solid-js@1.9.14) + version: 5.101.4(@tanstack/solid-query@5.101.4(solid-js@1.9.15))(solid-js@1.9.15) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table @@ -11870,45 +12949,48 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table-devtools solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/solid/with-tanstack-router: dependencies: '@tanstack/solid-devtools': - specifier: ^0.8.10 - version: 0.8.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.8.12 + version: 0.8.12(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/solid-pacer': specifier: ^0.22.0 - version: 0.22.0(solid-js@1.9.14) + version: 0.22.0(solid-js@1.9.15) '@tanstack/solid-pacer-devtools': specifier: 0.7.0 - version: 0.7.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) + version: 0.7.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) '@tanstack/solid-query': specifier: ^5.101.4 - version: 5.101.4(solid-js@1.9.14) + version: 5.101.4(solid-js@1.9.15) '@tanstack/solid-query-devtools': specifier: ^5.101.4 - version: 5.101.4(@tanstack/solid-query@5.101.4(solid-js@1.9.14))(solid-js@1.9.14) + version: 5.101.4(@tanstack/solid-query@5.101.4(solid-js@1.9.15))(solid-js@1.9.15) '@tanstack/solid-router': - specifier: ^1.170.25 - version: 1.170.25(solid-js@1.9.14) + specifier: ^1.170.30 + version: 1.170.30(solid-js@1.9.15) '@tanstack/solid-router-devtools': specifier: ^1.167.1 - version: 1.167.1(@tanstack/router-core@1.171.22)(@tanstack/solid-router@1.170.25(solid-js@1.9.14))(csstype@3.2.3)(solid-js@1.9.14) + version: 1.167.1(@tanstack/router-core@1.171.27)(@tanstack/solid-router@1.170.30(solid-js@1.9.15))(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/solid-table': specifier: workspace:* version: link:../../../packages/solid-table @@ -11916,36 +12998,42 @@ importers: specifier: workspace:* version: link:../../../packages/solid-table-devtools solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@tanstack/router-vite-plugin': - specifier: ^1.167.30 - version: 1.167.30(@tanstack/react-router@1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) + specifier: ^1.167.35 + version: 1.167.35(@tanstack/react-router@1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) examples/svelte/aggregation: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -11953,29 +13041,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/basic-app-table: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -11983,29 +13074,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/basic-create-table: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12013,29 +13107,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/basic-dynamic-columns: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12043,33 +13140,36 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/basic-external-atoms: dependencies: '@tanstack/svelte-store': specifier: ^0.12.1 - version: 0.12.1(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + version: 0.12.1(svelte@5.56.10(@typescript-eslint/types@8.68.0)) devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12077,29 +13177,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/basic-external-state: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12107,29 +13210,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/basic-snippets: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12137,32 +13243,35 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/cell-selection: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-hotkeys': specifier: ^0.10.0 - version: 0.10.0(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + version: 0.10.0(svelte@5.56.10(@typescript-eslint/types@8.68.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12170,29 +13279,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/cell-spanning: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12200,29 +13312,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/column-ordering: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12230,29 +13345,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/column-pinning: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12260,29 +13378,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/column-pinning-split: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12290,29 +13411,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/column-pinning-sticky: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12320,29 +13444,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/column-resizing: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12350,29 +13477,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/column-resizing-performant: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12380,29 +13510,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/column-sizing: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12410,29 +13543,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/column-visibility: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12440,29 +13576,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/composable-tables: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12470,29 +13609,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/expanding: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12500,29 +13642,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/filtering: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12530,29 +13675,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/filters-faceted: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12560,29 +13708,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/filters-faceted-bucketed: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12590,29 +13741,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/filters-fuzzy: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -12623,29 +13777,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/grouped-aggregation: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12653,29 +13810,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/grouping: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12683,29 +13843,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/header-groups: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12713,29 +13876,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/kitchen-sink: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -12746,23 +13912,23 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/kitchen-sink-shadcn: devDependencies: '@dnd-kit-svelte/svelte': specifier: ^0.1.6 - version: 0.1.6(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + version: 0.1.6(svelte@5.56.10(@typescript-eslint/types@8.68.0)) '@dnd-kit/abstract': specifier: ^0.2.3 version: 0.2.4 @@ -12770,23 +13936,26 @@ importers: specifier: ^0.2.3 version: 0.2.4 '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@internationalized/date': specifier: 3.12.3 version: 3.12.3 '@lucide/svelte': - specifier: ^1.31.0 - version: 1.31.0(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + specifier: ^1.34.0 + version: 1.34.0(svelte@5.56.10(@typescript-eslint/types@8.68.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tailwindcss/vite': specifier: ^4.3.3 - version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 4.3.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -12803,17 +13972,17 @@ importers: specifier: ^26.2.0 version: 26.2.0 bits-ui: - specifier: ^2.18.1 - version: 2.18.1(@internationalized/date@3.12.3)(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + specifier: ^2.19.0 + version: 2.19.0(@internationalized/date@3.12.3)(svelte@5.56.10(@typescript-eslint/types@8.68.0)) clsx: specifier: ^2.1.1 version: 2.1.1 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) tailwind-merge: specifier: ^3.6.0 version: 3.6.0 @@ -12830,26 +13999,29 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/lib-shadcn: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@lucide/svelte': - specifier: ^1.31.0 - version: 1.31.0(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + specifier: ^1.34.0 + version: 1.34.0(svelte@5.56.10(@typescript-eslint/types@8.68.0)) + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tailwindcss/vite': specifier: ^4.3.3 - version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 4.3.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/pacer': specifier: ^0.22.0 version: 0.22.0 @@ -12863,17 +14035,17 @@ importers: specifier: ^26.2.0 version: 26.2.0 bits-ui: - specifier: ^2.18.1 - version: 2.18.1(@internationalized/date@3.12.3)(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + specifier: ^2.19.0 + version: 2.19.0(@internationalized/date@3.12.3)(svelte@5.56.10(@typescript-eslint/types@8.68.0)) clsx: specifier: ^2.1.1 version: 2.1.1 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) tailwind-merge: specifier: ^3.6.0 version: 3.6.0 @@ -12890,20 +14062,23 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/pagination: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12911,29 +14086,69 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) + svelte-check: + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) + typescript: + specifier: 6.0.3 + version: 6.0.3 + vite: + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + + examples/svelte/realtime-trading: + dependencies: + '@tanstack/store': + specifier: ^0.11.1 + version: 0.11.1 + '@tanstack/svelte-store': + specifier: ^0.12.1 + version: 0.12.1(svelte@5.56.10(@typescript-eslint/types@8.68.0)) + '@tanstack/svelte-table': + specifier: workspace:* + version: link:../../../packages/svelte-table + '@tanstack/svelte-virtual': + specifier: ^3.13.36 + version: 3.13.36(svelte@5.56.10(@typescript-eslint/types@8.68.0)) + svelte: + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) + devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 + '@sveltejs/vite-plugin-svelte': + specifier: ^7.3.0 + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@tsconfig/svelte': + specifier: ^5.0.8 + version: 5.0.8 svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/row-pinning: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12941,29 +14156,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/row-selection: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -12971,29 +14189,32 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/sorting: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -13001,65 +14222,71 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/spreadsheet: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-hotkeys': specifier: ^0.10.0 - version: 0.10.0(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + version: 0.10.0(svelte@5.56.10(@typescript-eslint/types@8.68.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table '@tanstack/svelte-virtual': - specifier: ^3.13.35 - version: 3.13.35(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + specifier: ^3.13.36 + version: 3.13.36(svelte@5.56.10(@typescript-eslint/types@8.68.0)) '@tsconfig/svelte': specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/sub-components: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -13067,119 +14294,128 @@ importers: specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/virtualized-columns: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table '@tanstack/svelte-virtual': - specifier: ^3.13.35 - version: 3.13.35(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + specifier: ^3.13.36 + version: 3.13.36(svelte@5.56.10(@typescript-eslint/types@8.68.0)) '@tsconfig/svelte': specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/virtualized-infinite-scrolling: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-query': specifier: ^6.1.38 - version: 6.1.38(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + version: 6.1.38(svelte@5.56.10(@typescript-eslint/types@8.68.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table '@tanstack/svelte-virtual': - specifier: ^3.13.35 - version: 3.13.35(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + specifier: ^3.13.36 + version: 3.13.36(svelte@5.56.10(@typescript-eslint/types@8.68.0)) '@tsconfig/svelte': specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/virtualized-rows: devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table '@tanstack/svelte-virtual': - specifier: ^3.13.35 - version: 3.13.35(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + specifier: ^3.13.36 + version: 3.13.36(svelte@5.56.10(@typescript-eslint/types@8.68.0)) '@tsconfig/svelte': specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/with-tanstack-form: dependencies: @@ -13187,11 +14423,11 @@ importers: specifier: ^1.33.5 version: 1.33.5 '@tanstack/svelte-devtools': - specifier: ^0.1.3 - version: 0.1.3(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + specifier: ^0.1.6 + version: 0.1.6(csstype@3.2.3)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0)) '@tanstack/svelte-form': specifier: ^1.33.5 - version: 1.33.5(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + version: 1.33.5(svelte@5.56.10(@typescript-eslint/types@8.68.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -13203,29 +14439,32 @@ importers: version: 4.4.3 devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tsconfig/svelte': specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/svelte/with-tanstack-query: dependencies: @@ -13233,14 +14472,14 @@ importers: specifier: ^5.101.4 version: 5.101.4 '@tanstack/svelte-devtools': - specifier: ^0.1.3 - version: 0.1.3(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + specifier: ^0.1.6 + version: 0.1.6(csstype@3.2.3)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0)) '@tanstack/svelte-query': specifier: ^6.1.38 - version: 6.1.38(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + version: 6.1.38(svelte@5.56.10(@typescript-eslint/types@8.68.0)) '@tanstack/svelte-query-devtools': specifier: ^6.1.38 - version: 6.1.38(@tanstack/svelte-query@6.1.38(svelte@5.56.8(@typescript-eslint/types@8.67.0)))(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + version: 6.1.38(@tanstack/svelte-query@6.1.38(svelte@5.56.10(@typescript-eslint/types@8.68.0)))(svelte@5.56.10(@typescript-eslint/types@8.68.0)) '@tanstack/svelte-table': specifier: workspace:* version: link:../../../packages/svelte-table @@ -13249,29 +14488,32 @@ importers: version: link:../../../packages/table-devtools devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tsconfig/svelte': specifier: ^5.0.8 version: 5.0.8 svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/vanilla/aggregation: dependencies: @@ -13280,11 +14522,14 @@ importers: version: link:../../../packages/table-core devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/node': specifier: ^26.2.0 version: 26.2.0 @@ -13292,8 +14537,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/vanilla/basic: dependencies: @@ -13302,11 +14547,14 @@ importers: version: link:../../../packages/table-core devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/node': specifier: ^26.2.0 version: 26.2.0 @@ -13314,8 +14562,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/vanilla/pagination: dependencies: @@ -13324,11 +14572,14 @@ importers: version: link:../../../packages/table-core devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/node': specifier: ^26.2.0 version: 26.2.0 @@ -13336,8 +14587,8 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/vanilla/sorting: dependencies: @@ -13346,11 +14597,14 @@ importers: version: link:../../../packages/table-core devDependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@rollup/plugin-replace': specifier: ^6.0.3 - version: 6.0.3(rollup@4.62.4) + version: 6.0.3(rollup@4.63.0) '@types/node': specifier: ^26.2.0 version: 26.2.0 @@ -13358,14 +14612,14 @@ importers: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) examples/vue/aggregation: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -13373,33 +14627,36 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/basic-dynamic-columns: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-devtools': - specifier: ^0.2.24 - version: 0.2.24(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.2.26 + version: 0.2.26(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -13410,33 +14667,36 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/basic-external-atoms: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-devtools': - specifier: ^0.2.24 - version: 0.2.24(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.2.26 + version: 0.2.26(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/vue-store': specifier: ^0.11.1 version: 0.11.1(vue@3.5.41(typescript@6.0.3)) @@ -13450,33 +14710,36 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/basic-external-state: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-devtools': - specifier: ^0.2.24 - version: 0.2.24(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.2.26 + version: 0.2.26(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -13487,30 +14750,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/basic-use-app-table: dependencies: '@tanstack/vue-devtools': - specifier: ^0.2.24 - version: 0.2.24(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.2.26 + version: 0.2.26(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -13521,30 +14787,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/basic-use-table: dependencies: '@tanstack/vue-devtools': - specifier: ^0.2.24 - version: 0.2.24(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.2.26 + version: 0.2.26(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -13555,33 +14824,36 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/cell-selection: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-devtools': - specifier: ^0.2.24 - version: 0.2.24(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.2.26 + version: 0.2.26(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/vue-hotkeys': specifier: ^0.10.0 version: 0.10.0(vue@3.5.41(typescript@6.0.3)) @@ -13595,30 +14867,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/cell-spanning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -13626,30 +14901,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/column-ordering: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -13657,30 +14935,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/column-pinning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -13688,30 +14969,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/column-pinning-split: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -13719,30 +15003,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/column-pinning-sticky: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -13750,30 +15037,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/column-resizing: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -13781,30 +15071,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/column-resizing-performant: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -13812,30 +15105,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/column-sizing: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -13843,30 +15139,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/column-visibility: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -13874,30 +15173,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/composable-tables: dependencies: '@tanstack/vue-devtools': - specifier: ^0.2.24 - version: 0.2.24(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.2.26 + version: 0.2.26(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/vue-store': specifier: ^0.11.1 version: 0.11.1(vue@3.5.41(typescript@6.0.3)) @@ -13911,30 +15213,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/expanding: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -13942,30 +15247,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/filters: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -13973,30 +15281,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/filters-faceted: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -14004,30 +15315,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/filters-faceted-bucketed: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -14035,30 +15349,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/filters-fuzzy: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -14069,30 +15386,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/grouped-aggregation: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -14100,30 +15420,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/grouping: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -14131,30 +15454,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/header-groups: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -14162,36 +15488,39 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/kitchen-sink: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils '@tanstack/vue-devtools': - specifier: ^0.2.24 - version: 0.2.24(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.2.26 + version: 0.2.26(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -14202,39 +15531,42 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/kitchen-sink-shadcn: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@internationalized/date': specifier: 3.12.3 version: 3.12.3 '@lucide/vue': - specifier: ^1.31.0 - version: 1.31.0(vue@3.5.41(typescript@6.0.3)) + specifier: ^1.34.0 + version: 1.34.0(vue@3.5.41(typescript@6.0.3)) '@tailwindcss/vite': specifier: ^4.3.3 - version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 4.3.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -14242,8 +15574,8 @@ importers: specifier: ^0.22.0 version: 0.22.0 '@tanstack/vue-devtools': - specifier: ^0.2.24 - version: 0.2.24(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.2.26 + version: 0.2.26(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -14263,8 +15595,8 @@ importers: specifier: ^0.0.2 version: 0.0.2(vue@3.5.41(typescript@6.0.3)) reka-ui: - specifier: ^2.10.3 - version: 2.10.3(vue@3.5.41(typescript@6.0.3)) + specifier: ^2.10.4 + version: 2.10.4(vue@3.5.41(typescript@6.0.3)) tailwind-merge: specifier: ^3.6.0 version: 3.6.0 @@ -14278,36 +15610,39 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/lib-shadcn: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@lucide/vue': - specifier: ^1.31.0 - version: 1.31.0(vue@3.5.41(typescript@6.0.3)) + specifier: ^1.34.0 + version: 1.34.0(vue@3.5.41(typescript@6.0.3)) '@tailwindcss/vite': specifier: ^4.3.3 - version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 4.3.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/pacer': specifier: ^0.22.0 version: 0.22.0 @@ -14324,8 +15659,8 @@ importers: specifier: ^2.1.1 version: 2.1.1 reka-ui: - specifier: ^2.10.3 - version: 2.10.3(vue@3.5.41(typescript@6.0.3)) + specifier: ^2.10.4 + version: 2.10.4(vue@3.5.41(typescript@6.0.3)) tailwind-merge: specifier: ^3.6.0 version: 3.6.0 @@ -14339,30 +15674,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/pagination: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -14370,30 +15708,67 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) + + examples/vue/realtime-trading: + dependencies: + '@tanstack/vue-table': + specifier: workspace:* + version: link:../../../packages/vue-table + '@tanstack/vue-virtual': + specifier: ^3.13.36 + version: 3.13.36(vue@3.5.41(typescript@6.0.3)) + vue: + specifier: ^3.5.41 + version: 3.5.41(typescript@6.0.3) + devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 + '@types/node': + specifier: ^26.2.0 + version: 26.2.0 + '@vitejs/plugin-vue': + specifier: ^6.0.8 + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + '@vitejs/plugin-vue-jsx': + specifier: ^5.1.6 + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + typescript: + specifier: 6.0.3 + version: 6.0.3 + vite: + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vue-tsc: + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/row-pinning: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -14401,33 +15776,36 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/row-selection: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-devtools': - specifier: ^0.2.24 - version: 0.2.24(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.2.26 + version: 0.2.26(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -14438,30 +15816,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/sorting: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -14469,30 +15850,33 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/sub-components: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table @@ -14500,64 +15884,70 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/virtualized-columns: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table '@tanstack/vue-virtual': - specifier: ^3.13.35 - version: 3.13.35(vue@3.5.41(typescript@6.0.3)) + specifier: ^3.13.36 + version: 3.13.36(vue@3.5.41(typescript@6.0.3)) vue: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/virtualized-infinite-scrolling: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils @@ -14571,73 +15961,79 @@ importers: specifier: workspace:* version: link:../../../packages/vue-table '@tanstack/vue-virtual': - specifier: ^3.13.35 - version: 3.13.35(vue@3.5.41(typescript@6.0.3)) + specifier: ^3.13.36 + version: 3.13.36(vue@3.5.41(typescript@6.0.3)) vue: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/virtualized-rows: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-table': specifier: workspace:* version: link:../../../packages/vue-table '@tanstack/vue-virtual': - specifier: ^3.13.35 - version: 3.13.35(vue@3.5.41(typescript@6.0.3)) + specifier: ^3.13.36 + version: 3.13.36(vue@3.5.41(typescript@6.0.3)) vue: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/with-tanstack-form: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/vue-devtools': - specifier: ^0.2.24 - version: 0.2.24(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.2.26 + version: 0.2.26(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/vue-form': specifier: ^1.33.5 version: 1.33.5(vue@3.5.41(typescript@6.0.3)) @@ -14654,36 +16050,39 @@ importers: specifier: ^4.4.3 version: 4.4.3 devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) examples/vue/with-tanstack-query: dependencies: '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 '@tanstack/match-sorter-utils': specifier: workspace:* version: link:../../../packages/match-sorter-utils '@tanstack/vue-devtools': - specifier: ^0.2.24 - version: 0.2.24(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.2.26 + version: 0.2.26(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/vue-query': specifier: ^5.101.4 version: 5.101.4(vue@3.5.41(typescript@6.0.3)) @@ -14700,24 +16099,27 @@ importers: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) devDependencies: + '@rolldown/binding-wasm32-wasi': + specifier: ~1.2.4 + version: 1.2.6 '@types/node': specifier: ^26.2.0 version: 26.2.0 '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue-jsx': specifier: ^5.1.6 - version: 5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 vite: - specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue-tsc: - specifier: ^3.3.9 - version: 3.3.9(typescript@6.0.3) + specifier: ^3.3.11 + version: 3.3.11(typescript@6.0.3) packages/alpine-table: dependencies: @@ -14735,8 +16137,8 @@ importers: specifier: ^3.13.11 version: 3.13.11 alpinejs: - specifier: ^3.16.1 - version: 3.16.1 + specifier: ^3.16.3 + version: 3.16.3 packages/angular-table: dependencies: @@ -14751,11 +16153,11 @@ importers: version: 2.8.1 devDependencies: '@analogjs/vite-plugin-angular': - specifier: ^2.7.0 - version: 2.7.0(@angular-devkit/build-angular@22.1.2(d03b5bb02029a616bfe59858a9b5776f))(@angular/build@22.1.2(0b302439204a1b184ed0f1b31fd67e96))(@angular/compiler@22.1.1)(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^2.7.1 + version: 2.7.1(@angular-devkit/build-angular@22.1.6(2828c779ce3b028972f8555a72f25fb0))(@angular/build@22.1.6(024014ee1152fb75104fa34d053c7f64))(@angular/compiler@22.1.1)(@emnapi/core@2.0.0-alpha.4)(@emnapi/runtime@2.0.0-alpha.4)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@analogjs/vitest-angular': - specifier: ^2.7.0 - version: 2.7.0(@analogjs/vite-plugin-angular@2.7.0(@angular-devkit/build-angular@22.1.2(d03b5bb02029a616bfe59858a9b5776f))(@angular/build@22.1.2(0b302439204a1b184ed0f1b31fd67e96))(@angular/compiler@22.1.1)(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(@angular-devkit/architect@0.2201.2(chokidar@5.0.0))(@angular-devkit/schematics@22.1.2(chokidar@5.0.0))(vitest@4.1.10) + specifier: ^2.7.1 + version: 2.7.1(@analogjs/vite-plugin-angular@2.7.1(@angular-devkit/build-angular@22.1.6(2828c779ce3b028972f8555a72f25fb0))(@angular/build@22.1.6(024014ee1152fb75104fa34d053c7f64))(@angular/compiler@22.1.1)(@emnapi/core@2.0.0-alpha.4)(@emnapi/runtime@2.0.0-alpha.4)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(@angular-devkit/architect@0.2201.6(chokidar@5.0.0))(@angular-devkit/schematics@22.1.6(chokidar@5.0.0))(vitest@4.1.11) '@angular/compiler': specifier: ^22.1.1 version: 22.1.1 @@ -14775,8 +16177,8 @@ importers: packages/angular-table-devtools: dependencies: '@tanstack/devtools-utils': - specifier: ^0.6.0 - version: 0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) + specifier: ^0.7.0 + version: 0.7.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) '@tanstack/table-core': specifier: workspace:* version: link:../table-core @@ -14823,7 +16225,7 @@ importers: version: 5.4.3(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@embroider/addon-dev': specifier: ^8.3.1 - version: 8.3.1(@glint/template@1.8.0)(rollup@4.62.4)(supports-color@8.1.1) + version: 8.3.1(@glint/template@1.8.0)(rollup@4.63.0)(supports-color@8.1.1) '@embroider/core': specifier: 4.6.3 version: 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) @@ -14831,26 +16233,26 @@ importers: specifier: 1.20.6 version: 1.20.6(@babel/core@7.29.7(supports-color@8.1.1))(@glint/template@1.8.0)(supports-color@8.1.1) '@embroider/vite': - specifier: ^1.7.9 - version: 1.7.9(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(@glint/template@1.8.0)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^1.7.10 + version: 1.7.10(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(@glint/template@1.8.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)) + version: 10.0.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)) '@glimmer/component': specifier: 2.1.1 version: 2.1.1(supports-color@8.1.1) '@glint/ember-tsc': - specifier: 1.10.0 - version: 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: 1.11.0 + version: 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@glint/template': specifier: 1.8.0 version: 1.8.0 '@glint/tsserver-plugin': - specifier: 2.7.0 - version: 2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) + specifier: 2.7.3 + version: 2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1) '@rollup/plugin-babel': specifier: 7.1.0 - version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + version: 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) '@types/qunit': specifier: ^2.19.14 version: 2.19.14 @@ -14868,13 +16270,13 @@ importers: version: 0.1.1(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)) + version: 10.1.8(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)) eslint-plugin-ember: specifier: ^13.5.0 - version: 13.5.0(@babel/eslint-parser@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)))(@typescript-eslint/parser@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(typescript@6.0.3) + version: 13.5.0(@babel/eslint-parser@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)))(@typescript-eslint/parser@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(typescript@6.0.3) eslint-plugin-import-x: specifier: ^4.17.1 - version: 4.17.1(@typescript-eslint/utils@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@8.1.1))(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1) + version: 4.17.1(@typescript-eslint/utils@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@8.1.1))(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1) globals: specifier: ^17.11.0 version: 17.11.0 @@ -14885,14 +16287,14 @@ importers: specifier: ^3.6.0 version: 3.6.0 rollup: - specifier: ^4.62.4 - version: 4.62.4 + specifier: ^4.63.0 + version: 4.63.0 testem: specifier: ^3.20.1 version: 3.20.1(@babel/core@7.29.7(supports-color@8.1.1))(debug@4.4.3(supports-color@8.1.1))(handlebars@4.7.9)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@8.1.1)(underscore@1.13.8) typescript-eslint: - specifier: ^8.67.0 - version: 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: ^8.68.0 + version: 8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) packages/lit-table: dependencies: @@ -14923,17 +16325,17 @@ importers: dependencies: '@tanstack/octane-store': specifier: ^0.12.2 - version: 0.12.2(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))) + version: 0.12.2(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))) '@tanstack/table-core': specifier: workspace:* version: link:../table-core devDependencies: '@tsrx/typescript-plugin': specifier: ^0.3.118 - version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) + version: 0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3) octane: specifier: 0.1.36 - version: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) typescript: specifier: 6.0.3 version: 6.0.3 @@ -14949,7 +16351,7 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@testing-library/preact': specifier: ^3.2.4 version: 3.2.4(preact@10.29.8) @@ -14963,15 +16365,15 @@ importers: packages/preact-table-devtools: dependencies: '@tanstack/devtools-utils': - specifier: ^0.6.0 - version: 0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) + specifier: ^0.7.0 + version: 0.7.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) '@tanstack/table-devtools': specifier: workspace:* version: link:../table-devtools devDependencies: '@preact/preset-vite': specifier: ^2.10.6 - version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tanstack/table-core': specifier: workspace:* version: link:../table-core @@ -14989,26 +16391,26 @@ importers: version: link:../table-core devDependencies: '@eslint-react/eslint-plugin': - specifier: ^5.18.1 - version: 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: ^5.18.6 + version: 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@testing-library/react': specifier: ^16.3.2 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@types/react': specifier: ^19.2.18 version: 19.2.18 '@types/react-dom': - specifier: ^19.2.4 - version: 19.2.4(@types/react@19.2.18) + specifier: ^19.2.5 + version: 19.2.5(@types/react@19.2.18) '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@7.29.7(supports-color@8.1.1))(@babel/plugin-transform-runtime@8.0.1(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@7.29.7(supports-color@8.1.1))(@babel/plugin-transform-runtime@8.0.1(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/runtime@8.0.0)(rolldown@1.2.6)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) eslint-plugin-react-compiler: specifier: 19.1.0-rc.2 - version: 19.1.0-rc.2(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1) + version: 19.1.0-rc.2(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1) eslint-plugin-react-hooks: specifier: ^7.1.1 - version: 7.1.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1) + version: 7.1.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1) react: specifier: ^19.2.8 version: 19.2.8 @@ -15019,11 +16421,11 @@ importers: packages/react-table-devtools: dependencies: '@tanstack/devtools-utils': - specifier: ^0.6.0 - version: 0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) + specifier: ^0.7.0 + version: 0.7.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) '@tanstack/react-devtools': specifier: '>=0.10.0' - version: 0.10.5(@types/react-dom@19.2.3(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.6(react@19.2.8))(react@19.2.8)(solid-js@1.9.14) + version: 0.10.5(@types/react-dom@19.2.3(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.6(react@19.2.8))(react@19.2.8)(solid-js@1.9.15) '@tanstack/table-devtools': specifier: workspace:* version: link:../table-devtools @@ -15035,8 +16437,8 @@ importers: version: 19.2.6(react@19.2.8) devDependencies: '@eslint-react/eslint-plugin': - specifier: ^5.18.1 - version: 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + specifier: ^5.18.6 + version: 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) '@tanstack/table-core': specifier: workspace:* version: link:../table-core @@ -15044,14 +16446,14 @@ importers: specifier: ^19.2.18 version: 19.2.18 '@vitejs/plugin-react': - specifier: ^6.0.5 - version: 6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + specifier: ^6.1.0 + version: 6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.6)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) eslint-plugin-react-compiler: specifier: 19.1.0-rc.2 - version: 19.1.0-rc.2(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1) + version: 19.1.0-rc.2(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1) eslint-plugin-react-hooks: specifier: ^7.1.1 - version: 7.1.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1) + version: 7.1.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1) react: specifier: ^19.2.8 version: 19.2.8 @@ -15067,19 +16469,19 @@ importers: devDependencies: '@solidjs/testing-library': specifier: ^0.8.10 - version: 0.8.10(solid-js@1.9.14) + version: 0.8.10(solid-js@1.9.15) solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) packages/solid-table-devtools: dependencies: '@tanstack/devtools-utils': - specifier: ^0.6.0 - version: 0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) + specifier: ^0.7.0 + version: 0.7.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) '@tanstack/table-devtools': specifier: workspace:* version: link:../table-devtools @@ -15088,39 +16490,39 @@ importers: specifier: workspace:* version: link:../table-core solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) packages/svelte-table: dependencies: '@tanstack/svelte-store': specifier: ^0.12.1 - version: 0.12.1(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + version: 0.12.1(svelte@5.56.10(@typescript-eslint/types@8.68.0)) '@tanstack/table-core': specifier: workspace:* version: link:../table-core devDependencies: '@sveltejs/package': specifier: ^2.5.8 - version: 2.5.8(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + version: 2.5.8(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) '@sveltejs/vite-plugin-svelte': specifier: ^7.3.0 - version: 7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0)) + version: 7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@testing-library/svelte': specifier: ^5.4.2 - version: 5.4.2(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0))(vitest@4.1.10) + version: 5.4.2(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vitest@4.1.11) eslint-plugin-svelte: - specifier: ^3.22.0 - version: 3.22.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + specifier: ^3.23.0 + version: 3.23.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(svelte@5.56.10(@typescript-eslint/types@8.68.0)) svelte: - specifier: ^5.56.8 - version: 5.56.8(@typescript-eslint/types@8.67.0) + specifier: ^5.56.10 + version: 5.56.10(@typescript-eslint/types@8.68.0) svelte-check: - specifier: ^4.7.4 - version: 4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + specifier: ^4.7.6 + version: 4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) packages/table-core: dependencies: @@ -15131,30 +16533,30 @@ importers: packages/table-devtools: dependencies: '@tanstack/devtools-ui': - specifier: ^0.7.0 - version: 0.7.0(csstype@3.2.3)(solid-js@1.9.14) + specifier: ^0.7.1 + version: 0.7.1(csstype@3.2.3)(solid-js@1.9.15) '@tanstack/devtools-utils': - specifier: ^0.6.0 - version: 0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) + specifier: ^0.7.0 + version: 0.7.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) '@tanstack/solid-store': specifier: ^0.11.1 - version: 0.11.1(solid-js@1.9.14) + version: 0.11.1(solid-js@1.9.15) goober: specifier: ^2.1.19 version: 2.1.19(csstype@3.2.3) solid-js: - specifier: ^1.9.14 - version: 1.9.14 + specifier: ^1.9.15 + version: 1.9.15 devDependencies: '@tanstack/table-core': specifier: workspace:* version: link:../table-core eslint-plugin-solid: specifier: ^0.14.5 - version: 0.14.5(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + version: 0.14.5(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) vite-plugin-solid: specifier: ^2.11.14 - version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + version: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) packages/vue-table: dependencies: @@ -15170,10 +16572,10 @@ importers: version: 8.1.0(@vue/compiler-dom@3.5.41)(@vue/compiler-sfc@3.5.41)(@vue/server-renderer@3.5.41)(vue@3.5.41(typescript@6.0.3)) '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) eslint-plugin-vue: specifier: ^10.10.0 - version: 10.10.0(@stylistic/eslint-plugin@5.10.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)))(@typescript-eslint/parser@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(vue-eslint-parser@10.4.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)) + version: 10.10.0(@stylistic/eslint-plugin@5.10.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)))(@typescript-eslint/parser@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(vue-eslint-parser@10.4.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)) vue: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) @@ -15181,8 +16583,8 @@ importers: packages/vue-table-devtools: dependencies: '@tanstack/devtools-utils': - specifier: ^0.6.0 - version: 0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) + specifier: ^0.7.0 + version: 0.7.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) '@tanstack/table-devtools': specifier: workspace:* version: link:../table-devtools @@ -15192,7 +16594,7 @@ importers: version: link:../table-core '@vitejs/plugin-vue': specifier: ^6.0.8 - version: 6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) vue: specifier: ^3.5.41 version: 3.5.41(typescript@6.0.3) @@ -15230,8 +16632,8 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@analogjs/vite-plugin-angular@2.7.0': - resolution: {integrity: sha512-KhFC9wiIxD4vi0p3Iyd6tPXyvV9J8GF1eLTkANtBcUbuLkdCRFtbqp/U08cDt+Ae+mVOiSZliBO+JSr66YCqFA==} + '@analogjs/vite-plugin-angular@2.7.1': + resolution: {integrity: sha512-avRNF3ryDkWqBNege4kIuEalGYI7XnmFJXf/IT/hDjSeHObi+NNXLYfYBcZifjOYuChTRcr7FhR2Ogu4EToiBg==} peerDependencies: '@angular-devkit/build-angular': ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0 '@angular/build': ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0 @@ -15247,8 +16649,8 @@ packages: vite: optional: true - '@analogjs/vitest-angular@2.7.0': - resolution: {integrity: sha512-39qs+o5zGJ0xtzubNpy89t2/kwnYTl03US/z7YD1vss2Tb//R38ymjaLrUtirDW/X9nk5NdFGi8nasbctSDOrw==} + '@analogjs/vitest-angular@2.7.1': + resolution: {integrity: sha512-Ra+XrsjlA5NvG0u94dxOE5ZE1gRVA/HMauYXiWEFTddeltJoI8bJ4Tc0du62iZo2AdJxUADaei8Liu0nm0GRBQ==} peerDependencies: '@analogjs/vite-plugin-angular': '*' '@angular-devkit/architect': '>=0.1700.0 < 0.2300.0 || >=0.2200.0 < 0.2300.0' @@ -15259,13 +16661,13 @@ packages: zone.js: optional: true - '@angular-devkit/architect@0.2201.2': - resolution: {integrity: sha512-RRG3JA3hPH0ypbDIyquZt9DDTP5pOMPgqQ/iLSkok1MZdKiOgpk6FGfXCa1ei72SwlX7lnJdq94d6WWdqpbyKg==} + '@angular-devkit/architect@0.2201.6': + resolution: {integrity: sha512-oGQEdof2/1bZk58PN9dvpGi8pvtbgE5vkP1xRtCqN8dSVxwre1l0pKynOj/Uge1KxjCvs4c1QrQu0vsAnY0vpg==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} hasBin: true - '@angular-devkit/build-angular@22.1.2': - resolution: {integrity: sha512-+jngKxBnagJcfrFcNXHfb0bmKWMmxTPEba0T9KPXmtgv+jk6AUlVhWfcU3fpBKrRZs9ChxyVWMDnI56FNItpvA==} + '@angular-devkit/build-angular@22.1.6': + resolution: {integrity: sha512-4UIWd8tXCnZuM9E9uRDPmZmD5TM6ln+d/J2wktGA8Lqq7cUaI2q1YMphrCTEN1NbGDoqZWN4BMk2uf2hB4Yi8w==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} deprecated: Angular's Webpack support is deprecated. Use the esbuild and Vite-based "@angular/build" package instead. peerDependencies: @@ -15275,7 +16677,7 @@ packages: '@angular/platform-browser': ^22.0.0 '@angular/platform-server': ^22.0.0 '@angular/service-worker': ^22.0.0 - '@angular/ssr': ^22.1.2 + '@angular/ssr': ^22.1.6 browser-sync: ^3.0.2 karma: ^6.3.0 ng-packagr: ^22.0.0 @@ -15303,15 +16705,15 @@ packages: tailwindcss: optional: true - '@angular-devkit/build-webpack@0.2201.2': - resolution: {integrity: sha512-mRt2JsrQVBI/CKoD6yxFJRsTb9Xv20kmJDjzuAiuxAbwXLjXDgZWqqibPjt3bd78IHDntE5+n5ZNjsj0vR9lJA==} + '@angular-devkit/build-webpack@0.2201.6': + resolution: {integrity: sha512-RgmvgY+7AJVd0RDS8SDJ8SlEUPwaK3CWhxkBZ2q6MxxWcpnPDDBFcy0mzEArY7+PyoppN0hIO8ZOEg2sUxK5Wg==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: webpack: ^5.30.0 webpack-dev-server: ^5.0.2 - '@angular-devkit/core@22.1.2': - resolution: {integrity: sha512-tF1oEE7KPs8I08HJQmH5e4GkLUB3+MXXy8t6gMJULaLFxZYP9K1oXRFLappMpdm9OIbEXOChk23hrho0By9aYg==} + '@angular-devkit/core@22.1.6': + resolution: {integrity: sha512-KLBsZoc2RhOy0xSdeYcLoSOqV/fBP3feBmhY9o12ry2IuyW/17sCmWr6XbIfTIYQN6M98Y1ewmwVNFsvV5b0gA==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: chokidar: ^5.0.0 @@ -15319,8 +16721,8 @@ packages: chokidar: optional: true - '@angular-devkit/schematics@22.1.2': - resolution: {integrity: sha512-Lw6NvW5rfMUl/2dsuWY8l6wlfWCuYBzCYSSqqliLPDco0doGzBliHwY9uxuzuUKZgOl5TvuVyvEo0t3o4Jj4GA==} + '@angular-devkit/schematics@22.1.6': + resolution: {integrity: sha512-IbDO9KbQyQm20uinsfT8d9ZtQw41/WVutI/65mAw39WZfN8Ky+MOgOUJCGLiSccMprvZ9YdodBTnN9bLH149Ag==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} '@angular/animations@22.1.1': @@ -15330,8 +16732,8 @@ packages: peerDependencies: '@angular/core': 22.1.1 - '@angular/build@22.1.2': - resolution: {integrity: sha512-DE/3o17JTel4EBt2BA4DqJYeBBuz5Ef/kf1jL9YZTyJu4SrLr/HI79K14jFr0VRIxzcqG92FdIzfLDxbOesQsg==} + '@angular/build@22.1.6': + resolution: {integrity: sha512-J7JBd3hDAV4dlGNMavDC0KjtvbDd4KOddaom1inwkq92tYnD1ljmhDDigAsUBnRvQhJ82cvagD8zi0s9Ki4rTQ==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: '@angular/compiler': ^22.0.0 @@ -15341,7 +16743,7 @@ packages: '@angular/platform-browser': ^22.0.0 '@angular/platform-server': ^22.0.0 '@angular/service-worker': ^22.0.0 - '@angular/ssr': ^22.1.2 + '@angular/ssr': ^22.1.6 istanbul-lib-instrument: ^6.0.0 karma: ^6.4.0 less: ^4.2.0 @@ -15382,16 +16784,16 @@ packages: vitest: optional: true - '@angular/cdk@22.1.0': - resolution: {integrity: sha512-yfQug47CZ+51mHy0ZLWzi6F/YHfsAF2Z7Jxo3JLM7Aj3Er47hHB8VnrNERwK5tBLs0bE5DoEIm59ga/MI3fVGg==} + '@angular/cdk@22.1.4': + resolution: {integrity: sha512-//KICh/rxeLbYLgNj8HawaliVAPNlSV0aRmki45Tf/YhoXVhzon9DfFqCs5u1cLvmMkMTHdFm5ghGTB8SUv3DA==} peerDependencies: '@angular/common': ^22.0.0 || ^23.0.0 '@angular/core': ^22.0.0 || ^23.0.0 '@angular/platform-browser': ^22.0.0 || ^23.0.0 rxjs: ^6.5.3 || ^7.4.0 - '@angular/cli@22.1.2': - resolution: {integrity: sha512-gzB+iuZzB507DAkZb9s5+Jw8QRzOBolUhHEuAKH74xF6oWlEP5JdexfTgti45SjXaKKqeYpODJFnUmSQQJRhxA==} + '@angular/cli@22.1.6': + resolution: {integrity: sha512-HT3OzYkSpCyXMTgD5G1tsS7vkrY8cYJ/JgSjRjrpwOAooSMtKF1hv7BgBcn79sKg4eaiPLrDpQLXP93vHxgSFg==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} hasBin: true @@ -15479,8 +16881,8 @@ packages: '@angular/platform-browser': 22.1.1 rxjs: ^6.5.3 || ^7.4.0 - '@angular/ssr@22.1.2': - resolution: {integrity: sha512-cuTwQHq9f6vrEz0mNOzJxJurAE6mb+os+m1zGPFVIVnRMK3bJhAhHWYRkInOBvsfC1K0cpHtGR/97ctvmiqP0A==} + '@angular/ssr@22.1.6': + resolution: {integrity: sha512-MvSaCg2Kren50Ei8o98bDG4555aNAQdeP+PfamOyUPWx3LBdoW5LEhnOq7yxWDcuzyXIs/k0DjQnbojPH/75Uw==} peerDependencies: '@angular/common': ^22.0.0 '@angular/core': ^22.0.0 @@ -16596,16 +17998,6 @@ packages: date-fns: optional: true - '@base-ui/utils@0.3.1': - resolution: {integrity: sha512-gFFiltORVmW/N6IILTGxizP3PBpVpysqML1ALY5Vk0mH+7faVkCknOU31goYHN5Aoek2dkjxva1XOD2Ce9WuIg==} - peerDependencies: - '@types/react': ^17 || ^18 || ^19 - react: ^17 || ^18 || ^19 - react-dom: ^17 || ^18 || ^19 - peerDependenciesMeta: - '@types/react': - optional: true - '@base-ui/utils@0.3.2': resolution: {integrity: sha512-oWy1aq/I2GmYjpl4PhEAhzflF8VPGKgZeq0xAWTbfD5KBWyxcN0ZP2+WHSUm/5Z6lVMBDLReLcoXwSYoRc/zNQ==} peerDependencies: @@ -16647,8 +18039,8 @@ packages: resolution: {integrity: sha512-PNCSH5CGJrqOKxRjrMp2NLhceQv2QBs6HkjrLvYQqsEE2/ItN5R8GD/mskZZluoNWYvjPYFsY9T6swXfp5E0UA==} engines: {node: ^22.11 || ^24 || >=26} - '@changesets/cli@3.0.0': - resolution: {integrity: sha512-V7Gm+GP5OT3mJinMI2YcJD/JyO/a4WChnaMCCzTRhWHgu1zhtsyY7zCjP6n5W6zsgSjJKs+yPmvtREvE0F2g8A==} + '@changesets/cli@3.0.1': + resolution: {integrity: sha512-3IVpRSgiKDj2aRbBHKtWTXSRH2/iR3bWxau9iQUoEsZjDhRIj9nhl90k7FWMxZAJvLgJBbgMq8+qS0xQsenYsQ==} engines: {node: ^22.11 || ^24 || >=26, npm: '>=10.9.0', pnpm: '>=10.0.0', yarn: '>=4.5.2'} hasBin: true @@ -16696,8 +18088,8 @@ packages: resolution: {integrity: sha512-c5GoiQyt3pxiXjrWSNoP8/GRf4kG+VnKzovx1OQM8dYYALlSwgedmkPmJ+ZqGxqwg9D3Bkj85Uo4KLd5BN3A0w==} engines: {node: ^22.11 || ^24 || >=26} - '@changesets/write@1.0.0': - resolution: {integrity: sha512-xCK3/4C7Z7muQB/wguE6HcbjtY9iOtaK9orZKE+7xi573cMGD8rLZz7qlo6IvK7s+SIUIKajzj1l+F1QuP97tw==} + '@changesets/write@1.0.1': + resolution: {integrity: sha512-q/ThtP9gcnEP6xlv7LrY26C2mHqdGBti/MmOVngt/M/oIGYkssmQGxPK9WzBNt2juVcH/vml2WQ+ra8LXYOTaA==} engines: {node: ^22.11 || ^24 || >=26} '@clack/core@1.4.3': @@ -16919,16 +18311,16 @@ packages: resolution: {integrity: sha512-IlxD8okTt9cRUFpJKD8gTuQUBuEflrhCUju1xZFdYvmGm5XVqHPfG4I6+bEdKb8NO92aqHxr9SYuYibDmpMM9w==} engines: {node: 12.* || 14.* || >= 16} - '@embroider/vite@1.7.8': - resolution: {integrity: sha512-UaFzBi6yrZNYU3P1Aw+nI5L1NAaV2y7MhU6dcR0d3JZ9HZ6CmEW1+yfp3szni6SEy8+gIwKDAaraSZ1s2cO63A==} + '@embroider/vite@1.7.10': + resolution: {integrity: sha512-cKMjDQm7OgKJMHIlOX46sZtDDcN2ATKW4oZtBVewQHZKp7RYfCtl0MQFq88p2ruSa+d1OQ01GWg1ybdvCoFaoQ==} peerDependencies: - '@embroider/core': ^4.6.2 + '@embroider/core': ^4.6.3 vite: '>= 5.2.0' - '@embroider/vite@1.7.9': - resolution: {integrity: sha512-TmatvdDPM4THy4wKA7JvTZa4sJSagQEZeFyeYQCxKBFcIcOxvtrDzDV9oPhv0+LPr+7XXqVOni593Io2m0xnMQ==} + '@embroider/vite@1.7.8': + resolution: {integrity: sha512-UaFzBi6yrZNYU3P1Aw+nI5L1NAaV2y7MhU6dcR0d3JZ9HZ6CmEW1+yfp3szni6SEy8+gIwKDAaraSZ1s2cO63A==} peerDependencies: - '@embroider/core': ^4.6.3 + '@embroider/core': ^4.6.2 vite: '>= 5.2.0' '@emnapi/core@1.10.0': @@ -16946,6 +18338,9 @@ packages: '@emnapi/core@2.0.0-alpha.3': resolution: {integrity: sha512-AZypUeJ/yByuxyS7BlSNRDOMLMlROYtjYdIAuBmJssVz1UJDSeYxLrdizhXCFYhedC5bqd/ASy8EuNXbVVXp9g==} + '@emnapi/core@2.0.0-alpha.4': + resolution: {integrity: sha512-KjoUR6mNvjT+z5bKMy+a5QDI+kTNTiMZi6uPKzWuWjwZGNa0UPwIVduTfeBRdf6v8Ws5fmHDh7Usf15w/ANfkg==} + '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} @@ -16961,6 +18356,9 @@ packages: '@emnapi/runtime@2.0.0-alpha.3': resolution: {integrity: sha512-hFPAhMUjJD9BSyCANEISPOogeXC9Zo9ZQl7L6vKnaVsMkCtzznaW/naYypeyl0Gv5rYfWYsZbpixTMpjDJzQeA==} + '@emnapi/runtime@2.0.0-alpha.4': + resolution: {integrity: sha512-Wy1TQ99obRP3Ah7cf/OOtK1zD9t3pYTWz+G/SpAwTFMhG5hoMdlvfzBpYoHUigS/izu3q+VhYMKhJd7Ii/trpg==} + '@emnapi/wasi-threads@1.0.4': resolution: {integrity: sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==} @@ -17033,156 +18431,312 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.28.1': resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.28.1': resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.28.1': resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.28.1': resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.28.1': resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.28.1': resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.28.1': resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.28.1': resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.28.1': resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.28.1': resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.28.1': resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.28.1': resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.28.1': resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.28.1': resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.28.1': resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.28.1': resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.28.1': resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.28.1': resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.28.1': resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.28.1': resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.28.1': resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.28.1': resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.28.1': resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.28.1': resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.28.1': resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -17193,50 +18747,50 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint-react/ast@5.18.1': - resolution: {integrity: sha512-6NTpdv+Z6eHT2lc8DkfJZUG6tUvZQkRBlvBpYuoeen+HIvzz59aOt1YEL4dd6FQlXD4DPbCBGXCjcV879hT8Sg==} + '@eslint-react/ast@5.18.6': + resolution: {integrity: sha512-okgOez6L9onvcdU0lyLOykKQSaj2hMtVV2ucx2iqmTsfKDGyhVlMuNLnfyOkgQyHdgfROTVtAAYnQ6KPf7PggQ==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - '@eslint-react/core@5.18.1': - resolution: {integrity: sha512-n2avrghmy22iMFJWGXKacyMMvtaFrPqq1Yydd7L1DKmUe/hubjD4Uc1ZKV/F2xRh8dQ0Gp2b5TVv7H/Nq5DxUQ==} + '@eslint-react/core@5.18.6': + resolution: {integrity: sha512-utvjmfgy/lMSMt4QSU5QK2coHk6tkRChxLmkW6z8sthgmB6138CYzC3cPR9kze5pOgYJouF95xiaPnHKnXx21A==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - '@eslint-react/eslint-plugin@5.18.1': - resolution: {integrity: sha512-BlgYu//MKKnLHhQhh6E6ChSbEYj/a/cuRnyc+akOUtn8qCEqf2Le+/Rcxjfso3ujDjrq5yZt8E28aNOubtE6WA==} + '@eslint-react/eslint-plugin@5.18.6': + resolution: {integrity: sha512-qBZXKx05CPNrvdNydM958rZt2hgVhhriU/8LUeS5s/5gdpuekflrfF+y3yT4NT8Ej3J37h7e50RdH6Lu1r0KPg==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - '@eslint-react/eslint@5.18.1': - resolution: {integrity: sha512-T7AOWRwc1+gBEQUFoGSsBVHmWpsanGWVU52NTmWxij9ZGIlqbG+JC6vpCBa6IzGPKbulCu4B/np2JIydZQM1pQ==} + '@eslint-react/eslint@5.18.6': + resolution: {integrity: sha512-8BzLB6mtIDmAIwAt1u4g6Yp+1LSGAnqm8SGNHbyZG1sQikWW9Fskv3fx5Zy6CGMV9D7gafcHTiVTcuBYNE+87w==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - '@eslint-react/jsx@5.18.1': - resolution: {integrity: sha512-sT0JQ0yw/prFwtEu0cplzS0fZBpNHL1s7awHrD5xKABpqsVS2wofB52p2TSX2nmuNj011hSUW+xlu58GXYZ/fQ==} + '@eslint-react/jsx@5.18.6': + resolution: {integrity: sha512-oAbG2pW6XhiROZotfSjLU19A84/AxYHiiKjim5USHH5xtYfYjO7skFSM6LztuPggqn/wccSxLgmKIFGUKM/95g==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - '@eslint-react/shared@5.18.1': - resolution: {integrity: sha512-sLtaIw5PGVriltlBfDD/wUvF4+K3EDGuFhoUF2HKSIdhf28glyrcf6s2d0HnjFXUjXKcD325MNWL7Cectvs2GA==} + '@eslint-react/shared@5.18.6': + resolution: {integrity: sha512-zCzb/W1xwG412BWVTjqhDznsJEHdyZVkVJz4jbAebHLpKxygK5XeG+vShdYbIFC7OcJU8hYbvEf3P2UNqXVhBw==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - '@eslint-react/var@5.18.1': - resolution: {integrity: sha512-w1OP5/EJ4ocGWSw+nSpZnfehlnAvfVxOrlgx7k+xTHACyoFQZZXrehOYC7M/0ArQA68sOXo0C1ymEfTJE30StQ==} + '@eslint-react/var@5.18.6': + resolution: {integrity: sha512-5pxFlOy0Ajx+JUz4I4PwnYtOrqcj/R59Gx9m/WWjukFza/ap3FYnu8vEl2Q0txUQoUPJ7euPnBhkKOE7LhsOWA==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' @@ -17280,19 +18834,13 @@ packages: '@noble/hashes': optional: true - '@faker-js/faker@10.5.0': - resolution: {integrity: sha512-bsxD8WLS5lIj7aaoCx1YJkktqYj5vlBUE6HWzu2Q51ksrGJ0H737ECCKlFU7Yf8Br45z9t99frBp/J7kzbMPAg==} + '@faker-js/faker@10.6.0': + resolution: {integrity: sha512-3RQHgEtvL1Frl/d1cSreo7qhJ3Gk1OdNUai/CtZ8G+wYeRQnJih3s9xJ9/kgYekPQRdwgh0HXRPqMlzWGwivIQ==} engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} - '@floating-ui/core@1.7.5': - resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} - '@floating-ui/core@1.8.0': resolution: {integrity: sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==} - '@floating-ui/dom@1.7.6': - resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} - '@floating-ui/dom@1.8.0': resolution: {integrity: sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==} @@ -17314,9 +18862,6 @@ packages: react: '>=17.0.0' react-dom: '>=17.0.0' - '@floating-ui/utils@0.2.11': - resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} - '@floating-ui/utils@0.2.12': resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==} @@ -17360,8 +18905,8 @@ packages: '@glimmer/wire-format@0.94.8': resolution: {integrity: sha512-A+Cp5m6vZMAEu0Kg/YwU2dJZXyYxVJs2zI57d3CP6NctmX7FsT8WjViiRUmt5abVmMmRH5b8BUovqY6GSMAdrw==} - '@glint/ember-tsc@1.10.0': - resolution: {integrity: sha512-861yPIu5fNTZwCkKrnTiP2r+roc2JwxCHljoihDpv7eduzpeuiXZxh+hCpvSxume6znv8oRBX96u86FBtk0YqA==} + '@glint/ember-tsc@1.11.0': + resolution: {integrity: sha512-BP0621N68b6yvie2WjO96JBWAU8XltqZZgbgRjEydaKlx/yJLlALlnlSVF3BhZH7SC/0Ffps8pHMXvOQkkP59w==} hasBin: true peerDependencies: ember-source: '>=3.28.0' @@ -17373,8 +18918,8 @@ packages: '@glint/template@1.8.0': resolution: {integrity: sha512-TeVv3JnM0wbF86Sl2YyNhxeTEPnR5Q0xtIKqZueVzX8ouL3bj49Rk1gS0jFq7FNL7u6R+1oqToZBQmI+OCL4QA==} - '@glint/tsserver-plugin@2.7.0': - resolution: {integrity: sha512-sID/TfqvIZL6Igf3zrBeSQ32Y1xlSLiBqX6GkNNeiu5nxUHSxrala0zzDT/vgLm8E/BcvqcfzX6E1L040N+iWg==} + '@glint/tsserver-plugin@2.7.3': + resolution: {integrity: sha512-6tShPFE4gnBoWsonDfQs4KV8XqLL1BhTTrucSikbyVT5L0SEe6PyZ7eAFKafkkP2A6kykRRgfTWGHwYS+YMdAw==} '@handlebars/parser@2.2.2': resolution: {integrity: sha512-n/SZW+12rwikx/f8YcSv9JCi5p9vn1Bnts9ZtVvfErG4h0gbjHI1H1ZMhVUnaOC7yzFc6PtsCKIK8XeTnL90Gw==} @@ -17732,12 +19277,12 @@ packages: '@leichtgewicht/ip-codec@2.0.5': resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==} - '@listr2/prompt-adapter-inquirer@4.2.4': - resolution: {integrity: sha512-/KRI2DMD7JGSYaREF0Ygl7AefJ/2ase4Gc5cBiKqT5l4tFjsSJfhFGcc5nSkgl0Sp9LkCQNzl/cqbVJYP2L3dw==} + '@listr2/prompt-adapter-inquirer@4.2.5': + resolution: {integrity: sha512-pYGy9dTdTwXdasPgyohkr0HoQ4FrkAzFnsUZl/gcnadDArbpZ8e+fgr+F9WBdNEl2y00mb9bCM4WgmoBkZJ27A==} engines: {node: '>=22.13.0'} peerDependencies: '@inquirer/prompts': '>= 3 < 9' - listr2: 10.2.1 + listr2: 11.0.0 '@lit-labs/ssr-dom-shim@1.6.0': resolution: {integrity: sha512-VHb0ALPMTlgKjM6yIxxoQNnpKyUKLD04VzeQdsiXkMqkvYlAHxq9glGLmgbb889/1GsohSOAjvQYoiBppXFqrQ==} @@ -17783,34 +19328,34 @@ packages: cpu: [x64] os: [win32] - '@lucide/svelte@1.31.0': - resolution: {integrity: sha512-pgPuLEJdF0UpsajG9eSw0YvqXVuDxB+/x58BRiC4xE/KEHiopOqT1id3KCUvRN/PUmQkN1F26sslcs/1jutlBQ==} + '@lucide/svelte@1.34.0': + resolution: {integrity: sha512-sHFL8KVSaPXv0dsmdUTq4q/tj8clT2XYejnoSg0mHObpXWn/9SfET4f14v/7VOba1IsbPIW9+sWaq+Qq1wTdNA==} peerDependencies: svelte: ^5 - '@lucide/vue@1.31.0': - resolution: {integrity: sha512-NtjEHhcAa7umPh40wrRmlESJqNGdnpc7LziBKFnW3fmlrW0g2xMCDpdWU7WeEHRSl3xOpxbqiFTLKxoK3CoVCg==} + '@lucide/vue@1.34.0': + resolution: {integrity: sha512-eB48kx1oe9O6mJAg0gFWgv66y4rhYJYuhfWF8wIz/YBFPDDHWHI7+kRJpkvz/8kePY6ddbwxXIGfP8E54wlGhA==} peerDependencies: vue: '>=3.0.1' - '@mantine/core@9.5.1': - resolution: {integrity: sha512-3olDOYJBfW4kR37Aqdy/+FnYG7iNb5SPzOGeCp9dDxnt65K94sEqETDnXGJptOMO2xLm4KLJ/eBt3IIhJA7Z4Q==} + '@mantine/core@9.5.2': + resolution: {integrity: sha512-yhnR+XVGmy7S66abvj/tF9SxzNJ+k60w+UZlC/vGOztrU2Cxpbr95gtrBrin4fpWyiE80qzVC2AY0WzaHPufWw==} peerDependencies: - '@mantine/hooks': 9.5.1 + '@mantine/hooks': 9.5.2 react: ^19.2.0 react-dom: ^19.2.0 - '@mantine/dates@9.5.1': - resolution: {integrity: sha512-1FTIgF8L6AKEb+Ql53zVyCCp4JxvQp/AUDts5T/JEI7U0CZGpzg+FHGtmNShLR4ONuOfzOV1gkgU8INbxVJjag==} + '@mantine/dates@9.5.2': + resolution: {integrity: sha512-640r4aDYR7EfNV+qRqnIMC/HX0fuLiD8O4/qVVrLCgBV4w6ZtfcaTjLwDRR/F8uGIX5epNTujzhffz0n14HXCQ==} peerDependencies: - '@mantine/core': 9.5.1 - '@mantine/hooks': 9.5.1 + '@mantine/core': 9.5.2 + '@mantine/hooks': 9.5.2 dayjs: '>=1.0.0' react: ^19.2.0 react-dom: ^19.2.0 - '@mantine/hooks@9.5.1': - resolution: {integrity: sha512-2sK9OdWvrzKBOuWxLfQA5qcAJzxpzqNlKumaP7Uq0i7LDBQeY/sYgNiBWLwtW+iZw6fFXwPf0nI7q5VVpvqnNQ==} + '@mantine/hooks@9.5.2': + resolution: {integrity: sha512-CsANdaF07VRhcvDCupIvAPtIqU1NxYSc+bhFCCasDHpgJOUQxmqeMOGCCGSjtOOEIs+E+pt2ZbbdfnygDYPybA==} peerDependencies: react: ^19.2.0 @@ -17826,8 +19371,8 @@ packages: resolution: {integrity: sha512-6QEf6yqFbETdwGITKq57aYoPfX/3K8XFNwsAlx0C1M7o8cb79sv1M3w+tWuWvIcSbNqrLF7OD7YpZMVVz335hQ==} engines: {node: '>=20.0.0'} - '@modelcontextprotocol/sdk@1.29.0': - resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} + '@modelcontextprotocol/sdk@1.30.0': + resolution: {integrity: sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==} engines: {node: '>=18'} peerDependencies: '@cfworker/json-schema': ^4.1.1 @@ -17957,8 +19502,8 @@ packages: '@types/react': optional: true - '@mui/x-date-pickers@9.11.0': - resolution: {integrity: sha512-3vLmkn1wG+hNBaGobnk/9R8APCRhOiAXBTC78m7wZ2OWZ2NoMqi+O09HwTGlIgK6mScZZCeCQTSj5phNLrK1hw==} + '@mui/x-date-pickers@9.12.0': + resolution: {integrity: sha512-8buJZhsDQmq2mfG4ID7JPI8RmbBW8FZkF5GfgGkH0Bi/Y9UkpCeEuOFF/Tbg8TxL5gKAOkXRZTK/pFlNZYqdhg==} engines: {node: '>=14.0.0'} peerDependencies: '@emotion/react': ^11.9.0 @@ -17994,11 +19539,12 @@ packages: moment-jalaali: optional: true - '@mui/x-internals@9.11.0': - resolution: {integrity: sha512-JjKe9k1+gVWNPwMTZLNSc92eVmoZqP5Xq3Ui6mJkstotUrbWIZC0o9+4AfTR1lYqWwnKmqm+VtLLVCa7MEBXWQ==} + '@mui/x-internals@9.12.0': + resolution: {integrity: sha512-rpG9EgJhH3JeOK2Q/tKaUWk5vP8C1NfL8DaXMKR1XCA7RhpZUI/xT67WKY80QtogNWu7U/BRezKyQGtiZ8soYg==} engines: {node: '>=14.0.0'} peerDependencies: react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 '@napi-rs/lzma-linux-x64-gnu@1.5.1': resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} @@ -18130,6 +19676,13 @@ packages: '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.3 '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.3 + '@napi-rs/wasm-runtime@1.2.3': + resolution: {integrity: sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + peerDependencies: + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 + '@neodrag/core@3.0.0-next.11': resolution: {integrity: sha512-3WQWxyrbxiaK9zS5JU2wJsW2gpoQlZBXVghduBh61JpqaeE0T0cte8R0qYK2RuJo3J2TYQYqxO19CpG/C1i5eg==} @@ -18139,9 +19692,10 @@ packages: '@neodrag/core': 3.0.0-next.11 solid-js: ^1.0.0 - '@ngtools/webpack@22.1.2': - resolution: {integrity: sha512-5o3zbOdEHv5+wjRCMN+t6RBou28dbPkio5/rxEJBsQ9iEq11K+atsSKEaZXBMUhYr9nLYR8Pckm5Cqx2FP9R2Q==} + '@ngtools/webpack@22.1.6': + resolution: {integrity: sha512-TtRaHNESPQWdxeY+mbDrnXrKE1b2TwGE5joQqm/h0K8N4KNZNZOOvbKBGs19xra6zb+4R/kowB5TfjgTlTwagw==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + deprecated: Angular's Webpack support is deprecated. Use the esbuild and Vite-based "@angular/build" package instead. peerDependencies: '@angular/compiler-cli': ^22.0.0 typescript: '>=6.0 <6.1' @@ -18775,6 +20329,9 @@ packages: '@oxc-project/types@0.143.0': resolution: {integrity: sha512-u6JZdLBTLotrNC9Vd6vPssINdzcCzleKAH6EJKImQb7GtYvX5keN2dxkoK44stCc4tffE6QQRtZTXVSzsLUlWA==} + '@oxc-project/types@0.147.0': + resolution: {integrity: sha512-IJ3s6ltHLp45S0bh7phkX+gJO7A1Wuz2EaqpAhb8WjqDwbzMiWKHhyyT42tskaWjEYXtHtVCPpnBJVT9+dcRLg==} + '@oxc-resolver/binding-android-arm-eabi@11.24.2': resolution: {integrity: sha512-y09e0L0SRI2OA2tUIrjBgoV3eH5hvUKXNkJqXmNo5V2WxIjyC7I7aJfRLMEVpA8yi95f90gFDvO0VMgrDw+vwA==} cpu: [arm] @@ -19052,8 +20609,8 @@ packages: preact: ^10.4.0 || ^11.0.0-0 vite: '>=2.0.0' - '@publint/pack@0.1.6': - resolution: {integrity: sha512-3uVNyGcVplhPZSLVyeIpL7+cIRn1YCSNHLG/rUIlBQMVH8YuN9++YF+5+UDIIO9RW98dujiUoTltO7RDB5bFJA==} + '@publint/pack@0.1.7': + resolution: {integrity: sha512-4EDEmvxWtgsCnnVeBvtFIFZtUhPPt1+bA9JrSwU4Sa//6oKtzCSlGGXYJr44OD9aGISymbieJ4mCKHUygUDU+g==} engines: {node: '>=18'} '@quansync/fs@1.0.0': @@ -20066,6 +21623,12 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + '@rolldown/binding-android-arm-eabi@1.2.6': + resolution: {integrity: sha512-b+jTcARdTiFLI6jB4a5XjTm0RWd6KcRfQj/I2356fxUZemiho9zQLxo0RtCuMDAyKcLo6cEltkgbQp6d1+sjjQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + '@rolldown/binding-android-arm64@1.1.5': resolution: {integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -20084,6 +21647,12 @@ packages: cpu: [arm64] os: [android] + '@rolldown/binding-android-arm64@1.2.6': + resolution: {integrity: sha512-lkWU8ZJaRk9q3CIEY1Tc7vIFALp3Xw5NfGJo2hQg5oIqNgxWi1zI+IiDEK3r70BF5Dzol1tcXsnzsRc8NLhG+Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + '@rolldown/binding-darwin-arm64@1.1.5': resolution: {integrity: sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -20102,6 +21671,12 @@ packages: cpu: [arm64] os: [darwin] + '@rolldown/binding-darwin-arm64@1.2.6': + resolution: {integrity: sha512-dgR56NYnvAszm7Ob1B2/Vn0e8bUQYZH2UjVaMMtMVOCKFSfjhfLmuA/9+O+F+ajUdG6B/bSssrKW6JJYASa8jA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + '@rolldown/binding-darwin-x64@1.1.5': resolution: {integrity: sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==} engines: {node: ^20.19.0 || >=22.12.0} @@ -20120,6 +21695,12 @@ packages: cpu: [x64] os: [darwin] + '@rolldown/binding-darwin-x64@1.2.6': + resolution: {integrity: sha512-vpVxFvUCFioJqug7OTvqptkc4yb8UX0AwfDmJpaR/0sWz+BUmqSVAf7c8JkUgnN8YLspb4a/N6NhTyMAmdyQ7Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + '@rolldown/binding-freebsd-x64@1.1.5': resolution: {integrity: sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -20138,6 +21719,12 @@ packages: cpu: [x64] os: [freebsd] + '@rolldown/binding-freebsd-x64@1.2.6': + resolution: {integrity: sha512-h1wG6Y6K3JlRswxsI64qQJqBAy4vrLuHgRbc8CZMGSWTOFRY6ghMApM1NKzB2I0n5xV1fjkE18SuVl2QpLeNpA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + '@rolldown/binding-linux-arm-gnueabihf@1.1.5': resolution: {integrity: sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -20156,6 +21743,12 @@ packages: cpu: [arm] os: [linux] + '@rolldown/binding-linux-arm-gnueabihf@1.2.6': + resolution: {integrity: sha512-tbCiqub0q2MVWJKgF5PoAlNWCtQydiOYSLIkd8sByqK/6MMYLJRcSXSYodqYtd0O+Fw7QaVmKKlS4oL94YRZ0w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + '@rolldown/binding-linux-arm64-gnu@1.1.5': resolution: {integrity: sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==} engines: {node: ^20.19.0 || >=22.12.0} @@ -20177,6 +21770,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-arm64-gnu@1.2.6': + resolution: {integrity: sha512-oxK9+baEBPhZG5HB4URY+uU04zJWeZlH6Tb9rB5DK4DF9XR1uXNLXt5Q5ZsugTKayNCNLhkcwz/ye74hRI98dg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-arm64-musl@1.1.5': resolution: {integrity: sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -20198,6 +21798,13 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-arm64-musl@1.2.6': + resolution: {integrity: sha512-muWCk27FVBEZtv0MsK8gnfSmgczA8KQ0uRVJbTABKhkRfQc38aUrcb7fhi3BNiyseFmgcRsoMfQsSNJ+DbZdSw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + '@rolldown/binding-linux-ppc64-gnu@1.1.5': resolution: {integrity: sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -20219,6 +21826,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-ppc64-gnu@1.2.6': + resolution: {integrity: sha512-eWDoSfU7Co2qj3vgB3Dt4lj1mG6CoWbcJQkRMP3XJplyCMtuaq3LHvPFjS9QIPvMGWVadJC04Xiy0IdcVPtnwQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.1.5': resolution: {integrity: sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -20240,6 +21854,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.2.6': + resolution: {integrity: sha512-2bWNjRSIayvupRKxXUY2tWG9fYdoUlTqWywHRvE8Eq3GvuQ+f2HeIkve697fIt+IQs/PV8yFsdWuhp1aJ1PdnA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.1.5': resolution: {integrity: sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -20261,6 +21882,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.2.6': + resolution: {integrity: sha512-KekI0gS0wLxe1UBSQSjenBVwou/JkcQPDzBPICGZjxUv9k3RteHDPBQaiOicZUFKRIH2wKEimGwVpnJsbPzu7w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-musl@1.1.5': resolution: {integrity: sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -20282,6 +21910,13 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-x64-musl@1.2.6': + resolution: {integrity: sha512-TvtPnfVr+HtyGiDmPK4VWmlNm7QhNNAcK5Q9A7aOXsI8545yCyaoMaicXrFZ72JzeYjaUVk7yT243zT0jzjFKQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + '@rolldown/binding-openharmony-arm64@1.1.5': resolution: {integrity: sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -20300,6 +21935,12 @@ packages: cpu: [arm64] os: [openharmony] + '@rolldown/binding-openharmony-arm64@1.2.6': + resolution: {integrity: sha512-iOo0VEay2XFhaCcH0sps5XIimkSuOnNaZrf6+ZkoSOQBJPKNU48RkmJv0/lSpipexu5P+ouFgafe5IGr/DiQfg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + '@rolldown/binding-wasm32-wasi@1.1.5': resolution: {integrity: sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -20314,6 +21955,10 @@ packages: resolution: {integrity: sha512-/TX0SoRGojHzSAHpfVBbavRVSazg5U3h3Y3VXfcc0cdugq6kxdqw8LPGFiPr+/7gE/60zRcsOY2Vi9b9eT0jww==} engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + '@rolldown/binding-wasm32-wasi@1.2.6': + resolution: {integrity: sha512-7l2ygq7igusdJglAiXxy52BMlUT4ykpmLhX4YWR2bi+IGfAX4OAbpKyN74g9Zj64a9bhcekBxav4qRMsTIQmmg==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + '@rolldown/binding-win32-arm64-msvc@1.1.5': resolution: {integrity: sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -20332,6 +21977,12 @@ packages: cpu: [arm64] os: [win32] + '@rolldown/binding-win32-arm64-msvc@1.2.6': + resolution: {integrity: sha512-y5NTmmasMS455JlOCO4ZM9krIchv3Mvm1crL1iUPGOPgEzSkves9n0SdC5Sjz6+qWDFhd8/JpfWMH8NSWNHe+A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + '@rolldown/binding-win32-x64-msvc@1.1.5': resolution: {integrity: sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -20350,6 +22001,12 @@ packages: cpu: [x64] os: [win32] + '@rolldown/binding-win32-x64-msvc@1.2.6': + resolution: {integrity: sha512-np8iZSLfXlAD4kWhiyq/u0Yt8oZDtRQ8lGhQaCXo2rl37KNjeU0GjJuwr4P3oeZ++ROfofsKNBqR5LTO8aXyWQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@rolldown/plugin-babel@0.2.3': resolution: {integrity: sha512-+zEk16yGlz1F9STiRr6uG9hmIXb6nprjLczV/htGptYuLoCuxb+itZ03RKCEeOhBpDDd1NU7qF6x1VLMUp62bw==} engines: {node: '>=22.12.0 || ^24.0.0'} @@ -20414,141 +22071,141 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.62.4': - resolution: {integrity: sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==} + '@rollup/rollup-android-arm-eabi@4.63.0': + resolution: {integrity: sha512-70TeIFezKKy65LgAVyQh+w94/gjWhvPWaLaGGeMEgVrPkQhuj/M5bAYYZzIFUj9Y69oHyTm5Um/R6gcLh4A8JA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.62.4': - resolution: {integrity: sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==} + '@rollup/rollup-android-arm64@4.63.0': + resolution: {integrity: sha512-YC86tYIHK6M1IV+wbzO+Bxk8RCBr6ZyWYgWxUCzaZD8mc8rrFoIJDNzDrkHBYRc/wKdrsIXmm6/F7NzrAO+OrA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.62.4': - resolution: {integrity: sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==} + '@rollup/rollup-darwin-arm64@4.63.0': + resolution: {integrity: sha512-oI+ECtUcli0y0fi4xpW82GdPIXdTkI8G8DSjG2LRuw09fPAGykaWYH/hXxiKuTxiAjiPSTIIuYUqof5Z2hShWw==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.62.4': - resolution: {integrity: sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==} + '@rollup/rollup-darwin-x64@4.63.0': + resolution: {integrity: sha512-NwV+1s7TiKrMe4owHyKB/dTLD7ZJD0YEBEhIz+hvav1Cu1GReJjF+rsdNwjzENQeIAbE/CoNiaAc5Vz2h5DPAA==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.62.4': - resolution: {integrity: sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==} + '@rollup/rollup-freebsd-arm64@4.63.0': + resolution: {integrity: sha512-tWtHBTu5gOPK4u4Urtk4qAHW3zZ9rQAmbssO8gp7ELvGTGI3aCiq6NqyTQ0PCIg7KbHJF2UkGDDs77YZGxfjCA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.62.4': - resolution: {integrity: sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==} + '@rollup/rollup-freebsd-x64@4.63.0': + resolution: {integrity: sha512-2qPoJiwTvtHQ27NnYvTnsgk8laXWYuVmNESG8WFZBcEPKLfZ3I27qBJarjVRQtwGeYyRfq5ZowHXih9lm2BItw==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.62.4': - resolution: {integrity: sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==} + '@rollup/rollup-linux-arm-gnueabihf@4.63.0': + resolution: {integrity: sha512-FQwsTRvLNuHoTdICABJQfbPUSEueISGmnpT06tXTMpfprf5NiKLSXKA0A+w45wJnCmZAnzgqBwbt6ARFuyOi5w==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.62.4': - resolution: {integrity: sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==} + '@rollup/rollup-linux-arm-musleabihf@4.63.0': + resolution: {integrity: sha512-BBVTXziw8mY1a4ZbWME9tZyfzqXCDPqaC7Z3heQ29p5dkvXzwL0NwelO8zLa8c3RBKvl3YTuSnBgsBhYBtwjIw==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.62.4': - resolution: {integrity: sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==} + '@rollup/rollup-linux-arm64-gnu@4.63.0': + resolution: {integrity: sha512-w2Iyy9+RqKwx3d9qWMKsJg0FfRBsY0/pXNv0mCQ3ueRvJI6+QAScfD4nrMlzFLs2HNVW6Ew+mtZfDl9b7Ew5/Q==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.62.4': - resolution: {integrity: sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==} + '@rollup/rollup-linux-arm64-musl@4.63.0': + resolution: {integrity: sha512-YK++KtrFRHYE0P6/RtYEAy9t8F37znP+K03RrIuLPYOL6SVlObRumf/0OE4V/h63xL9DwkWbNssZfmA9hawuDA==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.62.4': - resolution: {integrity: sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==} + '@rollup/rollup-linux-loong64-gnu@4.63.0': + resolution: {integrity: sha512-aBfOG6fP7YkkPmTqPwufRJeFyz7WPpECv9XNbnsk9+vg7rxdih0lbtEel7jcRng4LZrrmU3FfitCFyEj4BWDWg==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.62.4': - resolution: {integrity: sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==} + '@rollup/rollup-linux-loong64-musl@4.63.0': + resolution: {integrity: sha512-LGaHEOeHNAag9VuS1Crs5DFg4RrU9MPi2nVnNJk9DTePx/B6RRYKVmrIXt2h7YOJlwjaFJ6lwtFDliZxScTLrQ==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.62.4': - resolution: {integrity: sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==} + '@rollup/rollup-linux-ppc64-gnu@4.63.0': + resolution: {integrity: sha512-jClvk+J0FC3b7Udvegiw5/4hErbHtmsNsQgENnKXDWtNCJXsJYZH5WURvu7imDOO38xYml24eeh5x3A04ppwCw==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.62.4': - resolution: {integrity: sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==} + '@rollup/rollup-linux-ppc64-musl@4.63.0': + resolution: {integrity: sha512-0OJlaGK+8+B777Ql5okIpD7ua5Ro9+VB9Ve0OKa28OQJZ1RbuUBVNHK/e3pr4BROqsyPl1JrPO1ZxJseCNffcA==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.62.4': - resolution: {integrity: sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==} + '@rollup/rollup-linux-riscv64-gnu@4.63.0': + resolution: {integrity: sha512-Ygsx+HoNH7afwi1bTIXbnTvVnsO+zurPLSYxybV1hHFVU72OWOCl6v05ql/z0hkpAPx+DK7Kn9Bi7MayCcjLTA==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.62.4': - resolution: {integrity: sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==} + '@rollup/rollup-linux-riscv64-musl@4.63.0': + resolution: {integrity: sha512-pDQxtMGb+OvG3fLwR2OkZlSd47hW+kWg4BYMG/++sR6RqorQccwPTDsxda5hPwiIeIErAnCF9ma3SAU06bdQtQ==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.62.4': - resolution: {integrity: sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==} + '@rollup/rollup-linux-s390x-gnu@4.63.0': + resolution: {integrity: sha512-0BnUG9mS8I4SSHr3XsxVhuCMEiu+rX61xxZF5vujso4LaiAGFZFxvDjg6Xn6tLPNTUAfuCvQYas4LMQMVsKRSQ==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.62.4': - resolution: {integrity: sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==} + '@rollup/rollup-linux-x64-gnu@4.63.0': + resolution: {integrity: sha512-Adu/VttB1dpPNW+FEacrZ+xVm9tFty84+RrFzsqlFaPxoJB+9XXyDGtp5dCOoBwGBIEVH0To7lExFXEx0BIF4A==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.62.4': - resolution: {integrity: sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==} + '@rollup/rollup-linux-x64-musl@4.63.0': + resolution: {integrity: sha512-NQ3bDvjUbFKmP23671xUlXtKmqVsUBd6M4PQCvbmNtOy06hnQIdKHy8oG/6S3R/S6He1JgPk6A5VT+prAJMYEw==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.62.4': - resolution: {integrity: sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==} + '@rollup/rollup-openbsd-x64@4.63.0': + resolution: {integrity: sha512-u2eDAl4+0aFvA13GxlGBtTI3SS3sdgwgtV0HyjZ0QaQVCgNE+jqNGey+GtxWiq+wxr/UycAx/OnfJzApCFamvA==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.62.4': - resolution: {integrity: sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==} + '@rollup/rollup-openharmony-arm64@4.63.0': + resolution: {integrity: sha512-XvRb5vfW3wAZQ+ZUG21AnHHDKtNcw99eigzEhjr//NZ3u7SoBaPP0seSc7FgP7p1epAEdAoZckMW9WY/+4w70w==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.62.4': - resolution: {integrity: sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==} + '@rollup/rollup-win32-arm64-msvc@4.63.0': + resolution: {integrity: sha512-iZPmniy4kNBf5yo2RezbkYNNK5HPbXE9+g+twnbqSng7dtLEJy1SKoxiE/ni4FDacjyuZpEeb9U054N4EoKHYw==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.62.4': - resolution: {integrity: sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==} + '@rollup/rollup-win32-ia32-msvc@4.63.0': + resolution: {integrity: sha512-mFBBd+LF37fnE8JnYUOH+imj0aPFPK30vpar4ehJkgnLj9sZn8ZxiRENmLtgIwxK7TC8klF6N57fxdNBwQoqOA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.62.4': - resolution: {integrity: sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==} + '@rollup/rollup-win32-x64-gnu@4.63.0': + resolution: {integrity: sha512-ujeqEY3B+zbGn3Z4Q03cUBG/LGWnBJncVT36WER31LcOsQk9+1dmINKKtvmmfChUvRbK1G0R8OhMWFgHgaZtAw==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.62.4': - resolution: {integrity: sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==} + '@rollup/rollup-win32-x64-msvc@4.63.0': + resolution: {integrity: sha512-hncn90N4sOky0L2LKE5oESKLbxCPeVo4eLA2LSMoDzM+879ml4WSr+Rr4DWknNIVVvS1Hirkc9hx02W6YxS8rQ==} cpu: [x64] os: [win32] @@ -20557,8 +22214,8 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - '@schematics/angular@22.1.2': - resolution: {integrity: sha512-52udja/QGSNH5geSnL4JWFOEfx8M7tqf7LNXz8byjki4VshVOkKHTawQcL4YbJfo3MfwwXm4AsoadMOk8EST2w==} + '@schematics/angular@22.1.6': + resolution: {integrity: sha512-RiD4OZJ4yuaM1aXb3pt1gjDSWwkP0jrgiCuoaBls1eabcrDmlsNuQv0ekxbcGgCRPdSJvmHRZIHHmFPzei8w3Q==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} '@sec-ant/readable-stream@0.4.1': @@ -20684,8 +22341,8 @@ packages: peerDependencies: acorn: ^8.9.0 - '@sveltejs/load-config@0.2.1': - resolution: {integrity: sha512-5m3B2cbqQ4TbwW6Xkh66Ntw6dD7gNc77cCxABTTesWcq9jxIzMgTk97pZx5vEtvQx8iokgi7GIphqZe+PGwcZA==} + '@sveltejs/load-config@0.2.3': + resolution: {integrity: sha512-VT3qmUb8pRV2QrZjd8iAmtg8lf4W0TIjZbvXtz5MKei/q96teWZgGJyyidJzOjzZzvdq616eSRVeMYIQChUTAQ==} engines: {node: '>= 18.0.0'} '@sveltejs/package@2.5.8': @@ -20807,8 +22464,8 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 || ^8 - '@tanstack/angular-devtools@0.0.9': - resolution: {integrity: sha512-X/U0SDQOtu1xUJPwzZuIIZtM5hG40zaKJqVV/bxaB+Fe1JhpKEFG3zQjezAZ6FzSFJMKnSw0QZBKhwBBD5UolA==} + '@tanstack/angular-devtools@0.0.11': + resolution: {integrity: sha512-iHZsgR+oWkNVHZ1V+pqgT5atV88nkX9JuDvztmmTIZ0B+hQip1r79Fq7dWBJS3l0XesxvVkn8flVgX8u4rqRig==} engines: {node: '>=18'} peerDependencies: '@angular/core': '>=21.0.0' @@ -20855,8 +22512,8 @@ packages: '@angular/common': '>=19.0.0' '@angular/core': '>=19.0.0' - '@tanstack/angular-virtual@6.0.2': - resolution: {integrity: sha512-y/u2ZKAN5ob+ljwUoSK+r2j2piXw/ol63ykFbzZ8Hahj0dRU9xCJ0cJIDxTQ9zRoGbk0ZIiy3BK5w8Mso1daKA==} + '@tanstack/angular-virtual@6.0.3': + resolution: {integrity: sha512-FIYtUG/EewDi//ISz4GX2/h4WcjcclM+FKh7mhgj/2xV3ATLWK+ZrrGICdsfAeAeVVdOBmSCKybWIbAG7Hljrw==} peerDependencies: '@angular/core': '>=20.0.0' @@ -20872,8 +22529,8 @@ packages: resolution: {integrity: sha512-cNnJ89Q021Zf883rlbBTfsaxTfi2r73/qejGtyTa7ksErF3hyDyAq1aTbo5crK9dAL7zSHh9viKY1BtMls1QOA==} engines: {node: '>=18'} - '@tanstack/devtools-event-bus@0.4.2': - resolution: {integrity: sha512-2LHzhwBFlKHCcklsQrGe8TeyjHd4XAF8nuCO6wHmva5fePUkJUULbu6CsCNAlGlCi0KkEsMXZSvRdR4HgMq4yA==} + '@tanstack/devtools-event-bus@0.4.3': + resolution: {integrity: sha512-NeegBt5/n2E5q4DbrXHqECBq42+kDi6JBOp8/+RNqkIE+P4hJpbM36kGyjnGQFMWOoku31qhMyX9/48VuTTdmg==} engines: {node: '>=18'} '@tanstack/devtools-event-client@0.4.3': @@ -20898,8 +22555,8 @@ packages: peerDependencies: solid-js: '>=1.9.7' - '@tanstack/devtools-ui@0.7.0': - resolution: {integrity: sha512-px/a+JgRSVHDj/hID1cwfsIi+ly5l7t3Yw7fLw4G556HXCNgDri36fupt9h7oBeEKntpsx3ep/XtZn51rrCv2g==} + '@tanstack/devtools-ui@0.7.1': + resolution: {integrity: sha512-3xQ/ezZ2qVNszhjpCN2N3jn7uHc2J1PMgcyjHzH4XZBt9xAQyMMcPNoR2cd7rzReyxWoJpZUWiDBmOJiCtLj9A==} engines: {node: '>=18'} peerDependencies: solid-js: '>=1.9.7' @@ -20954,6 +22611,34 @@ packages: vue: optional: true + '@tanstack/devtools-utils@0.7.0': + resolution: {integrity: sha512-D9oosgtwvOe5nHQuhCqO/pxZz923REExp2kTc2YaJQ5+0QjTU3xRU+KkwRbFmlJwEXRcJCeAGF5j9Y72TZQ/xQ==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@angular/core': '>=19.0.0' + '@types/react': '>=17.0.0' + preact: '>=10.0.0' + react: '>=17.0.0' + solid-js: '>=1.9.7' + svelte: '>=5.0.0' + vue: '>=3.2.0' + peerDependenciesMeta: + '@angular/core': + optional: true + '@types/react': + optional: true + preact: + optional: true + react: + optional: true + solid-js: + optional: true + svelte: + optional: true + vue: + optional: true + '@tanstack/devtools@0.12.2': resolution: {integrity: sha512-Xdl8pLzoDUvXaclQ0poY36WAPx0jEHk8vqUFd8FYFUm1BMshtB7RnTgD1HE9jCAXODxqw9I0gXBiUZLK3o3+Bw==} engines: {node: '>=18'} @@ -20961,8 +22646,8 @@ packages: peerDependencies: solid-js: '>=1.9.7' - '@tanstack/devtools@0.14.0': - resolution: {integrity: sha512-tN0SEi1BVaJYtkZbgYpvLsInjwNRAZkR3r6slSvz9Jm+bfkhcdjuOSrZp0cAwOGwdnauHZ1mYgtfe2AfC/V1NQ==} + '@tanstack/devtools@0.14.2': + resolution: {integrity: sha512-8FVVmDU+x3iEwrl5rtbIhud8gwp9eSXPlhs36SCV59yAtXmheFFvLqLAUXpfIU79sZVBg3LLTy2VlTIXaWbaBw==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -20990,8 +22675,8 @@ packages: resolution: {integrity: sha512-vqH7X9nb0MTJ/O08++dB5bP9jgj4+BIPOUu/U+6myG86lDsirZSVSobpq5UQpE7nBuk62i8eIYeOhd+OMl/UrA==} engines: {node: '>=18'} - '@tanstack/intent@0.3.6': - resolution: {integrity: sha512-ylew/4T3layUXSfE/SDGUSAi1B3U/wuoNUE0adC3j/s6wzX7omV6e6hAv0WyMC52Inren8kqvwpHj+G/ZBbQHQ==} + '@tanstack/intent@0.3.7': + resolution: {integrity: sha512-119d81v2JpdFtvLlX8C7Kmx0zqaNUnY4iTyd5Q8rVyE7sVCnuBYIS/NNCa8T6Ni0bdVkcOVDl1zdz78Oz2dfAg==} hasBin: true '@tanstack/lit-hotkeys@0.11.0': @@ -21005,8 +22690,8 @@ packages: peerDependencies: lit: ^3.0.0 - '@tanstack/lit-virtual@3.13.36': - resolution: {integrity: sha512-dju+ZvpztbcSZjWLllJIgHioXWypAm8hq9ALqFfAt/9hmRtU3gZKNEWgy+pgxtbHMouq2hQFrXWKfF3LRXKwJQ==} + '@tanstack/lit-virtual@3.13.37': + resolution: {integrity: sha512-ZBX/yYKwJmTrGgJa7Sg2nZ3bm7MI9c5CLUi8jS8nldFxoByf6PpVyBLtbaUNOmro2xDKgiTaRaGu1+1pn2Jptw==} peerDependencies: lit: ^3.1.0 @@ -21030,8 +22715,8 @@ packages: resolution: {integrity: sha512-Zq23KOn30tFiA6ZYWihs5x++ttHkOIcnIIjRrJq05tGrYx9+iHsmVaj8jb7UJVemEI+JRWGzJ9C+50YV4nRz0w==} engines: {node: '>=18'} - '@tanstack/preact-devtools@0.10.10': - resolution: {integrity: sha512-KPTLQ2GCEdscS1vQ8L10BfuV34GgDl/X2VVyer7gX+YnFJrqhJEtWtNV+ROUw/nQ7orOOfsfEKg4V7gbwHtuxA==} + '@tanstack/preact-devtools@0.10.12': + resolution: {integrity: sha512-m5js5Va2IeqxW2ZPE3wgN5gNu5Tud/Gc/Ku2uKeHF+nUFwCOSFLwXRnnh1BCEffxIp8/W2Zw4TR56iLaJAYOvw==} engines: {node: '>=18'} peerDependencies: preact: '>=10.0.0' @@ -21070,11 +22755,6 @@ packages: peerDependencies: preact: ^10.0.0 - '@tanstack/preact-store@0.13.1': - resolution: {integrity: sha512-0h8ku2LfJ/TtVtgx24CLgS2OgzY5wVsRWIGktE0yq6b6fHlsCcY55IEJXTDRs0RTYWFOXu7N/1kfb2SLEOasaw==} - peerDependencies: - preact: ^10.0.0 - '@tanstack/preact-store@0.13.2': resolution: {integrity: sha512-CBosOLog5UnaZX9YHRA2LKJm5XR0tCABvNWDfDMcyFeLtEnJ9W9DOVbz4JxXMb3+LZhGEMVrt1iA77npNx/9rw==} peerDependencies: @@ -21086,8 +22766,8 @@ packages: '@tanstack/query-devtools@5.101.4': resolution: {integrity: sha512-z5IPHnDX3aUWeTWlRKLyooBQekaCAw4xRpZqPQ390RiWTDBcTynjpPT221BArw0u2+pnQMdGvPQI9YNNubBcmA==} - '@tanstack/react-devtools@0.10.10': - resolution: {integrity: sha512-hYH34MSVbajs1pUc22ftSapyKQp2gOh0w34a7ouYOdIcbXD6YPckSR2YpAWGq1rrs6N0l/rvV6LM/G1pgN5ARg==} + '@tanstack/react-devtools@0.10.12': + resolution: {integrity: sha512-dgoz7TFm97Izo/D34z91PD0h+ufk+eBmoN9OgRHJlj/c7Ol5xpIP7bqLBNByjgt5paRE2eSu5AQHV92Ul+G6iw==} engines: {node: '>=18'} peerDependencies: '@types/react': '>=16.8' @@ -21164,22 +22844,22 @@ packages: '@tanstack/router-core': optional: true - '@tanstack/react-router@1.170.27': - resolution: {integrity: sha512-Hxl49xzd8ffWd2ZMigqfXZmpySpixWGvjq5zfh2nK2DbzzDH6IGVh+iUuwarK9MJNcnhWPZ85tOoy6o/OmNlww==} + '@tanstack/react-router@1.170.32': + resolution: {integrity: sha512-SIpxvaTKco100a5ZR3ePmArbhtm3XOx+w1dpGYY9gxHDta4iXSKDdQuhLonwJbIMkVJsU1rwXf0UDHMrF/1snw==} engines: {node: '>=20.19'} peerDependencies: react: '>=18.0.0 || >=19.0.0' react-dom: '>=18.0.0 || >=19.0.0' - '@tanstack/react-start-client@1.168.25': - resolution: {integrity: sha512-vwjhuXUXFEAS8btmmXa24J/cP12AuAqIn/9OdZnrVufBE489IaxUEE3KuqEyUyZ+dtwPxChgVxFPHLcG9zonwA==} + '@tanstack/react-start-client@1.168.30': + resolution: {integrity: sha512-qsZuykUl1EF0/rc1bin1RtjFzz07YMOTBzhOstSDzbOVm/WKf1QKFTN+qAZi74xlbXSWNuT2MiFRyg4RKwj8iw==} engines: {node: '>=22.12.0'} peerDependencies: react: '>=18.0.0 || >=19.0.0' react-dom: '>=18.0.0 || >=19.0.0' - '@tanstack/react-start-rsc@0.1.43': - resolution: {integrity: sha512-5h5qytaTlhakTWX0oMz7pVxS/4FuCJeg5a/jKkbLsEU2hWy/R098zQG9tftkWbzPhq+B3pfrGk32ufUzsiwK5A==} + '@tanstack/react-start-rsc@0.1.48': + resolution: {integrity: sha512-UglRdTMuF3c4dvzL/gh4dMVbMWHsPy8ZgTQdT2qpTlyt1b/3m+R40tBFdsfTgw76VTXivW+qV/ih0PN9000XTw==} engines: {node: '>=22.12.0'} peerDependencies: '@rspack/core': '>=2.0.0-0' @@ -21195,15 +22875,15 @@ packages: react-server-dom-rspack: optional: true - '@tanstack/react-start-server@1.167.32': - resolution: {integrity: sha512-HZV8EE9f2XU+KnyJcB20SCZgAm6G3uGPUwihaqgAz+MPnuJ/xG1iNy1oyQRz/SeqI3PVnPKzWK3Dkv+7xiO7cA==} + '@tanstack/react-start-server@1.167.37': + resolution: {integrity: sha512-cODHpFU8vIm7AdHii9W3NEuwyruNmT5wLDZjRsJLT9Jp+7FACnfJrRbvxnp1ldSv/9mxcHKi/OgwbdHQeMZcAQ==} engines: {node: '>=22.12.0'} peerDependencies: react: '>=18.0.0 || >=19.0.0' react-dom: '>=18.0.0 || >=19.0.0' - '@tanstack/react-start@1.168.44': - resolution: {integrity: sha512-varBaGENYuX0qdRMy8xZvr3BpHCHfkOeBaFCQkXUaOzK3NmWdpqj6CSbPq5uMCHkvFTDXNN6PZukp5zRa5Wmcg==} + '@tanstack/react-start@1.168.49': + resolution: {integrity: sha512-iQb1ZoEHqvZMGLR4G7v3tTtgL06yv/bwxvGP3waVHxVn7bRpyopM44YbOluaGkcJzc13ZTvdLKWYNAN3bxMX/Q==} engines: {node: '>=22.12.0'} peerDependencies: '@rsbuild/core': ^2.0.0 @@ -21219,12 +22899,6 @@ packages: vite: optional: true - '@tanstack/react-store@0.11.0': - resolution: {integrity: sha512-tX4YXh3PDkmpvGQWkWqKpzs/MSqbtuwY9dWdWhtV9Q50PmO+jOkUKIWIX4G85dwt7lxdHLXsiaEKPdKmC8F41w==} - 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 - '@tanstack/react-store@0.11.1': resolution: {integrity: sha512-HaIGKI3YLmjBYIvy5DFDY23oNaYZIsTZfngey07Uh5iLVJgM3bIGCnZeOFOqzjFld9JHWcaHJnasD/bKoGKwJQ==} peerDependencies: @@ -21237,14 +22911,14 @@ packages: 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 - '@tanstack/react-virtual@3.14.9': - resolution: {integrity: sha512-qZyr0FZDP8rDC4WBhsryIZmAd9bveJvFGUJJtskWaew6/0dTRS6wZxnR6VQ5bY2KwL3LjerrHqQLk3a0GKcPXQ==} + '@tanstack/react-virtual@3.14.10': + resolution: {integrity: sha512-SRyoUbdFMRHuYXMijV5H4ZarQWpXkj3iANq8OFre+pybeVap8ZJjZ3Nz9bVjx4d8PfobVUQUdKyyyHYk3E+djw==} 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 - '@tanstack/router-core@1.171.22': - resolution: {integrity: sha512-sitsuRkz4qpTjIAV97S5zFCoeGv0OFd6+VWg3ZcIlQbi5R4NIXfz6ogg51n5w6rvTwSODz/lKWb5dl5tvh2bQw==} + '@tanstack/router-core@1.171.27': + resolution: {integrity: sha512-wDwSLvoLwIaNcnx9UNcN9Mb7Y8QwCYq1U1RQZwyN186gnkIoIYI2SOxy8VqH1vFigbkHkk4FmwMAQlghPgDK2g==} engines: {node: '>=20.19'} '@tanstack/router-devtools-core@1.168.1': @@ -21257,16 +22931,16 @@ packages: csstype: optional: true - '@tanstack/router-generator@1.167.28': - resolution: {integrity: sha512-AxvzdqQoBxrA8hoO1fHYg4cAUVug/xLqQhsGbNG1PelU3RbYRYEtDim7+HbYQCOqJaEuvV8tCvrTPTnT69iIwg==} + '@tanstack/router-generator@1.167.33': + resolution: {integrity: sha512-Z3lCWIPuRUMPmuI8Mm48x/s49TxmHOaFVZ52j1W1QKYrsFHyT6U/h9bqfHJDxfQ8kz7y9q+W1YPKZ15Ee7yuCA==} engines: {node: '>=20.19'} - '@tanstack/router-plugin@1.168.30': - resolution: {integrity: sha512-Z53FeZjSddyn3c+lmUGHOU3bhZPpaFabcynja8/s87CZeyMYS7oNgUMoaYZAhVLk9cAEC/z3fkqISXqktZadDA==} + '@tanstack/router-plugin@1.168.35': + resolution: {integrity: sha512-foDAZKFqHXae+oFbIgcsSvy2QCVRn7XdS3nhwcRvD+ed6JrKPUP/1lQMsZLJqWycgR1vkZF7gs955KGa0NZQ0w==} engines: {node: '>=20.19'} peerDependencies: '@rsbuild/core': '>=1.0.2 || ^2.0.0' - '@tanstack/react-router': ^1.170.26 + '@tanstack/react-router': ^1.170.32 vite: '>=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0' vite-plugin-solid: ^2.11.10 || ^3.0.0-0 webpack: '>=5.92.0' @@ -21286,12 +22960,12 @@ packages: resolution: {integrity: sha512-hTWqJtqIFFdvuCl8WXNyrodp2L9zo2G37xKRrcVmVRWpAB2h+U1LuRAfS4tsFTiWOIoE/B+WDVFB8JpoEdw6jQ==} engines: {node: '>=20.19'} - '@tanstack/router-vite-plugin@1.167.30': - resolution: {integrity: sha512-Tv1ENYWshAroCK48aped2hcOG0JHdxfGfa5+bxt29XDuNuAZarLd0c3iX5IjtXle/clyJCdvstauoge4ajke0A==} + '@tanstack/router-vite-plugin@1.167.35': + resolution: {integrity: sha512-vWSKmKdLo5PxQBwGZgInSXPQodCBrW6rin+q2zz2NvI27o4oVCjCGUioxafCdft1+PX4PljxZgjZCcbYLV13Dw==} engines: {node: '>=20.19'} - '@tanstack/solid-devtools@0.8.10': - resolution: {integrity: sha512-jpaNX8VXhE3qDDUwYXfdac480mDchC3YwUC9sgyRRFTbZA5eptK/oLO7nHhMIPkJOeQ4HCG+BAY6QWuPLSmtlA==} + '@tanstack/solid-devtools@0.8.12': + resolution: {integrity: sha512-THj3KcmkPM2nqMkxt++8n28WrHHMh35JeFe8f/ZyMp99zM5ay/JYrE+tyE9NWPNhnxsOPqIUrNqwRRRK2g3Itw==} engines: {node: '>=18'} peerDependencies: solid-js: '>=1.9.7' @@ -21347,8 +23021,8 @@ packages: '@tanstack/router-core': optional: true - '@tanstack/solid-router@1.170.25': - resolution: {integrity: sha512-HCLrjNbEHXe4sDxxhJPti48RWu9qgtvRiEEkQqa9/0PAW3YlnZXc3csB0b21DGOyG9eeRCIHiJdllug8dKhhyQ==} + '@tanstack/solid-router@1.170.30': + resolution: {integrity: sha512-FozWeln6hx6o2T45gFFdkGQJxvq/LN0EUlzx7+eENy9HJH/thEBSb89KTkQahULzs9bsMOufzeXJJVgB6H9/wA==} engines: {node: '>=20.19'} peerDependencies: solid-js: ^1.9.10 @@ -21363,21 +23037,21 @@ packages: peerDependencies: solid-js: ^1.6.0 - '@tanstack/solid-virtual@3.13.36': - resolution: {integrity: sha512-9x4Eg3M+t7cY0/lswB6JnK1C/3YcsdBttUYQgSre+5zcwVJMZnp0Gy3mT++jeSN1bi7M5pxUPnAVoD1YE9DuLQ==} + '@tanstack/solid-virtual@3.13.37': + resolution: {integrity: sha512-RxJC8n/6nnFHcPvDGMg7ZkqSzCVUco4JNw3ctIChj1HjoKs5I9wt5nsU+DUVtMVEiMfizUxOAx4TPIN8SHjxUQ==} peerDependencies: solid-js: ^1.3.0 - '@tanstack/start-client-core@1.170.22': - resolution: {integrity: sha512-18gHvhrVLEmhO0qZVIJaR/y3Mb7tvC9UQnCEiooQG/aIpYg4/kqoQ06E7WUJ/0WFy4NZOkEjk8QkDQNkFED+1g==} + '@tanstack/start-client-core@1.170.27': + resolution: {integrity: sha512-Ro6ZSM0NgYKDMxM0e8qyU4mBfnld2Zb74BA/9f4i35C0Y3IAA8Zxs/DIPfOo9VRYWp5c5n5Q8dRBn2qn0vtPhQ==} engines: {node: '>=22.12.0'} '@tanstack/start-fn-stubs@1.162.0': resolution: {integrity: sha512-QWfUZ3Yo923tdQn38LyKMU8rcTw69zc+T4dAvgTWV4O56SqFRsGfS0lSWIMhJRwXIx/bvdi7nTUBDdZtTHtpTQ==} engines: {node: '>=22.12.0'} - '@tanstack/start-plugin-core@1.171.34': - resolution: {integrity: sha512-MMp5Mlt8HAtstkVKwHW6dY5w58CP/Vtq+DhXdH4mIPuOeEhFtl/BYErJCzpnq80QqbEpRxCfMZPf9ng2PzApaA==} + '@tanstack/start-plugin-core@1.171.39': + resolution: {integrity: sha512-Zyj6G4MDFLXcHYhPavhewCBo8dsxi3qvPk31zl/QtTzYzOY9rJHDDBGarKsJq20ziChmkGn/sttYqb4vGCxJDA==} engines: {node: '>=22.12.0'} peerDependencies: '@rsbuild/core': ^2.0.0 @@ -21388,12 +23062,12 @@ packages: vite: optional: true - '@tanstack/start-server-core@1.169.26': - resolution: {integrity: sha512-57Pvc00i/Y6l8+kqlV/QElVUh5onFUPeMUBDDRNwelAA4eoOmRDmfEWfVfkJNYlcAF4kt/s0mgnD58DlCgC9JA==} + '@tanstack/start-server-core@1.169.31': + resolution: {integrity: sha512-56w8l+Fao01YCrmv0hzNxL3b3FRmqLRGdE11izZNQsW+1CcSYuehAM5khWKABuI1DI/UIBLGV7BwL4Dlg0eHCw==} engines: {node: '>=22.12.0'} - '@tanstack/start-storage-context@1.167.24': - resolution: {integrity: sha512-HPltgydit1LmLJFX3BhMcXMxkmUgtWJopPUx6Eg0YTC4tVwFvUhSWCrfgtTIiGWcHd1Ah+fi6fK9BAe8Y5KZtw==} + '@tanstack/start-storage-context@1.167.29': + resolution: {integrity: sha512-8qfprC5774XMRDQlMogkfiGpFLiBf0xDG4bMFUbfkSzpCAQwpLbgGY4Zwft22O9rKYq2vUXusKAdVjvJTUEquQ==} engines: {node: '>=22.12.0'} '@tanstack/store@0.11.0': @@ -21405,8 +23079,8 @@ packages: '@tanstack/store@0.9.3': resolution: {integrity: sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==} - '@tanstack/svelte-devtools@0.1.3': - resolution: {integrity: sha512-rDk8K2q6ee6+X7qUyCpGemVsUdrT9lzL92arYjPweePHFTNMNMSm/6Pg07n1sio+T0ogwnj9IlQbFz2eSr4rcw==} + '@tanstack/svelte-devtools@0.1.6': + resolution: {integrity: sha512-Ubuqgmbl08UEhcmOumRGmp2s1aQ0YoF5tp5Hi1ZNDNkEjaIASh+jK8QMLcXisfNHDb969rgVrxqtzkmGFr933Q==} engines: {node: '>=18'} peerDependencies: svelte: '>=5.0.0' @@ -21432,18 +23106,13 @@ packages: peerDependencies: svelte: ^5.25.0 - '@tanstack/svelte-store@0.12.0': - resolution: {integrity: sha512-XhXlU3jIO/WxikfeVczRdsAvRWzsLBh8Ic6sC7nzfzvMbPut7ZSdCbE7/usfm0bMjVGMmZmyzZy2xRu73QYWAA==} - peerDependencies: - svelte: ^5.0.0 - '@tanstack/svelte-store@0.12.1': resolution: {integrity: sha512-ZFj8gyIWHZRYLv8RHp5jhnMhvw15g86KinotrUp9RfY7ygjkU3CcaMUytIdMJ4Xzq/9GqVlAphV9gFIGKRXWSw==} peerDependencies: svelte: ^5.0.0 - '@tanstack/svelte-virtual@3.13.35': - resolution: {integrity: sha512-4ur3bPzSXnZZtQWwns/ziCR9pJ/4x/AlBIeDZu96MKrRMbZBL1TQkGiO+ZaX5zCgdpXUZwJnehKzBp32KOumCQ==} + '@tanstack/svelte-virtual@3.13.36': + resolution: {integrity: sha512-q5z39QWDQriLDc0aAcDY/htR0Sg9mrItQnhXNy/DNtEDQsdkTFTR7ZnMA6idJpLwnUg6PYa8Fb9O3RcCu+H7FQ==} peerDependencies: svelte: ^3.48.0 || ^4.0.0 || ^5.0.0 @@ -21454,12 +23123,15 @@ packages: '@tanstack/virtual-core@3.17.7': resolution: {integrity: sha512-bp+v10y65sp2H7WpWfIMyxTNfl8ZVfxFTLRjPIFRryi6FV/J33z4IS53WO4pTk36KlvJ4iLiQz+oaydDC1xbcA==} + '@tanstack/virtual-core@3.17.8': + resolution: {integrity: sha512-BfEvehNpOT75r5Ksc5xW6NZuXujTfb7nlSEyVu4XHG3gdxNg1KqXruWbDewXOUaUYIo4oRbSfkjIajz4MAT8tA==} + '@tanstack/virtual-file-routes@1.162.0': resolution: {integrity: sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==} engines: {node: '>=20.19'} - '@tanstack/vue-devtools@0.2.24': - resolution: {integrity: sha512-0x5+HiPEB6hQ0cmuILtM8rDYaXQpL+xex6SfYeUokhwr4t0/YmSAsyy59auUV8L+2cow9jaU+gRGEdi00BKWZA==} + '@tanstack/vue-devtools@0.2.26': + resolution: {integrity: sha512-H4F10MzyKhvkVIBs19xyb651FOMyS+Iylf8+hhTsFw5YO1Dx69LUcQO+P8KXbLV6Eg5Miydfs67hQDUgpg3XXg==} engines: {node: '>=18'} '@tanstack/vue-form@1.33.5': @@ -21511,6 +23183,11 @@ packages: peerDependencies: vue: ^2.7.0 || ^3.0.0 + '@tanstack/vue-virtual@3.13.36': + resolution: {integrity: sha512-gKpExv4RbB9luVG+SucTXoqPZv/gzu/Yvz6BNO+8kpNxJ2x+I/ulryzl5W9BRciahZGp5Tls3Dp5XP1ztVGbMw==} + peerDependencies: + vue: ^2.7.0 || ^3.0.0 + '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} engines: {node: '>=18'} @@ -21707,9 +23384,6 @@ packages: '@types/minimatch@3.0.5': resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} - '@types/node@26.1.2': - resolution: {integrity: sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==} - '@types/node@26.2.0': resolution: {integrity: sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==} @@ -21733,8 +23407,8 @@ packages: peerDependencies: '@types/react': ^19.2.0 - '@types/react-dom@19.2.4': - resolution: {integrity: sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==} + '@types/react-dom@19.2.5': + resolution: {integrity: sha512-fMPwH9v7r/pp43yUd2/Mbiex5KouJwwR3dzHkhLREUC6764VyDsqxhAxv6OFEYR1RhjOyD1naqba8ECDBe7ZQg==} peerDependencies: '@types/react': ^19.2.0 @@ -21790,11 +23464,11 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/eslint-plugin@8.67.0': - resolution: {integrity: sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==} + '@typescript-eslint/eslint-plugin@8.68.0': + resolution: {integrity: sha512-WASHDpCm6qO5jj9g1a+8NiW5+GCkAyLReR56/4VruYmNgfUmqpxOfZ2Yfb8xGfJPWv5Qi6LSD8sXdces3vbp/Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.67.0 + '@typescript-eslint/parser': ^8.68.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' @@ -21805,8 +23479,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.67.0': - resolution: {integrity: sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==} + '@typescript-eslint/parser@8.68.0': + resolution: {integrity: sha512-fHq2VC1kpyYfvEcbiMjOpySY4WS7voEp89yAThrHRX5sm9j2lzYppCb2umFMEed4fWcyeLjHxrz0mpjNBaBxMQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -21818,14 +23492,14 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.65.0': - resolution: {integrity: sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==} + '@typescript-eslint/project-service@8.67.0': + resolution: {integrity: sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.67.0': - resolution: {integrity: sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==} + '@typescript-eslint/project-service@8.68.0': + resolution: {integrity: sha512-5GQtWZCXFcFYux955pvoS02WLc49pXNlvIxocKjS0clvwo3in1RdlzVKyiqQH9vE5AKWFLTaUgeQkOrTS+0Qxw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' @@ -21834,14 +23508,14 @@ packages: resolution: {integrity: sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/scope-manager@8.65.0': - resolution: {integrity: sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/scope-manager@8.67.0': resolution: {integrity: sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.68.0': + resolution: {integrity: sha512-T5eXpcaJNg8bhjHJ8Rjp68Vq/QBteYtTKY8TZqVNPaUbuz0f6jI9t6aDkylwvalpAB9XTTFeFOjrjXAZ3YvmVA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/tsconfig-utils@8.60.1': resolution: {integrity: sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -21860,6 +23534,12 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/tsconfig-utils@8.68.0': + resolution: {integrity: sha512-F7zrGQfiJHojPwi8vhxZQC1tWtJzvL74cK/nqri2lk8YUXvYaYwl263xOJ69jDWPUk1hmcdoayFwk9lX09npVw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/type-utils@8.60.1': resolution: {integrity: sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -21867,15 +23547,15 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.65.0': - resolution: {integrity: sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==} + '@typescript-eslint/type-utils@8.67.0': + resolution: {integrity: sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.67.0': - resolution: {integrity: sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==} + '@typescript-eslint/type-utils@8.68.0': + resolution: {integrity: sha512-X77zqoY1EjeWGs/0JNxeaMfp5C5lIz4Tw8y66F1Ne8Faq6g424sBNYM6xBAqElfGZPLpWS+CZAp0DXyKDzWiHg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -21889,28 +23569,28 @@ packages: resolution: {integrity: sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.65.0': - resolution: {integrity: sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.67.0': resolution: {integrity: sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.68.0': + resolution: {integrity: sha512-9RnpsGJjrAllCMefGVVsImJM24YurhC0Q1h4UbvivtvOqXmR/vEJge2OoE++z9m6hyg8T1Q8t5SNT6tHSbrxcg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@8.60.1': resolution: {integrity: sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/typescript-estree@8.65.0': - resolution: {integrity: sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==} + '@typescript-eslint/typescript-estree@8.67.0': + resolution: {integrity: sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/typescript-estree@8.67.0': - resolution: {integrity: sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==} + '@typescript-eslint/typescript-estree@8.68.0': + resolution: {integrity: sha512-OKKsD0tYmoNiU5PW2zehO1yO56jYOm1ShYlxon/Z0SJNidAkdVg86eg9ruRuoXf8xfnuWZGbwDsStkoXbZtIIA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' @@ -21922,15 +23602,15 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.65.0': - resolution: {integrity: sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==} + '@typescript-eslint/utils@8.67.0': + resolution: {integrity: sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.67.0': - resolution: {integrity: sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==} + '@typescript-eslint/utils@8.68.0': + resolution: {integrity: sha512-PB5gJMMOg0Q5P1tsgWtEAqQacJXq0qEqRHDX/YJ4FaTMLfZPpHB3gjl2EJuiZyPABxmj4ZQYiY9m1bdAJ5y7tQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -21940,14 +23620,14 @@ packages: resolution: {integrity: sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.65.0': - resolution: {integrity: sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.67.0': resolution: {integrity: sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.68.0': + resolution: {integrity: sha512-YR65gGdGvTUAWLldC3xLOvOzamdGzB4A5/N8rehEaHs3Zvoe39BhgY+u0SPch1OvrVTfLcc55wsSgK2NcnTS/A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@unrs/resolver-binding-android-arm-eabi@1.12.2': resolution: {integrity: sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==} cpu: [arm] @@ -22074,18 +23754,21 @@ packages: peerDependencies: vite: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@vitejs/plugin-react@6.0.5': - resolution: {integrity: sha512-BOVzne/NL162sMdResB25mUv+vWMF5NoAjNf09TeGlE7ZpszZWSD3winycicLJw72yeVsoCn/2kOhEuCvEShMA==} + '@vitejs/plugin-react@6.1.0': + resolution: {integrity: sha512-qd2BzUBehkov86WFhg0JkEFEYyCLG9uPCe6qWTY/kRlss9OvJrOF2UbIWT7p+8IzZHkEu0DNGHc4HSv+JdDLsw==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 babel-plugin-react-compiler: ^1.0.0 + oxc-transform-react: ^0.145.0 vite: ^8.0.0 peerDependenciesMeta: '@rolldown/plugin-babel': optional: true babel-plugin-react-compiler: optional: true + oxc-transform-react: + optional: true '@vitejs/plugin-vue-jsx@5.1.6': resolution: {integrity: sha512-YXvi4as2clxt6DFw5+a0tTA97ntiQXm/raR8ofNj3aNwwdlVGTiG2gp7EvfZW17P50acL/9bP0ccF4XnqNmlgA==} @@ -22101,20 +23784,20 @@ packages: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 vue: ^3.2.25 - '@vitest/coverage-v8@4.1.10': - resolution: {integrity: sha512-IM49HmthevbgAO4anp1hwtoT9wYe59w0LR00gr+eagHE+ZJ5lK4sLPeO0ubgoJcwLk6dehU3R24N+FbEEKDc8g==} + '@vitest/coverage-v8@4.1.11': + resolution: {integrity: sha512-8MVGEFnJIcdGjcbfKmeq8z0pZHH0JlVtoVZH9Q/qwUp6wyFnEJUBMrw9DCaj+ra3vShGmhavjalMIhPNxZAUcw==} peerDependencies: - '@vitest/browser': 4.1.10 - vitest: 4.1.10 + '@vitest/browser': 4.1.11 + vitest: 4.1.11 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@4.1.10': - resolution: {integrity: sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==} + '@vitest/expect@4.1.11': + resolution: {integrity: sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==} - '@vitest/mocker@4.1.10': - resolution: {integrity: sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==} + '@vitest/mocker@4.1.11': + resolution: {integrity: sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -22124,20 +23807,20 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.10': - resolution: {integrity: sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==} + '@vitest/pretty-format@4.1.11': + resolution: {integrity: sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==} - '@vitest/runner@4.1.10': - resolution: {integrity: sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==} + '@vitest/runner@4.1.11': + resolution: {integrity: sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==} - '@vitest/snapshot@4.1.10': - resolution: {integrity: sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==} + '@vitest/snapshot@4.1.11': + resolution: {integrity: sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==} - '@vitest/spy@4.1.10': - resolution: {integrity: sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==} + '@vitest/spy@4.1.11': + resolution: {integrity: sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==} - '@vitest/utils@4.1.10': - resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} + '@vitest/utils@4.1.11': + resolution: {integrity: sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==} '@volar/kit@2.4.28': resolution: {integrity: sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg==} @@ -22223,11 +23906,8 @@ packages: '@vue/devtools-api@6.6.4': resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} - '@vue/language-core@3.3.9': - resolution: {integrity: sha512-in/68oAa4BCtVY6n/nkuhLIkV8DHYd2UivedJ6cMZ6UYtlq9jaoaSNUBHYCVO44z3nKg7MdE5OBoHKt5SxeBKQ==} - - '@vue/reactivity@3.1.5': - resolution: {integrity: sha512-1tdfLmNjWG6t/CsPldh+foumYFo3cpyCHgBYQ34ylaMsJ+SNHQ1kApMIa8jN+i593zQuaw3AdWH0nJTARzCFhg==} + '@vue/language-core@3.3.11': + resolution: {integrity: sha512-QJmpliwAVpC/OxubIByPAhNzsQPRc8/gxlN2qnVzVfIMjMDz/9RnXRFoetjz5yEgXVXyp4LqhXq3V53PjmNzFw==} '@vue/reactivity@3.5.41': resolution: {integrity: sha512-rznsqKM0np0x18EjzF8x88MpEhdNsffbvFbckLL5+oUKz1BxAImEmO7J1ArRYSyo6aQaVoBDp7jEkT91OOxydA==} @@ -22241,9 +23921,6 @@ packages: '@vue/server-renderer@3.5.41': resolution: {integrity: sha512-n6hx/pNFfbD6SuyeuMVkvqox8bwf/ET9JlA/kAz/imw8sw++wkqKe2mHX5KutjPpbKE4Z56yTHszoOjGMI9igQ==} - '@vue/shared@3.1.5': - resolution: {integrity: sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==} - '@vue/shared@3.5.40': resolution: {integrity: sha512-WxnBtruIqOoV3rA4jeKDWzrYI5h7Cp4+pjwDi8kWGHz+IslhiN+wguLVVhtv2l8VoU02rzDCVfDjgCl1lNpZVg==} @@ -22775,8 +24452,8 @@ packages: alien-signals@3.2.1: resolution: {integrity: sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==} - alpinejs@3.16.1: - resolution: {integrity: sha512-QXcW8MK9JoG8GZ7vCt2cXJlcEPIA7Xk/7IQ1+L2iLp7sXcIxct0PrgidmHzK97gD9QlfUjHXPxujdZ1mC2PYVg==} + alpinejs@3.16.3: + resolution: {integrity: sha512-kLIO2JOPs5ZY3mHPH+CHHPzp89Y6Gb2luLRy+RDIb1oG9y6N5Vfc75kkEoaSOPhJqvakuPiAsnd9paNPNSZyVg==} amd-name-resolver@1.3.1: resolution: {integrity: sha512-26qTEWqZQ+cxSYygZ4Cf8tsjDBLceJahhtewxtKZA3SRa4PluuqYCuheemDQD+7Mf5B7sr+zhTDWAHDh02a1Dw==} @@ -23044,11 +24721,6 @@ packages: resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} engines: {node: ^4.5.0 || >= 5.9} - baseline-browser-mapping@2.10.34: - resolution: {integrity: sha512-IMDedajPifLnHNY0X9n8hKxRTQ6/eTHwr5bDo04WnuqxyKw6LYtQywCuuqPZwhl3aBXMvQpJov42GLCwRRdQzw==} - engines: {node: '>=6.0.0'} - hasBin: true - baseline-browser-mapping@2.11.8: resolution: {integrity: sha512-zAgkquC2WYF0PIc6XbNYkA2uuxxFavzgmX61R+dHDUa558V8Ejf8ozTZFR6QzM24RWu4kBcRkhJ5kpz77j9fnQ==} engines: {node: '>=6.0.0'} @@ -23082,8 +24754,8 @@ packages: birecord@0.1.2: resolution: {integrity: sha512-5PAPTTmMpMEb+GuMb5DebfBkipRGyIW9+gtwEBSoDA9xkhHILm04+hZQ702pMksu3d8YAuGkmgTzQWcKqTPScA==} - bits-ui@2.18.1: - resolution: {integrity: sha512-KkemzKFH4T3gt3H+P86JcnAWExjByv/6vlwjm/BoCwTPHu03yiCdxbghdJLvFReQTe0acCAiRcKfmixxD6XvlA==} + bits-ui@2.19.0: + resolution: {integrity: sha512-dHDm5Jw2NZJgLRvHAwPeuR4BnZij+AqTIq33OqVfo+qiMXontoC/yIvGT5TZaviv7OuBdJ2QUy2JPQ2yKBvF6w==} engines: {node: '>=20'} peerDependencies: '@internationalized/date': 3.12.3 @@ -23112,10 +24784,6 @@ packages: brace-expansion@2.1.1: resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==} - brace-expansion@5.0.6: - resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} - engines: {node: 18 || 20 || >=22} - brace-expansion@5.0.8: resolution: {integrity: sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==} engines: {node: 20 || >=22} @@ -23174,11 +24842,6 @@ packages: peerDependencies: browserslist: '*' - browserslist@4.28.2: - resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - browserslist@4.28.7: resolution: {integrity: sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -23238,9 +24901,6 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - caniuse-lite@1.0.30001797: - resolution: {integrity: sha512-l8xKG+gwAIExZGl9FrF7KUwuOmk6wbEPC9Xoy/RtnWv1XG0Q4LFlagaLpUv3Kiza3W/wm27zy0yWJEieYKAP6w==} - caniuse-lite@1.0.30001806: resolution: {integrity: sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==} @@ -23308,9 +24968,9 @@ packages: resolution: {integrity: sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==} engines: {node: '>=18.20'} - cli-truncate@5.2.0: - resolution: {integrity: sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==} - engines: {node: '>=20'} + cli-truncate@6.1.1: + resolution: {integrity: sha512-06p9vyLahLa4zkGcgsGxU6iEkSOiuI4fhCH6Emhe2lPAcoUv73n72DnODsnHA+5wwXGnV0n9M9/qOQJSjYhFhw==} + engines: {node: '>=22'} cli-width@4.1.0: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} @@ -23719,6 +25379,9 @@ packages: dayjs@1.11.21: resolution: {integrity: sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==} + dayjs@1.11.23: + resolution: {integrity: sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -23924,9 +25587,6 @@ packages: engines: {node: '>=0.12.18'} hasBin: true - electron-to-chromium@1.5.368: - resolution: {integrity: sha512-7RckJJK4uESJF9PxvfMWd3TGqIiieUTG4HxnKaKuIpGbcr+r2ZEB3g2gAhCP3Fqm42vJSzLfgab9eva/C4/XVw==} - electron-to-chromium@1.5.398: resolution: {integrity: sha512-AsvhAxopJGh6museTDMIjn6JpDYOfgu4RLlygomt87MUwBUqTfd/1EiPtx10/LZE8xpTvkP2E9Gafq7lkLtodQ==} @@ -23974,6 +25634,12 @@ packages: ember-estree@0.6.10: resolution: {integrity: sha512-5nItZGzvxHgoCdASQbn9qBzF4sdjSggUeZpXdihAanmYWm6XkObT/TlUvakYtoKret1/8gm0jNLwNPqZYwHtCw==} + ember-estree@0.8.0: + resolution: {integrity: sha512-FvH2jGEkcIMPDPgQLHFVSTyF5p7HscVIiJ36v6ce1C9q/6KXCcE0EB2idaGcDWlhB42I3PmLg+vLbUp2GIznBQ==} + + ember-modifier@4.3.0: + resolution: {integrity: sha512-O0rirSLQbGg0VJ/NqoQ4uN1bh2iAekZC/Ykma+FkjCM2ofrO38u+d8n3+AK6uVWeMJmogGX2KL+Is5fofoInJg==} + ember-qunit@9.1.0: resolution: {integrity: sha512-dE32lSODyv4em0ACBS8PDzrAIPKR75hhSpn/au0qFBlzbdmNA/VVsgv2aoFAVRdlQ0zYJ8EiNPFqsBFciIeXVA==} peerDependencies: @@ -24126,8 +25792,8 @@ packages: resolution: {integrity: sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==} engines: {node: '>= 0.4'} - esbuild-wasm@0.28.1: - resolution: {integrity: sha512-p/GD4E8oYRjg3kjdKrnMb0s4PzXgJF42e0MF4H0+ACyK/kIlFRp3e0fzOleIG+wBBm6MM3XQrbpe7soEA+vJIA==} + esbuild-wasm@0.28.2: + resolution: {integrity: sha512-GccVwhv3mmOUVQHCQm2Ox/rby8n/EqUwvZxE6Pjfikrq/lWw9g9WX/u9EykWnpot3Ko6j426DgQdea2xWKIAQA==} engines: {node: '>=18'} hasBin: true @@ -24136,6 +25802,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -24229,8 +25900,8 @@ packages: peerDependencies: eslint: '>=7' - eslint-plugin-react-dom@5.18.1: - resolution: {integrity: sha512-0PakQ8iPZ2yq4zi99T28l+NlefxrE/92CpIQ1SbbFT2fqNIjRz1L+ewWIzAsMdyUUjQzcCj8domEJ36y20K8Zw==} + eslint-plugin-react-dom@5.18.6: + resolution: {integrity: sha512-xco47I0Agu+83QH2ONbgZd1JPLSXJON+gtFGJbOhgfPvetfO7UkcHu8iLpncopwyWekAXfhvomJsDlNLTm26/g==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' @@ -24242,36 +25913,36 @@ packages: peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 - eslint-plugin-react-jsx@5.18.1: - resolution: {integrity: sha512-bT8/pcYwp1Anyjnvjqz1jRJBGdo4ydXlR6hciyQUiHzOxAWpIOP61ggAVgbA9JU3qOr4/hldMpGZHdJP5pqfgw==} + eslint-plugin-react-jsx@5.18.6: + resolution: {integrity: sha512-6EvzS5gZGfQ0byvSxgqV/F0qXTVnNGcCU7wgFZqz8I1IXmcbYyBCyU7gqNlKW1/1ptiZFmuwo57+eW6HyK+wEg==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - eslint-plugin-react-naming-convention@5.18.1: - resolution: {integrity: sha512-fN6U+Q5QOZ7ZJlTn7XsKB0NvRx0qDp+7tV2Zht3nhtKQ2tl4cxFz8QV78l++FqMtBtCNfxTiInuo5u5Xt8Ymjw==} + eslint-plugin-react-naming-convention@5.18.6: + resolution: {integrity: sha512-3KZkJN8XDTq6YtaYvyWJt3GQRjW3WhoVuGgLfhf0yO+8H0GW78FkesqGe//+np+pBXwPv6hck4c8ViTEQJ9qIQ==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - eslint-plugin-react-rsc@5.18.1: - resolution: {integrity: sha512-s792p16e8YNhGA3vgIseDxdrwTuNb+gHn0Gau5PsTZ42d8Zuvi3ZJWLfkAZfvMfblaDev6tSAv2fZzWB0brEIg==} + eslint-plugin-react-rsc@5.18.6: + resolution: {integrity: sha512-4mzLkRKRpN9Rr5JMeNrxkMFLHce1ikAdsjAiPOSIgYwWSsQWxHwpMTf+UfjXgfB6CcAcyKCyIe5HmOMX2kUoVQ==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - eslint-plugin-react-web-api@5.18.1: - resolution: {integrity: sha512-Az8kJEM2Bk8PhJR3UBLWBVZkir/2l+qX545PTi8Kx3JdDlK6IlU1vz69/B5tJ/YXo6cJKP3bKTqaAzcT5ikl8g==} + eslint-plugin-react-web-api@5.18.6: + resolution: {integrity: sha512-r8s39AbHZ0071XcgCMoCdNkSARftqI6U/0bBJXPioVUw+hjp0n4EB27fsc69AHzRl/NJWA1oUJb+kcqxoWMR4w==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - eslint-plugin-react-x@5.18.1: - resolution: {integrity: sha512-i0a17vUMoMhiHjcXz4IYfO42Br6xQkbu+PqVftUHM49i1bbYD+22GFMgNmKkLCMNKXZSQhocKvIKUwhMIbFTQg==} + eslint-plugin-react-x@5.18.6: + resolution: {integrity: sha512-VvxeREksTiY9Q7YnpNvQNrjapUGu43rQJXrtbjT9ADwXX5nZiyUqD7T7fkbUYfH6NPz2bYvnAmGEctIfEGTTfQ==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' @@ -24284,8 +25955,8 @@ packages: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 typescript: '>=4.8.4' - eslint-plugin-svelte@3.22.0: - resolution: {integrity: sha512-O3qn0NePTWta+1o25dIThqeEP/hEQ3VxDK2LVO8SQ5wG9umLMvulK+m1yQ4JGOb2Pkl8IB0G1lpRV/HXDXSLTQ==} + eslint-plugin-svelte@3.23.0: + resolution: {integrity: sha512-n9jRklDqy0+W834568a4ZIZTK7DHXxvvHHxxGP8nNq7N//pOZMubttskHOquyGgfTR4Z05q2NdGNlsTpIEA48w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.1 || ^9.0.0 || ^10.0.0 @@ -24342,8 +26013,8 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@10.8.1: - resolution: {integrity: sha512-wqA7W2jbsC/BnV9Iv1UZpKVFkO1AdNoSmYW8NWG4HNOBbkAMvIqDZ27pI2f07dqn583NcIC44ckjAcOXDL1QbQ==} + eslint@10.9.1: + resolution: {integrity: sha512-9VaAkDURekixUQJy0oJYl2DcN6oKMfxay7XzaGYAWQwsb6qfKf+x76R2k1L8kb1boc+FyCAaTA9GmiKaaiaF+A==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: @@ -24409,9 +26080,6 @@ packages: eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} - eventemitter3@5.0.4: - resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} - events-to-array@2.0.3: resolution: {integrity: sha512-f/qE2gImHRa4Cp2y1stEOSgw8wTFyUdVJX7G//bMwbaV9JqISFxg99NbmVQeP7YLnDUZ2un851jlaDrlpmGehQ==} engines: {node: '>=12'} @@ -24705,9 +26373,6 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - get-tsconfig@4.14.0: - resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} - get-tsconfig@4.14.1: resolution: {integrity: sha512-Dz/6HxkrxgNehhxLVeyv8sad9UzF2xBVeaKBQNDfJ5XiSXmp2gTR0eO0RWiT2NCKS5aGP9jjkOMggTN90qU50A==} @@ -25449,8 +27114,8 @@ packages: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} - knip@6.32.2: - resolution: {integrity: sha512-WXTXbmocrw7gqm1A1TQvFN0OgJ7hUSU6E1g6SPRIzzHFogUBhXByc7cYeOFVtJ2uODg7DP4VbESYBYnfbtBYsg==} + knip@6.32.3: + resolution: {integrity: sha512-wOJ1Av8PwKqFO0wU7F64vzIcUjxhrieA3Tc2lmeK9C9prpxq+TeG2ewNH5tCaBVZwXNPp6lJkrr+IhZ20iqkMA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -25669,8 +27334,8 @@ packages: linkify-it@5.0.2: resolution: {integrity: sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==} - listr2@10.2.2: - resolution: {integrity: sha512-JtNtbZj8q5BnDMR7trpwvwk3RIrANtIVzEUm8w7amp6xelLgyuq+4WZoTH913XaQAoH/cNdYhaNzBPA2U3xbDw==} + listr2@11.0.0: + resolution: {integrity: sha512-8K88S0aSrcSXdJfiZtEy5BQMnR+TyjrCGLcgAvQs6ta0NEnIm0RJ72/Pv67Jvg07cfBhDbuN74V81lSSVYEFEw==} engines: {node: '>=22.13.0'} lit-element@4.2.2: @@ -25725,9 +27390,9 @@ packages: resolution: {integrity: sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==} engines: {node: '>=18'} - log-update@6.1.0: - resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} - engines: {node: '>=18'} + log-update@8.0.0: + resolution: {integrity: sha512-lddSgOt3bPASrylL54ZSpy8nBHns+vBVSoILlVOx+dei300pnLRN958rj/EdlVLKuWlSESU3qdnDZdAI7FXYGg==} + engines: {node: '>=22'} loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} @@ -25746,8 +27411,8 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lucide-react@1.31.0: - resolution: {integrity: sha512-G8u2eEtoHUnUa9f8lbvqDhCiORMnYLdUEo06EEG9MQvHQrInKcX3Pa2TH39MM5qyzRcWETxB0+aOwAPI1g1kEg==} + lucide-react@1.34.0: + resolution: {integrity: sha512-vnjGJNI7Htk5+oWW8gXGuaLgwgAb0T6/iZbBrp9JCfRFwdNWZ0YTm3eyxjOLgwN6r8iyAf3UA70zNmBRBNv7yg==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -26025,11 +27690,6 @@ packages: resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} engines: {node: ^20.17.0 || >=22.9.0} - nanoid@3.3.16: - resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - nanoid@3.3.18: resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -26110,10 +27770,6 @@ packages: node-html-parser@6.1.13: resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} - node-releases@2.0.47: - resolution: {integrity: sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==} - engines: {node: '>=18'} - node-releases@2.0.51: resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==} engines: {node: '>=18'} @@ -26192,10 +27848,6 @@ packages: obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} - obug@2.1.3: - resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} - engines: {node: '>=12.20.0'} - obug@2.1.4: resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==} engines: {node: '>=12.20.0'} @@ -26581,10 +28233,6 @@ packages: postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.19: - resolution: {integrity: sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ==} - engines: {node: ^10 || ^12 || >=14} - postcss@8.5.25: resolution: {integrity: sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==} engines: {node: ^10 || ^12 || >=14} @@ -26614,8 +28262,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier-plugin-ember-template-tag@2.1.7: - resolution: {integrity: sha512-NQS/a03LCefDbOJ1o0NeN+4VdfZRJt6NBp6/5yLMXTQ2TNT4fkcbhfXkvcgl7lN9nmssm6GweX51G/CAEvtazg==} + prettier-plugin-ember-template-tag@2.1.8: + resolution: {integrity: sha512-ioLdBFoZ11kuiuFF9/bGwHgzjiU3vQVOF1rQhcuEqGc1jmKBH+G3i3BL2yHGum2Z2IQOE/7MPstYo5iAU0Uhlw==} engines: {node: 18.* || >= 20} peerDependencies: prettier: '>= 3.0.0' @@ -26703,8 +28351,8 @@ packages: prr@1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} - publint@0.3.23: - resolution: {integrity: sha512-5MQipUPcB7MWw84zLUkHrg/H/UBtk3LL+A0GngTTBSsiNJLQurMUaSIRG3edlOrRz4UFe0AOKK9TZdIWviV+jQ==} + publint@0.3.24: + resolution: {integrity: sha512-9zS56KrKBoqi5Qt8h92uMP8TTM9AYZSgnmCo4u2priMqkOZvQnTsziZ2p5LJ2ywbYkAjoCDp2jda9u4cgFefIw==} engines: {node: '>=18'} hasBin: true @@ -26974,8 +28622,8 @@ packages: resolution: {integrity: sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==} hasBin: true - reka-ui@2.10.3: - resolution: {integrity: sha512-nJGZbwcha8AcP2wbnjodfzsciTKBqp1mIzepC9Pi2xDI/YK3++ej3vpJOSPyxqrkq1Oorj4K+BdJkbVCV6x6ag==} + reka-ui@2.10.4: + resolution: {integrity: sha512-kbS5GAbkHkYj0EVKAg5ZPEPndhBjeUFSa1Aq5m5ftQwyHnB1v5tw8X6fcwfKH/ry3StPXblMWM1DW82MVS71cw==} peerDependencies: vue: '>= 3.4.0' @@ -27061,9 +28709,6 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rfdc@1.4.1: - resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rimraf@2.7.1: resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} deprecated: Rimraf versions prior to v4 are no longer supported @@ -27117,6 +28762,11 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + rolldown@1.2.6: + resolution: {integrity: sha512-vMM4q3aixf46GiF1Kok8jDPFsEpXgFWGjUHXNkNHNm+Y2adXAG2dbX91jkti3i0ZRsOlcmbuzAz1poObSHCmUA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rollup-plugin-copy-assets@2.0.3: resolution: {integrity: sha512-ETShhQGb9SoiwcNrvb3BhUNSGR89Jao0+XxxfzzLW1YsUzx8+rMO4z9oqWWmo6OHUmfNQRvqRj0cAyPkS9lN9w==} peerDependencies: @@ -27129,8 +28779,8 @@ packages: rollup: ^3.29.4 || ^4 typescript: ^4.5 || ^5.0 || ^6.0 - rollup@4.62.4: - resolution: {integrity: sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==} + rollup@4.63.0: + resolution: {integrity: sha512-T5vnZ2y4QqC3/4P+w2+JO+Q/OVdnPsv4XcSYJYMEn0R9/jjl5AgLwO9LAZMzP2lN71O6pypn91rB7lDstUkfrQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -27453,13 +29103,9 @@ packages: engines: {node: ^22.18.0 || ^24.0.0 || >=26.0.0} hasBin: true - slice-ansi@7.1.2: - resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} - engines: {node: '>=18'} - - slice-ansi@8.0.0: - resolution: {integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==} - engines: {node: '>=20'} + slice-ansi@9.0.0: + resolution: {integrity: sha512-SO/3iYL5S3W57LLEniscOGPZgOqZUPCx6d3dB+52B80yJ0XstzsC/eV8gnA4tM3MHDrKz+OCFSLNjswdSC+/bA==} + engines: {node: '>=22'} smol-toml@1.6.1: resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==} @@ -27489,6 +29135,9 @@ packages: solid-js@1.9.14: resolution: {integrity: sha512-sAEXC0Kk0S1EDg+8ysEWJDbYhA3RRoEjwuySUGlKIemeo0I5YZfOyumNjNs9Sv3y2nmhD+0rW66ag2HsMuQiGQ==} + solid-js@1.9.15: + resolution: {integrity: sha512-EeiY2xfpZJqPLjXspVEKjAII4yv8NyG//NxZ3IpOFHdUNnnTyL0uJOeS9LWGvA7cFCz5y94cjFwYlmw5Luncsg==} + solid-refresh@0.6.3: resolution: {integrity: sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==} peerDependencies: @@ -27678,8 +29327,8 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - svelte-check@4.7.4: - resolution: {integrity: sha512-IW9ot9YqAoyv8FvyN+eb4ZTe8zgcKZrJLNYU6dzSKkGwEBsSPc4K7lmQ8bKn8W2YMXM6WDfZSSVOaGtekyUfOQ==} + svelte-check@4.7.6: + resolution: {integrity: sha512-t2scM//ZuVbSY/T2w6FSBw1v9s2NEmh/g+sy1lqtosW5ylBV5AF4wFb1Ts9Kf3MbfPDUDJDZ9L436YT0SPTdvw==} engines: {node: '>= 18.0.0'} hasBin: true peerDependencies: @@ -27707,8 +29356,8 @@ packages: svelte: ^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0 typescript: ^4.9.4 || ^5.0.0 || ^6.0.0 - svelte@5.56.8: - resolution: {integrity: sha512-PY8LOw7xP6c8IOiVqdo0sbbZVYhXRSfklOQLAUyGBKqjTX0wx/z4l/9J+PmBpmlLnxzEb1NqltxQ5/wZme/Cmg==} + svelte@5.56.10: + resolution: {integrity: sha512-Lcxbj8I/KAbpY+VjtY4ENQBV0dDCipfGAhqb51XQZ67CIQqXgsv/8dPkbILaj4Fb6/b6JAEM/PIVbILXgDQy2g==} engines: {node: '>=18'} svg-tags@1.0.0: @@ -28007,8 +29656,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - typescript-eslint@8.67.0: - resolution: {integrity: sha512-S2udFs8tCKEKffuJ4TB1idGUZiXdCPGi3IPBGWXarbLQ5UPXORV8QEVzJ4gCRduURMb5EkpNCdjbk0eDIuI8Yg==} + typescript-eslint@8.68.0: + resolution: {integrity: sha512-MHy0Y0ynqeEbx/S45+i/bBssdy3X6KNBfmJAP35GrgtNxu2TQ5K5xsFDhAnmsq1jvpdoZOPG1LGtJo0HWqYCrQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -28227,13 +29876,13 @@ packages: yaml: optional: true - vite@8.2.1: - resolution: {integrity: sha512-EU/eS7BH3XROHh2YnBefjM6DBKA6ZeMZEYQbj7NLWg5wHYlhB8B/Mayd5XsgWq+NFYccDOTemRpdETWR6Ka/lw==} + vite@8.2.2: + resolution: {integrity: sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.4.0 + '@vitejs/devtools': ^0.4.0 || ^0.5.0 esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' less: ^4.0.0 @@ -28278,20 +29927,20 @@ packages: vite: optional: true - vitest@4.1.10: - resolution: {integrity: sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==} + vitest@4.1.11: + resolution: {integrity: sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.10 - '@vitest/browser-preview': 4.1.10 - '@vitest/browser-webdriverio': 4.1.10 - '@vitest/coverage-istanbul': 4.1.10 - '@vitest/coverage-v8': 4.1.10 - '@vitest/ui': 4.1.10 + '@vitest/browser-playwright': 4.1.11 + '@vitest/browser-preview': 4.1.11 + '@vitest/browser-webdriverio': 4.1.11 + '@vitest/coverage-istanbul': 4.1.11 + '@vitest/coverage-v8': 4.1.11 + '@vitest/ui': 4.1.11 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -28394,8 +30043,8 @@ packages: peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - vue-tsc@3.3.9: - resolution: {integrity: sha512-TS3Y1ux/IRoE8OCP2PpACAeOseuIs0UvWrcr7u+w3PmfY+SlCfEf8zjrBgnQksHUgLpthi5vHlffcQTQTdPBZA==} + vue-tsc@3.3.11: + resolution: {integrity: sha512-gOb0B9rtU2+f1dszwPqSH5kAieIF9ReeLhD3kSRNHv5WZZUQz/JdVXW0RTdqhNTMlQkqKzrTTviqKr/4FYZraQ==} hasBin: true peerDependencies: typescript: '>=5.0.0' @@ -28483,10 +30132,6 @@ packages: resolution: {integrity: sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==} engines: {node: '>=18.0.0'} - webpack-sources@3.5.0: - resolution: {integrity: sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==} - engines: {node: '>=10.13.0'} - webpack-sources@3.5.1: resolution: {integrity: sha512-jyuiGJdtvY434z5bUZrjz67v76/ePNvFZTp9Mdz29IlH4+GPsgyGjiv0fKI+M7BdkU6ADjulUcKAd3tUK3WlEw==} engines: {node: '>=10.13.0'} @@ -28686,6 +30331,10 @@ packages: resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yargs@18.1.0: + resolution: {integrity: sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -28782,42 +30431,42 @@ snapshots: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 - '@analogjs/vite-plugin-angular@2.7.0(@angular-devkit/build-angular@22.1.2(d03b5bb02029a616bfe59858a9b5776f))(@angular/build@22.1.2(0b302439204a1b184ed0f1b31fd67e96))(@angular/compiler@22.1.1)(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': + '@analogjs/vite-plugin-angular@2.7.1(@angular-devkit/build-angular@22.1.6(2828c779ce3b028972f8555a72f25fb0))(@angular/build@22.1.6(024014ee1152fb75104fa34d053c7f64))(@angular/compiler@22.1.1)(@emnapi/core@2.0.0-alpha.4)(@emnapi/runtime@2.0.0-alpha.4)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': dependencies: magic-string: 0.30.21 obug: 2.1.4 - oxc-parser: 0.121.0(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3) + oxc-parser: 0.121.0(@emnapi/core@2.0.0-alpha.4)(@emnapi/runtime@2.0.0-alpha.4) tinyglobby: 0.2.17 optionalDependencies: - '@angular-devkit/build-angular': 22.1.2(d03b5bb02029a616bfe59858a9b5776f) - '@angular/build': 22.1.2(0b302439204a1b184ed0f1b31fd67e96) + '@angular-devkit/build-angular': 22.1.6(2828c779ce3b028972f8555a72f25fb0) + '@angular/build': 22.1.6(024014ee1152fb75104fa34d053c7f64) '@angular/compiler': 22.1.1 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' - '@analogjs/vitest-angular@2.7.0(@analogjs/vite-plugin-angular@2.7.0(@angular-devkit/build-angular@22.1.2(d03b5bb02029a616bfe59858a9b5776f))(@angular/build@22.1.2(0b302439204a1b184ed0f1b31fd67e96))(@angular/compiler@22.1.1)(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(@angular-devkit/architect@0.2201.2(chokidar@5.0.0))(@angular-devkit/schematics@22.1.2(chokidar@5.0.0))(vitest@4.1.10)': + '@analogjs/vitest-angular@2.7.1(@analogjs/vite-plugin-angular@2.7.1(@angular-devkit/build-angular@22.1.6(2828c779ce3b028972f8555a72f25fb0))(@angular/build@22.1.6(024014ee1152fb75104fa34d053c7f64))(@angular/compiler@22.1.1)(@emnapi/core@2.0.0-alpha.4)(@emnapi/runtime@2.0.0-alpha.4)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(@angular-devkit/architect@0.2201.6(chokidar@5.0.0))(@angular-devkit/schematics@22.1.6(chokidar@5.0.0))(vitest@4.1.11)': dependencies: - '@analogjs/vite-plugin-angular': 2.7.0(@angular-devkit/build-angular@22.1.2(d03b5bb02029a616bfe59858a9b5776f))(@angular/build@22.1.2(0b302439204a1b184ed0f1b31fd67e96))(@angular/compiler@22.1.1)(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) - '@angular-devkit/architect': 0.2201.2(chokidar@5.0.0) - '@angular-devkit/schematics': 22.1.2(chokidar@5.0.0) - vitest: 4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@analogjs/vite-plugin-angular': 2.7.1(@angular-devkit/build-angular@22.1.6(2828c779ce3b028972f8555a72f25fb0))(@angular/build@22.1.6(024014ee1152fb75104fa34d053c7f64))(@angular/compiler@22.1.1)(@emnapi/core@2.0.0-alpha.4)(@emnapi/runtime@2.0.0-alpha.4)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@angular-devkit/architect': 0.2201.6(chokidar@5.0.0) + '@angular-devkit/schematics': 22.1.6(chokidar@5.0.0) + vitest: 4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) - '@angular-devkit/architect@0.2201.2(chokidar@5.0.0)': + '@angular-devkit/architect@0.2201.6(chokidar@5.0.0)': dependencies: - '@angular-devkit/core': 22.1.2(chokidar@5.0.0) + '@angular-devkit/core': 22.1.6(chokidar@5.0.0) rxjs: 7.8.2 transitivePeerDependencies: - chokidar - '@angular-devkit/build-angular@22.1.2(606360f3438ba79468f86dfc05103714)': + '@angular-devkit/build-angular@22.1.6(2828c779ce3b028972f8555a72f25fb0)': dependencies: '@ampproject/remapping': 2.3.0 - '@angular-devkit/architect': 0.2201.2(chokidar@5.0.0) - '@angular-devkit/build-webpack': 0.2201.2(chokidar@5.0.0)(webpack-dev-server@5.2.6(debug@4.4.3(supports-color@7.2.0))(supports-color@8.1.1)(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) - '@angular-devkit/core': 22.1.2(chokidar@5.0.0) - '@angular/build': 22.1.2(600b68b74c5a5d3d3c143d1ae1ff9706) + '@angular-devkit/architect': 0.2201.6(chokidar@5.0.0) + '@angular-devkit/build-webpack': 0.2201.6(chokidar@5.0.0)(webpack-dev-server@5.2.6(debug@4.4.3(supports-color@7.2.0))(supports-color@8.1.1)(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) + '@angular-devkit/core': 22.1.6(chokidar@5.0.0) + '@angular/build': 22.1.6(a773e405eb84736ce1b30c5697aedeb8) '@angular/compiler-cli': 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) '@babel/core': 8.0.1 '@babel/generator': 8.0.0 @@ -28829,51 +30478,51 @@ snapshots: '@babel/preset-env': 8.0.2(@babel/core@8.0.1) '@babel/runtime': 8.0.0 '@discoveryjs/json-ext': 1.1.0 - '@ngtools/webpack': 22.1.2(@angular/compiler-cli@22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3))(typescript@6.0.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + '@ngtools/webpack': 22.1.6(@angular/compiler-cli@22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3))(typescript@6.0.3)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) ansi-colors: 4.1.3 - autoprefixer: 10.5.4(postcss@8.5.19) - babel-loader: 10.1.1(@babel/core@8.0.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) - browserslist: 4.28.2 - copy-webpack-plugin: 14.0.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) - css-loader: 7.1.4(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) - esbuild-wasm: 0.28.1 + autoprefixer: 10.5.4(postcss@8.5.25) + babel-loader: 10.1.1(@babel/core@8.0.1)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) + browserslist: 4.28.7 + copy-webpack-plugin: 14.0.0(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) + css-loader: 7.1.4(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) + esbuild-wasm: 0.28.2 http-proxy-middleware: 4.2.0(supports-color@8.1.1) istanbul-lib-instrument: 6.0.3(supports-color@8.1.1) jsonc-parser: 3.3.1 karma-source-map-support: 1.4.0 less: 4.6.7 - less-loader: 13.0.0(less@4.6.7)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) - license-webpack-plugin: 4.0.2(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + less-loader: 13.0.0(less@4.6.7)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) + license-webpack-plugin: 4.0.2(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) loader-utils: 3.3.1 - mini-css-extract-plugin: 2.10.2(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + mini-css-extract-plugin: 2.10.2(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) open: 11.0.0 ora: 9.4.1 picomatch: 4.0.5 piscina: 5.2.0 - postcss: 8.5.19 - postcss-loader: 8.2.1(postcss@8.5.19)(typescript@6.0.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + postcss: 8.5.25 + postcss-loader: 8.2.1(postcss@8.5.25)(typescript@6.0.3)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) resolve-url-loader: 5.0.0 rxjs: 7.8.2 sass: 1.101.0 - sass-loader: 17.0.0(sass@1.101.0)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + sass-loader: 17.0.0(sass@1.101.0)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) semver: 7.8.5 - source-map-loader: 5.0.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + source-map-loader: 5.0.0(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) source-map-support: 0.5.21 terser: 5.49.0 tinyglobby: 0.2.17 tslib: 2.8.1 typescript: 6.0.3 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) - webpack-dev-middleware: 8.0.3(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) - webpack-dev-server: 5.2.6(debug@4.4.3(supports-color@7.2.0))(supports-color@8.1.1)(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) + webpack-dev-middleware: 8.0.3(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) + webpack-dev-server: 5.2.6(debug@4.4.3(supports-color@7.2.0))(supports-color@8.1.1)(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) webpack-merge: 6.0.1 - webpack-subresource-integrity: 5.1.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + webpack-subresource-integrity: 5.1.0(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) optionalDependencies: '@angular/core': 22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2) '@angular/platform-browser': 22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) '@angular/platform-server': 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/compiler@22.1.1)(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) - '@angular/ssr': 22.1.2(874fc147373d2913205073a55aa65479) - esbuild: 0.28.1 + '@angular/ssr': 22.1.6(874fc147373d2913205073a55aa65479) + esbuild: 0.28.2 ng-packagr: 22.1.1(@angular/compiler-cli@22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3))(tailwindcss@4.3.3)(tslib@2.8.1)(typescript@6.0.3) tailwindcss: 4.3.3 transitivePeerDependencies: @@ -28907,14 +30556,15 @@ snapshots: - vitest - webpack-cli - yaml + optional: true - '@angular-devkit/build-angular@22.1.2(d03b5bb02029a616bfe59858a9b5776f)': + '@angular-devkit/build-angular@22.1.6(35a4b302a500827ad46859b04c2b40f3)': dependencies: '@ampproject/remapping': 2.3.0 - '@angular-devkit/architect': 0.2201.2(chokidar@5.0.0) - '@angular-devkit/build-webpack': 0.2201.2(chokidar@5.0.0)(webpack-dev-server@5.2.6(debug@4.4.3(supports-color@7.2.0))(supports-color@8.1.1)(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) - '@angular-devkit/core': 22.1.2(chokidar@5.0.0) - '@angular/build': 22.1.2(c97137312ea58da1f91f849b3847e053) + '@angular-devkit/architect': 0.2201.6(chokidar@5.0.0) + '@angular-devkit/build-webpack': 0.2201.6(chokidar@5.0.0)(webpack-dev-server@5.2.6(debug@4.4.3(supports-color@7.2.0))(supports-color@8.1.1)(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) + '@angular-devkit/core': 22.1.6(chokidar@5.0.0) + '@angular/build': 22.1.6(e744d2f495b304c3ce1de678488cb1ba) '@angular/compiler-cli': 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) '@babel/core': 8.0.1 '@babel/generator': 8.0.0 @@ -28926,51 +30576,51 @@ snapshots: '@babel/preset-env': 8.0.2(@babel/core@8.0.1) '@babel/runtime': 8.0.0 '@discoveryjs/json-ext': 1.1.0 - '@ngtools/webpack': 22.1.2(@angular/compiler-cli@22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3))(typescript@6.0.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + '@ngtools/webpack': 22.1.6(@angular/compiler-cli@22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3))(typescript@6.0.3)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) ansi-colors: 4.1.3 - autoprefixer: 10.5.4(postcss@8.5.19) - babel-loader: 10.1.1(@babel/core@8.0.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) - browserslist: 4.28.2 - copy-webpack-plugin: 14.0.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) - css-loader: 7.1.4(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) - esbuild-wasm: 0.28.1 + autoprefixer: 10.5.4(postcss@8.5.25) + babel-loader: 10.1.1(@babel/core@8.0.1)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) + browserslist: 4.28.7 + copy-webpack-plugin: 14.0.0(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) + css-loader: 7.1.4(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) + esbuild-wasm: 0.28.2 http-proxy-middleware: 4.2.0(supports-color@8.1.1) istanbul-lib-instrument: 6.0.3(supports-color@8.1.1) jsonc-parser: 3.3.1 karma-source-map-support: 1.4.0 less: 4.6.7 - less-loader: 13.0.0(less@4.6.7)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) - license-webpack-plugin: 4.0.2(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + less-loader: 13.0.0(less@4.6.7)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) + license-webpack-plugin: 4.0.2(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) loader-utils: 3.3.1 - mini-css-extract-plugin: 2.10.2(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + mini-css-extract-plugin: 2.10.2(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) open: 11.0.0 ora: 9.4.1 picomatch: 4.0.5 piscina: 5.2.0 - postcss: 8.5.19 - postcss-loader: 8.2.1(postcss@8.5.19)(typescript@6.0.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + postcss: 8.5.25 + postcss-loader: 8.2.1(postcss@8.5.25)(typescript@6.0.3)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) resolve-url-loader: 5.0.0 rxjs: 7.8.2 sass: 1.101.0 - sass-loader: 17.0.0(sass@1.101.0)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + sass-loader: 17.0.0(sass@1.101.0)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) semver: 7.8.5 - source-map-loader: 5.0.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + source-map-loader: 5.0.0(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) source-map-support: 0.5.21 terser: 5.49.0 tinyglobby: 0.2.17 tslib: 2.8.1 typescript: 6.0.3 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) - webpack-dev-middleware: 8.0.3(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) - webpack-dev-server: 5.2.6(debug@4.4.3(supports-color@7.2.0))(supports-color@8.1.1)(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) + webpack-dev-middleware: 8.0.3(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) + webpack-dev-server: 5.2.6(debug@4.4.3(supports-color@7.2.0))(supports-color@8.1.1)(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) webpack-merge: 6.0.1 - webpack-subresource-integrity: 5.1.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + webpack-subresource-integrity: 5.1.0(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) optionalDependencies: '@angular/core': 22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2) '@angular/platform-browser': 22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) '@angular/platform-server': 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/compiler@22.1.1)(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) - '@angular/ssr': 22.1.2(874fc147373d2913205073a55aa65479) - esbuild: 0.28.1 + '@angular/ssr': 22.1.6(874fc147373d2913205073a55aa65479) + esbuild: 0.28.2 ng-packagr: 22.1.1(@angular/compiler-cli@22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3))(tailwindcss@4.3.3)(tslib@2.8.1)(typescript@6.0.3) tailwindcss: 4.3.3 transitivePeerDependencies: @@ -29004,18 +30654,17 @@ snapshots: - vitest - webpack-cli - yaml - optional: true - '@angular-devkit/build-webpack@0.2201.2(chokidar@5.0.0)(webpack-dev-server@5.2.6(debug@4.4.3(supports-color@7.2.0))(supports-color@8.1.1)(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3))': + '@angular-devkit/build-webpack@0.2201.6(chokidar@5.0.0)(webpack-dev-server@5.2.6(debug@4.4.3(supports-color@7.2.0))(supports-color@8.1.1)(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3))': dependencies: - '@angular-devkit/architect': 0.2201.2(chokidar@5.0.0) + '@angular-devkit/architect': 0.2201.6(chokidar@5.0.0) rxjs: 7.8.2 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) - webpack-dev-server: 5.2.6(debug@4.4.3(supports-color@7.2.0))(supports-color@8.1.1)(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) + webpack-dev-server: 5.2.6(debug@4.4.3(supports-color@7.2.0))(supports-color@8.1.1)(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) transitivePeerDependencies: - chokidar - '@angular-devkit/core@22.1.2(chokidar@5.0.0)': + '@angular-devkit/core@22.1.6(chokidar@5.0.0)': dependencies: ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) @@ -29026,9 +30675,9 @@ snapshots: optionalDependencies: chokidar: 5.0.0 - '@angular-devkit/schematics@22.1.2(chokidar@5.0.0)': + '@angular-devkit/schematics@22.1.6(chokidar@5.0.0)': dependencies: - '@angular-devkit/core': 22.1.2(chokidar@5.0.0) + '@angular-devkit/core': 22.1.6(chokidar@5.0.0) jsonc-parser: 3.3.1 magic-string: 1.0.0 ora: 9.4.1 @@ -29041,23 +30690,23 @@ snapshots: '@angular/core': 22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2) tslib: 2.8.1 - '@angular/build@22.1.2(0b302439204a1b184ed0f1b31fd67e96)': + '@angular/build@22.1.6(024014ee1152fb75104fa34d053c7f64)': dependencies: '@ampproject/remapping': 2.3.0 - '@angular-devkit/architect': 0.2201.2(chokidar@5.0.0) + '@angular-devkit/architect': 0.2201.6(chokidar@5.0.0) '@angular/compiler': 22.1.1 '@angular/compiler-cli': 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) '@babel/core': 8.0.1 '@babel/helper-annotate-as-pure': 8.0.0 '@babel/helper-split-export-declaration': 7.24.7 '@inquirer/confirm': 6.1.1(@types/node@26.2.0) - '@vitejs/plugin-basic-ssl': 2.3.0(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@vitejs/plugin-basic-ssl': 2.3.0(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) beasties: 0.4.3 - browserslist: 4.28.2 - esbuild: 0.28.1 + browserslist: 4.28.7 + esbuild: 0.28.2 https-proxy-agent: 9.1.0(supports-color@8.1.1) jsonc-parser: 3.3.1 - listr2: 10.2.2 + listr2: 11.0.0 magic-string: 1.0.0 mrmime: 2.0.1 oxc-parser: 0.142.0 @@ -29071,140 +30720,21 @@ snapshots: tinyglobby: 0.2.17 tslib: 2.8.1 typescript: 6.0.3 - vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) watchpack: 2.5.2 optionalDependencies: '@angular/core': 22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2) '@angular/platform-browser': 22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) '@angular/platform-server': 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/compiler@22.1.1)(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) - '@angular/ssr': 22.1.2(874fc147373d2913205073a55aa65479) + '@angular/ssr': 22.1.6(874fc147373d2913205073a55aa65479) istanbul-lib-instrument: 6.0.3(supports-color@8.1.1) less: 4.6.7 lmdb: 3.5.6 ng-packagr: 22.1.1(@angular/compiler-cli@22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3))(tailwindcss@4.3.3)(tslib@2.8.1)(typescript@6.0.3) postcss: 8.5.26 - rollup: 4.62.4 - tailwindcss: 4.3.3 - vitest: 4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) - transitivePeerDependencies: - - '@types/node' - - '@vitejs/devtools' - - chokidar - - jiti - - kerberos - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - optional: true - - '@angular/build@22.1.2(273b611b619075aa5982f3d91848666a)': - dependencies: - '@ampproject/remapping': 2.3.0 - '@angular-devkit/architect': 0.2201.2(chokidar@5.0.0) - '@angular/compiler': 22.1.1 - '@angular/compiler-cli': 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) - '@babel/core': 8.0.1 - '@babel/helper-annotate-as-pure': 8.0.0 - '@babel/helper-split-export-declaration': 7.24.7 - '@inquirer/confirm': 6.1.1(@types/node@26.1.2) - '@vitejs/plugin-basic-ssl': 2.3.0(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0)) - beasties: 0.4.3 - browserslist: 4.28.2 - esbuild: 0.28.1 - https-proxy-agent: 9.1.0(supports-color@8.1.1) - jsonc-parser: 3.3.1 - listr2: 10.2.2 - magic-string: 1.0.0 - mrmime: 2.0.1 - oxc-parser: 0.142.0 - parse5-html-rewriting-stream: 8.0.1 - picomatch: 4.0.5 - piscina: 5.2.0 - rolldown: 1.2.0 - sass: 1.101.0 - semver: 7.8.5 - source-map-support: 0.5.21 - tinyglobby: 0.2.17 - tslib: 2.8.1 - typescript: 6.0.3 - vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0) - watchpack: 2.5.2 - optionalDependencies: - '@angular/core': 22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2) - '@angular/platform-browser': 22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) - '@angular/platform-server': 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/compiler@22.1.1)(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) - '@angular/ssr': 22.1.2(874fc147373d2913205073a55aa65479) - istanbul-lib-instrument: 6.0.3(supports-color@8.1.1) - less: 4.6.7 - lmdb: 3.5.6 - ng-packagr: 22.1.1(@angular/compiler-cli@22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3))(tailwindcss@4.3.3)(tslib@2.8.1)(typescript@6.0.3) - postcss: 8.5.25 - rollup: 4.62.4 - tailwindcss: 4.3.3 - vitest: 4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0)) - transitivePeerDependencies: - - '@types/node' - - '@vitejs/devtools' - - chokidar - - jiti - - kerberos - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - '@angular/build@22.1.2(600b68b74c5a5d3d3c143d1ae1ff9706)': - dependencies: - '@ampproject/remapping': 2.3.0 - '@angular-devkit/architect': 0.2201.2(chokidar@5.0.0) - '@angular/compiler': 22.1.1 - '@angular/compiler-cli': 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) - '@babel/core': 8.0.1 - '@babel/helper-annotate-as-pure': 8.0.0 - '@babel/helper-split-export-declaration': 7.24.7 - '@inquirer/confirm': 6.1.1(@types/node@26.2.0) - '@vitejs/plugin-basic-ssl': 2.3.0(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.19))(terser@5.49.0)(yaml@2.9.0)) - beasties: 0.4.3 - browserslist: 4.28.2 - esbuild: 0.28.1 - https-proxy-agent: 9.1.0(supports-color@8.1.1) - jsonc-parser: 3.3.1 - listr2: 10.2.2 - magic-string: 1.0.0 - mrmime: 2.0.1 - oxc-parser: 0.142.0 - parse5-html-rewriting-stream: 8.0.1 - picomatch: 4.0.5 - piscina: 5.2.0 - rolldown: 1.2.0 - sass: 1.101.0 - semver: 7.8.5 - source-map-support: 0.5.21 - tinyglobby: 0.2.17 - tslib: 2.8.1 - typescript: 6.0.3 - vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.19))(terser@5.49.0)(yaml@2.9.0) - watchpack: 2.5.2 - optionalDependencies: - '@angular/core': 22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2) - '@angular/platform-browser': 22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) - '@angular/platform-server': 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/compiler@22.1.1)(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) - '@angular/ssr': 22.1.2(874fc147373d2913205073a55aa65479) - istanbul-lib-instrument: 6.0.3(supports-color@8.1.1) - less: 4.6.7 - lmdb: 3.5.6 - ng-packagr: 22.1.1(@angular/compiler-cli@22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3))(tailwindcss@4.3.3)(tslib@2.8.1)(typescript@6.0.3) - postcss: 8.5.19 - rollup: 4.62.4 + rollup: 4.63.0 tailwindcss: 4.3.3 - vitest: 4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.19))(terser@5.49.0)(yaml@2.9.0)) + vitest: 4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) transitivePeerDependencies: - '@types/node' - '@vitejs/devtools' @@ -29219,23 +30749,23 @@ snapshots: - tsx - yaml - '@angular/build@22.1.2(c49ddd1db132d78553f0a5c28aa748f0)': + '@angular/build@22.1.6(a773e405eb84736ce1b30c5697aedeb8)': dependencies: '@ampproject/remapping': 2.3.0 - '@angular-devkit/architect': 0.2201.2(chokidar@5.0.0) + '@angular-devkit/architect': 0.2201.6(chokidar@5.0.0) '@angular/compiler': 22.1.1 '@angular/compiler-cli': 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) '@babel/core': 8.0.1 '@babel/helper-annotate-as-pure': 8.0.0 '@babel/helper-split-export-declaration': 7.24.7 '@inquirer/confirm': 6.1.1(@types/node@26.2.0) - '@vitejs/plugin-basic-ssl': 2.3.0(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@vitejs/plugin-basic-ssl': 2.3.0(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) beasties: 0.4.3 - browserslist: 4.28.2 - esbuild: 0.28.1 + browserslist: 4.28.7 + esbuild: 0.28.2 https-proxy-agent: 9.1.0(supports-color@8.1.1) jsonc-parser: 3.3.1 - listr2: 10.2.2 + listr2: 11.0.0 magic-string: 1.0.0 mrmime: 2.0.1 oxc-parser: 0.142.0 @@ -29249,21 +30779,21 @@ snapshots: tinyglobby: 0.2.17 tslib: 2.8.1 typescript: 6.0.3 - vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) watchpack: 2.5.2 optionalDependencies: '@angular/core': 22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2) '@angular/platform-browser': 22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) '@angular/platform-server': 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/compiler@22.1.1)(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) - '@angular/ssr': 22.1.2(874fc147373d2913205073a55aa65479) + '@angular/ssr': 22.1.6(874fc147373d2913205073a55aa65479) istanbul-lib-instrument: 6.0.3(supports-color@8.1.1) less: 4.6.7 lmdb: 3.5.6 ng-packagr: 22.1.1(@angular/compiler-cli@22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3))(tailwindcss@4.3.3)(tslib@2.8.1)(typescript@6.0.3) postcss: 8.5.25 - rollup: 4.62.4 + rollup: 4.63.0 tailwindcss: 4.3.3 - vitest: 4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + vitest: 4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) transitivePeerDependencies: - '@types/node' - '@vitejs/devtools' @@ -29277,24 +30807,25 @@ snapshots: - terser - tsx - yaml + optional: true - '@angular/build@22.1.2(c97137312ea58da1f91f849b3847e053)': + '@angular/build@22.1.6(e744d2f495b304c3ce1de678488cb1ba)': dependencies: '@ampproject/remapping': 2.3.0 - '@angular-devkit/architect': 0.2201.2(chokidar@5.0.0) + '@angular-devkit/architect': 0.2201.6(chokidar@5.0.0) '@angular/compiler': 22.1.1 '@angular/compiler-cli': 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) '@babel/core': 8.0.1 '@babel/helper-annotate-as-pure': 8.0.0 '@babel/helper-split-export-declaration': 7.24.7 '@inquirer/confirm': 6.1.1(@types/node@26.2.0) - '@vitejs/plugin-basic-ssl': 2.3.0(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@vitejs/plugin-basic-ssl': 2.3.0(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0)) beasties: 0.4.3 - browserslist: 4.28.2 - esbuild: 0.28.1 + browserslist: 4.28.7 + esbuild: 0.28.2 https-proxy-agent: 9.1.0(supports-color@8.1.1) jsonc-parser: 3.3.1 - listr2: 10.2.2 + listr2: 11.0.0 magic-string: 1.0.0 mrmime: 2.0.1 oxc-parser: 0.142.0 @@ -29308,21 +30839,21 @@ snapshots: tinyglobby: 0.2.17 tslib: 2.8.1 typescript: 6.0.3 - vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0) watchpack: 2.5.2 optionalDependencies: '@angular/core': 22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2) '@angular/platform-browser': 22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)) '@angular/platform-server': 22.1.1(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/compiler@22.1.1)(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2) - '@angular/ssr': 22.1.2(874fc147373d2913205073a55aa65479) + '@angular/ssr': 22.1.6(874fc147373d2913205073a55aa65479) istanbul-lib-instrument: 6.0.3(supports-color@8.1.1) less: 4.6.7 lmdb: 3.5.6 ng-packagr: 22.1.1(@angular/compiler-cli@22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3))(tailwindcss@4.3.3)(tslib@2.8.1)(typescript@6.0.3) - postcss: 8.5.19 - rollup: 4.62.4 + postcss: 8.5.25 + rollup: 4.63.0 tailwindcss: 4.3.3 - vitest: 4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + vitest: 4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0)) transitivePeerDependencies: - '@types/node' - '@vitejs/devtools' @@ -29336,9 +30867,8 @@ snapshots: - terser - tsx - yaml - optional: true - '@angular/cdk@22.1.0(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2)': + '@angular/cdk@22.1.4(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@angular/platform-browser@22.1.1(@angular/animations@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(@angular/common@22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2)))(rxjs@7.8.2)': dependencies: '@angular/common': 22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2) '@angular/core': 22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2) @@ -29347,43 +30877,21 @@ snapshots: rxjs: 7.8.2 tslib: 2.8.1 - '@angular/cli@22.1.2(@types/node@26.1.2)(chokidar@5.0.0)(supports-color@8.1.1)': + '@angular/cli@22.1.6(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1)': dependencies: - '@angular-devkit/architect': 0.2201.2(chokidar@5.0.0) - '@angular-devkit/core': 22.1.2(chokidar@5.0.0) - '@angular-devkit/schematics': 22.1.2(chokidar@5.0.0) - '@inquirer/prompts': 8.5.2(@types/node@26.1.2) - '@listr2/prompt-adapter-inquirer': 4.2.4(@inquirer/prompts@8.5.2(@types/node@26.1.2))(@types/node@26.1.2)(listr2@10.2.2) - '@modelcontextprotocol/sdk': 1.29.0(supports-color@8.1.1)(zod@4.4.3) - '@schematics/angular': 22.1.2(chokidar@5.0.0) - jsonc-parser: 3.3.1 - listr2: 10.2.2 - npm-package-arg: 14.0.0 - parse5-html-rewriting-stream: 8.0.1 - semver: 7.8.5 - yargs: 18.0.0 - zod: 4.4.3 - transitivePeerDependencies: - - '@cfworker/json-schema' - - '@types/node' - - chokidar - - supports-color - - '@angular/cli@22.1.2(@types/node@26.2.0)(chokidar@5.0.0)(supports-color@8.1.1)': - dependencies: - '@angular-devkit/architect': 0.2201.2(chokidar@5.0.0) - '@angular-devkit/core': 22.1.2(chokidar@5.0.0) - '@angular-devkit/schematics': 22.1.2(chokidar@5.0.0) + '@angular-devkit/architect': 0.2201.6(chokidar@5.0.0) + '@angular-devkit/core': 22.1.6(chokidar@5.0.0) + '@angular-devkit/schematics': 22.1.6(chokidar@5.0.0) '@inquirer/prompts': 8.5.2(@types/node@26.2.0) - '@listr2/prompt-adapter-inquirer': 4.2.4(@inquirer/prompts@8.5.2(@types/node@26.2.0))(@types/node@26.2.0)(listr2@10.2.2) - '@modelcontextprotocol/sdk': 1.29.0(supports-color@8.1.1)(zod@4.4.3) - '@schematics/angular': 22.1.2(chokidar@5.0.0) + '@listr2/prompt-adapter-inquirer': 4.2.5(@inquirer/prompts@8.5.2(@types/node@26.2.0))(@types/node@26.2.0)(listr2@11.0.0) + '@modelcontextprotocol/sdk': 1.30.0(supports-color@8.1.1)(zod@4.4.3) + '@schematics/angular': 22.1.6(chokidar@5.0.0) jsonc-parser: 3.3.1 - listr2: 10.2.2 + listr2: 11.0.0 npm-package-arg: 14.0.0 parse5-html-rewriting-stream: 8.0.1 semver: 7.8.5 - yargs: 18.0.0 + yargs: 18.1.0 zod: 4.4.3 transitivePeerDependencies: - '@cfworker/json-schema' @@ -29466,7 +30974,7 @@ snapshots: rxjs: 7.8.2 tslib: 2.8.1 - '@angular/ssr@22.1.2(874fc147373d2913205073a55aa65479)': + '@angular/ssr@22.1.6(874fc147373d2913205073a55aa65479)': dependencies: '@angular/common': 22.1.1(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(rxjs@7.8.2) '@angular/core': 22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2) @@ -29650,11 +31158,11 @@ snapshots: obug: 2.1.4 semver: 7.8.5 - '@babel/eslint-parser@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))': + '@babel/eslint-parser@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))': dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) eslint-visitor-keys: 2.1.0 semver: 6.3.1 optional: true @@ -31042,17 +32550,6 @@ snapshots: '@types/react': 19.2.18 date-fns: 4.4.0 - '@base-ui/utils@0.3.1(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': - dependencies: - '@babel/runtime': 7.29.7 - '@floating-ui/utils': 0.2.11 - react: 19.2.8 - react-dom: 19.2.8(react@19.2.8) - reselect: 5.2.0 - use-sync-external-store: 1.6.0(react@19.2.8) - optionalDependencies: - '@types/react': 19.2.18 - '@base-ui/utils@0.3.2(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@babel/runtime': 7.29.7 @@ -31111,7 +32608,7 @@ snapshots: '@changesets/get-github-info': 1.0.0 '@changesets/types': 7.0.0 - '@changesets/cli@3.0.0': + '@changesets/cli@3.0.1': dependencies: '@changesets/apply-release-plan': 8.0.0 '@changesets/assemble-release-plan': 7.0.0 @@ -31124,7 +32621,7 @@ snapshots: '@changesets/read': 1.0.0 '@changesets/should-skip-package': 1.0.0 '@changesets/types': 7.0.0 - '@changesets/write': 1.0.0 + '@changesets/write': 1.0.1 '@clack/prompts': 1.7.0 '@manypkg/get-packages': 3.1.0 '@pnpm/deps.graph-sequencer': 1100.0.1 @@ -31148,7 +32645,7 @@ snapshots: '@changesets/format@0.1.1': dependencies: package-manager-detector: 1.8.0 - tinyexec: 1.2.4 + tinyexec: 1.3.0 '@changesets/get-dependents-graph@3.0.0': dependencies: @@ -31190,7 +32687,7 @@ snapshots: '@changesets/types@7.0.0': {} - '@changesets/write@1.0.0': + '@changesets/write@1.0.1': dependencies: '@changesets/format': 0.1.1 '@changesets/types': 7.0.0 @@ -31261,14 +32758,14 @@ snapshots: '@discoveryjs/json-ext@1.1.0': {} - '@dnd-kit-svelte/svelte@0.1.6(svelte@5.56.8(@typescript-eslint/types@8.67.0))': + '@dnd-kit-svelte/svelte@0.1.6(svelte@5.56.10(@typescript-eslint/types@8.68.0))': dependencies: '@dnd-kit/abstract': 0.2.4 '@dnd-kit/collision': 0.2.4 '@dnd-kit/dom': 0.2.4 '@dnd-kit/geometry': 0.1.21 '@dnd-kit/state': 0.2.4 - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) '@dnd-kit/abstract@0.1.21': dependencies: @@ -31390,20 +32887,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@embroider/addon-dev@8.3.1(@glint/template@1.8.0)(rollup@4.62.4)(supports-color@8.1.1)': + '@embroider/addon-dev@8.3.1(@glint/template@1.8.0)(rollup@4.63.0)(supports-color@8.1.1)': dependencies: '@embroider/core': 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) - '@rollup/pluginutils': 5.4.0(rollup@4.62.4) + '@rollup/pluginutils': 5.4.0(rollup@4.63.0) content-tag: 4.2.0 execa: 5.1.1 fs-extra: 10.1.0 minimatch: 3.1.5 package-up: 5.0.0 - rollup-plugin-copy-assets: 2.0.3(rollup@4.62.4) + rollup-plugin-copy-assets: 2.0.3(rollup@4.63.0) walk-sync: 3.0.0 yargs: 17.7.2 optionalDependencies: - rollup: 4.62.4 + rollup: 4.63.0 transitivePeerDependencies: - '@glint/template' - bufferutil @@ -31520,11 +33017,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@embroider/vite@1.7.8(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(@glint/template@1.8.0)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': + '@embroider/vite@1.7.10(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(@glint/template@1.8.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) '@embroider/core': 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) - '@embroider/macros': 1.20.5(@babel/core@7.29.7(supports-color@8.1.1))(@glint/template@1.8.0)(supports-color@8.1.1) + '@embroider/macros': 1.20.6(@babel/core@7.29.7(supports-color@8.1.1))(@glint/template@1.8.0)(supports-color@8.1.1) '@embroider/reverse-exports': 0.2.0 assert-never: 1.4.0 browserslist: 4.28.7 @@ -31538,7 +33035,7 @@ snapshots: send: 1.2.1(supports-color@8.1.1) source-map-url: 0.4.1 terser: 5.49.0 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) transitivePeerDependencies: - '@glint/template' - bufferutil @@ -31546,11 +33043,11 @@ snapshots: - supports-color - utf-8-validate - '@embroider/vite@1.7.9(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(@glint/template@1.8.0)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': + '@embroider/vite@1.7.8(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(@glint/template@1.8.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) '@embroider/core': 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) - '@embroider/macros': 1.20.6(@babel/core@7.29.7(supports-color@8.1.1))(@glint/template@1.8.0)(supports-color@8.1.1) + '@embroider/macros': 1.20.5(@babel/core@7.29.7(supports-color@8.1.1))(@glint/template@1.8.0)(supports-color@8.1.1) '@embroider/reverse-exports': 0.2.0 assert-never: 1.4.0 browserslist: 4.28.7 @@ -31564,7 +33061,7 @@ snapshots: send: 1.2.1(supports-color@8.1.1) source-map-url: 0.4.1 terser: 5.49.0 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) transitivePeerDependencies: - '@glint/template' - bufferutil @@ -31600,6 +33097,11 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/core@2.0.0-alpha.4': + dependencies: + '@emnapi/wasi-threads': 2.0.1 + tslib: 2.8.1 + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 @@ -31623,6 +33125,10 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/runtime@2.0.0-alpha.4': + dependencies: + tslib: 2.8.1 + '@emnapi/wasi-threads@1.0.4': dependencies: tslib: 2.8.1 @@ -31639,7 +33145,6 @@ snapshots: '@emnapi/wasi-threads@2.0.1': dependencies: tslib: 2.8.1 - optional: true '@emotion/babel-plugin@11.13.5(supports-color@7.2.0)': dependencies: @@ -31727,174 +33232,252 @@ snapshots: '@esbuild/aix-ppc64@0.28.1': optional: true + '@esbuild/aix-ppc64@0.28.2': + optional: true + '@esbuild/android-arm64@0.28.1': optional: true + '@esbuild/android-arm64@0.28.2': + optional: true + '@esbuild/android-arm@0.28.1': optional: true + '@esbuild/android-arm@0.28.2': + optional: true + '@esbuild/android-x64@0.28.1': optional: true + '@esbuild/android-x64@0.28.2': + optional: true + '@esbuild/darwin-arm64@0.28.1': optional: true + '@esbuild/darwin-arm64@0.28.2': + optional: true + '@esbuild/darwin-x64@0.28.1': optional: true + '@esbuild/darwin-x64@0.28.2': + optional: true + '@esbuild/freebsd-arm64@0.28.1': optional: true + '@esbuild/freebsd-arm64@0.28.2': + optional: true + '@esbuild/freebsd-x64@0.28.1': optional: true + '@esbuild/freebsd-x64@0.28.2': + optional: true + '@esbuild/linux-arm64@0.28.1': optional: true + '@esbuild/linux-arm64@0.28.2': + optional: true + '@esbuild/linux-arm@0.28.1': optional: true + '@esbuild/linux-arm@0.28.2': + optional: true + '@esbuild/linux-ia32@0.28.1': optional: true + '@esbuild/linux-ia32@0.28.2': + optional: true + '@esbuild/linux-loong64@0.28.1': optional: true + '@esbuild/linux-loong64@0.28.2': + optional: true + '@esbuild/linux-mips64el@0.28.1': optional: true + '@esbuild/linux-mips64el@0.28.2': + optional: true + '@esbuild/linux-ppc64@0.28.1': optional: true + '@esbuild/linux-ppc64@0.28.2': + optional: true + '@esbuild/linux-riscv64@0.28.1': optional: true + '@esbuild/linux-riscv64@0.28.2': + optional: true + '@esbuild/linux-s390x@0.28.1': optional: true + '@esbuild/linux-s390x@0.28.2': + optional: true + '@esbuild/linux-x64@0.28.1': optional: true + '@esbuild/linux-x64@0.28.2': + optional: true + '@esbuild/netbsd-arm64@0.28.1': optional: true + '@esbuild/netbsd-arm64@0.28.2': + optional: true + '@esbuild/netbsd-x64@0.28.1': optional: true + '@esbuild/netbsd-x64@0.28.2': + optional: true + '@esbuild/openbsd-arm64@0.28.1': optional: true + '@esbuild/openbsd-arm64@0.28.2': + optional: true + '@esbuild/openbsd-x64@0.28.1': optional: true + '@esbuild/openbsd-x64@0.28.2': + optional: true + '@esbuild/openharmony-arm64@0.28.1': optional: true + '@esbuild/openharmony-arm64@0.28.2': + optional: true + '@esbuild/sunos-x64@0.28.1': optional: true + '@esbuild/sunos-x64@0.28.2': + optional: true + '@esbuild/win32-arm64@0.28.1': optional: true + '@esbuild/win32-arm64@0.28.2': + optional: true + '@esbuild/win32-ia32@0.28.1': optional: true + '@esbuild/win32-ia32@0.28.2': + optional: true + '@esbuild/win32-x64@0.28.1': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))': + '@esbuild/win32-x64@0.28.2': + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))': dependencies: - eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + eslint: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.9.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))': dependencies: - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint-react/ast@5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': + '@eslint-react/ast@5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/typescript-estree': 8.65.0(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/utils': 8.65.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/typescript-estree': 8.67.0(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/utils': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) string-ts: 2.3.1 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@eslint-react/core@5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': + '@eslint-react/core@5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@eslint-react/ast': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/eslint': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/shared': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/var': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.65.0 - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/utils': 8.65.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + '@eslint-react/ast': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/eslint': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/shared': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/var': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.67.0 + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/utils': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) ts-pattern: 5.9.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@eslint-react/eslint-plugin@5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': + '@eslint-react/eslint-plugin@5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@eslint-react/shared': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) - eslint-plugin-react-dom: 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint-plugin-react-jsx: 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint-plugin-react-naming-convention: 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint-plugin-react-rsc: 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint-plugin-react-web-api: 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint-plugin-react-x: 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/shared': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) + eslint-plugin-react-dom: 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint-plugin-react-jsx: 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint-plugin-react-naming-convention: 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint-plugin-react-rsc: 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint-plugin-react-web-api: 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint-plugin-react-x: 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@eslint-react/eslint@5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': + '@eslint-react/eslint@5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@typescript-eslint/utils': 8.65.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + '@typescript-eslint/utils': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@eslint-react/jsx@5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': + '@eslint-react/jsx@5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@eslint-react/ast': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/eslint': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/shared': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/var': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/utils': 8.65.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + '@eslint-react/ast': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/eslint': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/shared': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/var': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/utils': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) ts-pattern: 5.9.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@eslint-react/shared@5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': + '@eslint-react/shared@5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@eslint-react/eslint': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/utils': 8.65.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + '@eslint-react/eslint': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/utils': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) ts-pattern: 5.9.0 typescript: 6.0.3 zod: 4.4.3 transitivePeerDependencies: - supports-color - '@eslint-react/var@5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': + '@eslint-react/var@5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@eslint-react/ast': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/eslint': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.65.0 - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/utils': 8.65.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + '@eslint-react/ast': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/eslint': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.67.0 + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/utils': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) ts-pattern: 5.9.0 typescript: 6.0.3 transitivePeerDependencies: @@ -31924,13 +33507,13 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/js@10.0.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))': + '@eslint/js@10.0.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))': optionalDependencies: - eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + eslint: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) - '@eslint/js@10.0.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))': + '@eslint/js@10.0.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))': optionalDependencies: - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) '@eslint/object-schema@3.0.5': {} @@ -31943,21 +33526,12 @@ snapshots: optionalDependencies: '@noble/hashes': 2.2.0 - '@faker-js/faker@10.5.0': {} - - '@floating-ui/core@1.7.5': - dependencies: - '@floating-ui/utils': 0.2.11 + '@faker-js/faker@10.6.0': {} '@floating-ui/core@1.8.0': dependencies: '@floating-ui/utils': 0.2.12 - '@floating-ui/dom@1.7.6': - dependencies: - '@floating-ui/core': 1.7.5 - '@floating-ui/utils': 0.2.11 - '@floating-ui/dom@1.8.0': dependencies: '@floating-ui/core': 1.8.0 @@ -31965,7 +33539,7 @@ snapshots: '@floating-ui/react-dom@2.1.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@floating-ui/dom': 1.7.6 + '@floating-ui/dom': 1.8.0 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) @@ -31977,20 +33551,18 @@ snapshots: '@floating-ui/react@0.27.19(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@floating-ui/react-dom': 2.1.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@floating-ui/utils': 0.2.11 + '@floating-ui/react-dom': 2.1.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@floating-ui/utils': 0.2.12 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) tabbable: 6.4.0 - '@floating-ui/utils@0.2.11': {} - '@floating-ui/utils@0.2.12': {} '@floating-ui/vue@1.1.11(vue@3.5.41(typescript@6.0.3))': dependencies: - '@floating-ui/dom': 1.7.6 - '@floating-ui/utils': 0.2.11 + '@floating-ui/dom': 1.8.0 + '@floating-ui/utils': 0.2.12 vue-demi: 0.14.10(vue@3.5.41(typescript@6.0.3)) transitivePeerDependencies: - '@vue/composition-api' @@ -32060,7 +33632,7 @@ snapshots: dependencies: '@glimmer/interfaces': 0.94.6 - '@glint/ember-tsc@1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3)': + '@glint/ember-tsc@1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3)': dependencies: '@glimmer/syntax': 0.95.0 '@glint/template': 1.8.0 @@ -32072,6 +33644,7 @@ snapshots: '@volar/test-utils': 2.4.28(typescript@5.9.3) '@volar/typescript': 2.4.28(typescript@5.9.3) content-tag: 4.2.0 + ember-estree: 0.8.0 silent-error: 1.1.1(supports-color@8.1.1) typescript: 5.9.3 volar-service-html: 0.0.71(@volar/language-service@2.4.28(typescript@5.9.3)) @@ -32084,7 +33657,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@glint/ember-tsc@1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': + '@glint/ember-tsc@1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': dependencies: '@glimmer/syntax': 0.95.0 '@glint/template': 1.8.0 @@ -32096,6 +33669,7 @@ snapshots: '@volar/test-utils': 2.4.28(typescript@6.0.3) '@volar/typescript': 2.4.28(typescript@6.0.3) content-tag: 4.2.0 + ember-estree: 0.8.0 silent-error: 1.1.1(supports-color@8.1.1) typescript: 6.0.3 volar-service-html: 0.0.71(@volar/language-service@2.4.28(typescript@6.0.3)) @@ -32110,9 +33684,9 @@ snapshots: '@glint/template@1.8.0': {} - '@glint/tsserver-plugin@2.7.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)': + '@glint/tsserver-plugin@2.7.3(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@glint/ember-tsc': 1.10.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) + '@glint/ember-tsc': 1.11.0(ember-source@7.2.0(@glimmer/component@2.1.1(supports-color@8.1.1))(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) '@volar/language-core': 2.4.28 '@volar/typescript': 2.4.28(typescript@5.9.3) jiti: 2.7.0 @@ -32126,10 +33700,10 @@ snapshots: '@harperfast/extended-iterable@1.0.3': optional: true - '@heroui/react@3.2.4(@react-aria/i18n@3.13.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-aria/ssr@3.10.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-aria/utils@3.34.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-spectrum/provider@3.11.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-aria-components@1.20.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-aria@3.51.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(tailwindcss@4.3.3)': + '@heroui/react@3.2.4(@react-aria/i18n@3.13.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-aria/ssr@3.10.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-aria/utils@3.34.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@react-spectrum/provider@3.11.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-aria-components@1.20.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-aria@3.51.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(tailwindcss@4.3.3)': dependencies: '@heroui/styles': 3.2.4(tailwind-merge@3.4.0)(tailwindcss@4.3.3) - '@radix-ui/react-avatar': 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-avatar': 1.1.11(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@react-aria/i18n': 3.13.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@react-aria/ssr': 3.10.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@react-aria/utils': 3.34.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -32187,15 +33761,6 @@ snapshots: '@inquirer/ansi@2.0.7': {} - '@inquirer/checkbox@5.2.1(@types/node@26.1.2)': - dependencies: - '@inquirer/ansi': 2.0.7 - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/figures': 2.0.7 - '@inquirer/type': 4.0.7(@types/node@26.1.2) - optionalDependencies: - '@types/node': 26.1.2 - '@inquirer/checkbox@5.2.1(@types/node@26.2.0)': dependencies: '@inquirer/ansi': 2.0.7 @@ -32205,13 +33770,6 @@ snapshots: optionalDependencies: '@types/node': 26.2.0 - '@inquirer/confirm@6.1.1(@types/node@26.1.2)': - dependencies: - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/type': 4.0.7(@types/node@26.1.2) - optionalDependencies: - '@types/node': 26.1.2 - '@inquirer/confirm@6.1.1(@types/node@26.2.0)': dependencies: '@inquirer/core': 11.2.1(@types/node@26.2.0) @@ -32219,18 +33777,6 @@ snapshots: optionalDependencies: '@types/node': 26.2.0 - '@inquirer/core@11.2.1(@types/node@26.1.2)': - dependencies: - '@inquirer/ansi': 2.0.7 - '@inquirer/figures': 2.0.7 - '@inquirer/type': 4.0.7(@types/node@26.1.2) - cli-width: 4.1.0 - fast-wrap-ansi: 0.2.2 - mute-stream: 3.0.0 - signal-exit: 4.1.0 - optionalDependencies: - '@types/node': 26.1.2 - '@inquirer/core@11.2.1(@types/node@26.2.0)': dependencies: '@inquirer/ansi': 2.0.7 @@ -32243,14 +33789,6 @@ snapshots: optionalDependencies: '@types/node': 26.2.0 - '@inquirer/editor@5.2.2(@types/node@26.1.2)': - dependencies: - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/external-editor': 3.0.3(@types/node@26.1.2) - '@inquirer/type': 4.0.7(@types/node@26.1.2) - optionalDependencies: - '@types/node': 26.1.2 - '@inquirer/editor@5.2.2(@types/node@26.2.0)': dependencies: '@inquirer/core': 11.2.1(@types/node@26.2.0) @@ -32259,13 +33797,6 @@ snapshots: optionalDependencies: '@types/node': 26.2.0 - '@inquirer/expand@5.1.1(@types/node@26.1.2)': - dependencies: - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/type': 4.0.7(@types/node@26.1.2) - optionalDependencies: - '@types/node': 26.1.2 - '@inquirer/expand@5.1.1(@types/node@26.2.0)': dependencies: '@inquirer/core': 11.2.1(@types/node@26.2.0) @@ -32273,13 +33804,6 @@ snapshots: optionalDependencies: '@types/node': 26.2.0 - '@inquirer/external-editor@3.0.3(@types/node@26.1.2)': - dependencies: - chardet: 2.1.1 - iconv-lite: 0.7.2 - optionalDependencies: - '@types/node': 26.1.2 - '@inquirer/external-editor@3.0.3(@types/node@26.2.0)': dependencies: chardet: 2.1.1 @@ -32289,13 +33813,6 @@ snapshots: '@inquirer/figures@2.0.7': {} - '@inquirer/input@5.1.2(@types/node@26.1.2)': - dependencies: - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/type': 4.0.7(@types/node@26.1.2) - optionalDependencies: - '@types/node': 26.1.2 - '@inquirer/input@5.1.2(@types/node@26.2.0)': dependencies: '@inquirer/core': 11.2.1(@types/node@26.2.0) @@ -32303,13 +33820,6 @@ snapshots: optionalDependencies: '@types/node': 26.2.0 - '@inquirer/number@4.1.1(@types/node@26.1.2)': - dependencies: - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/type': 4.0.7(@types/node@26.1.2) - optionalDependencies: - '@types/node': 26.1.2 - '@inquirer/number@4.1.1(@types/node@26.2.0)': dependencies: '@inquirer/core': 11.2.1(@types/node@26.2.0) @@ -32317,14 +33827,6 @@ snapshots: optionalDependencies: '@types/node': 26.2.0 - '@inquirer/password@5.1.1(@types/node@26.1.2)': - dependencies: - '@inquirer/ansi': 2.0.7 - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/type': 4.0.7(@types/node@26.1.2) - optionalDependencies: - '@types/node': 26.1.2 - '@inquirer/password@5.1.1(@types/node@26.2.0)': dependencies: '@inquirer/ansi': 2.0.7 @@ -32333,21 +33835,6 @@ snapshots: optionalDependencies: '@types/node': 26.2.0 - '@inquirer/prompts@8.5.2(@types/node@26.1.2)': - dependencies: - '@inquirer/checkbox': 5.2.1(@types/node@26.1.2) - '@inquirer/confirm': 6.1.1(@types/node@26.1.2) - '@inquirer/editor': 5.2.2(@types/node@26.1.2) - '@inquirer/expand': 5.1.1(@types/node@26.1.2) - '@inquirer/input': 5.1.2(@types/node@26.1.2) - '@inquirer/number': 4.1.1(@types/node@26.1.2) - '@inquirer/password': 5.1.1(@types/node@26.1.2) - '@inquirer/rawlist': 5.3.1(@types/node@26.1.2) - '@inquirer/search': 4.2.1(@types/node@26.1.2) - '@inquirer/select': 5.2.1(@types/node@26.1.2) - optionalDependencies: - '@types/node': 26.1.2 - '@inquirer/prompts@8.5.2(@types/node@26.2.0)': dependencies: '@inquirer/checkbox': 5.2.1(@types/node@26.2.0) @@ -32363,13 +33850,6 @@ snapshots: optionalDependencies: '@types/node': 26.2.0 - '@inquirer/rawlist@5.3.1(@types/node@26.1.2)': - dependencies: - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/type': 4.0.7(@types/node@26.1.2) - optionalDependencies: - '@types/node': 26.1.2 - '@inquirer/rawlist@5.3.1(@types/node@26.2.0)': dependencies: '@inquirer/core': 11.2.1(@types/node@26.2.0) @@ -32377,14 +33857,6 @@ snapshots: optionalDependencies: '@types/node': 26.2.0 - '@inquirer/search@4.2.1(@types/node@26.1.2)': - dependencies: - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/figures': 2.0.7 - '@inquirer/type': 4.0.7(@types/node@26.1.2) - optionalDependencies: - '@types/node': 26.1.2 - '@inquirer/search@4.2.1(@types/node@26.2.0)': dependencies: '@inquirer/core': 11.2.1(@types/node@26.2.0) @@ -32393,15 +33865,6 @@ snapshots: optionalDependencies: '@types/node': 26.2.0 - '@inquirer/select@5.2.1(@types/node@26.1.2)': - dependencies: - '@inquirer/ansi': 2.0.7 - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/figures': 2.0.7 - '@inquirer/type': 4.0.7(@types/node@26.1.2) - optionalDependencies: - '@types/node': 26.1.2 - '@inquirer/select@5.2.1(@types/node@26.2.0)': dependencies: '@inquirer/ansi': 2.0.7 @@ -32411,10 +33874,6 @@ snapshots: optionalDependencies: '@types/node': 26.2.0 - '@inquirer/type@4.0.7(@types/node@26.1.2)': - optionalDependencies: - '@types/node': 26.1.2 - '@inquirer/type@4.0.7(@types/node@26.2.0)': optionalDependencies: '@types/node': 26.2.0 @@ -32610,19 +34069,11 @@ snapshots: '@leichtgewicht/ip-codec@2.0.5': {} - '@listr2/prompt-adapter-inquirer@4.2.4(@inquirer/prompts@8.5.2(@types/node@26.1.2))(@types/node@26.1.2)(listr2@10.2.2)': - dependencies: - '@inquirer/prompts': 8.5.2(@types/node@26.1.2) - '@inquirer/type': 4.0.7(@types/node@26.1.2) - listr2: 10.2.2 - transitivePeerDependencies: - - '@types/node' - - '@listr2/prompt-adapter-inquirer@4.2.4(@inquirer/prompts@8.5.2(@types/node@26.2.0))(@types/node@26.2.0)(listr2@10.2.2)': + '@listr2/prompt-adapter-inquirer@4.2.5(@inquirer/prompts@8.5.2(@types/node@26.2.0))(@types/node@26.2.0)(listr2@11.0.0)': dependencies: '@inquirer/prompts': 8.5.2(@types/node@26.2.0) '@inquirer/type': 4.0.7(@types/node@26.2.0) - listr2: 10.2.2 + listr2: 11.0.0 transitivePeerDependencies: - '@types/node' @@ -32657,18 +34108,18 @@ snapshots: '@lmdb/lmdb-win32-x64@3.5.6': optional: true - '@lucide/svelte@1.31.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))': + '@lucide/svelte@1.34.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))': dependencies: - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) - '@lucide/vue@1.31.0(vue@3.5.41(typescript@6.0.3))': + '@lucide/vue@1.34.0(vue@3.5.41(typescript@6.0.3))': dependencies: vue: 3.5.41(typescript@6.0.3) - '@mantine/core@9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@mantine/core@9.5.2(@mantine/hooks@9.5.2(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@floating-ui/react': 0.27.19(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@mantine/hooks': 9.5.1(react@19.2.8) + '@mantine/hooks': 9.5.2(react@19.2.8) clsx: 2.1.1 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) @@ -32678,16 +34129,16 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@mantine/dates@9.5.1(@mantine/core@9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mantine/hooks@9.5.1(react@19.2.8))(dayjs@1.11.21)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@mantine/dates@9.5.2(@mantine/core@9.5.2(@mantine/hooks@9.5.2(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mantine/hooks@9.5.2(react@19.2.8))(dayjs@1.11.23)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@mantine/core': 9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@mantine/hooks': 9.5.1(react@19.2.8) + '@mantine/core': 9.5.2(@mantine/hooks@9.5.2(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@mantine/hooks': 9.5.2(react@19.2.8) clsx: 2.1.1 - dayjs: 1.11.21 + dayjs: 1.11.23 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - '@mantine/hooks@9.5.1(react@19.2.8)': + '@mantine/hooks@9.5.2(react@19.2.8)': dependencies: react: 19.2.8 @@ -32706,7 +34157,7 @@ snapshots: tinyglobby: 0.2.17 yaml: 2.9.0 - '@modelcontextprotocol/sdk@1.29.0(supports-color@8.1.1)(zod@4.4.3)': + '@modelcontextprotocol/sdk@1.30.0(supports-color@8.1.1)(zod@4.4.3)': dependencies: '@hono/node-server': 1.19.14(hono@4.12.23) ajv: 8.20.0 @@ -32833,13 +34284,13 @@ snapshots: optionalDependencies: '@types/react': 19.2.18 - '@mui/x-date-pickers@9.11.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@mui/material@9.3.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mui/system@9.3.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(date-fns@4.4.0)(dayjs@1.11.21)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@mui/x-date-pickers@9.12.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@mui/material@9.3.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@mui/system@9.3.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(date-fns@4.4.0)(dayjs@1.11.23)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@babel/runtime': 7.29.7 '@mui/material': 9.3.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@mui/system': 9.3.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8) '@mui/utils': 9.3.0(@types/react@19.2.18)(react@19.2.8) - '@mui/x-internals': 9.11.0(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@mui/x-internals': 9.12.0(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@types/react-transition-group': 4.4.12(@types/react@19.2.18) clsx: 2.1.1 prop-types: 15.8.1 @@ -32850,21 +34301,21 @@ snapshots: '@emotion/react': 11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0) '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0))(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0) date-fns: 4.4.0 - dayjs: 1.11.21 + dayjs: 1.11.23 transitivePeerDependencies: - '@types/react' - '@mui/x-internals@9.11.0(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@mui/x-internals@9.12.0(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@babel/runtime': 7.29.7 - '@base-ui/utils': 0.3.1(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@base-ui/utils': 0.3.2(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@mui/utils': 9.3.0(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) reselect: 5.2.0 use-sync-external-store: 1.6.0(react@19.2.8) transitivePeerDependencies: - '@types/react' - - react-dom '@napi-rs/lzma-linux-x64-gnu@1.5.1': optional: true @@ -32975,18 +34426,38 @@ snapshots: '@tybys/wasm-util': 0.10.3 optional: true + '@napi-rs/wasm-runtime@1.2.1(@emnapi/core@2.0.0-alpha.4)(@emnapi/runtime@2.0.0-alpha.4)': + dependencies: + '@emnapi/core': 2.0.0-alpha.4 + '@emnapi/runtime': 2.0.0-alpha.4 + '@tybys/wasm-util': 0.10.3 + optional: true + + '@napi-rs/wasm-runtime@1.2.3(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': + dependencies: + '@emnapi/core': 1.11.2 + '@emnapi/runtime': 1.11.2 + '@tybys/wasm-util': 0.10.3 + optional: true + + '@napi-rs/wasm-runtime@1.2.3(@emnapi/core@2.0.0-alpha.4)(@emnapi/runtime@2.0.0-alpha.4)': + dependencies: + '@emnapi/core': 2.0.0-alpha.4 + '@emnapi/runtime': 2.0.0-alpha.4 + '@tybys/wasm-util': 0.10.3 + '@neodrag/core@3.0.0-next.11': {} - '@neodrag/solid@3.0.0-next.11(@neodrag/core@3.0.0-next.11)(solid-js@1.9.14)': + '@neodrag/solid@3.0.0-next.11(@neodrag/core@3.0.0-next.11)(solid-js@1.9.15)': dependencies: '@neodrag/core': 3.0.0-next.11 - solid-js: 1.9.14 + solid-js: 1.9.15 - '@ngtools/webpack@22.1.2(@angular/compiler-cli@22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3))(typescript@6.0.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3))': + '@ngtools/webpack@22.1.6(@angular/compiler-cli@22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3))(typescript@6.0.3)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3))': dependencies: '@angular/compiler-cli': 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) typescript: 6.0.3 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) '@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1': dependencies: @@ -33009,23 +34480,23 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 - '@nullvoxpopuli/ember-build-tooling-utils@1.1.0(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)': + '@nullvoxpopuli/ember-build-tooling-utils@1.1.0(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)': dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) '@rolldown/pluginutils': 1.0.1 - '@rollup/plugin-babel': 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + '@rollup/plugin-babel': 7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) transitivePeerDependencies: - '@types/babel__core' - rollup - supports-color - '@nullvoxpopuli/ember-vite@1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': + '@nullvoxpopuli/ember-vite@1.1.0(@glint/template@1.8.0)(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) '@embroider/core': 4.6.3(@glint/template@1.8.0)(supports-color@8.1.1) '@embroider/macros': 1.20.6(@babel/core@7.29.7(supports-color@8.1.1))(@glint/template@1.8.0)(supports-color@8.1.1) - '@embroider/vite': 1.7.8(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(@glint/template@1.8.0)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) - '@nullvoxpopuli/ember-build-tooling-utils': 1.1.0(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1) + '@embroider/vite': 1.7.8(@embroider/core@4.6.3(@glint/template@1.8.0)(supports-color@8.1.1))(@glint/template@1.8.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@nullvoxpopuli/ember-build-tooling-utils': 1.1.0(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1) transitivePeerDependencies: - '@glint/template' - '@types/babel__core' @@ -33279,9 +34750,9 @@ snapshots: '@oxc-parser/binding-openharmony-arm64@0.143.0': optional: true - '@oxc-parser/binding-wasm32-wasi@0.121.0(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)': + '@oxc-parser/binding-wasm32-wasi@0.121.0(@emnapi/core@2.0.0-alpha.4)(@emnapi/runtime@2.0.0-alpha.4)': dependencies: - '@napi-rs/wasm-runtime': 1.2.1(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3) + '@napi-rs/wasm-runtime': 1.2.1(@emnapi/core@2.0.0-alpha.4)(@emnapi/runtime@2.0.0-alpha.4) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' @@ -33349,6 +34820,8 @@ snapshots: '@oxc-project/types@0.143.0': {} + '@oxc-project/types@0.147.0': {} + '@oxc-resolver/binding-android-arm-eabi@11.24.2': optional: true @@ -33401,7 +34874,7 @@ snapshots: dependencies: '@emnapi/core': 1.11.2 '@emnapi/runtime': 1.11.2 - '@napi-rs/wasm-runtime': 1.2.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) + '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) optional: true '@oxc-resolver/binding-win32-arm64-msvc@11.24.2': @@ -33580,19 +35053,19 @@ snapshots: '@popperjs/core@2.11.8': {} - '@preact/preset-vite@2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.62.4)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': + '@preact/preset-vite@2.10.6(@babel/core@7.29.7(supports-color@8.1.1))(preact@10.29.8)(rollup@4.63.0)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/plugin-transform-react-jsx-development': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) - '@prefresh/vite': 2.4.12(preact@10.29.8)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) - '@rollup/pluginutils': 5.4.0(rollup@4.62.4) + '@prefresh/vite': 2.4.12(preact@10.29.8)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rollup/pluginutils': 5.4.0(rollup@4.63.0) babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.29.7(supports-color@8.1.1)) debug: 4.4.3(supports-color@8.1.1) magic-string: 0.30.21 picocolors: 1.1.1 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) - vite-prerender-plugin: 0.5.13(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite-prerender-plugin: 0.5.13(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) zimmerframe: 1.1.4 transitivePeerDependencies: - preact @@ -33609,7 +35082,7 @@ snapshots: '@prefresh/utils@1.2.1': {} - '@prefresh/vite@2.4.12(preact@10.29.8)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': + '@prefresh/vite@2.4.12(preact@10.29.8)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) '@prefresh/babel-plugin': 0.5.3 @@ -33617,13 +35090,13 @@ snapshots: '@prefresh/utils': 1.2.1 '@rollup/pluginutils': 4.2.1 preact: 10.29.8(preact-render-to-string@6.7.0) - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) transitivePeerDependencies: - supports-color - '@publint/pack@0.1.6': + '@publint/pack@0.1.7': dependencies: - tinyexec: 1.2.4 + tinyexec: 1.3.0 '@quansync/fs@1.0.0': dependencies: @@ -33635,67 +35108,67 @@ snapshots: '@radix-ui/primitive@1.1.7': {} - '@radix-ui/react-accessible-icon@1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-accessible-icon@1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-accordion@1.2.20(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-accordion@1.2.20(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-collapsible': 1.1.20(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-collapsible': 1.1.20(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-alert-dialog@1.1.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-alert-dialog@1.1.23(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-dialog': 1.1.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-dialog': 1.1.23(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-arrow@1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-arrow@1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-aspect-ratio@1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-aspect-ratio@1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-avatar@1.1.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-avatar@1.1.11(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/react-context': 1.1.3(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.18)(react@19.2.8) @@ -33703,13 +35176,13 @@ snapshots: react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-avatar@1.2.6(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-avatar@1.2.6(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-is-hydrated': 0.1.3(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) @@ -33717,50 +35190,50 @@ snapshots: react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-checkbox@1.3.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-checkbox@1.3.11(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-size': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-collapsible@1.1.20(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-collapsible@1.1.20(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-collection@1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-collection@1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.18)(react@19.2.8)': dependencies: @@ -33780,18 +35253,18 @@ snapshots: optionalDependencies: '@types/react': 19.2.18 - '@radix-ui/react-context-menu@2.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-context-menu@2.3.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-menu': 2.1.24(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-menu': 2.1.24(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) '@radix-ui/react-context@1.1.3(@types/react@19.2.18)(react@19.2.8)': dependencies: @@ -33811,18 +35284,18 @@ snapshots: optionalDependencies: '@types/react': 19.2.18 - '@radix-ui/react-dialog@1.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-dialog@1.1.16(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.4 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-dismissable-layer': 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-focus-scope': 1.1.9(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.9(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-id': 1.1.2(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-portal': 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.11(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-slot': 1.2.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.18)(react@19.2.8) aria-hidden: 1.2.6 @@ -33831,20 +35304,20 @@ snapshots: react-remove-scroll: 2.7.2(@types/react@19.2.18)(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-dialog@1.1.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-dialog@1.1.23(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) @@ -33854,7 +35327,7 @@ snapshots: react-remove-scroll: 2.7.2(@types/react@19.2.18)(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) '@radix-ui/react-direction@1.1.4(@types/react@19.2.18)(react@19.2.8)': dependencies: @@ -33862,46 +35335,46 @@ snapshots: optionalDependencies: '@types/react': 19.2.18 - '@radix-ui/react-dismissable-layer@1.1.12(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-dismissable-layer@1.1.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.4 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-escape-keydown': 1.1.2(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-dismissable-layer@1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-dismissable-layer@1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-dropdown-menu@2.1.24(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-dropdown-menu@2.1.24(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-menu': 2.1.24(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-menu': 2.1.24(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) '@radix-ui/react-focus-guards@1.1.4(@types/react@19.2.18)(react@19.2.8)': dependencies: @@ -33915,58 +35388,58 @@ snapshots: optionalDependencies: '@types/react': 19.2.18 - '@radix-ui/react-focus-scope@1.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-focus-scope@1.1.16(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-focus-scope@1.1.9(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-focus-scope@1.1.9(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-form@0.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-form@0.1.16(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-label': 2.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-label': 2.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-hover-card@1.1.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-hover-card@1.1.23(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) '@radix-ui/react-id@1.1.2(@types/react@19.2.18)(react@19.2.8)': dependencies: @@ -33982,31 +35455,31 @@ snapshots: optionalDependencies: '@types/react': 19.2.18 - '@radix-ui/react-label@2.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-label@2.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-menu@2.1.24(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-menu@2.1.24(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.2.8) aria-hidden: 1.2.6 @@ -34015,58 +35488,58 @@ snapshots: react-remove-scroll: 2.7.2(@types/react@19.2.18)(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-menubar@1.1.24(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-menubar@1.1.24(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-menu': 2.1.24(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-menu': 2.1.24(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-navigation-menu@1.2.22(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-navigation-menu@1.2.22(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-previous': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-one-time-password-field@0.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-one-time-password-field@0.1.16(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/number': 1.1.3 '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-is-hydrated': 0.1.3(@types/react@19.2.18)(react@19.2.8) @@ -34075,15 +35548,15 @@ snapshots: react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-password-toggle-field@0.1.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-password-toggle-field@0.1.11(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-is-hydrated': 0.1.3(@types/react@19.2.18)(react@19.2.8) @@ -34091,21 +35564,21 @@ snapshots: react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-popover@1.1.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-popover@1.1.23(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) aria-hidden: 1.2.6 @@ -34114,15 +35587,15 @@ snapshots: react-remove-scroll: 2.7.2(@types/react@19.2.18)(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-popper@1.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-popper@1.3.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@floating-ui/react-dom': 2.1.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-arrow': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-arrow': 1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-rect': 1.1.4(@types/react@19.2.18)(react@19.2.8) @@ -34132,109 +35605,109 @@ snapshots: react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-portal@1.1.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-portal@1.1.11(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-portal@1.1.17(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-portal@1.1.17(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-presence@1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-presence@1.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-presence@1.1.6(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-presence@1.1.6(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-primitive@2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-primitive@2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/react-slot': 1.2.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-primitive@2.1.5(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-primitive@2.1.5(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/react-slot': 1.2.5(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-progress@1.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-progress@1.1.16(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-radio-group@1.4.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-radio-group@1.4.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-size': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-roving-focus@1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-roving-focus@1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-is-hydrated': 0.1.3(@types/react@19.2.18)(react@19.2.8) @@ -34243,73 +35716,73 @@ snapshots: react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-scroll-area@1.2.18(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-scroll-area@1.2.18(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/number': 1.1.3 '@radix-ui/primitive': 1.1.7 '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-select@2.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-select@2.3.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/number': 1.1.3 '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-previous': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) aria-hidden: 1.2.6 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) react-remove-scroll: 2.7.2(@types/react@19.2.18)(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-separator@1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-separator@1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-slider@1.4.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-slider@1.4.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/number': 1.1.3 '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-previous': 1.1.4(@types/react@19.2.18)(react@19.2.8) @@ -34318,7 +35791,7 @@ snapshots: react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) '@radix-ui/react-slot@1.2.4(@types/react@19.2.18)(react@19.2.8)': dependencies: @@ -34341,117 +35814,117 @@ snapshots: optionalDependencies: '@types/react': 19.2.18 - '@radix-ui/react-switch@1.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-switch@1.3.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-size': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-tabs@1.1.21(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-tabs@1.1.21(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-toast@1.2.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-toast@1.2.23(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-toggle-group@1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-toggle-group@1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-toggle': 1.1.18(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-toggle': 1.1.18(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-toggle@1.1.18(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-toggle@1.1.18(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-toolbar@1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-toolbar@1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-separator': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-toggle-group': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-separator': 1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-toggle-group': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@radix-ui/react-tooltip@1.2.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-tooltip@1.2.16(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.18)(react@19.2.8)': dependencies: @@ -34567,14 +36040,14 @@ snapshots: optionalDependencies: '@types/react': 19.2.18 - '@radix-ui/react-visually-hidden@1.2.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-visually-hidden@1.2.11(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) '@radix-ui/rect@1.1.3': {} @@ -34656,6 +36129,9 @@ snapshots: dependencies: react: 19.2.8 + '@rolldown/binding-android-arm-eabi@1.2.6': + optional: true + '@rolldown/binding-android-arm64@1.1.5': optional: true @@ -34665,6 +36141,9 @@ snapshots: '@rolldown/binding-android-arm64@1.2.1': optional: true + '@rolldown/binding-android-arm64@1.2.6': + optional: true + '@rolldown/binding-darwin-arm64@1.1.5': optional: true @@ -34674,6 +36153,9 @@ snapshots: '@rolldown/binding-darwin-arm64@1.2.1': optional: true + '@rolldown/binding-darwin-arm64@1.2.6': + optional: true + '@rolldown/binding-darwin-x64@1.1.5': optional: true @@ -34683,6 +36165,9 @@ snapshots: '@rolldown/binding-darwin-x64@1.2.1': optional: true + '@rolldown/binding-darwin-x64@1.2.6': + optional: true + '@rolldown/binding-freebsd-x64@1.1.5': optional: true @@ -34692,6 +36177,9 @@ snapshots: '@rolldown/binding-freebsd-x64@1.2.1': optional: true + '@rolldown/binding-freebsd-x64@1.2.6': + optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.1.5': optional: true @@ -34701,6 +36189,9 @@ snapshots: '@rolldown/binding-linux-arm-gnueabihf@1.2.1': optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.2.6': + optional: true + '@rolldown/binding-linux-arm64-gnu@1.1.5': optional: true @@ -34710,6 +36201,9 @@ snapshots: '@rolldown/binding-linux-arm64-gnu@1.2.1': optional: true + '@rolldown/binding-linux-arm64-gnu@1.2.6': + optional: true + '@rolldown/binding-linux-arm64-musl@1.1.5': optional: true @@ -34719,6 +36213,9 @@ snapshots: '@rolldown/binding-linux-arm64-musl@1.2.1': optional: true + '@rolldown/binding-linux-arm64-musl@1.2.6': + optional: true + '@rolldown/binding-linux-ppc64-gnu@1.1.5': optional: true @@ -34728,6 +36225,9 @@ snapshots: '@rolldown/binding-linux-ppc64-gnu@1.2.1': optional: true + '@rolldown/binding-linux-ppc64-gnu@1.2.6': + optional: true + '@rolldown/binding-linux-s390x-gnu@1.1.5': optional: true @@ -34737,6 +36237,9 @@ snapshots: '@rolldown/binding-linux-s390x-gnu@1.2.1': optional: true + '@rolldown/binding-linux-s390x-gnu@1.2.6': + optional: true + '@rolldown/binding-linux-x64-gnu@1.1.5': optional: true @@ -34746,6 +36249,9 @@ snapshots: '@rolldown/binding-linux-x64-gnu@1.2.1': optional: true + '@rolldown/binding-linux-x64-gnu@1.2.6': + optional: true + '@rolldown/binding-linux-x64-musl@1.1.5': optional: true @@ -34755,6 +36261,9 @@ snapshots: '@rolldown/binding-linux-x64-musl@1.2.1': optional: true + '@rolldown/binding-linux-x64-musl@1.2.6': + optional: true + '@rolldown/binding-openharmony-arm64@1.1.5': optional: true @@ -34764,6 +36273,9 @@ snapshots: '@rolldown/binding-openharmony-arm64@1.2.1': optional: true + '@rolldown/binding-openharmony-arm64@1.2.6': + optional: true + '@rolldown/binding-wasm32-wasi@1.1.5': dependencies: '@emnapi/core': 1.11.1 @@ -34785,6 +36297,12 @@ snapshots: '@napi-rs/wasm-runtime': 1.2.1(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3) optional: true + '@rolldown/binding-wasm32-wasi@1.2.6': + dependencies: + '@emnapi/core': 2.0.0-alpha.4 + '@emnapi/runtime': 2.0.0-alpha.4 + '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@2.0.0-alpha.4)(@emnapi/runtime@2.0.0-alpha.4) + '@rolldown/binding-win32-arm64-msvc@1.1.5': optional: true @@ -34794,6 +36312,9 @@ snapshots: '@rolldown/binding-win32-arm64-msvc@1.2.1': optional: true + '@rolldown/binding-win32-arm64-msvc@1.2.6': + optional: true + '@rolldown/binding-win32-x64-msvc@1.1.5': optional: true @@ -34803,18 +36324,21 @@ snapshots: '@rolldown/binding-win32-x64-msvc@1.2.1': optional: true - '@rolldown/plugin-babel@0.2.3(@babel/core@7.29.7(supports-color@8.1.1))(@babel/plugin-transform-runtime@8.0.1(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': + '@rolldown/binding-win32-x64-msvc@1.2.6': + optional: true + + '@rolldown/plugin-babel@0.2.3(@babel/core@7.29.7(supports-color@8.1.1))(@babel/plugin-transform-runtime@8.0.1(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/runtime@8.0.0)(rolldown@1.2.6)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) picomatch: 4.0.5 - rolldown: 1.2.1 + rolldown: 1.2.6 optionalDependencies: '@babel/plugin-transform-runtime': 8.0.1(@babel/core@7.29.7(supports-color@8.1.1)) '@babel/runtime': 8.0.0 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) optional: true - '@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': + '@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': dependencies: '@babel/core': 8.0.1 picomatch: 4.0.5 @@ -34822,121 +36346,132 @@ snapshots: optionalDependencies: '@babel/plugin-transform-runtime': 8.0.1(@babel/core@8.0.1) '@babel/runtime': 8.0.0 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + + '@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.6)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': + dependencies: + '@babel/core': 8.0.1 + picomatch: 4.0.5 + rolldown: 1.2.6 + optionalDependencies: + '@babel/plugin-transform-runtime': 8.0.1(@babel/core@8.0.1) + '@babel/runtime': 8.0.0 + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + optional: true '@rolldown/pluginutils@1.0.1': {} - '@rollup/plugin-babel@7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.62.4)(supports-color@8.1.1)': + '@rollup/plugin-babel@7.1.0(@babel/core@7.29.7(supports-color@8.1.1))(@types/babel__core@7.20.5)(rollup@4.63.0)(supports-color@8.1.1)': dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/helper-module-imports': 7.29.7(supports-color@8.1.1) - '@rollup/pluginutils': 5.4.0(rollup@4.62.4) + '@rollup/pluginutils': 5.4.0(rollup@4.63.0) workerpool: 9.3.4 optionalDependencies: '@types/babel__core': 7.20.5 - rollup: 4.62.4 + rollup: 4.63.0 transitivePeerDependencies: - supports-color - '@rollup/plugin-json@6.1.0(rollup@4.62.4)': + '@rollup/plugin-json@6.1.0(rollup@4.63.0)': dependencies: - '@rollup/pluginutils': 5.4.0(rollup@4.62.4) + '@rollup/pluginutils': 5.4.0(rollup@4.63.0) optionalDependencies: - rollup: 4.62.4 + rollup: 4.63.0 - '@rollup/plugin-replace@6.0.3(rollup@4.62.4)': + '@rollup/plugin-replace@6.0.3(rollup@4.63.0)': dependencies: - '@rollup/pluginutils': 5.4.0(rollup@4.62.4) + '@rollup/pluginutils': 5.4.0(rollup@4.63.0) magic-string: 0.30.21 optionalDependencies: - rollup: 4.62.4 + rollup: 4.63.0 '@rollup/pluginutils@4.2.1': dependencies: estree-walker: 2.0.2 picomatch: 2.3.2 - '@rollup/pluginutils@5.4.0(rollup@4.62.4)': + '@rollup/pluginutils@5.4.0(rollup@4.63.0)': dependencies: '@types/estree': 1.0.9 estree-walker: 2.0.2 picomatch: 4.0.5 optionalDependencies: - rollup: 4.62.4 + rollup: 4.63.0 - '@rollup/rollup-android-arm-eabi@4.62.4': + '@rollup/rollup-android-arm-eabi@4.63.0': optional: true - '@rollup/rollup-android-arm64@4.62.4': + '@rollup/rollup-android-arm64@4.63.0': optional: true - '@rollup/rollup-darwin-arm64@4.62.4': + '@rollup/rollup-darwin-arm64@4.63.0': optional: true - '@rollup/rollup-darwin-x64@4.62.4': + '@rollup/rollup-darwin-x64@4.63.0': optional: true - '@rollup/rollup-freebsd-arm64@4.62.4': + '@rollup/rollup-freebsd-arm64@4.63.0': optional: true - '@rollup/rollup-freebsd-x64@4.62.4': + '@rollup/rollup-freebsd-x64@4.63.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.62.4': + '@rollup/rollup-linux-arm-gnueabihf@4.63.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.62.4': + '@rollup/rollup-linux-arm-musleabihf@4.63.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.62.4': + '@rollup/rollup-linux-arm64-gnu@4.63.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.62.4': + '@rollup/rollup-linux-arm64-musl@4.63.0': optional: true - '@rollup/rollup-linux-loong64-gnu@4.62.4': + '@rollup/rollup-linux-loong64-gnu@4.63.0': optional: true - '@rollup/rollup-linux-loong64-musl@4.62.4': + '@rollup/rollup-linux-loong64-musl@4.63.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.62.4': + '@rollup/rollup-linux-ppc64-gnu@4.63.0': optional: true - '@rollup/rollup-linux-ppc64-musl@4.62.4': + '@rollup/rollup-linux-ppc64-musl@4.63.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.62.4': + '@rollup/rollup-linux-riscv64-gnu@4.63.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.62.4': + '@rollup/rollup-linux-riscv64-musl@4.63.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.62.4': + '@rollup/rollup-linux-s390x-gnu@4.63.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.62.4': + '@rollup/rollup-linux-x64-gnu@4.63.0': optional: true - '@rollup/rollup-linux-x64-musl@4.62.4': + '@rollup/rollup-linux-x64-musl@4.63.0': optional: true - '@rollup/rollup-openbsd-x64@4.62.4': + '@rollup/rollup-openbsd-x64@4.63.0': optional: true - '@rollup/rollup-openharmony-arm64@4.62.4': + '@rollup/rollup-openharmony-arm64@4.63.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.62.4': + '@rollup/rollup-win32-arm64-msvc@4.63.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.62.4': + '@rollup/rollup-win32-ia32-msvc@4.63.0': optional: true - '@rollup/rollup-win32-x64-gnu@4.62.4': + '@rollup/rollup-win32-x64-gnu@4.63.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.62.4': + '@rollup/rollup-win32-x64-msvc@4.63.0': optional: true '@rollup/wasm-node@4.61.1': @@ -34945,10 +36480,10 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - '@schematics/angular@22.1.2(chokidar@5.0.0)': + '@schematics/angular@22.1.6(chokidar@5.0.0)': dependencies: - '@angular-devkit/core': 22.1.2(chokidar@5.0.0) - '@angular-devkit/schematics': 22.1.2(chokidar@5.0.0) + '@angular-devkit/core': 22.1.6(chokidar@5.0.0) + '@angular-devkit/schematics': 22.1.6(chokidar@5.0.0) jsonc-parser: 3.3.1 typescript: 6.0.3 transitivePeerDependencies: @@ -34998,53 +36533,53 @@ snapshots: '@socket.io/component-emitter@3.1.2': {} - '@solid-primitives/event-listener@2.4.5(solid-js@1.9.14)': + '@solid-primitives/event-listener@2.4.5(solid-js@1.9.15)': dependencies: - '@solid-primitives/utils': 6.4.0(solid-js@1.9.14) - solid-js: 1.9.14 + '@solid-primitives/utils': 6.4.0(solid-js@1.9.15) + solid-js: 1.9.15 - '@solid-primitives/keyboard@1.3.5(solid-js@1.9.14)': + '@solid-primitives/keyboard@1.3.5(solid-js@1.9.15)': dependencies: - '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.14) - '@solid-primitives/rootless': 1.5.3(solid-js@1.9.14) - '@solid-primitives/utils': 6.4.0(solid-js@1.9.14) - solid-js: 1.9.14 + '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.15) + '@solid-primitives/rootless': 1.5.3(solid-js@1.9.15) + '@solid-primitives/utils': 6.4.0(solid-js@1.9.15) + solid-js: 1.9.15 - '@solid-primitives/refs@1.1.3(solid-js@1.9.14)': + '@solid-primitives/refs@1.1.3(solid-js@1.9.15)': dependencies: - '@solid-primitives/utils': 6.4.0(solid-js@1.9.14) - solid-js: 1.9.14 + '@solid-primitives/utils': 6.4.0(solid-js@1.9.15) + solid-js: 1.9.15 - '@solid-primitives/resize-observer@2.1.5(solid-js@1.9.14)': + '@solid-primitives/resize-observer@2.1.5(solid-js@1.9.15)': dependencies: - '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.14) - '@solid-primitives/rootless': 1.5.3(solid-js@1.9.14) - '@solid-primitives/static-store': 0.1.3(solid-js@1.9.14) - '@solid-primitives/utils': 6.4.0(solid-js@1.9.14) - solid-js: 1.9.14 + '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.15) + '@solid-primitives/rootless': 1.5.3(solid-js@1.9.15) + '@solid-primitives/static-store': 0.1.3(solid-js@1.9.15) + '@solid-primitives/utils': 6.4.0(solid-js@1.9.15) + solid-js: 1.9.15 - '@solid-primitives/rootless@1.5.3(solid-js@1.9.14)': + '@solid-primitives/rootless@1.5.3(solid-js@1.9.15)': dependencies: - '@solid-primitives/utils': 6.4.0(solid-js@1.9.14) - solid-js: 1.9.14 + '@solid-primitives/utils': 6.4.0(solid-js@1.9.15) + solid-js: 1.9.15 - '@solid-primitives/static-store@0.1.3(solid-js@1.9.14)': + '@solid-primitives/static-store@0.1.3(solid-js@1.9.15)': dependencies: - '@solid-primitives/utils': 6.4.0(solid-js@1.9.14) - solid-js: 1.9.14 + '@solid-primitives/utils': 6.4.0(solid-js@1.9.15) + solid-js: 1.9.15 - '@solid-primitives/utils@6.4.0(solid-js@1.9.14)': + '@solid-primitives/utils@6.4.0(solid-js@1.9.15)': dependencies: - solid-js: 1.9.14 + solid-js: 1.9.15 - '@solidjs/meta@0.29.4(solid-js@1.9.14)': + '@solidjs/meta@0.29.4(solid-js@1.9.15)': dependencies: - solid-js: 1.9.14 + solid-js: 1.9.15 - '@solidjs/testing-library@0.8.10(solid-js@1.9.14)': + '@solidjs/testing-library@0.8.10(solid-js@1.9.15)': dependencies: '@testing-library/dom': 10.4.1 - solid-js: 1.9.14 + solid-js: 1.9.15 '@spectrum-icons/ui@3.7.1(@adobe/react-spectrum@3.47.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: @@ -35082,21 +36617,21 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@stylistic/eslint-plugin@5.10.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))': + '@stylistic/eslint-plugin@5.10.0(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) - '@typescript-eslint/types': 8.67.0 - eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0)) + '@typescript-eslint/types': 8.68.0 + eslint: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 picomatch: 4.0.5 - '@stylistic/eslint-plugin@5.10.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))': + '@stylistic/eslint-plugin@5.10.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)) - '@typescript-eslint/types': 8.67.0 - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)) + '@typescript-eslint/types': 8.68.0 + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 @@ -35107,36 +36642,27 @@ snapshots: dependencies: acorn: 8.18.0 - '@sveltejs/load-config@0.2.1': {} + '@sveltejs/load-config@0.2.3': {} - '@sveltejs/package@2.5.8(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3)': + '@sveltejs/package@2.5.8(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3)': dependencies: chokidar: 5.0.0 kleur: 4.1.5 sade: 1.8.1 semver: 7.8.2 - svelte: 5.56.8(@typescript-eslint/types@8.67.0) - svelte2tsx: 0.7.56(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) + svelte2tsx: 0.7.56(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3) transitivePeerDependencies: - typescript - '@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0))': - dependencies: - deepmerge: 4.3.1 - magic-string: 1.0.0 - obug: 2.1.4 - svelte: 5.56.8(@typescript-eslint/types@8.67.0) - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0) - vitefu: 1.1.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0)) - - '@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': + '@sveltejs/vite-plugin-svelte@7.3.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': dependencies: deepmerge: 4.3.1 magic-string: 1.0.0 obug: 2.1.4 - svelte: 5.56.8(@typescript-eslint/types@8.67.0) - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) - vitefu: 1.1.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vitefu: 1.1.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@swc/helpers@0.5.23': dependencies: @@ -35210,20 +36736,19 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 '@tailwindcss/oxide-win32-x64-msvc': 4.3.3 - '@tailwindcss/vite@4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': + '@tailwindcss/vite@4.3.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': dependencies: '@tailwindcss/node': 4.3.3 '@tailwindcss/oxide': 4.3.3 tailwindcss: 4.3.3 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) - '@tanstack/angular-devtools@0.0.9(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14)': + '@tanstack/angular-devtools@0.0.11(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(csstype@3.2.3)(solid-js@1.9.15)': dependencies: '@angular/core': 22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2) - '@tanstack/devtools': 0.14.0(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + '@tanstack/devtools': 0.14.2(csstype@3.2.3)(solid-js@1.9.15) tslib: 2.8.1 transitivePeerDependencies: - - '@neodrag/core' - bufferutil - csstype - solid-js @@ -35280,10 +36805,10 @@ snapshots: '@tanstack/store': 0.9.3 tslib: 2.8.1 - '@tanstack/angular-virtual@6.0.2(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))': + '@tanstack/angular-virtual@6.0.3(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))': dependencies: '@angular/core': 22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2) - '@tanstack/virtual-core': 3.17.7 + '@tanstack/virtual-core': 3.17.8 '@tanstack/devtools-client@0.0.6': dependencies: @@ -35300,7 +36825,7 @@ snapshots: - bufferutil - utf-8-validate - '@tanstack/devtools-event-bus@0.4.2': + '@tanstack/devtools-event-bus@0.4.3': dependencies: ws: 8.21.0 transitivePeerDependencies: @@ -35311,12 +36836,12 @@ snapshots: '@tanstack/devtools-event-client@0.5.0': {} - '@tanstack/devtools-ui@0.5.2(csstype@3.2.3)(solid-js@1.9.14)': + '@tanstack/devtools-ui@0.5.2(csstype@3.2.3)(solid-js@1.9.15)': dependencies: clsx: 2.1.1 dayjs: 1.11.21 goober: 2.1.19(csstype@3.2.3) - solid-js: 1.9.14 + solid-js: 1.9.15 transitivePeerDependencies: - csstype @@ -35329,77 +36854,97 @@ snapshots: transitivePeerDependencies: - csstype - '@tanstack/devtools-ui@0.7.0(csstype@3.2.3)(solid-js@1.9.14)': + '@tanstack/devtools-ui@0.7.1(csstype@3.2.3)(solid-js@1.9.15)': dependencies: clsx: 2.1.1 dayjs: 1.11.21 goober: 2.1.19(csstype@3.2.3) - solid-js: 1.9.14 + solid-js: 1.9.15 transitivePeerDependencies: - csstype - '@tanstack/devtools-utils@0.4.0(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(vue@3.5.41(typescript@6.0.3))': + '@tanstack/devtools-utils@0.4.0(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(vue@3.5.41(typescript@6.0.3))': optionalDependencies: '@types/react': 19.2.18 preact: 10.29.8(preact-render-to-string@6.7.0) react: 19.2.8 - solid-js: 1.9.14 + solid-js: 1.9.15 vue: 3.5.41(typescript@6.0.3) - '@tanstack/devtools-utils@0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3))': + '@tanstack/devtools-utils@0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3))': optionalDependencies: '@angular/core': 22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2) '@types/react': 19.2.18 preact: 10.29.8(preact-render-to-string@6.7.0) react: 19.2.8 solid-js: 1.9.14 - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) + vue: 3.5.41(typescript@6.0.3) + + '@tanstack/devtools-utils@0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3))': + optionalDependencies: + '@angular/core': 22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2) + '@types/react': 19.2.18 + preact: 10.29.8(preact-render-to-string@6.7.0) + react: 19.2.8 + solid-js: 1.9.15 + svelte: 5.56.10(@typescript-eslint/types@8.68.0) + vue: 3.5.41(typescript@6.0.3) + + '@tanstack/devtools-utils@0.7.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3))': + optionalDependencies: + '@angular/core': 22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2) + '@types/react': 19.2.18 + preact: 10.29.8(preact-render-to-string@6.7.0) + react: 19.2.8 + solid-js: 1.9.15 + svelte: 5.56.10(@typescript-eslint/types@8.68.0) vue: 3.5.41(typescript@6.0.3) - '@tanstack/devtools@0.12.2(csstype@3.2.3)(solid-js@1.9.14)': + '@tanstack/devtools@0.12.2(csstype@3.2.3)(solid-js@1.9.15)': dependencies: - '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.14) - '@solid-primitives/keyboard': 1.3.5(solid-js@1.9.14) - '@solid-primitives/resize-observer': 2.1.5(solid-js@1.9.14) + '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.15) + '@solid-primitives/keyboard': 1.3.5(solid-js@1.9.15) + '@solid-primitives/resize-observer': 2.1.5(solid-js@1.9.15) '@tanstack/devtools-client': 0.0.6 '@tanstack/devtools-event-bus': 0.4.1 - '@tanstack/devtools-ui': 0.5.2(csstype@3.2.3)(solid-js@1.9.14) + '@tanstack/devtools-ui': 0.5.2(csstype@3.2.3)(solid-js@1.9.15) clsx: 2.1.1 goober: 2.1.19(csstype@3.2.3) - solid-js: 1.9.14 + solid-js: 1.9.15 transitivePeerDependencies: - bufferutil - csstype - utf-8-validate - '@tanstack/devtools@0.14.0(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14)': + '@tanstack/devtools@0.14.2(csstype@3.2.3)(solid-js@1.9.15)': dependencies: - '@neodrag/solid': 3.0.0-next.11(@neodrag/core@3.0.0-next.11)(solid-js@1.9.14) - '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.14) - '@solid-primitives/keyboard': 1.3.5(solid-js@1.9.14) - '@solid-primitives/resize-observer': 2.1.5(solid-js@1.9.14) + '@neodrag/core': 3.0.0-next.11 + '@neodrag/solid': 3.0.0-next.11(@neodrag/core@3.0.0-next.11)(solid-js@1.9.15) + '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.15) + '@solid-primitives/keyboard': 1.3.5(solid-js@1.9.15) + '@solid-primitives/resize-observer': 2.1.5(solid-js@1.9.15) '@tanstack/devtools-client': 0.0.8 - '@tanstack/devtools-event-bus': 0.4.2 - '@tanstack/devtools-ui': 0.7.0(csstype@3.2.3)(solid-js@1.9.14) + '@tanstack/devtools-event-bus': 0.4.3 + '@tanstack/devtools-ui': 0.7.1(csstype@3.2.3)(solid-js@1.9.15) clsx: 2.1.1 goober: 2.1.19(csstype@3.2.3) - solid-js: 1.9.14 + solid-js: 1.9.15 transitivePeerDependencies: - - '@neodrag/core' - bufferutil - csstype - utf-8-validate - '@tanstack/eslint-config@0.4.0(@typescript-eslint/utils@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@7.2.0))(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': + '@tanstack/eslint-config@0.4.0(@typescript-eslint/utils@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@7.2.0))(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@eslint/js': 10.0.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) - '@stylistic/eslint-plugin': 5.10.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) - eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) - eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@7.2.0))(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) - eslint-plugin-n: 17.24.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(typescript@6.0.3) + '@eslint/js': 10.0.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0)) + '@stylistic/eslint-plugin': 5.10.0(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0)) + eslint: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) + eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@7.2.0))(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) + eslint-plugin-n: 17.24.0(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(typescript@6.0.3) globals: 17.6.0 - typescript-eslint: 8.60.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) - vue-eslint-parser: 10.4.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) + typescript-eslint: 8.60.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + vue-eslint-parser: 10.4.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) transitivePeerDependencies: - '@typescript-eslint/utils' - eslint-import-resolver-node @@ -35410,17 +36955,17 @@ snapshots: dependencies: '@tanstack/devtools-event-client': 0.4.3 '@tanstack/pacer-lite': 0.1.1 - '@tanstack/store': 0.11.0 + '@tanstack/store': 0.11.1 - '@tanstack/form-devtools@0.2.34(@types/react@19.2.18)(csstype@3.2.3)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(vue@3.5.41(typescript@6.0.3))': + '@tanstack/form-devtools@0.2.34(@types/react@19.2.18)(csstype@3.2.3)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(vue@3.5.41(typescript@6.0.3))': dependencies: - '@tanstack/devtools-ui': 0.5.2(csstype@3.2.3)(solid-js@1.9.14) - '@tanstack/devtools-utils': 0.4.0(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(vue@3.5.41(typescript@6.0.3)) + '@tanstack/devtools-ui': 0.5.2(csstype@3.2.3)(solid-js@1.9.15) + '@tanstack/devtools-utils': 0.4.0(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(vue@3.5.41(typescript@6.0.3)) '@tanstack/form-core': 1.33.5 clsx: 2.1.1 dayjs: 1.11.21 goober: 2.1.19(csstype@3.2.3) - solid-js: 1.9.14 + solid-js: 1.9.15 transitivePeerDependencies: - '@types/react' - csstype @@ -35434,7 +36979,7 @@ snapshots: dependencies: '@tanstack/store': 0.11.0 - '@tanstack/intent@0.3.6': + '@tanstack/intent@0.3.7': dependencies: cac: 6.7.14 jsonc-parser: 3.3.1 @@ -35452,20 +36997,20 @@ snapshots: '@tanstack/store': 0.11.1 lit: 3.3.3 - '@tanstack/lit-virtual@3.13.36(lit@3.3.3)': + '@tanstack/lit-virtual@3.13.37(lit@3.3.3)': dependencies: - '@tanstack/virtual-core': 3.17.7 + '@tanstack/virtual-core': 3.17.8 lit: 3.3.3 - '@tanstack/octane-store@0.12.2(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))': + '@tanstack/octane-store@0.12.2(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))': dependencies: '@tanstack/store': 0.11.1 - octane: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + octane: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) - '@tanstack/pacer-devtools@1.4.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3))': + '@tanstack/pacer-devtools@1.4.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3))': dependencies: '@tanstack/devtools-ui': 0.6.0(csstype@3.2.3)(solid-js@1.9.14) - '@tanstack/devtools-utils': 0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) + '@tanstack/devtools-utils': 0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) '@tanstack/pacer': 0.22.0 '@tanstack/solid-store': 0.11.1(solid-js@1.9.14) clsx: 2.1.1 @@ -35488,12 +37033,11 @@ snapshots: '@tanstack/devtools-event-client': 0.5.0 '@tanstack/store': 0.11.1 - '@tanstack/preact-devtools@0.10.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.14)': + '@tanstack/preact-devtools@0.10.12(csstype@3.2.3)(preact@10.29.8)(solid-js@1.9.15)': dependencies: - '@tanstack/devtools': 0.14.0(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + '@tanstack/devtools': 0.14.2(csstype@3.2.3)(solid-js@1.9.15) preact: 10.29.8(preact-render-to-string@6.7.0) transitivePeerDependencies: - - '@neodrag/core' - bufferutil - csstype - solid-js @@ -35502,7 +37046,7 @@ snapshots: '@tanstack/preact-form@1.30.5(preact@10.29.8)': dependencies: '@tanstack/form-core': 1.33.5 - '@tanstack/preact-store': 0.13.1(preact@10.29.8) + '@tanstack/preact-store': 0.13.2(preact@10.29.8) preact: 10.29.8(preact-render-to-string@6.7.0) '@tanstack/preact-hotkeys@0.10.0(preact@10.29.8)': @@ -35511,10 +37055,10 @@ snapshots: '@tanstack/preact-store': 0.13.2(preact@10.29.8) preact: 10.29.8(preact-render-to-string@6.7.0) - '@tanstack/preact-pacer-devtools@0.7.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3))': + '@tanstack/preact-pacer-devtools@0.7.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3))': dependencies: - '@tanstack/devtools-utils': 0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) - '@tanstack/pacer-devtools': 1.4.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) + '@tanstack/devtools-utils': 0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) + '@tanstack/pacer-devtools': 1.4.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) preact: 10.29.8(preact-render-to-string@6.7.0) transitivePeerDependencies: - '@angular/core' @@ -35542,11 +37086,6 @@ snapshots: '@tanstack/query-core': 5.101.4 preact: 10.29.8(preact-render-to-string@6.7.0) - '@tanstack/preact-store@0.13.1(preact@10.29.8)': - dependencies: - '@tanstack/store': 0.11.0 - preact: 10.29.8(preact-render-to-string@6.7.0) - '@tanstack/preact-store@0.13.2(preact@10.29.8)': dependencies: '@tanstack/store': 0.11.1 @@ -35556,23 +37095,22 @@ snapshots: '@tanstack/query-devtools@5.101.4': {} - '@tanstack/react-devtools@0.10.10(@neodrag/core@3.0.0-next.11)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14)': + '@tanstack/react-devtools@0.10.12(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15)': dependencies: - '@tanstack/devtools': 0.14.0(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + '@tanstack/devtools': 0.14.2(csstype@3.2.3)(solid-js@1.9.15) '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) transitivePeerDependencies: - - '@neodrag/core' - bufferutil - csstype - solid-js - utf-8-validate - '@tanstack/react-devtools@0.10.5(@types/react-dom@19.2.3(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.6(react@19.2.8))(react@19.2.8)(solid-js@1.9.14)': + '@tanstack/react-devtools@0.10.5(@types/react-dom@19.2.3(@types/react@19.2.18))(@types/react@19.2.18)(csstype@3.2.3)(react-dom@19.2.6(react@19.2.8))(react@19.2.8)(solid-js@1.9.15)': dependencies: - '@tanstack/devtools': 0.12.2(csstype@3.2.3)(solid-js@1.9.14) + '@tanstack/devtools': 0.12.2(csstype@3.2.3)(solid-js@1.9.15) '@types/react': 19.2.18 '@types/react-dom': 19.2.3(@types/react@19.2.18) react: 19.2.8 @@ -35583,10 +37121,10 @@ snapshots: - solid-js - utf-8-validate - '@tanstack/react-form-devtools@0.2.34(@types/react@19.2.18)(csstype@3.2.3)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(vue@3.5.41(typescript@6.0.3))': + '@tanstack/react-form-devtools@0.2.34(@types/react@19.2.18)(csstype@3.2.3)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(vue@3.5.41(typescript@6.0.3))': dependencies: - '@tanstack/devtools-utils': 0.4.0(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(vue@3.5.41(typescript@6.0.3)) - '@tanstack/form-devtools': 0.2.34(@types/react@19.2.18)(csstype@3.2.3)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(vue@3.5.41(typescript@6.0.3)) + '@tanstack/devtools-utils': 0.4.0(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(vue@3.5.41(typescript@6.0.3)) + '@tanstack/form-devtools': 0.2.34(@types/react@19.2.18)(csstype@3.2.3)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(vue@3.5.41(typescript@6.0.3)) react: 19.2.8 transitivePeerDependencies: - '@types/react' @@ -35595,13 +37133,13 @@ snapshots: - solid-js - vue - '@tanstack/react-form@1.33.5(@tanstack/react-start@1.168.44(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@tanstack/react-form@1.33.5(@tanstack/react-start@1.168.49(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@tanstack/form-core': 1.33.5 - '@tanstack/react-store': 0.11.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@tanstack/react-store': 0.11.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 optionalDependencies: - '@tanstack/react-start': 1.168.44(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) + '@tanstack/react-start': 1.168.49(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) transitivePeerDependencies: - react-dom @@ -35612,12 +37150,12 @@ snapshots: react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - '@tanstack/react-pacer-devtools@0.8.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(preact@10.29.8)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3))': + '@tanstack/react-pacer-devtools@0.8.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(preact@10.29.8)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3))': dependencies: - '@tanstack/devtools-utils': 0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) - '@tanstack/pacer-devtools': 1.4.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) + '@tanstack/devtools-utils': 0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) + '@tanstack/pacer-devtools': 1.4.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) transitivePeerDependencies: @@ -35646,43 +37184,43 @@ snapshots: '@tanstack/query-core': 5.101.4 react: 19.2.8 - '@tanstack/react-router-devtools@1.167.1(@tanstack/react-router@1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@tanstack/router-core@1.171.22)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@tanstack/react-router-devtools@1.167.1(@tanstack/react-router@1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@tanstack/router-core@1.171.27)(csstype@3.2.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@tanstack/react-router': 1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@tanstack/router-devtools-core': 1.168.1(@tanstack/router-core@1.171.22)(csstype@3.2.3) + '@tanstack/react-router': 1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@tanstack/router-devtools-core': 1.168.1(@tanstack/router-core@1.171.27)(csstype@3.2.3) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@tanstack/router-core': 1.171.22 + '@tanstack/router-core': 1.171.27 transitivePeerDependencies: - csstype - '@tanstack/react-router@1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@tanstack/react-router@1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@tanstack/history': 1.162.1 '@tanstack/react-store': 0.9.3(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@tanstack/router-core': 1.171.22 + '@tanstack/router-core': 1.171.27 isbot: 5.1.41 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - '@tanstack/react-start-client@1.168.25(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@tanstack/react-start-client@1.168.30(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@tanstack/react-router': 1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@tanstack/router-core': 1.171.22 - '@tanstack/start-client-core': 1.170.22 + '@tanstack/react-router': 1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@tanstack/router-core': 1.171.27 + '@tanstack/start-client-core': 1.170.27 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - '@tanstack/react-start-rsc@0.1.43(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))': + '@tanstack/react-start-rsc@0.1.48(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))': dependencies: - '@tanstack/react-router': 1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@tanstack/router-core': 1.171.22 + '@tanstack/react-router': 1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@tanstack/router-core': 1.171.27 '@tanstack/router-utils': 1.162.2(supports-color@7.2.0) - '@tanstack/start-client-core': 1.170.22 + '@tanstack/start-client-core': 1.170.27 '@tanstack/start-fn-stubs': 1.162.0 - '@tanstack/start-plugin-core': 1.171.34(@tanstack/react-router@1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) - '@tanstack/start-storage-context': 1.167.24 + '@tanstack/start-plugin-core': 1.171.39(@tanstack/react-router@1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) + '@tanstack/start-storage-context': 1.167.29 pathe: 2.0.3 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) @@ -35694,31 +37232,31 @@ snapshots: - vite-plugin-solid - webpack - '@tanstack/react-start-server@1.167.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@tanstack/react-start-server@1.167.37(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@tanstack/react-router': 1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@tanstack/router-core': 1.171.22 - '@tanstack/start-server-core': 1.169.26 + '@tanstack/react-router': 1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@tanstack/router-core': 1.171.27 + '@tanstack/start-server-core': 1.169.31 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) transitivePeerDependencies: - crossws - '@tanstack/react-start@1.168.44(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))': + '@tanstack/react-start@1.168.49(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))': dependencies: - '@tanstack/react-router': 1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@tanstack/react-start-client': 1.168.25(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@tanstack/react-start-rsc': 0.1.43(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) - '@tanstack/react-start-server': 1.167.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@tanstack/react-router': 1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@tanstack/react-start-client': 1.168.30(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@tanstack/react-start-rsc': 0.1.48(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) + '@tanstack/react-start-server': 1.167.37(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tanstack/router-utils': 1.162.2(supports-color@7.2.0) - '@tanstack/start-client-core': 1.170.22 - '@tanstack/start-plugin-core': 1.171.34(@tanstack/react-router@1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) - '@tanstack/start-server-core': 1.169.26 + '@tanstack/start-client-core': 1.170.27 + '@tanstack/start-plugin-core': 1.171.39(@tanstack/react-router@1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) + '@tanstack/start-server-core': 1.169.31 pathe: 2.0.3 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) transitivePeerDependencies: - '@rspack/core' - crossws @@ -35727,13 +37265,6 @@ snapshots: - vite-plugin-solid - webpack - '@tanstack/react-store@0.11.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': - dependencies: - '@tanstack/store': 0.11.0 - react: 19.2.8 - react-dom: 19.2.8(react@19.2.8) - use-sync-external-store: 1.6.0(react@19.2.8) - '@tanstack/react-store@0.11.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@tanstack/store': 0.11.1 @@ -35748,31 +37279,31 @@ snapshots: react-dom: 19.2.8(react@19.2.8) use-sync-external-store: 1.6.0(react@19.2.8) - '@tanstack/react-virtual@3.14.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@tanstack/react-virtual@3.14.10(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@tanstack/virtual-core': 3.17.7 + '@tanstack/virtual-core': 3.17.8 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - '@tanstack/router-core@1.171.22': + '@tanstack/router-core@1.171.27': dependencies: '@tanstack/history': 1.162.1 cookie-es: 3.1.1 seroval: 1.6.2 seroval-plugins: 1.6.2(seroval@1.6.2) - '@tanstack/router-devtools-core@1.168.1(@tanstack/router-core@1.171.22)(csstype@3.2.3)': + '@tanstack/router-devtools-core@1.168.1(@tanstack/router-core@1.171.27)(csstype@3.2.3)': dependencies: - '@tanstack/router-core': 1.171.22 + '@tanstack/router-core': 1.171.27 clsx: 2.1.1 goober: 2.1.19(csstype@3.2.3) optionalDependencies: csstype: 3.2.3 - '@tanstack/router-generator@1.167.28(supports-color@7.2.0)': + '@tanstack/router-generator@1.167.33(supports-color@7.2.0)': dependencies: '@babel/types': 7.29.8 - '@tanstack/router-core': 1.171.22 + '@tanstack/router-core': 1.171.27 '@tanstack/router-utils': 1.162.2(supports-color@7.2.0) '@tanstack/virtual-file-routes': 1.162.0 jiti: 2.7.0 @@ -35782,22 +37313,22 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.168.30(@tanstack/react-router@1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))': + '@tanstack/router-plugin@1.168.35(@tanstack/react-router@1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))': dependencies: '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/template': 7.29.7 '@babel/types': 7.29.8 - '@tanstack/router-core': 1.171.22 - '@tanstack/router-generator': 1.167.28(supports-color@7.2.0) + '@tanstack/router-core': 1.171.27 + '@tanstack/router-generator': 1.167.33(supports-color@7.2.0) '@tanstack/router-utils': 1.162.2(supports-color@7.2.0) chokidar: 5.0.0 unplugin: 3.0.0 zod: 4.4.3 optionalDependencies: - '@tanstack/react-router': 1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) - vite-plugin-solid: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3) + '@tanstack/react-router': 1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite-plugin-solid: 2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3) transitivePeerDependencies: - supports-color @@ -35814,9 +37345,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-vite-plugin@1.167.30(@tanstack/react-router@1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))': + '@tanstack/router-vite-plugin@1.167.35(@tanstack/react-router@1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))': dependencies: - '@tanstack/router-plugin': 1.168.30(@tanstack/react-router@1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) + '@tanstack/router-plugin': 1.168.35(@tanstack/react-router@1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) transitivePeerDependencies: - '@rsbuild/core' - '@tanstack/react-router' @@ -35825,21 +37356,20 @@ snapshots: - vite-plugin-solid - webpack - '@tanstack/solid-devtools@0.8.10(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14)': + '@tanstack/solid-devtools@0.8.12(csstype@3.2.3)(solid-js@1.9.15)': dependencies: - '@tanstack/devtools': 0.14.0(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) - solid-js: 1.9.14 + '@tanstack/devtools': 0.14.2(csstype@3.2.3)(solid-js@1.9.15) + solid-js: 1.9.15 transitivePeerDependencies: - - '@neodrag/core' - bufferutil - csstype - utf-8-validate - '@tanstack/solid-form-devtools@0.2.34(@types/react@19.2.18)(csstype@3.2.3)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(vue@3.5.41(typescript@6.0.3))': + '@tanstack/solid-form-devtools@0.2.34(@types/react@19.2.18)(csstype@3.2.3)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(vue@3.5.41(typescript@6.0.3))': dependencies: - '@tanstack/devtools-utils': 0.4.0(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(vue@3.5.41(typescript@6.0.3)) - '@tanstack/form-devtools': 0.2.34(@types/react@19.2.18)(csstype@3.2.3)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(vue@3.5.41(typescript@6.0.3)) - solid-js: 1.9.14 + '@tanstack/devtools-utils': 0.4.0(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(vue@3.5.41(typescript@6.0.3)) + '@tanstack/form-devtools': 0.2.34(@types/react@19.2.18)(csstype@3.2.3)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(vue@3.5.41(typescript@6.0.3)) + solid-js: 1.9.15 transitivePeerDependencies: - '@types/react' - csstype @@ -35847,23 +37377,23 @@ snapshots: - react - vue - '@tanstack/solid-form@1.33.5(solid-js@1.9.14)': + '@tanstack/solid-form@1.33.5(solid-js@1.9.15)': dependencies: '@tanstack/form-core': 1.33.5 - '@tanstack/solid-store': 0.11.0(solid-js@1.9.14) - solid-js: 1.9.14 + '@tanstack/solid-store': 0.11.0(solid-js@1.9.15) + solid-js: 1.9.15 - '@tanstack/solid-hotkeys@0.10.0(solid-js@1.9.14)': + '@tanstack/solid-hotkeys@0.10.0(solid-js@1.9.15)': dependencies: '@tanstack/hotkeys': 0.8.0 - '@tanstack/solid-store': 0.11.0(solid-js@1.9.14) - solid-js: 1.9.14 + '@tanstack/solid-store': 0.11.0(solid-js@1.9.15) + solid-js: 1.9.15 - '@tanstack/solid-pacer-devtools@0.7.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3))': + '@tanstack/solid-pacer-devtools@0.7.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3))': dependencies: - '@tanstack/devtools-utils': 0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) - '@tanstack/pacer-devtools': 1.4.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vue@3.5.41(typescript@6.0.3)) - solid-js: 1.9.14 + '@tanstack/devtools-utils': 0.6.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) + '@tanstack/pacer-devtools': 1.4.0(@angular/core@22.1.1(@angular/compiler@22.1.1)(rxjs@7.8.2))(@tanstack/pacer@0.22.0)(@types/react@19.2.18)(preact@10.29.8)(react@19.2.8)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vue@3.5.41(typescript@6.0.3)) + solid-js: 1.9.15 transitivePeerDependencies: - '@angular/core' - '@tanstack/pacer' @@ -35873,76 +37403,81 @@ snapshots: - svelte - vue - '@tanstack/solid-pacer@0.22.0(solid-js@1.9.14)': + '@tanstack/solid-pacer@0.22.0(solid-js@1.9.15)': dependencies: '@tanstack/pacer': 0.22.0 - '@tanstack/solid-store': 0.11.1(solid-js@1.9.14) - solid-js: 1.9.14 + '@tanstack/solid-store': 0.11.1(solid-js@1.9.15) + solid-js: 1.9.15 - '@tanstack/solid-query-devtools@5.101.4(@tanstack/solid-query@5.101.4(solid-js@1.9.14))(solid-js@1.9.14)': + '@tanstack/solid-query-devtools@5.101.4(@tanstack/solid-query@5.101.4(solid-js@1.9.15))(solid-js@1.9.15)': dependencies: '@tanstack/query-devtools': 5.101.4 - '@tanstack/solid-query': 5.101.4(solid-js@1.9.14) - solid-js: 1.9.14 + '@tanstack/solid-query': 5.101.4(solid-js@1.9.15) + solid-js: 1.9.15 - '@tanstack/solid-query@5.101.4(solid-js@1.9.14)': + '@tanstack/solid-query@5.101.4(solid-js@1.9.15)': dependencies: '@tanstack/query-core': 5.101.4 - solid-js: 1.9.14 + solid-js: 1.9.15 - '@tanstack/solid-router-devtools@1.167.1(@tanstack/router-core@1.171.22)(@tanstack/solid-router@1.170.25(solid-js@1.9.14))(csstype@3.2.3)(solid-js@1.9.14)': + '@tanstack/solid-router-devtools@1.167.1(@tanstack/router-core@1.171.27)(@tanstack/solid-router@1.170.30(solid-js@1.9.15))(csstype@3.2.3)(solid-js@1.9.15)': dependencies: - '@tanstack/router-devtools-core': 1.168.1(@tanstack/router-core@1.171.22)(csstype@3.2.3) - '@tanstack/solid-router': 1.170.25(solid-js@1.9.14) - solid-js: 1.9.14 + '@tanstack/router-devtools-core': 1.168.1(@tanstack/router-core@1.171.27)(csstype@3.2.3) + '@tanstack/solid-router': 1.170.30(solid-js@1.9.15) + solid-js: 1.9.15 optionalDependencies: - '@tanstack/router-core': 1.171.22 + '@tanstack/router-core': 1.171.27 transitivePeerDependencies: - csstype - '@tanstack/solid-router@1.170.25(solid-js@1.9.14)': + '@tanstack/solid-router@1.170.30(solid-js@1.9.15)': dependencies: - '@solid-primitives/refs': 1.1.3(solid-js@1.9.14) - '@solidjs/meta': 0.29.4(solid-js@1.9.14) + '@solid-primitives/refs': 1.1.3(solid-js@1.9.15) + '@solidjs/meta': 0.29.4(solid-js@1.9.15) '@tanstack/history': 1.162.1 - '@tanstack/router-core': 1.171.22 + '@tanstack/router-core': 1.171.27 isbot: 5.1.41 - solid-js: 1.9.14 + solid-js: 1.9.15 - '@tanstack/solid-store@0.11.0(solid-js@1.9.14)': + '@tanstack/solid-store@0.11.0(solid-js@1.9.15)': dependencies: '@tanstack/store': 0.11.0 - solid-js: 1.9.14 + solid-js: 1.9.15 '@tanstack/solid-store@0.11.1(solid-js@1.9.14)': dependencies: '@tanstack/store': 0.11.1 solid-js: 1.9.14 - '@tanstack/solid-virtual@3.13.36(solid-js@1.9.14)': + '@tanstack/solid-store@0.11.1(solid-js@1.9.15)': dependencies: - '@tanstack/virtual-core': 3.17.7 - solid-js: 1.9.14 + '@tanstack/store': 0.11.1 + solid-js: 1.9.15 + + '@tanstack/solid-virtual@3.13.37(solid-js@1.9.15)': + dependencies: + '@tanstack/virtual-core': 3.17.8 + solid-js: 1.9.15 - '@tanstack/start-client-core@1.170.22': + '@tanstack/start-client-core@1.170.27': dependencies: - '@tanstack/router-core': 1.171.22 + '@tanstack/router-core': 1.171.27 '@tanstack/start-fn-stubs': 1.162.0 - '@tanstack/start-storage-context': 1.167.24 + '@tanstack/start-storage-context': 1.167.29 seroval: 1.6.2 '@tanstack/start-fn-stubs@1.162.0': {} - '@tanstack/start-plugin-core@1.171.34(@tanstack/react-router@1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))': + '@tanstack/start-plugin-core@1.171.39(@tanstack/react-router@1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))': dependencies: '@babel/code-frame': 7.27.1 '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/types': 7.29.8 - '@tanstack/router-core': 1.171.22 - '@tanstack/router-generator': 1.167.28(supports-color@7.2.0) - '@tanstack/router-plugin': 1.168.30(@tanstack/react-router@1.170.27(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) + '@tanstack/router-core': 1.171.27 + '@tanstack/router-generator': 1.167.33(supports-color@7.2.0) + '@tanstack/router-plugin': 1.168.35(@tanstack/react-router@1.170.32(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(supports-color@7.2.0)(vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) '@tanstack/router-utils': 1.162.2(supports-color@7.2.0) - '@tanstack/start-server-core': 1.169.26 + '@tanstack/start-server-core': 1.169.31 exsolve: 1.1.0 lightningcss: 1.33.0 pathe: 2.0.3 @@ -35952,11 +37487,11 @@ snapshots: srvx: 0.11.18 tinyglobby: 0.2.17 ufo: 1.6.4 - vitefu: 1.1.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + vitefu: 1.1.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) xmlbuilder2: 4.0.3 zod: 4.4.3 optionalDependencies: - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) transitivePeerDependencies: - '@tanstack/react-router' - crossws @@ -35964,21 +37499,21 @@ snapshots: - vite-plugin-solid - webpack - '@tanstack/start-server-core@1.169.26': + '@tanstack/start-server-core@1.169.31': dependencies: '@tanstack/history': 1.162.1 - '@tanstack/router-core': 1.171.22 - '@tanstack/start-client-core': 1.170.22 - '@tanstack/start-storage-context': 1.167.24 + '@tanstack/router-core': 1.171.27 + '@tanstack/start-client-core': 1.170.27 + '@tanstack/start-storage-context': 1.167.29 fetchdts: 0.1.7 h3-v2: h3@2.0.1-rc.20 seroval: 1.6.2 transitivePeerDependencies: - crossws - '@tanstack/start-storage-context@1.167.24': + '@tanstack/start-storage-context@1.167.29': dependencies: - '@tanstack/router-core': 1.171.22 + '@tanstack/router-core': 1.171.27 '@tanstack/store@0.11.0': {} @@ -35986,54 +37521,48 @@ snapshots: '@tanstack/store@0.9.3': {} - '@tanstack/svelte-devtools@0.1.3(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14)(svelte@5.56.8(@typescript-eslint/types@8.67.0))': + '@tanstack/svelte-devtools@0.1.6(csstype@3.2.3)(solid-js@1.9.15)(svelte@5.56.10(@typescript-eslint/types@8.68.0))': dependencies: - '@tanstack/devtools': 0.14.0(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + '@tanstack/devtools': 0.14.2(csstype@3.2.3)(solid-js@1.9.15) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) transitivePeerDependencies: - - '@neodrag/core' - bufferutil - csstype - solid-js - utf-8-validate - '@tanstack/svelte-form@1.33.5(svelte@5.56.8(@typescript-eslint/types@8.67.0))': + '@tanstack/svelte-form@1.33.5(svelte@5.56.10(@typescript-eslint/types@8.68.0))': dependencies: '@tanstack/form-core': 1.33.5 - '@tanstack/svelte-store': 0.12.0(svelte@5.56.8(@typescript-eslint/types@8.67.0)) - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + '@tanstack/svelte-store': 0.12.1(svelte@5.56.10(@typescript-eslint/types@8.68.0)) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) - '@tanstack/svelte-hotkeys@0.10.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))': + '@tanstack/svelte-hotkeys@0.10.0(svelte@5.56.10(@typescript-eslint/types@8.68.0))': dependencies: '@tanstack/hotkeys': 0.8.0 - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) - '@tanstack/svelte-query-devtools@6.1.38(@tanstack/svelte-query@6.1.38(svelte@5.56.8(@typescript-eslint/types@8.67.0)))(svelte@5.56.8(@typescript-eslint/types@8.67.0))': + '@tanstack/svelte-query-devtools@6.1.38(@tanstack/svelte-query@6.1.38(svelte@5.56.10(@typescript-eslint/types@8.68.0)))(svelte@5.56.10(@typescript-eslint/types@8.68.0))': dependencies: '@tanstack/query-devtools': 5.101.4 - '@tanstack/svelte-query': 6.1.38(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + '@tanstack/svelte-query': 6.1.38(svelte@5.56.10(@typescript-eslint/types@8.68.0)) esm-env: 1.2.2 - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) - '@tanstack/svelte-query@6.1.38(svelte@5.56.8(@typescript-eslint/types@8.67.0))': + '@tanstack/svelte-query@6.1.38(svelte@5.56.10(@typescript-eslint/types@8.68.0))': dependencies: '@tanstack/query-core': 5.101.4 - svelte: 5.56.8(@typescript-eslint/types@8.67.0) - - '@tanstack/svelte-store@0.12.0(svelte@5.56.8(@typescript-eslint/types@8.67.0))': - dependencies: - '@tanstack/store': 0.11.0 - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) - '@tanstack/svelte-store@0.12.1(svelte@5.56.8(@typescript-eslint/types@8.67.0))': + '@tanstack/svelte-store@0.12.1(svelte@5.56.10(@typescript-eslint/types@8.68.0))': dependencies: '@tanstack/store': 0.11.1 - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) - '@tanstack/svelte-virtual@3.13.35(svelte@5.56.8(@typescript-eslint/types@8.67.0))': + '@tanstack/svelte-virtual@3.13.36(svelte@5.56.10(@typescript-eslint/types@8.68.0))': dependencies: - '@tanstack/virtual-core': 3.17.7 - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + '@tanstack/virtual-core': 3.17.8 + svelte: 5.56.10(@typescript-eslint/types@8.68.0) '@tanstack/typedoc-config@0.3.4(typescript@6.0.3)': dependencies: @@ -36045,13 +37574,14 @@ snapshots: '@tanstack/virtual-core@3.17.7': {} + '@tanstack/virtual-core@3.17.8': {} + '@tanstack/virtual-file-routes@1.162.0': {} - '@tanstack/vue-devtools@0.2.24(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14)': + '@tanstack/vue-devtools@0.2.26(csstype@3.2.3)(solid-js@1.9.15)': dependencies: - '@tanstack/devtools': 0.14.0(@neodrag/core@3.0.0-next.11)(csstype@3.2.3)(solid-js@1.9.14) + '@tanstack/devtools': 0.14.2(csstype@3.2.3)(solid-js@1.9.15) transitivePeerDependencies: - - '@neodrag/core' - bufferutil - csstype - solid-js @@ -36060,7 +37590,7 @@ snapshots: '@tanstack/vue-form@1.33.5(vue@3.5.41(typescript@6.0.3))': dependencies: '@tanstack/form-core': 1.33.5 - '@tanstack/vue-store': 0.11.0(vue@3.5.41(typescript@6.0.3)) + '@tanstack/vue-store': 0.11.1(vue@3.5.41(typescript@6.0.3)) vue: 3.5.41(typescript@6.0.3) transitivePeerDependencies: - '@vue/composition-api' @@ -36104,6 +37634,11 @@ snapshots: '@tanstack/virtual-core': 3.17.7 vue: 3.5.41(typescript@6.0.3) + '@tanstack/vue-virtual@3.13.36(vue@3.5.41(typescript@6.0.3))': + dependencies: + '@tanstack/virtual-core': 3.17.8 + vue: 3.5.41(typescript@6.0.3) + '@testing-library/dom@10.4.1': dependencies: '@babel/code-frame': 7.29.7 @@ -36137,7 +37672,7 @@ snapshots: lz-string: 1.5.0 pretty-format: 27.5.1 - '@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10)': + '@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11)': dependencies: '@adobe/css-tools': 4.5.0 '@testing-library/dom': 10.4.1 @@ -36147,14 +37682,14 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 optionalDependencies: - vitest: 4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + vitest: 4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@testing-library/preact@3.2.4(preact@10.29.8)': dependencies: '@testing-library/dom': 8.20.1 preact: 10.29.8(preact-render-to-string@6.7.0) - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@babel/runtime': 7.29.7 '@testing-library/dom': 10.4.1 @@ -36162,20 +37697,20 @@ snapshots: react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) - '@testing-library/svelte-core@1.1.3(svelte@5.56.8(@typescript-eslint/types@8.67.0))': + '@testing-library/svelte-core@1.1.3(svelte@5.56.10(@typescript-eslint/types@8.68.0))': dependencies: - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) - '@testing-library/svelte@5.4.2(svelte@5.56.8(@typescript-eslint/types@8.67.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0))(vitest@4.1.10)': + '@testing-library/svelte@5.4.2(svelte@5.56.10(@typescript-eslint/types@8.68.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vitest@4.1.11)': dependencies: '@testing-library/dom': 10.4.1 - '@testing-library/svelte-core': 1.1.3(svelte@5.56.8(@typescript-eslint/types@8.67.0)) - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + '@testing-library/svelte-core': 1.1.3(svelte@5.56.10(@typescript-eslint/types@8.68.0)) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) optionalDependencies: - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0) - vitest: 4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0)) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vitest: 4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@testing-library/vue@8.1.0(@vue/compiler-dom@3.5.41)(@vue/compiler-sfc@3.5.41)(@vue/server-renderer@3.5.41)(vue@3.5.41(typescript@6.0.3))': dependencies: @@ -36191,7 +37726,7 @@ snapshots: '@tsconfig/svelte@5.0.8': {} - '@tsrx/core@0.1.56(@typescript-eslint/types@8.67.0)': + '@tsrx/core@0.1.56(@typescript-eslint/types@8.68.0)': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 '@noble/hashes': 2.2.0 @@ -36199,25 +37734,24 @@ snapshots: '@types/estree': 1.0.9 '@types/estree-jsx': 1.0.5 acorn: 8.18.0 - esrap: 2.3.0(@typescript-eslint/types@8.67.0) + esrap: 2.3.0(@typescript-eslint/types@8.68.0) is-reference: 3.0.3 magic-string: 0.30.21 zimmerframe: 1.1.4 transitivePeerDependencies: - '@typescript-eslint/types' - '@tsrx/typescript-plugin@0.3.118(octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3)': + '@tsrx/typescript-plugin@0.3.118(octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(typescript@6.0.3)': dependencies: '@volar/language-core': 2.4.28 '@volar/typescript': 2.4.28(typescript@6.0.3) typescript: 6.0.3 optionalDependencies: - octane: 0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + octane: 0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) '@tybys/wasm-util@0.10.3': dependencies: tslib: 2.8.1 - optional: true '@tybys/wasm-util@0.9.0': dependencies: @@ -36273,7 +37807,7 @@ snapshots: '@types/cors@2.8.19': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/deep-eql@4.0.2': {} @@ -36334,10 +37868,6 @@ snapshots: '@types/minimatch@3.0.5': {} - '@types/node@26.1.2': - dependencies: - undici-types: 8.3.0 - '@types/node@26.2.0': dependencies: undici-types: 8.3.0 @@ -36356,7 +37886,7 @@ snapshots: dependencies: '@types/react': 19.2.18 - '@types/react-dom@19.2.4(@types/react@19.2.18)': + '@types/react-dom@19.2.5(@types/react@19.2.18)': dependencies: '@types/react': 19.2.18 @@ -36410,15 +37940,15 @@ snapshots: dependencies: '@types/node': 26.2.0 - '@typescript-eslint/eslint-plugin@8.60.1(@typescript-eslint/parser@8.60.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': + '@typescript-eslint/eslint-plugin@8.60.1(@typescript-eslint/parser@8.60.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.60.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.60.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.60.1 - '@typescript-eslint/type-utils': 8.60.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.60.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/type-utils': 8.60.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.60.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.60.1 - eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + eslint: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@6.0.3) @@ -36426,15 +37956,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.67.0(@typescript-eslint/parser@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': + '@typescript-eslint/eslint-plugin@8.68.0(@typescript-eslint/parser@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.67.0 - '@typescript-eslint/type-utils': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/utils': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.67.0 - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + '@typescript-eslint/parser': 8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.68.0 + '@typescript-eslint/type-utils': 8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/utils': 8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.68.0 + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@6.0.3) @@ -36442,46 +37972,46 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.60.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': + '@typescript-eslint/parser@8.60.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.60.1 '@typescript-eslint/types': 8.60.1 '@typescript-eslint/typescript-estree': 8.60.1(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.60.1 debug: 4.4.3(supports-color@7.2.0) - eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + eslint: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': + '@typescript-eslint/parser@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/scope-manager': 8.67.0 - '@typescript-eslint/types': 8.67.0 - '@typescript-eslint/typescript-estree': 8.67.0(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.67.0 + '@typescript-eslint/scope-manager': 8.68.0 + '@typescript-eslint/types': 8.68.0 + '@typescript-eslint/typescript-estree': 8.68.0(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.68.0 debug: 4.4.3(supports-color@7.2.0) - eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + eslint: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': + '@typescript-eslint/parser@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@typescript-eslint/scope-manager': 8.67.0 - '@typescript-eslint/types': 8.67.0 - '@typescript-eslint/typescript-estree': 8.67.0(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.67.0 + '@typescript-eslint/scope-manager': 8.68.0 + '@typescript-eslint/types': 8.68.0 + '@typescript-eslint/typescript-estree': 8.68.0(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.68.0 debug: 4.4.3(supports-color@8.1.1) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) typescript: 6.0.3 transitivePeerDependencies: - supports-color '@typescript-eslint/project-service@8.60.1(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@6.0.3) - '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3) + '@typescript-eslint/types': 8.67.0 debug: 4.4.3(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: @@ -36489,35 +38019,35 @@ snapshots: '@typescript-eslint/project-service@8.60.1(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@6.0.3) - '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3) + '@typescript-eslint/types': 8.67.0 debug: 4.4.3(supports-color@8.1.1) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.65.0(supports-color@8.1.1)(typescript@6.0.3)': + '@typescript-eslint/project-service@8.67.0(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@6.0.3) - '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3) + '@typescript-eslint/types': 8.67.0 debug: 4.4.3(supports-color@8.1.1) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.67.0(supports-color@7.2.0)(typescript@6.0.3)': + '@typescript-eslint/project-service@8.68.0(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3) - '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/tsconfig-utils': 8.68.0(typescript@6.0.3) + '@typescript-eslint/types': 8.68.0 debug: 4.4.3(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.67.0(supports-color@8.1.1)(typescript@6.0.3)': + '@typescript-eslint/project-service@8.68.0(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3) - '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/tsconfig-utils': 8.68.0(typescript@6.0.3) + '@typescript-eslint/types': 8.68.0 debug: 4.4.3(supports-color@8.1.1) typescript: 6.0.3 transitivePeerDependencies: @@ -36528,16 +38058,16 @@ snapshots: '@typescript-eslint/types': 8.60.1 '@typescript-eslint/visitor-keys': 8.60.1 - '@typescript-eslint/scope-manager@8.65.0': - dependencies: - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/visitor-keys': 8.65.0 - '@typescript-eslint/scope-manager@8.67.0': dependencies: '@typescript-eslint/types': 8.67.0 '@typescript-eslint/visitor-keys': 8.67.0 + '@typescript-eslint/scope-manager@8.68.0': + dependencies: + '@typescript-eslint/types': 8.68.0 + '@typescript-eslint/visitor-keys': 8.68.0 + '@typescript-eslint/tsconfig-utils@8.60.1(typescript@6.0.3)': dependencies: typescript: 6.0.3 @@ -36550,37 +38080,41 @@ snapshots: dependencies: typescript: 6.0.3 - '@typescript-eslint/type-utils@8.60.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': + '@typescript-eslint/tsconfig-utils@8.68.0(typescript@6.0.3)': + dependencies: + typescript: 6.0.3 + + '@typescript-eslint/type-utils@8.60.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.60.1 '@typescript-eslint/typescript-estree': 8.60.1(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.60.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.60.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) debug: 4.4.3(supports-color@7.2.0) - eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + eslint: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.65.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/typescript-estree': 8.65.0(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/utils': 8.65.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/typescript-estree': 8.67.0(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/utils': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) debug: 4.4.3(supports-color@8.1.1) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.67.0 - '@typescript-eslint/typescript-estree': 8.67.0(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/utils': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/types': 8.68.0 + '@typescript-eslint/typescript-estree': 8.68.0(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/utils': 8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) debug: 4.4.3(supports-color@8.1.1) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: @@ -36590,10 +38124,10 @@ snapshots: '@typescript-eslint/types@8.62.0': {} - '@typescript-eslint/types@8.65.0': {} - '@typescript-eslint/types@8.67.0': {} + '@typescript-eslint/types@8.68.0': {} + '@typescript-eslint/typescript-estree@8.60.1(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/project-service': 8.60.1(supports-color@7.2.0)(typescript@6.0.3) @@ -36624,12 +38158,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.65.0(supports-color@8.1.1)(typescript@6.0.3)': + '@typescript-eslint/typescript-estree@8.67.0(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.65.0(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@6.0.3) - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/visitor-keys': 8.65.0 + '@typescript-eslint/project-service': 8.67.0(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3) + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/visitor-keys': 8.67.0 debug: 4.4.3(supports-color@8.1.1) minimatch: 10.2.5 semver: 7.8.5 @@ -36639,12 +38173,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.67.0(supports-color@7.2.0)(typescript@6.0.3)': + '@typescript-eslint/typescript-estree@8.68.0(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.67.0(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3) - '@typescript-eslint/types': 8.67.0 - '@typescript-eslint/visitor-keys': 8.67.0 + '@typescript-eslint/project-service': 8.68.0(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.68.0(typescript@6.0.3) + '@typescript-eslint/types': 8.68.0 + '@typescript-eslint/visitor-keys': 8.68.0 debug: 4.4.3(supports-color@7.2.0) minimatch: 10.2.5 semver: 7.8.5 @@ -36654,12 +38188,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.67.0(supports-color@8.1.1)(typescript@6.0.3)': + '@typescript-eslint/typescript-estree@8.68.0(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.67.0(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3) - '@typescript-eslint/types': 8.67.0 - '@typescript-eslint/visitor-keys': 8.67.0 + '@typescript-eslint/project-service': 8.68.0(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.68.0(typescript@6.0.3) + '@typescript-eslint/types': 8.68.0 + '@typescript-eslint/visitor-keys': 8.68.0 debug: 4.4.3(supports-color@8.1.1) minimatch: 10.2.5 semver: 7.8.5 @@ -36669,58 +38203,58 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.60.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': + '@typescript-eslint/utils@8.60.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0)) '@typescript-eslint/scope-manager': 8.60.1 '@typescript-eslint/types': 8.60.1 '@typescript-eslint/typescript-estree': 8.60.1(supports-color@7.2.0)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + eslint: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.60.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': + '@typescript-eslint/utils@8.60.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)) '@typescript-eslint/scope-manager': 8.60.1 '@typescript-eslint/types': 8.60.1 '@typescript-eslint/typescript-estree': 8.60.1(supports-color@8.1.1)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.65.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': + '@typescript-eslint/utils@8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)) - '@typescript-eslint/scope-manager': 8.65.0 - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/typescript-estree': 8.65.0(supports-color@8.1.1)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)) + '@typescript-eslint/scope-manager': 8.67.0 + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/typescript-estree': 8.67.0(supports-color@8.1.1)(typescript@6.0.3) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': + '@typescript-eslint/utils@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) - '@typescript-eslint/scope-manager': 8.67.0 - '@typescript-eslint/types': 8.67.0 - '@typescript-eslint/typescript-estree': 8.67.0(supports-color@7.2.0)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0)) + '@typescript-eslint/scope-manager': 8.68.0 + '@typescript-eslint/types': 8.68.0 + '@typescript-eslint/typescript-estree': 8.68.0(supports-color@7.2.0)(typescript@6.0.3) + eslint: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color optional: true - '@typescript-eslint/utils@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': + '@typescript-eslint/utils@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)) - '@typescript-eslint/scope-manager': 8.67.0 - '@typescript-eslint/types': 8.67.0 - '@typescript-eslint/typescript-estree': 8.67.0(supports-color@8.1.1)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)) + '@typescript-eslint/scope-manager': 8.68.0 + '@typescript-eslint/types': 8.68.0 + '@typescript-eslint/typescript-estree': 8.68.0(supports-color@8.1.1)(typescript@6.0.3) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -36730,14 +38264,14 @@ snapshots: '@typescript-eslint/types': 8.60.1 eslint-visitor-keys: 5.0.1 - '@typescript-eslint/visitor-keys@8.65.0': + '@typescript-eslint/visitor-keys@8.67.0': dependencies: - '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/types': 8.67.0 eslint-visitor-keys: 5.0.1 - '@typescript-eslint/visitor-keys@8.67.0': + '@typescript-eslint/visitor-keys@8.68.0': dependencies: - '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/types': 8.68.0 eslint-visitor-keys: 5.0.1 '@unrs/resolver-binding-android-arm-eabi@1.12.2': @@ -36810,131 +38344,126 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.12.2': optional: true - '@vitejs/plugin-basic-ssl@2.3.0(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.19))(terser@5.49.0)(yaml@2.9.0))': + '@vitejs/plugin-basic-ssl@2.3.0(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0))': dependencies: - vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.19))(terser@5.49.0)(yaml@2.9.0) + vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0) - '@vitejs/plugin-basic-ssl@2.3.0(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0))': + '@vitejs/plugin-basic-ssl@2.3.0(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': dependencies: - vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0) + vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) - '@vitejs/plugin-basic-ssl@2.3.0(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': + '@vitejs/plugin-react@6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@7.29.7(supports-color@8.1.1))(@babel/plugin-transform-runtime@8.0.1(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/runtime@8.0.0)(rolldown@1.2.6)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': dependencies: - vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + '@rolldown/pluginutils': 1.0.1 + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + optionalDependencies: + '@rolldown/plugin-babel': 0.2.3(@babel/core@7.29.7(supports-color@8.1.1))(@babel/plugin-transform-runtime@8.0.1(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/runtime@8.0.0)(rolldown@1.2.6)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + babel-plugin-react-compiler: 1.0.0 - '@vitejs/plugin-react@6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@7.29.7(supports-color@8.1.1))(@babel/plugin-transform-runtime@8.0.1(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': + '@vitejs/plugin-react@6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) optionalDependencies: - '@rolldown/plugin-babel': 0.2.3(@babel/core@7.29.7(supports-color@8.1.1))(@babel/plugin-transform-runtime@8.0.1(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/plugin-babel': 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: 1.0.0 - '@vitejs/plugin-react@6.0.5(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': + '@vitejs/plugin-react@6.1.0(@rolldown/plugin-babel@0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.6)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) optionalDependencies: - '@rolldown/plugin-babel': 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@rolldown/plugin-babel': 0.2.3(@babel/core@8.0.1)(@babel/plugin-transform-runtime@8.0.1(@babel/core@8.0.1))(@babel/runtime@8.0.0)(rolldown@1.2.6)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) babel-plugin-react-compiler: 1.0.0 - '@vitejs/plugin-vue-jsx@5.1.6(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3))': + '@vitejs/plugin-vue-jsx@5.1.6(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3))': dependencies: '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) '@rolldown/pluginutils': 1.0.1 '@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue: 3.5.41(typescript@6.0.3) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@6.0.8(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3))': + '@vitejs/plugin-vue@6.0.8(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3))': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) vue: 3.5.41(typescript@6.0.3) - '@vitest/coverage-v8@4.1.10(vitest@4.1.10)': + '@vitest/coverage-v8@4.1.11(vitest@4.1.11)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.1.10 + '@vitest/utils': 4.1.11 ast-v8-to-istanbul: 1.0.4 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-reports: 3.2.0 magicast: 0.5.3 - obug: 2.1.3 + obug: 2.1.4 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + vitest: 4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) - '@vitest/expect@4.1.10': + '@vitest/expect@4.1.11': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.10 - '@vitest/utils': 4.1.10 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.10(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.11(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.10 + '@vitest/spy': 4.1.11 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0) + vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) optional: true - '@vitest/mocker@4.1.10(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.19))(terser@5.49.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.11(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.10 + '@vitest/spy': 4.1.11 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.19))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0) optional: true - '@vitest/mocker@4.1.10(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.11(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.10 + '@vitest/spy': 4.1.11 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0) - optional: true + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) - '@vitest/mocker@4.1.10(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0))': - dependencies: - '@vitest/spy': 4.1.10 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) - - '@vitest/pretty-format@4.1.10': + '@vitest/pretty-format@4.1.11': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.10': + '@vitest/runner@4.1.11': dependencies: - '@vitest/utils': 4.1.10 + '@vitest/utils': 4.1.11 pathe: 2.0.3 - '@vitest/snapshot@4.1.10': + '@vitest/snapshot@4.1.11': dependencies: - '@vitest/pretty-format': 4.1.10 - '@vitest/utils': 4.1.10 + '@vitest/pretty-format': 4.1.11 + '@vitest/utils': 4.1.11 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.10': {} + '@vitest/spy@4.1.11': {} - '@vitest/utils@4.1.10': + '@vitest/utils@4.1.11': dependencies: - '@vitest/pretty-format': 4.1.10 + '@vitest/pretty-format': 4.1.11 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 @@ -37108,7 +38637,7 @@ snapshots: '@vue/shared': 3.5.40 estree-walker: 2.0.2 magic-string: 0.30.21 - postcss: 8.5.25 + postcss: 8.5.26 source-map-js: 1.2.1 '@vue/compiler-sfc@3.5.41': @@ -37135,7 +38664,7 @@ snapshots: '@vue/devtools-api@6.6.4': {} - '@vue/language-core@3.3.9': + '@vue/language-core@3.3.11': dependencies: '@volar/language-core': 2.4.28 '@vue/compiler-dom': 3.5.41 @@ -37145,10 +38674,6 @@ snapshots: path-browserify: 1.0.1 picomatch: 4.0.5 - '@vue/reactivity@3.1.5': - dependencies: - '@vue/shared': 3.1.5 - '@vue/reactivity@3.5.41': dependencies: '@vue/shared': 3.5.41 @@ -37171,8 +38696,6 @@ snapshots: '@vue/runtime-dom': 3.5.41 '@vue/shared': 3.5.41 - '@vue/shared@3.1.5': {} - '@vue/shared@3.5.40': {} '@vue/shared@3.5.41': {} @@ -37712,7 +39235,7 @@ snapshots: '@zag-js/popper@1.41.2': dependencies: - '@floating-ui/dom': 1.7.6 + '@floating-ui/dom': 1.8.0 '@zag-js/dom-query': 1.41.2 '@zag-js/utils': 1.41.2 @@ -37997,9 +39520,9 @@ snapshots: alien-signals@3.2.1: {} - alpinejs@3.16.1: + alpinejs@3.16.3: dependencies: - '@vue/reactivity': 3.1.5 + '@vue/reactivity': 3.5.41 amd-name-resolver@1.3.1: dependencies: @@ -38133,13 +39656,13 @@ snapshots: at-least-node@1.0.0: {} - autoprefixer@10.5.4(postcss@8.5.19): + autoprefixer@10.5.4(postcss@8.5.25): dependencies: browserslist: 4.28.7 caniuse-lite: 1.0.30001806 fraction.js: 5.3.4 picocolors: 1.1.1 - postcss: 8.5.19 + postcss: 8.5.25 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.7: @@ -38169,12 +39692,12 @@ snapshots: babel-import-util@3.0.1: {} - babel-loader@10.1.1(@babel/core@8.0.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + babel-loader@10.1.1(@babel/core@8.0.1)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: '@babel/core': 8.0.1 find-up: 5.0.0 optionalDependencies: - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) babel-plugin-debug-macros@0.3.4(@babel/core@7.29.7(supports-color@8.1.1)): dependencies: @@ -38279,19 +39802,19 @@ snapshots: dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) - babel-preset-solid@1.9.12(@babel/core@7.29.7(supports-color@7.2.0))(solid-js@1.9.14): + babel-preset-solid@1.9.12(@babel/core@7.29.7(supports-color@7.2.0))(solid-js@1.9.15): dependencies: '@babel/core': 7.29.7(supports-color@7.2.0) babel-plugin-jsx-dom-expressions: 0.40.7(@babel/core@7.29.7(supports-color@7.2.0)) optionalDependencies: - solid-js: 1.9.14 + solid-js: 1.9.15 - babel-preset-solid@1.9.12(@babel/core@7.29.7(supports-color@8.1.1))(solid-js@1.9.14): + babel-preset-solid@1.9.12(@babel/core@7.29.7(supports-color@8.1.1))(solid-js@1.9.15): dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) babel-plugin-jsx-dom-expressions: 0.40.7(@babel/core@7.29.7(supports-color@8.1.1)) optionalDependencies: - solid-js: 1.9.14 + solid-js: 1.9.15 backbone@1.6.1: dependencies: @@ -38307,8 +39830,6 @@ snapshots: base64id@2.0.0: {} - baseline-browser-mapping@2.10.34: {} - baseline-browser-mapping@2.11.8: {} batch@0.6.1: {} @@ -38321,9 +39842,9 @@ snapshots: domhandler: 5.0.3 htmlparser2: 10.1.0 picocolors: 1.1.1 - postcss: 8.5.25 + postcss: 8.5.26 postcss-media-query-parser: 0.2.3 - postcss-safe-parser: 7.0.1(postcss@8.5.25) + postcss-safe-parser: 7.0.1(postcss@8.5.26) better-path-resolve@1.0.0: dependencies: @@ -38341,15 +39862,15 @@ snapshots: birecord@0.1.2: {} - bits-ui@2.18.1(@internationalized/date@3.12.3)(svelte@5.56.8(@typescript-eslint/types@8.67.0)): + bits-ui@2.19.0(@internationalized/date@3.12.3)(svelte@5.56.10(@typescript-eslint/types@8.68.0)): dependencies: - '@floating-ui/core': 1.7.5 - '@floating-ui/dom': 1.7.6 + '@floating-ui/core': 1.8.0 + '@floating-ui/dom': 1.8.0 '@internationalized/date': 3.12.3 esm-env: 1.2.2 - runed: 0.35.1(svelte@5.56.8(@typescript-eslint/types@8.67.0)) - svelte: 5.56.8(@typescript-eslint/types@8.67.0) - svelte-toolbelt: 0.10.6(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + runed: 0.35.1(svelte@5.56.10(@typescript-eslint/types@8.68.0)) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) + svelte-toolbelt: 0.10.6(svelte@5.56.10(@typescript-eslint/types@8.68.0)) tabbable: 6.4.0 transitivePeerDependencies: - '@sveltejs/kit' @@ -38407,10 +39928,6 @@ snapshots: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.6: - dependencies: - balanced-match: 4.0.3 - brace-expansion@5.0.8: dependencies: balanced-match: 4.0.3 @@ -38517,14 +40034,6 @@ snapshots: browserslist: 4.28.7 meow: 13.2.0 - browserslist@4.28.2: - dependencies: - baseline-browser-mapping: 2.10.34 - caniuse-lite: 1.0.30001797 - electron-to-chromium: 1.5.368 - node-releases: 2.0.47 - update-browserslist-db: 1.2.3(browserslist@4.28.2) - browserslist@4.28.7: dependencies: baseline-browser-mapping: 2.11.8 @@ -38579,8 +40088,6 @@ snapshots: camelcase-css@2.0.1: {} - caniuse-lite@1.0.30001797: {} - caniuse-lite@1.0.30001806: {} chai@6.2.2: {} @@ -38665,9 +40172,9 @@ snapshots: cli-spinners@3.4.0: {} - cli-truncate@5.2.0: + cli-truncate@6.1.1: dependencies: - slice-ansi: 8.0.0 + slice-ansi: 9.0.0 string-width: 8.2.1 cli-width@4.1.0: {} @@ -38698,12 +40205,12 @@ snapshots: clsx@2.1.1: {} - cmdk@1.1.1(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): + cmdk@1.1.1(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-dialog': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-dialog': 1.1.16(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-id': 1.1.2(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) transitivePeerDependencies: @@ -38809,14 +40316,14 @@ snapshots: dependencies: is-what: 4.1.16 - copy-webpack-plugin@14.0.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + copy-webpack-plugin@14.0.0(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: glob-parent: 6.0.2 normalize-path: 3.0.0 schema-utils: 4.3.3 serialize-javascript: 7.0.5 tinyglobby: 0.2.17 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) core-js-compat@3.49.0: dependencies: @@ -38852,18 +40359,18 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-loader@7.1.4(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + css-loader@7.1.4(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: - icss-utils: 5.1.0(postcss@8.5.25) - postcss: 8.5.25 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.25) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.25) - postcss-modules-scope: 3.2.1(postcss@8.5.25) - postcss-modules-values: 4.0.0(postcss@8.5.25) + icss-utils: 5.1.0(postcss@8.5.26) + postcss: 8.5.26 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.26) + postcss-modules-local-by-default: 4.2.0(postcss@8.5.26) + postcss-modules-scope: 3.2.1(postcss@8.5.26) + postcss-modules-values: 4.0.0(postcss@8.5.26) postcss-value-parser: 4.2.0 semver: 7.8.5 optionalDependencies: - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) css-select@5.2.2: dependencies: @@ -38940,6 +40447,8 @@ snapshots: dayjs@1.11.21: {} + dayjs@1.11.23: {} + debug@2.6.9(supports-color@8.1.1): dependencies: ms: 2.0.0 @@ -39068,7 +40577,7 @@ snapshots: '@dnd-kit/dom': 0.1.21 '@dnd-kit/state': 0.1.21 '@vueuse/core': 13.9.0(vue@3.5.41(typescript@6.0.3)) - reka-ui: 2.10.3(vue@3.5.41(typescript@6.0.3)) + reka-ui: 2.10.4(vue@3.5.41(typescript@6.0.3)) vue: 3.5.41(typescript@6.0.3) transitivePeerDependencies: - '@vue/composition-api' @@ -39152,8 +40661,6 @@ snapshots: ejs@5.0.1: {} - electron-to-chromium@1.5.368: {} - electron-to-chromium@1.5.398: {} ember-cli-babel-plugin-helpers@1.1.1: {} @@ -39218,7 +40725,7 @@ snapshots: transitivePeerDependencies: - supports-color - ember-eslint-parser@0.14.4(@babel/eslint-parser@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)))(@typescript-eslint/parser@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(typescript@6.0.3): + ember-eslint-parser@0.14.4(@babel/eslint-parser@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)))(@typescript-eslint/parser@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(typescript@6.0.3): dependencies: '@glimmer/syntax': 0.95.0 '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@6.0.3) @@ -39229,8 +40736,8 @@ snapshots: mathml-tag-names: 4.0.0 svg-tags: 1.0.0 optionalDependencies: - '@babel/eslint-parser': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)) - '@typescript-eslint/parser': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@babel/eslint-parser': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)) + '@typescript-eslint/parser': 8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) transitivePeerDependencies: - typescript @@ -39241,6 +40748,21 @@ snapshots: content-tag: 4.2.0 oxc-parser: 0.130.0 + ember-estree@0.8.0: + dependencies: + '@glimmer/env': 0.1.7 + '@glimmer/syntax': 0.95.0 + content-tag: 4.2.0 + oxc-parser: 0.130.0 + + ember-modifier@4.3.0(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1): + dependencies: + '@embroider/addon-shim': 1.10.3(supports-color@8.1.1) + decorator-transforms: 2.4.0(@babel/core@7.29.7(supports-color@8.1.1)) + transitivePeerDependencies: + - '@babel/core' + - supports-color + ember-qunit@9.1.0(@ember/test-helpers@5.4.3(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1))(qunit@2.26.0)(supports-color@8.1.1): dependencies: '@ember/test-helpers': 5.4.3(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) @@ -39318,7 +40840,7 @@ snapshots: engine.io@6.6.9(supports-color@8.1.1): dependencies: '@types/cors': 2.8.19 - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/ws': 8.18.1 accepts: 1.3.8 base64id: 2.0.0 @@ -39487,7 +41009,7 @@ snapshots: is-symbol: 1.1.1 optional: true - esbuild-wasm@0.28.1: {} + esbuild-wasm@0.28.2: {} esbuild@0.28.1: optionalDependencies: @@ -39518,6 +41040,35 @@ snapshots: '@esbuild/win32-ia32': 0.28.1 '@esbuild/win32-x64': 0.28.1 + esbuild@0.28.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 + escalade@3.2.0: {} escape-html@1.0.3: {} @@ -39526,18 +41077,18 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-compat-utils@0.5.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)): + eslint-compat-utils@0.5.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0)): dependencies: - eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + eslint: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) semver: 7.8.5 - eslint-config-prettier@10.1.8(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)): + eslint-config-prettier@10.1.8(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)): dependencies: - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) eslint-import-context@0.1.9(unrs-resolver@1.12.2): dependencies: - get-tsconfig: 4.14.0 + get-tsconfig: 4.14.1 stable-hash-x: 0.2.0 optionalDependencies: unrs-resolver: 1.12.2 @@ -39560,17 +41111,17 @@ snapshots: - supports-color optional: true - eslint-plugin-ember@13.5.0(@babel/eslint-parser@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)))(@typescript-eslint/parser@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(typescript@6.0.3): + eslint-plugin-ember@13.5.0(@babel/eslint-parser@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)))(@typescript-eslint/parser@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(typescript@6.0.3): dependencies: '@ember-data/rfc395-data': 0.0.4 aria-query: 5.3.2 axobject-query: 4.1.0 css-tree: 3.2.1 editorconfig: 3.0.2 - ember-eslint-parser: 0.14.4(@babel/eslint-parser@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)))(@typescript-eslint/parser@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(typescript@6.0.3) + ember-eslint-parser: 0.14.4(@babel/eslint-parser@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)))(@typescript-eslint/parser@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(typescript@6.0.3) ember-rfc176-data: 0.3.18 - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) - eslint-utils: 3.0.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) + eslint-utils: 3.0.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)) estraverse: 5.3.0 html-tags: 3.3.1 language-tags: 1.0.9 @@ -39581,25 +41132,25 @@ snapshots: snake-case: 3.0.4 svg-tags: 1.0.0 optionalDependencies: - '@typescript-eslint/parser': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/parser': 8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) transitivePeerDependencies: - '@babel/eslint-parser' - typescript - eslint-plugin-es-x@7.8.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)): + eslint-plugin-es-x@7.8.0(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0)) '@eslint-community/regexpp': 4.12.2 - eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) - eslint-compat-utils: 0.5.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) + eslint: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) + eslint-compat-utils: 0.5.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0)) - eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@7.2.0))(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0): + eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@7.2.0))(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0): dependencies: '@package-json/types': 0.0.12 '@typescript-eslint/types': 8.60.1 comment-parser: 1.4.7 debug: 4.4.3(supports-color@7.2.0) - eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + eslint: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) eslint-import-context: 0.1.9(unrs-resolver@1.12.2) is-glob: 4.0.3 minimatch: 10.2.5 @@ -39607,17 +41158,17 @@ snapshots: stable-hash-x: 0.2.0 unrs-resolver: 1.12.2 optionalDependencies: - '@typescript-eslint/utils': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) eslint-import-resolver-node: 0.3.10(supports-color@7.2.0) transitivePeerDependencies: - supports-color - eslint-plugin-import-x@4.17.1(@typescript-eslint/utils@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@8.1.1))(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1): + eslint-plugin-import-x@4.17.1(@typescript-eslint/utils@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@8.1.1))(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1): dependencies: '@typescript-eslint/types': 8.62.0 comment-parser: 1.4.7 debug: 4.4.3(supports-color@8.1.1) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) eslint-import-context: 0.1.9(unrs-resolver@1.12.2) is-glob: 4.0.3 minimatch: 10.2.5 @@ -39625,18 +41176,18 @@ snapshots: stable-hash-x: 0.2.0 unrs-resolver: 1.12.2 optionalDependencies: - '@typescript-eslint/utils': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/utils': 8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) eslint-import-resolver-node: 0.3.10(supports-color@8.1.1) transitivePeerDependencies: - supports-color - eslint-plugin-n@17.24.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(typescript@6.0.3): + eslint-plugin-n@17.24.0(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(typescript@6.0.3): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0)) enhanced-resolve: 5.23.0 - eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) - eslint-plugin-es-x: 7.8.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) - get-tsconfig: 4.14.0 + eslint: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) + eslint-plugin-es-x: 7.8.0(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0)) + get-tsconfig: 4.14.1 globals: 15.15.0 globrex: 0.1.2 ignore: 5.3.2 @@ -39645,117 +41196,117 @@ snapshots: transitivePeerDependencies: - typescript - eslint-plugin-react-compiler@19.1.0-rc.2(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1): + eslint-plugin-react-compiler@19.1.0-rc.2(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1): dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/parser': 7.29.7 '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) hermes-parser: 0.25.1 zod: 3.25.76 zod-validation-error: 3.5.4(zod@3.25.76) transitivePeerDependencies: - supports-color - eslint-plugin-react-dom@5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3): + eslint-plugin-react-dom@5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3): dependencies: - '@eslint-react/ast': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/eslint': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/jsx': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/shared': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/utils': 8.65.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/ast': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/eslint': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/jsx': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/shared': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/utils': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) compare-versions: 6.1.1 - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) typescript: 6.0.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-hooks@7.1.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1): + eslint-plugin-react-hooks@7.1.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1): dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/parser': 7.29.7 - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) hermes-parser: 0.25.1 zod: 4.4.3 zod-validation-error: 4.0.2(zod@4.4.3) transitivePeerDependencies: - supports-color - eslint-plugin-react-jsx@5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3): + eslint-plugin-react-jsx@5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3): dependencies: - '@eslint-react/ast': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/core': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/eslint': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/jsx': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/shared': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/utils': 8.65.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + '@eslint-react/ast': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/core': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/eslint': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/jsx': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/shared': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/utils': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) typescript: 6.0.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-naming-convention@5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3): + eslint-plugin-react-naming-convention@5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3): dependencies: - '@eslint-react/ast': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/core': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/eslint': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/shared': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/var': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/utils': 8.65.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + '@eslint-react/ast': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/core': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/eslint': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/shared': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/var': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/utils': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) ts-pattern: 5.9.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-rsc@5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3): + eslint-plugin-react-rsc@5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3): dependencies: - '@eslint-react/ast': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/core': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/eslint': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/shared': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/var': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/utils': 8.65.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + '@eslint-react/ast': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/core': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/eslint': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/shared': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/var': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/utils': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) typescript: 6.0.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-web-api@5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3): + eslint-plugin-react-web-api@5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3): dependencies: - '@eslint-react/ast': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/core': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/eslint': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/shared': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/var': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/utils': 8.65.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/ast': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/core': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/eslint': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/shared': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/var': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/utils': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) birecord: 0.1.2 - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) ts-pattern: 5.9.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-x@5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3): - dependencies: - '@eslint-react/ast': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/core': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/eslint': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/jsx': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/shared': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@eslint-react/var': 5.18.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.65.0 - '@typescript-eslint/type-utils': 8.65.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/typescript-estree': 8.65.0(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/utils': 8.65.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint-plugin-react-x@5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3): + dependencies: + '@eslint-react/ast': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/core': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/eslint': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/jsx': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/shared': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@eslint-react/var': 5.18.6(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.67.0 + '@typescript-eslint/type-utils': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/typescript-estree': 8.67.0(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/utils': 8.67.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) compare-versions: 6.1.1 - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) string-ts: 2.3.1 ts-api-utils: 2.5.0(typescript@6.0.3) ts-pattern: 5.9.0 @@ -39763,10 +41314,10 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-solid@0.14.5(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3): + eslint-plugin-solid@0.14.5(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3): dependencies: - '@typescript-eslint/utils': 8.60.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + '@typescript-eslint/utils': 8.60.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) estraverse: 5.3.0 is-html: 2.0.0 kebab-case: 1.0.2 @@ -39776,37 +41327,37 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-svelte@3.22.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(svelte@5.56.8(@typescript-eslint/types@8.67.0)): + eslint-plugin-svelte@3.23.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(svelte@5.56.10(@typescript-eslint/types@8.68.0)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)) '@jridgewell/sourcemap-codec': 1.5.5 - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) esutils: 2.0.3 globals: 16.5.0 known-css-properties: 0.37.0 - postcss: 8.5.25 - postcss-load-config: 3.1.4(postcss@8.5.25) - postcss-safe-parser: 7.0.1(postcss@8.5.25) + postcss: 8.5.26 + postcss-load-config: 3.1.4(postcss@8.5.26) + postcss-safe-parser: 7.0.1(postcss@8.5.26) semver: 7.8.5 - svelte-eslint-parser: 1.8.0(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + svelte-eslint-parser: 1.8.0(svelte@5.56.10(@typescript-eslint/types@8.68.0)) optionalDependencies: - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) transitivePeerDependencies: - ts-node - eslint-plugin-vue@10.10.0(@stylistic/eslint-plugin@5.10.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)))(@typescript-eslint/parser@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(vue-eslint-parser@10.4.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)): + eslint-plugin-vue@10.10.0(@stylistic/eslint-plugin@5.10.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)))(@typescript-eslint/parser@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(vue-eslint-parser@10.4.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 7.1.4 semver: 7.8.5 - vue-eslint-parser: 10.4.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1) + vue-eslint-parser: 10.4.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1) xml-name-validator: 5.0.0 optionalDependencies: - '@stylistic/eslint-plugin': 5.10.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)) - '@typescript-eslint/parser': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@stylistic/eslint-plugin': 5.10.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)) + '@typescript-eslint/parser': 8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) eslint-scope@5.1.1: dependencies: @@ -39825,9 +41376,9 @@ snapshots: esrecurse: 4.3.0 estraverse: 5.3.0 - eslint-utils@3.0.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)): + eslint-utils@3.0.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)): dependencies: - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) eslint-visitor-keys: 2.1.0 eslint-visitor-keys@2.1.0: {} @@ -39838,9 +41389,9 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0): + eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.23.5(supports-color@7.2.0) '@eslint/config-helpers': 0.7.0 @@ -39875,9 +41426,9 @@ snapshots: transitivePeerDependencies: - supports-color - eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1): + eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.23.5(supports-color@8.1.1) '@eslint/config-helpers': 0.7.0 @@ -39932,11 +41483,11 @@ snapshots: dependencies: estraverse: 5.3.0 - esrap@2.3.0(@typescript-eslint/types@8.67.0): + esrap@2.3.0(@typescript-eslint/types@8.68.0): dependencies: '@jridgewell/sourcemap-codec': 1.5.5 optionalDependencies: - '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/types': 8.68.0 esrecurse@4.3.0: dependencies: @@ -39958,8 +41509,6 @@ snapshots: eventemitter3@4.0.7: {} - eventemitter3@5.0.4: {} - events-to-array@2.0.3: {} events@3.3.0: {} @@ -40380,10 +41929,6 @@ snapshots: get-intrinsic: 1.3.0 optional: true - get-tsconfig@4.14.0: - dependencies: - resolve-pkg-maps: 1.0.0 - get-tsconfig@4.14.1: dependencies: resolve-pkg-maps: 1.0.0 @@ -40692,9 +42237,9 @@ snapshots: dependencies: safer-buffer: 2.1.2 - icss-utils@5.1.0(postcss@8.5.25): + icss-utils@5.1.0(postcss@8.5.26): dependencies: - postcss: 8.5.25 + postcss: 8.5.26 ieee754@1.2.1: {} @@ -41147,7 +42692,7 @@ snapshots: kleur@4.1.5: {} - knip@6.32.2: + knip@6.32.3: dependencies: fdir: 6.5.0(picomatch@4.0.5) formatly: 0.3.0 @@ -41180,12 +42725,12 @@ snapshots: picocolors: 1.1.1 shell-quote: 1.8.4 - less-loader@13.0.0(less@4.6.7)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + less-loader@13.0.0(less@4.6.7)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: '@types/less': 3.0.8 less: 4.6.7 optionalDependencies: - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) less@4.6.7: dependencies: @@ -41205,11 +42750,11 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - license-webpack-plugin@4.0.2(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + license-webpack-plugin@4.0.2(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: - webpack-sources: 3.5.0 + webpack-sources: 3.5.1 optionalDependencies: - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) lightningcss-android-arm64@1.32.0: optional: true @@ -41321,12 +42866,10 @@ snapshots: dependencies: uc.micro: 2.1.0 - listr2@10.2.2: + listr2@11.0.0: dependencies: - cli-truncate: 5.2.0 - eventemitter3: 5.0.4 - log-update: 6.1.0 - rfdc: 1.4.1 + cli-truncate: 6.1.1 + log-update: 8.0.0 wrap-ansi: 10.0.0 lit-element@4.2.2: @@ -41400,13 +42943,14 @@ snapshots: is-unicode-supported: 2.1.0 yoctocolors: 2.1.2 - log-update@6.1.0: + log-update@8.0.0: dependencies: ansi-escapes: 7.3.0 cli-cursor: 5.0.0 - slice-ansi: 7.1.2 + slice-ansi: 9.0.0 + string-width: 8.2.1 strip-ansi: 7.2.0 - wrap-ansi: 9.0.2 + wrap-ansi: 10.0.0 loose-envify@1.4.0: dependencies: @@ -41424,7 +42968,7 @@ snapshots: dependencies: yallist: 3.1.1 - lucide-react@1.31.0(react@19.2.8): + lucide-react@1.34.0(react@19.2.8): dependencies: react: 19.2.8 @@ -41442,8 +42986,8 @@ snapshots: magicast@0.5.3: dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 source-map-js: 1.2.1 make-dir@4.0.0: @@ -41563,17 +43107,17 @@ snapshots: min-indent@1.0.1: {} - mini-css-extract-plugin@2.10.2(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + mini-css-extract-plugin@2.10.2(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: schema-utils: 4.3.3 tapable: 2.3.3 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) minimalistic-assert@1.0.1: {} minimatch@10.2.5: dependencies: - brace-expansion: 5.0.6 + brace-expansion: 5.0.8 minimatch@3.1.5: dependencies: @@ -41589,28 +43133,28 @@ snapshots: minimist@1.2.8: {} - minimizer-webpack-plugin@5.6.1(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + minimizer-webpack-plugin@5.6.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 terser: 5.49.0 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) optionalDependencies: - esbuild: 0.28.1 + esbuild: 0.28.2 lightningcss: 1.33.0 - postcss: 8.5.19 + postcss: 8.5.25 uglify-js: 3.19.3 - minimizer-webpack-plugin@5.6.1(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)): + minimizer-webpack-plugin@5.6.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 terser: 5.49.0 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3) optionalDependencies: - esbuild: 0.28.1 + esbuild: 0.28.2 lightningcss: 1.33.0 postcss: 8.5.26 uglify-js: 3.19.3 @@ -41664,8 +43208,6 @@ snapshots: mute-stream@3.0.0: {} - nanoid@3.3.16: {} - nanoid@3.3.18: {} nanoid@6.0.0: {} @@ -41701,14 +43243,14 @@ snapshots: dependencies: '@ampproject/remapping': 2.3.0 '@angular/compiler-cli': 22.1.1(@angular/compiler@22.1.1)(typescript@6.0.3) - '@rollup/plugin-json': 6.1.0(rollup@4.62.4) + '@rollup/plugin-json': 6.1.0(rollup@4.63.0) '@rollup/wasm-node': 4.61.1 ajv: 8.20.0 browserslist: 4.28.7 chokidar: 5.0.0 commander: 15.0.0 dependency-graph: 1.0.0 - esbuild: 0.28.1 + esbuild: 0.28.2 find-cache-directory: 6.0.0 injection-js: 2.6.1 jsonc-parser: 3.3.1 @@ -41716,14 +43258,14 @@ snapshots: ora: 9.4.1 piscina: 5.2.0 postcss: 8.5.26 - rollup-plugin-dts: 6.4.1(rollup@4.62.4)(typescript@6.0.3) + rollup-plugin-dts: 6.4.1(rollup@4.63.0)(typescript@6.0.3) rxjs: 7.8.2 sass: 1.101.0 tinyglobby: 0.2.17 tslib: 2.8.1 typescript: 6.0.3 optionalDependencies: - rollup: 4.62.4 + rollup: 4.63.0 tailwindcss: 4.3.3 no-case@3.0.4: @@ -41755,8 +43297,6 @@ snapshots: css-select: 5.2.2 he: 1.2.0 - node-releases@2.0.47: {} - node-releases@2.0.51: {} node-watch@0.7.3: {} @@ -41955,21 +43495,19 @@ snapshots: obuf@1.1.2: {} - obug@2.1.3: {} - obug@2.1.4: {} - octane@0.1.36(@typescript-eslint/types@8.67.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)): + octane@0.1.36(@typescript-eslint/types@8.68.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)): dependencies: - '@tsrx/core': 0.1.56(@typescript-eslint/types@8.67.0) + '@tsrx/core': 0.1.56(@typescript-eslint/types@8.68.0) '@types/react': 19.2.18 devalue: 5.8.2 es-module-lexer: 1.7.0 - esrap: 2.3.0(@typescript-eslint/types@8.67.0) + esrap: 2.3.0(@typescript-eslint/types@8.68.0) optionalDependencies: react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) transitivePeerDependencies: - '@typescript-eslint/types' @@ -42058,7 +43596,7 @@ snapshots: safe-push-apply: 1.0.0 optional: true - oxc-parser@0.121.0(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3): + oxc-parser@0.121.0(@emnapi/core@2.0.0-alpha.4)(@emnapi/runtime@2.0.0-alpha.4): dependencies: '@oxc-project/types': 0.121.0 optionalDependencies: @@ -42078,7 +43616,7 @@ snapshots: '@oxc-parser/binding-linux-x64-gnu': 0.121.0 '@oxc-parser/binding-linux-x64-musl': 0.121.0 '@oxc-parser/binding-openharmony-arm64': 0.121.0 - '@oxc-parser/binding-wasm32-wasi': 0.121.0(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3) + '@oxc-parser/binding-wasm32-wasi': 0.121.0(@emnapi/core@2.0.0-alpha.4)(@emnapi/runtime@2.0.0-alpha.4) '@oxc-parser/binding-win32-arm64-msvc': 0.121.0 '@oxc-parser/binding-win32-ia32-msvc': 0.121.0 '@oxc-parser/binding-win32-x64-msvc': 0.121.0 @@ -42350,21 +43888,21 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.5.26 - postcss-load-config@3.1.4(postcss@8.5.25): + postcss-load-config@3.1.4(postcss@8.5.26): dependencies: lilconfig: 2.1.0 yaml: 1.10.3 optionalDependencies: - postcss: 8.5.25 + postcss: 8.5.26 - postcss-loader@8.2.1(postcss@8.5.19)(typescript@6.0.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + postcss-loader@8.2.1(postcss@8.5.25)(typescript@6.0.3)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: cosmiconfig: 9.0.1(typescript@6.0.3) jiti: 2.7.0 - postcss: 8.5.19 + postcss: 8.5.25 semver: 7.8.5 optionalDependencies: - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) transitivePeerDependencies: - typescript @@ -42378,26 +43916,26 @@ snapshots: sugarss: 5.0.1(postcss@8.5.26) tinyglobby: 0.2.17 - postcss-modules-extract-imports@3.1.0(postcss@8.5.25): + postcss-modules-extract-imports@3.1.0(postcss@8.5.26): dependencies: - postcss: 8.5.25 + postcss: 8.5.26 - postcss-modules-local-by-default@4.2.0(postcss@8.5.25): + postcss-modules-local-by-default@4.2.0(postcss@8.5.26): dependencies: - icss-utils: 5.1.0(postcss@8.5.25) - postcss: 8.5.25 - postcss-selector-parser: 7.1.1 + icss-utils: 5.1.0(postcss@8.5.26) + postcss: 8.5.26 + postcss-selector-parser: 7.1.4 postcss-value-parser: 4.2.0 - postcss-modules-scope@3.2.1(postcss@8.5.25): + postcss-modules-scope@3.2.1(postcss@8.5.26): dependencies: - postcss: 8.5.25 - postcss-selector-parser: 7.1.1 + postcss: 8.5.26 + postcss-selector-parser: 7.1.4 - postcss-modules-values@4.0.0(postcss@8.5.25): + postcss-modules-values@4.0.0(postcss@8.5.26): dependencies: - icss-utils: 5.1.0(postcss@8.5.25) - postcss: 8.5.25 + icss-utils: 5.1.0(postcss@8.5.26) + postcss: 8.5.26 postcss-nested@7.0.2(postcss@8.5.26): dependencies: @@ -42410,13 +43948,13 @@ snapshots: postcss-mixins: 12.1.2(postcss@8.5.26) postcss-nested: 7.0.2(postcss@8.5.26) - postcss-safe-parser@7.0.1(postcss@8.5.25): + postcss-safe-parser@7.0.1(postcss@8.5.26): dependencies: - postcss: 8.5.25 + postcss: 8.5.26 - postcss-scss@4.0.9(postcss@8.5.25): + postcss-scss@4.0.9(postcss@8.5.26): dependencies: - postcss: 8.5.25 + postcss: 8.5.26 postcss-selector-parser@7.1.1: dependencies: @@ -42434,15 +43972,9 @@ snapshots: postcss-value-parser@4.2.0: {} - postcss@8.5.19: - dependencies: - nanoid: 3.3.16 - picocolors: 1.1.1 - source-map-js: 1.2.1 - postcss@8.5.25: dependencies: - nanoid: 3.3.16 + nanoid: 3.3.18 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -42464,7 +43996,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier-plugin-ember-template-tag@2.1.7(prettier@3.9.6)(supports-color@7.2.0): + prettier-plugin-ember-template-tag@2.1.8(prettier@3.9.6)(supports-color@7.2.0): dependencies: '@babel/traverse': 7.29.7(supports-color@7.2.0) content-tag: 4.2.0 @@ -42472,10 +44004,10 @@ snapshots: transitivePeerDependencies: - supports-color - prettier-plugin-svelte@4.1.1(prettier@3.9.6)(svelte@5.56.8(@typescript-eslint/types@8.67.0)): + prettier-plugin-svelte@4.1.1(prettier@3.9.6)(svelte@5.56.10(@typescript-eslint/types@8.68.0)): dependencies: prettier: 3.9.6 - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) prettier@2.8.8: {} @@ -42533,9 +44065,9 @@ snapshots: prr@1.0.1: optional: true - publint@0.3.23: + publint@0.3.24: dependencies: - '@publint/pack': 0.1.6 + '@publint/pack': 0.1.7 package-manager-detector: 1.8.0 picocolors: 1.1.1 sade: 1.8.1 @@ -42576,55 +44108,55 @@ snapshots: node-watch: 0.7.3 tiny-glob: 0.2.9 - radix-ui@1.6.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): + radix-ui@1.6.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-accessible-icon': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-accordion': 1.2.20(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-alert-dialog': 1.1.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-arrow': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-aspect-ratio': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-avatar': 1.2.6(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-checkbox': 1.3.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-collapsible': 1.1.20(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-accessible-icon': 1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-accordion': 1.2.20(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-alert-dialog': 1.1.23(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-arrow': 1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-aspect-ratio': 1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-avatar': 1.2.6(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-checkbox': 1.3.11(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-collapsible': 1.1.20(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-context-menu': 2.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-dialog': 1.1.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-context-menu': 2.3.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-dialog': 1.1.23(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-dropdown-menu': 2.1.24(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-dropdown-menu': 2.1.24(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-form': 0.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-hover-card': 1.1.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-label': 2.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-menu': 2.1.24(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-menubar': 1.1.24(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-navigation-menu': 1.2.22(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-one-time-password-field': 0.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-password-toggle-field': 0.1.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-popover': 1.1.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-progress': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-radio-group': 1.4.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-scroll-area': 1.2.18(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-select': 2.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-separator': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-slider': 1.4.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-form': 0.1.16(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-hover-card': 1.1.23(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-label': 2.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-menu': 2.1.24(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-menubar': 1.1.24(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-navigation-menu': 1.2.22(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-one-time-password-field': 0.1.16(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-password-toggle-field': 0.1.11(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-popover': 1.1.23(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-progress': 1.1.16(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-radio-group': 1.4.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-scroll-area': 1.2.18(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-select': 2.3.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-separator': 1.1.15(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slider': 1.4.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-switch': 1.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-tabs': 1.1.21(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-toast': 1.2.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-toggle': 1.1.18(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-toggle-group': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-toolbar': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-tooltip': 1.2.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-switch': 1.3.7(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-tabs': 1.1.21(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-toast': 1.2.23(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-toggle': 1.1.18(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-toggle-group': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-toolbar': 1.1.19(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-tooltip': 1.2.16(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.2.18)(react@19.2.8) @@ -42632,12 +44164,12 @@ snapshots: '@radix-ui/react-use-is-hydrated': 0.1.3(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-use-size': 1.1.4(@types/react@19.2.18)(react@19.2.8) - '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: '@types/react': 19.2.18 - '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@types/react-dom': 19.2.5(@types/react@19.2.18) range-parser@1.2.1: {} @@ -42943,9 +44475,9 @@ snapshots: dependencies: jsesc: 3.1.0 - reka-ui@2.10.3(vue@3.5.41(typescript@6.0.3)): + reka-ui@2.10.4(vue@3.5.41(typescript@6.0.3)): dependencies: - '@floating-ui/dom': 1.7.6 + '@floating-ui/dom': 1.8.0 '@floating-ui/vue': 1.1.11(vue@3.5.41(typescript@6.0.3)) '@internationalized/date': 3.12.3 '@internationalized/number': 3.6.7 @@ -43007,7 +44539,7 @@ snapshots: adjust-sourcemap-loader: 4.0.0 convert-source-map: 1.9.0 loader-utils: 2.0.4 - postcss: 8.5.25 + postcss: 8.5.26 source-map: 0.6.1 resolve.exports@2.0.3: {} @@ -43043,8 +44575,6 @@ snapshots: reusify@1.1.0: {} - rfdc@1.4.1: {} - rimraf@2.7.1: dependencies: glob: 7.2.3 @@ -43062,7 +44592,7 @@ snapshots: glob: 13.0.6 package-json-from-dist: 1.0.1 - rolldown-plugin-dts@0.27.14(@volar/typescript@2.4.28(typescript@6.0.3))(oxc-resolver@11.24.2)(rolldown@1.2.1)(typescript@6.0.3)(vue-tsc@3.3.9(typescript@6.0.3)): + rolldown-plugin-dts@0.27.14(@volar/typescript@2.4.28(typescript@6.0.3))(oxc-resolver@11.24.2)(rolldown@1.2.1)(typescript@6.0.3)(vue-tsc@3.3.11(typescript@6.0.3)): dependencies: dts-resolver: 3.0.0(oxc-resolver@11.24.2) get-tsconfig: 5.0.0-beta.5 @@ -43074,7 +44604,7 @@ snapshots: optionalDependencies: '@volar/typescript': 2.4.28(typescript@6.0.3) typescript: 6.0.3 - vue-tsc: 3.3.9(typescript@6.0.3) + vue-tsc: 3.3.11(typescript@6.0.3) transitivePeerDependencies: - oxc-resolver @@ -43141,52 +44671,73 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.2.1 '@rolldown/binding-win32-x64-msvc': 1.2.1 - rollup-plugin-copy-assets@2.0.3(rollup@4.62.4): + rolldown@1.2.6: + dependencies: + '@oxc-project/types': 0.147.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm-eabi': 1.2.6 + '@rolldown/binding-android-arm64': 1.2.6 + '@rolldown/binding-darwin-arm64': 1.2.6 + '@rolldown/binding-darwin-x64': 1.2.6 + '@rolldown/binding-freebsd-x64': 1.2.6 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.6 + '@rolldown/binding-linux-arm64-gnu': 1.2.6 + '@rolldown/binding-linux-arm64-musl': 1.2.6 + '@rolldown/binding-linux-ppc64-gnu': 1.2.6 + '@rolldown/binding-linux-s390x-gnu': 1.2.6 + '@rolldown/binding-linux-x64-gnu': 1.2.6 + '@rolldown/binding-linux-x64-musl': 1.2.6 + '@rolldown/binding-openharmony-arm64': 1.2.6 + '@rolldown/binding-win32-arm64-msvc': 1.2.6 + '@rolldown/binding-win32-x64-msvc': 1.2.6 + + rollup-plugin-copy-assets@2.0.3(rollup@4.63.0): dependencies: fs-extra: 7.0.1 - rollup: 4.62.4 + rollup: 4.63.0 - rollup-plugin-dts@6.4.1(rollup@4.62.4)(typescript@6.0.3): + rollup-plugin-dts@6.4.1(rollup@4.63.0)(typescript@6.0.3): dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.5.5 convert-source-map: 2.0.0 magic-string: 0.30.21 - rollup: 4.62.4 + rollup: 4.63.0 typescript: 6.0.3 optionalDependencies: '@babel/code-frame': 7.29.7 - rollup@4.62.4: + rollup@4.63.0: dependencies: '@types/estree': 1.0.9 optionalDependencies: '@napi-rs/lzma-linux-x64-gnu': 1.5.1 - '@rollup/rollup-android-arm-eabi': 4.62.4 - '@rollup/rollup-android-arm64': 4.62.4 - '@rollup/rollup-darwin-arm64': 4.62.4 - '@rollup/rollup-darwin-x64': 4.62.4 - '@rollup/rollup-freebsd-arm64': 4.62.4 - '@rollup/rollup-freebsd-x64': 4.62.4 - '@rollup/rollup-linux-arm-gnueabihf': 4.62.4 - '@rollup/rollup-linux-arm-musleabihf': 4.62.4 - '@rollup/rollup-linux-arm64-gnu': 4.62.4 - '@rollup/rollup-linux-arm64-musl': 4.62.4 - '@rollup/rollup-linux-loong64-gnu': 4.62.4 - '@rollup/rollup-linux-loong64-musl': 4.62.4 - '@rollup/rollup-linux-ppc64-gnu': 4.62.4 - '@rollup/rollup-linux-ppc64-musl': 4.62.4 - '@rollup/rollup-linux-riscv64-gnu': 4.62.4 - '@rollup/rollup-linux-riscv64-musl': 4.62.4 - '@rollup/rollup-linux-s390x-gnu': 4.62.4 - '@rollup/rollup-linux-x64-gnu': 4.62.4 - '@rollup/rollup-linux-x64-musl': 4.62.4 - '@rollup/rollup-openbsd-x64': 4.62.4 - '@rollup/rollup-openharmony-arm64': 4.62.4 - '@rollup/rollup-win32-arm64-msvc': 4.62.4 - '@rollup/rollup-win32-ia32-msvc': 4.62.4 - '@rollup/rollup-win32-x64-gnu': 4.62.4 - '@rollup/rollup-win32-x64-msvc': 4.62.4 + '@rollup/rollup-android-arm-eabi': 4.63.0 + '@rollup/rollup-android-arm64': 4.63.0 + '@rollup/rollup-darwin-arm64': 4.63.0 + '@rollup/rollup-darwin-x64': 4.63.0 + '@rollup/rollup-freebsd-arm64': 4.63.0 + '@rollup/rollup-freebsd-x64': 4.63.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.63.0 + '@rollup/rollup-linux-arm-musleabihf': 4.63.0 + '@rollup/rollup-linux-arm64-gnu': 4.63.0 + '@rollup/rollup-linux-arm64-musl': 4.63.0 + '@rollup/rollup-linux-loong64-gnu': 4.63.0 + '@rollup/rollup-linux-loong64-musl': 4.63.0 + '@rollup/rollup-linux-ppc64-gnu': 4.63.0 + '@rollup/rollup-linux-ppc64-musl': 4.63.0 + '@rollup/rollup-linux-riscv64-gnu': 4.63.0 + '@rollup/rollup-linux-riscv64-musl': 4.63.0 + '@rollup/rollup-linux-s390x-gnu': 4.63.0 + '@rollup/rollup-linux-x64-gnu': 4.63.0 + '@rollup/rollup-linux-x64-musl': 4.63.0 + '@rollup/rollup-openbsd-x64': 4.63.0 + '@rollup/rollup-openharmony-arm64': 4.63.0 + '@rollup/rollup-win32-arm64-msvc': 4.63.0 + '@rollup/rollup-win32-ia32-msvc': 4.63.0 + '@rollup/rollup-win32-x64-gnu': 4.63.0 + '@rollup/rollup-win32-x64-msvc': 4.63.0 fsevents: 2.3.3 rou3@0.8.1: {} @@ -43221,12 +44772,12 @@ snapshots: dependencies: queue-microtask: 1.2.3 - runed@0.35.1(svelte@5.56.8(@typescript-eslint/types@8.67.0)): + runed@0.35.1(svelte@5.56.10(@typescript-eslint/types@8.68.0)): dependencies: dequal: 2.0.3 esm-env: 1.2.2 lz-string: 1.5.0 - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) rxjs@7.8.2: dependencies: @@ -43263,10 +44814,10 @@ snapshots: safer-buffer@2.1.2: {} - sass-loader@17.0.0(sass@1.101.0)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + sass-loader@17.0.0(sass@1.101.0)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): optionalDependencies: sass: 1.101.0 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) sass@1.101.0: dependencies: @@ -43525,12 +45076,7 @@ snapshots: lilconfig: 3.1.3 nanospinner: 1.2.2 - slice-ansi@7.1.2: - dependencies: - ansi-styles: 6.2.3 - is-fullwidth-code-point: 5.1.0 - - slice-ansi@8.0.0: + slice-ansi@9.0.0: dependencies: ansi-styles: 6.2.3 is-fullwidth-code-point: 5.1.0 @@ -43586,31 +45132,37 @@ snapshots: seroval: 1.5.4 seroval-plugins: 1.5.4(seroval@1.5.4) - solid-refresh@0.6.3(solid-js@1.9.14)(supports-color@7.2.0): + solid-js@1.9.15: + dependencies: + csstype: 3.2.3 + seroval: 1.5.4 + seroval-plugins: 1.5.4(seroval@1.5.4) + + solid-refresh@0.6.3(solid-js@1.9.15)(supports-color@7.2.0): dependencies: '@babel/generator': 7.29.7 '@babel/helper-module-imports': 7.29.7(supports-color@7.2.0) '@babel/types': 7.29.8 - solid-js: 1.9.14 + solid-js: 1.9.15 transitivePeerDependencies: - supports-color - solid-refresh@0.6.3(solid-js@1.9.14)(supports-color@8.1.1): + solid-refresh@0.6.3(solid-js@1.9.15)(supports-color@8.1.1): dependencies: '@babel/generator': 7.29.7 '@babel/helper-module-imports': 7.29.7(supports-color@8.1.1) '@babel/types': 7.29.8 - solid-js: 1.9.14 + solid-js: 1.9.15 transitivePeerDependencies: - supports-color source-map-js@1.2.1: {} - source-map-loader@5.0.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + source-map-loader@5.0.0(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: iconv-lite: 0.6.3 source-map-js: 1.2.1 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) source-map-support@0.5.21: dependencies: @@ -43767,11 +45319,6 @@ snapshots: stylis@4.2.0: {} - sugarss@5.0.1(postcss@8.5.19): - dependencies: - postcss: 8.5.19 - optional: true - sugarss@5.0.1(postcss@8.5.25): dependencies: postcss: 8.5.25 @@ -43795,48 +45342,48 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-check@4.7.4(picomatch@4.0.5)(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3): + svelte-check@4.7.6(picomatch@4.0.5)(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3): dependencies: '@jridgewell/trace-mapping': 0.3.31 - '@sveltejs/load-config': 0.2.1 + '@sveltejs/load-config': 0.2.3 chokidar: 4.0.3 fdir: 6.5.0(picomatch@4.0.5) picocolors: 1.1.1 sade: 1.8.1 - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) typescript: 6.0.3 transitivePeerDependencies: - picomatch - svelte-eslint-parser@1.8.0(svelte@5.56.8(@typescript-eslint/types@8.67.0)): + svelte-eslint-parser@1.8.0(svelte@5.56.10(@typescript-eslint/types@8.68.0)): dependencies: eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0 - postcss: 8.5.25 - postcss-scss: 4.0.9(postcss@8.5.25) - postcss-selector-parser: 7.1.1 + postcss: 8.5.26 + postcss-scss: 4.0.9(postcss@8.5.26) + postcss-selector-parser: 7.1.4 semver: 7.8.5 optionalDependencies: - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) - svelte-toolbelt@0.10.6(svelte@5.56.8(@typescript-eslint/types@8.67.0)): + svelte-toolbelt@0.10.6(svelte@5.56.10(@typescript-eslint/types@8.68.0)): dependencies: clsx: 2.1.1 - runed: 0.35.1(svelte@5.56.8(@typescript-eslint/types@8.67.0)) + runed: 0.35.1(svelte@5.56.10(@typescript-eslint/types@8.68.0)) style-to-object: 1.0.14 - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) transitivePeerDependencies: - '@sveltejs/kit' - svelte2tsx@0.7.56(svelte@5.56.8(@typescript-eslint/types@8.67.0))(typescript@6.0.3): + svelte2tsx@0.7.56(svelte@5.56.10(@typescript-eslint/types@8.68.0))(typescript@6.0.3): dependencies: dedent-js: 1.0.1 scule: 1.3.0 - svelte: 5.56.8(@typescript-eslint/types@8.67.0) + svelte: 5.56.10(@typescript-eslint/types@8.68.0) typescript: 6.0.3 - svelte@5.56.8(@typescript-eslint/types@8.67.0): + svelte@5.56.10(@typescript-eslint/types@8.68.0): dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.5.5 @@ -43849,7 +45396,7 @@ snapshots: clsx: 2.1.1 devalue: 5.8.2 esm-env: 1.2.2 - esrap: 2.3.0(@typescript-eslint/types@8.67.0) + esrap: 2.3.0(@typescript-eslint/types@8.68.0) is-reference: 3.0.3 locate-character: 3.0.0 magic-string: 0.30.21 @@ -44101,7 +45648,7 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 - tsdown@0.22.14(@volar/typescript@2.4.28(typescript@6.0.3))(oxc-resolver@11.24.2)(publint@0.3.23)(typescript@6.0.3)(vue-tsc@3.3.9(typescript@6.0.3)): + tsdown@0.22.14(@volar/typescript@2.4.28(typescript@6.0.3))(oxc-resolver@11.24.2)(publint@0.3.24)(typescript@6.0.3)(vue-tsc@3.3.11(typescript@6.0.3)): dependencies: ansis: 4.3.1 cac: 7.0.0 @@ -44112,14 +45659,14 @@ snapshots: obug: 2.1.4 picomatch: 4.0.5 rolldown: 1.2.1 - rolldown-plugin-dts: 0.27.14(@volar/typescript@2.4.28(typescript@6.0.3))(oxc-resolver@11.24.2)(rolldown@1.2.1)(typescript@6.0.3)(vue-tsc@3.3.9(typescript@6.0.3)) + rolldown-plugin-dts: 0.27.14(@volar/typescript@2.4.28(typescript@6.0.3))(oxc-resolver@11.24.2)(rolldown@1.2.1)(typescript@6.0.3)(vue-tsc@3.3.11(typescript@6.0.3)) tinyexec: 1.2.4 tinyglobby: 0.2.17 tree-kill: 1.2.2 unconfig-core: 7.5.0 verkit: 0.3.1 optionalDependencies: - publint: 0.3.23 + publint: 0.3.24 typescript: 6.0.3 transitivePeerDependencies: - '@typescript/native-preview' @@ -44221,24 +45768,24 @@ snapshots: dependencies: semver: 7.8.5 - typescript-eslint@8.60.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3): + typescript-eslint@8.60.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.60.1(@typescript-eslint/parser@8.60.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/parser': 8.60.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/eslint-plugin': 8.60.1(@typescript-eslint/parser@8.60.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.60.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/typescript-estree': 8.60.1(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.60.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + '@typescript-eslint/utils': 8.60.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + eslint: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - typescript-eslint@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3): + typescript-eslint@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.67.0(@typescript-eslint/parser@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/parser': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/typescript-estree': 8.67.0(supports-color@8.1.1)(typescript@6.0.3) - '@typescript-eslint/utils': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + '@typescript-eslint/eslint-plugin': 8.68.0(@typescript-eslint/parser@8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3))(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/parser': 8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.68.0(supports-color@8.1.1)(typescript@6.0.3) + '@typescript-eslint/utils': 8.68.0(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1)(typescript@6.0.3) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -44336,12 +45883,6 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 '@unrs/resolver-binding-win32-x64-msvc': 1.12.2 - update-browserslist-db@1.2.3(browserslist@4.28.2): - dependencies: - browserslist: 4.28.2 - escalade: 3.2.0 - picocolors: 1.1.1 - update-browserslist-db@1.2.3(browserslist@4.28.7): dependencies: browserslist: 4.28.7 @@ -44387,37 +45928,37 @@ snapshots: verkit@0.3.1: {} - vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)): + vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@7.2.0)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)): dependencies: '@babel/core': 7.29.7(supports-color@7.2.0) '@types/babel__core': 7.20.5 - babel-preset-solid: 1.9.12(@babel/core@7.29.7(supports-color@7.2.0))(solid-js@1.9.14) + babel-preset-solid: 1.9.12(@babel/core@7.29.7(supports-color@7.2.0))(solid-js@1.9.15) merge-anything: 5.1.7 - solid-js: 1.9.14 - solid-refresh: 0.6.3(solid-js@1.9.14)(supports-color@7.2.0) - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) - vitefu: 1.1.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + solid-js: 1.9.15 + solid-refresh: 0.6.3(solid-js@1.9.15)(supports-color@7.2.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vitefu: 1.1.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) optionalDependencies: - '@testing-library/jest-dom': 7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10) + '@testing-library/jest-dom': 7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11) transitivePeerDependencies: - supports-color - vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10))(solid-js@1.9.14)(supports-color@8.1.1)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)): + vite-plugin-solid@2.11.14(@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11))(solid-js@1.9.15)(supports-color@8.1.1)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)): dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) '@types/babel__core': 7.20.5 - babel-preset-solid: 1.9.12(@babel/core@7.29.7(supports-color@8.1.1))(solid-js@1.9.14) + babel-preset-solid: 1.9.12(@babel/core@7.29.7(supports-color@8.1.1))(solid-js@1.9.15) merge-anything: 5.1.7 - solid-js: 1.9.14 - solid-refresh: 0.6.3(solid-js@1.9.14)(supports-color@8.1.1) - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) - vitefu: 1.1.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + solid-js: 1.9.15 + solid-refresh: 0.6.3(solid-js@1.9.15)(supports-color@8.1.1) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vitefu: 1.1.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) optionalDependencies: - '@testing-library/jest-dom': 7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.10) + '@testing-library/jest-dom': 7.0.1(@testing-library/dom@10.4.1)(vitest@4.1.11) transitivePeerDependencies: - supports-color - vite-prerender-plugin@0.5.13(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)): + vite-prerender-plugin@0.5.13(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)): dependencies: kolorist: 1.8.0 magic-string: 0.30.21 @@ -44425,36 +45966,18 @@ snapshots: simple-code-frame: 1.3.0 source-map: 0.7.6 stack-trace: 1.0.0 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) - - vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.19))(terser@5.49.0)(yaml@2.9.0): - dependencies: - lightningcss: 1.32.0 - picomatch: 4.0.5 - postcss: 8.5.25 - rolldown: 1.1.5 - tinyglobby: 0.2.17 - optionalDependencies: - '@types/node': 26.2.0 - esbuild: 0.28.1 - fsevents: 2.3.3 - jiti: 2.7.0 - less: 4.6.7 - sass: 1.101.0 - sugarss: 5.0.1(postcss@8.5.19) - terser: 5.49.0 - yaml: 2.9.0 + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) - vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0): + vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0): dependencies: - lightningcss: 1.32.0 + lightningcss: 1.33.0 picomatch: 4.0.5 - postcss: 8.5.25 + postcss: 8.5.26 rolldown: 1.1.5 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 26.2.0 - esbuild: 0.28.1 + esbuild: 0.28.2 fsevents: 2.3.3 jiti: 2.7.0 less: 4.6.7 @@ -44463,16 +45986,16 @@ snapshots: terser: 5.49.0 yaml: 2.9.0 - vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0): + vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0): dependencies: - lightningcss: 1.32.0 + lightningcss: 1.33.0 picomatch: 4.0.5 - postcss: 8.5.25 + postcss: 8.5.26 rolldown: 1.1.5 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 26.2.0 - esbuild: 0.28.1 + esbuild: 0.28.2 fsevents: 2.3.3 jiti: 2.7.0 less: 4.6.7 @@ -44481,35 +46004,16 @@ snapshots: terser: 5.49.0 yaml: 2.9.0 - vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.19))(terser@5.49.0)(yaml@2.9.0): + vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0): dependencies: lightningcss: 1.33.0 picomatch: 4.0.5 - postcss: 8.5.25 - rolldown: 1.2.1 - tinyglobby: 0.2.17 - optionalDependencies: - '@types/node': 26.2.0 - esbuild: 0.28.1 - fsevents: 2.3.3 - jiti: 2.7.0 - less: 4.6.7 - sass: 1.101.0 - sugarss: 5.0.1(postcss@8.5.19) - terser: 5.49.0 - yaml: 2.9.0 - optional: true - - vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0): - dependencies: - lightningcss: 1.33.0 - picomatch: 4.0.5 - postcss: 8.5.25 - rolldown: 1.2.1 + postcss: 8.5.26 + rolldown: 1.2.6 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 26.2.0 - esbuild: 0.28.1 + esbuild: 0.28.2 fsevents: 2.3.3 jiti: 2.7.0 less: 4.6.7 @@ -44517,17 +46021,18 @@ snapshots: sugarss: 5.0.1(postcss@8.5.25) terser: 5.49.0 yaml: 2.9.0 + optional: true - vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0): + vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0): dependencies: lightningcss: 1.33.0 picomatch: 4.0.5 - postcss: 8.5.25 - rolldown: 1.2.1 + postcss: 8.5.26 + rolldown: 1.2.6 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 26.2.0 - esbuild: 0.28.1 + esbuild: 0.28.2 fsevents: 2.3.3 jiti: 2.7.0 less: 4.6.7 @@ -44536,129 +46041,95 @@ snapshots: terser: 5.49.0 yaml: 2.9.0 - vitefu@1.1.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0)): - optionalDependencies: - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0) - - vitefu@1.1.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)): - optionalDependencies: - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) - - vitest@4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0)): - dependencies: - '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.10 - '@vitest/runner': 4.1.10 - '@vitest/snapshot': 4.1.10 - '@vitest/spy': 4.1.10 - '@vitest/utils': 4.1.10 - es-module-lexer: 2.1.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.3 - pathe: 2.0.3 - picomatch: 4.0.5 - std-env: 4.1.0 - tinybench: 2.9.0 - tinyexec: 1.2.4 - tinyglobby: 0.2.17 - tinyrainbow: 3.1.0 - vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0) - why-is-node-running: 2.3.0 + vitefu@1.1.3(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)): optionalDependencies: - '@types/node': 26.2.0 - '@vitest/coverage-v8': 4.1.10(vitest@4.1.10) - jsdom: 30.0.1(@noble/hashes@2.2.0) - transitivePeerDependencies: - - msw - optional: true + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) - vitest@4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.19))(terser@5.49.0)(yaml@2.9.0)): + vitest@4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.19))(terser@5.49.0)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.10 - '@vitest/runner': 4.1.10 - '@vitest/snapshot': 4.1.10 - '@vitest/spy': 4.1.10 - '@vitest/utils': 4.1.10 + '@vitest/expect': 4.1.11 + '@vitest/mocker': 4.1.11(vite@8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.11 + '@vitest/runner': 4.1.11 + '@vitest/snapshot': 4.1.11 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 - obug: 2.1.3 + obug: 2.1.4 pathe: 2.0.3 picomatch: 4.0.5 std-env: 4.1.0 tinybench: 2.9.0 - tinyexec: 1.2.4 + tinyexec: 1.3.0 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.19))(terser@5.49.0)(yaml@2.9.0) + vite: 8.1.5(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 26.2.0 - '@vitest/coverage-v8': 4.1.10(vitest@4.1.10) + '@vitest/coverage-v8': 4.1.11(vitest@4.1.11) jsdom: 30.0.1(@noble/hashes@2.2.0) transitivePeerDependencies: - msw optional: true - vitest@4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0)): + vitest@4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.10 - '@vitest/runner': 4.1.10 - '@vitest/snapshot': 4.1.10 - '@vitest/spy': 4.1.10 - '@vitest/utils': 4.1.10 + '@vitest/expect': 4.1.11 + '@vitest/mocker': 4.1.11(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.11 + '@vitest/runner': 4.1.11 + '@vitest/snapshot': 4.1.11 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 - obug: 2.1.3 + obug: 2.1.4 pathe: 2.0.3 picomatch: 4.0.5 std-env: 4.1.0 tinybench: 2.9.0 - tinyexec: 1.2.4 + tinyexec: 1.3.0 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.49.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 26.2.0 - '@vitest/coverage-v8': 4.1.10(vitest@4.1.10) + '@vitest/coverage-v8': 4.1.11(vitest@4.1.11) jsdom: 30.0.1(@noble/hashes@2.2.0) transitivePeerDependencies: - msw optional: true - vitest@4.1.10(@types/node@26.2.0)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)): + vitest@4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1(@noble/hashes@2.2.0))(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.10 - '@vitest/runner': 4.1.10 - '@vitest/snapshot': 4.1.10 - '@vitest/spy': 4.1.10 - '@vitest/utils': 4.1.10 + '@vitest/expect': 4.1.11 + '@vitest/mocker': 4.1.11(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.11 + '@vitest/runner': 4.1.11 + '@vitest/snapshot': 4.1.11 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 - obug: 2.1.3 + obug: 2.1.4 pathe: 2.0.3 picomatch: 4.0.5 std-env: 4.1.0 tinybench: 2.9.0 - tinyexec: 1.2.4 + tinyexec: 1.3.0 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.49.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 26.2.0 - '@vitest/coverage-v8': 4.1.10(vitest@4.1.10) + '@vitest/coverage-v8': 4.1.11(vitest@4.1.11) jsdom: 30.0.1(@noble/hashes@2.2.0) transitivePeerDependencies: - msw @@ -44744,10 +46215,10 @@ snapshots: dependencies: vue: 3.5.41(typescript@6.0.3) - vue-eslint-parser@10.4.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0): + vue-eslint-parser@10.4.1(eslint@10.9.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0): dependencies: debug: 4.4.3(supports-color@7.2.0) - eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + eslint: 10.9.1(jiti@2.7.0)(supports-color@7.2.0) eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 espree: 11.2.0 @@ -44756,10 +46227,10 @@ snapshots: transitivePeerDependencies: - supports-color - vue-eslint-parser@10.4.1(eslint@10.8.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1): + vue-eslint-parser@10.4.1(eslint@10.9.1(jiti@2.7.0)(supports-color@8.1.1))(supports-color@8.1.1): dependencies: debug: 4.4.3(supports-color@8.1.1) - eslint: 10.8.1(jiti@2.7.0)(supports-color@8.1.1) + eslint: 10.9.1(jiti@2.7.0)(supports-color@8.1.1) eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 espree: 11.2.0 @@ -44768,10 +46239,10 @@ snapshots: transitivePeerDependencies: - supports-color - vue-tsc@3.3.9(typescript@6.0.3): + vue-tsc@3.3.11(typescript@6.0.3): dependencies: '@volar/typescript': 2.4.28(typescript@6.0.3) - '@vue/language-core': 3.3.9 + '@vue/language-core': 3.3.11 typescript: 6.0.3 vue@3.5.41(typescript@6.0.3): @@ -44828,7 +46299,7 @@ snapshots: webidl-conversions@8.0.1: {} - webpack-dev-middleware@7.4.5(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + webpack-dev-middleware@7.4.5(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: colorette: 2.0.20 memfs: 4.57.6(tslib@2.8.1) @@ -44837,11 +46308,11 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.3.3 optionalDependencies: - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) transitivePeerDependencies: - tslib - webpack-dev-middleware@8.0.3(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + webpack-dev-middleware@8.0.3(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: memfs: 4.57.6(tslib@2.8.1) mime-types: 3.0.2 @@ -44849,11 +46320,11 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.3.3 optionalDependencies: - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) transitivePeerDependencies: - tslib - webpack-dev-server@5.2.6(debug@4.4.3(supports-color@7.2.0))(supports-color@8.1.1)(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + webpack-dev-server@5.2.6(debug@4.4.3(supports-color@7.2.0))(supports-color@8.1.1)(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -44881,10 +46352,10 @@ snapshots: serve-index: 1.9.2(supports-color@8.1.1) sockjs: 0.3.24 spdy: 4.0.2(supports-color@8.1.1) - webpack-dev-middleware: 7.4.5(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + webpack-dev-middleware: 7.4.5(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) ws: 8.21.0 optionalDependencies: - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) transitivePeerDependencies: - bufferutil - debug @@ -44898,18 +46369,16 @@ snapshots: flat: 5.0.2 wildcard: 2.0.1 - webpack-sources@3.5.0: {} - webpack-sources@3.5.1: {} - webpack-subresource-integrity@5.1.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + webpack-subresource-integrity@5.1.0(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: typed-assert: 1.0.9 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) webpack-virtual-modules@0.6.2: {} - webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3): + webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3): dependencies: '@types/estree': 1.0.9 '@types/json-schema': 7.0.15 @@ -44925,7 +46394,7 @@ snapshots: events: 3.3.0 graceful-fs: 4.2.11 mime-db: 1.54.0 - minimizer-webpack-plugin: 5.6.1(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + minimizer-webpack-plugin: 5.6.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.3 @@ -44945,7 +46414,7 @@ snapshots: - postcss - uglify-js - webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3): + webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3): dependencies: '@types/estree': 1.0.9 '@types/json-schema': 7.0.15 @@ -44961,7 +46430,7 @@ snapshots: events: 3.3.0 graceful-fs: 4.2.11 mime-db: 1.54.0 - minimizer-webpack-plugin: 5.6.1(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) + minimizer-webpack-plugin: 5.6.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)(webpack@5.109.2(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.3 @@ -45169,6 +46638,15 @@ snapshots: y18n: 5.0.8 yargs-parser: 22.0.0 + yargs@18.1.0: + dependencies: + cliui: 9.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + string-width: 8.2.1 + y18n: 5.0.8 + yargs-parser: 22.0.0 + yocto-queue@0.1.0: {} yoctocolors@2.1.2: {} diff --git a/tests/e2e/helpers/setRangeValue.ts b/tests/e2e/helpers/setRangeValue.ts new file mode 100644 index 0000000000..f5b270d3c6 --- /dev/null +++ b/tests/e2e/helpers/setRangeValue.ts @@ -0,0 +1,59 @@ +import { expect, type Locator, type Page } from '@playwright/test' + +export async function setRangeValue(locator: Locator, value: string) { + await locator.evaluate((element, nextValue) => { + const input = element as HTMLInputElement + const descriptor = Object.getOwnPropertyDescriptor( + window.HTMLInputElement.prototype, + 'value', + ) + descriptor?.set?.call(input, nextValue) + input.dispatchEvent(new Event('input', { bubbles: true })) + input.dispatchEvent(new Event('change', { bubbles: true })) + }, value) +} + +export async function scrollTradingTable(page: Page, top: number) { + await page.locator('[data-trading-table]').evaluate((element, nextTop) => { + const scroller = element as HTMLElement + scroller.scrollTop = nextTop + scroller.dispatchEvent(new Event('scroll')) + }, top) +} + +export async function pauseTradingFeed(page: Page) { + const toggle = page.getByTestId('feed-toggle') + await expect(toggle).toBeVisible() + if ((await toggle.textContent())?.includes('PAUSE')) { + await toggle.click() + } + await expect(page.getByTestId('feed-status')).toHaveText('FEED PAUSED') +} + +export async function resumeTradingFeed(page: Page) { + const toggle = page.getByTestId('feed-toggle') + await expect(toggle).toBeVisible() + if ((await toggle.textContent())?.includes('START')) { + await toggle.click() + } + await expect(page.getByTestId('feed-status')).toHaveText('FEED LIVE') +} + +export function pausedFeedUrl(url: string) { + const next = new URL(url) + next.searchParams.set('paused', '1') + return next.href +} + +export async function selectOptionValue(locator: Locator, value: string) { + await locator.evaluate((element, nextValue) => { + const select = element as HTMLSelectElement + const descriptor = Object.getOwnPropertyDescriptor( + window.HTMLSelectElement.prototype, + 'value', + ) + descriptor?.set?.call(select, nextValue) + select.dispatchEvent(new Event('input', { bubbles: true })) + select.dispatchEvent(new Event('change', { bubbles: true })) + }, value) +} diff --git a/tests/e2e/helpers/startExampleServer.ts b/tests/e2e/helpers/startExampleServer.ts index 74383ef4b7..556fe44f4a 100644 --- a/tests/e2e/helpers/startExampleServer.ts +++ b/tests/e2e/helpers/startExampleServer.ts @@ -43,10 +43,13 @@ export async function startExampleServer(exampleDir: string) { throw new Error(`Failed to find a Vite app for ${exampleDir}`) } + const playwrightViteMode = (process.env as Record) + .PLAYWRIGHT_VITE_MODE const server = await createServer({ root: exampleDir, configFile: configFile ?? false, logLevel: 'error', + ...(playwrightViteMode ? { mode: playwrightViteMode } : {}), server: { host: '127.0.0.1', port: 0, @@ -69,9 +72,27 @@ export async function startExampleServer(exampleDir: string) { } async function startSpawnedViteServer(exampleDir: string) { + const maxAttempts = 5 + + for (let attempt = 0; attempt < maxAttempts; attempt++) { + try { + return await listenOnSpawnedVitePort(exampleDir) + } catch (error) { + const message = error instanceof Error ? error.message : String(error) + if (!message.includes('already in use') || attempt === maxAttempts - 1) { + throw error + } + } + } + + throw new Error(`Failed to start Vite server for ${exampleDir}`) +} + +async function listenOnSpawnedVitePort(exampleDir: string) { // Random high port: `vite dev` has no port-0 support, and parallel test - // workers must not collide. - const port = 4100 + Math.floor(Math.random() * 2000) + // workers must not collide. Avoid the 4100-6099 range so we do not land on + // macOS services such as port 6000. + const port = 18000 + Math.floor(Math.random() * 2000) const child = spawn( 'pnpm', [ @@ -105,7 +126,7 @@ async function startSpawnedViteServer(exampleDir: string) { `Timed out starting Vite server for ${exampleDir}\n${output}`, ), ) - }, 60_000) + }, 90_000) const handleOutput = (chunk: Buffer) => { output += chunk.toString() @@ -185,7 +206,7 @@ async function startAngularExampleServer(exampleDir: string) { `Timed out starting Angular server for ${exampleDir}\n${output}`, ), ) - }, 60_000) + }, 90_000) const handleOutput = (chunk: Buffer) => { output += chunk.toString()