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.
@@ -20137,12 +20137,12 @@ Defaults to 30000 (30 seconds).`),
20137
20137
  });
20138
20138
 
20139
20139
  // package.json
20140
- var name = "tidewave", version = "0.5.5", package_default;
20140
+ var name = "tidewave", version = "0.6.0", package_default;
20141
20141
  var init_package = __esm(() => {
20142
20142
  package_default = {
20143
20143
  name,
20144
20144
  version,
20145
- description: "Tidewave for JavaScript/Next.js",
20145
+ description: "Tidewave for JavaScript (Next.js, TanStack, Vite)",
20146
20146
  keywords: [
20147
20147
  "typescript",
20148
20148
  "documentation",
@@ -20185,6 +20185,11 @@ var init_package = __esm(() => {
20185
20185
  import: "./dist/next-js/instrumentation.js",
20186
20186
  require: "./dist/next-js/instrumentation.js"
20187
20187
  },
20188
+ "./tanstack": {
20189
+ types: "./dist/tanstack.d.ts",
20190
+ import: "./dist/tanstack.js",
20191
+ require: "./dist/tanstack.js"
20192
+ },
20188
20193
  "./package.json": "./package.json"
20189
20194
  },
20190
20195
  files: [
@@ -20195,7 +20200,7 @@ var init_package = __esm(() => {
20195
20200
  ],
20196
20201
  scripts: {
20197
20202
  dist: "bun run clean && bun run build:js && bun run build:types",
20198
- "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",
20203
+ "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",
20199
20204
  "build:types": "tsc -p tsconfig.declarations.json",
20200
20205
  dev: "bun run src/cli/index.ts",
20201
20206
  test: "bun test",
@@ -21092,23 +21097,31 @@ var init_src = __esm(() => {
21092
21097
  };
21093
21098
  });
21094
21099
 
21095
- // src/logger/circular-buffer.ts
21096
- class CircularBuffer {
21097
- buffer;
21098
- maxSize;
21099
- writeIndex = 0;
21100
- count = 0;
21101
- constructor(maxSize = 1024) {
21102
- this.buffer = new Array(maxSize);
21103
- this.maxSize = maxSize;
21104
- }
21105
- addLog(log) {
21106
- this.buffer[this.writeIndex] = log;
21107
- this.writeIndex = (this.writeIndex + 1) % this.maxSize;
21108
- this.count = Math.min(this.count + 1, this.maxSize);
21109
- }
21110
- getLogs(options) {
21111
- let logs = this.getAllLogs();
21100
+ // src/logger/tidewave-logger.ts
21101
+ import { appendFile, readFile } from "fs/promises";
21102
+ import * as path5 from "path";
21103
+ import * as os from "os";
21104
+ import * as crypto from "crypto";
21105
+
21106
+ class TidewaveLogger {
21107
+ logFilePath;
21108
+ constructor() {
21109
+ const cwd = process.cwd();
21110
+ const digest = crypto.createHash("md5").update(cwd).digest("hex").slice(0, 16);
21111
+ const tempDir = os.tmpdir();
21112
+ this.logFilePath = path5.join(tempDir, `${digest}.tidewave.ndjson`);
21113
+ }
21114
+ async addLog(log) {
21115
+ const line = JSON.stringify(log) + `
21116
+ `;
21117
+ try {
21118
+ await appendFile(this.logFilePath, line, "utf8");
21119
+ } catch (error) {
21120
+ console.log("[Tidewave] failed to write to log file, error:", error);
21121
+ }
21122
+ }
21123
+ async getLogs(options) {
21124
+ let logs = await this.getAllLogs();
21112
21125
  if (options?.level) {
21113
21126
  const level = options.level.toUpperCase();
21114
21127
  logs = logs.filter((log) => log.severityText === level);
@@ -21126,31 +21139,26 @@ class CircularBuffer {
21126
21139
  }
21127
21140
  return logs;
21128
21141
  }
21129
- getAllLogs() {
21130
- if (this.count < this.maxSize) {
21131
- return this.buffer.slice(0, this.count).filter(Boolean);
21142
+ async getAllLogs() {
21143
+ try {
21144
+ const content = await readFile(this.logFilePath, "utf8");
21145
+ return content.split(`
21146
+ `).map((line) => {
21147
+ try {
21148
+ return JSON.parse(line);
21149
+ } catch {
21150
+ return null;
21151
+ }
21152
+ }).filter((log) => log !== null);
21153
+ } catch (error) {
21154
+ console.log("[Tidewave] failed to read from log file, error:", error);
21155
+ return [];
21132
21156
  }
21133
- return [...this.buffer.slice(this.writeIndex), ...this.buffer.slice(0, this.writeIndex)].filter(Boolean);
21134
- }
21135
- getStats() {
21136
- return {
21137
- totalLogs: this.count,
21138
- bufferSize: this.maxSize,
21139
- bufferUsage: Math.min(this.count / this.maxSize * 100, 100).toFixed(1) + "%"
21140
- };
21141
- }
21142
- clear() {
21143
- this.buffer = new Array(this.maxSize);
21144
- this.writeIndex = 0;
21145
- this.count = 0;
21146
21157
  }
21147
21158
  }
21148
- var circularBuffer;
21149
- var init_circular_buffer = __esm(() => {
21150
- if (!globalThis.__tidewaveCircularBuffer) {
21151
- globalThis.__tidewaveCircularBuffer = new CircularBuffer(1024);
21152
- }
21153
- circularBuffer = globalThis.__tidewaveCircularBuffer;
21159
+ var tidewaveLogger;
21160
+ var init_tidewave_logger = __esm(() => {
21161
+ tidewaveLogger = new TidewaveLogger;
21154
21162
  });
21155
21163
 
21156
21164
  // src/mcp.ts
@@ -21242,15 +21250,15 @@ async function handleGetSourcePath({ reference }) {
21242
21250
  isError: true
21243
21251
  };
21244
21252
  }
21245
- const { path: path5, format } = sourceResult;
21253
+ const { path: path6, format } = sourceResult;
21246
21254
  return {
21247
- content: [{ type: "text", text: `${path5}(${format})` }],
21255
+ content: [{ type: "text", text: `${path6}(${format})` }],
21248
21256
  isError: false
21249
21257
  };
21250
21258
  }
21251
21259
  async function handleGetLogs(args) {
21252
21260
  try {
21253
- const logs = circularBuffer.getLogs({
21261
+ const logs = await tidewaveLogger.getLogs({
21254
21262
  tail: args.tail,
21255
21263
  grep: args.grep,
21256
21264
  level: args.level,
@@ -21306,7 +21314,7 @@ var init_mcp2 = __esm(() => {
21306
21314
  init_package();
21307
21315
  init_core();
21308
21316
  init_src();
21309
- init_circular_buffer();
21317
+ init_tidewave_logger();
21310
21318
  ({
21311
21319
  docs: { mcp: docsMcp },
21312
21320
  source: { mcp: sourceMcp },
@@ -21359,108 +21367,6 @@ var init_mcp3 = __esm(() => {
21359
21367
  init_mcp2();
21360
21368
  });
21361
21369
 
21362
- // src/http/handlers/shell.ts
21363
- import { spawn } from "child_process";
21364
- import { platform } from "os";
21365
- async function handleShell(req, res, next) {
21366
- try {
21367
- if (req.method !== "POST") {
21368
- methodNotAllowed(res);
21369
- return;
21370
- }
21371
- const command = req.body?.command;
21372
- if (!command) {
21373
- res.statusCode = 400;
21374
- res.end("Missing command in request body");
21375
- return;
21376
- }
21377
- res.statusCode = 200;
21378
- res.setHeader("Content-Type", "application/octet-stream");
21379
- const { cmd, args } = getShellCommand(command);
21380
- const child = spawn(cmd, args, {
21381
- stdio: ["ignore", "pipe", "pipe"],
21382
- shell: false,
21383
- cwd: process.cwd()
21384
- });
21385
- child.stdout.on("data", (data) => {
21386
- if (!res.destroyed) {
21387
- const chunk = Buffer.concat([
21388
- Buffer.from([0]),
21389
- Buffer.from([
21390
- data.length >>> 24 & 255,
21391
- data.length >>> 16 & 255,
21392
- data.length >>> 8 & 255,
21393
- data.length & 255
21394
- ]),
21395
- data
21396
- ]);
21397
- res.write(chunk);
21398
- }
21399
- });
21400
- child.stderr.on("data", (data) => {
21401
- if (!res.destroyed) {
21402
- const chunk = Buffer.concat([
21403
- Buffer.from([0]),
21404
- Buffer.from([
21405
- data.length >>> 24 & 255,
21406
- data.length >>> 16 & 255,
21407
- data.length >>> 8 & 255,
21408
- data.length & 255
21409
- ]),
21410
- data
21411
- ]);
21412
- res.write(chunk);
21413
- }
21414
- });
21415
- child.on("exit", (code) => {
21416
- if (!res.destroyed) {
21417
- const statusData = JSON.stringify({ status: code || 0 });
21418
- const statusBuffer = Buffer.from(statusData);
21419
- const chunk = Buffer.concat([
21420
- Buffer.from([1]),
21421
- Buffer.from([
21422
- statusBuffer.length >>> 24 & 255,
21423
- statusBuffer.length >>> 16 & 255,
21424
- statusBuffer.length >>> 8 & 255,
21425
- statusBuffer.length & 255
21426
- ]),
21427
- statusBuffer
21428
- ]);
21429
- res.write(chunk);
21430
- }
21431
- res.end();
21432
- });
21433
- req.on("close", () => {
21434
- if (!child.killed) {
21435
- child.kill();
21436
- }
21437
- });
21438
- } catch (e) {
21439
- console.error(`[Tidewave] Failed to execute shell command: ${e}`);
21440
- if (!res.headersSent) {
21441
- res.statusCode = 500;
21442
- res.setHeader("Content-Type", "application/json");
21443
- res.end(JSON.stringify({
21444
- error: "Internal server error",
21445
- message: e instanceof Error ? e.message : String(e)
21446
- }));
21447
- }
21448
- next(e);
21449
- }
21450
- }
21451
- function getShellCommand(command) {
21452
- const isWindows = platform() === "win32";
21453
- if (isWindows) {
21454
- const comspec = process.env.COMSPEC || "cmd.exe";
21455
- return { cmd: comspec, args: ["/s", "/c", command] };
21456
- } else {
21457
- return { cmd: "sh", args: ["-c", command] };
21458
- }
21459
- }
21460
- var init_shell = __esm(() => {
21461
- init_http();
21462
- });
21463
-
21464
21370
  // src/http/handlers/html.ts
21465
21371
  function createHandleHtml(config) {
21466
21372
  return async function handleHtml(req, res, next) {
@@ -22003,7 +21909,7 @@ var require_has_flag = __commonJS((exports, module) => {
22003
21909
 
22004
21910
  // node_modules/supports-color/index.js
22005
21911
  var require_supports_color = __commonJS((exports, module) => {
22006
- var os = __require("os");
21912
+ var os2 = __require("os");
22007
21913
  var tty = __require("tty");
22008
21914
  var hasFlag = require_has_flag();
22009
21915
  var { env } = process;
@@ -22051,7 +21957,7 @@ var require_supports_color = __commonJS((exports, module) => {
22051
21957
  return min;
22052
21958
  }
22053
21959
  if (process.platform === "win32") {
22054
- const osRelease = os.release().split(".");
21960
+ const osRelease = os2.release().split(".");
22055
21961
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
22056
21962
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
22057
21963
  }
@@ -31973,11 +31879,11 @@ var require_mime_types = __commonJS((exports) => {
31973
31879
  }
31974
31880
  return exts[0];
31975
31881
  }
31976
- function lookup(path5) {
31977
- if (!path5 || typeof path5 !== "string") {
31882
+ function lookup(path6) {
31883
+ if (!path6 || typeof path6 !== "string") {
31978
31884
  return false;
31979
31885
  }
31980
- var extension2 = extname("x." + path5).toLowerCase().slice(1);
31886
+ var extension2 = extname("x." + path6).toLowerCase().slice(1);
31981
31887
  if (!extension2) {
31982
31888
  return false;
31983
31889
  }
@@ -34788,8 +34694,7 @@ function getHandlers(config) {
34788
34694
  return {
34789
34695
  "": createHandleHtml(config),
34790
34696
  config: createHandleConfig(config),
34791
- mcp: handleMcp,
34792
- shell: handleShell
34697
+ mcp: handleMcp
34793
34698
  };
34794
34699
  }
34795
34700
  function configureServer(server = import_connect.default(), config = DEFAULT_OPTIONS) {
@@ -34797,8 +34702,8 @@ function configureServer(server = import_connect.default(), config = DEFAULT_OPT
34797
34702
  server.use(`${ENDPOINT}`, securityChecker);
34798
34703
  server.use(`${ENDPOINT}`, import_body_parser.default.json());
34799
34704
  const handlers = getHandlers(config);
34800
- for (const [path5, handler] of Object.entries(handlers)) {
34801
- server.use(ENDPOINT + "/" + path5, handler);
34705
+ for (const [path6, handler] of Object.entries(handlers)) {
34706
+ server.use(ENDPOINT + "/" + path6, handler);
34802
34707
  }
34803
34708
  return server;
34804
34709
  }
@@ -34824,7 +34729,6 @@ var import_connect, import_body_parser, ENDPOINT = "/tidewave", DEFAULT_PORT = 5
34824
34729
  var init_http = __esm(() => {
34825
34730
  import_connect = __toESM(require_connect(), 1);
34826
34731
  init_mcp3();
34827
- init_shell();
34828
34732
  init_html();
34829
34733
  init_config();
34830
34734
  import_body_parser = __toESM(require_body_parser(), 1);
@@ -34836,102 +34740,10 @@ var init_http = __esm(() => {
34836
34740
  };
34837
34741
  });
34838
34742
 
34839
- // src/logger/tidewave-span-processor.ts
34840
- class TidewaveSpanProcessor {
34841
- onStart(_span, _parentContext) {}
34842
- onEnd(span) {
34843
- try {
34844
- const spanType = span.attributes["next.span_type"];
34845
- const httpMethod = span.attributes["http.method"];
34846
- const relevantSpanTypes = [
34847
- "BaseServer.handleRequest",
34848
- "AppRender.getBodyResult",
34849
- "AppRouteRouteHandlers.runHandler"
34850
- ];
34851
- if (!spanType || !relevantSpanTypes.includes(spanType)) {
34852
- return;
34853
- }
34854
- const route = span.attributes["next.route"] || span.attributes["http.route"];
34855
- const httpUrl = span.attributes["http.url"];
34856
- const httpTarget = span.attributes["http.target"];
34857
- const httpStatusCode = span.attributes["http.status_code"];
34858
- const path5 = route || httpTarget || httpUrl || "unknown";
34859
- if (typeof path5 === "string" && path5.startsWith("/tidewave")) {
34860
- return;
34861
- }
34862
- const durationMs = this.calculateDuration(span);
34863
- let message = "";
34864
- let severity = "INFO";
34865
- if (spanType === "BaseServer.handleRequest") {
34866
- const method = httpMethod || "UNKNOWN";
34867
- const status = httpStatusCode || "unknown";
34868
- message = `${method} ${path5} ${status} ${durationMs.toFixed(2)}ms`;
34869
- if (typeof httpStatusCode === "number") {
34870
- if (httpStatusCode >= 500)
34871
- severity = "ERROR";
34872
- else if (httpStatusCode >= 400)
34873
- severity = "WARN";
34874
- }
34875
- } else if (spanType === "AppRender.getBodyResult") {
34876
- message = `Rendered route: ${route || "unknown"} (${durationMs.toFixed(2)}ms)`;
34877
- } else if (spanType === "AppRouteRouteHandlers.runHandler") {
34878
- message = `API route: ${route || "unknown"} (${durationMs.toFixed(2)}ms)`;
34879
- }
34880
- circularBuffer.addLog({
34881
- timestamp: new Date(span.endTime[0] * 1000 + span.endTime[1] / 1e6).toISOString(),
34882
- severityText: severity,
34883
- body: message,
34884
- attributes: {
34885
- "log.origin": "opentelemetry-span",
34886
- "span.name": span.name,
34887
- "span.kind": span.kind,
34888
- "span.type": spanType,
34889
- "http.method": httpMethod,
34890
- "http.route": route,
34891
- "http.status_code": httpStatusCode,
34892
- "duration.ms": durationMs
34893
- }
34894
- });
34895
- } catch (_error) {}
34896
- }
34897
- calculateDuration(span) {
34898
- const startTimeMs = span.startTime[0] * 1000 + span.startTime[1] / 1e6;
34899
- const endTimeMs = span.endTime[0] * 1000 + span.endTime[1] / 1e6;
34900
- return endTimeMs - startTimeMs;
34901
- }
34902
- async forceFlush() {}
34903
- async shutdown() {}
34904
- }
34905
- var init_tidewave_span_processor = __esm(() => {
34906
- init_circular_buffer();
34907
- });
34908
-
34909
- // src/logger/tidewave-log-record-processor.ts
34910
- class TidewaveLogRecordProcessor {
34911
- onEmit(logRecord, _context) {
34912
- try {
34913
- const body = String(logRecord.body || "");
34914
- circularBuffer.addLog({
34915
- timestamp: new Date(logRecord.hrTime[0] * 1000 + logRecord.hrTime[1] / 1e6).toISOString(),
34916
- severityText: logRecord.severityText || "INFO",
34917
- body,
34918
- attributes: logRecord.attributes,
34919
- resource: logRecord.resource?.attributes
34920
- });
34921
- } catch (_error) {}
34922
- }
34923
- async forceFlush() {}
34924
- async shutdown() {}
34925
- }
34926
- var init_tidewave_log_record_processor = __esm(() => {
34927
- init_circular_buffer();
34928
- });
34929
-
34930
- // src/logger/instrumentation.ts
34931
- var exports_instrumentation = {};
34932
- __export(exports_instrumentation, {
34933
- TidewaveSpanProcessor: () => TidewaveSpanProcessor,
34934
- TidewaveLogRecordProcessor: () => TidewaveLogRecordProcessor
34743
+ // src/logger/console-patch.ts
34744
+ var exports_console_patch = {};
34745
+ __export(exports_console_patch, {
34746
+ patchConsole: () => patchConsole
34935
34747
  });
34936
34748
  function stripAnsiCodes(text) {
34937
34749
  return text.replace(ANSI_REGEX, "");
@@ -34970,15 +34782,18 @@ function patchConsole() {
34970
34782
  }
34971
34783
  return String(arg);
34972
34784
  }).map(stripAnsiCodes).join(" ");
34973
- circularBuffer.addLog({
34974
- timestamp: new Date().toISOString(),
34975
- severityText: severity,
34976
- body,
34977
- attributes: {
34978
- "log.origin": "console",
34979
- "log.method": method
34980
- }
34981
- });
34785
+ const isAllWhitespace = body.match(/^\s+$/);
34786
+ if (!isAllWhitespace) {
34787
+ tidewaveLogger.addLog({
34788
+ timestamp: new Date().toISOString(),
34789
+ severityText: severity,
34790
+ body,
34791
+ attributes: {
34792
+ "log.origin": "console",
34793
+ "log.method": method
34794
+ }
34795
+ });
34796
+ }
34982
34797
  } catch {}
34983
34798
  original(...args);
34984
34799
  };
@@ -34986,12 +34801,9 @@ function patchConsole() {
34986
34801
  globalThis.__TIDEWAVE_CONSOLE_PATCHED__ = true;
34987
34802
  }
34988
34803
  var ANSI_REGEX;
34989
- var init_instrumentation = __esm(() => {
34990
- init_circular_buffer();
34991
- init_tidewave_span_processor();
34992
- init_tidewave_log_record_processor();
34804
+ var init_console_patch = __esm(() => {
34805
+ init_tidewave_logger();
34993
34806
  ANSI_REGEX = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
34994
- patchConsole();
34995
34807
  });
34996
34808
 
34997
34809
  // src/next-js/handler.ts
@@ -35010,7 +34822,8 @@ async function tidewaveHandler(config = DEFAULT_CONFIG) {
35010
34822
  throw Error(`[Tidewave] tidewave is designed to only work on development environment, got: ${env}`);
35011
34823
  }
35012
34824
  if (process.env["NEXT_RUNTIME"] !== "edge") {
35013
- await Promise.resolve().then(() => (init_instrumentation(), exports_instrumentation));
34825
+ const { patchConsole: patchConsole2 } = await Promise.resolve().then(() => (init_console_patch(), exports_console_patch));
34826
+ patchConsole2();
35014
34827
  }
35015
34828
  config.framework = "nextjs";
35016
34829
  config.projectName = config.projectName || await getProjectName("next_app");
@@ -1,7 +1,2 @@
1
- /**
2
- * Tidewave OpenTelemetry processors for Next.js
3
- *
4
- * Importing this module will automatically patch console.log to capture console output.
5
- * You can then add the processors to your OpenTelemetry setup.
6
- */
7
- export { TidewaveSpanProcessor, TidewaveLogRecordProcessor } from '../logger/instrumentation';
1
+ export { TidewaveSpanProcessor } from '../logger/tidewave-span-processor';
2
+ export { TidewaveLogRecordProcessor } from '../logger/tidewave-log-record-processor';