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 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
- - React + Vite frontends, with either a backend as a service (such as Supabase)
13
- or a third-party framework
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
- If you are using React with Django, FastAPI, Flask, Phoenix, or Rails,
16
- [follow the steps here instead](http://hexdocs.pm/tidewave/react.html).
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
- ### React + Vite
170
+ ### TanStack Start
172
171
 
173
- If you are building a front-end application, using a backend as a service, such
174
- as Supabase, or a non-officially supported web framework, we recommend using our
175
- React + Vite integration.
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
- If you are using Supabase or similar, you can prompt Tidewave to use the
205
- `supabase` CLI so it has complete access to your database. For non-officially
206
- supported web frameworks, our React + Vite integration allows Tidewave Web to
207
- perform changes on the front-end, and the agent will be able to modify your
208
- backend code as usual, but some functionality (such as accessing logs, doing
209
- database calls, etc) won't be available.
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/TypeScript code to evaluate."),
5869
- arguments: exports_external.array(exports_external.any()).optional().default([]).describe("The arguments to pass to evaluation. They are available inside the evaluated code as `arguments`."),
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.5.4", package_default;
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/Next.js",
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/circular-buffer.ts
16160
- class CircularBuffer {
16161
- buffer;
16162
- maxSize;
16163
- writeIndex = 0;
16164
- count = 0;
16165
- constructor(maxSize = 1024) {
16166
- this.buffer = new Array(maxSize);
16167
- this.maxSize = maxSize;
16168
- }
16169
- addLog(log) {
16170
- this.buffer[this.writeIndex] = log;
16171
- this.writeIndex = (this.writeIndex + 1) % this.maxSize;
16172
- this.count = Math.min(this.count + 1, this.maxSize);
16173
- }
16174
- getLogs(options) {
16175
- let logs = this.getAllLogs();
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
- if (this.count < this.maxSize) {
16195
- return this.buffer.slice(0, this.count).filter(Boolean);
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 circularBuffer;
16213
- var init_circular_buffer = __esm(() => {
16214
- if (!globalThis.__tidewaveCircularBuffer) {
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: path5, format } = sourceResult;
16317
+ const { path: path6, format } = sourceResult;
16310
16318
  return {
16311
- content: [{ type: "text", text: `${path5}(${format})` }],
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 = circularBuffer.getLogs({
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
- init_circular_buffer();
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 path5 from "path";
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 = path5.join(dir, "node_modules", "next", "package.json");
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(path5.join(dir, "bun.lockb")))
17070
+ if (fs2.existsSync(path6.join(dir, "bun.lockb")))
17065
17071
  return "bun";
17066
- if (fs2.existsSync(path5.join(dir, "pnpm-lock.yaml")))
17072
+ if (fs2.existsSync(path6.join(dir, "pnpm-lock.yaml")))
17067
17073
  return "pnpm";
17068
- if (fs2.existsSync(path5.join(dir, "yarn.lock")))
17074
+ if (fs2.existsSync(path6.join(dir, "yarn.lock")))
17069
17075
  return "yarn";
17070
- if (fs2.existsSync(path5.join(dir, "package-lock.json")))
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 = path5.join(dir, "pages", "api");
17142
- const handlerPath = path5.join(apiDir, "tidewave.ts");
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: ${path5.relative(dir, handlerPath)}`));
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
- ⚠️ ${path5.relative(dir, handlerPath)} already exists. Overwrite? (Y/n): `));
17175
+ ⚠️ ${path6.relative(dir, handlerPath)} already exists. Overwrite? (Y/n): `));
17172
17176
  if (!shouldOverwrite) {
17173
- console.log(source_default.gray(`⏭️ Skipping: ${path5.relative(dir, handlerPath)}`));
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: ${path5.relative(dir, handlerPath)}`));
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: ${path5.relative(dir, handlerPath)}`));
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 = path5.join(dir, fileName);
17192
+ const filePath = path6.join(dir, fileName);
17189
17193
  if (fs2.existsSync(filePath)) {
17190
- console.log(source_default.yellow(`⏭️ ${fileName} already exists`));
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 = path5.join(dir, "instrumentation.ts");
17253
- const srcPath = path5.join(dir, "src", "instrumentation.ts");
17254
- const hasSrcDir = fs2.existsSync(path5.join(dir, "src"));
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(`⏭️ ${existingFile} already exists`));
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: ${path5.relative(dir, instrumentationPath)}`));
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(path5.dirname(instrumentationPath), { recursive: true });
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: ${path5.relative(dir, instrumentationPath)}`));
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(path6) {
17333
+ function chdir(path7) {
17330
17334
  try {
17331
- process.chdir(path6);
17335
+ process.chdir(path7);
17332
17336
  } catch (e) {
17333
17337
  console.error(source_default.red(`Failed to apply given prefix: ${e}`));
17334
17338
  }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Patch console methods to write directly to the tidewave logger.
3
+ * This is called automatically when this module is imported.
4
+ */
5
+ export declare function patchConsole(): void;
@@ -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 circular buffer.
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 circular buffer.
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 circular buffer.
17
+ * and write it directly to the tidewave logger.
18
18
  */
19
19
  onEnd(span: ReadableSpan): void;
20
20
  /**