@graphty/remote-logger 1.2.2 → 1.3.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.
Files changed (84) hide show
  1. package/README.md +53 -2
  2. package/dist/bundle/browser-entry.d.ts +34 -0
  3. package/dist/bundle/browser-entry.d.ts.map +1 -0
  4. package/dist/bundle/browser-entry.js +129 -0
  5. package/dist/bundle/browser-entry.js.map +1 -0
  6. package/dist/client/RemoteLogClient.d.ts +2 -1
  7. package/dist/client/RemoteLogClient.d.ts.map +1 -1
  8. package/dist/client/RemoteLogClient.js +20 -10
  9. package/dist/client/RemoteLogClient.js.map +1 -1
  10. package/dist/client/types.d.ts +6 -0
  11. package/dist/client/types.d.ts.map +1 -1
  12. package/dist/mcp/index.d.ts +1 -1
  13. package/dist/mcp/index.d.ts.map +1 -1
  14. package/dist/mcp/index.js +20 -1
  15. package/dist/mcp/index.js.map +1 -1
  16. package/dist/mcp/mcp-server.d.ts +5 -0
  17. package/dist/mcp/mcp-server.d.ts.map +1 -1
  18. package/dist/mcp/mcp-server.js +54 -8
  19. package/dist/mcp/mcp-server.js.map +1 -1
  20. package/dist/mcp/tools/index.d.ts +6 -6
  21. package/dist/mcp/tools/index.d.ts.map +1 -1
  22. package/dist/mcp/tools/index.js +1 -1
  23. package/dist/mcp/tools/index.js.map +1 -1
  24. package/dist/mcp/tools/logs-clear.d.ts +1 -2
  25. package/dist/mcp/tools/logs-clear.d.ts.map +1 -1
  26. package/dist/mcp/tools/logs-get-all.d.ts +1 -2
  27. package/dist/mcp/tools/logs-get-all.d.ts.map +1 -1
  28. package/dist/mcp/tools/logs-get-errors.d.ts +1 -2
  29. package/dist/mcp/tools/logs-get-errors.d.ts.map +1 -1
  30. package/dist/mcp/tools/logs-get-file-path.d.ts +8 -2
  31. package/dist/mcp/tools/logs-get-file-path.d.ts.map +1 -1
  32. package/dist/mcp/tools/logs-get-file-path.js +1 -1
  33. package/dist/mcp/tools/logs-get-file-path.js.map +1 -1
  34. package/dist/mcp/tools/logs-receive.d.ts +9 -10
  35. package/dist/mcp/tools/logs-receive.d.ts.map +1 -1
  36. package/dist/mcp/tools/logs-search.d.ts +1 -2
  37. package/dist/mcp/tools/logs-search.d.ts.map +1 -1
  38. package/dist/mcp/tools/logs-status.d.ts.map +1 -1
  39. package/dist/mcp/tools/logs-status.js +4 -1
  40. package/dist/mcp/tools/logs-status.js.map +1 -1
  41. package/dist/remote-logger.browser.js +166 -0
  42. package/dist/remote-logger.browser.js.map +1 -0
  43. package/dist/server/dual-server.d.ts +7 -4
  44. package/dist/server/dual-server.d.ts.map +1 -1
  45. package/dist/server/dual-server.js +124 -50
  46. package/dist/server/dual-server.js.map +1 -1
  47. package/dist/server/log-server.d.ts +12 -2
  48. package/dist/server/log-server.d.ts.map +1 -1
  49. package/dist/server/log-server.js +109 -63
  50. package/dist/server/log-server.js.map +1 -1
  51. package/dist/server/log-storage.d.ts +4 -0
  52. package/dist/server/log-storage.d.ts.map +1 -1
  53. package/dist/server/log-storage.js.map +1 -1
  54. package/dist/server/proxy.d.ts +39 -0
  55. package/dist/server/proxy.d.ts.map +1 -0
  56. package/dist/server/proxy.js +290 -0
  57. package/dist/server/proxy.js.map +1 -0
  58. package/dist/server/self-signed-cert.d.ts +9 -0
  59. package/dist/server/self-signed-cert.d.ts.map +1 -1
  60. package/dist/server/self-signed-cert.js +9 -0
  61. package/dist/server/self-signed-cert.js.map +1 -1
  62. package/dist/ui/ConsoleCaptureUI.d.ts.map +1 -1
  63. package/dist/ui/ConsoleCaptureUI.js +6 -1
  64. package/dist/ui/ConsoleCaptureUI.js.map +1 -1
  65. package/package.json +7 -2
  66. package/src/bundle/browser-entry.ts +157 -0
  67. package/src/client/RemoteLogClient.ts +22 -11
  68. package/src/client/types.ts +6 -0
  69. package/src/mcp/index.ts +42 -0
  70. package/src/mcp/mcp-server.ts +54 -8
  71. package/src/mcp/tools/index.ts +7 -0
  72. package/src/mcp/tools/logs-clear.ts +1 -1
  73. package/src/mcp/tools/logs-get-all.ts +1 -1
  74. package/src/mcp/tools/logs-get-errors.ts +1 -1
  75. package/src/mcp/tools/logs-get-file-path.ts +2 -2
  76. package/src/mcp/tools/logs-receive.ts +1 -1
  77. package/src/mcp/tools/logs-search.ts +1 -1
  78. package/src/mcp/tools/logs-status.ts +4 -1
  79. package/src/server/dual-server.ts +165 -57
  80. package/src/server/log-server.ts +126 -68
  81. package/src/server/log-storage.ts +4 -0
  82. package/src/server/proxy.ts +357 -0
  83. package/src/server/self-signed-cert.ts +9 -0
  84. package/src/ui/ConsoleCaptureUI.ts +6 -1
