tidewave 0.5.4 → 0.6.0
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/CHANGELOG.md +10 -0
- package/README.md +67 -17
- package/dist/cli/index.js +84 -80
- package/dist/logger/console-patch.d.ts +5 -0
- package/dist/logger/tidewave-log-record-processor.d.ts +1 -1
- package/dist/logger/tidewave-logger.d.ts +37 -0
- package/dist/logger/tidewave-span-processor.d.ts +2 -2
- package/dist/next-js/handler.js +84 -271
- package/dist/next-js/instrumentation.d.ts +2 -7
- package/dist/next-js/instrumentation.js +118 -117
- package/dist/tanstack.d.ts +1 -0
- package/dist/tanstack.js +163 -0
- package/dist/tools.d.ts +3 -3
- package/dist/vite-plugin.d.ts +0 -1
- package/dist/vite-plugin.js +84 -271
- package/package.json +12 -4
- package/dist/http/handlers/shell.d.ts +0 -6
- package/dist/logger/circular-buffer.d.ts +0 -54
- package/dist/logger/instrumentation.d.ts +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.0] - 2025-12-31
|
|
4
|
+
|
|
5
|
+
* Tanstack support
|
|
6
|
+
* Write logs and instrumentation to a file so it works across multiple runtimes
|
|
7
|
+
|
|
8
|
+
## [0.5.5] - 2025-11-25
|
|
9
|
+
|
|
10
|
+
* Fix missing items element on `project_eval`
|
|
11
|
+
* Allow install to continue even if dependencies cannot be installed
|
|
12
|
+
|
|
3
13
|
## [0.5.4] - 2025-11-13
|
|
4
14
|
|
|
5
15
|
* Fix async messages on `project_eval`
|
package/README.md
CHANGED
|
@@ -8,15 +8,14 @@ more information.
|
|
|
8
8
|
This project supports:
|
|
9
9
|
|
|
10
10
|
- Next.js 15/16
|
|
11
|
+
- TanStack Start with React
|
|
12
|
+
- Vite with React/Vue
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
If you are using React/Vue with Django, FastAPI, Flask, Phoenix, or Rails,
|
|
15
|
+
[follow the steps here instead](http://hexdocs.pm/tidewave/frontend.html).
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
[
|
|
17
|
-
|
|
18
|
-
This project can also be used through the CLI or as a standalone Model Context
|
|
19
|
-
Protocol (MCP) server for your editors.
|
|
17
|
+
This project can also be used through the CLI or as
|
|
18
|
+
[a standalone Model Context Protocol server](https://hexdocs.pm/tidewave/mcp.html).
|
|
20
19
|
|
|
21
20
|
## Installation
|
|
22
21
|
|
|
@@ -168,11 +167,56 @@ export async function register() {
|
|
|
168
167
|
|
|
169
168
|
</details>
|
|
170
169
|
|
|
171
|
-
###
|
|
170
|
+
### TanStack Start
|
|
172
171
|
|
|
173
|
-
If you are
|
|
174
|
-
|
|
175
|
-
|
|
172
|
+
If you are using TanStack Start with React, install Tidewave with:
|
|
173
|
+
|
|
174
|
+
```sh
|
|
175
|
+
$ npm install -D tidewave
|
|
176
|
+
# or
|
|
177
|
+
$ yarn add -D tidewave
|
|
178
|
+
# or
|
|
179
|
+
$ pnpm add --save-dev tidewave
|
|
180
|
+
# or
|
|
181
|
+
$ bun add --dev tidewave
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Then configure your `vite.config.js` (also works for `.ts` and `.mjs`):
|
|
185
|
+
|
|
186
|
+
```javascript
|
|
187
|
+
import { defineConfig } from 'vite';
|
|
188
|
+
import tidewave from 'tidewave/vite-plugin';
|
|
189
|
+
|
|
190
|
+
export default defineConfig({
|
|
191
|
+
plugins: [tidewave()],
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
And finally create or modify `src/start.ts` file to import Tidewave in
|
|
196
|
+
development:
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
import { createStart } from '@tanstack/react-start';
|
|
200
|
+
|
|
201
|
+
// Import Tidewave only in development.
|
|
202
|
+
if (process.env.NODE_ENV === 'development' && typeof window === 'undefined') {
|
|
203
|
+
import('tidewave/tanstack');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export const startInstance = createStart(() => {
|
|
207
|
+
return {};
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Now make sure
|
|
212
|
+
[Tidewave is installed](https://hexdocs.pm/tidewave/installation.html) and you
|
|
213
|
+
are ready to connect Tidewave to your app.
|
|
214
|
+
|
|
215
|
+
### Vite
|
|
216
|
+
|
|
217
|
+
If you are building a frontend application with React or Vue, using a backend as
|
|
218
|
+
a service, such as Supabase, or a non-officially supported web framework, we
|
|
219
|
+
recommend using our Vite integration.
|
|
176
220
|
|
|
177
221
|
Install it with:
|
|
178
222
|
|
|
@@ -201,12 +245,13 @@ Now make sure
|
|
|
201
245
|
[Tidewave is installed](https://hexdocs.pm/tidewave/installation.html) and you
|
|
202
246
|
are ready to connect Tidewave to your app.
|
|
203
247
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
248
|
+
Our Vite integration for React and Vue allows Tidewave Web to perform changes on
|
|
249
|
+
the front-end, and the agent will be able to modify your backend code as usual,
|
|
250
|
+
but some functionality (such as accessing logs, doing database calls, etc) won't
|
|
251
|
+
be available. You can also use our
|
|
252
|
+
[Figma Dev Mode](https://hexdocs.pm/tidewave/figma.html) and
|
|
253
|
+
[Supabase](https://hexdocs.pm/tidewave/supabase.html) integration for additional
|
|
254
|
+
features.
|
|
210
255
|
|
|
211
256
|
### Configuration
|
|
212
257
|
|
|
@@ -283,6 +328,11 @@ bun run format:check # Check Prettier formatting
|
|
|
283
328
|
bun run clean # Clean dist directory
|
|
284
329
|
```
|
|
285
330
|
|
|
331
|
+
## Acknowledgements
|
|
332
|
+
|
|
333
|
+
A thank you to [Zoey](https://github.com/zoedsoupe/) for implementing both
|
|
334
|
+
Next.js and Vite integrations as well as the CLI interface.
|
|
335
|
+
|
|
286
336
|
## License
|
|
287
337
|
|
|
288
338
|
Copyright (c) 2025 Dashbit
|
package/dist/cli/index.js
CHANGED
|
@@ -5865,8 +5865,8 @@ Imports are allowed only as the form of dynamic imports with async/await, e.g.:
|
|
|
5865
5865
|
const path = await import('node:path');
|
|
5866
5866
|
`;
|
|
5867
5867
|
projectEvalInputSchema = exports_external.object({
|
|
5868
|
-
code: exports_external.string().describe("The JavaScript
|
|
5869
|
-
arguments: exports_external.array(exports_external.
|
|
5868
|
+
code: exports_external.string().describe("The JavaScript code to evaluate."),
|
|
5869
|
+
arguments: exports_external.array(exports_external.unknown()).optional().default([]).describe("The arguments to pass to evaluation. They are available inside the evaluated code as `arguments`."),
|
|
5870
5870
|
timeout: exports_external.number().optional().default(30000).describe(`Optional. A timeout in milliseconds after which the execution stops if it did not finish yet.
|
|
5871
5871
|
Defaults to 30000 (30 seconds).`),
|
|
5872
5872
|
json: exports_external.boolean().optional().default(false).describe("Whether to return the result as JSON or not (string)")
|
|
@@ -6787,12 +6787,12 @@ var init_src = __esm(() => {
|
|
|
6787
6787
|
});
|
|
6788
6788
|
|
|
6789
6789
|
// package.json
|
|
6790
|
-
var name = "tidewave", version = "0.
|
|
6790
|
+
var name = "tidewave", version = "0.6.0", package_default;
|
|
6791
6791
|
var init_package = __esm(() => {
|
|
6792
6792
|
package_default = {
|
|
6793
6793
|
name,
|
|
6794
6794
|
version,
|
|
6795
|
-
description: "Tidewave for JavaScript
|
|
6795
|
+
description: "Tidewave for JavaScript (Next.js, TanStack, Vite)",
|
|
6796
6796
|
keywords: [
|
|
6797
6797
|
"typescript",
|
|
6798
6798
|
"documentation",
|
|
@@ -6835,6 +6835,11 @@ var init_package = __esm(() => {
|
|
|
6835
6835
|
import: "./dist/next-js/instrumentation.js",
|
|
6836
6836
|
require: "./dist/next-js/instrumentation.js"
|
|
6837
6837
|
},
|
|
6838
|
+
"./tanstack": {
|
|
6839
|
+
types: "./dist/tanstack.d.ts",
|
|
6840
|
+
import: "./dist/tanstack.js",
|
|
6841
|
+
require: "./dist/tanstack.js"
|
|
6842
|
+
},
|
|
6838
6843
|
"./package.json": "./package.json"
|
|
6839
6844
|
},
|
|
6840
6845
|
files: [
|
|
@@ -6845,7 +6850,7 @@ var init_package = __esm(() => {
|
|
|
6845
6850
|
],
|
|
6846
6851
|
scripts: {
|
|
6847
6852
|
dist: "bun run clean && bun run build:js && bun run build:types",
|
|
6848
|
-
"build:js": "bun build --outdir dist --root src --external typescript --external child_process --external module --external @opentelemetry/api --external @opentelemetry/sdk-logs --external @opentelemetry/sdk-trace-base src/next-js/handler.ts src/next-js/instrumentation.ts src/vite-plugin.ts src/evaluation/eval_worker.ts src/cli/index.ts --target node",
|
|
6853
|
+
"build:js": "bun build --outdir dist --root src --external typescript --external child_process --external module --external @opentelemetry/api --external @opentelemetry/sdk-logs --external @opentelemetry/sdk-trace-base src/next-js/handler.ts src/next-js/instrumentation.ts src/vite-plugin.ts src/tanstack.ts src/evaluation/eval_worker.ts src/cli/index.ts --target node",
|
|
6849
6854
|
"build:types": "tsc -p tsconfig.declarations.json",
|
|
6850
6855
|
dev: "bun run src/cli/index.ts",
|
|
6851
6856
|
test: "bun test",
|
|
@@ -16156,23 +16161,31 @@ var init_mcp = __esm(() => {
|
|
|
16156
16161
|
};
|
|
16157
16162
|
});
|
|
16158
16163
|
|
|
16159
|
-
// src/logger/
|
|
16160
|
-
|
|
16161
|
-
|
|
16162
|
-
|
|
16163
|
-
|
|
16164
|
-
|
|
16165
|
-
|
|
16166
|
-
|
|
16167
|
-
|
|
16168
|
-
|
|
16169
|
-
|
|
16170
|
-
|
|
16171
|
-
this.
|
|
16172
|
-
|
|
16173
|
-
|
|
16174
|
-
|
|
16175
|
-
|
|
16164
|
+
// src/logger/tidewave-logger.ts
|
|
16165
|
+
import { appendFile, readFile } from "fs/promises";
|
|
16166
|
+
import * as path5 from "path";
|
|
16167
|
+
import * as os2 from "os";
|
|
16168
|
+
import * as crypto from "crypto";
|
|
16169
|
+
|
|
16170
|
+
class TidewaveLogger {
|
|
16171
|
+
logFilePath;
|
|
16172
|
+
constructor() {
|
|
16173
|
+
const cwd = process.cwd();
|
|
16174
|
+
const digest = crypto.createHash("md5").update(cwd).digest("hex").slice(0, 16);
|
|
16175
|
+
const tempDir = os2.tmpdir();
|
|
16176
|
+
this.logFilePath = path5.join(tempDir, `${digest}.tidewave.ndjson`);
|
|
16177
|
+
}
|
|
16178
|
+
async addLog(log) {
|
|
16179
|
+
const line = JSON.stringify(log) + `
|
|
16180
|
+
`;
|
|
16181
|
+
try {
|
|
16182
|
+
await appendFile(this.logFilePath, line, "utf8");
|
|
16183
|
+
} catch (error) {
|
|
16184
|
+
console.log("[Tidewave] failed to write to log file, error:", error);
|
|
16185
|
+
}
|
|
16186
|
+
}
|
|
16187
|
+
async getLogs(options) {
|
|
16188
|
+
let logs = await this.getAllLogs();
|
|
16176
16189
|
if (options?.level) {
|
|
16177
16190
|
const level = options.level.toUpperCase();
|
|
16178
16191
|
logs = logs.filter((log) => log.severityText === level);
|
|
@@ -16190,31 +16203,26 @@ class CircularBuffer {
|
|
|
16190
16203
|
}
|
|
16191
16204
|
return logs;
|
|
16192
16205
|
}
|
|
16193
|
-
getAllLogs() {
|
|
16194
|
-
|
|
16195
|
-
|
|
16206
|
+
async getAllLogs() {
|
|
16207
|
+
try {
|
|
16208
|
+
const content = await readFile(this.logFilePath, "utf8");
|
|
16209
|
+
return content.split(`
|
|
16210
|
+
`).map((line) => {
|
|
16211
|
+
try {
|
|
16212
|
+
return JSON.parse(line);
|
|
16213
|
+
} catch {
|
|
16214
|
+
return null;
|
|
16215
|
+
}
|
|
16216
|
+
}).filter((log) => log !== null);
|
|
16217
|
+
} catch (error) {
|
|
16218
|
+
console.log("[Tidewave] failed to read from log file, error:", error);
|
|
16219
|
+
return [];
|
|
16196
16220
|
}
|
|
16197
|
-
return [...this.buffer.slice(this.writeIndex), ...this.buffer.slice(0, this.writeIndex)].filter(Boolean);
|
|
16198
|
-
}
|
|
16199
|
-
getStats() {
|
|
16200
|
-
return {
|
|
16201
|
-
totalLogs: this.count,
|
|
16202
|
-
bufferSize: this.maxSize,
|
|
16203
|
-
bufferUsage: Math.min(this.count / this.maxSize * 100, 100).toFixed(1) + "%"
|
|
16204
|
-
};
|
|
16205
|
-
}
|
|
16206
|
-
clear() {
|
|
16207
|
-
this.buffer = new Array(this.maxSize);
|
|
16208
|
-
this.writeIndex = 0;
|
|
16209
|
-
this.count = 0;
|
|
16210
16221
|
}
|
|
16211
16222
|
}
|
|
16212
|
-
var
|
|
16213
|
-
var
|
|
16214
|
-
|
|
16215
|
-
globalThis.__tidewaveCircularBuffer = new CircularBuffer(1024);
|
|
16216
|
-
}
|
|
16217
|
-
circularBuffer = globalThis.__tidewaveCircularBuffer;
|
|
16223
|
+
var tidewaveLogger;
|
|
16224
|
+
var init_tidewave_logger = __esm(() => {
|
|
16225
|
+
tidewaveLogger = new TidewaveLogger;
|
|
16218
16226
|
});
|
|
16219
16227
|
|
|
16220
16228
|
// src/mcp.ts
|
|
@@ -16306,15 +16314,15 @@ async function handleGetSourcePath({ reference }) {
|
|
|
16306
16314
|
isError: true
|
|
16307
16315
|
};
|
|
16308
16316
|
}
|
|
16309
|
-
const { path:
|
|
16317
|
+
const { path: path6, format } = sourceResult;
|
|
16310
16318
|
return {
|
|
16311
|
-
content: [{ type: "text", text: `${
|
|
16319
|
+
content: [{ type: "text", text: `${path6}(${format})` }],
|
|
16312
16320
|
isError: false
|
|
16313
16321
|
};
|
|
16314
16322
|
}
|
|
16315
16323
|
async function handleGetLogs(args) {
|
|
16316
16324
|
try {
|
|
16317
|
-
const logs =
|
|
16325
|
+
const logs = await tidewaveLogger.getLogs({
|
|
16318
16326
|
tail: args.tail,
|
|
16319
16327
|
grep: args.grep,
|
|
16320
16328
|
level: args.level,
|
|
@@ -16370,7 +16378,7 @@ var init_mcp2 = __esm(() => {
|
|
|
16370
16378
|
init_package();
|
|
16371
16379
|
init_core();
|
|
16372
16380
|
init_src();
|
|
16373
|
-
|
|
16381
|
+
init_tidewave_logger();
|
|
16374
16382
|
({
|
|
16375
16383
|
docs: { mcp: docsMcp },
|
|
16376
16384
|
source: { mcp: sourceMcp },
|
|
@@ -16991,7 +16999,7 @@ init_mcp2();
|
|
|
16991
16999
|
|
|
16992
17000
|
// src/cli/install.ts
|
|
16993
17001
|
import * as fs2 from "fs";
|
|
16994
|
-
import * as
|
|
17002
|
+
import * as path6 from "path";
|
|
16995
17003
|
import * as child_process from "child_process";
|
|
16996
17004
|
import * as readline from "readline";
|
|
16997
17005
|
async function handleInstall(options) {
|
|
@@ -17017,11 +17025,6 @@ The installer only works for Next.js projects
|
|
|
17017
17025
|
process.exit(1);
|
|
17018
17026
|
}
|
|
17019
17027
|
console.log(source_default.green(`✅ Detected Next.js ${nextVersion.raw} (v${nextVersion.major})`));
|
|
17020
|
-
if (!skipDeps) {
|
|
17021
|
-
await installDependencies(targetDir, dryRun);
|
|
17022
|
-
} else {
|
|
17023
|
-
console.log(source_default.gray("⏭️ Skipping dependency installation"));
|
|
17024
|
-
}
|
|
17025
17028
|
const steps = [
|
|
17026
17029
|
() => createApiHandler(targetDir, dryRun),
|
|
17027
17030
|
() => createMiddleware(targetDir, nextVersion, dryRun),
|
|
@@ -17030,6 +17033,9 @@ The installer only works for Next.js projects
|
|
|
17030
17033
|
for (const step of steps) {
|
|
17031
17034
|
await step();
|
|
17032
17035
|
}
|
|
17036
|
+
if (!skipDeps) {
|
|
17037
|
+
await installDependencies(targetDir, dryRun);
|
|
17038
|
+
}
|
|
17033
17039
|
console.log(source_default.green(`
|
|
17034
17040
|
✅ Tidewave setup complete!
|
|
17035
17041
|
`));
|
|
@@ -17041,7 +17047,7 @@ The installer only works for Next.js projects
|
|
|
17041
17047
|
}
|
|
17042
17048
|
async function detectNextJsVersion(dir) {
|
|
17043
17049
|
try {
|
|
17044
|
-
const nextPackageJsonPath =
|
|
17050
|
+
const nextPackageJsonPath = path6.join(dir, "node_modules", "next", "package.json");
|
|
17045
17051
|
if (!fs2.existsSync(nextPackageJsonPath)) {
|
|
17046
17052
|
return null;
|
|
17047
17053
|
}
|
|
@@ -17061,13 +17067,13 @@ async function detectNextJsVersion(dir) {
|
|
|
17061
17067
|
}
|
|
17062
17068
|
}
|
|
17063
17069
|
function detectPackageManager(dir) {
|
|
17064
|
-
if (fs2.existsSync(
|
|
17070
|
+
if (fs2.existsSync(path6.join(dir, "bun.lockb")))
|
|
17065
17071
|
return "bun";
|
|
17066
|
-
if (fs2.existsSync(
|
|
17072
|
+
if (fs2.existsSync(path6.join(dir, "pnpm-lock.yaml")))
|
|
17067
17073
|
return "pnpm";
|
|
17068
|
-
if (fs2.existsSync(
|
|
17074
|
+
if (fs2.existsSync(path6.join(dir, "yarn.lock")))
|
|
17069
17075
|
return "yarn";
|
|
17070
|
-
if (fs2.existsSync(
|
|
17076
|
+
if (fs2.existsSync(path6.join(dir, "package-lock.json")))
|
|
17071
17077
|
return "npm";
|
|
17072
17078
|
return "npm";
|
|
17073
17079
|
}
|
|
@@ -17132,14 +17138,12 @@ async function installDependencies(dir, dryRun) {
|
|
|
17132
17138
|
console.log(source_default.gray(`
|
|
17133
17139
|
Please install manually:
|
|
17134
17140
|
${pm} ${devCmds.join(" ")}
|
|
17135
|
-
${pm} ${depCmds.join(" ")}
|
|
17136
|
-
`));
|
|
17137
|
-
process.exit(1);
|
|
17141
|
+
${pm} ${depCmds.join(" ")}`));
|
|
17138
17142
|
}
|
|
17139
17143
|
}
|
|
17140
17144
|
async function createApiHandler(dir, dryRun) {
|
|
17141
|
-
const apiDir =
|
|
17142
|
-
const handlerPath =
|
|
17145
|
+
const apiDir = path6.join(dir, "pages", "api");
|
|
17146
|
+
const handlerPath = path6.join(apiDir, "tidewave.ts");
|
|
17143
17147
|
const handlerContent = `import type { NextApiRequest, NextApiResponse } from 'next';
|
|
17144
17148
|
|
|
17145
17149
|
export default async function handler(
|
|
@@ -17164,30 +17168,30 @@ export const config = {
|
|
|
17164
17168
|
`;
|
|
17165
17169
|
if (fs2.existsSync(handlerPath)) {
|
|
17166
17170
|
if (dryRun) {
|
|
17167
|
-
console.log(source_default.gray(`[DRY RUN] Would ask to overwrite: ${
|
|
17171
|
+
console.log(source_default.gray(`[DRY RUN] Would ask to overwrite: ${path6.relative(dir, handlerPath)}`));
|
|
17168
17172
|
return;
|
|
17169
17173
|
}
|
|
17170
17174
|
const shouldOverwrite = await promptUser(source_default.yellow(`
|
|
17171
|
-
⚠️
|
|
17175
|
+
⚠️ ${path6.relative(dir, handlerPath)} already exists. Overwrite? (Y/n): `));
|
|
17172
17176
|
if (!shouldOverwrite) {
|
|
17173
|
-
console.log(source_default.gray(`⏭️
|
|
17177
|
+
console.log(source_default.gray(`⏭️ Skipping: ${path6.relative(dir, handlerPath)}`));
|
|
17174
17178
|
return;
|
|
17175
17179
|
}
|
|
17176
17180
|
}
|
|
17177
17181
|
if (dryRun) {
|
|
17178
|
-
console.log(source_default.gray(`[DRY RUN] Would create: ${
|
|
17182
|
+
console.log(source_default.gray(`[DRY RUN] Would create: ${path6.relative(dir, handlerPath)}`));
|
|
17179
17183
|
return;
|
|
17180
17184
|
}
|
|
17181
17185
|
fs2.mkdirSync(apiDir, { recursive: true });
|
|
17182
17186
|
fs2.writeFileSync(handlerPath, handlerContent, "utf-8");
|
|
17183
|
-
console.log(source_default.green(`✅ Created: ${
|
|
17187
|
+
console.log(source_default.green(`✅ Created: ${path6.relative(dir, handlerPath)}`));
|
|
17184
17188
|
}
|
|
17185
17189
|
async function createMiddleware(dir, nextVersion, dryRun) {
|
|
17186
17190
|
const isNext16Plus = nextVersion.major >= 16;
|
|
17187
17191
|
const fileName = isNext16Plus ? "proxy.ts" : "middleware.ts";
|
|
17188
|
-
const filePath =
|
|
17192
|
+
const filePath = path6.join(dir, fileName);
|
|
17189
17193
|
if (fs2.existsSync(filePath)) {
|
|
17190
|
-
console.log(source_default.yellow(`⏭️
|
|
17194
|
+
console.log(source_default.yellow(`⏭️ ${fileName} already exists`));
|
|
17191
17195
|
const content = fs2.readFileSync(filePath, "utf-8");
|
|
17192
17196
|
if (content.includes("/tidewave") && content.includes("/api/tidewave")) {
|
|
17193
17197
|
console.log(source_default.green(`✅ ${fileName} already configured for Tidewave`));
|
|
@@ -17249,14 +17253,14 @@ function printMiddlewareInstructions(isNext16Plus) {
|
|
|
17249
17253
|
console.log();
|
|
17250
17254
|
}
|
|
17251
17255
|
async function createInstrumentation(dir, dryRun) {
|
|
17252
|
-
const rootPath =
|
|
17253
|
-
const srcPath =
|
|
17254
|
-
const hasSrcDir = fs2.existsSync(
|
|
17256
|
+
const rootPath = path6.join(dir, "instrumentation.ts");
|
|
17257
|
+
const srcPath = path6.join(dir, "src", "instrumentation.ts");
|
|
17258
|
+
const hasSrcDir = fs2.existsSync(path6.join(dir, "src"));
|
|
17255
17259
|
const instrumentationPath = hasSrcDir ? srcPath : rootPath;
|
|
17256
17260
|
if (fs2.existsSync(rootPath) || fs2.existsSync(srcPath)) {
|
|
17257
17261
|
const existingPath = fs2.existsSync(rootPath) ? rootPath : srcPath;
|
|
17258
17262
|
const existingFile = fs2.existsSync(rootPath) ? "instrumentation.ts" : "src/instrumentation.ts";
|
|
17259
|
-
console.log(source_default.yellow(`⏭️
|
|
17263
|
+
console.log(source_default.yellow(`⏭️ ${existingFile} already exists`));
|
|
17260
17264
|
const content = fs2.readFileSync(existingPath, "utf-8");
|
|
17261
17265
|
if (content.includes("TidewaveSpanProcessor") && content.includes("TidewaveLogRecordProcessor")) {
|
|
17262
17266
|
console.log(source_default.green(`✅ ${existingFile} already configured for Tidewave`));
|
|
@@ -17300,14 +17304,14 @@ export async function register() {
|
|
|
17300
17304
|
}
|
|
17301
17305
|
`;
|
|
17302
17306
|
if (dryRun) {
|
|
17303
|
-
console.log(source_default.gray(`[DRY RUN] Would create: ${
|
|
17307
|
+
console.log(source_default.gray(`[DRY RUN] Would create: ${path6.relative(dir, instrumentationPath)}`));
|
|
17304
17308
|
return;
|
|
17305
17309
|
}
|
|
17306
17310
|
if (hasSrcDir) {
|
|
17307
|
-
fs2.mkdirSync(
|
|
17311
|
+
fs2.mkdirSync(path6.dirname(instrumentationPath), { recursive: true });
|
|
17308
17312
|
}
|
|
17309
17313
|
fs2.writeFileSync(instrumentationPath, instrumentationContent, "utf-8");
|
|
17310
|
-
console.log(source_default.green(`✅ Created: ${
|
|
17314
|
+
console.log(source_default.green(`✅ Created: ${path6.relative(dir, instrumentationPath)}`));
|
|
17311
17315
|
}
|
|
17312
17316
|
function printInstrumentationInstructions() {
|
|
17313
17317
|
console.log(source_default.cyan(` // Inside your register() function:
|
|
@@ -17326,9 +17330,9 @@ function printInstrumentationInstructions() {
|
|
|
17326
17330
|
}
|
|
17327
17331
|
|
|
17328
17332
|
// src/cli/index.ts
|
|
17329
|
-
function chdir(
|
|
17333
|
+
function chdir(path7) {
|
|
17330
17334
|
try {
|
|
17331
|
-
process.chdir(
|
|
17335
|
+
process.chdir(path7);
|
|
17332
17336
|
} catch (e) {
|
|
17333
17337
|
console.error(source_default.red(`Failed to apply given prefix: ${e}`));
|
|
17334
17338
|
}
|
|
@@ -2,7 +2,7 @@ import type { LogRecordProcessor, SdkLogRecord } from '@opentelemetry/sdk-logs';
|
|
|
2
2
|
import type { Context } from '@opentelemetry/api';
|
|
3
3
|
/**
|
|
4
4
|
* Custom LogRecordProcessor that captures OpenTelemetry logger logs
|
|
5
|
-
* and writes them directly to the
|
|
5
|
+
* and writes them directly to the tidewave logger.
|
|
6
6
|
*
|
|
7
7
|
* This is opt-in for users who want to capture actual logger logs
|
|
8
8
|
* (not console.log, which is handled separately by console patching).
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface StoredLogRecord {
|
|
2
|
+
timestamp: string;
|
|
3
|
+
severityText: string;
|
|
4
|
+
body: string;
|
|
5
|
+
attributes?: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
export interface LogFilterOptions {
|
|
8
|
+
tail?: number;
|
|
9
|
+
grep?: string;
|
|
10
|
+
level?: string;
|
|
11
|
+
since?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Tidewave log store.
|
|
15
|
+
*
|
|
16
|
+
* Storing logs in memory can be problematic, because some frameworks
|
|
17
|
+
* can use multiple execution contexts with isolated module loading
|
|
18
|
+
* and globals. In such circumstances, if we import the logger and
|
|
19
|
+
* write to it within the app, it may be a different logger instance
|
|
20
|
+
* from the one that the MCP server uses the get the logs. To avoid
|
|
21
|
+
* issues we persist logs in a NDJSON file, so it works across
|
|
22
|
+
* execution contexts.
|
|
23
|
+
*/
|
|
24
|
+
export declare class TidewaveLogger {
|
|
25
|
+
private logFilePath;
|
|
26
|
+
constructor();
|
|
27
|
+
/**
|
|
28
|
+
* Store a log entry.
|
|
29
|
+
*/
|
|
30
|
+
addLog(log: StoredLogRecord): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Get stored logs.
|
|
33
|
+
*/
|
|
34
|
+
getLogs(options?: LogFilterOptions): Promise<StoredLogRecord[]>;
|
|
35
|
+
private getAllLogs;
|
|
36
|
+
}
|
|
37
|
+
export declare const tidewaveLogger: TidewaveLogger;
|
|
@@ -3,7 +3,7 @@ import type { ReadableSpan } from '@opentelemetry/sdk-trace-base';
|
|
|
3
3
|
import type { Span, Context } from '@opentelemetry/api';
|
|
4
4
|
/**
|
|
5
5
|
* Custom SpanProcessor that converts OpenTelemetry spans to logs and writes them
|
|
6
|
-
* directly to the
|
|
6
|
+
* directly to the tidewave logger.
|
|
7
7
|
* This is used to capture Next.js HTTP request/response spans and
|
|
8
8
|
* make them available via the get_logs tool.
|
|
9
9
|
*/
|
|
@@ -14,7 +14,7 @@ export declare class TidewaveSpanProcessor implements SpanProcessor {
|
|
|
14
14
|
onStart(_span: Span, _parentContext: Context): void;
|
|
15
15
|
/**
|
|
16
16
|
* Called when a span ends. This is where we convert the span to a log entry
|
|
17
|
-
* and write it directly to the
|
|
17
|
+
* and write it directly to the tidewave logger.
|
|
18
18
|
*/
|
|
19
19
|
onEnd(span: ReadableSpan): void;
|
|
20
20
|
/**
|