diff --git a/.changeset/metal-aliens-juggle.md b/.changeset/metal-aliens-juggle.md
new file mode 100644
index 00000000..5ea3dc72
--- /dev/null
+++ b/.changeset/metal-aliens-juggle.md
@@ -0,0 +1,15 @@
+---
+'@tanstack/devtools-event-client': minor
+'@tanstack/react-devtools': minor
+'@tanstack/solid-devtools': minor
+'@tanstack/devtools-event-bus': minor
+'@tanstack/devtools': minor
+---
+
+Added event bus functionality into @tanstack/devtools
+
+- @tanstack/devtools now comes with an integrated Event Bus on the Client.
+- The Event Bus allows for seamless communication between different parts of your running application
+ without tight coupling.
+- Exposed APIs for publishing and subscribing to events.
+- Added config for the client event bus
diff --git a/examples/react/basic/package.json b/examples/react/basic/package.json
index e511d082..509d7ff1 100644
--- a/examples/react/basic/package.json
+++ b/examples/react/basic/package.json
@@ -9,13 +9,15 @@
"test:types": "tsc"
},
"dependencies": {
+ "@tanstack/devtools-event-client": "workspace:^",
"@tanstack/react-devtools": "^0.1.1",
"@tanstack/react-query": "^5.83.0",
"@tanstack/react-query-devtools": "^5.83.0",
"@tanstack/react-router": "^1.130.2",
"@tanstack/react-router-devtools": "^1.130.2",
"react": "^19.1.0",
- "react-dom": "^19.1.0"
+ "react-dom": "^19.1.0",
+ "zod": "^4.0.14"
},
"devDependencies": {
"@types/react": "^19.1.2",
diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx
index 14987e3f..a08f1873 100644
--- a/examples/react/basic/src/index.tsx
+++ b/examples/react/basic/src/index.tsx
@@ -1,6 +1,17 @@
import ReactDOM from 'react-dom/client'
import Devtools from './setup'
+import { queryPlugin } from './plugin'
+setTimeout(() => {
+ queryPlugin.emit('test', {
+ title: 'Test Event',
+ description:
+ 'This is a test event from the TanStack Query Devtools plugin.',
+ })
+}, 1000)
+queryPlugin.on('test', (event) => {
+ console.log('Received test event:', event)
+})
function App() {
return (
diff --git a/examples/react/basic/src/plugin.ts b/examples/react/basic/src/plugin.ts
new file mode 100644
index 00000000..8bac08e3
--- /dev/null
+++ b/examples/react/basic/src/plugin.ts
@@ -0,0 +1,25 @@
+import { EventClient } from '@tanstack/devtools-event-client'
+
+interface EventMap {
+ 'query-devtools:test': {
+ title: string
+ description: string
+ }
+ 'query-devtools:init': {
+ title: string
+ description: string
+ }
+ 'query-devtools:query': {
+ title: string
+ description: string
+ }
+}
+class QueryDevtoolsPlugin extends EventClient
{
+ constructor() {
+ super({
+ pluginId: 'query-devtools',
+ })
+ }
+}
+
+export const queryPlugin = new QueryDevtoolsPlugin()
diff --git a/examples/react/start/package.json b/examples/react/start/package.json
index 65931747..59a6ff5f 100644
--- a/examples/react/start/package.json
+++ b/examples/react/start/package.json
@@ -17,21 +17,25 @@
"@prisma/extension-accelerate": "^2.0.2",
"@prisma/studio-core": "^0.5.1",
"@tailwindcss/vite": "^4.0.6",
+ "@tanstack/devtools-event-bus": "workspace:^",
+ "@tanstack/devtools-event-client": "workspace:^",
"@tanstack/react-devtools": "^0.1.1",
"@tanstack/react-query": "^5.83.0",
"@tanstack/react-query-devtools": "^5.83.0",
"@tanstack/react-router": "^1.130.2",
"@tanstack/react-router-devtools": "^1.130.2",
"@tanstack/react-router-with-query": "^1.130.2",
- "@tanstack/react-start": "^1.130.2",
+ "@tanstack/react-start": "^1.130.15",
"@tanstack/router-plugin": "^1.121.2",
"prisma": "^6.13.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"tailwindcss": "^4.0.6",
- "vite-tsconfig-paths": "^5.1.4"
+ "vite-tsconfig-paths": "^5.1.4",
+ "zod": "^4.0.14"
},
"devDependencies": {
+ "@tanstack/devtools": "workspace:^",
"@testing-library/dom": "^10.4.0",
"@testing-library/react": "^16.2.0",
"@types/react": "^19.1.2",
diff --git a/examples/react/start/src/components/client-plugin.tsx b/examples/react/start/src/components/client-plugin.tsx
new file mode 100644
index 00000000..34532482
--- /dev/null
+++ b/examples/react/start/src/components/client-plugin.tsx
@@ -0,0 +1,41 @@
+import { queryPlugin } from '@/plugin'
+import { useEffect, useState } from 'react'
+
+export default function ClientPlugin() {
+ const [events, setEvents] = useState<
+ Array<{ type: string; payload: { title: string; description: string } }>
+ >([])
+ useEffect(() => {
+ const cleanup = queryPlugin.on('test', (event) => {
+ console.log('Received message in here:', event)
+ setEvents((prev) => [...prev, event as any])
+ })
+
+ return cleanup
+ }, [])
+ return (
+
+
Client Plugin Initialized
+
Devtools Client is connected.
+
{
+ console.log('Button clicked, emitting event')
+ queryPlugin.emit('test', {
+ title: 'Button Clicked',
+ description:
+ 'This is a custom event triggered by the client plugin.',
+ })
+ }}
+ >
+ Click me
+
+ {events.map((event, i) => (
+
+
{event.payload.title}
+
{event.payload.description}
+
+ ))}
+
+ )
+}
diff --git a/examples/react/start/src/components/devtools.tsx b/examples/react/start/src/components/devtools.tsx
index 5833a28b..0c3e11b3 100644
--- a/examples/react/start/src/components/devtools.tsx
+++ b/examples/react/start/src/components/devtools.tsx
@@ -3,6 +3,7 @@ import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools'
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
import { TanstackDevtools } from '@tanstack/react-devtools'
import { StudioPlugin } from './prisma-plugin'
+import ClientPlugin from './client-plugin'
const queryClient = new QueryClient()
@@ -11,6 +12,9 @@ export default function DevtoolsExample() {
<>
,
},
+ {
+ name: 'Client Plugin',
+ render: ,
+ },
]}
/>
diff --git a/examples/react/start/src/plugin.ts b/examples/react/start/src/plugin.ts
new file mode 100644
index 00000000..18b3f2fc
--- /dev/null
+++ b/examples/react/start/src/plugin.ts
@@ -0,0 +1,26 @@
+import { EventClient } from '@tanstack/devtools-event-client'
+
+interface EventMap {
+ 'query-devtools:test': {
+ title: string
+ description: string
+ }
+ 'query-devtools:init': {
+ title: string
+ description: string
+ }
+ 'query-devtools:query': {
+ title: string
+ description: string
+ }
+}
+
+class QueryDevtoolsClient extends EventClient {
+ constructor() {
+ super({
+ pluginId: 'query-devtools',
+ })
+ }
+}
+
+export const queryPlugin = new QueryDevtoolsClient()
diff --git a/examples/react/start/src/server-setup.ts b/examples/react/start/src/server-setup.ts
new file mode 100644
index 00000000..d6937f91
--- /dev/null
+++ b/examples/react/start/src/server-setup.ts
@@ -0,0 +1,7 @@
+import { ServerEventBus } from '@tanstack/devtools-event-bus/server'
+
+const devtoolsServer = new ServerEventBus()
+
+devtoolsServer.start()
+
+export { devtoolsServer }
diff --git a/examples/react/start/vite.config.ts b/examples/react/start/vite.config.ts
index f2b854b4..8a70c308 100644
--- a/examples/react/start/vite.config.ts
+++ b/examples/react/start/vite.config.ts
@@ -3,6 +3,7 @@ import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import viteReact from '@vitejs/plugin-react'
import viteTsConfigPaths from 'vite-tsconfig-paths'
import tailwindcss from '@tailwindcss/vite'
+//import { devtoolsServer } from './src/server-setup'
const config = defineConfig({
plugins: [
@@ -10,6 +11,7 @@ const config = defineConfig({
viteTsConfigPaths({
projects: ['./tsconfig.json'],
}),
+
tailwindcss(),
tanstackStart({
customViteReactPlugin: true,
diff --git a/package.json b/package.json
index 448084f2..77bd0de2 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"changeset:version": "changeset version && pnpm install --no-frozen-lockfile && pnpm prettier:write",
"clean": "find . -name 'dist' -type d -prune -exec rm -rf {} +",
"clean:node_modules": "find . -name 'node_modules' -type d -prune -exec rm -rf {} +",
+ "clean:all": "pnpm run clean && pnpm run clean:node_modules",
"dev": "pnpm run watch",
"docs:generate": "node scripts/generateDocs.js",
"format": "pnpm run prettier:write",
diff --git a/packages/devtools/README.md b/packages/devtools/README.md
index 42286506..4de2d3cd 100644
--- a/packages/devtools/README.md
+++ b/packages/devtools/README.md
@@ -27,8 +27,8 @@ In order to create a plugin for TanStack Devtools, you can use the `plugins` arg
import { TanStackDevtoolsCore } from '@tanstack/devtools'
const devtools = new TanStackDevtoolsCore({
- options: {
- // your options here
+ config: {
+ // your config here
},
plugins: [
{
diff --git a/packages/devtools/package.json b/packages/devtools/package.json
index 25d2ee0c..20a24b42 100644
--- a/packages/devtools/package.json
+++ b/packages/devtools/package.json
@@ -54,6 +54,7 @@
},
"dependencies": {
"@solid-primitives/keyboard": "^1.2.8",
+ "@tanstack/devtools-event-bus": "workspace:*",
"clsx": "^2.1.1",
"goober": "^2.1.16",
"solid-js": "^1.9.7"
diff --git a/packages/devtools/src/core.tsx b/packages/devtools/src/core.tsx
index 4f40d921..b372db34 100644
--- a/packages/devtools/src/core.tsx
+++ b/packages/devtools/src/core.tsx
@@ -1,7 +1,9 @@
import { lazy } from 'solid-js'
import { Portal, render } from 'solid-js/web'
+import { ClientEventBus } from '@tanstack/devtools-event-bus/client'
import { DevtoolsProvider } from './context/devtools-context'
import { initialState } from './context/devtools-store'
+import type { ClientEventBusConfig } from '@tanstack/devtools-event-bus/client'
import type {
TanStackDevtoolsConfig,
TanStackDevtoolsPlugin,
@@ -34,6 +36,7 @@ export interface TanStackDevtoolsInit {
* ```
*/
plugins?: Array
+ eventBusConfig?: ClientEventBusConfig
}
export class TanStackDevtoolsCore {
@@ -44,9 +47,12 @@ export class TanStackDevtoolsCore {
#isMounted = false
#dispose?: () => void
#Component: any
+ #eventBus: ClientEventBus | undefined
+ #eventBusConfig: ClientEventBusConfig | undefined
constructor(init: TanStackDevtoolsInit) {
this.#plugins = init.plugins || []
+ this.#eventBusConfig = init.eventBusConfig
this.#config = {
...this.#config,
...init.config,
@@ -60,9 +66,9 @@ export class TanStackDevtoolsCore {
const mountTo = el
const dispose = render(() => {
this.#Component = lazy(() => import('./devtools'))
-
const Devtools = this.#Component
-
+ this.#eventBus = new ClientEventBus(this.#eventBusConfig)
+ this.#eventBus.start()
return (
@@ -80,6 +86,7 @@ export class TanStackDevtoolsCore {
if (!this.#isMounted) {
throw new Error('Devtools is not mounted')
}
+ this.#eventBus?.stop()
this.#dispose?.()
this.#isMounted = false
}
@@ -91,3 +98,5 @@ export class TanStackDevtoolsCore {
}
}
}
+
+export type { ClientEventBusConfig }
diff --git a/packages/devtools/src/index.ts b/packages/devtools/src/index.ts
index 8b8497ef..058273ba 100644
--- a/packages/devtools/src/index.ts
+++ b/packages/devtools/src/index.ts
@@ -1,6 +1,6 @@
export { PLUGIN_CONTAINER_ID, PLUGIN_TITLE_CONTAINER_ID } from './constants'
export { TanStackDevtoolsCore } from './core'
-export type { TanStackDevtoolsInit } from './core'
+export type { TanStackDevtoolsInit, ClientEventBusConfig } from './core'
export type {
TanStackDevtoolsPlugin,
TanStackDevtoolsConfig,
diff --git a/packages/devtools/tsconfig.json b/packages/devtools/tsconfig.json
index 1c53831b..50837fb4 100644
--- a/packages/devtools/tsconfig.json
+++ b/packages/devtools/tsconfig.json
@@ -1,6 +1,12 @@
{
"extends": "../../tsconfig.json",
- "include": ["src", "eslint.config.js", "vite.config.ts", "tests"],
+ "include": [
+ "src",
+ "eslint.config.js",
+ "vite.config.ts",
+ "tests",
+ "src/server"
+ ],
"compilerOptions": {
"jsxImportSource": "solid-js",
"jsx": "preserve"
diff --git a/packages/event-bus-client/README.md b/packages/event-bus-client/README.md
new file mode 100644
index 00000000..614a17d7
--- /dev/null
+++ b/packages/event-bus-client/README.md
@@ -0,0 +1,39 @@
+# @tanstack/devtools
+
+This package is still under active development and might have breaking changes in the future. Please use it with caution.
+
+## General Usage
+
+```tsx
+import { EventClient } from '@tanstack/devtools-event-client'
+
+interface EventMap {
+ 'query-devtools:a': { foo: string }
+ 'query-devtools:b': { foo: number }
+}
+
+class QueryDevtoolsPlugin extends EventClient {
+ constructor() {
+ super({
+ pluginId: 'query-devtools',
+ })
+ }
+}
+
+export const queryPlugin = new QueryDevtoolsPlugin()
+
+// I'm fully typed here
+plugin.emit('a', {
+ foo: 'bar',
+})
+plugin.on('b', (e) => {
+ // I'm fully typed here
+ e.payload.foo
+})
+```
+
+## Understanding the implementation
+
+The `EventClient` class is a base class for creating plugins that can subscribe to events in the Tanstack Devtools event bus. It allows you to define a set of events and their corresponding data schemas using a standard-schema based schemas.
+
+It will work on both the client/server side and all you have to worry about is emitting/listening to events.
diff --git a/packages/event-bus-client/eslint.config.js b/packages/event-bus-client/eslint.config.js
new file mode 100644
index 00000000..e472c69e
--- /dev/null
+++ b/packages/event-bus-client/eslint.config.js
@@ -0,0 +1,10 @@
+// @ts-check
+
+import rootConfig from '../../eslint.config.js'
+
+export default [
+ ...rootConfig,
+ {
+ rules: {},
+ },
+]
diff --git a/packages/event-bus-client/package.json b/packages/event-bus-client/package.json
new file mode 100644
index 00000000..49021398
--- /dev/null
+++ b/packages/event-bus-client/package.json
@@ -0,0 +1,58 @@
+{
+ "name": "@tanstack/devtools-event-client",
+ "version": "0.1.1",
+ "description": "TanStack Event Client is a lightweight event client for TanStack Devtools event bus.",
+ "author": "Tanner Linsley",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/TanStack/devtools.git",
+ "directory": "packages/devtools"
+ },
+ "homepage": "https://tanstack.com/devtools",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ },
+ "keywords": [
+ "devtools"
+ ],
+ "type": "module",
+ "types": "dist/esm/index.d.ts",
+ "main": "dist/cjs/index.cjs",
+ "module": "dist/esm/index.js",
+ "exports": {
+ ".": {
+ "import": {
+ "types": "./dist/esm/index.d.ts",
+ "default": "./dist/esm/index.js"
+ },
+ "require": {
+ "types": "./dist/cjs/index.d.cts",
+ "default": "./dist/cjs/index.cjs"
+ }
+ },
+ "./package.json": "./package.json"
+ },
+ "sideEffects": false,
+ "engines": {
+ "node": ">=18"
+ },
+ "files": [
+ "dist/",
+ "src"
+ ],
+ "scripts": {
+ "clean": "premove ./build ./dist",
+ "lint:fix": "eslint ./src --fix",
+ "test:eslint": "eslint ./src",
+ "test:lib": "vitest",
+ "test:lib:dev": "pnpm test:lib --watch",
+ "test:types": "tsc",
+ "test:build": "publint --strict",
+ "build": "vite build"
+ },
+ "devDependencies": {
+ "@tanstack/devtools-event-bus": "workspace:*"
+ }
+}
diff --git a/packages/event-bus-client/src/index.ts b/packages/event-bus-client/src/index.ts
new file mode 100644
index 00000000..6b3402a0
--- /dev/null
+++ b/packages/event-bus-client/src/index.ts
@@ -0,0 +1 @@
+export { EventClient } from './plugin'
diff --git a/packages/event-bus-client/src/plugin.ts b/packages/event-bus-client/src/plugin.ts
new file mode 100644
index 00000000..192cb0dd
--- /dev/null
+++ b/packages/event-bus-client/src/plugin.ts
@@ -0,0 +1,150 @@
+interface TanStackDevtoolsEvent {
+ type: TEventName
+ payload: TPayload
+ pluginId?: string // Optional pluginId to filter events by plugin
+}
+declare global {
+ // eslint-disable-next-line no-var
+ var __TANSTACK_EVENT_TARGET__: EventTarget | null
+}
+
+type AllDevtoolsEvents> = {
+ [Key in keyof TEventMap]: TanStackDevtoolsEvent
+}[keyof TEventMap]
+
+export class EventClient<
+ TEventMap extends Record,
+ TPluginId extends string = TEventMap extends Record
+ ? P extends `${infer Id}:${string}`
+ ? Id
+ : never
+ : never,
+> {
+ #pluginId: TPluginId
+ #eventTarget: () => EventTarget
+ #debug: boolean
+
+ constructor({
+ pluginId,
+ debug = false,
+ }: {
+ pluginId: TPluginId
+ debug?: boolean
+ }) {
+ this.#pluginId = pluginId
+ this.#eventTarget = this.getGlobalTarget
+ this.#debug = debug
+ this.debugLog(' Initializing event subscription for plugin', this.#pluginId)
+ }
+
+ private debugLog(...args: Array) {
+ if (this.#debug) {
+ console.log(`🌴 [tanstack-devtools:${this.#pluginId}-plugin]`, ...args)
+ }
+ }
+ private getGlobalTarget() {
+ // server one is the global event target
+ if (
+ typeof globalThis !== 'undefined' &&
+ globalThis.__TANSTACK_EVENT_TARGET__
+ ) {
+ this.debugLog('Using global event target')
+ return globalThis.__TANSTACK_EVENT_TARGET__
+ }
+ // CLient event target is the window object
+ if (typeof window !== 'undefined') {
+ this.debugLog('Using window as event target')
+
+ return window
+ }
+
+ this.debugLog('Using new EventTarget as fallback')
+ return new EventTarget()
+ }
+
+ getPluginId() {
+ return this.#pluginId
+ }
+
+ private emitEventToBus(event: TanStackDevtoolsEvent) {
+ this.debugLog('Emitting event to client bus', event)
+ this.#eventTarget().dispatchEvent(
+ new CustomEvent('tanstack-dispatch-event', { detail: event }),
+ )
+ }
+
+ emit<
+ TSuffix extends Extract<
+ keyof TEventMap,
+ `${TPluginId & string}:${string}`
+ > extends `${TPluginId & string}:${infer S}`
+ ? S
+ : never,
+ >(
+ eventSuffix: TSuffix,
+ payload: TEventMap[`${TPluginId & string}:${TSuffix}`],
+ ) {
+ this.emitEventToBus({
+ type: `${this.#pluginId}:${eventSuffix}`,
+ payload,
+ pluginId: this.#pluginId,
+ })
+ }
+
+ on<
+ TSuffix extends Extract<
+ keyof TEventMap,
+ `${TPluginId & string}:${string}`
+ > extends `${TPluginId & string}:${infer S}`
+ ? S
+ : never,
+ >(
+ eventSuffix: TSuffix,
+ cb: (
+ event: TanStackDevtoolsEvent<
+ `${TPluginId & string}:${TSuffix}`,
+ TEventMap[`${TPluginId & string}:${TSuffix}`]
+ >,
+ ) => void,
+ ) {
+ const eventName = `${this.#pluginId}:${eventSuffix}` as const
+ const handler = (e: Event) => {
+ this.debugLog('Received event from bus', (e as CustomEvent).detail)
+ cb((e as CustomEvent).detail)
+ }
+ this.#eventTarget().addEventListener(eventName, handler)
+ this.debugLog('Registered event to bus', eventName)
+ return () => {
+ this.#eventTarget().removeEventListener(eventName, handler)
+ }
+ }
+
+ onAll(cb: (event: TanStackDevtoolsEvent) => void) {
+ const handler = (e: Event) => {
+ const event = (e as CustomEvent).detail
+
+ cb(event)
+ }
+ this.#eventTarget().addEventListener('tanstack-devtools-global', handler)
+ return () =>
+ this.#eventTarget().removeEventListener(
+ 'tanstack-devtools-global',
+ handler,
+ )
+ }
+ onAllPluginEvents(cb: (event: AllDevtoolsEvents) => void) {
+ const handler = (e: Event) => {
+ const event = (e as CustomEvent).detail
+ if (this.#pluginId && event.pluginId !== this.#pluginId) {
+ return
+ }
+ cb(event)
+ }
+ this.#eventTarget().addEventListener('tanstack-devtools-global', handler)
+ return () =>
+ this.#eventTarget().removeEventListener(
+ 'tanstack-devtools-global',
+ handler,
+ )
+ }
+}
diff --git a/packages/event-bus-client/tests/index.test.ts b/packages/event-bus-client/tests/index.test.ts
new file mode 100644
index 00000000..37eb501c
--- /dev/null
+++ b/packages/event-bus-client/tests/index.test.ts
@@ -0,0 +1,226 @@
+import { describe, expect, it, vi } from 'vitest'
+import { EventClient } from '../src'
+import { ClientEventBus } from '@tanstack/devtools-event-bus/client'
+
+// start the client bus for testing
+new ClientEventBus().start()
+// client bus uses window to dispatch events
+const clientBusEmitTarget = window
+
+describe('EventClient', () => {
+ describe('debug config', () => {
+ it('should emit logs when debug set to true and have the correct plugin name', () => {
+ const consoleSpy = vi.spyOn(console, 'log')
+ new EventClient({
+ debug: true,
+ pluginId: 'test',
+ })
+ expect(consoleSpy).toHaveBeenCalledWith(
+ '🌴 [tanstack-devtools:test-plugin]',
+ ' Initializing event subscription for plugin',
+ 'test',
+ )
+ })
+
+ it("shouldn't emit logs when debug set to false", () => {
+ const consoleSpy = vi.spyOn(console, 'log')
+ new EventClient({
+ debug: false,
+ pluginId: 'test',
+ })
+ expect(consoleSpy).not.toHaveBeenCalled()
+ })
+ })
+
+ describe('getGlobalTarget', () => {
+ it('if the global target is set it should re-use it for emitting/listening/removing of events', () => {
+ const target = new EventTarget()
+ globalThis.__TANSTACK_EVENT_TARGET__ = target
+ const client = new EventClient({
+ debug: false,
+ pluginId: 'test',
+ })
+ const targetEmitSpy = vi.spyOn(target, 'dispatchEvent')
+ const targetListenSpy = vi.spyOn(target, 'addEventListener')
+ const targetRemoveSpy = vi.spyOn(target, 'removeEventListener')
+ const cleanup = client.on('test:event', () => {})
+ cleanup()
+ client.emit('test:event', { foo: 'bar' })
+ expect(targetEmitSpy).toHaveBeenCalledWith(expect.any(Event))
+ expect(targetListenSpy).toHaveBeenCalledWith(
+ expect.any(String),
+ expect.any(Function),
+ )
+ expect(targetRemoveSpy).toHaveBeenCalledWith(
+ expect.any(String),
+ expect.any(Function),
+ )
+ globalThis.__TANSTACK_EVENT_TARGET__ = null
+ })
+
+ it('should use the window object if the globalTarget is not set for emitting/listening/removing of events', () => {
+ const target = window
+ const client = new EventClient({
+ debug: false,
+ pluginId: 'test',
+ })
+ const targetEmitSpy = vi.spyOn(target, 'dispatchEvent')
+ const targetListenSpy = vi.spyOn(target, 'addEventListener')
+ const targetRemoveSpy = vi.spyOn(target, 'removeEventListener')
+ const cleanup = client.on('test:event', () => {})
+ cleanup()
+ client.emit('test:event', { foo: 'bar' })
+ expect(targetEmitSpy).toHaveBeenCalledWith(expect.any(Event))
+ expect(targetListenSpy).toHaveBeenCalledWith(
+ expect.any(String),
+ expect.any(Function),
+ )
+ expect(targetRemoveSpy).toHaveBeenCalledWith(
+ expect.any(String),
+ expect.any(Function),
+ )
+ })
+ })
+
+ describe('on', () => {
+ it('should register an event with the pluginId (event => test:event)', () => {
+ const client = new EventClient({
+ debug: false,
+ pluginId: 'test',
+ })
+
+ const eventBusSpy = vi.spyOn(clientBusEmitTarget, 'addEventListener')
+ client.on('event', () => {})
+ expect(eventBusSpy).toHaveBeenCalledWith(
+ 'test:event',
+ expect.any(Function),
+ )
+ })
+ it('should register an event listener for the specified event and get events when they are emitted', () => {
+ const client = new EventClient({
+ debug: false,
+ pluginId: 'test',
+ })
+ const eventHandler = vi.fn()
+ const cleanup = client.on('event', eventHandler)
+ client.emit('event', { foo: 'bar' })
+ expect(eventHandler).toHaveBeenCalledWith({
+ type: 'test:event',
+ payload: { foo: 'bar' },
+ pluginId: 'test',
+ })
+ cleanup()
+ })
+
+ it("shouldn't get an event if unregistered before it comes", () => {
+ const client = new EventClient({
+ debug: false,
+ pluginId: 'test',
+ })
+ const eventHandler = vi.fn()
+ const cleanup = client.on('event', eventHandler)
+ cleanup()
+ client.emit('event', { foo: 'bar' })
+ expect(eventHandler).not.toHaveBeenCalled()
+ })
+
+ it("shouldn't get an event if it's not registered to it", () => {
+ const client = new EventClient({
+ debug: false,
+ pluginId: 'test',
+ })
+ const eventHandler = vi.fn()
+ client.on('event', eventHandler)
+ client.emit('other_event', { foo: 'bar' })
+ expect(eventHandler).not.toHaveBeenCalled()
+ })
+ })
+
+ describe('emit', () => {
+ it('should emit an event with the correct type and payload to the event bus', () => {
+ const client = new EventClient({
+ debug: false,
+ pluginId: 'test',
+ })
+ const eventHandler = vi.fn()
+ client.on('event', eventHandler)
+ client.emit('event', { foo: 'bar' })
+ expect(eventHandler).toHaveBeenCalledWith({
+ type: 'test:event',
+ payload: { foo: 'bar' },
+ pluginId: 'test',
+ })
+ })
+ })
+
+ describe('onAll', () => {
+ it('should listen to all events even if they do not come from the registered client', () => {
+ const client = new EventClient({
+ debug: false,
+ pluginId: 'test',
+ })
+ const eventHandler = vi.fn()
+ client.onAll(eventHandler)
+ client.emit('event', { foo: 'bar' })
+ expect(eventHandler).toHaveBeenCalledWith({
+ type: 'test:event',
+ payload: { foo: 'bar' },
+ pluginId: 'test',
+ })
+ clientBusEmitTarget.dispatchEvent(
+ new CustomEvent('tanstack-dispatch-event', {
+ detail: {
+ type: 'other-plugin',
+ payload: { foo: 'bar' },
+ },
+ }),
+ )
+
+ expect(eventHandler).lastCalledWith({
+ type: 'other-plugin',
+ payload: { foo: 'bar' },
+ })
+ })
+ })
+
+ describe('onAllPluginEvents', () => {
+ it('should listen to all events that come from the plugin', () => {
+ const client = new EventClient({
+ debug: false,
+ pluginId: 'test',
+ })
+ const eventHandler = vi.fn()
+ client.onAllPluginEvents(eventHandler)
+ client.emit('event', { foo: 'bar' })
+ client.emit('event2', { foo: 'bar' })
+ expect(eventHandler).nthCalledWith(1, {
+ type: 'test:event',
+ payload: { foo: 'bar' },
+ pluginId: 'test',
+ })
+ expect(eventHandler).nthCalledWith(2, {
+ type: 'test:event2',
+ payload: { foo: 'bar' },
+ pluginId: 'test',
+ })
+ })
+
+ it('should ignore events that do not come from the plugin', () => {
+ const client = new EventClient({
+ debug: false,
+ pluginId: 'test',
+ })
+ const eventHandler = vi.fn()
+ client.onAllPluginEvents(eventHandler)
+ clientBusEmitTarget.dispatchEvent(
+ new CustomEvent('tanstack-dispatch-event', {
+ detail: {
+ type: 'other-plugin',
+ payload: { foo: 'bar' },
+ },
+ }),
+ )
+ expect(eventHandler).not.toHaveBeenCalled()
+ })
+ })
+})
diff --git a/packages/event-bus-client/tests/test-setup.ts b/packages/event-bus-client/tests/test-setup.ts
new file mode 100644
index 00000000..a9d0dd31
--- /dev/null
+++ b/packages/event-bus-client/tests/test-setup.ts
@@ -0,0 +1 @@
+import '@testing-library/jest-dom/vitest'
diff --git a/packages/event-bus-client/tsconfig.docs.json b/packages/event-bus-client/tsconfig.docs.json
new file mode 100644
index 00000000..2880b4df
--- /dev/null
+++ b/packages/event-bus-client/tsconfig.docs.json
@@ -0,0 +1,4 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["tests", "src"]
+}
diff --git a/packages/event-bus-client/tsconfig.json b/packages/event-bus-client/tsconfig.json
new file mode 100644
index 00000000..1838eb23
--- /dev/null
+++ b/packages/event-bus-client/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "extends": "../../tsconfig.json",
+ "include": [
+ "src",
+ "eslint.config.js",
+ "vite.config.ts",
+ "tests",
+ "src/server"
+ ]
+}
diff --git a/packages/event-bus-client/vite.config.ts b/packages/event-bus-client/vite.config.ts
new file mode 100644
index 00000000..79dae7cd
--- /dev/null
+++ b/packages/event-bus-client/vite.config.ts
@@ -0,0 +1,23 @@
+import { defineConfig, mergeConfig } from 'vitest/config'
+import { tanstackViteConfig } from '@tanstack/config/vite'
+import packageJson from './package.json'
+
+const config = defineConfig({
+ plugins: [],
+ test: {
+ name: packageJson.name,
+ dir: './',
+ watch: false,
+ environment: 'jsdom',
+ setupFiles: ['./tests/test-setup.ts'],
+ globals: true,
+ },
+})
+
+export default mergeConfig(
+ config,
+ tanstackViteConfig({
+ entry: ['./src/index.ts'],
+ srcDir: './src',
+ }),
+)
diff --git a/packages/event-bus/README.md b/packages/event-bus/README.md
new file mode 100644
index 00000000..918d61b2
--- /dev/null
+++ b/packages/event-bus/README.md
@@ -0,0 +1,33 @@
+# @tanstack/devtools-event-bus
+
+This package is still under active development and might have breaking changes in the future. Please use it with caution.
+
+## General Usage
+
+### Server Event Bus
+
+```tsx
+import { ServerEventBus } from '@tanstack/devtools-event-bus/server'
+// Start the server event bus
+const devtoolsServer = new ServerEventBus()
+
+devtoolsServer.start()
+
+export { devtoolsServer }
+```
+
+### Client Event Bus
+
+```ts
+import { ClientEventBus } from '@tanstack/devtools-event-bus/client'
+// Start the client event bus
+const devtoolsClient = new ClientEventBus()
+
+devtoolsClient.start()
+
+export { devtoolsClient }
+```
+
+## Plugins
+
+Check out @tanstack/devtools-event-client for more information on how to create plugins for the event bus.
diff --git a/packages/event-bus/eslint.config.js b/packages/event-bus/eslint.config.js
new file mode 100644
index 00000000..e472c69e
--- /dev/null
+++ b/packages/event-bus/eslint.config.js
@@ -0,0 +1,10 @@
+// @ts-check
+
+import rootConfig from '../../eslint.config.js'
+
+export default [
+ ...rootConfig,
+ {
+ rules: {},
+ },
+]
diff --git a/packages/event-bus/package.json b/packages/event-bus/package.json
new file mode 100644
index 00000000..dcb16231
--- /dev/null
+++ b/packages/event-bus/package.json
@@ -0,0 +1,82 @@
+{
+ "name": "@tanstack/devtools-event-bus",
+ "version": "0.1.1",
+ "description": "TanStack Event Bus is a lightweight event bus for TanStack Devtools.",
+ "author": "Tanner Linsley",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/TanStack/devtools.git",
+ "directory": "packages/devtools"
+ },
+ "homepage": "https://tanstack.com/devtools",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ },
+ "keywords": [
+ "devtools"
+ ],
+ "type": "module",
+ "types": "dist/esm/index.d.ts",
+ "main": "dist/cjs/index.cjs",
+ "module": "dist/esm/index.js",
+ "exports": {
+ "./server": {
+ "import": {
+ "types": "./dist/esm/server/index.d.ts",
+ "default": "./dist/esm/server/index.js"
+ },
+ "require": {
+ "types": "./dist/cjs/server/index.d.cts",
+ "default": "./dist/cjs/server/index.cjs"
+ }
+ },
+ "./client": {
+ "import": {
+ "types": "./dist/esm/client/index.d.ts",
+ "default": "./dist/esm/client/index.js"
+ },
+ "require": {
+ "types": "./dist/cjs/client/index.d.cts",
+ "default": "./dist/cjs/client/index.cjs"
+ }
+ },
+ ".": {
+ "import": {
+ "types": "./dist/esm/index.d.ts",
+ "default": "./dist/esm/index.js"
+ },
+ "require": {
+ "types": "./dist/cjs/index.d.cts",
+ "default": "./dist/cjs/index.cjs"
+ }
+ },
+ "./package.json": "./package.json"
+ },
+ "sideEffects": false,
+ "engines": {
+ "node": ">=18"
+ },
+ "files": [
+ "dist/",
+ "src"
+ ],
+ "scripts": {
+ "clean": "premove ./build ./dist",
+ "lint:fix": "eslint ./src --fix",
+ "test:eslint": "eslint ./src",
+ "test:lib": "vitest",
+ "test:lib:dev": "pnpm test:lib --watch",
+ "test:types": "tsc",
+ "test:build": "publint --strict",
+ "build": "vite build"
+ },
+ "dependencies": {
+ "ws": "^8.18.3"
+ },
+ "devDependencies": {
+ "@types/node": "^22.15.2",
+ "@types/ws": "^8.18.1"
+ }
+}
diff --git a/packages/event-bus/src/client/client.ts b/packages/event-bus/src/client/client.ts
new file mode 100644
index 00000000..0695b781
--- /dev/null
+++ b/packages/event-bus/src/client/client.ts
@@ -0,0 +1,165 @@
+interface TanStackDevtoolsEvent {
+ type: TEventName
+ payload: TPayload
+ pluginId?: string // Optional pluginId to filter events by plugin
+}
+
+export interface ClientEventBusConfig {
+ /**
+ * Optional flag to indicate if the devtools server event bus is available to connect to.
+ * This is used to determine if the devtools can connect to the server for real-time event streams.
+ */
+ connectToServerBus?: boolean
+
+ /**
+ * Optional flag to enable debug mode for the event bus.
+ */
+ debug?: boolean
+
+ /**
+ * Optional port to connect to the devtools server event bus.
+ * Defaults to 42069.
+ */
+ port?: number
+}
+
+export class ClientEventBus {
+ #port: number
+ #socket: WebSocket | null
+ #eventSource: EventSource | null
+ #eventTarget: EventTarget
+ #debug: boolean
+ #connectToServerBus: boolean
+ #dispatcher = (e: Event) => {
+ const event = (e as CustomEvent).detail
+ this.emitToServer(event)
+ this.emitToClients(event)
+ }
+ constructor({
+ port = 42069,
+ debug = false,
+ connectToServerBus = false,
+ }: ClientEventBusConfig = {}) {
+ this.#debug = debug
+ this.#eventSource = null
+ this.#port = port
+ this.#socket = null
+ this.#connectToServerBus = connectToServerBus
+ this.#eventTarget = this.getGlobalTarget()
+ this.debugLog('Initializing client event bus')
+ }
+
+ private emitToClients(event: TanStackDevtoolsEvent) {
+ this.debugLog('Emitting event from client bus', event)
+ const specificEvent = new CustomEvent(event.type, { detail: event })
+ this.debugLog('Emitting event to specific client listeners', event)
+ this.#eventTarget.dispatchEvent(specificEvent)
+ const globalEvent = new CustomEvent('tanstack-devtools-global', {
+ detail: event,
+ })
+ this.debugLog('Emitting event to global client listeners', event)
+ this.#eventTarget.dispatchEvent(globalEvent)
+ }
+
+ private emitToServer(event: TanStackDevtoolsEvent) {
+ const json = JSON.stringify(event)
+ // try to emit it to the event bus first
+ if (this.#socket && this.#socket.readyState === WebSocket.OPEN) {
+ this.debugLog('Emitting event to server via WS', event)
+ this.#socket.send(json)
+ // try to emit to SSE if WebSocket is not available (this will only happen on the client side)
+ } else if (this.#eventSource) {
+ this.debugLog('Emitting event to server via SSE', event)
+
+ fetch(`http://localhost:${this.#port}/__devtools/send`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: json,
+ }).catch(() => {})
+ }
+ }
+ start() {
+ this.debugLog('Starting client event bus')
+ if (typeof window === 'undefined') {
+ return
+ }
+ if (this.#connectToServerBus) {
+ this.connect()
+ }
+ this.#eventTarget = window
+ this.#eventTarget.addEventListener(
+ 'tanstack-dispatch-event',
+ this.#dispatcher,
+ )
+ }
+ stop() {
+ this.debugLog('Stopping client event bus')
+ if (typeof window === 'undefined') {
+ return
+ }
+ this.#eventTarget.removeEventListener(
+ 'tanstack-dispatch-event',
+ this.#dispatcher,
+ )
+ this.#eventSource?.close()
+ this.#socket?.close()
+ this.#socket = null
+ this.#eventSource = null
+ }
+ private getGlobalTarget() {
+ if (typeof window !== 'undefined') {
+ return window
+ }
+
+ return new EventTarget()
+ }
+ private debugLog(...messages: Array) {
+ if (this.#debug) {
+ console.log('🌴 [tanstack-devtools:client-bus]', ...messages)
+ }
+ }
+ private connectSSE() {
+ this.debugLog('Connecting to SSE server')
+ this.#eventSource = new EventSource(
+ `http://localhost:${this.#port}/__devtools/sse`,
+ )
+ this.#eventSource.onmessage = (e) => {
+ this.debugLog('Received message from SSE server', e.data)
+ this.handleEventReceived(e.data)
+ }
+ }
+
+ private connectWebSocket() {
+ this.debugLog('Connecting to WebSocket server')
+
+ this.#socket = new WebSocket(`ws://localhost:${this.#port}/__devtools/ws`)
+ this.#socket.onmessage = (e) => {
+ this.debugLog('Received message from server', e.data)
+ this.handleEventReceived(e.data)
+ }
+ this.#socket.onclose = () => {
+ this.debugLog('WebSocket connection closed')
+ this.#socket = null
+ }
+ this.#socket.onerror = () => {
+ this.debugLog('WebSocket connection error')
+ }
+ }
+
+ private connect() {
+ try {
+ this.connectWebSocket()
+ } catch {
+ // Do not try to connect if we're on the server side
+ if (typeof window === 'undefined') return
+ this.connectSSE()
+ }
+ }
+
+ private handleEventReceived(data: string) {
+ try {
+ const event = JSON.parse(data) as TanStackDevtoolsEvent
+ this.emitToClients(event)
+ } catch {}
+ }
+}
diff --git a/packages/event-bus/src/client/index.ts b/packages/event-bus/src/client/index.ts
new file mode 100644
index 00000000..c083f323
--- /dev/null
+++ b/packages/event-bus/src/client/index.ts
@@ -0,0 +1,2 @@
+export { ClientEventBus } from './client'
+export type { ClientEventBusConfig } from './client'
diff --git a/packages/event-bus/src/index.ts b/packages/event-bus/src/index.ts
new file mode 100644
index 00000000..e69de29b
diff --git a/packages/event-bus/src/server/index.ts b/packages/event-bus/src/server/index.ts
new file mode 100644
index 00000000..03485a72
--- /dev/null
+++ b/packages/event-bus/src/server/index.ts
@@ -0,0 +1,2 @@
+export { ServerEventBus } from './server'
+export type { TanstackDevtoolsEvent } from './server'
diff --git a/packages/event-bus/src/server/server.ts b/packages/event-bus/src/server/server.ts
new file mode 100644
index 00000000..932381f5
--- /dev/null
+++ b/packages/event-bus/src/server/server.ts
@@ -0,0 +1,205 @@
+import http from 'node:http'
+import { WebSocket, WebSocketServer } from 'ws'
+
+// Shared types
+export interface TanstackDevtoolsEvent<
+ TEventName extends string,
+ TPayload = any,
+> {
+ type: TEventName
+ payload: TPayload
+ pluginId?: string // Optional pluginId to filter events by plugin
+}
+// Used so no new server starts up when HMR happens
+declare global {
+ // eslint-disable-next-line no-var
+ var __TANSTACK_DEVTOOLS_SERVER__: http.Server | null
+ // eslint-disable-next-line no-var
+ var __TANSTACK_DEVTOOLS_WSS_SERVER__: WebSocketServer | null
+ // eslint-disable-next-line no-var
+ var __EVENT_TARGET__: EventTarget | null
+}
+
+export class ServerEventBus {
+ #eventTarget: EventTarget
+ #clients = new Set()
+ #sseClients = new Set()
+ #server: http.Server | null = null
+ #wssServer: WebSocketServer | null = null
+ #port: number
+ #debug: boolean
+ #dispatcher = (e: Event) => {
+ const event = (e as CustomEvent).detail
+ this.debugLog('Dispatching event from dispatcher, forwarding', event)
+ this.emit(event)
+ }
+
+ constructor({ port = 42069, debug = false } = {}) {
+ this.#port = port
+ this.#eventTarget = globalThis.__EVENT_TARGET__ ?? new EventTarget()
+ // we want to set the global event target only once so that we can emit/listen to events on the server
+ if (!globalThis.__EVENT_TARGET__) {
+ globalThis.__EVENT_TARGET__ = this.#eventTarget
+ }
+ this.#server = globalThis.__TANSTACK_DEVTOOLS_SERVER__ ?? null
+ this.#wssServer = globalThis.__TANSTACK_DEVTOOLS_WSS_SERVER__ ?? null
+ this.#debug = debug
+ this.debugLog('Initializing server event bus')
+ }
+
+ private debugLog(...args: Array) {
+ if (this.#debug) {
+ console.log('🌴 [tanstack-devtools:server-bus] ', ...args)
+ }
+ }
+
+ private emitToServer(event: TanstackDevtoolsEvent) {
+ this.debugLog('Emitting event to specific server listeners', event)
+ this.#eventTarget.dispatchEvent(
+ new CustomEvent(event.type, { detail: event }),
+ )
+ this.debugLog('Emitting event to global server listeners', event)
+ this.#eventTarget.dispatchEvent(
+ new CustomEvent('tanstack-devtools-global', { detail: event }),
+ )
+ }
+
+ private emitEventToClients(event: TanstackDevtoolsEvent) {
+ this.debugLog('Emitting event to clients', event)
+ const json = JSON.stringify(event)
+
+ for (const client of this.#clients) {
+ if (client.readyState === WebSocket.OPEN) {
+ client.send(json)
+ }
+ }
+ for (const res of this.#sseClients) {
+ res.write(`data: ${json}\n\n`)
+ }
+ }
+
+ private emit(event: TanstackDevtoolsEvent) {
+ this.emitEventToClients(event)
+ this.emitToServer(event)
+ }
+
+ private createSSEServer() {
+ if (this.#server) {
+ return this.#server
+ }
+ const server = http.createServer((req, res) => {
+ if (req.url === '/__devtools/sse') {
+ res.writeHead(200, {
+ 'Content-Type': 'text/event-stream',
+ 'Cache-Control': 'no-cache',
+ Connection: 'keep-alive',
+ 'Access-Control-Allow-Origin': '*',
+ })
+ res.write('\n')
+ this.debugLog('New SSE client connected')
+ this.#sseClients.add(res)
+ req.on('close', () => this.#sseClients.delete(res))
+ return
+ }
+
+ if (req.url === '/__devtools/send' && req.method === 'POST') {
+ let body = ''
+ req.on('data', (chunk) => (body += chunk))
+ req.on('end', () => {
+ try {
+ const msg = JSON.parse(body)
+ this.debugLog('Received event from client', msg)
+ this.emitToServer(msg)
+ } catch {}
+ })
+ res.writeHead(200).end()
+ return
+ }
+
+ res.statusCode = 404
+ res.end()
+ })
+ globalThis.__TANSTACK_DEVTOOLS_SERVER__ = server
+ this.#server = server
+ return server
+ }
+
+ private createWebSocketServer() {
+ if (this.#wssServer) {
+ return this.#wssServer
+ }
+
+ const wss = new WebSocketServer({ noServer: true })
+ this.#wssServer = wss
+ globalThis.__TANSTACK_DEVTOOLS_WSS_SERVER__ = wss
+ return wss
+ }
+
+ private handleNewConnection(wss: WebSocketServer) {
+ wss.on('connection', (ws: WebSocket) => {
+ this.debugLog('New WebSocket client connected')
+ this.#clients.add(ws)
+ ws.on('close', () => {
+ this.debugLog('WebSocket client disconnected')
+ this.#clients.delete(ws)
+ })
+ ws.on('message', (msg) => {
+ this.debugLog('Received message from WebSocket client', msg.toString())
+ const data = JSON.parse(msg.toString())
+ this.emitToServer(data)
+ })
+ })
+ }
+
+ start() {
+ if (process.env.NODE_ENV !== 'development') return
+ if (this.#server || this.#wssServer) {
+ // console.warn('Server is already running')
+ return
+ }
+ this.debugLog('Starting server event bus')
+ const server = this.createSSEServer()
+ const wss = this.createWebSocketServer()
+
+ this.#eventTarget.addEventListener(
+ 'tanstack-dispatch-event',
+ this.#dispatcher,
+ )
+ this.handleNewConnection(wss)
+
+ // Handle connection upgrade for WebSocket
+ server.on('upgrade', (req, socket, head) => {
+ if (req.url === '/__devtools/ws') {
+ wss.handleUpgrade(req, socket, head, (ws) => {
+ this.debugLog('WebSocket connection established')
+ wss.emit('connection', ws, req)
+ })
+ }
+ })
+
+ server.listen(this.#port, () => {
+ this.debugLog(`Listening on http://localhost:${this.#port}`)
+ })
+ }
+
+ stop() {
+ this.#server?.close(() => {
+ this.debugLog('Server stopped')
+ })
+ this.#wssServer?.close(() => {
+ this.debugLog('WebSocket server stopped')
+ })
+ this.debugLog('Clearing all connections')
+ this.#clients.clear()
+ this.#sseClients.forEach((res) => res.end())
+ this.#sseClients.clear()
+ this.debugLog('Cleared all WS/SSE connections')
+ this.#server = null
+ this.#wssServer = null
+ this.#eventTarget.removeEventListener(
+ 'tanstack-dispatch-event',
+ this.#dispatcher,
+ )
+ this.debugLog('[tanstack-devtools] All connections cleared')
+ }
+}
diff --git a/packages/event-bus/tests/index.test.ts b/packages/event-bus/tests/index.test.ts
new file mode 100644
index 00000000..305c4ead
--- /dev/null
+++ b/packages/event-bus/tests/index.test.ts
@@ -0,0 +1,88 @@
+import { afterEach, describe, expect, it, vi } from 'vitest'
+import { ClientEventBus } from '../src/client'
+
+describe('ClientEventBus', () => {
+ describe('debug', () => {
+ afterEach(() => {
+ vi.restoreAllMocks()
+ })
+ it('should log events to the console when debug set to true', () => {
+ const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
+ const clientBus = new ClientEventBus({ debug: true })
+ clientBus.start()
+
+ expect(logSpy).toHaveBeenCalledWith(
+ '🌴 [tanstack-devtools:client-bus]',
+ 'Initializing client event bus',
+ )
+ logSpy.mockRestore()
+ clientBus.stop()
+ })
+
+ it('should not log events to the console when debug set to false', () => {
+ const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
+ const clientBus = new ClientEventBus({ debug: false })
+ clientBus.start()
+
+ expect(logSpy).not.toHaveBeenCalled()
+ logSpy.mockRestore()
+ clientBus.stop()
+ })
+ })
+ it('should emit events to a subscribed listener', () => {
+ const clientBus = new ClientEventBus()
+ clientBus.start()
+ const handler = vi.fn()
+ window.addEventListener('test:event', handler)
+
+ window.dispatchEvent(
+ new CustomEvent('tanstack-dispatch-event', {
+ detail: {
+ type: 'test:event',
+ payload: { foo: 'bar' },
+ },
+ }),
+ )
+ expect(handler).toHaveBeenCalled()
+ clientBus.stop()
+ })
+
+ it('should emit events to listeners that are subscribed', () => {
+ const clientBus = new ClientEventBus()
+ clientBus.start()
+ const handler = vi.fn()
+ window.addEventListener('test:event', handler)
+ const secondHandler = vi.fn()
+ window.addEventListener('test:event', secondHandler)
+
+ window.dispatchEvent(
+ new CustomEvent('tanstack-dispatch-event', {
+ detail: {
+ type: 'test:event',
+ payload: { foo: 'bar' },
+ },
+ }),
+ )
+ expect(handler).toHaveBeenCalled()
+ expect(secondHandler).toHaveBeenCalled()
+ clientBus.stop()
+ })
+
+ it('should emit events to global listeners when they are subscribed', () => {
+ const clientBus = new ClientEventBus()
+ clientBus.start()
+ const handler = vi.fn()
+ window.addEventListener('tanstack-devtools-global', handler)
+
+ window.dispatchEvent(
+ new CustomEvent('tanstack-dispatch-event', {
+ detail: {
+ type: 'test:event',
+ payload: { foo: 'bar' },
+ },
+ }),
+ )
+ expect(handler).toHaveBeenCalled()
+ clientBus.stop()
+ })
+})
diff --git a/packages/event-bus/tests/test-setup.ts b/packages/event-bus/tests/test-setup.ts
new file mode 100644
index 00000000..a9d0dd31
--- /dev/null
+++ b/packages/event-bus/tests/test-setup.ts
@@ -0,0 +1 @@
+import '@testing-library/jest-dom/vitest'
diff --git a/packages/event-bus/tsconfig.docs.json b/packages/event-bus/tsconfig.docs.json
new file mode 100644
index 00000000..2880b4df
--- /dev/null
+++ b/packages/event-bus/tsconfig.docs.json
@@ -0,0 +1,4 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["tests", "src"]
+}
diff --git a/packages/event-bus/tsconfig.json b/packages/event-bus/tsconfig.json
new file mode 100644
index 00000000..1838eb23
--- /dev/null
+++ b/packages/event-bus/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "extends": "../../tsconfig.json",
+ "include": [
+ "src",
+ "eslint.config.js",
+ "vite.config.ts",
+ "tests",
+ "src/server"
+ ]
+}
diff --git a/packages/event-bus/vite.config.ts b/packages/event-bus/vite.config.ts
new file mode 100644
index 00000000..0060a798
--- /dev/null
+++ b/packages/event-bus/vite.config.ts
@@ -0,0 +1,23 @@
+import { defineConfig, mergeConfig } from 'vitest/config'
+import { tanstackViteConfig } from '@tanstack/config/vite'
+import packageJson from './package.json'
+
+const config = defineConfig({
+ plugins: [],
+ test: {
+ name: packageJson.name,
+ dir: './',
+ watch: false,
+ environment: 'jsdom',
+ setupFiles: ['./tests/test-setup.ts'],
+ globals: true,
+ },
+})
+
+export default mergeConfig(
+ config,
+ tanstackViteConfig({
+ entry: ['./src/client/index.ts', './src/server/index.ts', './src/index.ts'],
+ srcDir: './src',
+ }),
+)
diff --git a/packages/react-devtools/src/devtools.tsx b/packages/react-devtools/src/devtools.tsx
index 1f5753cd..c988c289 100644
--- a/packages/react-devtools/src/devtools.tsx
+++ b/packages/react-devtools/src/devtools.tsx
@@ -7,6 +7,7 @@ import {
import { createPortal } from 'react-dom'
import type { JSX } from 'react'
import type {
+ ClientEventBusConfig,
TanStackDevtoolsConfig,
TanStackDevtoolsPlugin,
} from '@tanstack/devtools'
@@ -83,6 +84,10 @@ export interface TanStackDevtoolsReactInit {
* the settings are persisted in local storage and changed through the settings panel.
*/
config?: Partial
+ /**
+ * Configuration for the TanStack Devtools client event bus.
+ */
+ eventBusConfig?: ClientEventBusConfig
}
const convertRender = (
@@ -95,6 +100,7 @@ const convertRender = (
export const TanstackDevtools = ({
plugins,
config,
+ eventBusConfig,
}: TanStackDevtoolsReactInit) => {
const devToolRef = useRef(null)
const [pluginContainer, setPluginContainer] = useState(
@@ -109,6 +115,7 @@ export const TanstackDevtools = ({
() =>
new TanStackDevtoolsCore({
config,
+ eventBusConfig,
plugins: plugins?.map((plugin) => {
return {
...plugin,
@@ -141,9 +148,7 @@ export const TanstackDevtools = ({
devtools.mount(devToolRef.current)
}
- return () => {
- devtools.unmount()
- }
+ return () => devtools.unmount()
}, [devtools])
return (
diff --git a/packages/solid-devtools/src/devtools.tsx b/packages/solid-devtools/src/devtools.tsx
index f4d4157e..795a6943 100644
--- a/packages/solid-devtools/src/devtools.tsx
+++ b/packages/solid-devtools/src/devtools.tsx
@@ -3,6 +3,7 @@ import { createEffect, createSignal, onCleanup, onMount } from 'solid-js'
import { Portal } from 'solid-js/web'
import type { JSX } from 'solid-js'
import type {
+ ClientEventBusConfig,
TanStackDevtoolsConfig,
TanStackDevtoolsPlugin,
} from '@tanstack/devtools'
@@ -85,13 +86,22 @@ interface TanstackDevtoolsInit {
* initial state of the devtools when it is started for the first time. Afterwards,
* the settings are persisted in local storage and changed through the settings panel.
*/
- config?: TanStackDevtoolsConfig
+ config?: Partial
+ /**
+ * Configuration for the TanStack Devtools client event bus.
+ */
+ eventBusConfig?: ClientEventBusConfig
}
-export const TanstackDevtools = ({ config, plugins }: TanstackDevtoolsInit) => {
+export const TanstackDevtools = ({
+ config,
+ plugins,
+ eventBusConfig,
+}: TanstackDevtoolsInit) => {
const [devtools] = createSignal(
new TanStackDevtoolsCore({
config,
+ eventBusConfig,
plugins: plugins?.map((plugin) => ({
...plugin,
name:
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 82b0050d..62289d57 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -74,6 +74,9 @@ importers:
examples/react/basic:
dependencies:
+ '@tanstack/devtools-event-client':
+ specifier: workspace:^
+ version: link:../../../packages/event-bus-client
'@tanstack/react-devtools':
specifier: ^0.1.1
version: link:../../../packages/react-devtools
@@ -88,13 +91,16 @@ importers:
version: 1.130.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@tanstack/react-router-devtools':
specifier: ^1.130.2
- version: 1.130.2(@tanstack/react-router@1.130.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.130.9)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(solid-js@1.9.7)(tiny-invariant@1.3.3)
+ version: 1.130.2(@tanstack/react-router@1.130.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.130.12)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(solid-js@1.9.7)(tiny-invariant@1.3.3)
react:
specifier: ^19.1.0
version: 19.1.0
react-dom:
specifier: ^19.1.0
version: 19.1.0(react@19.1.0)
+ zod:
+ specifier: ^4.0.14
+ version: 4.0.14
devDependencies:
'@types/react':
specifier: ^19.1.2
@@ -151,6 +157,12 @@ importers:
'@tailwindcss/vite':
specifier: ^4.0.6
version: 4.1.11(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
+ '@tanstack/devtools-event-bus':
+ specifier: workspace:^
+ version: link:../../../packages/event-bus
+ '@tanstack/devtools-event-client':
+ specifier: workspace:^
+ version: link:../../../packages/event-bus-client
'@tanstack/react-devtools':
specifier: ^0.1.1
version: link:../../../packages/react-devtools
@@ -165,13 +177,13 @@ importers:
version: 1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@tanstack/react-router-devtools':
specifier: ^1.130.2
- version: 1.130.2(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.130.9)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(solid-js@1.9.7)(tiny-invariant@1.3.3)
+ version: 1.130.2(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.130.12)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(solid-js@1.9.7)(tiny-invariant@1.3.3)
'@tanstack/react-router-with-query':
specifier: ^1.130.2
- version: 1.130.9(@tanstack/react-query@5.83.0(react@19.1.0))(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.130.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ version: 1.130.9(@tanstack/react-query@5.83.0(react@19.1.0))(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.130.12)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@tanstack/react-start':
- specifier: ^1.130.2
- version: 1.130.9(@netlify/blobs@9.1.2)(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@vitejs/plugin-react@4.7.0(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
+ specifier: ^1.130.15
+ version: 1.130.15(@netlify/blobs@9.1.2)(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@vitejs/plugin-react@4.7.0(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
'@tanstack/router-plugin':
specifier: ^1.121.2
version: 1.130.9(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
@@ -190,7 +202,13 @@ importers:
vite-tsconfig-paths:
specifier: ^5.1.4
version: 5.1.4(typescript@5.8.3)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
+ zod:
+ specifier: ^4.0.14
+ version: 4.0.14
devDependencies:
+ '@tanstack/devtools':
+ specifier: workspace:^
+ version: link:../../../packages/devtools
'@testing-library/dom':
specifier: ^10.4.0
version: 10.4.1
@@ -222,6 +240,8 @@ importers:
specifier: ^4.2.4
version: 4.2.4
+ examples/react/start/generated/prisma: {}
+
examples/solid/basic:
dependencies:
'@tanstack/solid-devtools':
@@ -238,7 +258,7 @@ importers:
version: 1.130.2(solid-js@1.9.7)
'@tanstack/solid-router-devtools':
specifier: ^1.129.8
- version: 1.130.2(@tanstack/router-core@1.130.9)(@tanstack/solid-router@1.130.2(solid-js@1.9.7))(csstype@3.1.3)(solid-js@1.9.7)(tiny-invariant@1.3.3)
+ version: 1.130.2(@tanstack/router-core@1.130.12)(@tanstack/solid-router@1.130.2(solid-js@1.9.7))(csstype@3.1.3)(solid-js@1.9.7)(tiny-invariant@1.3.3)
solid-js:
specifier: ^1.9.7
version: 1.9.7
@@ -255,6 +275,9 @@ importers:
'@solid-primitives/keyboard':
specifier: ^1.2.8
version: 1.2.8(solid-js@1.9.7)
+ '@tanstack/devtools-event-bus':
+ specifier: workspace:*
+ version: link:../event-bus
clsx:
specifier: ^2.1.1
version: 2.1.1
@@ -269,6 +292,25 @@ importers:
specifier: ^2.11.6
version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
+ packages/event-bus:
+ dependencies:
+ ws:
+ specifier: ^8.18.3
+ version: 8.18.3
+ devDependencies:
+ '@types/node':
+ specifier: ^22.15.2
+ version: 22.15.2
+ '@types/ws':
+ specifier: ^8.18.1
+ version: 8.18.1
+
+ packages/event-bus-client:
+ devDependencies:
+ '@tanstack/devtools-event-bus':
+ specifier: workspace:*
+ version: link:../event-bus
+
packages/react-devtools:
dependencies:
'@tanstack/devtools':
@@ -2172,8 +2214,8 @@ packages:
peerDependencies:
solid-js: '>=1.9.7'
- '@tanstack/directive-functions-plugin@1.129.7':
- resolution: {integrity: sha512-2VvlVmDvwHOnDAXQQa+gnhDnWPW59JcqePFf1ujOG0QGv+pw1G+JzHpiLZs4Dwr4myMxMGzFp5AWtvF96rpE7Q==}
+ '@tanstack/directive-functions-plugin@1.130.12':
+ resolution: {integrity: sha512-Q5O6D0iPFZGfpj7WYoiXoYRnpfePO61SveAJQL3EWMATGGBueD90JkbCDRXP+Ib4fcWjlmj10tXRUXDMeEapxA==}
engines: {node: '>=12'}
peerDependencies:
vite: '>=6.0.0'
@@ -2186,6 +2228,10 @@ packages:
resolution: {integrity: sha512-I3YTkbe4RZQN54Qw4+IUhOjqG2DdbG2+EBWuQfew4MEk0eddLYAQVa50BZVww4/D2eh5I9vEk2Fd1Y0Wty7pug==}
engines: {node: '>=12'}
+ '@tanstack/history@1.130.12':
+ resolution: {integrity: sha512-2VO1nNFDWojgZ7Uqv/OJfH6LphZQ1kE6l8sI3YBgSPtj3qN6I/rsoTHW9rGjwiDO8sQoDRXod2hpH6HMs5NDsw==}
+ engines: {node: '>=12'}
+
'@tanstack/publish-config@0.2.0':
resolution: {integrity: sha512-RC0yRBFJvGuR58tKQUIkMXVEiATXgESIc+3/NTqoCC7D2YOF4fZGmHGYIanFEPQH7EGfQ5+Bwi+H6BOtKnymtw==}
engines: {node: '>=18'}
@@ -2235,6 +2281,13 @@ packages:
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
+ '@tanstack/react-router@1.130.12':
+ resolution: {integrity: sha512-7BYgOpGc1vK8MH1LIFLLBudGpH46GQy+hewnP7dNQJ4KHmkwPHv958L1IMA9jU/rs5g1ZH5n1f33BAMOBXUMYQ==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ react: '>=18.0.0 || >=19.0.0'
+ react-dom: '>=18.0.0 || >=19.0.0'
+
'@tanstack/react-router@1.130.2':
resolution: {integrity: sha512-gDWChae5jszlBs/IYSZ46QS85iyfDrfukalV5hU2tU52Q7a3IAtr7SPSIVkClZsU4JT4GwZ35NcGHzDQ/8NQzA==}
engines: {node: '>=12'}
@@ -2249,29 +2302,29 @@ packages:
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
- '@tanstack/react-start-client@1.130.9':
- resolution: {integrity: sha512-iGz4vvIaRHM0CGuxC7TvdPmB4HVYyOJg06LdYaJr7QiXjANiMjkQhm2SUEe5mPn6QVLv7CX8zX3ErRoAhMBwzA==}
+ '@tanstack/react-start-client@1.130.12':
+ resolution: {integrity: sha512-ATV8zccbwkSC7OP7t59yfxeOVcNjIViUThDKVQ2r8YQGUSIqbi05EYNeG1D89Jb4sLdSeXWoPnxGQS9/2veBDA==}
engines: {node: '>=12'}
peerDependencies:
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
- '@tanstack/react-start-plugin@1.130.9':
- resolution: {integrity: sha512-ideuWfOazh4xLw9Ld6Qt1DS+W+Q+t0pKWRu/QKuAZgpH+z5QG8PwpwbzTKKIWk79fJT0yyxA8bpKydBuJdN0Ag==}
+ '@tanstack/react-start-plugin@1.130.15':
+ resolution: {integrity: sha512-kZ1WBWNLtgl0al9Ahbq/zfEuKc+CezCGNqWb7B8byIjthnRcdrXBaah35zG65FMEzAk0e+F1bpS+5Q2RNxvthQ==}
engines: {node: '>=12'}
peerDependencies:
'@vitejs/plugin-react': '>=4.3.4'
vite: '>=6.0.0'
- '@tanstack/react-start-server@1.130.9':
- resolution: {integrity: sha512-6Ka/5pP/sqdki81YgalgCq8h5Xz5NLJZ2gvAPrGZI8/Uc4vtD6SY6SuZbu/Q5ZgYlp4xWhEiKlkZe6KkuPwCPA==}
+ '@tanstack/react-start-server@1.130.12':
+ resolution: {integrity: sha512-5gW1V6fqPwFiG+J7W7k7DmB75wjP6zoy6hQcoxlKurMaFm3VTtck9d6mrfOz/47TUB+xb95aSf56Yqq/tuAO7g==}
engines: {node: '>=12'}
peerDependencies:
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
- '@tanstack/react-start@1.130.9':
- resolution: {integrity: sha512-4mHdI7zBtBRU9+31E4fVSH7hT3Cz08/yW1NdEMp8PllSKJZLG/630StPqeceCTePiFqpvB6NEcS5iFoixA8XJg==}
+ '@tanstack/react-start@1.130.15':
+ resolution: {integrity: sha512-mb2mcA0CTYzLs8rKf+wiUT2vSFh85nohQJQCS5pRG5JgIPEWxuIODcx+e2Fn2jiORb4khQNm5vm/qMqmAAkarw==}
engines: {node: '>=12'}
peerDependencies:
'@vitejs/plugin-react': '>=4.3.4'
@@ -2285,6 +2338,10 @@ 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/router-core@1.130.12':
+ resolution: {integrity: sha512-emq3cRU9Na1hnIToojzkfJcOZm/MG2bv9M+Kr/elUxEf83enGEwQXC1EKezTuwNgeJrOv8vPJdEhWM7IQodnHQ==}
+ engines: {node: '>=12'}
+
'@tanstack/router-core@1.130.2':
resolution: {integrity: sha512-d5hYEEAvNUImpoomTlP2tRelX4JiNx3g2uk6xAO/aPKuMYdfntBSV7xbKuWZEhSwqeN2Z4qD3YyQEXBa4Fu7Mg==}
engines: {node: '>=12'}
@@ -2305,10 +2362,35 @@ packages:
csstype:
optional: true
+ '@tanstack/router-generator@1.130.15':
+ resolution: {integrity: sha512-2TICfuSN8oYydTHd+nATkKV4B37XRrAWrwK9+g5dPVUP9lhLy7FQy3IVcb1HRXFXvW0zr5zPNxXErTrOmrceyA==}
+ engines: {node: '>=12'}
+
'@tanstack/router-generator@1.130.9':
resolution: {integrity: sha512-DsQ7kLQmMk0L3K3/QtuMveILQWAarzfv6DpLMN9+fHlIFuw7OQinVrzD9i+9oAKcYzsBgM1iez5IMXYpCta1gA==}
engines: {node: '>=12'}
+ '@tanstack/router-plugin@1.130.15':
+ resolution: {integrity: sha512-ovYGN0a5CxIPkVdbJPLAqwlE0eUYhHm0PkPCH0TxR24XpEGaCxAOw92DriLRZj9R4xTg5oeJqM+3wiZJfujx/A==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ '@rsbuild/core': '>=1.0.2'
+ '@tanstack/react-router': ^1.130.12
+ vite: '>=5.0.0 || >=6.0.0'
+ vite-plugin-solid: ^2.11.2
+ webpack: '>=5.92.0'
+ peerDependenciesMeta:
+ '@rsbuild/core':
+ optional: true
+ '@tanstack/react-router':
+ optional: true
+ vite:
+ optional: true
+ vite-plugin-solid:
+ optional: true
+ webpack:
+ optional: true
+
'@tanstack/router-plugin@1.130.9':
resolution: {integrity: sha512-/QmDbj+z/UysHeMi9F4sJqh76clSX4QFjIdOgO7u8nXkgjSBfPcyWos+1rw9ovn+DeDmyKlvzt3BEIU1+bvptA==}
engines: {node: '>=12'}
@@ -2334,8 +2416,12 @@ packages:
resolution: {integrity: sha512-I2OyQF5U6sxHJApXKCUmCncTHKcpj4681FwyxpYg5QYOatHcn/zVMl7Rj4h36fu8/Lo2ZRLxUMd5kmXgp5Pb/A==}
engines: {node: '>=12'}
- '@tanstack/server-functions-plugin@1.129.7':
- resolution: {integrity: sha512-s0foXwzTAn7FOVeZCNM7BuJr5Y/hUKt2yizsTjlG2i9kWRI8K7g0GbJPNgP86iIVGAEsKmOoJH00HUwLTVNajg==}
+ '@tanstack/router-utils@1.130.12':
+ resolution: {integrity: sha512-vyk7qduNrVrJWgUXHqRyZrFLOL9YJ/4ycN5PbJ2cLRBln01NkG/abKTHi32V31yMehxkxAO0EoicicvalnV0FA==}
+ engines: {node: '>=12'}
+
+ '@tanstack/server-functions-plugin@1.130.12':
+ resolution: {integrity: sha512-aiYxrC6A8jPojAhHfH10YiwfI626yTBlyzIvdPzVvv3DWkRA7yShSOc6FDuwX+oSPmScJSIX/OAHTzJnStY5GA==}
engines: {node: '>=12'}
'@tanstack/solid-query-devtools@5.83.0':
@@ -2367,34 +2453,34 @@ packages:
peerDependencies:
solid-js: ^1.6.0
- '@tanstack/start-client-core@1.130.9':
- resolution: {integrity: sha512-/Rot3+3eOaTOM5lyosNByAk0j+zVmZ5SE2F37dV6dk1OiurObHslkFIT2UquQ+sI+ZzzKw8h6leSoOXPhRM2gg==}
+ '@tanstack/start-client-core@1.130.12':
+ resolution: {integrity: sha512-UedcsrVeObBlmTJ180oC2llOQY9WhkTjylEV9w7hgQ5QHmbu1i6Jw3WPjIrT1KjSxGRG+t7jmafs2AyICpIpQg==}
engines: {node: '>=12'}
- '@tanstack/start-plugin-core@1.130.9':
- resolution: {integrity: sha512-h2vFCTneLVWos7xqAgVTXfPPrbsTR3MyZ6431zcIn4AbbfE7G8mIJKYBWvV2iIW+cY4CIwW/+7oz0Q6YxP1k8Q==}
+ '@tanstack/start-plugin-core@1.130.15':
+ resolution: {integrity: sha512-zhHLoSIRuM8NmsZP12RIRSUFlF3yZraWBfcg/6XDfwJVYmYGyWZSWhCjzXQe2XerXhTvpTscDJcBIWzZZRC85g==}
engines: {node: '>=12'}
peerDependencies:
vite: '>=6.0.0'
- '@tanstack/start-server-core@1.130.9':
- resolution: {integrity: sha512-Bgau6dGRrmKCjSlNwuyrxsZGBu+R/sMQ303tgJqngXXG9p6mzCVa9yb0GoZqGvMfE5MvzS70AauXVV7hgeRePQ==}
+ '@tanstack/start-server-core@1.130.12':
+ resolution: {integrity: sha512-xDuuv4nRECfEnXkA3W3yRw+ci4XUjway2CWopGFDDGyTJn/Ff1OSyLvZxyGGrBLPeVk8+vzLoO3y39UUO8HWaQ==}
engines: {node: '>=12'}
- '@tanstack/start-server-functions-client@1.130.9':
- resolution: {integrity: sha512-0tZmahdSLJcLlARJS8BVjzVrA7jYjkZLgwzeQ+TuuupPi84TmD+ZWQF9xUgHdWV17ZBm7nmKMzrXXeL981M1jQ==}
+ '@tanstack/start-server-functions-client@1.130.12':
+ resolution: {integrity: sha512-sXPVGilBGZlx8Kxc6NHpE3kRSk7mArvjgETQbzHmxJAv0ut7FeXNSWVd5LyXGHWdQ83cP1AKhAz129Una6U/gw==}
engines: {node: '>=12'}
- '@tanstack/start-server-functions-fetcher@1.130.9':
- resolution: {integrity: sha512-MH95sd65uTbVVe3JfwoCo/UX5n989Mry6UQxNqsiXwtmTmpxya/M3JRdHKYcMidZbLW6VB472W3y2aqdbr0dJw==}
+ '@tanstack/start-server-functions-fetcher@1.130.12':
+ resolution: {integrity: sha512-tzYrcsKmFSLGuzrWwlguJSl8fzuLVxAl+OJbfBcJ/pVpkvi/aJ9toLV8h/M10wHhlZQWyu69lb0MAak3eCE+dA==}
engines: {node: '>=12'}
- '@tanstack/start-server-functions-server@1.129.7':
- resolution: {integrity: sha512-iHECAPMycUv1S8gc47ldm4oFYqAzhfgwt7hnwOAx3W+y+qwTn9WP/+S2TWXyo+2QvsJX4+b1NaZSRyQQsd9Ypg==}
+ '@tanstack/start-server-functions-server@1.130.12':
+ resolution: {integrity: sha512-VXiXpfkRcQmrVa45eTztJvLRx0N9E5ggaZxyRQcYU3FTnTADeC+MC7q0eiB0t46if4N/39XwSYCiyu6c1UL1Lw==}
engines: {node: '>=12'}
- '@tanstack/start-storage-context@1.130.9':
- resolution: {integrity: sha512-aTenkZfNe9CJ/kJfXIK9+3JqnG43SRu8Y8hcGHGghr60vCUiKX/RIfoxKg4OEIvq3fr7s1amlJoEcIDmawsE9w==}
+ '@tanstack/start-storage-context@1.130.12':
+ resolution: {integrity: sha512-qs2vos0jO1SFjgi9yHQOqjwuYPEu4VX22r/8JDE1fIfSDuRIZkYKHtxKEooXrZtZhqsOrzf0tulpGCGcIImCcQ==}
engines: {node: '>=12'}
'@tanstack/store@0.7.0':
@@ -2506,6 +2592,9 @@ packages:
'@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
+ '@types/ws@8.18.1':
+ resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
+
'@types/yauzl@2.10.3':
resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
@@ -6498,6 +6587,9 @@ packages:
zod@3.24.3:
resolution: {integrity: sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==}
+ zod@4.0.14:
+ resolution: {integrity: sha512-nGFJTnJN6cM2v9kXL+SOBq3AtjQby3Mv5ySGFof5UGRHrRioSJ5iG680cYNjE/yWk671nROcpPj4hAS8nyLhSw==}
+
snapshots:
'@adobe/css-tools@4.4.2': {}
@@ -7521,8 +7613,8 @@ snapshots:
'@jridgewell/source-map@0.3.10':
dependencies:
- '@jridgewell/gen-mapping': 0.3.8
- '@jridgewell/trace-mapping': 0.3.25
+ '@jridgewell/gen-mapping': 0.3.12
+ '@jridgewell/trace-mapping': 0.3.29
'@jridgewell/sourcemap-codec@1.5.0': {}
@@ -7671,7 +7763,7 @@ snapshots:
'@netlify/zip-it-and-ship-it@12.2.1(rollup@4.46.2)':
dependencies:
- '@babel/parser': 7.27.0
+ '@babel/parser': 7.28.0
'@babel/types': 7.28.0
'@netlify/binary-info': 1.0.0
'@netlify/serverless-functions-api': 2.1.3
@@ -7909,7 +8001,7 @@ snapshots:
'@rollup/pluginutils': 5.1.4(rollup@4.46.2)
commondir: 1.0.1
estree-walker: 2.0.2
- fdir: 6.4.4(picomatch@4.0.3)
+ fdir: 6.4.6(picomatch@4.0.3)
is-reference: 1.2.1
magic-string: 0.30.17
picomatch: 4.0.3
@@ -8394,13 +8486,13 @@ snapshots:
- csstype
- utf-8-validate
- '@tanstack/directive-functions-plugin@1.129.7(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
+ '@tanstack/directive-functions-plugin@1.130.12(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/core': 7.28.0
'@babel/traverse': 7.28.0
'@babel/types': 7.28.2
- '@tanstack/router-utils': 1.129.7
+ '@tanstack/router-utils': 1.130.12
babel-dead-code-elimination: 1.0.10
tiny-invariant: 1.3.3
vite: 7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
@@ -8428,6 +8520,8 @@ snapshots:
'@tanstack/history@1.129.7': {}
+ '@tanstack/history@1.130.12': {}
+
'@tanstack/publish-config@0.2.0':
dependencies:
'@commitlint/parse': 19.8.1
@@ -8465,10 +8559,10 @@ snapshots:
'@tanstack/query-core': 5.83.0
react: 19.1.0
- '@tanstack/react-router-devtools@1.130.2(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.130.9)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(solid-js@1.9.7)(tiny-invariant@1.3.3)':
+ '@tanstack/react-router-devtools@1.130.2(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.130.12)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(solid-js@1.9.7)(tiny-invariant@1.3.3)':
dependencies:
'@tanstack/react-router': 1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
- '@tanstack/router-devtools-core': 1.130.2(@tanstack/router-core@1.130.9)(csstype@3.1.3)(solid-js@1.9.7)(tiny-invariant@1.3.3)
+ '@tanstack/router-devtools-core': 1.130.2(@tanstack/router-core@1.130.12)(csstype@3.1.3)(solid-js@1.9.7)(tiny-invariant@1.3.3)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
transitivePeerDependencies:
@@ -8477,10 +8571,10 @@ snapshots:
- solid-js
- tiny-invariant
- '@tanstack/react-router-devtools@1.130.2(@tanstack/react-router@1.130.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.130.9)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(solid-js@1.9.7)(tiny-invariant@1.3.3)':
+ '@tanstack/react-router-devtools@1.130.2(@tanstack/react-router@1.130.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.130.12)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(solid-js@1.9.7)(tiny-invariant@1.3.3)':
dependencies:
'@tanstack/react-router': 1.130.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
- '@tanstack/router-devtools-core': 1.130.2(@tanstack/router-core@1.130.9)(csstype@3.1.3)(solid-js@1.9.7)(tiny-invariant@1.3.3)
+ '@tanstack/router-devtools-core': 1.130.2(@tanstack/router-core@1.130.12)(csstype@3.1.3)(solid-js@1.9.7)(tiny-invariant@1.3.3)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
transitivePeerDependencies:
@@ -8489,13 +8583,24 @@ snapshots:
- solid-js
- tiny-invariant
- '@tanstack/react-router-with-query@1.130.9(@tanstack/react-query@5.83.0(react@19.1.0))(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.130.9)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
+ '@tanstack/react-router-with-query@1.130.9(@tanstack/react-query@5.83.0(react@19.1.0))(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.130.12)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@tanstack/react-query': 5.83.0(react@19.1.0)
'@tanstack/react-router': 1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
- '@tanstack/router-core': 1.130.9
+ '@tanstack/router-core': 1.130.12
+ react: 19.1.0
+ react-dom: 19.1.0(react@19.1.0)
+
+ '@tanstack/react-router@1.130.12(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
+ dependencies:
+ '@tanstack/history': 1.130.12
+ '@tanstack/react-store': 0.7.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ '@tanstack/router-core': 1.130.12
+ isbot: 5.1.28
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
+ tiny-invariant: 1.3.3
+ tiny-warning: 1.0.3
'@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
@@ -8519,20 +8624,20 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
- '@tanstack/react-start-client@1.130.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
+ '@tanstack/react-start-client@1.130.12(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
- '@tanstack/react-router': 1.130.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
- '@tanstack/router-core': 1.130.9
- '@tanstack/start-client-core': 1.130.9
+ '@tanstack/react-router': 1.130.12(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ '@tanstack/router-core': 1.130.12
+ '@tanstack/start-client-core': 1.130.12
cookie-es: 1.2.2
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
- '@tanstack/react-start-plugin@1.130.9(@netlify/blobs@9.1.2)(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@vitejs/plugin-react@4.7.0(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
+ '@tanstack/react-start-plugin@1.130.15(@netlify/blobs@9.1.2)(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@vitejs/plugin-react@4.7.0(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
dependencies:
- '@tanstack/start-plugin-core': 1.130.9(@netlify/blobs@9.1.2)(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
+ '@tanstack/start-plugin-core': 1.130.15(@netlify/blobs@9.1.2)(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
'@vitejs/plugin-react': 4.7.0(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
pathe: 2.0.3
vite: 7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
@@ -8569,25 +8674,25 @@ snapshots:
- webpack
- xml2js
- '@tanstack/react-start-server@1.130.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
+ '@tanstack/react-start-server@1.130.12(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
- '@tanstack/history': 1.129.7
- '@tanstack/react-router': 1.130.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
- '@tanstack/router-core': 1.130.9
- '@tanstack/start-client-core': 1.130.9
- '@tanstack/start-server-core': 1.130.9
+ '@tanstack/history': 1.130.12
+ '@tanstack/react-router': 1.130.12(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ '@tanstack/router-core': 1.130.12
+ '@tanstack/start-client-core': 1.130.12
+ '@tanstack/start-server-core': 1.130.12
h3: 1.13.0
isbot: 5.1.28
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
- '@tanstack/react-start@1.130.9(@netlify/blobs@9.1.2)(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@vitejs/plugin-react@4.7.0(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
+ '@tanstack/react-start@1.130.15(@netlify/blobs@9.1.2)(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@vitejs/plugin-react@4.7.0(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
dependencies:
- '@tanstack/react-start-client': 1.130.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
- '@tanstack/react-start-plugin': 1.130.9(@netlify/blobs@9.1.2)(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@vitejs/plugin-react@4.7.0(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
- '@tanstack/react-start-server': 1.130.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
- '@tanstack/start-server-functions-client': 1.130.9(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
- '@tanstack/start-server-functions-server': 1.129.7(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
+ '@tanstack/react-start-client': 1.130.12(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ '@tanstack/react-start-plugin': 1.130.15(@netlify/blobs@9.1.2)(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@vitejs/plugin-react@4.7.0(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
+ '@tanstack/react-start-server': 1.130.12(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ '@tanstack/start-server-functions-client': 1.130.12(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
+ '@tanstack/start-server-functions-server': 1.130.12(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
'@vitejs/plugin-react': 4.7.0(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
@@ -8631,6 +8736,16 @@ snapshots:
react-dom: 19.1.0(react@19.1.0)
use-sync-external-store: 1.5.0(react@19.1.0)
+ '@tanstack/router-core@1.130.12':
+ dependencies:
+ '@tanstack/history': 1.130.12
+ '@tanstack/store': 0.7.2
+ cookie-es: 1.2.2
+ seroval: 1.3.2
+ seroval-plugins: 1.3.2(seroval@1.3.2)
+ tiny-invariant: 1.3.3
+ tiny-warning: 1.0.3
+
'@tanstack/router-core@1.130.2':
dependencies:
'@tanstack/history': 1.129.7
@@ -8651,9 +8766,9 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
- '@tanstack/router-devtools-core@1.130.2(@tanstack/router-core@1.130.9)(csstype@3.1.3)(solid-js@1.9.7)(tiny-invariant@1.3.3)':
+ '@tanstack/router-devtools-core@1.130.2(@tanstack/router-core@1.130.12)(csstype@3.1.3)(solid-js@1.9.7)(tiny-invariant@1.3.3)':
dependencies:
- '@tanstack/router-core': 1.130.9
+ '@tanstack/router-core': 1.130.12
clsx: 2.1.1
goober: 2.1.16(csstype@3.1.3)
solid-js: 1.9.7
@@ -8661,6 +8776,19 @@ snapshots:
optionalDependencies:
csstype: 3.1.3
+ '@tanstack/router-generator@1.130.15':
+ dependencies:
+ '@tanstack/router-core': 1.130.12
+ '@tanstack/router-utils': 1.130.12
+ '@tanstack/virtual-file-routes': 1.129.7
+ prettier: 3.5.3
+ recast: 0.23.11
+ source-map: 0.7.6
+ tsx: 4.20.3
+ zod: 3.24.3
+ transitivePeerDependencies:
+ - supports-color
+
'@tanstack/router-generator@1.130.9':
dependencies:
'@tanstack/router-core': 1.130.9
@@ -8674,6 +8802,29 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@tanstack/router-plugin@1.130.15(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
+ dependencies:
+ '@babel/core': 7.28.0
+ '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.0)
+ '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.0)
+ '@babel/template': 7.27.2
+ '@babel/traverse': 7.28.0
+ '@babel/types': 7.28.2
+ '@tanstack/router-core': 1.130.12
+ '@tanstack/router-generator': 1.130.15
+ '@tanstack/router-utils': 1.130.12
+ '@tanstack/virtual-file-routes': 1.129.7
+ babel-dead-code-elimination: 1.0.10
+ chokidar: 3.6.0
+ unplugin: 2.3.5
+ zod: 3.24.3
+ optionalDependencies:
+ '@tanstack/react-router': 1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ vite: 7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
+ vite-plugin-solid: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
+ transitivePeerDependencies:
+ - supports-color
+
'@tanstack/router-plugin@1.130.9(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
dependencies:
'@babel/core': 7.28.0
@@ -8708,7 +8859,18 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@tanstack/server-functions-plugin@1.129.7(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
+ '@tanstack/router-utils@1.130.12':
+ dependencies:
+ '@babel/core': 7.28.0
+ '@babel/generator': 7.28.0
+ '@babel/parser': 7.28.0
+ '@babel/preset-typescript': 7.27.1(@babel/core@7.28.0)
+ ansis: 4.1.0
+ diff: 8.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@tanstack/server-functions-plugin@1.130.12(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/core': 7.28.0
@@ -8717,7 +8879,7 @@ snapshots:
'@babel/template': 7.27.2
'@babel/traverse': 7.28.0
'@babel/types': 7.28.2
- '@tanstack/directive-functions-plugin': 1.129.7(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
+ '@tanstack/directive-functions-plugin': 1.130.12(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
babel-dead-code-elimination: 1.0.10
tiny-invariant: 1.3.3
transitivePeerDependencies:
@@ -8735,9 +8897,9 @@ snapshots:
'@tanstack/query-core': 5.83.0
solid-js: 1.9.7
- '@tanstack/solid-router-devtools@1.130.2(@tanstack/router-core@1.130.9)(@tanstack/solid-router@1.130.2(solid-js@1.9.7))(csstype@3.1.3)(solid-js@1.9.7)(tiny-invariant@1.3.3)':
+ '@tanstack/solid-router-devtools@1.130.2(@tanstack/router-core@1.130.12)(@tanstack/solid-router@1.130.2(solid-js@1.9.7))(csstype@3.1.3)(solid-js@1.9.7)(tiny-invariant@1.3.3)':
dependencies:
- '@tanstack/router-devtools-core': 1.130.2(@tanstack/router-core@1.130.9)(csstype@3.1.3)(solid-js@1.9.7)(tiny-invariant@1.3.3)
+ '@tanstack/router-devtools-core': 1.130.2(@tanstack/router-core@1.130.12)(csstype@3.1.3)(solid-js@1.9.7)(tiny-invariant@1.3.3)
'@tanstack/solid-router': 1.130.2(solid-js@1.9.7)
solid-js: 1.9.7
transitivePeerDependencies:
@@ -8763,25 +8925,25 @@ snapshots:
'@tanstack/store': 0.7.0
solid-js: 1.9.7
- '@tanstack/start-client-core@1.130.9':
+ '@tanstack/start-client-core@1.130.12':
dependencies:
- '@tanstack/router-core': 1.130.9
- '@tanstack/start-storage-context': 1.130.9
+ '@tanstack/router-core': 1.130.12
+ '@tanstack/start-storage-context': 1.130.12
cookie-es: 1.2.2
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
- '@tanstack/start-plugin-core@1.130.9(@netlify/blobs@9.1.2)(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
+ '@tanstack/start-plugin-core@1.130.15(@netlify/blobs@9.1.2)(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
dependencies:
'@babel/code-frame': 7.26.2
'@babel/core': 7.28.0
- '@babel/types': 7.27.0
- '@tanstack/router-core': 1.130.9
- '@tanstack/router-generator': 1.130.9
- '@tanstack/router-plugin': 1.130.9(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
- '@tanstack/router-utils': 1.129.7
- '@tanstack/server-functions-plugin': 1.129.7(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
- '@tanstack/start-server-core': 1.130.9
+ '@babel/types': 7.28.2
+ '@tanstack/router-core': 1.130.12
+ '@tanstack/router-generator': 1.130.15
+ '@tanstack/router-plugin': 1.130.15(@tanstack/react-router@1.130.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite-plugin-solid@2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.7)(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
+ '@tanstack/router-utils': 1.130.12
+ '@tanstack/server-functions-plugin': 1.130.12(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
+ '@tanstack/start-server-core': 1.130.12
'@types/babel__code-frame': 7.0.6
'@types/babel__core': 7.20.5
babel-dead-code-elimination: 1.0.10
@@ -8826,42 +8988,42 @@ snapshots:
- webpack
- xml2js
- '@tanstack/start-server-core@1.130.9':
+ '@tanstack/start-server-core@1.130.12':
dependencies:
- '@tanstack/history': 1.129.7
- '@tanstack/router-core': 1.130.9
- '@tanstack/start-client-core': 1.130.9
- '@tanstack/start-storage-context': 1.130.9
+ '@tanstack/history': 1.130.12
+ '@tanstack/router-core': 1.130.12
+ '@tanstack/start-client-core': 1.130.12
+ '@tanstack/start-storage-context': 1.130.12
h3: 1.13.0
isbot: 5.1.28
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
unctx: 2.4.1
- '@tanstack/start-server-functions-client@1.130.9(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
+ '@tanstack/start-server-functions-client@1.130.12(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
dependencies:
- '@tanstack/server-functions-plugin': 1.129.7(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
- '@tanstack/start-server-functions-fetcher': 1.130.9
+ '@tanstack/server-functions-plugin': 1.130.12(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
+ '@tanstack/start-server-functions-fetcher': 1.130.12
transitivePeerDependencies:
- supports-color
- vite
- '@tanstack/start-server-functions-fetcher@1.130.9':
+ '@tanstack/start-server-functions-fetcher@1.130.12':
dependencies:
- '@tanstack/router-core': 1.130.9
- '@tanstack/start-client-core': 1.130.9
+ '@tanstack/router-core': 1.130.12
+ '@tanstack/start-client-core': 1.130.12
- '@tanstack/start-server-functions-server@1.129.7(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
+ '@tanstack/start-server-functions-server@1.130.12(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
dependencies:
- '@tanstack/server-functions-plugin': 1.129.7(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
+ '@tanstack/server-functions-plugin': 1.130.12(vite@7.0.6(@types/node@22.15.2)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
tiny-invariant: 1.3.3
transitivePeerDependencies:
- supports-color
- vite
- '@tanstack/start-storage-context@1.130.9':
+ '@tanstack/start-storage-context@1.130.12':
dependencies:
- '@tanstack/router-core': 1.130.9
+ '@tanstack/router-core': 1.130.12
'@tanstack/store@0.7.0': {}
@@ -8993,6 +9155,10 @@ snapshots:
'@types/unist@3.0.3': {}
+ '@types/ws@8.18.1':
+ dependencies:
+ '@types/node': 22.15.2
+
'@types/yauzl@2.10.3':
dependencies:
'@types/node': 22.15.2
@@ -9993,7 +10159,7 @@ snapshots:
detective-typescript@14.0.0(typescript@5.8.3):
dependencies:
- '@typescript-eslint/typescript-estree': 8.31.0(typescript@5.8.3)
+ '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.8.3)
ast-module-types: 6.0.1
node-source-walk: 7.0.1
typescript: 5.8.3
@@ -10591,7 +10757,7 @@ snapshots:
extract-zip@2.0.1:
dependencies:
- debug: 4.4.0
+ debug: 4.4.1
get-stream: 5.2.0
yauzl: 2.10.0
optionalDependencies:
@@ -10631,10 +10797,6 @@ snapshots:
optionalDependencies:
picomatch: 4.0.2
- fdir@6.4.4(picomatch@4.0.3):
- optionalDependencies:
- picomatch: 4.0.3
-
fdir@6.4.6(picomatch@4.0.3):
optionalDependencies:
picomatch: 4.0.3
@@ -10976,7 +11138,7 @@ snapshots:
dependencies:
'@ioredis/commands': 1.3.0
cluster-key-slot: 1.1.2
- debug: 4.4.0
+ debug: 4.4.1
denque: 2.1.0
lodash.defaults: 4.2.0
lodash.isarguments: 3.1.0
@@ -11226,7 +11388,7 @@ snapshots:
lambda-local@2.2.0:
dependencies:
commander: 10.0.1
- dotenv: 16.5.0
+ dotenv: 16.6.1
winston: 3.17.0
lazystream@1.0.1:
@@ -11303,7 +11465,7 @@ snapshots:
get-port-please: 3.2.0
h3: 1.15.4
http-shutdown: 1.2.2
- jiti: 2.4.2
+ jiti: 2.5.1
mlly: 1.7.4
node-forge: 1.3.1
pathe: 1.1.2
@@ -11389,8 +11551,8 @@ snapshots:
magicast@0.3.5:
dependencies:
- '@babel/parser': 7.27.0
- '@babel/types': 7.27.0
+ '@babel/parser': 7.28.0
+ '@babel/types': 7.28.2
source-map-js: 1.2.1
markdown-it@14.1.0:
@@ -11558,7 +11720,7 @@ snapshots:
hookable: 5.5.3
httpxy: 0.1.7
ioredis: 5.6.1
- jiti: 2.4.2
+ jiti: 2.5.1
klona: 2.0.6
knitwork: 1.2.0
listhen: 1.9.0
@@ -11650,7 +11812,7 @@ snapshots:
node-source-walk@7.0.1:
dependencies:
- '@babel/parser': 7.27.0
+ '@babel/parser': 7.28.0
nopt@8.1.0:
dependencies:
@@ -11862,7 +12024,7 @@ snapshots:
parse-json@8.3.0:
dependencies:
- '@babel/code-frame': 7.26.2
+ '@babel/code-frame': 7.27.1
index-to-position: 1.1.0
type-fest: 4.41.0
@@ -12295,7 +12457,7 @@ snapshots:
send@1.2.0:
dependencies:
- debug: 4.4.0
+ debug: 4.4.1
encodeurl: 2.0.0
escape-html: 1.0.3
etag: 1.8.1
@@ -12769,7 +12931,7 @@ snapshots:
unctx@2.4.1:
dependencies:
- acorn: 8.14.1
+ acorn: 8.15.0
estree-walker: 3.0.3
magic-string: 0.30.17
unplugin: 2.3.5
@@ -12888,7 +13050,7 @@ snapshots:
dependencies:
citty: 0.1.6
defu: 6.1.4
- jiti: 2.4.2
+ jiti: 2.5.1
knitwork: 1.2.0
scule: 1.3.0
@@ -13261,3 +13423,5 @@ snapshots:
zod: 3.24.3
zod@3.24.3: {}
+
+ zod@4.0.14: {}