@tanstack/devtools-vite 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,6 +22,8 @@ const devtools = (args) => {
22
22
  const consolePipingLevels = consolePipingConfig.levels ?? ["log", "warn", "error", "info", "debug"];
23
23
  let devtoolsFileId = null;
24
24
  let devtoolsPort = null;
25
+ let devtoolsHost = null;
26
+ let devtoolsProtocol = null;
25
27
  return [
26
28
  {
27
29
  enforce: "pre",
@@ -29,10 +31,15 @@ const devtools = (args) => {
29
31
  apply(config) {
30
32
  return config.mode === "development" && injectSourceConfig.enabled;
31
33
  },
32
- transform(code, id) {
33
- if (id.includes("node_modules") || id.includes("?raw") || id.includes("dist") || id.includes("build"))
34
- return;
35
- return addSourceToJsx(code, id, args?.injectSource?.ignore);
34
+ transform: {
35
+ filter: {
36
+ id: {
37
+ exclude: [/node_modules/, /\?raw/, /\/dist\//, /\/build\//]
38
+ }
39
+ },
40
+ handler(code, id) {
41
+ return addSourceToJsx(code, id, args?.injectSource?.ignore);
42
+ }
36
43
  }
37
44
  },
38
45
  {
@@ -53,9 +60,17 @@ const devtools = (args) => {
53
60
  async configureServer(server) {
54
61
  if (serverBusEnabled) {
55
62
  const preferredPort = args?.eventBusConfig?.port ?? 4206;
63
+ const isHttps = !!server.config.server.https;
64
+ const serverHost = typeof server.config.server.host === "string" ? server.config.server.host : "localhost";
65
+ devtoolsProtocol = isHttps ? "https" : "http";
66
+ devtoolsHost = serverHost;
56
67
  const bus = new ServerEventBus({
57
68
  ...args?.eventBusConfig,
58
- port: preferredPort
69
+ port: preferredPort,
70
+ host: serverHost,
71
+ // When HTTPS is enabled, piggyback on Vite's server
72
+ // so WebSocket/SSE connections share the same TLS certificate
73
+ ...isHttps && server.httpServer ? { httpServer: server.httpServer } : {}
59
74
  });
60
75
  devtoolsPort = await bus.start();
61
76
  }
@@ -342,24 +357,30 @@ ${chalk.greenBright(`[@tanstack/devtools-vite]`)} Removed devtools code from: ${
342
357
  apply(config, { command }) {
343
358
  return config.mode === "development" && command === "serve" && (consolePipingConfig.enabled ?? true);
344
359
  },
345
- transform(code, id) {
346
- if (id.includes("node_modules") || id.includes("dist") || id.includes("?") || !id.match(/\.(tsx?|jsx?)$/)) {
347
- return;
348
- }
349
- if (code.includes("__tsdConsolePipe")) {
350
- return;
351
- }
352
- const isRootEntry = /<html[\s>]/i.test(code) || code.includes("StartClient") || code.includes("hydrateRoot") || code.includes("createRoot") || code.includes("solid-js/web") && code.includes("render(");
353
- if (isRootEntry) {
354
- const viteServerUrl = `http://localhost:${port}`;
355
- const inlineCode = generateConsolePipeCode(
356
- consolePipingLevels,
357
- viteServerUrl
358
- );
359
- return `${inlineCode}
360
+ transform: {
361
+ filter: {
362
+ id: {
363
+ include: /\.(tsx?|jsx?)$/,
364
+ exclude: [/node_modules/, /\/dist\//, /\?/]
365
+ },
366
+ code: {
367
+ exclude: /__tsdConsolePipe/
368
+ // avoid transforming files that already contain the console pipe code
369
+ }
370
+ },
371
+ handler(code) {
372
+ const isRootEntry = /<html[\s>]/i.test(code) || code.includes("StartClient") || code.includes("hydrateRoot") || code.includes("createRoot") || code.includes("solid-js/web") && code.includes("render(");
373
+ if (isRootEntry) {
374
+ const viteServerUrl = `http://localhost:${port}`;
375
+ const inlineCode = generateConsolePipeCode(
376
+ consolePipingLevels,
377
+ viteServerUrl
378
+ );
379
+ return `${inlineCode}
360
380
  ${code}`;
381
+ }
382
+ return void 0;
361
383
  }
362
- return void 0;
363
384
  }
364
385
  },
365
386
  {
@@ -368,10 +389,18 @@ ${code}`;
368
389
  apply(config) {
369
390
  return config.mode === "development" && enhancedLogsConfig.enabled;
370
391
  },
371
- transform(code, id) {
372
- if (id.includes("node_modules") || id.includes("?raw") || id.includes("dist") || id.includes("build") || !code.includes("console."))
373
- return;
374
- return enhanceConsoleLog(code, id, port);
392
+ transform: {
393
+ filter: {
394
+ id: {
395
+ exclude: [/node_modules/, /\?raw/, /\/dist\//, /\/build\//]
396
+ },
397
+ code: {
398
+ include: "console."
399
+ }
400
+ },
401
+ handler(code, id) {
402
+ return enhanceConsoleLog(code, id, port);
403
+ }
375
404
  }
376
405
  },
377
406
  {
@@ -390,16 +419,32 @@ ${code}`;
390
419
  }
391
420
  },
392
421
  {
393
- name: "@tanstack/devtools:port-injection",
422
+ name: "@tanstack/devtools:connection-injection",
394
423
  apply(config, { command }) {
395
424
  return config.mode === "development" && command === "serve";
396
425
  },
397
426
  transform(code, id) {
398
- if (!code.includes("__TANSTACK_DEVTOOLS_PORT__")) return;
427
+ const hasPlaceholder = code.includes("__TANSTACK_DEVTOOLS_PORT__") || code.includes("__TANSTACK_DEVTOOLS_HOST__") || code.includes("__TANSTACK_DEVTOOLS_PROTOCOL__");
428
+ if (!hasPlaceholder) return;
399
429
  if (!id.includes("@tanstack/devtools") && !id.includes("@tanstack/event-bus"))
400
430
  return;
401
431
  const portValue = devtoolsPort ?? 4206;
402
- return code.replace(/__TANSTACK_DEVTOOLS_PORT__/g, String(portValue));
432
+ const hostValue = devtoolsHost ?? "localhost";
433
+ const protocolValue = devtoolsProtocol ?? "http";
434
+ let result = code;
435
+ result = result.replace(
436
+ /__TANSTACK_DEVTOOLS_PORT__/g,
437
+ String(portValue)
438
+ );
439
+ result = result.replace(
440
+ /__TANSTACK_DEVTOOLS_HOST__/g,
441
+ JSON.stringify(hostValue)
442
+ );
443
+ result = result.replace(
444
+ /__TANSTACK_DEVTOOLS_PROTOCOL__/g,
445
+ JSON.stringify(protocolValue)
446
+ );
447
+ return result;
403
448
  }
404
449
  }
405
450
  ];
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["../../src/plugin.ts"],"sourcesContent":["import { devtoolsEventClient } from '@tanstack/devtools-client'\nimport { ServerEventBus } from '@tanstack/devtools-event-bus/server'\nimport { normalizePath } from 'vite'\nimport chalk from 'chalk'\nimport {\n handleDevToolsViteRequest,\n readPackageJson,\n stripEnhancedLogPrefix,\n} from './utils'\nimport { DEFAULT_EDITOR_CONFIG, handleOpenSource } from './editor'\nimport { removeDevtools } from './remove-devtools'\nimport { addSourceToJsx } from './inject-source'\nimport { enhanceConsoleLog } from './enhance-logs'\nimport { detectDevtoolsFile, injectPluginIntoFile } from './inject-plugin'\nimport {\n addPluginToDevtools,\n emitOutdatedDeps,\n installPackage,\n} from './package-manager'\nimport { generateConsolePipeCode } from './virtual-console'\nimport type { ServerResponse } from 'node:http'\nimport type { Plugin } from 'vite'\nimport type { EditorConfig } from './editor'\nimport type { ServerEventBusConfig } from '@tanstack/devtools-event-bus/server'\n\nexport type ConsoleLevel = 'log' | 'warn' | 'error' | 'info' | 'debug'\n\nexport type TanStackDevtoolsViteConfig = {\n /**\n * Configuration for the editor integration. Defaults to opening in VS code\n */\n editor?: EditorConfig\n /**\n * The configuration options for the server event bus\n */\n eventBusConfig?: ServerEventBusConfig & {\n /**\n * Should the server event bus be enabled or not\n * @default true\n */\n enabled?: boolean // defaults to true\n }\n /**\n * Configuration for enhanced logging.\n */\n enhancedLogs?: {\n /**\n * Whether to enable enhanced logging.\n * @default true\n */\n enabled: boolean\n }\n /**\n * Whether to remove devtools from the production build.\n * @default true\n */\n removeDevtoolsOnBuild?: boolean\n\n /**\n * Whether to log information to the console.\n * @default true\n */\n logging?: boolean\n /**\n * Configuration for source injection.\n */\n injectSource?: {\n /**\n * Whether to enable source injection via data-tsd-source.\n * @default true\n */\n enabled: boolean\n /**\n * List of files or patterns to ignore for source injection.\n */\n ignore?: {\n files?: Array<string | RegExp>\n components?: Array<string | RegExp>\n }\n }\n /**\n * Configuration for console piping between client and server.\n * When enabled, console logs from the client will appear in the terminal,\n * and server logs will appear in the browser console.\n */\n consolePiping?: {\n /**\n * Whether to enable console piping.\n * @default true\n */\n enabled?: boolean\n /**\n * Which console methods to pipe.\n * @default ['log', 'warn', 'error', 'info', 'debug']\n */\n levels?: Array<ConsoleLevel>\n }\n}\n\nexport const defineDevtoolsConfig = (config: TanStackDevtoolsViteConfig) =>\n config\n\nexport const devtools = (args?: TanStackDevtoolsViteConfig): Array<Plugin> => {\n let port = 5173\n const logging = args?.logging ?? true\n const enhancedLogsConfig = args?.enhancedLogs ?? { enabled: true }\n const injectSourceConfig = args?.injectSource ?? { enabled: true }\n const removeDevtoolsOnBuild = args?.removeDevtoolsOnBuild ?? true\n const serverBusEnabled = args?.eventBusConfig?.enabled ?? true\n const consolePipingConfig = args?.consolePiping ?? { enabled: true }\n const consolePipingLevels: Array<ConsoleLevel> =\n consolePipingConfig.levels ?? ['log', 'warn', 'error', 'info', 'debug']\n\n let devtoolsFileId: string | null = null\n let devtoolsPort: number | null = null\n\n return [\n {\n enforce: 'pre',\n name: '@tanstack/devtools:inject-source',\n apply(config) {\n return config.mode === 'development' && injectSourceConfig.enabled\n },\n transform(code, id) {\n if (\n id.includes('node_modules') ||\n id.includes('?raw') ||\n id.includes('dist') ||\n id.includes('build')\n )\n return\n\n return addSourceToJsx(code, id, args?.injectSource?.ignore)\n },\n },\n {\n name: '@tanstack/devtools:config',\n enforce: 'pre',\n config(_, { command }) {\n // we do not apply any config changes for build\n if (command !== 'serve') {\n return\n }\n\n /* const solidDedupeDeps = [\n 'solid-js',\n 'solid-js/web',\n 'solid-js/store',\n 'solid-js/html',\n 'solid-js/h',\n ]\n\n return {\n resolve: {\n dedupe: solidDedupeDeps,\n },\n optimizeDeps: {\n include: solidDedupeDeps,\n },\n } */\n },\n },\n {\n enforce: 'pre',\n name: '@tanstack/devtools:custom-server',\n apply(config) {\n // Custom server is only needed in development for piping events to the client\n return config.mode === 'development'\n },\n async configureServer(server) {\n if (serverBusEnabled) {\n const preferredPort = args?.eventBusConfig?.port ?? 4206\n const bus = new ServerEventBus({\n ...args?.eventBusConfig,\n port: preferredPort,\n })\n // start() now handles EADDRINUSE and returns the actual port\n devtoolsPort = await bus.start()\n }\n\n server.middlewares.use((req, _res, next) => {\n if (req.socket.localPort && req.socket.localPort !== port) {\n port = req.socket.localPort\n }\n next()\n })\n if (server.config.server.port) {\n port = server.config.server.port\n }\n\n server.httpServer?.on('listening', () => {\n port = server.config.server.port\n })\n\n const editor = args?.editor ?? DEFAULT_EDITOR_CONFIG\n const openInEditor: EditorConfig['open'] = async (\n path,\n lineNum,\n columnNum,\n ) => {\n if (!path) {\n return\n }\n await editor.open(path, lineNum, columnNum)\n }\n\n // SSE clients for broadcasting server logs to browser\n const sseClients: Array<{\n res: ServerResponse\n id: number\n }> = []\n let sseClientId = 0\n const consolePipingEnabled = consolePipingConfig.enabled ?? true\n\n server.middlewares.use((req, res, next) =>\n handleDevToolsViteRequest(req, res, next, {\n onOpenSource: (parsedData) => {\n const { data, routine } = parsedData\n if (routine === 'open-source') {\n return handleOpenSource({\n data: { type: data.type, data },\n openInEditor,\n })\n }\n return\n },\n ...(consolePipingEnabled\n ? {\n onConsolePipe: (entries) => {\n for (const entry of entries) {\n const prefix = chalk.cyan('[Client]')\n const logMethod = console[entry.level as ConsoleLevel]\n const cleanedArgs = stripEnhancedLogPrefix(\n entry.args,\n (loc) => chalk.gray(loc),\n )\n logMethod(prefix, ...cleanedArgs)\n }\n },\n onConsolePipeSSE: (res, req) => {\n res.setHeader('Content-Type', 'text/event-stream')\n res.setHeader('Cache-Control', 'no-cache')\n res.setHeader('Connection', 'keep-alive')\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.flushHeaders()\n\n const clientId = ++sseClientId\n sseClients.push({ res, id: clientId })\n\n req.on('close', () => {\n const index = sseClients.findIndex(\n (c) => c.id === clientId,\n )\n if (index !== -1) {\n sseClients.splice(index, 1)\n }\n })\n },\n onServerConsolePipe: (entries) => {\n try {\n const data = JSON.stringify({\n entries: entries.map((e) => ({\n level: e.level,\n args: e.args,\n source: 'server',\n timestamp: e.timestamp || Date.now(),\n })),\n })\n\n for (const client of sseClients) {\n client.res.write(`data: ${data}\\n\\n`)\n }\n } catch {}\n },\n }\n : {}),\n }),\n )\n },\n },\n {\n name: '@tanstack/devtools:remove-devtools-on-build',\n apply(config, { command }) {\n // Check both command and mode to support various hosting providers\n // Some providers (Cloudflare, Netlify, Heroku) might not use 'build' command\n // but will always set mode to 'production' for production builds\n return (\n (command !== 'serve' || config.mode === 'production') &&\n removeDevtoolsOnBuild\n )\n },\n enforce: 'pre',\n transform(code, id) {\n const devtoolPackages = [\n '@tanstack/react-devtools',\n '@tanstack/preact-devtools',\n '@tanstack/solid-devtools',\n '@tanstack/vue-devtools',\n '@tanstack/devtools',\n ]\n if (\n id.includes('node_modules') ||\n id.includes('?raw') ||\n !devtoolPackages.some((pkg) => code.includes(pkg))\n )\n return\n const transform = removeDevtools(code, id)\n if (!transform) return\n if (logging) {\n console.log(\n `\\n${chalk.greenBright(`[@tanstack/devtools-vite]`)} Removed devtools code from: ${id.replace(normalizePath(process.cwd()), '')}\\n`,\n )\n }\n return transform\n },\n },\n {\n name: '@tanstack/devtools:event-client-setup',\n apply(config, { command }) {\n if (\n process.env.CI ||\n process.env.NODE_ENV !== 'development' ||\n command !== 'serve'\n )\n return false\n return config.mode === 'development'\n },\n async configureServer() {\n const packageJson = await readPackageJson()\n const outdatedDeps = emitOutdatedDeps().then((deps) => deps)\n\n // Listen for package installation requests\n devtoolsEventClient.on('install-devtools', async (event) => {\n const result = await installPackage(event.payload.packageName)\n devtoolsEventClient.emit('devtools-installed', {\n packageName: event.payload.packageName,\n success: result.success,\n error: result.error,\n })\n\n // If installation was successful, automatically add the plugin to devtools\n if (result.success) {\n const { packageName, pluginName, pluginImport } = event.payload\n\n console.log(\n chalk.blueBright(\n `[@tanstack/devtools-vite] Auto-adding ${packageName} to devtools...`,\n ),\n )\n\n const injectResult = addPluginToDevtools(\n devtoolsFileId,\n packageName,\n pluginName,\n pluginImport,\n )\n\n if (injectResult.success) {\n // Emit plugin-added event so the UI updates\n devtoolsEventClient.emit('plugin-added', {\n packageName,\n success: true,\n })\n\n // Also re-read package.json to update the UI with the newly installed package\n const updatedPackageJson = await readPackageJson()\n devtoolsEventClient.emit('package-json-read', {\n packageJson: updatedPackageJson,\n })\n }\n }\n })\n\n // Listen for add plugin to devtools requests\n devtoolsEventClient.on('add-plugin-to-devtools', (event) => {\n const { packageName, pluginName, pluginImport } = event.payload\n\n console.log(\n chalk.blueBright(\n `[@tanstack/devtools-vite] Adding ${packageName} to devtools...`,\n ),\n )\n\n const result = addPluginToDevtools(\n devtoolsFileId,\n packageName,\n pluginName,\n pluginImport,\n )\n\n devtoolsEventClient.emit('plugin-added', {\n packageName,\n success: result.success,\n error: result.error,\n })\n })\n\n // Handle bump-package-version event\n devtoolsEventClient.on('bump-package-version', async (event) => {\n const {\n packageName,\n devtoolsPackage,\n pluginName,\n minVersion,\n pluginImport,\n } = event.payload\n\n console.log(\n chalk.blueBright(\n `[@tanstack/devtools-vite] Bumping ${packageName} to version ${minVersion}...`,\n ),\n )\n\n // Install the package with the minimum version\n const packageWithVersion = minVersion\n ? `${packageName}@^${minVersion}`\n : packageName\n\n const result = await installPackage(packageWithVersion)\n\n if (!result.success) {\n console.log(\n chalk.redBright(\n `[@tanstack/devtools-vite] Failed to bump ${packageName}: ${result.error}`,\n ),\n )\n devtoolsEventClient.emit('devtools-installed', {\n packageName: devtoolsPackage,\n success: false,\n error: result.error,\n })\n return\n }\n\n console.log(\n chalk.greenBright(\n `[@tanstack/devtools-vite] Successfully bumped ${packageName} to ${minVersion}!`,\n ),\n )\n\n // Check if we found the devtools file\n if (!devtoolsFileId) {\n console.log(\n chalk.yellowBright(\n `[@tanstack/devtools-vite] Devtools file not found. Skipping auto-injection.`,\n ),\n )\n devtoolsEventClient.emit('devtools-installed', {\n packageName: devtoolsPackage,\n success: true,\n })\n return\n }\n\n // Now inject the devtools plugin\n console.log(\n chalk.blueBright(\n `[@tanstack/devtools-vite] Adding ${devtoolsPackage} to devtools...`,\n ),\n )\n\n const injectResult = injectPluginIntoFile(devtoolsFileId, {\n packageName: devtoolsPackage,\n pluginName,\n pluginImport,\n })\n\n if (injectResult.success) {\n console.log(\n chalk.greenBright(\n `[@tanstack/devtools-vite] Successfully added ${devtoolsPackage} to devtools!`,\n ),\n )\n\n devtoolsEventClient.emit('plugin-added', {\n packageName: devtoolsPackage,\n success: true,\n })\n\n // Re-read package.json to update the UI\n const updatedPackageJson = await readPackageJson()\n devtoolsEventClient.emit('package-json-read', {\n packageJson: updatedPackageJson,\n })\n } else {\n console.log(\n chalk.redBright(\n `[@tanstack/devtools-vite] Failed to add ${devtoolsPackage} to devtools: ${injectResult.error}`,\n ),\n )\n\n devtoolsEventClient.emit('plugin-added', {\n packageName: devtoolsPackage,\n success: false,\n error: injectResult.error,\n })\n }\n })\n\n // whenever a client mounts we send all the current info to the subscribers\n devtoolsEventClient.on('mounted', async () => {\n devtoolsEventClient.emit('outdated-deps-read', {\n outdatedDeps: await outdatedDeps,\n })\n devtoolsEventClient.emit('package-json-read', {\n packageJson,\n })\n })\n\n // Console piping is now handled via HTTP endpoints in the custom-server plugin\n },\n async handleHotUpdate({ file }) {\n if (file.endsWith('package.json')) {\n const newPackageJson = await readPackageJson()\n devtoolsEventClient.emit('package-json-read', {\n packageJson: newPackageJson,\n })\n emitOutdatedDeps()\n }\n },\n },\n // Inject console piping code into entry files (both client and server)\n {\n name: '@tanstack/devtools:console-pipe-transform',\n enforce: 'pre',\n apply(config, { command }) {\n return (\n config.mode === 'development' &&\n command === 'serve' &&\n (consolePipingConfig.enabled ?? true)\n )\n },\n transform(code, id) {\n // Inject the console pipe code into entry files\n if (\n id.includes('node_modules') ||\n id.includes('dist') ||\n id.includes('?') ||\n !id.match(/\\.(tsx?|jsx?)$/)\n ) {\n return\n }\n\n // Only inject once - check if already injected\n if (code.includes('__tsdConsolePipe')) {\n return\n }\n\n // Check if this is a root entry file (with <html> JSX or client entry points)\n // In SSR frameworks, this file runs on BOTH server (SSR) and client (hydration)\n // so our runtime check (typeof window === 'undefined') handles both environments\n const isRootEntry =\n /<html[\\s>]/i.test(code) ||\n code.includes('StartClient') ||\n code.includes('hydrateRoot') ||\n code.includes('createRoot') ||\n (code.includes('solid-js/web') && code.includes('render('))\n\n if (isRootEntry) {\n const viteServerUrl = `http://localhost:${port}`\n const inlineCode = generateConsolePipeCode(\n consolePipingLevels,\n viteServerUrl,\n )\n\n return `${inlineCode}\\n${code}`\n }\n\n return undefined\n },\n },\n {\n name: '@tanstack/devtools:better-console-logs',\n enforce: 'pre',\n apply(config) {\n return config.mode === 'development' && enhancedLogsConfig.enabled\n },\n transform(code, id) {\n // Ignore anything external\n if (\n id.includes('node_modules') ||\n id.includes('?raw') ||\n id.includes('dist') ||\n id.includes('build') ||\n !code.includes('console.')\n )\n return\n\n return enhanceConsoleLog(code, id, port)\n },\n },\n {\n name: '@tanstack/devtools:inject-plugin',\n apply(config, { command }) {\n return config.mode === 'development' && command === 'serve'\n },\n transform(code, id) {\n // First pass: find where TanStackDevtools is imported\n if (!devtoolsFileId && detectDevtoolsFile(code)) {\n // Extract actual file path (remove query params)\n const [filePath] = id.split('?')\n if (filePath) {\n devtoolsFileId = filePath\n }\n }\n\n return undefined\n },\n },\n {\n name: '@tanstack/devtools:port-injection',\n apply(config, { command }) {\n return config.mode === 'development' && command === 'serve'\n },\n transform(code, id) {\n // Only transform @tanstack packages that contain the port placeholder\n if (!code.includes('__TANSTACK_DEVTOOLS_PORT__')) return\n if (\n !id.includes('@tanstack/devtools') &&\n !id.includes('@tanstack/event-bus')\n )\n return\n\n // Replace placeholder with actual port (or fallback to 4206 if not resolved yet)\n const portValue = devtoolsPort ?? 4206\n return code.replace(/__TANSTACK_DEVTOOLS_PORT__/g, String(portValue))\n },\n },\n ]\n}\n"],"names":["res","req"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sources":["../../src/plugin.ts"],"sourcesContent":["import { devtoolsEventClient } from '@tanstack/devtools-client'\nimport { ServerEventBus } from '@tanstack/devtools-event-bus/server'\nimport { normalizePath } from 'vite'\nimport chalk from 'chalk'\nimport {\n handleDevToolsViteRequest,\n readPackageJson,\n stripEnhancedLogPrefix,\n} from './utils'\nimport { DEFAULT_EDITOR_CONFIG, handleOpenSource } from './editor'\nimport { removeDevtools } from './remove-devtools'\nimport { addSourceToJsx } from './inject-source'\nimport { enhanceConsoleLog } from './enhance-logs'\nimport { detectDevtoolsFile, injectPluginIntoFile } from './inject-plugin'\nimport {\n addPluginToDevtools,\n emitOutdatedDeps,\n installPackage,\n} from './package-manager'\nimport { generateConsolePipeCode } from './virtual-console'\nimport type { ServerResponse } from 'node:http'\nimport type { Plugin } from 'vite'\nimport type { EditorConfig } from './editor'\nimport type {\n HttpServerLike,\n ServerEventBusConfig,\n} from '@tanstack/devtools-event-bus/server'\n\nexport type ConsoleLevel = 'log' | 'warn' | 'error' | 'info' | 'debug'\n\nexport type TanStackDevtoolsViteConfig = {\n /**\n * Configuration for the editor integration. Defaults to opening in VS code\n */\n editor?: EditorConfig\n /**\n * The configuration options for the server event bus\n */\n eventBusConfig?: ServerEventBusConfig & {\n /**\n * Should the server event bus be enabled or not\n * @default true\n */\n enabled?: boolean // defaults to true\n }\n /**\n * Configuration for enhanced logging.\n */\n enhancedLogs?: {\n /**\n * Whether to enable enhanced logging.\n * @default true\n */\n enabled: boolean\n }\n /**\n * Whether to remove devtools from the production build.\n * @default true\n */\n removeDevtoolsOnBuild?: boolean\n\n /**\n * Whether to log information to the console.\n * @default true\n */\n logging?: boolean\n /**\n * Configuration for source injection.\n */\n injectSource?: {\n /**\n * Whether to enable source injection via data-tsd-source.\n * @default true\n */\n enabled: boolean\n /**\n * List of files or patterns to ignore for source injection.\n */\n ignore?: {\n files?: Array<string | RegExp>\n components?: Array<string | RegExp>\n }\n }\n /**\n * Configuration for console piping between client and server.\n * When enabled, console logs from the client will appear in the terminal,\n * and server logs will appear in the browser console.\n */\n consolePiping?: {\n /**\n * Whether to enable console piping.\n * @default true\n */\n enabled?: boolean\n /**\n * Which console methods to pipe.\n * @default ['log', 'warn', 'error', 'info', 'debug']\n */\n levels?: Array<ConsoleLevel>\n }\n}\n\nexport const defineDevtoolsConfig = (config: TanStackDevtoolsViteConfig) =>\n config\n\nexport const devtools = (args?: TanStackDevtoolsViteConfig): Array<Plugin> => {\n let port = 5173\n const logging = args?.logging ?? true\n const enhancedLogsConfig = args?.enhancedLogs ?? { enabled: true }\n const injectSourceConfig = args?.injectSource ?? { enabled: true }\n const removeDevtoolsOnBuild = args?.removeDevtoolsOnBuild ?? true\n const serverBusEnabled = args?.eventBusConfig?.enabled ?? true\n const consolePipingConfig = args?.consolePiping ?? { enabled: true }\n const consolePipingLevels: Array<ConsoleLevel> =\n consolePipingConfig.levels ?? ['log', 'warn', 'error', 'info', 'debug']\n\n let devtoolsFileId: string | null = null\n let devtoolsPort: number | null = null\n let devtoolsHost: string | null = null\n let devtoolsProtocol: 'http' | 'https' | null = null\n\n return [\n {\n enforce: 'pre',\n name: '@tanstack/devtools:inject-source',\n apply(config) {\n return config.mode === 'development' && injectSourceConfig.enabled\n },\n transform: {\n filter: {\n id: {\n exclude: [/node_modules/, /\\?raw/, /\\/dist\\//, /\\/build\\//],\n },\n },\n handler(code, id) {\n return addSourceToJsx(code, id, args?.injectSource?.ignore)\n },\n },\n },\n {\n name: '@tanstack/devtools:config',\n enforce: 'pre',\n config(_, { command }) {\n // we do not apply any config changes for build\n if (command !== 'serve') {\n return\n }\n\n /* const solidDedupeDeps = [\n 'solid-js',\n 'solid-js/web',\n 'solid-js/store',\n 'solid-js/html',\n 'solid-js/h',\n ]\n\n return {\n resolve: {\n dedupe: solidDedupeDeps,\n },\n optimizeDeps: {\n include: solidDedupeDeps,\n },\n } */\n },\n },\n {\n enforce: 'pre',\n name: '@tanstack/devtools:custom-server',\n apply(config) {\n // Custom server is only needed in development for piping events to the client\n return config.mode === 'development'\n },\n async configureServer(server) {\n if (serverBusEnabled) {\n const preferredPort = args?.eventBusConfig?.port ?? 4206\n const isHttps = !!server.config.server.https\n const serverHost =\n typeof server.config.server.host === 'string'\n ? server.config.server.host\n : 'localhost'\n\n devtoolsProtocol = isHttps ? 'https' : 'http'\n devtoolsHost = serverHost\n\n const bus = new ServerEventBus({\n ...args?.eventBusConfig,\n port: preferredPort,\n host: serverHost,\n // When HTTPS is enabled, piggyback on Vite's server\n // so WebSocket/SSE connections share the same TLS certificate\n ...(isHttps && server.httpServer\n ? { httpServer: server.httpServer as HttpServerLike }\n : {}),\n })\n // start() now handles EADDRINUSE and returns the actual port\n devtoolsPort = await bus.start()\n }\n\n server.middlewares.use((req, _res, next) => {\n if (req.socket.localPort && req.socket.localPort !== port) {\n port = req.socket.localPort\n }\n next()\n })\n if (server.config.server.port) {\n port = server.config.server.port\n }\n\n server.httpServer?.on('listening', () => {\n port = server.config.server.port\n })\n\n const editor = args?.editor ?? DEFAULT_EDITOR_CONFIG\n const openInEditor: EditorConfig['open'] = async (\n path,\n lineNum,\n columnNum,\n ) => {\n if (!path) {\n return\n }\n await editor.open(path, lineNum, columnNum)\n }\n\n // SSE clients for broadcasting server logs to browser\n const sseClients: Array<{\n res: ServerResponse\n id: number\n }> = []\n let sseClientId = 0\n const consolePipingEnabled = consolePipingConfig.enabled ?? true\n\n server.middlewares.use((req, res, next) =>\n handleDevToolsViteRequest(req, res, next, {\n onOpenSource: (parsedData) => {\n const { data, routine } = parsedData\n if (routine === 'open-source') {\n return handleOpenSource({\n data: { type: data.type, data },\n openInEditor,\n })\n }\n return\n },\n ...(consolePipingEnabled\n ? {\n onConsolePipe: (entries) => {\n for (const entry of entries) {\n const prefix = chalk.cyan('[Client]')\n const logMethod = console[entry.level as ConsoleLevel]\n const cleanedArgs = stripEnhancedLogPrefix(\n entry.args,\n (loc) => chalk.gray(loc),\n )\n logMethod(prefix, ...cleanedArgs)\n }\n },\n onConsolePipeSSE: (res, req) => {\n res.setHeader('Content-Type', 'text/event-stream')\n res.setHeader('Cache-Control', 'no-cache')\n res.setHeader('Connection', 'keep-alive')\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.flushHeaders()\n\n const clientId = ++sseClientId\n sseClients.push({ res, id: clientId })\n\n req.on('close', () => {\n const index = sseClients.findIndex(\n (c) => c.id === clientId,\n )\n if (index !== -1) {\n sseClients.splice(index, 1)\n }\n })\n },\n onServerConsolePipe: (entries) => {\n try {\n const data = JSON.stringify({\n entries: entries.map((e) => ({\n level: e.level,\n args: e.args,\n source: 'server',\n timestamp: e.timestamp || Date.now(),\n })),\n })\n\n for (const client of sseClients) {\n client.res.write(`data: ${data}\\n\\n`)\n }\n } catch {}\n },\n }\n : {}),\n }),\n )\n },\n },\n {\n name: '@tanstack/devtools:remove-devtools-on-build',\n apply(config, { command }) {\n // Check both command and mode to support various hosting providers\n // Some providers (Cloudflare, Netlify, Heroku) might not use 'build' command\n // but will always set mode to 'production' for production builds\n return (\n (command !== 'serve' || config.mode === 'production') &&\n removeDevtoolsOnBuild\n )\n },\n enforce: 'pre',\n transform(code, id) {\n const devtoolPackages = [\n '@tanstack/react-devtools',\n '@tanstack/preact-devtools',\n '@tanstack/solid-devtools',\n '@tanstack/vue-devtools',\n '@tanstack/devtools',\n ]\n if (\n id.includes('node_modules') ||\n id.includes('?raw') ||\n !devtoolPackages.some((pkg) => code.includes(pkg))\n )\n return\n const transform = removeDevtools(code, id)\n if (!transform) return\n if (logging) {\n console.log(\n `\\n${chalk.greenBright(`[@tanstack/devtools-vite]`)} Removed devtools code from: ${id.replace(normalizePath(process.cwd()), '')}\\n`,\n )\n }\n return transform\n },\n },\n {\n name: '@tanstack/devtools:event-client-setup',\n apply(config, { command }) {\n if (\n process.env.CI ||\n process.env.NODE_ENV !== 'development' ||\n command !== 'serve'\n )\n return false\n return config.mode === 'development'\n },\n async configureServer() {\n const packageJson = await readPackageJson()\n const outdatedDeps = emitOutdatedDeps().then((deps) => deps)\n\n // Listen for package installation requests\n devtoolsEventClient.on('install-devtools', async (event) => {\n const result = await installPackage(event.payload.packageName)\n devtoolsEventClient.emit('devtools-installed', {\n packageName: event.payload.packageName,\n success: result.success,\n error: result.error,\n })\n\n // If installation was successful, automatically add the plugin to devtools\n if (result.success) {\n const { packageName, pluginName, pluginImport } = event.payload\n\n console.log(\n chalk.blueBright(\n `[@tanstack/devtools-vite] Auto-adding ${packageName} to devtools...`,\n ),\n )\n\n const injectResult = addPluginToDevtools(\n devtoolsFileId,\n packageName,\n pluginName,\n pluginImport,\n )\n\n if (injectResult.success) {\n // Emit plugin-added event so the UI updates\n devtoolsEventClient.emit('plugin-added', {\n packageName,\n success: true,\n })\n\n // Also re-read package.json to update the UI with the newly installed package\n const updatedPackageJson = await readPackageJson()\n devtoolsEventClient.emit('package-json-read', {\n packageJson: updatedPackageJson,\n })\n }\n }\n })\n\n // Listen for add plugin to devtools requests\n devtoolsEventClient.on('add-plugin-to-devtools', (event) => {\n const { packageName, pluginName, pluginImport } = event.payload\n\n console.log(\n chalk.blueBright(\n `[@tanstack/devtools-vite] Adding ${packageName} to devtools...`,\n ),\n )\n\n const result = addPluginToDevtools(\n devtoolsFileId,\n packageName,\n pluginName,\n pluginImport,\n )\n\n devtoolsEventClient.emit('plugin-added', {\n packageName,\n success: result.success,\n error: result.error,\n })\n })\n\n // Handle bump-package-version event\n devtoolsEventClient.on('bump-package-version', async (event) => {\n const {\n packageName,\n devtoolsPackage,\n pluginName,\n minVersion,\n pluginImport,\n } = event.payload\n\n console.log(\n chalk.blueBright(\n `[@tanstack/devtools-vite] Bumping ${packageName} to version ${minVersion}...`,\n ),\n )\n\n // Install the package with the minimum version\n const packageWithVersion = minVersion\n ? `${packageName}@^${minVersion}`\n : packageName\n\n const result = await installPackage(packageWithVersion)\n\n if (!result.success) {\n console.log(\n chalk.redBright(\n `[@tanstack/devtools-vite] Failed to bump ${packageName}: ${result.error}`,\n ),\n )\n devtoolsEventClient.emit('devtools-installed', {\n packageName: devtoolsPackage,\n success: false,\n error: result.error,\n })\n return\n }\n\n console.log(\n chalk.greenBright(\n `[@tanstack/devtools-vite] Successfully bumped ${packageName} to ${minVersion}!`,\n ),\n )\n\n // Check if we found the devtools file\n if (!devtoolsFileId) {\n console.log(\n chalk.yellowBright(\n `[@tanstack/devtools-vite] Devtools file not found. Skipping auto-injection.`,\n ),\n )\n devtoolsEventClient.emit('devtools-installed', {\n packageName: devtoolsPackage,\n success: true,\n })\n return\n }\n\n // Now inject the devtools plugin\n console.log(\n chalk.blueBright(\n `[@tanstack/devtools-vite] Adding ${devtoolsPackage} to devtools...`,\n ),\n )\n\n const injectResult = injectPluginIntoFile(devtoolsFileId, {\n packageName: devtoolsPackage,\n pluginName,\n pluginImport,\n })\n\n if (injectResult.success) {\n console.log(\n chalk.greenBright(\n `[@tanstack/devtools-vite] Successfully added ${devtoolsPackage} to devtools!`,\n ),\n )\n\n devtoolsEventClient.emit('plugin-added', {\n packageName: devtoolsPackage,\n success: true,\n })\n\n // Re-read package.json to update the UI\n const updatedPackageJson = await readPackageJson()\n devtoolsEventClient.emit('package-json-read', {\n packageJson: updatedPackageJson,\n })\n } else {\n console.log(\n chalk.redBright(\n `[@tanstack/devtools-vite] Failed to add ${devtoolsPackage} to devtools: ${injectResult.error}`,\n ),\n )\n\n devtoolsEventClient.emit('plugin-added', {\n packageName: devtoolsPackage,\n success: false,\n error: injectResult.error,\n })\n }\n })\n\n // whenever a client mounts we send all the current info to the subscribers\n devtoolsEventClient.on('mounted', async () => {\n devtoolsEventClient.emit('outdated-deps-read', {\n outdatedDeps: await outdatedDeps,\n })\n devtoolsEventClient.emit('package-json-read', {\n packageJson,\n })\n })\n\n // Console piping is now handled via HTTP endpoints in the custom-server plugin\n },\n async handleHotUpdate({ file }) {\n if (file.endsWith('package.json')) {\n const newPackageJson = await readPackageJson()\n devtoolsEventClient.emit('package-json-read', {\n packageJson: newPackageJson,\n })\n emitOutdatedDeps()\n }\n },\n },\n // Inject console piping code into entry files (both client and server)\n {\n name: '@tanstack/devtools:console-pipe-transform',\n enforce: 'pre',\n apply(config, { command }) {\n return (\n config.mode === 'development' &&\n command === 'serve' &&\n (consolePipingConfig.enabled ?? true)\n )\n },\n transform: {\n filter: {\n id: {\n include: /\\.(tsx?|jsx?)$/,\n exclude: [/node_modules/, /\\/dist\\//, /\\?/],\n },\n code: {\n exclude: /__tsdConsolePipe/, // avoid transforming files that already contain the console pipe code\n },\n },\n handler(code) {\n // Check if this is a root entry file (with <html> JSX or client entry points)\n // In SSR frameworks, this file runs on BOTH server (SSR) and client (hydration)\n // so our runtime check (typeof window === 'undefined') handles both environments\n const isRootEntry =\n /<html[\\s>]/i.test(code) ||\n code.includes('StartClient') ||\n code.includes('hydrateRoot') ||\n code.includes('createRoot') ||\n (code.includes('solid-js/web') && code.includes('render('))\n\n if (isRootEntry) {\n const viteServerUrl = `http://localhost:${port}`\n const inlineCode = generateConsolePipeCode(\n consolePipingLevels,\n viteServerUrl,\n )\n\n return `${inlineCode}\\n${code}`\n }\n\n return undefined\n },\n },\n },\n {\n name: '@tanstack/devtools:better-console-logs',\n enforce: 'pre',\n apply(config) {\n return config.mode === 'development' && enhancedLogsConfig.enabled\n },\n transform: {\n filter: {\n id: {\n exclude: [/node_modules/, /\\?raw/, /\\/dist\\//, /\\/build\\//],\n },\n code: {\n include: 'console.',\n },\n },\n handler(code, id) {\n return enhanceConsoleLog(code, id, port)\n },\n },\n },\n {\n name: '@tanstack/devtools:inject-plugin',\n apply(config, { command }) {\n return config.mode === 'development' && command === 'serve'\n },\n transform(code, id) {\n // First pass: find where TanStackDevtools is imported\n if (!devtoolsFileId && detectDevtoolsFile(code)) {\n // Extract actual file path (remove query params)\n const [filePath] = id.split('?')\n if (filePath) {\n devtoolsFileId = filePath\n }\n }\n\n return undefined\n },\n },\n {\n name: '@tanstack/devtools:connection-injection',\n apply(config, { command }) {\n return config.mode === 'development' && command === 'serve'\n },\n transform(code, id) {\n // Only transform @tanstack packages that contain the connection placeholders\n const hasPlaceholder =\n code.includes('__TANSTACK_DEVTOOLS_PORT__') ||\n code.includes('__TANSTACK_DEVTOOLS_HOST__') ||\n code.includes('__TANSTACK_DEVTOOLS_PROTOCOL__')\n if (!hasPlaceholder) return\n if (\n !id.includes('@tanstack/devtools') &&\n !id.includes('@tanstack/event-bus')\n )\n return\n\n // Replace placeholders with actual values (or fallback defaults)\n const portValue = devtoolsPort ?? 4206\n const hostValue = devtoolsHost ?? 'localhost'\n const protocolValue = devtoolsProtocol ?? 'http'\n\n let result = code\n result = result.replace(\n /__TANSTACK_DEVTOOLS_PORT__/g,\n String(portValue),\n )\n result = result.replace(\n /__TANSTACK_DEVTOOLS_HOST__/g,\n JSON.stringify(hostValue),\n )\n result = result.replace(\n /__TANSTACK_DEVTOOLS_PROTOCOL__/g,\n JSON.stringify(protocolValue),\n )\n return result\n },\n },\n ]\n}\n"],"names":["res","req"],"mappings":"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"}
package/dist/esm/utils.js CHANGED
@@ -91,6 +91,7 @@ const handleDevToolsViteRequest = (req, res, next, cbOrOptions) => {
91
91
  } catch (e) {
92
92
  }
93
93
  res.write("OK");
94
+ res.end();
94
95
  });
95
96
  };
96
97
  const parseOpenSourceParam = (source) => {
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["import fs from 'node:fs/promises'\nimport { normalizePath } from 'vite'\nimport type { Connect } from 'vite'\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { PackageJson } from '@tanstack/devtools-client'\n\ntype DevToolsRequestHandler = (data: any) => void\n\ntype DevToolsViteRequestOptions = {\n onOpenSource?: DevToolsRequestHandler\n onConsolePipe?: (entries: Array<any>) => void\n onServerConsolePipe?: (entries: Array<any>) => void\n onConsolePipeSSE?: (\n res: ServerResponse<IncomingMessage>,\n req: Connect.IncomingMessage,\n ) => void\n}\n\nexport const handleDevToolsViteRequest = (\n req: Connect.IncomingMessage,\n res: ServerResponse<IncomingMessage>,\n next: Connect.NextFunction,\n cbOrOptions: DevToolsRequestHandler | DevToolsViteRequestOptions,\n) => {\n // Normalize to options object for backward compatibility\n const options: DevToolsViteRequestOptions =\n typeof cbOrOptions === 'function'\n ? { onOpenSource: cbOrOptions }\n : cbOrOptions\n\n // Handle open-source requests\n if (req.url?.includes('__tsd/open-source')) {\n const searchParams = new URLSearchParams(req.url.split('?')[1])\n\n const source = searchParams.get('source')\n if (!source) {\n return\n }\n\n const parsed = parseOpenSourceParam(source)\n if (!parsed) {\n return\n }\n const { file, line, column } = parsed\n\n options.onOpenSource?.({\n type: 'open-source',\n routine: 'open-source',\n data: {\n source: file ? normalizePath(`${process.cwd()}/${file}`) : undefined,\n line,\n column,\n },\n })\n res.setHeader('Content-Type', 'text/html')\n res.write(`<script> window.close(); </script>`)\n res.end()\n return\n }\n\n // Handle console-pipe SSE endpoint (browser subscribes to server logs)\n if (req.url?.includes('__tsd/console-pipe/sse') && req.method === 'GET') {\n if (options.onConsolePipeSSE) {\n options.onConsolePipeSSE(res, req)\n return\n }\n return next()\n }\n\n // Handle server console-pipe POST endpoint (from app server runtime)\n if (req.url?.includes('__tsd/console-pipe/server') && req.method === 'POST') {\n if (options.onServerConsolePipe) {\n let body = ''\n req.on('data', (chunk: Buffer) => {\n body += chunk.toString()\n })\n req.on('end', () => {\n try {\n const { entries } = JSON.parse(body)\n options.onServerConsolePipe!(entries)\n res.statusCode = 200\n res.end('OK')\n } catch {\n res.statusCode = 400\n res.end('Bad Request')\n }\n })\n return\n }\n return next()\n }\n\n // Handle console-pipe POST endpoint (from client)\n if (req.url?.includes('__tsd/console-pipe') && req.method === 'POST') {\n if (options.onConsolePipe) {\n let body = ''\n req.on('data', (chunk: Buffer) => {\n body += chunk.toString()\n })\n req.on('end', () => {\n try {\n const { entries } = JSON.parse(body)\n options.onConsolePipe!(entries)\n res.statusCode = 200\n res.end('OK')\n } catch {\n res.statusCode = 400\n res.end('Bad Request')\n }\n })\n return\n }\n return next()\n }\n\n if (!req.url?.includes('__tsd')) {\n return next()\n }\n\n const chunks: Array<any> = []\n req.on('data', (chunk) => {\n chunks.push(chunk)\n })\n req.on('end', () => {\n const dataToParse = Buffer.concat(chunks)\n try {\n const parsedData = JSON.parse(dataToParse.toString())\n options.onOpenSource?.(parsedData)\n } catch (e) {}\n res.write('OK')\n })\n}\n\nexport const parseOpenSourceParam = (source: string) => {\n // Capture everything up to the last two colon-separated numeric parts as the file.\n // This supports filenames that may themselves contain colons.\n const parts = source.match(/^(.+):(\\d+):(\\d+)$/)\n\n if (!parts) return null\n\n const [, file, line, column] = parts\n return { file, line, column }\n}\n\nconst tryReadFile = async (filePath: string) => {\n try {\n const data = await fs.readFile(filePath, 'utf-8')\n return data\n } catch (error) {\n return null\n }\n}\n\nexport const tryParseJson = <T extends any>(\n jsonString: string | null | undefined,\n) => {\n if (!jsonString) {\n return null\n }\n try {\n const result = JSON.parse(jsonString)\n return result as T\n } catch (error) {\n return null\n }\n}\n\nexport const readPackageJson = async () =>\n tryParseJson<PackageJson>(await tryReadFile(process.cwd() + '/package.json'))\n\n/**\n * Extracts and formats the source location from enhanced client console logs.\n * Instead of stripping the prefix entirely, we extract the file:line:column\n * from the \"Go to Source\" URL and use that as a prefix.\n *\n * Enhanced logs format (two variants):\n * 1. ['%cLOG%c %cGo to Source: http://...?source=%2Fsrc%2F...%c \\n → ', 'color:...', 'color:...', 'color:...', 'color:...', 'message']\n * 2. ['\\x1b[...]%s\\x1b[...]', '%cLOG%c %cGo to Source: ...%c \\n → ', 'color:...', 'color:...', 'color:...', 'color:...', 'message']\n *\n * Output: ['src/components/Header.tsx:26:13', 'message']\n */\nexport const stripEnhancedLogPrefix = (\n args: Array<unknown>,\n formatSourceLocation?: (location: string) => unknown,\n): Array<unknown> => {\n if (args.length === 0) return args\n\n // Find the arg that contains the Go to Source URL\n let sourceArgIndex = -1\n for (let i = 0; i < args.length; i++) {\n const arg = args[i]\n if (typeof arg === 'string' && arg.includes('__tsd/open-source?source=')) {\n sourceArgIndex = i\n break\n }\n }\n\n // If no source URL found, return args as-is (not an enhanced log)\n if (sourceArgIndex === -1) {\n return args\n }\n\n const sourceArg = args[sourceArgIndex] as string\n\n // Extract the source from the \"Go to Source\" URL\n // URL format: http://localhost:3000/__tsd/open-source?source=%2Fsrc%2Ffile.tsx%3A26%3A13%c\n // Note: The URL ends with %c which is a console format specifier, not URL encoding\n let sourceLocation = ''\n const sourceMatch = sourceArg.match(/source=([^&\\s]+?)%c/)\n if (sourceMatch?.[1]) {\n try {\n sourceLocation = decodeURIComponent(sourceMatch[1])\n // Remove leading slash if present\n if (sourceLocation.startsWith('/')) {\n sourceLocation = sourceLocation.slice(1)\n }\n } catch {\n // If decoding fails, leave it empty\n }\n }\n\n // Count %c markers in the source arg to know how many style args follow it\n const styleCount = (sourceArg.match(/%c/g) || []).length\n\n // The actual user args start after the source arg and all its style args\n const userArgsStart = sourceArgIndex + 1 + styleCount\n\n // Build the result: source location prefix + remaining args (the actual user data)\n const result: Array<unknown> = []\n\n // Add source location as prefix if we found one\n if (sourceLocation) {\n result.push(\n formatSourceLocation\n ? formatSourceLocation(sourceLocation)\n : sourceLocation,\n )\n }\n\n // Add remaining args (the actual user data)\n for (let i = userArgsStart; i < args.length; i++) {\n result.push(args[i])\n }\n\n return result.length > 0 ? result : args\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["import fs from 'node:fs/promises'\nimport { normalizePath } from 'vite'\nimport type { Connect } from 'vite'\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { PackageJson } from '@tanstack/devtools-client'\n\ntype DevToolsRequestHandler = (data: any) => void\n\ntype DevToolsViteRequestOptions = {\n onOpenSource?: DevToolsRequestHandler\n onConsolePipe?: (entries: Array<any>) => void\n onServerConsolePipe?: (entries: Array<any>) => void\n onConsolePipeSSE?: (\n res: ServerResponse<IncomingMessage>,\n req: Connect.IncomingMessage,\n ) => void\n}\n\nexport const handleDevToolsViteRequest = (\n req: Connect.IncomingMessage,\n res: ServerResponse<IncomingMessage>,\n next: Connect.NextFunction,\n cbOrOptions: DevToolsRequestHandler | DevToolsViteRequestOptions,\n) => {\n // Normalize to options object for backward compatibility\n const options: DevToolsViteRequestOptions =\n typeof cbOrOptions === 'function'\n ? { onOpenSource: cbOrOptions }\n : cbOrOptions\n\n // Handle open-source requests\n if (req.url?.includes('__tsd/open-source')) {\n const searchParams = new URLSearchParams(req.url.split('?')[1])\n\n const source = searchParams.get('source')\n if (!source) {\n return\n }\n\n const parsed = parseOpenSourceParam(source)\n if (!parsed) {\n return\n }\n const { file, line, column } = parsed\n\n options.onOpenSource?.({\n type: 'open-source',\n routine: 'open-source',\n data: {\n source: file ? normalizePath(`${process.cwd()}/${file}`) : undefined,\n line,\n column,\n },\n })\n res.setHeader('Content-Type', 'text/html')\n res.write(`<script> window.close(); </script>`)\n res.end()\n return\n }\n\n // Handle console-pipe SSE endpoint (browser subscribes to server logs)\n if (req.url?.includes('__tsd/console-pipe/sse') && req.method === 'GET') {\n if (options.onConsolePipeSSE) {\n options.onConsolePipeSSE(res, req)\n return\n }\n return next()\n }\n\n // Handle server console-pipe POST endpoint (from app server runtime)\n if (req.url?.includes('__tsd/console-pipe/server') && req.method === 'POST') {\n if (options.onServerConsolePipe) {\n let body = ''\n req.on('data', (chunk: Buffer) => {\n body += chunk.toString()\n })\n req.on('end', () => {\n try {\n const { entries } = JSON.parse(body)\n options.onServerConsolePipe!(entries)\n res.statusCode = 200\n res.end('OK')\n } catch {\n res.statusCode = 400\n res.end('Bad Request')\n }\n })\n return\n }\n return next()\n }\n\n // Handle console-pipe POST endpoint (from client)\n if (req.url?.includes('__tsd/console-pipe') && req.method === 'POST') {\n if (options.onConsolePipe) {\n let body = ''\n req.on('data', (chunk: Buffer) => {\n body += chunk.toString()\n })\n req.on('end', () => {\n try {\n const { entries } = JSON.parse(body)\n options.onConsolePipe!(entries)\n res.statusCode = 200\n res.end('OK')\n } catch {\n res.statusCode = 400\n res.end('Bad Request')\n }\n })\n return\n }\n return next()\n }\n\n if (!req.url?.includes('__tsd')) {\n return next()\n }\n\n const chunks: Array<any> = []\n req.on('data', (chunk) => {\n chunks.push(chunk)\n })\n req.on('end', () => {\n const dataToParse = Buffer.concat(chunks)\n try {\n const parsedData = JSON.parse(dataToParse.toString())\n options.onOpenSource?.(parsedData)\n } catch (e) {}\n res.write('OK')\n res.end()\n })\n}\n\nexport const parseOpenSourceParam = (source: string) => {\n // Capture everything up to the last two colon-separated numeric parts as the file.\n // This supports filenames that may themselves contain colons.\n const parts = source.match(/^(.+):(\\d+):(\\d+)$/)\n\n if (!parts) return null\n\n const [, file, line, column] = parts\n return { file, line, column }\n}\n\nconst tryReadFile = async (filePath: string) => {\n try {\n const data = await fs.readFile(filePath, 'utf-8')\n return data\n } catch (error) {\n return null\n }\n}\n\nexport const tryParseJson = <T extends any>(\n jsonString: string | null | undefined,\n) => {\n if (!jsonString) {\n return null\n }\n try {\n const result = JSON.parse(jsonString)\n return result as T\n } catch (error) {\n return null\n }\n}\n\nexport const readPackageJson = async () =>\n tryParseJson<PackageJson>(await tryReadFile(process.cwd() + '/package.json'))\n\n/**\n * Extracts and formats the source location from enhanced client console logs.\n * Instead of stripping the prefix entirely, we extract the file:line:column\n * from the \"Go to Source\" URL and use that as a prefix.\n *\n * Enhanced logs format (two variants):\n * 1. ['%cLOG%c %cGo to Source: http://...?source=%2Fsrc%2F...%c \\n → ', 'color:...', 'color:...', 'color:...', 'color:...', 'message']\n * 2. ['\\x1b[...]%s\\x1b[...]', '%cLOG%c %cGo to Source: ...%c \\n → ', 'color:...', 'color:...', 'color:...', 'color:...', 'message']\n *\n * Output: ['src/components/Header.tsx:26:13', 'message']\n */\nexport const stripEnhancedLogPrefix = (\n args: Array<unknown>,\n formatSourceLocation?: (location: string) => unknown,\n): Array<unknown> => {\n if (args.length === 0) return args\n\n // Find the arg that contains the Go to Source URL\n let sourceArgIndex = -1\n for (let i = 0; i < args.length; i++) {\n const arg = args[i]\n if (typeof arg === 'string' && arg.includes('__tsd/open-source?source=')) {\n sourceArgIndex = i\n break\n }\n }\n\n // If no source URL found, return args as-is (not an enhanced log)\n if (sourceArgIndex === -1) {\n return args\n }\n\n const sourceArg = args[sourceArgIndex] as string\n\n // Extract the source from the \"Go to Source\" URL\n // URL format: http://localhost:3000/__tsd/open-source?source=%2Fsrc%2Ffile.tsx%3A26%3A13%c\n // Note: The URL ends with %c which is a console format specifier, not URL encoding\n let sourceLocation = ''\n const sourceMatch = sourceArg.match(/source=([^&\\s]+?)%c/)\n if (sourceMatch?.[1]) {\n try {\n sourceLocation = decodeURIComponent(sourceMatch[1])\n // Remove leading slash if present\n if (sourceLocation.startsWith('/')) {\n sourceLocation = sourceLocation.slice(1)\n }\n } catch {\n // If decoding fails, leave it empty\n }\n }\n\n // Count %c markers in the source arg to know how many style args follow it\n const styleCount = (sourceArg.match(/%c/g) || []).length\n\n // The actual user args start after the source arg and all its style args\n const userArgsStart = sourceArgIndex + 1 + styleCount\n\n // Build the result: source location prefix + remaining args (the actual user data)\n const result: Array<unknown> = []\n\n // Add source location as prefix if we found one\n if (sourceLocation) {\n result.push(\n formatSourceLocation\n ? formatSourceLocation(sourceLocation)\n : sourceLocation,\n )\n }\n\n // Add remaining args (the actual user data)\n for (let i = userArgsStart; i < args.length; i++) {\n result.push(args[i])\n }\n\n return result.length > 0 ? result : args\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/devtools-vite",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "TanStack Vite plugin used to enhance the core devtools with additional functionalities",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -50,7 +50,7 @@
50
50
  "launch-editor": "^2.11.1",
51
51
  "picomatch": "^4.0.3",
52
52
  "@tanstack/devtools-client": "0.0.5",
53
- "@tanstack/devtools-event-bus": "0.4.0"
53
+ "@tanstack/devtools-event-bus": "0.4.1"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@types/babel__core": "^7.20.5",
package/src/plugin.ts CHANGED
@@ -21,7 +21,10 @@ import { generateConsolePipeCode } from './virtual-console'
21
21
  import type { ServerResponse } from 'node:http'
22
22
  import type { Plugin } from 'vite'
23
23
  import type { EditorConfig } from './editor'
24
- import type { ServerEventBusConfig } from '@tanstack/devtools-event-bus/server'
24
+ import type {
25
+ HttpServerLike,
26
+ ServerEventBusConfig,
27
+ } from '@tanstack/devtools-event-bus/server'
25
28
 
26
29
  export type ConsoleLevel = 'log' | 'warn' | 'error' | 'info' | 'debug'
27
30
 
@@ -113,6 +116,8 @@ export const devtools = (args?: TanStackDevtoolsViteConfig): Array<Plugin> => {
113
116
 
114
117
  let devtoolsFileId: string | null = null
115
118
  let devtoolsPort: number | null = null
119
+ let devtoolsHost: string | null = null
120
+ let devtoolsProtocol: 'http' | 'https' | null = null
116
121
 
117
122
  return [
118
123
  {
@@ -121,16 +126,15 @@ export const devtools = (args?: TanStackDevtoolsViteConfig): Array<Plugin> => {
121
126
  apply(config) {
122
127
  return config.mode === 'development' && injectSourceConfig.enabled
123
128
  },
124
- transform(code, id) {
125
- if (
126
- id.includes('node_modules') ||
127
- id.includes('?raw') ||
128
- id.includes('dist') ||
129
- id.includes('build')
130
- )
131
- return
132
-
133
- return addSourceToJsx(code, id, args?.injectSource?.ignore)
129
+ transform: {
130
+ filter: {
131
+ id: {
132
+ exclude: [/node_modules/, /\?raw/, /\/dist\//, /\/build\//],
133
+ },
134
+ },
135
+ handler(code, id) {
136
+ return addSourceToJsx(code, id, args?.injectSource?.ignore)
137
+ },
134
138
  },
135
139
  },
136
140
  {
@@ -170,9 +174,24 @@ export const devtools = (args?: TanStackDevtoolsViteConfig): Array<Plugin> => {
170
174
  async configureServer(server) {
171
175
  if (serverBusEnabled) {
172
176
  const preferredPort = args?.eventBusConfig?.port ?? 4206
177
+ const isHttps = !!server.config.server.https
178
+ const serverHost =
179
+ typeof server.config.server.host === 'string'
180
+ ? server.config.server.host
181
+ : 'localhost'
182
+
183
+ devtoolsProtocol = isHttps ? 'https' : 'http'
184
+ devtoolsHost = serverHost
185
+
173
186
  const bus = new ServerEventBus({
174
187
  ...args?.eventBusConfig,
175
188
  port: preferredPort,
189
+ host: serverHost,
190
+ // When HTTPS is enabled, piggyback on Vite's server
191
+ // so WebSocket/SSE connections share the same TLS certificate
192
+ ...(isHttps && server.httpServer
193
+ ? { httpServer: server.httpServer as HttpServerLike }
194
+ : {}),
176
195
  })
177
196
  // start() now handles EADDRINUSE and returns the actual port
178
197
  devtoolsPort = await bus.start()
@@ -530,43 +549,39 @@ export const devtools = (args?: TanStackDevtoolsViteConfig): Array<Plugin> => {
530
549
  (consolePipingConfig.enabled ?? true)
531
550
  )
532
551
  },
533
- transform(code, id) {
534
- // Inject the console pipe code into entry files
535
- if (
536
- id.includes('node_modules') ||
537
- id.includes('dist') ||
538
- id.includes('?') ||
539
- !id.match(/\.(tsx?|jsx?)$/)
540
- ) {
541
- return
542
- }
543
-
544
- // Only inject once - check if already injected
545
- if (code.includes('__tsdConsolePipe')) {
546
- return
547
- }
548
-
549
- // Check if this is a root entry file (with <html> JSX or client entry points)
550
- // In SSR frameworks, this file runs on BOTH server (SSR) and client (hydration)
551
- // so our runtime check (typeof window === 'undefined') handles both environments
552
- const isRootEntry =
553
- /<html[\s>]/i.test(code) ||
554
- code.includes('StartClient') ||
555
- code.includes('hydrateRoot') ||
556
- code.includes('createRoot') ||
557
- (code.includes('solid-js/web') && code.includes('render('))
558
-
559
- if (isRootEntry) {
560
- const viteServerUrl = `http://localhost:${port}`
561
- const inlineCode = generateConsolePipeCode(
562
- consolePipingLevels,
563
- viteServerUrl,
564
- )
552
+ transform: {
553
+ filter: {
554
+ id: {
555
+ include: /\.(tsx?|jsx?)$/,
556
+ exclude: [/node_modules/, /\/dist\//, /\?/],
557
+ },
558
+ code: {
559
+ exclude: /__tsdConsolePipe/, // avoid transforming files that already contain the console pipe code
560
+ },
561
+ },
562
+ handler(code) {
563
+ // Check if this is a root entry file (with <html> JSX or client entry points)
564
+ // In SSR frameworks, this file runs on BOTH server (SSR) and client (hydration)
565
+ // so our runtime check (typeof window === 'undefined') handles both environments
566
+ const isRootEntry =
567
+ /<html[\s>]/i.test(code) ||
568
+ code.includes('StartClient') ||
569
+ code.includes('hydrateRoot') ||
570
+ code.includes('createRoot') ||
571
+ (code.includes('solid-js/web') && code.includes('render('))
572
+
573
+ if (isRootEntry) {
574
+ const viteServerUrl = `http://localhost:${port}`
575
+ const inlineCode = generateConsolePipeCode(
576
+ consolePipingLevels,
577
+ viteServerUrl,
578
+ )
565
579
 
566
- return `${inlineCode}\n${code}`
567
- }
580
+ return `${inlineCode}\n${code}`
581
+ }
568
582
 
569
- return undefined
583
+ return undefined
584
+ },
570
585
  },
571
586
  },
572
587
  {
@@ -575,18 +590,18 @@ export const devtools = (args?: TanStackDevtoolsViteConfig): Array<Plugin> => {
575
590
  apply(config) {
576
591
  return config.mode === 'development' && enhancedLogsConfig.enabled
577
592
  },
578
- transform(code, id) {
579
- // Ignore anything external
580
- if (
581
- id.includes('node_modules') ||
582
- id.includes('?raw') ||
583
- id.includes('dist') ||
584
- id.includes('build') ||
585
- !code.includes('console.')
586
- )
587
- return
588
-
589
- return enhanceConsoleLog(code, id, port)
593
+ transform: {
594
+ filter: {
595
+ id: {
596
+ exclude: [/node_modules/, /\?raw/, /\/dist\//, /\/build\//],
597
+ },
598
+ code: {
599
+ include: 'console.',
600
+ },
601
+ },
602
+ handler(code, id) {
603
+ return enhanceConsoleLog(code, id, port)
604
+ },
590
605
  },
591
606
  },
592
607
  {
@@ -608,22 +623,42 @@ export const devtools = (args?: TanStackDevtoolsViteConfig): Array<Plugin> => {
608
623
  },
609
624
  },
610
625
  {
611
- name: '@tanstack/devtools:port-injection',
626
+ name: '@tanstack/devtools:connection-injection',
612
627
  apply(config, { command }) {
613
628
  return config.mode === 'development' && command === 'serve'
614
629
  },
615
630
  transform(code, id) {
616
- // Only transform @tanstack packages that contain the port placeholder
617
- if (!code.includes('__TANSTACK_DEVTOOLS_PORT__')) return
631
+ // Only transform @tanstack packages that contain the connection placeholders
632
+ const hasPlaceholder =
633
+ code.includes('__TANSTACK_DEVTOOLS_PORT__') ||
634
+ code.includes('__TANSTACK_DEVTOOLS_HOST__') ||
635
+ code.includes('__TANSTACK_DEVTOOLS_PROTOCOL__')
636
+ if (!hasPlaceholder) return
618
637
  if (
619
638
  !id.includes('@tanstack/devtools') &&
620
639
  !id.includes('@tanstack/event-bus')
621
640
  )
622
641
  return
623
642
 
624
- // Replace placeholder with actual port (or fallback to 4206 if not resolved yet)
643
+ // Replace placeholders with actual values (or fallback defaults)
625
644
  const portValue = devtoolsPort ?? 4206
626
- return code.replace(/__TANSTACK_DEVTOOLS_PORT__/g, String(portValue))
645
+ const hostValue = devtoolsHost ?? 'localhost'
646
+ const protocolValue = devtoolsProtocol ?? 'http'
647
+
648
+ let result = code
649
+ result = result.replace(
650
+ /__TANSTACK_DEVTOOLS_PORT__/g,
651
+ String(portValue),
652
+ )
653
+ result = result.replace(
654
+ /__TANSTACK_DEVTOOLS_HOST__/g,
655
+ JSON.stringify(hostValue),
656
+ )
657
+ result = result.replace(
658
+ /__TANSTACK_DEVTOOLS_PROTOCOL__/g,
659
+ JSON.stringify(protocolValue),
660
+ )
661
+ return result
627
662
  },
628
663
  },
629
664
  ]
package/src/utils.ts CHANGED
@@ -128,6 +128,7 @@ export const handleDevToolsViteRequest = (
128
128
  options.onOpenSource?.(parsedData)
129
129
  } catch (e) {}
130
130
  res.write('OK')
131
+ res.end()
131
132
  })
132
133
  }
133
134