tidewave 0.5.5 → 0.7.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.
@@ -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';
@@ -4,47 +4,73 @@ var __getProtoOf = Object.getPrototypeOf;
4
4
  var __defProp = Object.defineProperty;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ function __accessProp(key) {
8
+ return this[key];
9
+ }
10
+ var __toESMCache_node;
11
+ var __toESMCache_esm;
7
12
  var __toESM = (mod, isNodeMode, target) => {
13
+ var canCache = mod != null && typeof mod === "object";
14
+ if (canCache) {
15
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
16
+ var cached = cache.get(mod);
17
+ if (cached)
18
+ return cached;
19
+ }
8
20
  target = mod != null ? __create(__getProtoOf(mod)) : {};
9
21
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
22
  for (let key of __getOwnPropNames(mod))
11
23
  if (!__hasOwnProp.call(to, key))
12
24
  __defProp(to, key, {
13
- get: () => mod[key],
25
+ get: __accessProp.bind(mod, key),
14
26
  enumerable: true
15
27
  });
28
+ if (canCache)
29
+ cache.set(mod, to);
16
30
  return to;
17
31
  };
18
32
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
33
+ var __returnValue = (v) => v;
34
+ function __exportSetter(name, newValue) {
35
+ this[name] = __returnValue.bind(null, newValue);
36
+ }
19
37
  var __export = (target, all) => {
20
38
  for (var name in all)
21
39
  __defProp(target, name, {
22
40
  get: all[name],
23
41
  enumerable: true,
24
42
  configurable: true,
25
- set: (newValue) => all[name] = () => newValue
43
+ set: __exportSetter.bind(all, name)
26
44
  });
27
45
  };
28
46
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
29
47
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
30
48
 
