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.
- package/LICENSE +21 -0
- package/README.md +403 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +53 -0
- package/dist/collector.d.ts +8 -0
- package/dist/collector.d.ts.map +1 -0
- package/dist/dashboard/html.d.ts +2 -0
- package/dist/dashboard/html.d.ts.map +1 -0
- package/dist/dashboard/index.d.ts +3 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/hooks.d.ts +3 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +140 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10874 -0
- package/dist/instrumentation/console.d.ts +2 -0
- package/dist/instrumentation/console.d.ts.map +1 -0
- package/dist/instrumentation/errors.d.ts +2 -0
- package/dist/instrumentation/errors.d.ts.map +1 -0
- package/dist/instrumentation/fetch.d.ts +2 -0
- package/dist/instrumentation/fetch.d.ts.map +1 -0
- package/dist/instrumentation/index.d.ts +2 -0
- package/dist/instrumentation/index.d.ts.map +1 -0
- package/dist/instrumentation/stdout.d.ts +2 -0
- package/dist/instrumentation/stdout.d.ts.map +1 -0
- package/dist/loader.d.ts +3 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +10987 -0
- package/dist/metrics.d.ts +3 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/patch/bun.d.ts +2 -0
- package/dist/patch/bun.d.ts.map +1 -0
- package/dist/patch/node.d.ts +2 -0
- package/dist/patch/node.d.ts.map +1 -0
- package/dist/patch/utils.d.ts +6 -0
- package/dist/patch/utils.d.ts.map +1 -0
- package/dist/register.d.ts +2 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +10869 -0
- package/dist/storage/db.d.ts +72 -0
- package/dist/storage/db.d.ts.map +1 -0
- package/dist/storage/schema.d.ts +3 -0
- package/dist/storage/schema.d.ts.map +1 -0
- 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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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"}
|
package/dist/hooks.d.ts
ADDED
|
@@ -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
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|