surrge 0.4.1

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 (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +403 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +53 -0
  6. package/dist/collector.d.ts +8 -0
  7. package/dist/collector.d.ts.map +1 -0
  8. package/dist/dashboard/html.d.ts +2 -0
  9. package/dist/dashboard/html.d.ts.map +1 -0
  10. package/dist/dashboard/index.d.ts +3 -0
  11. package/dist/dashboard/index.d.ts.map +1 -0
  12. package/dist/hooks.d.ts +3 -0
  13. package/dist/hooks.d.ts.map +1 -0
  14. package/dist/hooks.js +140 -0
  15. package/dist/index.d.ts +5 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +10874 -0
  18. package/dist/instrumentation/console.d.ts +2 -0
  19. package/dist/instrumentation/console.d.ts.map +1 -0
  20. package/dist/instrumentation/errors.d.ts +2 -0
  21. package/dist/instrumentation/errors.d.ts.map +1 -0
  22. package/dist/instrumentation/fetch.d.ts +2 -0
  23. package/dist/instrumentation/fetch.d.ts.map +1 -0
  24. package/dist/instrumentation/index.d.ts +2 -0
  25. package/dist/instrumentation/index.d.ts.map +1 -0
  26. package/dist/instrumentation/stdout.d.ts +2 -0
  27. package/dist/instrumentation/stdout.d.ts.map +1 -0
  28. package/dist/loader.d.ts +3 -0
  29. package/dist/loader.d.ts.map +1 -0
  30. package/dist/loader.js +10987 -0
  31. package/dist/metrics.d.ts +3 -0
  32. package/dist/metrics.d.ts.map +1 -0
  33. package/dist/patch/bun.d.ts +2 -0
  34. package/dist/patch/bun.d.ts.map +1 -0
  35. package/dist/patch/node.d.ts +2 -0
  36. package/dist/patch/node.d.ts.map +1 -0
  37. package/dist/patch/utils.d.ts +6 -0
  38. package/dist/patch/utils.d.ts.map +1 -0
  39. package/dist/register.d.ts +2 -0
  40. package/dist/register.d.ts.map +1 -0
  41. package/dist/register.js +10869 -0
  42. package/dist/storage/db.d.ts +72 -0
  43. package/dist/storage/db.d.ts.map +1 -0
  44. package/dist/storage/schema.d.ts +3 -0
  45. package/dist/storage/schema.d.ts.map +1 -0
  46. package/package.json +84 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 blakbelt78
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,403 @@
1
+ # Surrge
2
+
3
+ One-line observability for Node.js and Bun. Captures logs, HTTP requests, errors, and server metrics with zero configuration. Dashboard at `/surrge`.
4
+
5
+ ```bash
6
+ # Bun
7
+ bun --preload surrge/src/loader.ts app.ts
8
+
9
+ # Node.js
10
+ node --import surrge/loader.js app.js
11
+ ```
12
+
13
+ ## Features
14
+
15
+ - **Logs**: Console output + structured loggers (pino, winston JSON)
16
+ - **Requests**: Incoming HTTP + outgoing fetch calls
17
+ - **Errors**: Uncaught exceptions with stack traces
18
+ - **Metrics**: Memory, CPU, event loop lag, uptime
19
+ - **Dashboard**: Real-time view at `/surrge`
20
+ - **Storage**: SQLite via libSQL with 7-day retention
21
+
22
+ ## Architecture
23
+
24
+ ### Data Flow
25
+
26
+ ```mermaid
27
+ flowchart TB
28
+ subgraph App["User Application"]
29
+ Console["console.log/warn/error"]
30
+ Fetch["fetch()"]
31
+ Logger["pino/winston"]
32
+ Server["HTTP Server"]
33
+ end
34
+
35
+ subgraph Hooks["hooks.ts (--preload)"]
36
+ StdoutPatch["process.stdout.write patch"]
37
+ FsPatch["fs.writeSync patch"]
38
+ end
39
+
40
+ subgraph Instrumentation["instrumentation/"]
41
+ ConsolePatch["console.ts"]
42
+ FetchPatch["fetch.ts"]
43
+ ErrorPatch["errors.ts"]
44
+ end
45
+
46
+ subgraph Patch["patch/"]
47
+ NodePatch["node.ts: http.createServer"]
48
+ BunPatch["bun.ts: Bun.serve"]
49
+ end
50
+
51
+ subgraph Core["Core"]
52
+ Collector["collector.ts (queue)"]
53
+ DB["storage/db.ts (libSQL)"]
54
+ Metrics["metrics.ts (polling)"]
55
+ end
56
+
57
+ subgraph Dashboard["dashboard/"]
58
+ Routes["index.ts (Hono)"]
59
+ HTML["html.ts"]
60
+ end
61
+
62
+ Console --> ConsolePatch --> Collector
63
+ Fetch --> FetchPatch --> Collector
64
+ Logger --> StdoutPatch --> Collector
65
+ Logger --> FsPatch --> Collector
66
+ Server --> NodePatch --> Collector
67
+ Server --> BunPatch --> Collector
68
+
69
+ App --> ErrorPatch --> Collector
70
+
71
+ Collector -->|batch insert| DB
72
+ Metrics -->|10s poll| DB
73
+
74
+ DB --> Routes
75
+ Routes --> HTML
76
+ HTML -->|/surrge| Server
77
+ ```
78
+
79
+ ### File Structure
80
+
81
+ ```mermaid
82
+ flowchart LR
83
+ subgraph Entry["Entry Points"]
84
+ loader["loader.ts"]
85
+ hooks["hooks.ts"]
86
+ register["register.ts"]
87
+ end
88
+
89
+ subgraph Storage["storage/"]
90
+ db["db.ts"]
91
+ schema["schema.ts"]
92
+ end
93
+
94
+ subgraph Instr["instrumentation/"]
95
+ console["console.ts"]
96
+ fetch["fetch.ts"]
97
+ errors["errors.ts"]
98
+ stdout["stdout.ts"]
99
+ end
100
+
101
+ subgraph ServerPatch["patch/"]
102
+ node["node.ts"]
103
+ bun["bun.ts"]
104
+ utils["utils.ts"]
105
+ end
106
+
107
+ subgraph Dash["dashboard/"]
108
+ dashIndex["index.ts"]
109
+ html["html.ts"]
110
+ end
111
+
112
+ loader --> hooks
113
+ loader --> register
114
+ register --> Instr
115
+ register --> ServerPatch
116
+ register --> Storage
117
+ register --> collector["collector.ts"]
118
+ register --> metrics["metrics.ts"]
119
+
120
+ ServerPatch --> Dash
121
+ Dash --> Storage
122
+ ```
123
+
124
+ ### Request Lifecycle
125
+
126
+ ```mermaid
127
+ sequenceDiagram
128
+ participant Client
129
+ participant Patch as Server Patch
130
+ participant App as User App
131
+ participant Collector
132
+ participant DB as SQLite
133
+
134
+ Client->>Patch: HTTP Request
135
+ Patch->>Patch: Check if /surrge
136
+
137
+ alt /surrge route
138
+ Patch->>DB: Query data
139
+ DB-->>Patch: Results
140
+ Patch-->>Client: Dashboard HTML
141
+ else App route
142
+ Patch->>Patch: Record start time
143
+ Patch->>App: Forward request
144
+ App-->>Patch: Response
145
+ Patch->>Collector: Track request
146
+ Collector->>Collector: Queue event
147
+ Patch-->>Client: Response
148
+ end
149
+
150
+ Note over Collector,DB: Every 1s or 100 items
151
+ Collector->>DB: Batch INSERT
152
+ ```
153
+
154
+ ## Key Files
155
+
156
+ | File | Purpose |
157
+ |------|---------|
158
+ | `loader.ts` | Entry point for `--preload`. Imports hooks then register. |
159
+ | `hooks.ts` | Patches stdout BEFORE any modules load. Captures pino/winston JSON. |
160
+ | `register.ts` | Initializes DB, collector, instrumentation, metrics, server patches. |
161
+ | `collector.ts` | Queue-based event collection. Batches INSERTs for performance. |
162
+ | `storage/db.ts` | libSQL wrapper. All DB operations. |
163
+ | `storage/schema.ts` | Table definitions. 5 tables + indexes. |
164
+ | `patch/node.ts` | Patches `http.createServer` to intercept requests and serve dashboard. |
165
+ | `patch/bun.ts` | Patches `Bun.serve` for same purpose. |
166
+ | `dashboard/index.ts` | Hono routes for `/surrge`, `/surrge/api/*`. |
167
+ | `dashboard/html.ts` | Single HTML string with inline CSS/JS. |
168
+
169
+ ## Database Schema
170
+
171
+ ```mermaid
172
+ erDiagram
173
+ logs {
174
+ integer id PK
175
+ integer timestamp
176
+ text level
177
+ text message
178
+ text metadata
179
+ }
180
+
181
+ requests {
182
+ integer id PK
183
+ integer timestamp
184
+ text method
185
+ text url
186
+ integer status
187
+ integer duration_ms
188
+ text direction
189
+ }
190
+
191
+ errors {
192
+ integer id PK
193
+ integer timestamp
194
+ text message
195
+ text stack
196
+ text fingerprint
197
+ }
198
+
199
+ page_views {
200
+ integer id PK
201
+ integer timestamp
202
+ text path
203
+ text referrer
204
+ text visitor_id
205
+ text country
206
+ text device
207
+ text browser
208
+ }
209
+
210
+ server_metrics {
211
+ integer id PK
212
+ integer timestamp
213
+ integer memory_rss
214
+ integer memory_heap
215
+ real cpu_user
216
+ real cpu_system
217
+ real event_loop_lag
218
+ real load_avg
219
+ }
220
+ ```
221
+
222
+ ## Design Decisions
223
+
224
+ ### Why Loader Hooks?
225
+
226
+ Pino and other structured loggers write directly to stdout via `fs.writeSync`, bypassing `console.log`. To capture these:
227
+
228
+ 1. `hooks.ts` loads via `--preload` BEFORE any user code
229
+ 2. Patches `fs.writeSync`, `process.stdout.write`, `Bun.write`
230
+ 3. Parses JSON lines and queues them
231
+ 4. `loader.ts` drains the queue after surrge initializes
232
+
233
+ ### Why libSQL?
234
+
235
+ - Single API works in Node.js, Bun, Deno
236
+ - SQLite-compatible (can use standard tools)
237
+ - Supports local file, remote sync, embedded replicas
238
+ - Open-source, self-hostable
239
+
240
+ ### Why Queue + Batch?
241
+
242
+ Never block the request path:
243
+
244
+ ```typescript
245
+ // Fast: just push to array
246
+ queue.push(event);
247
+
248
+ // Async: flush every 1s or 100 items
249
+ setInterval(() => {
250
+ const batch = queue.splice(0, 100);
251
+ db.insertBatch(batch);
252
+ }, 1000);
253
+ ```
254
+
255
+ ### Why Inline HTML?
256
+
257
+ - Zero build step required
258
+ - No static file serving complexity
259
+ - Single import, everything works
260
+ - Dashboard is ~10KB total
261
+
262
+ ## Known Limitations
263
+
264
+ ### Pino Worker Thread Transports
265
+
266
+ When pino uses `transport: { targets: [...] }`, it spawns worker threads. These have their own `fs` module that isn't patched.
267
+
268
+ ```typescript
269
+ // ❌ Logs NOT captured (worker thread)
270
+ pino({ transport: { target: 'pino/file' } });
271
+
272
+ // ✅ Logs captured (direct stdout)
273
+ pino({ level: 'info' }); // no transport option
274
+ ```
275
+
276
+ **Workaround:** Unset `OTLP_ENDPOINT` or any config that enables transports.
277
+
278
+ ### Framework Detection
279
+
280
+ Surrge patches at runtime level, so it works with any framework. But it can't access framework-specific context (e.g., Express `req.user`). For richer data, add optional middleware.
281
+
282
+ ## Development
283
+
284
+ ```bash
285
+ # Install dependencies
286
+ bun install
287
+
288
+ # Run tests
289
+ bun test
290
+
291
+ # Type check
292
+ bun run typecheck
293
+
294
+ # Test with an app
295
+ bun --preload ./src/loader.ts /path/to/app.ts
296
+ ```
297
+
298
+ ### Build Scripts
299
+
300
+ | Script | Purpose |
301
+ |--------|---------|
302
+ | `bun run build` | Full build (dashboard + bundle + types) |
303
+ | `bun run build:dashboard` | Compiles React UI → embeds into `html.ts` |
304
+ | `bun run build:bundle` | Bundles TypeScript → JavaScript in `dist/` |
305
+ | `bun run build:types` | Generates `.d.ts` declaration files |
306
+
307
+ ### Testing Locally
308
+
309
+ ```bash
310
+ # 1. Build the package
311
+ bun run build
312
+
313
+ # 2. Create tarball
314
+ npm pack
315
+ # Creates surrge-0.1.0.tgz
316
+
317
+ # 3. Install in another project (Bun)
318
+ cd /path/to/test-project
319
+ bun add /path/to/surrge/surrge-0.1.0.tgz
320
+
321
+ # 3. Install in another project (Node/npm)
322
+ cd /path/to/test-project
323
+ npm install /path/to/surrge/surrge-0.1.0.tgz
324
+
325
+ # 4. Use it (Bun)
326
+ echo 'import "surrge/register"' > test.ts
327
+ bun run test.ts
328
+
329
+ # 4. Use it (Node)
330
+ echo 'import "surrge/register"' > test.mjs
331
+ node test.mjs
332
+ ```
333
+
334
+ Alternative: use link for symlink-based development:
335
+
336
+ ```bash
337
+ # Bun
338
+ bun link # in surrge directory
339
+ bun link surrge # in test project
340
+
341
+ # npm
342
+ npm link # in surrge directory
343
+ npm link surrge # in test project
344
+ ```
345
+
346
+ ### Publishing
347
+
348
+ ```bash
349
+ # First time: login to npm
350
+ npm login
351
+
352
+ # Bump version (auto-commits and tags)
353
+ npm version patch # 0.1.0 → 0.1.1
354
+ npm version minor # 0.1.0 → 0.2.0
355
+ npm version major # 0.1.0 → 1.0.0
356
+
357
+ # Publish (runs typecheck, tests, build automatically)
358
+ npm publish
359
+
360
+ # Push version tag to git
361
+ git push --follow-tags
362
+ ```
363
+
364
+ ### Pre-publish Checklist
365
+
366
+ - [ ] `bun run typecheck` passes
367
+ - [ ] `bun test` passes
368
+ - [ ] `bun run build` succeeds
369
+ - [ ] `npm pack --dry-run` shows expected files
370
+ - [ ] Tested in a real project via tarball
371
+
372
+ ## Usage with rdltr
373
+
374
+ ```bash
375
+ # From rdltr directory
376
+ OTLP_ENDPOINT= NODE_ENV=production bun --preload ../surrge/src/loader.ts index.tsx
377
+
378
+ # Open http://localhost:3000/surrge
379
+ ```
380
+
381
+ ## API Endpoints
382
+
383
+ | Endpoint | Description |
384
+ |----------|-------------|
385
+ | `GET /surrge` | Dashboard HTML |
386
+ | `GET /surrge/api/logs` | Recent logs (JSON) |
387
+ | `GET /surrge/api/requests` | Recent requests (JSON) |
388
+ | `GET /surrge/api/errors` | Recent errors (JSON) |
389
+ | `GET /surrge/api/analytics` | Page view analytics (JSON) |
390
+ | `GET /surrge/api/metrics` | Server metrics (JSON) |
391
+
392
+ ## Roadmap
393
+
394
+ - [ ] Web analytics (User-Agent parsing, geo lookup)
395
+ - [ ] Dashboard search/filtering
396
+ - [ ] Charts for metrics over time
397
+ - [x] npm package distribution
398
+ - [ ] Multi-instance sync (Pro)
399
+ - [ ] Alerts (Pro)
400
+
401
+ ## License
402
+
403
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli.ts
4
+ import { spawn, spawnSync } from "node:child_process";
5
+ import { fileURLToPath } from "node:url";
6
+ import { dirname, resolve } from "node:path";
7
+ var args = process.argv.slice(2);
8
+ if (args.length === 0) {
9
+ console.log("Usage: surrge [options] <script> [args...]");
10
+ console.log(" surrge node [options] <script> [args...]");
11
+ console.log(" surrge bun [options] <script> [args...]");
12
+ console.log("");
13
+ console.log("Options are passed through to the runtime (e.g., --hot, --watch)");
14
+ process.exit(1);
15
+ }
16
+ var loaderPath = resolve(dirname(fileURLToPath(import.meta.url)), "loader.js");
17
+ var hasBun = () => {
18
+ const result = spawnSync("bun", ["--version"], { stdio: "ignore" });
19
+ return result.status === 0;
20
+ };
21
+ var runtime;
22
+ var remaining;
23
+ if (args[0] === "node" || args[0] === "bun") {
24
+ runtime = args[0];
25
+ remaining = args.slice(1);
26
+ } else {
27
+ runtime = hasBun() ? "bun" : "node";
28
+ remaining = args;
29
+ }
30
+ var runtimeFlags = [];
31
+ var scriptIndex = 0;
32
+ for (let i = 0;i < remaining.length; i++) {
33
+ if (remaining[i].startsWith("-")) {
34
+ runtimeFlags.push(remaining[i]);
35
+ } else {
36
+ scriptIndex = i;
37
+ break;
38
+ }
39
+ }
40
+ var scriptArgs = remaining.slice(scriptIndex);
41
+ if (scriptArgs.length === 0) {
42
+ console.log("Error: No script specified");
43
+ process.exit(1);
44
+ }
45
+ var flag = runtime === "bun" ? "--preload" : "--import";
46
+ var child = spawn(runtime, [flag, loaderPath, ...runtimeFlags, ...scriptArgs], {
47
+ stdio: "inherit",
48
+ cwd: process.cwd(),
49
+ env: process.env
50
+ });
51
+ child.on("close", (code) => {
52
+ process.exit(code ?? 0);
53
+ });
@@ -0,0 +1,8 @@
1
+ export declare const start: () => void;
2
+ export declare const stop: () => void;
3
+ export declare const log: (level: string, message: string, metadata?: Record<string, unknown>) => void;
4
+ export declare const request: (method: string, url: string, status: number | null, duration: number | null, direction: "in" | "out") => void;
5
+ export declare const error: (message: string, stack: string | null) => void;
6
+ export declare const pageview: (path: string, referrer: string | null, visitor_id: string | null, country: string | null, device: string | null, browser: string | null) => void;
7
+ export declare const metric: (memory_rss: number, memory_heap: number, cpu_user: number, cpu_system: number, event_loop_lag: number, load_avg: number) => void;
8
+ //# sourceMappingURL=collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../src/collector.ts"],"names":[],"mappings":"AA0HA,eAAO,MAAM,KAAK,QAAO,IAOxB,CAAC;AAEF,eAAO,MAAM,IAAI,QAAO,IAQvB,CAAC;AAGF,eAAO,MAAM,GAAG,GACd,OAAO,MAAM,EACb,SAAS,MAAM,EACf,WAAW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACjC,IAQF,CAAC;AAEF,eAAO,MAAM,OAAO,GAClB,QAAQ,MAAM,EACd,KAAK,MAAM,EACX,QAAQ,MAAM,GAAG,IAAI,EACrB,UAAU,MAAM,GAAG,IAAI,EACvB,WAAW,IAAI,GAAG,KAAK,KACtB,IAUF,CAAC;AAEF,eAAO,MAAM,KAAK,GAAI,SAAS,MAAM,EAAE,OAAO,MAAM,GAAG,IAAI,KAAG,IAW7D,CAAC;AAEF,eAAO,MAAM,QAAQ,GACnB,MAAM,MAAM,EACZ,UAAU,MAAM,GAAG,IAAI,EACvB,YAAY,MAAM,GAAG,IAAI,EACzB,SAAS,MAAM,GAAG,IAAI,EACtB,QAAQ,MAAM,GAAG,IAAI,EACrB,SAAS,MAAM,GAAG,IAAI,KACrB,IAWF,CAAC;AAEF,eAAO,MAAM,MAAM,GACjB,YAAY,MAAM,EAClB,aAAa,MAAM,EACnB,UAAU,MAAM,EAChB,YAAY,MAAM,EAClB,gBAAgB,MAAM,EACtB,UAAU,MAAM,KACf,IAWF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const html: () => string;
2
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/dashboard/html.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,IAAI,QAAO,MAAqkquB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Hono } from "hono";
2
+ export declare const createDashboard: (basePath: string) => Hono;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dashboard/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5B,eAAO,MAAM,eAAe,GAAI,UAAU,MAAM,KAAG,IA0FlD,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const resolve: (specifier: string, context: unknown, nextResolve: Function) => Promise<any>;
2
+ export declare const load: (url: string, context: unknown, nextLoad: Function) => Promise<any>;
3
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAyJA,eAAO,MAAM,OAAO,GAClB,WAAW,MAAM,EACjB,SAAS,OAAO,EAChB,aAAa,QAAQ,iBAGtB,CAAC;AAEF,eAAO,MAAM,IAAI,GACf,KAAK,MAAM,EACX,SAAS,OAAO,EAChB,UAAU,QAAQ,iBAGnB,CAAC"}
package/dist/hooks.js ADDED
@@ -0,0 +1,140 @@
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
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
19
+ var __export = (target, all) => {
20
+ for (var name in all)
21
+ __defProp(target, name, {
22
+ get: all[name],
23
+ enumerable: true,
24
+ configurable: true,
25
+ set: (newValue) => all[name] = () => newValue
26
+ });
27
+ };
28
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
29
+
30
+ // src/hooks.ts
31
+ import fs from "node:fs";
32
+ import { createRequire as createRequire2 } from "node:module";
33
+ var STDOUT_FD = 1;
34
+ var buffer = "";
35
+ var originalWriteSync = fs.writeSync;
36
+ var originalWrite = fs.write;
37
+ var logQueue = [];
38
+ globalThis.__surrge_log_queue = logQueue;
39
+ var normalizeLevel = (level) => {
40
+ if (typeof level === "number") {
41
+ if (level >= 50)
42
+ return "error";
43
+ if (level >= 40)
44
+ return "warn";
45
+ if (level >= 30)
46
+ return "info";
47
+ return "debug";
48
+ }
49
+ if (typeof level === "string") {
50
+ const lower = level.toLowerCase();
51
+ if (["error", "err"].includes(lower))
52
+ return "error";
53
+ if (["warn", "warning"].includes(lower))
54
+ return "warn";
55
+ return lower;
56
+ }
57
+ return "info";
58
+ };
59
+ var captureOutput = (chunk) => {
60
+ const text = typeof chunk === "string" ? chunk : chunk.toString();
61
+ buffer += text;
62
+ const lines = buffer.split(`
63
+ `);
64
+ buffer = lines.pop() ?? "";
65
+ for (const line of lines) {
66
+ if (!line.trim() || !line.startsWith("{"))
67
+ continue;
68
+ try {
69
+ const parsed = JSON.parse(line);
70
+ const level = normalizeLevel(parsed.level ?? parsed.severity ?? "info");
71
+ const message = String(parsed.msg ?? parsed.message ?? line);
72
+ const { level: _, msg: __, message: ___, ...metadata } = parsed;
73
+ logQueue.push({
74
+ level,
75
+ message,
76
+ metadata: Object.keys(metadata).length > 0 ? metadata : undefined
77
+ });
78
+ } catch {}
79
+ }
80
+ };
81
+ var require2 = createRequire2(import.meta.url);
82
+ var cjsFs = require2("node:fs");
83
+ fs.writeSync = (fd, data, ...args) => {
84
+ if (fd === STDOUT_FD && (typeof data === "string" || Buffer.isBuffer(data))) {
85
+ captureOutput(data);
86
+ }
87
+ return originalWriteSync(fd, data, ...args);
88
+ };
89
+ fs.write = (fd, data, ...args) => {
90
+ if (fd === STDOUT_FD && (typeof data === "string" || Buffer.isBuffer(data))) {
91
+ captureOutput(data);
92
+ }
93
+ return originalWrite(fd, data, ...args);
94
+ };
95
+ var cjsOriginalWriteSync = cjsFs.writeSync;
96
+ var cjsOriginalWrite = cjsFs.write;
97
+ cjsFs.writeSync = (fd, data, ...args) => {
98
+ if (fd === STDOUT_FD && (typeof data === "string" || Buffer.isBuffer(data))) {
99
+ captureOutput(data);
100
+ }
101
+ return cjsOriginalWriteSync(fd, data, ...args);
102
+ };
103
+ cjsFs.write = (fd, data, ...args) => {
104
+ if (fd === STDOUT_FD && (typeof data === "string" || Buffer.isBuffer(data))) {
105
+ captureOutput(data);
106
+ }
107
+ return cjsOriginalWrite(fd, data, ...args);
108
+ };
109
+ var originalStdoutWrite = process.stdout.write.bind(process.stdout);
110
+ process.stdout.write = (chunk, encodingOrCallback, callback) => {
111
+ if (typeof chunk === "string" || Buffer.isBuffer(chunk)) {
112
+ captureOutput(chunk);
113
+ }
114
+ if (typeof encodingOrCallback === "function") {
115
+ return originalStdoutWrite(chunk, encodingOrCallback);
116
+ }
117
+ return originalStdoutWrite(chunk, encodingOrCallback, callback);
118
+ };
119
+ var Bun = globalThis.Bun;
120
+ var BunStdout = Bun?.stdout;
121
+ if (Bun?.write) {
122
+ const originalBunWrite = Bun.write;
123
+ Bun.write = (dest, data, ...args) => {
124
+ const isStdout = dest === STDOUT_FD || dest === process.stdout || dest === BunStdout;
125
+ if (isStdout && (typeof data === "string" || Buffer.isBuffer(data))) {
126
+ captureOutput(data);
127
+ }
128
+ return originalBunWrite(dest, data, ...args);
129
+ };
130
+ }
131
+ var resolve = async (specifier, context, nextResolve) => {
132
+ return nextResolve(specifier, context);
133
+ };
134
+ var load = async (url, context, nextLoad) => {
135
+ return nextLoad(url, context);
136
+ };
137
+ export {
138
+ resolve,
139
+ load
140
+ };
@@ -0,0 +1,5 @@
1
+ export * as collector from "./collector.js";
2
+ export { createDashboard } from "./dashboard/index.js";
3
+ export * as db from "./storage/db.js";
4
+ import "./register.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAGtC,OAAO,eAAe,CAAC"}