31
- // src/logger/circular-buffer.ts
32
- class CircularBuffer {
33
- buffer;
34
- maxSize;
35
- writeIndex = 0;
36
- count = 0;
37
- constructor(maxSize = 1024) {
38
- this.buffer = new Array(maxSize);
39
- this.maxSize = maxSize;
49
+ // src/logger/tidewave-logger.ts
50
+ import { appendFile, readFile } from "fs/promises";
51
+ import * as path from "path";
52
+ import * as os from "os";
53
+ import * as crypto from "crypto";
54
+
55
+ class TidewaveLogger {
56
+ logFilePath;
57
+ constructor() {
58
+ const cwd = process.cwd();
59
+ const digest = crypto.createHash("md5").update(cwd).digest("hex").slice(0, 16);
60
+ const tempDir = os.tmpdir();
61
+ this.logFilePath = path.join(tempDir, `${digest}.tidewave.ndjson`);
40
62
  }
41
- addLog(log) {
42
- this.buffer[this.writeIndex] = log;
43
- this.writeIndex = (this.writeIndex + 1) % this.maxSize;
44
- this.count = Math.min(this.count + 1, this.maxSize);
63
+ async addLog(log) {
64
+ const line = JSON.stringify(log) + `
65
+ `;
66
+ try {
67
+ await appendFile(this.logFilePath, line, "utf8");
68
+ } catch (error) {
69
+ console.log("[Tidewave] failed to write to log file, error:", error);
70
+ }
45
71
  }
46
- getLogs(options) {
47
- let logs = this.getAllLogs();
72
+ async getLogs(options) {
73
+ let logs = await this.getAllLogs();
48
74
  if (options?.level) {
49
75
  const level = options.level.toUpperCase();
50
76
  logs = logs.filter((log) => log.severityText === level);
@@ -62,34 +88,100 @@ class CircularBuffer {
62
88
  }
63
89
  return logs;
64
90
  }
65
- getAllLogs() {
66
- if (this.count < this.maxSize) {
67
- return this.buffer.slice(0, this.count).filter(Boolean);
91
+ async getAllLogs() {
92
+ try {
93
+ const content = await readFile(this.logFilePath, "utf8");
94
+ return content.split(`
95
+ `).map((line) => {
96
+ try {
97
+ return JSON.parse(line);
98
+ } catch {
99
+ return null;
100
+ }
101
+ }).filter((log) => log !== null);
102
+ } catch (error) {
103
+ console.log("[Tidewave] failed to read from log file, error:", error);
104
+ return [];
68
105
  }
69
- return [...this.buffer.slice(this.writeIndex), ...this.buffer.slice(0, this.writeIndex)].filter(Boolean);
70
106
  }
71
- getStats() {
72
- return {
73
- totalLogs: this.count,
74
- bufferSize: this.maxSize,
75
- bufferUsage: Math.min(this.count / this.maxSize * 100, 100).toFixed(1) + "%"
76
- };
107
+ }
108
+ var tidewaveLogger;
109
+ var init_tidewave_logger = __esm(() => {
110
+ tidewaveLogger = new TidewaveLogger;
111
+ });
112
+
113
+ // src/logger/console-patch.ts
114
+ var exports_console_patch = {};
115
+ __export(exports_console_patch, {
116
+ patchConsole: () => patchConsole
117
+ });
118
+ function stripAnsiCodes(text) {
119
+ return text.replace(ANSI_REGEX, "");
120
+ }
121
+ function patchConsole() {
122
+ const isBrowser = typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined";
123
+ if (isBrowser) {
124
+ return;
77
125
  }
78
- clear() {
79
- this.buffer = new Array(this.maxSize);
80
- this.writeIndex = 0;
81
- this.count = 0;
126
+ if (globalThis.__TIDEWAVE_CONSOLE_PATCHED__) {
127
+ return;
82
128
  }
129
+ const severityMap = {
130
+ log: "INFO",
131
+ info: "INFO",
132
+ warn: "WARN",
133
+ error: "ERROR",
134
+ debug: "DEBUG"
135
+ };
136
+ Object.entries(severityMap).forEach(([method, severity]) => {
137
+ const original = console[method].bind(console);
138
+ console[method] = (...args) => {
139
+ try {
140
+ const body = args.map((arg) => {
141
+ if (typeof arg === "string")
142
+ return arg;
143
+ if (arg instanceof Error) {
144
+ return String(arg.stack);
145
+ }
146
+ if (typeof arg === "object") {
147
+ try {
148
+ return JSON.stringify(arg);
149
+ } catch {
150
+ return String(arg);
151
+ }
152
+ }
153
+ return String(arg);
154
+ }).map(stripAnsiCodes).join(" ");
155
+ const isAllWhitespace = body.match(/^\s+$/);
156
+ if (!isAllWhitespace) {
157
+ tidewaveLogger.addLog({
158
+ timestamp: new Date().toISOString(),
159
+ severityText: severity,
160
+ body,
161
+ attributes: {
162
+ "log.origin": "console",
163
+ "log.method": method
164
+ }
165
+ });
166
+ }
167
+ } catch {}
168
+ original(...args);
169
+ };
170
+ });
171
+ globalThis.__TIDEWAVE_CONSOLE_PATCHED__ = true;
83
172
  }
84
- var circularBuffer;
85
- var init_circular_buffer = __esm(() => {
86
- if (!globalThis.__tidewaveCircularBuffer) {
87
- globalThis.__tidewaveCircularBuffer = new CircularBuffer(1024);
88
- }
89
- circularBuffer = globalThis.__tidewaveCircularBuffer;
173
+ var ANSI_REGEX;
174
+ var init_console_patch = __esm(() => {
175
+ init_tidewave_logger();
176
+ ANSI_REGEX = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
90
177
  });
91
178
 
179
+ // src/next-js/instrumentation.ts
180
+ init_console_patch();
181
+
92
182
  // src/logger/tidewave-span-processor.ts
183
+ init_tidewave_logger();
184
+
93
185
  class TidewaveSpanProcessor {
94
186
  onStart(_span, _parentContext) {}
95
187
  onEnd(span) {
@@ -108,8 +200,8 @@ class TidewaveSpanProcessor {
108
200
  const httpUrl = span.attributes["http.url"];
109
201
  const httpTarget = span.attributes["http.target"];
110
202
  const httpStatusCode = span.attributes["http.status_code"];
111
- const path = route || httpTarget || httpUrl || "unknown";
112
- if (typeof path === "string" && path.startsWith("/tidewave")) {
203
+ const path2 = route || httpTarget || httpUrl || "unknown";
204
+ if (typeof path2 === "string" && path2.startsWith("/tidewave")) {
113
205
  return;
114
206
  }
115
207
  const durationMs = this.calculateDuration(span);
@@ -118,7 +210,7 @@ class TidewaveSpanProcessor {
118
210
  if (spanType === "BaseServer.handleRequest") {
119
211
  const method = httpMethod || "UNKNOWN";
120
212
  const status = httpStatusCode || "unknown";
121
- message = `${method} ${path} ${status} ${durationMs.toFixed(2)}ms`;
213
+ message = `${method} ${path2} ${status} ${durationMs.toFixed(2)}ms`;
122
214
  if (typeof httpStatusCode === "number") {
123
215
  if (httpStatusCode >= 500)
124
216
  severity = "ERROR";
@@ -130,7 +222,7 @@ class TidewaveSpanProcessor {
130
222
  } else if (spanType === "AppRouteRouteHandlers.runHandler") {
131
223
  message = `API route: ${route || "unknown"} (${durationMs.toFixed(2)}ms)`;
132
224
  }
133
- circularBuffer.addLog({
225
+ tidewaveLogger.addLog({
134
226
  timestamp: new Date(span.endTime[0] * 1000 + span.endTime[1] / 1e6).toISOString(),
135
227
  severityText: severity,
136
228
  body: message,
@@ -155,100 +247,27 @@ class TidewaveSpanProcessor {
155
247
  async forceFlush() {}
156
248
  async shutdown() {}
157
249
  }
158
- var init_tidewave_span_processor = __esm(() => {
159
- init_circular_buffer();
160
- });
161
-
162
250
  // src/logger/tidewave-log-record-processor.ts
251
+ init_tidewave_logger();
252
+
163
253
  class TidewaveLogRecordProcessor {
164
254
  onEmit(logRecord, _context) {
165
255
  try {
166
256
  const body = String(logRecord.body || "");
167
- circularBuffer.addLog({
257
+ tidewaveLogger.addLog({
168
258
  timestamp: new Date(logRecord.hrTime[0] * 1000 + logRecord.hrTime[1] / 1e6).toISOString(),
169
259
  severityText: logRecord.severityText || "INFO",
170
260
  body,
171
- attributes: logRecord.attributes,
172
- resource: logRecord.resource?.attributes
261
+ attributes: logRecord.attributes
173
262
  });
174
263
  } catch (_error) {}
175
264
  }
176
265
  async forceFlush() {}
177
266
  async shutdown() {}
178
267
  }
179
- var init_tidewave_log_record_processor = __esm(() => {
180
- init_circular_buffer();
181
- });
182
-
183
- // src/logger/instrumentation.ts
184
- var exports_instrumentation = {};
185
- __export(exports_instrumentation, {
186
- TidewaveSpanProcessor: () => TidewaveSpanProcessor,
187
- TidewaveLogRecordProcessor: () => TidewaveLogRecordProcessor
188
- });
189
- function stripAnsiCodes(text) {
190
- return text.replace(ANSI_REGEX, "");
191
- }
192
- function patchConsole() {
193
- const isBrowser = typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined";
194
- if (isBrowser) {
195
- return;
196
- }
197
- if (globalThis.__TIDEWAVE_CONSOLE_PATCHED__) {
198
- return;
199
- }
200
- const severityMap = {
201
- log: "INFO",
202
- info: "INFO",
203
- warn: "WARN",
204
- error: "ERROR",
205
- debug: "DEBUG"
206
- };
207
- Object.entries(severityMap).forEach(([method, severity]) => {
208
- const original = console[method].bind(console);
209
- console[method] = (...args) => {
210
- try {
211
- const body = args.map((arg) => {
212
- if (typeof arg === "string")
213
- return arg;
214
- if (arg instanceof Error) {
215
- return String(arg.stack);
216
- }
217
- if (typeof arg === "object") {
218
- try {
219
- return JSON.stringify(arg);
220
- } catch {
221
- return String(arg);
222
- }
223
- }
224
- return String(arg);
225
- }).map(stripAnsiCodes).join(" ");
226
- circularBuffer.addLog({
227
- timestamp: new Date().toISOString(),
228
- severityText: severity,
229
- body,
230
- attributes: {
231
- "log.origin": "console",
232
- "log.method": method
233
- }
234
- });
235
- } catch {}
236
- original(...args);
237
- };
238
- });
239
- globalThis.__TIDEWAVE_CONSOLE_PATCHED__ = true;
240
- }
241
- var ANSI_REGEX;
242
- var init_instrumentation = __esm(() => {
243
- init_circular_buffer();
244
- init_tidewave_span_processor();
245
- init_tidewave_log_record_processor();
246
- ANSI_REGEX = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
247
- patchConsole();
248
- });
249
268
 
250
269
  // src/next-js/instrumentation.ts
251
- init_instrumentation();
270
+ patchConsole();
252
271
  export {
253
272
  TidewaveSpanProcessor,
254
273
  TidewaveLogRecordProcessor
@@ -1,5 +1,5 @@
1
1
  import ts from 'typescript';
2
- import type { SymbolInfo } from '../core';
2
+ import type { SymbolInfo, FileInfo } from '../core';
3
3
  export declare function getSignature(checker: ts.TypeChecker, symbol: ts.Symbol, type: ts.Type): string;
4
4
  export declare function getTypeString(checker: ts.TypeChecker, symbol: ts.Symbol, type: ts.Type): string;
5
- export declare function formatOutput(info: SymbolInfo): string;
5
+ export declare function formatOutput(info: SymbolInfo | FileInfo): string;
@@ -1,6 +1,5 @@
1
1
  import type { ExtractionRequest, ExtractResult, ExtractorOptions, ResolveResult } from '../core';
2
- import { formatOutput } from './formatters';
3
2
  export declare function extractDocs(modulePath: string): Promise<ExtractResult>;
4
3
  export declare function getSourceLocation(reference: string): Promise<ResolveResult>;
5
4
  export declare function extractSymbol(request: ExtractionRequest, options?: ExtractorOptions): Promise<ExtractResult>;
6
- export { formatOutput };
5
+ export { formatOutput } from './formatters';
@@ -1,4 +1,4 @@
1
1
  import ts from 'typescript';
2
- import type { ExtractResult } from '../core';
2
+ import type { SymbolInfo, ExtractError } from '../core';
3
3
  export declare function findSymbolInJavaScriptFile(sourceFile: ts.SourceFile, checker: ts.TypeChecker, symbolName: string): ts.Symbol | undefined;
4
- export declare function getSymbolInfo(checker: ts.TypeChecker, symbol: ts.Symbol, member?: string, isStatic?: boolean): ExtractResult;
4
+ export declare function getSymbolInfo(checker: ts.TypeChecker, symbol: ts.Symbol, member?: string, isStatic?: boolean): SymbolInfo | ExtractError;
@@ -3,3 +3,4 @@ export declare function getLocation(symbol: ts.Symbol): string;
3
3
  export declare function getDocumentation(checker: ts.TypeChecker, symbol: ts.Symbol): string;
4
4
  export declare function getJSDoc(checker: ts.TypeChecker, symbol: ts.Symbol): string;
5
5
  export declare function getSymbolKind(symbol: ts.Symbol): string;
6
+ export declare function getFileOverview(sourceFile: ts.SourceFile): string | undefined;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,181 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ function __accessProp(key) {
8
+ return this[key];
9
+ }
10
+ var __toESMCache_node;
11
+ var __toESMCache_esm;
12
+ var __toESM = (mod, isNodeMode, target) => {
13
+ var canCache = mod != null && typeof mod === "object";
14
+ if (canCache) {
15
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
16
+ var cached = cache.get(mod);
17
+ if (cached)
18
+ return cached;
19
+ }
20
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
21
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
22
+ for (let key of __getOwnPropNames(mod))
23
+ if (!__hasOwnProp.call(to, key))
24
+ __defProp(to, key, {
25
+ get: __accessProp.bind(mod, key),
26
+ enumerable: true
27
+ });
28
+ if (canCache)
29
+ cache.set(mod, to);
30
+ return to;
31
+ };
32
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
33
+ var __returnValue = (v) => v;
34
+ function __exportSetter(name, newValue) {
35
+ this[name] = __returnValue.bind(null, newValue);
36
+ }
37
+ var __export = (target, all) => {
38
+ for (var name in all)
39
+ __defProp(target, name, {
40
+ get: all[name],
41
+ enumerable: true,
42
+ configurable: true,
43
+ set: __exportSetter.bind(all, name)
44
+ });
45
+ };
46
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
47
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
48
+
49
+ // src/logger/tidewave-logger.ts
50
+ import { appendFile, readFile } from "fs/promises";
51
+ import * as path from "path";
52
+ import * as os from "os";
53
+ import * as crypto from "crypto";
54
+
55
+ class TidewaveLogger {
56
+ logFilePath;
57
+ constructor() {
58
+ const cwd = process.cwd();
59
+ const digest = crypto.createHash("md5").update(cwd).digest("hex").slice(0, 16);
60
+ const tempDir = os.tmpdir();
61
+ this.logFilePath = path.join(tempDir, `${digest}.tidewave.ndjson`);
62
+ }
63
+ async addLog(log) {
64
+ const line = JSON.stringify(log) + `
65
+ `;
66
+ try {
67
+ await appendFile(this.logFilePath, line, "utf8");
68
+ } catch (error) {
69
+ console.log("[Tidewave] failed to write to log file, error:", error);
70
+ }
71
+ }
72
+ async getLogs(options) {
73
+ let logs = await this.getAllLogs();
74
+ if (options?.level) {
75
+ const level = options.level.toUpperCase();
76
+ logs = logs.filter((log) => log.severityText === level);
77
+ }
78
+ if (options?.since) {
79
+ const sinceDate = new Date(options.since);
80
+ logs = logs.filter((log) => new Date(log.timestamp) >= sinceDate);
81
+ }
82
+ if (options?.grep) {
83
+ const regex = new RegExp(options.grep, "i");
84
+ logs = logs.filter((log) => regex.test(log.body) || regex.test(JSON.stringify(log.attributes)));
85
+ }
86
+ if (options?.tail) {
87
+ logs = logs.slice(-options.tail);
88
+ }
89
+ return logs;
90
+ }
91
+ async getAllLogs() {
92
+ try {
93
+ const content = await readFile(this.logFilePath, "utf8");
94
+ return content.split(`
95
+ `).map((line) => {
96
+ try {
97
+ return JSON.parse(line);
98
+ } catch {
99
+ return null;
100
+ }
101
+ }).filter((log) => log !== null);
102
+ } catch (error) {
103
+ console.log("[Tidewave] failed to read from log file, error:", error);
104
+ return [];
105
+ }
106
+ }
107
+ }
108
+ var tidewaveLogger;
109
+ var init_tidewave_logger = __esm(() => {
110
+ tidewaveLogger = new TidewaveLogger;
111
+ });
112
+
113
+ // src/logger/console-patch.ts
114
+ var exports_console_patch = {};
115
+ __export(exports_console_patch, {
116
+ patchConsole: () => patchConsole
117
+ });
118
+ function stripAnsiCodes(text) {
119
+ return text.replace(ANSI_REGEX, "");
120
+ }
121
+ function patchConsole() {
122
+ const isBrowser = typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined";
123
+ if (isBrowser) {
124
+ return;
125
+ }
126
+ if (globalThis.__TIDEWAVE_CONSOLE_PATCHED__) {
127
+ return;
128
+ }
129
+ const severityMap = {
130
+ log: "INFO",
131
+ info: "INFO",
132
+ warn: "WARN",
133
+ error: "ERROR",
134
+ debug: "DEBUG"
135
+ };
136
+ Object.entries(severityMap).forEach(([method, severity]) => {
137
+ const original = console[method].bind(console);
138
+ console[method] = (...args) => {
139
+ try {
140
+ const body = args.map((arg) => {
141
+ if (typeof arg === "string")
142
+ return arg;
143
+ if (arg instanceof Error) {
144
+ return String(arg.stack);
145
+ }
146
+ if (typeof arg === "object") {
147
+ try {
148
+ return JSON.stringify(arg);
149
+ } catch {
150
+ return String(arg);
151
+ }
152
+ }
153
+ return String(arg);
154
+ }).map(stripAnsiCodes).join(" ");
155
+ const isAllWhitespace = body.match(/^\s+$/);
156
+ if (!isAllWhitespace) {
157
+ tidewaveLogger.addLog({
158
+ timestamp: new Date().toISOString(),
159
+ severityText: severity,
160
+ body,
161
+ attributes: {
162
+ "log.origin": "console",
163
+ "log.method": method
164
+ }
165
+ });
166
+ }
167
+ } catch {}
168
+ original(...args);
169
+ };
170
+ });
171
+ globalThis.__TIDEWAVE_CONSOLE_PATCHED__ = true;
172
+ }
173
+ var ANSI_REGEX;
174
+ var init_console_patch = __esm(() => {
175
+ init_tidewave_logger();
176
+ ANSI_REGEX = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
177
+ });
178
+
179
+ // src/tanstack.ts
180
+ init_console_patch();
181
+ patchConsole();
@@ -1,4 +1,3 @@
1
1
  import type { TidewaveConfig } from './core';
2
2
  import type { Plugin } from 'vite';
3
- import './logger/instrumentation';
4
3
  export default function tidewave(config?: TidewaveConfig): Plugin;