tidewave 0.5.5 → 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 +5 -0
- package/README.md +64 -19
- package/dist/cli/index.js +76 -68
- 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 +82 -269
- 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/vite-plugin.d.ts +0 -1
- package/dist/vite-plugin.js +82 -269
- 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
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
|
|
171
|
+
|
|
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
|
|
172
216
|
|
|
173
|
-
If you are building a
|
|
174
|
-
as Supabase, or a non-officially supported web framework, we
|
|
175
|
-
|
|
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
|
|
|
@@ -285,8 +330,8 @@ bun run clean # Clean dist directory
|
|
|
285
330
|
|
|
286
331
|
## Acknowledgements
|
|
287
332
|
|
|
288
|
-
A thank you to [Zoey](https://github.com/zoedsoupe/) for implementing both
|
|
289
|
-
Vite integrations as well as the CLI interface.
|
|
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.
|
|
290
335
|
|
|
291
336
|
## License
|
|
292
337
|
|
package/dist/cli/index.js
CHANGED
|
@@ -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) {
|
|
@@ -17039,7 +17047,7 @@ The installer only works for Next.js projects
|
|
|
17039
17047
|
}
|
|
17040
17048
|
async function detectNextJsVersion(dir) {
|
|
17041
17049
|
try {
|
|
17042
|
-
const nextPackageJsonPath =
|
|
17050
|
+
const nextPackageJsonPath = path6.join(dir, "node_modules", "next", "package.json");
|
|
17043
17051
|
if (!fs2.existsSync(nextPackageJsonPath)) {
|
|
17044
17052
|
return null;
|
|
17045
17053
|
}
|
|
@@ -17059,13 +17067,13 @@ async function detectNextJsVersion(dir) {
|
|
|
17059
17067
|
}
|
|
17060
17068
|
}
|
|
17061
17069
|
function detectPackageManager(dir) {
|
|
17062
|
-
if (fs2.existsSync(
|
|
17070
|
+
if (fs2.existsSync(path6.join(dir, "bun.lockb")))
|
|
17063
17071
|
return "bun";
|
|
17064
|
-
if (fs2.existsSync(
|
|
17072
|
+
if (fs2.existsSync(path6.join(dir, "pnpm-lock.yaml")))
|
|
17065
17073
|
return "pnpm";
|
|
17066
|
-
if (fs2.existsSync(
|
|
17074
|
+
if (fs2.existsSync(path6.join(dir, "yarn.lock")))
|
|
17067
17075
|
return "yarn";
|
|
17068
|
-
if (fs2.existsSync(
|
|
17076
|
+
if (fs2.existsSync(path6.join(dir, "package-lock.json")))
|
|
17069
17077
|
return "npm";
|
|
17070
17078
|
return "npm";
|
|
17071
17079
|
}
|
|
@@ -17134,8 +17142,8 @@ Please install manually:
|
|
|
17134
17142
|
}
|
|
17135
17143
|
}
|
|
17136
17144
|
async function createApiHandler(dir, dryRun) {
|
|
17137
|
-
const apiDir =
|
|
17138
|
-
const handlerPath =
|
|
17145
|
+
const apiDir = path6.join(dir, "pages", "api");
|
|
17146
|
+
const handlerPath = path6.join(apiDir, "tidewave.ts");
|
|
17139
17147
|
const handlerContent = `import type { NextApiRequest, NextApiResponse } from 'next';
|
|
17140
17148
|
|
|
17141
17149
|
export default async function handler(
|
|
@@ -17160,28 +17168,28 @@ export const config = {
|
|
|
17160
17168
|
`;
|
|
17161
17169
|
if (fs2.existsSync(handlerPath)) {
|
|
17162
17170
|
if (dryRun) {
|
|
17163
|
-
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)}`));
|
|
17164
17172
|
return;
|
|
17165
17173
|
}
|
|
17166
17174
|
const shouldOverwrite = await promptUser(source_default.yellow(`
|
|
17167
|
-
⚠️ ${
|
|
17175
|
+
⚠️ ${path6.relative(dir, handlerPath)} already exists. Overwrite? (Y/n): `));
|
|
17168
17176
|
if (!shouldOverwrite) {
|
|
17169
|
-
console.log(source_default.gray(`⏭️ Skipping: ${
|
|
17177
|
+
console.log(source_default.gray(`⏭️ Skipping: ${path6.relative(dir, handlerPath)}`));
|
|
17170
17178
|
return;
|
|
17171
17179
|
}
|
|
17172
17180
|
}
|
|
17173
17181
|
if (dryRun) {
|
|
17174
|
-
console.log(source_default.gray(`[DRY RUN] Would create: ${
|
|
17182
|
+
console.log(source_default.gray(`[DRY RUN] Would create: ${path6.relative(dir, handlerPath)}`));
|
|
17175
17183
|
return;
|
|
17176
17184
|
}
|
|
17177
17185
|
fs2.mkdirSync(apiDir, { recursive: true });
|
|
17178
17186
|
fs2.writeFileSync(handlerPath, handlerContent, "utf-8");
|
|
17179
|
-
console.log(source_default.green(`✅ Created: ${
|
|
17187
|
+
console.log(source_default.green(`✅ Created: ${path6.relative(dir, handlerPath)}`));
|
|
17180
17188
|
}
|
|
17181
17189
|
async function createMiddleware(dir, nextVersion, dryRun) {
|
|
17182
17190
|
const isNext16Plus = nextVersion.major >= 16;
|
|
17183
17191
|
const fileName = isNext16Plus ? "proxy.ts" : "middleware.ts";
|
|
17184
|
-
const filePath =
|
|
17192
|
+
const filePath = path6.join(dir, fileName);
|
|
17185
17193
|
if (fs2.existsSync(filePath)) {
|
|
17186
17194
|
console.log(source_default.yellow(`⏭️ ${fileName} already exists`));
|
|
17187
17195
|
const content = fs2.readFileSync(filePath, "utf-8");
|
|
@@ -17245,9 +17253,9 @@ function printMiddlewareInstructions(isNext16Plus) {
|
|
|
17245
17253
|
console.log();
|
|
17246
17254
|
}
|
|
17247
17255
|
async function createInstrumentation(dir, dryRun) {
|
|
17248
|
-
const rootPath =
|
|
17249
|
-
const srcPath =
|
|
17250
|
-
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"));
|
|
17251
17259
|
const instrumentationPath = hasSrcDir ? srcPath : rootPath;
|
|
17252
17260
|
if (fs2.existsSync(rootPath) || fs2.existsSync(srcPath)) {
|
|
17253
17261
|
const existingPath = fs2.existsSync(rootPath) ? rootPath : srcPath;
|
|
@@ -17296,14 +17304,14 @@ export async function register() {
|
|
|
17296
17304
|
}
|
|
17297
17305
|
`;
|
|
17298
17306
|
if (dryRun) {
|
|
17299
|
-
console.log(source_default.gray(`[DRY RUN] Would create: ${
|
|
17307
|
+
console.log(source_default.gray(`[DRY RUN] Would create: ${path6.relative(dir, instrumentationPath)}`));
|
|
17300
17308
|
return;
|
|
17301
17309
|
}
|
|
17302
17310
|
if (hasSrcDir) {
|
|
17303
|
-
fs2.mkdirSync(
|
|
17311
|
+
fs2.mkdirSync(path6.dirname(instrumentationPath), { recursive: true });
|
|
17304
17312
|
}
|
|
17305
17313
|
fs2.writeFileSync(instrumentationPath, instrumentationContent, "utf-8");
|
|
17306
|
-
console.log(source_default.green(`✅ Created: ${
|
|
17314
|
+
console.log(source_default.green(`✅ Created: ${path6.relative(dir, instrumentationPath)}`));
|
|
17307
17315
|
}
|
|
17308
17316
|
function printInstrumentationInstructions() {
|
|
17309
17317
|
console.log(source_default.cyan(` // Inside your register() function:
|
|
@@ -17322,9 +17330,9 @@ function printInstrumentationInstructions() {
|
|
|
17322
17330
|
}
|
|
17323
17331
|
|
|
17324
17332
|
// src/cli/index.ts
|
|
17325
|
-
function chdir(
|
|
17333
|
+
function chdir(path7) {
|
|
17326
17334
|
try {
|
|
17327
|
-
process.chdir(
|
|
17335
|
+
process.chdir(path7);
|
|
17328
17336
|
} catch (e) {
|
|
17329
17337
|
console.error(source_default.red(`Failed to apply given prefix: ${e}`));
|
|
17330
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
|
/**
|