@@ -38,6 +38,7 @@ const DEFAULT_BATCH_INTERVAL_MS = 1000;
38
38
  const DEFAULT_MAX_RETRIES = 3;
39
39
  const DEFAULT_RETRY_DELAY_MS = 1000;
40
40
  const DEFAULT_SESSION_PREFIX = "session";
41
+ const DEFAULT_TIMEOUT_MS = 5000;
41
42
 
42
43
  /**
43
44
  * Generates a unique session ID with the given prefix.
@@ -86,6 +87,7 @@ export class RemoteLogClient {
86
87
  private readonly throttlePatterns: ThrottlePattern[];
87
88
  private readonly projectMarker: string | undefined;
88
89
  private readonly worktreePath: string | undefined;
90
+ private readonly timeoutMs: number;
89
91
 
90
92
  private pendingLogs: LogEntry[] = [];
91
93
  private batchTimer: ReturnType<typeof setTimeout> | null = null;
@@ -106,6 +108,7 @@ export class RemoteLogClient {
106
108
  this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
107
109
  this.retryDelayMs = options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
108
110
  this.throttlePatterns = options.throttlePatterns ?? [];
111
+ this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
109
112
 
110
113
  // Priority: explicit option > global variable
111
114
  this.projectMarker = options.projectMarker ?? getGlobalValue("__REMOTE_LOG_PROJECT_MARKER__");
@@ -229,7 +232,7 @@ export class RemoteLogClient {
229
232
  /**
230
233
  * Makes the actual HTTP request to send logs.
231
234
  * @param logs - The log entries to send
232
- * @throws Error if the request fails
235
+ * @throws Error if the request fails or times out
233
236
  */
