@tanstack/devtools-vite 0.4.1 → 0.5.1
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.
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/plugin.d.ts +18 -0
- package/dist/esm/plugin.js +123 -14
- package/dist/esm/plugin.js.map +1 -1
- package/dist/esm/utils.d.ts +21 -1
- package/dist/esm/utils.js +93 -3
- package/dist/esm/utils.js.map +1 -1
- package/dist/esm/utils.test.d.ts +1 -0
- package/dist/esm/virtual-console.d.ts +19 -0
- package/dist/esm/virtual-console.js +180 -0
- package/dist/esm/virtual-console.js.map +1 -0
- package/dist/esm/virtual-console.test.d.ts +1 -0
- package/package.json +2 -2
- package/src/enhance-logs.test.ts +1 -1
- package/src/index.ts +1 -1
- package/src/plugin.ts +197 -16
- package/src/utils.test.ts +184 -0
- package/src/utils.ts +156 -3
- package/src/virtual-console.test.ts +73 -0
- package/src/virtual-console.ts +202 -0
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { devtools, defineDevtoolsConfig } from './plugin.js';
|
|
2
|
-
export type { TanStackDevtoolsViteConfig } from './plugin.js';
|
|
2
|
+
export type { TanStackDevtoolsViteConfig, ConsoleLevel } from './plugin.js';
|
package/dist/esm/plugin.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
2
|
import { EditorConfig } from './editor.js';
|
|
3
3
|
import { ServerEventBusConfig } from '@tanstack/devtools-event-bus/server';
|
|
4
|
+
export type ConsoleLevel = 'log' | 'warn' | 'error' | 'info' | 'debug';
|
|
4
5
|
export type TanStackDevtoolsViteConfig = {
|
|
5
6
|
/**
|
|
6
7
|
* Configuration for the editor integration. Defaults to opening in VS code
|
|
@@ -53,6 +54,23 @@ export type TanStackDevtoolsViteConfig = {
|
|
|
53
54
|
components?: Array<string | RegExp>;
|
|
54
55
|
};
|
|
55
56
|
};
|
|
57
|
+
/**
|
|
58
|
+
* Configuration for console piping between client and server.
|
|
59
|
+
* When enabled, console logs from the client will appear in the terminal,
|
|
60
|
+
* and server logs will appear in the browser console.
|
|
61
|
+
*/
|
|
62
|
+
consolePiping?: {
|
|
63
|
+
/**
|
|
64
|
+
* Whether to enable console piping.
|
|
65
|
+
* @default true
|
|
66
|
+
*/
|
|
67
|
+
enabled?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Which console methods to pipe.
|
|
70
|
+
* @default ['log', 'warn', 'error', 'info', 'debug']
|
|
71
|
+
*/
|
|
72
|
+
levels?: Array<ConsoleLevel>;
|
|
73
|
+
};
|
|
56
74
|
};
|
|
57
75
|
export declare const defineDevtoolsConfig: (config: TanStackDevtoolsViteConfig) => TanStackDevtoolsViteConfig;
|
|
58
76
|
export declare const devtools: (args?: TanStackDevtoolsViteConfig) => Array<Plugin>;
|
package/dist/esm/plugin.js
CHANGED
|
@@ -2,13 +2,14 @@ import { devtoolsEventClient } from "@tanstack/devtools-client";
|
|
|
2
2
|
import { ServerEventBus } from "@tanstack/devtools-event-bus/server";
|
|
3
3
|
import { normalizePath } from "vite";
|
|
4
4
|
import chalk from "chalk";
|
|
5
|
-
import { handleDevToolsViteRequest, readPackageJson } from "./utils.js";
|
|
5
|
+
import { handleDevToolsViteRequest, readPackageJson, stripEnhancedLogPrefix } from "./utils.js";
|
|
6
6
|
import { DEFAULT_EDITOR_CONFIG, handleOpenSource } from "./editor.js";
|
|
7
7
|
import { removeDevtools } from "./remove-devtools.js";
|
|
8
8
|
import { addSourceToJsx } from "./inject-source.js";
|
|
9
9
|
import { enhanceConsoleLog } from "./enhance-logs.js";
|
|
10
10
|
import { detectDevtoolsFile, injectPluginIntoFile } from "./inject-plugin.js";
|
|
11
11
|
import { emitOutdatedDeps, installPackage, addPluginToDevtools } from "./package-manager.js";
|
|
12
|
+
import { generateConsolePipeCode } from "./virtual-console.js";
|
|
12
13
|
const defineDevtoolsConfig = (config) => config;
|
|
13
14
|
const devtools = (args) => {
|
|
14
15
|
let port = 5173;
|
|
@@ -17,8 +18,12 @@ const devtools = (args) => {
|
|
|
17
18
|
const injectSourceConfig = args?.injectSource ?? { enabled: true };
|
|
18
19
|
const removeDevtoolsOnBuild = args?.removeDevtoolsOnBuild ?? true;
|
|
19
20
|
const serverBusEnabled = args?.eventBusConfig?.enabled ?? true;
|
|
21
|
+
const consolePipingConfig = args?.consolePiping ?? { enabled: true };
|
|
22
|
+
const consolePipingLevels = consolePipingConfig.levels ?? ["log", "warn", "error", "info", "debug"];
|
|
20
23
|
let devtoolsFileId = null;
|
|
21
24
|
let devtoolsPort = null;
|
|
25
|
+
let devtoolsHost = null;
|
|
26
|
+
let devtoolsProtocol = null;
|
|
22
27
|
return [
|
|
23
28
|
{
|
|
24
29
|
enforce: "pre",
|
|
@@ -50,9 +55,17 @@ const devtools = (args) => {
|
|
|
50
55
|
async configureServer(server) {
|
|
51
56
|
if (serverBusEnabled) {
|
|
52
57
|
const preferredPort = args?.eventBusConfig?.port ?? 4206;
|
|
58
|
+
const isHttps = !!server.config.server.https;
|
|
59
|
+
const serverHost = typeof server.config.server.host === "string" ? server.config.server.host : "localhost";
|
|
60
|
+
devtoolsProtocol = isHttps ? "https" : "http";
|
|
61
|
+
devtoolsHost = serverHost;
|
|
53
62
|
const bus = new ServerEventBus({
|
|
54
63
|
...args?.eventBusConfig,
|
|
55
|
-
port: preferredPort
|
|
64
|
+
port: preferredPort,
|
|
65
|
+
host: serverHost,
|
|
66
|
+
// When HTTPS is enabled, piggyback on Vite's server
|
|
67
|
+
// so WebSocket/SSE connections share the same TLS certificate
|
|
68
|
+
...isHttps && server.httpServer ? { httpServer: server.httpServer } : {}
|
|
56
69
|
});
|
|
57
70
|
devtoolsPort = await bus.start();
|
|
58
71
|
}
|
|
@@ -75,16 +88,69 @@ const devtools = (args) => {
|
|
|
75
88
|
}
|
|
76
89
|
await editor.open(path, lineNum, columnNum);
|
|
77
90
|
};
|
|
91
|
+
const sseClients = [];
|
|
92
|
+
let sseClientId = 0;
|
|
93
|
+
const consolePipingEnabled = consolePipingConfig.enabled ?? true;
|
|
78
94
|
server.middlewares.use(
|
|
79
|
-
(req, res, next) => handleDevToolsViteRequest(req, res, next,
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
95
|
+
(req, res, next) => handleDevToolsViteRequest(req, res, next, {
|
|
96
|
+
onOpenSource: (parsedData) => {
|
|
97
|
+
const { data, routine } = parsedData;
|
|
98
|
+
if (routine === "open-source") {
|
|
99
|
+
return handleOpenSource({
|
|
100
|
+
data: { type: data.type, data },
|
|
101
|
+
openInEditor
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return;
|
|
105
|
+
},
|
|
106
|
+
...consolePipingEnabled ? {
|
|
107
|
+
onConsolePipe: (entries) => {
|
|
108
|
+
for (const entry of entries) {
|
|
109
|
+
const prefix = chalk.cyan("[Client]");
|
|
110
|
+
const logMethod = console[entry.level];
|
|
111
|
+
const cleanedArgs = stripEnhancedLogPrefix(
|
|
112
|
+
entry.args,
|
|
113
|
+
(loc) => chalk.gray(loc)
|
|
114
|
+
);
|
|
115
|
+
logMethod(prefix, ...cleanedArgs);
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
onConsolePipeSSE: (res2, req2) => {
|
|
119
|
+
res2.setHeader("Content-Type", "text/event-stream");
|
|
120
|
+
res2.setHeader("Cache-Control", "no-cache");
|
|
121
|
+
res2.setHeader("Connection", "keep-alive");
|
|
122
|
+
res2.setHeader("Access-Control-Allow-Origin", "*");
|
|
123
|
+
res2.flushHeaders();
|
|
124
|
+
const clientId = ++sseClientId;
|
|
125
|
+
sseClients.push({ res: res2, id: clientId });
|
|
126
|
+
req2.on("close", () => {
|
|
127
|
+
const index = sseClients.findIndex(
|
|
128
|
+
(c) => c.id === clientId
|
|
129
|
+
);
|
|
130
|
+
if (index !== -1) {
|
|
131
|
+
sseClients.splice(index, 1);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
onServerConsolePipe: (entries) => {
|
|
136
|
+
try {
|
|
137
|
+
const data = JSON.stringify({
|
|
138
|
+
entries: entries.map((e) => ({
|
|
139
|
+
level: e.level,
|
|
140
|
+
args: e.args,
|
|
141
|
+
source: "server",
|
|
142
|
+
timestamp: e.timestamp || Date.now()
|
|
143
|
+
}))
|
|
144
|
+
});
|
|
145
|
+
for (const client of sseClients) {
|
|
146
|
+
client.res.write(`data: ${data}
|
|
147
|
+
|
|
148
|
+
`);
|
|
149
|
+
}
|
|
150
|
+
} catch {
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
} : {}
|
|
88
154
|
})
|
|
89
155
|
);
|
|
90
156
|
}
|
|
@@ -279,6 +345,33 @@ ${chalk.greenBright(`[@tanstack/devtools-vite]`)} Removed devtools code from: ${
|
|
|
279
345
|
}
|
|
280
346
|
}
|
|
281
347
|
},
|
|
348
|
+
// Inject console piping code into entry files (both client and server)
|
|
349
|
+
{
|
|
350
|
+
name: "@tanstack/devtools:console-pipe-transform",
|
|
351
|
+
enforce: "pre",
|
|
352
|
+
apply(config, { command }) {
|
|
353
|
+
return config.mode === "development" && command === "serve" && (consolePipingConfig.enabled ?? true);
|
|
354
|
+
},
|
|
355
|
+
transform(code, id) {
|
|
356
|
+
if (id.includes("node_modules") || id.includes("dist") || id.includes("?") || !id.match(/\.(tsx?|jsx?)$/)) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (code.includes("__tsdConsolePipe")) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
const isRootEntry = /<html[\s>]/i.test(code) || code.includes("StartClient") || code.includes("hydrateRoot") || code.includes("createRoot") || code.includes("solid-js/web") && code.includes("render(");
|
|
363
|
+
if (isRootEntry) {
|
|
364
|
+
const viteServerUrl = `http://localhost:${port}`;
|
|
365
|
+
const inlineCode = generateConsolePipeCode(
|
|
366
|
+
consolePipingLevels,
|
|
367
|
+
viteServerUrl
|
|
368
|
+
);
|
|
369
|
+
return `${inlineCode}
|
|
370
|
+
${code}`;
|
|
371
|
+
}
|
|
372
|
+
return void 0;
|
|
373
|
+
}
|
|
374
|
+
},
|
|
282
375
|
{
|
|
283
376
|
name: "@tanstack/devtools:better-console-logs",
|
|
284
377
|
enforce: "pre",
|
|
@@ -307,16 +400,32 @@ ${chalk.greenBright(`[@tanstack/devtools-vite]`)} Removed devtools code from: ${
|
|
|
307
400
|
}
|
|
308
401
|
},
|
|
309
402
|
{
|
|
310
|
-
name: "@tanstack/devtools:
|
|
403
|
+
name: "@tanstack/devtools:connection-injection",
|
|
311
404
|
apply(config, { command }) {
|
|
312
405
|
return config.mode === "development" && command === "serve";
|
|
313
406
|
},
|
|
314
407
|
transform(code, id) {
|
|
315
|
-
|
|
408
|
+
const hasPlaceholder = code.includes("__TANSTACK_DEVTOOLS_PORT__") || code.includes("__TANSTACK_DEVTOOLS_HOST__") || code.includes("__TANSTACK_DEVTOOLS_PROTOCOL__");
|
|
409
|
+
if (!hasPlaceholder) return;
|
|
316
410
|
if (!id.includes("@tanstack/devtools") && !id.includes("@tanstack/event-bus"))
|
|
317
411
|
return;
|
|
318
412
|
const portValue = devtoolsPort ?? 4206;
|
|
319
|
-
|
|
413
|
+
const hostValue = devtoolsHost ?? "localhost";
|
|
414
|
+
const protocolValue = devtoolsProtocol ?? "http";
|
|
415
|
+
let result = code;
|
|
416
|
+
result = result.replace(
|
|
417
|
+
/__TANSTACK_DEVTOOLS_PORT__/g,
|
|
418
|
+
String(portValue)
|
|
419
|
+
);
|
|
420
|
+
result = result.replace(
|
|
421
|
+
/__TANSTACK_DEVTOOLS_HOST__/g,
|
|
422
|
+
JSON.stringify(hostValue)
|
|
423
|
+
);
|
|
424
|
+
result = result.replace(
|
|
425
|
+
/__TANSTACK_DEVTOOLS_PROTOCOL__/g,
|
|
426
|
+
JSON.stringify(protocolValue)
|
|
427
|
+
);
|
|
428
|
+
return result;
|
|
320
429
|
}
|
|
321
430
|
}
|
|
322
431
|
];
|
package/dist/esm/plugin.js.map
CHANGED
|
@@ -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 { handleDevToolsViteRequest, readPackageJson } 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 type { Plugin } from 'vite'\nimport type { EditorConfig } from './editor'\nimport type { ServerEventBusConfig } from '@tanstack/devtools-event-bus/server'\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\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\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 server.middlewares.use((req, res, next) =>\n handleDevToolsViteRequest(req, res, next, (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 )\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 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 {\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":[],"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(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 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(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: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":";;;;;;;;;;;;AAsGO,MAAM,uBAAuB,CAAC,WACnC;AAEK,MAAM,WAAW,CAAC,SAAqD;AAC5E,MAAI,OAAO;AACX,QAAM,UAAU,MAAM,WAAW;AACjC,QAAM,qBAAqB,MAAM,gBAAgB,EAAE,SAAS,KAAA;AAC5D,QAAM,qBAAqB,MAAM,gBAAgB,EAAE,SAAS,KAAA;AAC5D,QAAM,wBAAwB,MAAM,yBAAyB;AAC7D,QAAM,mBAAmB,MAAM,gBAAgB,WAAW;AAC1D,QAAM,sBAAsB,MAAM,iBAAiB,EAAE,SAAS,KAAA;AAC9D,QAAM,sBACJ,oBAAoB,UAAU,CAAC,OAAO,QAAQ,SAAS,QAAQ,OAAO;AAExE,MAAI,iBAAgC;AACpC,MAAI,eAA8B;AAClC,MAAI,eAA8B;AAClC,MAAI,mBAA4C;AAEhD,SAAO;AAAA,IACL;AAAA,MACE,SAAS;AAAA,MACT,MAAM;AAAA,MACN,MAAM,QAAQ;AACZ,eAAO,OAAO,SAAS,iBAAiB,mBAAmB;AAAA,MAC7D;AAAA,MACA,UAAU,MAAM,IAAI;AAClB,YACE,GAAG,SAAS,cAAc,KAC1B,GAAG,SAAS,MAAM,KAClB,GAAG,SAAS,MAAM,KAClB,GAAG,SAAS,OAAO;AAEnB;AAEF,eAAO,eAAe,MAAM,IAAI,MAAM,cAAc,MAAM;AAAA,MAC5D;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAO,GAAG,EAAE,WAAW;AAErB,YAAI,YAAY,SAAS;AACvB;AAAA,QACF;AAAA,MAkBF;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,SAAS;AAAA,MACT,MAAM;AAAA,MACN,MAAM,QAAQ;AAEZ,eAAO,OAAO,SAAS;AAAA,MACzB;AAAA,MACA,MAAM,gBAAgB,QAAQ;AAC5B,YAAI,kBAAkB;AACpB,gBAAM,gBAAgB,MAAM,gBAAgB,QAAQ;AACpD,gBAAM,UAAU,CAAC,CAAC,OAAO,OAAO,OAAO;AACvC,gBAAM,aACJ,OAAO,OAAO,OAAO,OAAO,SAAS,WACjC,OAAO,OAAO,OAAO,OACrB;AAEN,6BAAmB,UAAU,UAAU;AACvC,yBAAe;AAEf,gBAAM,MAAM,IAAI,eAAe;AAAA,YAC7B,GAAG,MAAM;AAAA,YACT,MAAM;AAAA,YACN,MAAM;AAAA;AAAA;AAAA,YAGN,GAAI,WAAW,OAAO,aAClB,EAAE,YAAY,OAAO,eACrB,CAAA;AAAA,UAAC,CACN;AAED,yBAAe,MAAM,IAAI,MAAA;AAAA,QAC3B;AAEA,eAAO,YAAY,IAAI,CAAC,KAAK,MAAM,SAAS;AAC1C,cAAI,IAAI,OAAO,aAAa,IAAI,OAAO,cAAc,MAAM;AACzD,mBAAO,IAAI,OAAO;AAAA,UACpB;AACA,eAAA;AAAA,QACF,CAAC;AACD,YAAI,OAAO,OAAO,OAAO,MAAM;AAC7B,iBAAO,OAAO,OAAO,OAAO;AAAA,QAC9B;AAEA,eAAO,YAAY,GAAG,aAAa,MAAM;AACvC,iBAAO,OAAO,OAAO,OAAO;AAAA,QAC9B,CAAC;AAED,cAAM,SAAS,MAAM,UAAU;AAC/B,cAAM,eAAqC,OACzC,MACA,SACA,cACG;AACH,cAAI,CAAC,MAAM;AACT;AAAA,UACF;AACA,gBAAM,OAAO,KAAK,MAAM,SAAS,SAAS;AAAA,QAC5C;AAGA,cAAM,aAGD,CAAA;AACL,YAAI,cAAc;AAClB,cAAM,uBAAuB,oBAAoB,WAAW;AAE5D,eAAO,YAAY;AAAA,UAAI,CAAC,KAAK,KAAK,SAChC,0BAA0B,KAAK,KAAK,MAAM;AAAA,YACxC,cAAc,CAAC,eAAe;AAC5B,oBAAM,EAAE,MAAM,QAAA,IAAY;AAC1B,kBAAI,YAAY,eAAe;AAC7B,uBAAO,iBAAiB;AAAA,kBACtB,MAAM,EAAE,MAAM,KAAK,MAAM,KAAA;AAAA,kBACzB;AAAA,gBAAA,CACD;AAAA,cACH;AACA;AAAA,YACF;AAAA,YACA,GAAI,uBACA;AAAA,cACE,eAAe,CAAC,YAAY;AAC1B,2BAAW,SAAS,SAAS;AAC3B,wBAAM,SAAS,MAAM,KAAK,UAAU;AACpC,wBAAM,YAAY,QAAQ,MAAM,KAAqB;AACrD,wBAAM,cAAc;AAAA,oBAClB,MAAM;AAAA,oBACN,CAAC,QAAQ,MAAM,KAAK,GAAG;AAAA,kBAAA;AAEzB,4BAAU,QAAQ,GAAG,WAAW;AAAA,gBAClC;AAAA,cACF;AAAA,cACA,kBAAkB,CAACA,MAAKC,SAAQ;AAC9BD,qBAAI,UAAU,gBAAgB,mBAAmB;AACjDA,qBAAI,UAAU,iBAAiB,UAAU;AACzCA,qBAAI,UAAU,cAAc,YAAY;AACxCA,qBAAI,UAAU,+BAA+B,GAAG;AAChDA,qBAAI,aAAA;AAEJ,sBAAM,WAAW,EAAE;AACnB,2BAAW,KAAK,EAAE,KAAAA,MAAK,IAAI,UAAU;AAErCC,qBAAI,GAAG,SAAS,MAAM;AACpB,wBAAM,QAAQ,WAAW;AAAA,oBACvB,CAAC,MAAM,EAAE,OAAO;AAAA,kBAAA;AAElB,sBAAI,UAAU,IAAI;AAChB,+BAAW,OAAO,OAAO,CAAC;AAAA,kBAC5B;AAAA,gBACF,CAAC;AAAA,cACH;AAAA,cACA,qBAAqB,CAAC,YAAY;AAChC,oBAAI;AACF,wBAAM,OAAO,KAAK,UAAU;AAAA,oBAC1B,SAAS,QAAQ,IAAI,CAAC,OAAO;AAAA,sBAC3B,OAAO,EAAE;AAAA,sBACT,MAAM,EAAE;AAAA,sBACR,QAAQ;AAAA,sBACR,WAAW,EAAE,aAAa,KAAK,IAAA;AAAA,oBAAI,EACnC;AAAA,kBAAA,CACH;AAED,6BAAW,UAAU,YAAY;AAC/B,2BAAO,IAAI,MAAM,SAAS,IAAI;AAAA;AAAA,CAAM;AAAA,kBACtC;AAAA,gBACF,QAAQ;AAAA,gBAAC;AAAA,cACX;AAAA,YAAA,IAEF,CAAA;AAAA,UAAC,CACN;AAAA,QAAA;AAAA,MAEL;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,MAAM;AAAA,MACN,MAAM,QAAQ,EAAE,WAAW;AAIzB,gBACG,YAAY,WAAW,OAAO,SAAS,iBACxC;AAAA,MAEJ;AAAA,MACA,SAAS;AAAA,MACT,UAAU,MAAM,IAAI;AAClB,cAAM,kBAAkB;AAAA,UACtB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QAAA;AAEF,YACE,GAAG,SAAS,cAAc,KAC1B,GAAG,SAAS,MAAM,KAClB,CAAC,gBAAgB,KAAK,CAAC,QAAQ,KAAK,SAAS,GAAG,CAAC;AAEjD;AACF,cAAM,YAAY,eAAe,MAAM,EAAE;AACzC,YAAI,CAAC,UAAW;AAChB,YAAI,SAAS;AACX,kBAAQ;AAAA,YACN;AAAA,EAAK,MAAM,YAAY,2BAA2B,CAAC,gCAAgC,GAAG,QAAQ,cAAc,QAAQ,IAAA,CAAK,GAAG,EAAE,CAAC;AAAA;AAAA,UAAA;AAAA,QAEnI;AACA,eAAO;AAAA,MACT;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,MAAM;AAAA,MACN,MAAM,QAAQ,EAAE,WAAW;AACzB,YACE,QAAQ,IAAI,MACZ,QAAQ,IAAI,aAAa,iBACzB,YAAY;AAEZ,iBAAO;AACT,eAAO,OAAO,SAAS;AAAA,MACzB;AAAA,MACA,MAAM,kBAAkB;AACtB,cAAM,cAAc,MAAM,gBAAA;AAC1B,cAAM,eAAe,iBAAA,EAAmB,KAAK,CAAC,SAAS,IAAI;AAG3D,4BAAoB,GAAG,oBAAoB,OAAO,UAAU;AAC1D,gBAAM,SAAS,MAAM,eAAe,MAAM,QAAQ,WAAW;AAC7D,8BAAoB,KAAK,sBAAsB;AAAA,YAC7C,aAAa,MAAM,QAAQ;AAAA,YAC3B,SAAS,OAAO;AAAA,YAChB,OAAO,OAAO;AAAA,UAAA,CACf;AAGD,cAAI,OAAO,SAAS;AAClB,kBAAM,EAAE,aAAa,YAAY,aAAA,IAAiB,MAAM;AAExD,oBAAQ;AAAA,cACN,MAAM;AAAA,gBACJ,yCAAyC,WAAW;AAAA,cAAA;AAAA,YACtD;AAGF,kBAAM,eAAe;AAAA,cACnB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YAAA;AAGF,gBAAI,aAAa,SAAS;AAExB,kCAAoB,KAAK,gBAAgB;AAAA,gBACvC;AAAA,gBACA,SAAS;AAAA,cAAA,CACV;AAGD,oBAAM,qBAAqB,MAAM,gBAAA;AACjC,kCAAoB,KAAK,qBAAqB;AAAA,gBAC5C,aAAa;AAAA,cAAA,CACd;AAAA,YACH;AAAA,UACF;AAAA,QACF,CAAC;AAGD,4BAAoB,GAAG,0BAA0B,CAAC,UAAU;AAC1D,gBAAM,EAAE,aAAa,YAAY,aAAA,IAAiB,MAAM;AAExD,kBAAQ;AAAA,YACN,MAAM;AAAA,cACJ,oCAAoC,WAAW;AAAA,YAAA;AAAA,UACjD;AAGF,gBAAM,SAAS;AAAA,YACb;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAGF,8BAAoB,KAAK,gBAAgB;AAAA,YACvC;AAAA,YACA,SAAS,OAAO;AAAA,YAChB,OAAO,OAAO;AAAA,UAAA,CACf;AAAA,QACH,CAAC;AAGD,4BAAoB,GAAG,wBAAwB,OAAO,UAAU;AAC9D,gBAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA,IACE,MAAM;AAEV,kBAAQ;AAAA,YACN,MAAM;AAAA,cACJ,qCAAqC,WAAW,eAAe,UAAU;AAAA,YAAA;AAAA,UAC3E;AAIF,gBAAM,qBAAqB,aACvB,GAAG,WAAW,KAAK,UAAU,KAC7B;AAEJ,gBAAM,SAAS,MAAM,eAAe,kBAAkB;AAEtD,cAAI,CAAC,OAAO,SAAS;AACnB,oBAAQ;AAAA,cACN,MAAM;AAAA,gBACJ,4CAA4C,WAAW,KAAK,OAAO,KAAK;AAAA,cAAA;AAAA,YAC1E;AAEF,gCAAoB,KAAK,sBAAsB;AAAA,cAC7C,aAAa;AAAA,cACb,SAAS;AAAA,cACT,OAAO,OAAO;AAAA,YAAA,CACf;AACD;AAAA,UACF;AAEA,kBAAQ;AAAA,YACN,MAAM;AAAA,cACJ,iDAAiD,WAAW,OAAO,UAAU;AAAA,YAAA;AAAA,UAC/E;AAIF,cAAI,CAAC,gBAAgB;AACnB,oBAAQ;AAAA,cACN,MAAM;AAAA,gBACJ;AAAA,cAAA;AAAA,YACF;AAEF,gCAAoB,KAAK,sBAAsB;AAAA,cAC7C,aAAa;AAAA,cACb,SAAS;AAAA,YAAA,CACV;AACD;AAAA,UACF;AAGA,kBAAQ;AAAA,YACN,MAAM;AAAA,cACJ,oCAAoC,eAAe;AAAA,YAAA;AAAA,UACrD;AAGF,gBAAM,eAAe,qBAAqB,gBAAgB;AAAA,YACxD,aAAa;AAAA,YACb;AAAA,YACA;AAAA,UAAA,CACD;AAED,cAAI,aAAa,SAAS;AACxB,oBAAQ;AAAA,cACN,MAAM;AAAA,gBACJ,gDAAgD,eAAe;AAAA,cAAA;AAAA,YACjE;AAGF,gCAAoB,KAAK,gBAAgB;AAAA,cACvC,aAAa;AAAA,cACb,SAAS;AAAA,YAAA,CACV;AAGD,kBAAM,qBAAqB,MAAM,gBAAA;AACjC,gCAAoB,KAAK,qBAAqB;AAAA,cAC5C,aAAa;AAAA,YAAA,CACd;AAAA,UACH,OAAO;AACL,oBAAQ;AAAA,cACN,MAAM;AAAA,gBACJ,2CAA2C,eAAe,iBAAiB,aAAa,KAAK;AAAA,cAAA;AAAA,YAC/F;AAGF,gCAAoB,KAAK,gBAAgB;AAAA,cACvC,aAAa;AAAA,cACb,SAAS;AAAA,cACT,OAAO,aAAa;AAAA,YAAA,CACrB;AAAA,UACH;AAAA,QACF,CAAC;AAGD,4BAAoB,GAAG,WAAW,YAAY;AAC5C,8BAAoB,KAAK,sBAAsB;AAAA,YAC7C,cAAc,MAAM;AAAA,UAAA,CACrB;AACD,8BAAoB,KAAK,qBAAqB;AAAA,YAC5C;AAAA,UAAA,CACD;AAAA,QACH,CAAC;AAAA,MAGH;AAAA,MACA,MAAM,gBAAgB,EAAE,QAAQ;AAC9B,YAAI,KAAK,SAAS,cAAc,GAAG;AACjC,gBAAM,iBAAiB,MAAM,gBAAA;AAC7B,8BAAoB,KAAK,qBAAqB;AAAA,YAC5C,aAAa;AAAA,UAAA,CACd;AACD,2BAAA;AAAA,QACF;AAAA,MACF;AAAA,IAAA;AAAA;AAAA,IAGF;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM,QAAQ,EAAE,WAAW;AACzB,eACE,OAAO,SAAS,iBAChB,YAAY,YACX,oBAAoB,WAAW;AAAA,MAEpC;AAAA,MACA,UAAU,MAAM,IAAI;AAElB,YACE,GAAG,SAAS,cAAc,KAC1B,GAAG,SAAS,MAAM,KAClB,GAAG,SAAS,GAAG,KACf,CAAC,GAAG,MAAM,gBAAgB,GAC1B;AACA;AAAA,QACF;AAGA,YAAI,KAAK,SAAS,kBAAkB,GAAG;AACrC;AAAA,QACF;AAKA,cAAM,cACJ,cAAc,KAAK,IAAI,KACvB,KAAK,SAAS,aAAa,KAC3B,KAAK,SAAS,aAAa,KAC3B,KAAK,SAAS,YAAY,KACzB,KAAK,SAAS,cAAc,KAAK,KAAK,SAAS,SAAS;AAE3D,YAAI,aAAa;AACf,gBAAM,gBAAgB,oBAAoB,IAAI;AAC9C,gBAAM,aAAa;AAAA,YACjB;AAAA,YACA;AAAA,UAAA;AAGF,iBAAO,GAAG,UAAU;AAAA,EAAK,IAAI;AAAA,QAC/B;AAEA,eAAO;AAAA,MACT;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM,QAAQ;AACZ,eAAO,OAAO,SAAS,iBAAiB,mBAAmB;AAAA,MAC7D;AAAA,MACA,UAAU,MAAM,IAAI;AAElB,YACE,GAAG,SAAS,cAAc,KAC1B,GAAG,SAAS,MAAM,KAClB,GAAG,SAAS,MAAM,KAClB,GAAG,SAAS,OAAO,KACnB,CAAC,KAAK,SAAS,UAAU;AAEzB;AAEF,eAAO,kBAAkB,MAAM,IAAI,IAAI;AAAA,MACzC;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,MAAM;AAAA,MACN,MAAM,QAAQ,EAAE,WAAW;AACzB,eAAO,OAAO,SAAS,iBAAiB,YAAY;AAAA,MACtD;AAAA,MACA,UAAU,MAAM,IAAI;AAElB,YAAI,CAAC,kBAAkB,mBAAmB,IAAI,GAAG;AAE/C,gBAAM,CAAC,QAAQ,IAAI,GAAG,MAAM,GAAG;AAC/B,cAAI,UAAU;AACZ,6BAAiB;AAAA,UACnB;AAAA,QACF;AAEA,eAAO;AAAA,MACT;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,MAAM;AAAA,MACN,MAAM,QAAQ,EAAE,WAAW;AACzB,eAAO,OAAO,SAAS,iBAAiB,YAAY;AAAA,MACtD;AAAA,MACA,UAAU,MAAM,IAAI;AAElB,cAAM,iBACJ,KAAK,SAAS,4BAA4B,KAC1C,KAAK,SAAS,4BAA4B,KAC1C,KAAK,SAAS,gCAAgC;AAChD,YAAI,CAAC,eAAgB;AACrB,YACE,CAAC,GAAG,SAAS,oBAAoB,KACjC,CAAC,GAAG,SAAS,qBAAqB;AAElC;AAGF,cAAM,YAAY,gBAAgB;AAClC,cAAM,YAAY,gBAAgB;AAClC,cAAM,gBAAgB,oBAAoB;AAE1C,YAAI,SAAS;AACb,iBAAS,OAAO;AAAA,UACd;AAAA,UACA,OAAO,SAAS;AAAA,QAAA;AAElB,iBAAS,OAAO;AAAA,UACd;AAAA,UACA,KAAK,UAAU,SAAS;AAAA,QAAA;AAE1B,iBAAS,OAAO;AAAA,UACd;AAAA,UACA,KAAK,UAAU,aAAa;AAAA,QAAA;AAE9B,eAAO;AAAA,MACT;AAAA,IAAA;AAAA,EACF;AAEJ;"}
|
package/dist/esm/utils.d.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { Connect } from 'vite';
|
|
2
2
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
3
3
|
import { PackageJson } from '@tanstack/devtools-client';
|
|
4
|
-
|
|
4
|
+
type DevToolsRequestHandler = (data: any) => void;
|
|
5
|
+
type DevToolsViteRequestOptions = {
|
|
6
|
+
onOpenSource?: DevToolsRequestHandler;
|
|
7
|
+
onConsolePipe?: (entries: Array<any>) => void;
|
|
8
|
+
onServerConsolePipe?: (entries: Array<any>) => void;
|
|
9
|
+
onConsolePipeSSE?: (res: ServerResponse<IncomingMessage>, req: Connect.IncomingMessage) => void;
|
|
10
|
+
};
|
|
11
|
+
export declare const handleDevToolsViteRequest: (req: Connect.IncomingMessage, res: ServerResponse<IncomingMessage>, next: Connect.NextFunction, cbOrOptions: DevToolsRequestHandler | DevToolsViteRequestOptions) => void;
|
|
5
12
|
export declare const parseOpenSourceParam: (source: string) => {
|
|
6
13
|
file: string | undefined;
|
|
7
14
|
line: string | undefined;
|
|
@@ -9,3 +16,16 @@ export declare const parseOpenSourceParam: (source: string) => {
|
|
|
9
16
|
} | null;
|
|
10
17
|
export declare const tryParseJson: <T extends any>(jsonString: string | null | undefined) => T | null;
|
|
11
18
|
export declare const readPackageJson: () => Promise<PackageJson | null>;
|
|
19
|
+
/**
|
|
20
|
+
* Extracts and formats the source location from enhanced client console logs.
|
|
21
|
+
* Instead of stripping the prefix entirely, we extract the file:line:column
|
|
22
|
+
* from the "Go to Source" URL and use that as a prefix.
|
|
23
|
+
*
|
|
24
|
+
* Enhanced logs format (two variants):
|
|
25
|
+
* 1. ['%cLOG%c %cGo to Source: http://...?source=%2Fsrc%2F...%c \n → ', 'color:...', 'color:...', 'color:...', 'color:...', 'message']
|
|
26
|
+
* 2. ['\x1b[...]%s\x1b[...]', '%cLOG%c %cGo to Source: ...%c \n → ', 'color:...', 'color:...', 'color:...', 'color:...', 'message']
|
|
27
|
+
*
|
|
28
|
+
* Output: ['src/components/Header.tsx:26:13', 'message']
|
|
29
|
+
*/
|
|
30
|
+
export declare const stripEnhancedLogPrefix: (args: Array<unknown>, formatSourceLocation?: (location: string) => unknown) => Array<unknown>;
|
|
31
|
+
export {};
|
package/dist/esm/utils.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import { normalizePath } from "vite";
|
|
3
|
-
const handleDevToolsViteRequest = (req, res, next,
|
|
3
|
+
const handleDevToolsViteRequest = (req, res, next, cbOrOptions) => {
|
|
4
|
+
const options = typeof cbOrOptions === "function" ? { onOpenSource: cbOrOptions } : cbOrOptions;
|
|
4
5
|
if (req.url?.includes("__tsd/open-source")) {
|
|
5
6
|
const searchParams = new URLSearchParams(req.url.split("?")[1]);
|
|
6
7
|
const source = searchParams.get("source");
|
|
@@ -12,7 +13,7 @@ const handleDevToolsViteRequest = (req, res, next, cb) => {
|
|
|
12
13
|
return;
|
|
13
14
|
}
|
|
14
15
|
const { file, line, column } = parsed;
|
|
15
|
-
|
|
16
|
+
options.onOpenSource?.({
|
|
16
17
|
type: "open-source",
|
|
17
18
|
routine: "open-source",
|
|
18
19
|
data: {
|
|
@@ -26,6 +27,55 @@ const handleDevToolsViteRequest = (req, res, next, cb) => {
|
|
|
26
27
|
res.end();
|
|
27
28
|
return;
|
|
28
29
|
}
|
|
30
|
+
if (req.url?.includes("__tsd/console-pipe/sse") && req.method === "GET") {
|
|
31
|
+
if (options.onConsolePipeSSE) {
|
|
32
|
+
options.onConsolePipeSSE(res, req);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
return next();
|
|
36
|
+
}
|
|
37
|
+
if (req.url?.includes("__tsd/console-pipe/server") && req.method === "POST") {
|
|
38
|
+
if (options.onServerConsolePipe) {
|
|
39
|
+
let body = "";
|
|
40
|
+
req.on("data", (chunk) => {
|
|
41
|
+
body += chunk.toString();
|
|
42
|
+
});
|
|
43
|
+
req.on("end", () => {
|
|
44
|
+
try {
|
|
45
|
+
const { entries } = JSON.parse(body);
|
|
46
|
+
options.onServerConsolePipe(entries);
|
|
47
|
+
res.statusCode = 200;
|
|
48
|
+
res.end("OK");
|
|
49
|
+
} catch {
|
|
50
|
+
res.statusCode = 400;
|
|
51
|
+
res.end("Bad Request");
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
return next();
|
|
57
|
+
}
|
|
58
|
+
if (req.url?.includes("__tsd/console-pipe") && req.method === "POST") {
|
|
59
|
+
if (options.onConsolePipe) {
|
|
60
|
+
let body = "";
|
|
61
|
+
req.on("data", (chunk) => {
|
|
62
|
+
body += chunk.toString();
|
|
63
|
+
});
|
|
64
|
+
req.on("end", () => {
|
|
65
|
+
try {
|
|
66
|
+
const { entries } = JSON.parse(body);
|
|
67
|
+
options.onConsolePipe(entries);
|
|
68
|
+
res.statusCode = 200;
|
|
69
|
+
res.end("OK");
|
|
70
|
+
} catch {
|
|
71
|
+
res.statusCode = 400;
|
|
72
|
+
res.end("Bad Request");
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
return next();
|
|
78
|
+
}
|
|
29
79
|
if (!req.url?.includes("__tsd")) {
|
|
30
80
|
return next();
|
|
31
81
|
}
|
|
@@ -37,10 +87,11 @@ const handleDevToolsViteRequest = (req, res, next, cb) => {
|
|
|
37
87
|
const dataToParse = Buffer.concat(chunks);
|
|
38
88
|
try {
|
|
39
89
|
const parsedData = JSON.parse(dataToParse.toString());
|
|
40
|
-
|
|
90
|
+
options.onOpenSource?.(parsedData);
|
|
41
91
|
} catch (e) {
|
|
42
92
|
}
|
|
43
93
|
res.write("OK");
|
|
94
|
+
res.end();
|
|
44
95
|
});
|
|
45
96
|
};
|
|
46
97
|
const parseOpenSourceParam = (source) => {
|
|
@@ -69,10 +120,49 @@ const tryParseJson = (jsonString) => {
|
|
|
69
120
|
}
|
|
70
121
|
};
|
|
71
122
|
const readPackageJson = async () => tryParseJson(await tryReadFile(process.cwd() + "/package.json"));
|
|
123
|
+
const stripEnhancedLogPrefix = (args, formatSourceLocation) => {
|
|
124
|
+
if (args.length === 0) return args;
|
|
125
|
+
let sourceArgIndex = -1;
|
|
126
|
+
for (let i = 0; i < args.length; i++) {
|
|
127
|
+
const arg = args[i];
|
|
128
|
+
if (typeof arg === "string" && arg.includes("__tsd/open-source?source=")) {
|
|
129
|
+
sourceArgIndex = i;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (sourceArgIndex === -1) {
|
|
134
|
+
return args;
|
|
135
|
+
}
|
|
136
|
+
const sourceArg = args[sourceArgIndex];
|
|
137
|
+
let sourceLocation = "";
|
|
138
|
+
const sourceMatch = sourceArg.match(/source=([^&\s]+?)%c/);
|
|
139
|
+
if (sourceMatch?.[1]) {
|
|
140
|
+
try {
|
|
141
|
+
sourceLocation = decodeURIComponent(sourceMatch[1]);
|
|
142
|
+
if (sourceLocation.startsWith("/")) {
|
|
143
|
+
sourceLocation = sourceLocation.slice(1);
|
|
144
|
+
}
|
|
145
|
+
} catch {
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const styleCount = (sourceArg.match(/%c/g) || []).length;
|
|
149
|
+
const userArgsStart = sourceArgIndex + 1 + styleCount;
|
|
150
|
+
const result = [];
|
|
151
|
+
if (sourceLocation) {
|
|
152
|
+
result.push(
|
|
153
|
+
formatSourceLocation ? formatSourceLocation(sourceLocation) : sourceLocation
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
for (let i = userArgsStart; i < args.length; i++) {
|
|
157
|
+
result.push(args[i]);
|
|
158
|
+
}
|
|
159
|
+
return result.length > 0 ? result : args;
|
|
160
|
+
};
|
|
72
161
|
export {
|
|
73
162
|
handleDevToolsViteRequest,
|
|
74
163
|
parseOpenSourceParam,
|
|
75
164
|
readPackageJson,
|
|
165
|
+
stripEnhancedLogPrefix,
|
|
76
166
|
tryParseJson
|
|
77
167
|
};
|
|
78
168
|
//# sourceMappingURL=utils.js.map
|
package/dist/esm/utils.js.map
CHANGED
|
@@ -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\nexport const handleDevToolsViteRequest = (\n req: Connect.IncomingMessage,\n res: ServerResponse<IncomingMessage>,\n next: Connect.NextFunction,\n cb: (data: any) => void,\n) => {\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 cb({\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 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 cb(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"],"names":[],"mappings":";;AAMO,MAAM,4BAA4B,CACvC,KACA,KACA,MACA,OACG;AACH,MAAI,IAAI,KAAK,SAAS,mBAAmB,GAAG;AAC1C,UAAM,eAAe,IAAI,gBAAgB,IAAI,IAAI,MAAM,GAAG,EAAE,CAAC,CAAC;AAE9D,UAAM,SAAS,aAAa,IAAI,QAAQ;AACxC,QAAI,CAAC,QAAQ;AACX;AAAA,IACF;AAEA,UAAM,SAAS,qBAAqB,MAAM;AAC1C,QAAI,CAAC,QAAQ;AACX;AAAA,IACF;AACA,UAAM,EAAE,MAAM,MAAM,OAAA,IAAW;AAE/B,OAAG;AAAA,MACD,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,QACJ,QAAQ,OAAO,cAAc,GAAG,QAAQ,KAAK,IAAI,IAAI,EAAE,IAAI;AAAA,QAC3D;AAAA,QACA;AAAA,MAAA;AAAA,IACF,CACD;AACD,QAAI,UAAU,gBAAgB,WAAW;AACzC,QAAI,MAAM,qCAAoC;AAC9C,QAAI,IAAA;AACJ;AAAA,EACF;AACA,MAAI,CAAC,IAAI,KAAK,SAAS,OAAO,GAAG;AAC/B,WAAO,KAAA;AAAA,EACT;AAEA,QAAM,SAAqB,CAAA;AAC3B,MAAI,GAAG,QAAQ,CAAC,UAAU;AACxB,WAAO,KAAK,KAAK;AAAA,EACnB,CAAC;AACD,MAAI,GAAG,OAAO,MAAM;AAClB,UAAM,cAAc,OAAO,OAAO,MAAM;AACxC,QAAI;AACF,YAAM,aAAa,KAAK,MAAM,YAAY,UAAU;AACpD,SAAG,UAAU;AAAA,IACf,SAAS,GAAG;AAAA,IAAC;AACb,QAAI,MAAM,IAAI;AAAA,EAChB,CAAC;AACH;AAEO,MAAM,uBAAuB,CAAC,WAAmB;AAGtD,QAAM,QAAQ,OAAO,MAAM,oBAAoB;AAE/C,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,GAAG,MAAM,MAAM,MAAM,IAAI;AAC/B,SAAO,EAAE,MAAM,MAAM,OAAA;AACvB;AAEA,MAAM,cAAc,OAAO,aAAqB;AAC9C,MAAI;AACF,UAAM,OAAO,MAAM,GAAG,SAAS,UAAU,OAAO;AAChD,WAAO;AAAA,EACT,SAAS,OAAO;AACd,WAAO;AAAA,EACT;AACF;AAEO,MAAM,eAAe,CAC1B,eACG;AACH,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,UAAU;AACpC,WAAO;AAAA,EACT,SAAS,OAAO;AACd,WAAO;AAAA,EACT;AACF;AAEO,MAAM,kBAAkB,YAC7B,aAA0B,MAAM,YAAY,QAAQ,IAAA,IAAQ,eAAe,CAAC;"}
|
|
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":";;AAkBO,MAAM,4BAA4B,CACvC,KACA,KACA,MACA,gBACG;AAEH,QAAM,UACJ,OAAO,gBAAgB,aACnB,EAAE,cAAc,gBAChB;AAGN,MAAI,IAAI,KAAK,SAAS,mBAAmB,GAAG;AAC1C,UAAM,eAAe,IAAI,gBAAgB,IAAI,IAAI,MAAM,GAAG,EAAE,CAAC,CAAC;AAE9D,UAAM,SAAS,aAAa,IAAI,QAAQ;AACxC,QAAI,CAAC,QAAQ;AACX;AAAA,IACF;AAEA,UAAM,SAAS,qBAAqB,MAAM;AAC1C,QAAI,CAAC,QAAQ;AACX;AAAA,IACF;AACA,UAAM,EAAE,MAAM,MAAM,OAAA,IAAW;AAE/B,YAAQ,eAAe;AAAA,MACrB,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,QACJ,QAAQ,OAAO,cAAc,GAAG,QAAQ,KAAK,IAAI,IAAI,EAAE,IAAI;AAAA,QAC3D;AAAA,QACA;AAAA,MAAA;AAAA,IACF,CACD;AACD,QAAI,UAAU,gBAAgB,WAAW;AACzC,QAAI,MAAM,qCAAoC;AAC9C,QAAI,IAAA;AACJ;AAAA,EACF;AAGA,MAAI,IAAI,KAAK,SAAS,wBAAwB,KAAK,IAAI,WAAW,OAAO;AACvE,QAAI,QAAQ,kBAAkB;AAC5B,cAAQ,iBAAiB,KAAK,GAAG;AACjC;AAAA,IACF;AACA,WAAO,KAAA;AAAA,EACT;AAGA,MAAI,IAAI,KAAK,SAAS,2BAA2B,KAAK,IAAI,WAAW,QAAQ;AAC3E,QAAI,QAAQ,qBAAqB;AAC/B,UAAI,OAAO;AACX,UAAI,GAAG,QAAQ,CAAC,UAAkB;AAChC,gBAAQ,MAAM,SAAA;AAAA,MAChB,CAAC;AACD,UAAI,GAAG,OAAO,MAAM;AAClB,YAAI;AACF,gBAAM,EAAE,QAAA,IAAY,KAAK,MAAM,IAAI;AACnC,kBAAQ,oBAAqB,OAAO;AACpC,cAAI,aAAa;AACjB,cAAI,IAAI,IAAI;AAAA,QACd,QAAQ;AACN,cAAI,aAAa;AACjB,cAAI,IAAI,aAAa;AAAA,QACvB;AAAA,MACF,CAAC;AACD;AAAA,IACF;AACA,WAAO,KAAA;AAAA,EACT;AAGA,MAAI,IAAI,KAAK,SAAS,oBAAoB,KAAK,IAAI,WAAW,QAAQ;AACpE,QAAI,QAAQ,eAAe;AACzB,UAAI,OAAO;AACX,UAAI,GAAG,QAAQ,CAAC,UAAkB;AAChC,gBAAQ,MAAM,SAAA;AAAA,MAChB,CAAC;AACD,UAAI,GAAG,OAAO,MAAM;AAClB,YAAI;AACF,gBAAM,EAAE,QAAA,IAAY,KAAK,MAAM,IAAI;AACnC,kBAAQ,cAAe,OAAO;AAC9B,cAAI,aAAa;AACjB,cAAI,IAAI,IAAI;AAAA,QACd,QAAQ;AACN,cAAI,aAAa;AACjB,cAAI,IAAI,aAAa;AAAA,QACvB;AAAA,MACF,CAAC;AACD;AAAA,IACF;AACA,WAAO,KAAA;AAAA,EACT;AAEA,MAAI,CAAC,IAAI,KAAK,SAAS,OAAO,GAAG;AAC/B,WAAO,KAAA;AAAA,EACT;AAEA,QAAM,SAAqB,CAAA;AAC3B,MAAI,GAAG,QAAQ,CAAC,UAAU;AACxB,WAAO,KAAK,KAAK;AAAA,EACnB,CAAC;AACD,MAAI,GAAG,OAAO,MAAM;AAClB,UAAM,cAAc,OAAO,OAAO,MAAM;AACxC,QAAI;AACF,YAAM,aAAa,KAAK,MAAM,YAAY,UAAU;AACpD,cAAQ,eAAe,UAAU;AAAA,IACnC,SAAS,GAAG;AAAA,IAAC;AACb,QAAI,MAAM,IAAI;AACd,QAAI,IAAA;AAAA,EACN,CAAC;AACH;AAEO,MAAM,uBAAuB,CAAC,WAAmB;AAGtD,QAAM,QAAQ,OAAO,MAAM,oBAAoB;AAE/C,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,GAAG,MAAM,MAAM,MAAM,IAAI;AAC/B,SAAO,EAAE,MAAM,MAAM,OAAA;AACvB;AAEA,MAAM,cAAc,OAAO,aAAqB;AAC9C,MAAI;AACF,UAAM,OAAO,MAAM,GAAG,SAAS,UAAU,OAAO;AAChD,WAAO;AAAA,EACT,SAAS,OAAO;AACd,WAAO;AAAA,EACT;AACF;AAEO,MAAM,eAAe,CAC1B,eACG;AACH,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,UAAU;AACpC,WAAO;AAAA,EACT,SAAS,OAAO;AACd,WAAO;AAAA,EACT;AACF;AAEO,MAAM,kBAAkB,YAC7B,aAA0B,MAAM,YAAY,QAAQ,IAAA,IAAQ,eAAe,CAAC;AAavE,MAAM,yBAAyB,CACpC,MACA,yBACmB;AACnB,MAAI,KAAK,WAAW,EAAG,QAAO;AAG9B,MAAI,iBAAiB;AACrB,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,OAAO,QAAQ,YAAY,IAAI,SAAS,2BAA2B,GAAG;AACxE,uBAAiB;AACjB;AAAA,IACF;AAAA,EACF;AAGA,MAAI,mBAAmB,IAAI;AACzB,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,KAAK,cAAc;AAKrC,MAAI,iBAAiB;AACrB,QAAM,cAAc,UAAU,MAAM,qBAAqB;AACzD,MAAI,cAAc,CAAC,GAAG;AACpB,QAAI;AACF,uBAAiB,mBAAmB,YAAY,CAAC,CAAC;AAElD,UAAI,eAAe,WAAW,GAAG,GAAG;AAClC,yBAAiB,eAAe,MAAM,CAAC;AAAA,MACzC;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,QAAM,cAAc,UAAU,MAAM,KAAK,KAAK,CAAA,GAAI;AAGlD,QAAM,gBAAgB,iBAAiB,IAAI;AAG3C,QAAM,SAAyB,CAAA;AAG/B,MAAI,gBAAgB;AAClB,WAAO;AAAA,MACL,uBACI,qBAAqB,cAAc,IACnC;AAAA,IAAA;AAAA,EAER;AAGA,WAAS,IAAI,eAAe,IAAI,KAAK,QAAQ,KAAK;AAChD,WAAO,KAAK,KAAK,CAAC,CAAC;AAAA,EACrB;AAEA,SAAO,OAAO,SAAS,IAAI,SAAS;AACtC;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ConsoleLevel } from './plugin.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generates inline code to inject into entry files (both client and server).
|
|
4
|
+
* This code detects the environment at runtime and:
|
|
5
|
+
*
|
|
6
|
+
* CLIENT:
|
|
7
|
+
* 1. Store original console methods
|
|
8
|
+
* 2. Create batched wrappers that POST to server via fetch
|
|
9
|
+
* 3. Override global console with the wrapped methods
|
|
10
|
+
* 4. Listen for server console logs via SSE
|
|
11
|
+
*
|
|
12
|
+
* SERVER (Nitro/Vinxi runtime):
|
|
13
|
+
* 1. Store original console methods
|
|
14
|
+
* 2. Create batched wrappers that POST to Vite dev server
|
|
15
|
+
* 3. Override global console - original logging still happens, just also pipes to Vite
|
|
16
|
+
*
|
|
17
|
+
* Returns the inline code as a string - no imports needed since we use fetch.
|
|
18
|
+
*/
|
|
19
|
+
export declare function generateConsolePipeCode(levels: Array<ConsoleLevel>, viteServerUrl: string): string;
|