234
237
  private async sendRequest(logs: LogEntry[]): Promise<void> {
235
238
  const requestBody: {
@@ -250,16 +253,24 @@ export class RemoteLogClient {
250
253
  requestBody.worktreePath = this.worktreePath;
251
254
  }
252
255
 
253
- const response = await fetch(`${this.serverUrl}/log`, {
254
- method: "POST",
255
- headers: {
256
- "Content-Type": "application/json",
257
- },
258
- body: JSON.stringify(requestBody),
259
- });
260
-
261
- if (!response.ok) {
262
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
256
+ const controller = new AbortController();
257
+ const timeoutId = setTimeout(() => { controller.abort(); }, this.timeoutMs);
258
+
259
+ try {
260
+ const response = await fetch(`${this.serverUrl}/log`, {
261
+ method: "POST",
262
+ headers: {
263
+ "Content-Type": "application/json",
264
+ },
265
+ body: JSON.stringify(requestBody),
266
+ signal: controller.signal,
267
+ });
268
+
269
+ if (!response.ok) {
270
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
271
+ }
272
+ } finally {
273
+ clearTimeout(timeoutId);
263
274
  }
264
275
  }
265
276
 
@@ -59,4 +59,10 @@ export interface RemoteLogClientOptions {
59
59
  * __REMOTE_LOG_WORKTREE_PATH__ global variable (injected by Vite plugin).
60
60
  */
61
61
  worktreePath?: string;
62
+ /**
63
+ * Request timeout in milliseconds.
64
+ * Requests that take longer than this will be aborted and retried.
65
+ * @default 5000
66
+ */
67
+ timeoutMs?: number;
62
68
  }
package/src/mcp/index.ts CHANGED
@@ -6,17 +6,59 @@
6
6
  */
7
7
 
8
8
  export { createMcpServer, getToolNames, startMcpServer } from "./mcp-server.js";
9
+
10
+ // Re-export all tool handlers, schemas, and definitions for programmatic use
9
11
  export {
12
+ // logs_get_file_path
13
+ getLogFilePath,
14
+ // logs_clear
15
+ logsClearHandler,
16
+ type LogsClearInput,
17
+ logsClearInputSchema,
18
+ type LogsClearOutput,
19
+ logsClearTool,
20
+ // logs_get_all
21
+ logsGetAllHandler,
22
+ type LogsGetAllInput,
23
+ logsGetAllInputSchema,
24
+ type LogsGetAllOutput,
25
+ logsGetAllTool,
26
+ // logs_get_errors
27
+ logsGetErrorsHandler,
28
+ type LogsGetErrorsInput,
29
+ logsGetErrorsInputSchema,
30
+ type LogsGetErrorsOutput,
31
+ logsGetErrorsTool,
32
+ logsGetFilePathHandler,
33
+ type LogsGetFilePathInput,
34
+ logsGetFilePathInputSchema,
35
+ type LogsGetFilePathOutput,
36
+ logsGetFilePathTool,
37
+ // logs_get_recent
10
38
  logsGetRecentHandler,
11
39
  type LogsGetRecentInput,
12
40
  logsGetRecentInputSchema,
13
41
  type LogsGetRecentOutput,
14
42
  logsGetRecentTool,
43
+ // logs_list_sessions
15
44
  logsListSessionsHandler,
16
45
  type LogsListSessionsInput,
17
46
  logsListSessionsInputSchema,
18
47
  type LogsListSessionsOutput,
19
48
  logsListSessionsTool,
49
+ // logs_receive
50
+ logsReceiveHandler,
51
+ type LogsReceiveInput,
52
+ logsReceiveInputSchema,
53
+ type LogsReceiveOutput,
54
+ logsReceiveTool,
55
+ // logs_search
56
+ logsSearchHandler,
57
+ type LogsSearchInput,
58
+ logsSearchInputSchema,
59
+ type LogsSearchOutput,
60
+ logsSearchTool,
61
+ // logs_status
20
62
  logsStatusHandler,
21
63
  type LogsStatusInput,
22
64
  logsStatusInputSchema,
@@ -61,8 +61,9 @@ export function getToolNames(): string[] {
61
61
 
62
62
  /**
63
63
  * Server instructions for LLMs describing the overall purpose and usage.
64
+ * Exported for testing purposes.
64
65
  */
65
- const SERVER_INSTRUCTIONS = `Remote Logger MCP Server - View console.log output from browser applications.
66
+ export const SERVER_INSTRUCTIONS = `Remote Logger MCP Server - View console.log output from browser applications.
66
67
 
67
68
  ## What is Remote Logging?
68
69
 
@@ -82,7 +83,7 @@ Remote logging is especially valuable for LLM assistants like this one - it enab
82
83
 
83
84
  ## Architecture
84
85
 
85
- Browser App → HTTP POST to /logs → Log Server (stores in memory + JSONL files) → MCP Tools (query logs)
86
+ Browser App → HTTP POST to /log → Log Server (stores in memory + JSONL files) → MCP Tools (query logs)
86
87
 
87
88
  ## Setting Up a Browser App to Send Logs
88
89
 
@@ -96,8 +97,8 @@ Install: npm install @graphty/remote-logger
96
97
  import { RemoteLogClient } from "@graphty/remote-logger";
97
98
 
98
99
  const logger = new RemoteLogClient({
99
- serverUrl: "http://localhost:9080/logs", // Get this from logs_status
100
- projectMarker: "my-project", // Optional: for filtering
100
+ serverUrl: "http://localhost:9080", // Get this from logs_status (client appends /log)
101
+ projectMarker: "my-project", // Optional: for filtering
101
102
  });
102
103
 
103
104
  // Intercept all console.log/warn/error calls
@@ -107,10 +108,32 @@ logger.interceptConsole();
107
108
  logger.log("INFO", "Hello from browser!");
108
109
  \`\`\`
109
110
 
110
- ### Option 2: Raw fetch() calls
111
+ ### Option 2: Script tag (zero install)
112
+
113
+ The server serves a browser-ready script that auto-configures itself.
114
+ Get the script URL from logs_status - look for server.scriptUrl in the response.
115
+
116
+ Add to HTML:
117
+ \`\`\`html
118
+ <script src="http://localhost:9080/remote-logger.js"></script>
119
+ \`\`\`
120
+
121
+ Or paste in browser console:
122
+ \`\`\`javascript
123
+ var s=document.createElement('script');s.src='http://localhost:9080/remote-logger.js';document.head.appendChild(s);
124
+ \`\`\`
125
+
126
+ The script automatically:
127
+ - Intercepts all console.log/warn/error/info/debug calls
128
+ - Sends them to the server it was loaded from (zero config)
129
+ - Exposes window.__remoteLogger__ for manual control (e.g., window.__remoteLogger__.destroy())
130
+
131
+ Add ?ui=true to the script URL to show a floating console capture widget.
132
+
133
+ ### Option 3: Raw fetch() calls
111
134
 
112
135
  \`\`\`typescript
113
- fetch("http://localhost:9080/logs", {
136
+ fetch("http://localhost:9080/log", {
114
137
  method: "POST",
115
138
  headers: { "Content-Type": "application/json" },
116
139
  body: JSON.stringify({
@@ -122,6 +145,28 @@ fetch("http://localhost:9080/logs", {
122
145
  });
123
146
  \`\`\`
124
147
 
148
+ ## Debugging Third-Party Websites
149
+
150
+ The server includes a reverse proxy that injects the remote logger into any website.
151
+ Get the proxy base URL from logs_status - look for server.proxyBaseUrl.
152
+
153
+ To debug a third-party site, prepend the proxy base URL to the target URL:
154
+ {proxyBaseUrl}https://example.com/page
155
+
156
+ Example: http://192.168.1.x:9080/proxy/https://example.com
157
+
158
+ The proxy automatically:
159
+ - Injects the remote-logger script into HTML responses
160
+ - Strips Content-Security-Policy headers that would block the script
161
+ - Forwards cookies, auth headers, and other request data
162
+ - Passes non-HTML resources (CSS, JS, images) through unmodified
163
+
164
+ Limitations:
165
+ - Resources using absolute paths (e.g., /fonts/..., /media/...) bypass the base tag and return 404
166
+ - JavaScript fetch() calls using absolute paths may bypass the proxy
167
+ - OAuth redirect flows that check the origin domain will not work
168
+ - WebSocket connections are not proxied (future enhancement)
169
+
125
170
  ## Querying Logs (MCP Tools)
126
171
 
127
172
  Once browser logs are flowing to the server:
@@ -137,8 +182,9 @@ Once browser logs are flowing to the server:
137
182
 
138
183
  ## Typical Debugging Workflow
139
184
 
140
- 1. Call logs_status to verify server is running and get the endpoint URL
141
- 2. Ensure the browser app is configured to send logs to that endpoint
185
+ 1. Call logs_status to verify server is running and get the endpoint URL, script URL, and proxy URL
186
+ 2. Add logging to the browser app using one of the options above (script tag is simplest)
187
+ - For third-party sites, use the proxy: navigate to {proxyBaseUrl}https://target-site.com
142
188
  3. Trigger the action in the browser you want to debug
143
189
  4. Call logs_get_recent to see what happened
144
190
  5. Use logs_search if looking for specific errors or messages`;
@@ -7,24 +7,29 @@ export {
7
7
  logsClearHandler,
8
8
  type LogsClearInput,
9
9
  logsClearInputSchema,
10
+ type LogsClearOutput,
10
11
  logsClearTool,
11
12
  } from "./logs-clear.js";
12
13
  export {
13
14
  logsGetAllHandler,
14
15
  type LogsGetAllInput,
15
16
  logsGetAllInputSchema,
17
+ type LogsGetAllOutput,
16
18
  logsGetAllTool,
17
19
  } from "./logs-get-all.js";
18
20
  export {
19
21
  logsGetErrorsHandler,
20
22
  type LogsGetErrorsInput,
21
23
  logsGetErrorsInputSchema,
24
+ type LogsGetErrorsOutput,
22
25
  logsGetErrorsTool,
23
26
  } from "./logs-get-errors.js";
24
27
  export {
28
+ getLogFilePath,
25
29
  logsGetFilePathHandler,
26
30
  type LogsGetFilePathInput,
27
31
  logsGetFilePathInputSchema,
32
+ type LogsGetFilePathOutput,
28
33
  logsGetFilePathTool,
29
34
  } from "./logs-get-file-path.js";
30
35
  export {
@@ -45,12 +50,14 @@ export {
45
50
  logsReceiveHandler,
46
51
  type LogsReceiveInput,
47
52
  logsReceiveInputSchema,
53
+ type LogsReceiveOutput,
48
54
  logsReceiveTool,
49
55
  } from "./logs-receive.js";
50
56
  export {
51
57
  logsSearchHandler,
52
58
  type LogsSearchInput,
53
59
  logsSearchInputSchema,
60
+ type LogsSearchOutput,
54
61
  logsSearchTool,
55
62
  } from "./logs-search.js";
56
63
  export {
@@ -29,7 +29,7 @@ export type LogsClearInput = z.infer<typeof logsClearInputSchema>;
29
29
  /**
30
30
  * Output type for the logs_clear handler.
31
31
  */
32
- interface LogsClearOutput {
32
+ export interface LogsClearOutput {
33
33
  /** Whether the operation succeeded */
34
34
  success: boolean;
35
35
  /** Number of sessions cleared */
@@ -25,7 +25,7 @@ export type LogsGetAllInput = z.infer<typeof logsGetAllInputSchema>;
25
25
  /**
26
26
  * Output type for the logs_get_all handler.
27
27
  */
28
- interface LogsGetAllOutput {
28
+ export interface LogsGetAllOutput {
29
29
  /** Logs grouped by session ID */
30
30
  sessions: Record<string, LogEntry[]>;
31
31
  /** Number of sessions */
@@ -27,7 +27,7 @@ export type LogsGetErrorsInput = z.infer<typeof logsGetErrorsInputSchema>;
27
27
  /**
28
28
  * Output type for the logs_get_errors handler.
29
29
  */
30
- interface LogsGetErrorsOutput {
30
+ export interface LogsGetErrorsOutput {
31
31
  /** Array of ERROR level log entries */
32
32
  errors: LogEntryWithSession[];
33
33
  /** Number of errors returned */
@@ -31,7 +31,7 @@ export type LogsGetFilePathInput = z.infer<typeof logsGetFilePathInputSchema>;
31
31
  /**
32
32
  * Output type for the logs_get_file_path handler.
33
33
  */
34
- interface LogsGetFilePathOutput {
34
+ export interface LogsGetFilePathOutput {
35
35
  /** Full path to the JSONL log file */
36
36
  path: string;
37
37
  /** Whether the file exists */
@@ -46,7 +46,7 @@ interface LogsGetFilePathOutput {
46
46
  * @param projectMarker - The project marker
47
47
  * @returns Full path to the JSONL file
48
48
  */
49
- function getLogFilePath(projectMarker: string): string {
49
+ export function getLogFilePath(projectMarker: string): string {
50
50
  return path.join(os.tmpdir(), "remote-logger", projectMarker, "logs.jsonl");
51
51
  }
52
52
 
@@ -47,7 +47,7 @@ export type LogsReceiveInput = z.infer<typeof logsReceiveInputSchema>;
47
47
  /**
48
48
  * Output type for the logs_receive handler.
49
49
  */
50
- interface LogsReceiveOutput {
50
+ export interface LogsReceiveOutput {
51
51
  /** Whether the operation succeeded */
52
52
  success: boolean;
53
53
  /** Number of logs stored */
@@ -33,7 +33,7 @@ export type LogsSearchInput = z.infer<typeof logsSearchInputSchema>;
33
33
  /**
34
34
  * Output type for the logs_search handler.
35
35
  */
36
- interface LogsSearchOutput {
36
+ export interface LogsSearchOutput {
37
37
  /** Matching log entries */
38
38
  results: LogEntryWithSession[];
39
39
  /** Number of results returned */
@@ -61,9 +61,12 @@ export const logsStatusTool = {
61
61
  description:
62
62
  "Get the status of the remote log server. " +
63
63
  "Returns health metrics (uptime, session count, log count, memory usage), " +
64
- "HTTP endpoint configuration (port, host, URL for browser clients), " +
64
+ "HTTP endpoint configuration (port, host, URL for browser clients, script URL for zero-config injection, " +
65
+ "proxy base URL for debugging third-party sites), " +
65
66
  "and retention settings (how long logs are kept before automatic cleanup). " +
66
67
  "Use this to verify the server is running, find the endpoint URL for configuring browser clients, " +
68
+ "get the script URL (server.scriptUrl) for injecting via a script tag, " +
69
+ "get the proxy URL (server.proxyBaseUrl) for debugging third-party sites, " +
67
70
  "or check server configuration.",
68
71
  inputSchema: logsStatusInputSchema,
69
72
  };