@zerotal/monitor 1.6.3 → 1.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.
Files changed (2) hide show
  1. package/api-surface.md +687 -0
  2. package/package.json +8 -7
package/api-surface.md ADDED
@@ -0,0 +1,687 @@
1
+ # @zerotal/monitor — public API surface
2
+
3
+ <!-- AUTO-GENERATED by scripts/api-surface.ts. Do not edit by hand.
4
+ Run `bun run api:surface` to regenerate after an intentional API change. -->
5
+
6
+ ## . `(./src/index.ts)`
7
+
8
+ class MonitorAuthMiddleware = {
9
+ new (): MonitorAuthMiddleware
10
+ handle: (http: HttpContext, next: NextFn) => Promise<Response | void>
11
+ }
12
+
13
+ class MonitorPayloadMiddleware = {
14
+ new (): MonitorPayloadMiddleware
15
+ handle: (http: HttpContext, next: NextFn) => Promise<Response | void>
16
+ }
17
+
18
+ class MonitorProvider = {
19
+ new (app: Application): MonitorProvider
20
+ static dependsOn: (typeof FlowProvider)[]
21
+ static environments: AppEnvironment[]
22
+ static priority?: number
23
+ static provides: readonly ['monitor', 'monitor.store', 'monitor.panel']
24
+ devProcesses: () => DevProcessDefinition[]
25
+ doctorChecks: () => DoctorCheck[]
26
+ onBooted: () => Promise<void>
27
+ onBooting: () => Promise<void>
28
+ onRegister: () => void
29
+ onRequestProcessed: (_ctx: HttpContext) => Promise<void>
30
+ onRequestReceived: (_ctx: HttpContext) => Promise<void>
31
+ onResponseSent: (_ctx: HttpContext) => Promise<void>
32
+ onStarted: () => Promise<void>
33
+ onStarting: () => Promise<void>
34
+ onStopped: () => Promise<void>
35
+ onStopping: () => Promise<void>
36
+ replContext: () => Record<string, unknown>
37
+ }
38
+
39
+ class MonitorStore = {
40
+ new (opts?: MonitorStoreOptions): MonitorStore
41
+ bindApp: (app: AppShape) => void
42
+ bufferQuery: (ctx: object, q: RequestQuery) => void
43
+ collectRequestState: (ctx: object) => RequestState
44
+ dispose: () => void
45
+ forgetFailed: (id: number) => Promise<boolean>
46
+ markNPlus: (ctx: object) => void
47
+ prune: () => number
48
+ recordCache: (hit: boolean, key?: string) => void
49
+ recordDeploy: (sha: string) => void
50
+ recordEvent: (e: { kind: string; label: string; status?: 'ok' | 'warn' | 'bad' | 'info'; route?: string | null; data?: Record<string, unknown>;}) => void
51
+ recordException: (error: Error | { type: string; message: string;}, location?: string, user?: string | null) => void
52
+ recordHttp: (h: { host: string; ms: number; error?: boolean;}) => void
53
+ recordJob: (job: { status: string; className?: string; queue?: string; ms?: number; error?: string | null;}) => void
54
+ recordMail: (m: Omit<MailEntry, 'id' | 'when'> & { when?: string;}) => void
55
+ recordQuery: (q: { sql: string; ms: number; location?: string;}) => void
56
+ recordRequest: (r: { method: string; path: string; status: number; ms: number; queries?: RequestQuery[]; logs?: unknown; nplus?: boolean; spans?: unknown; user?: string | null; ip?: string | null; memKb?: number; context?: Record<string, unknown>; payload?: RequestPayload | null; error?: string | null;}) => void
57
+ requeueDead: (id: number) => Promise<boolean>
58
+ retentionDays: () => number
59
+ retentionMode: () => RetentionMode
60
+ retryFailed: (id: number) => Promise<boolean>
61
+ routeDetail: (method: string, path: string, range?: MonitorRange) => Promise<RouteDetail>
62
+ snapshot: (range?: MonitorRange) => Promise<MonitorSnapshot>
63
+ storageInfo: () => StorageInfo
64
+ toggleQueuePaused: (name: string) => boolean
65
+ wipe: () => number
66
+ }
67
+
68
+ const Monitor = { readonly recordRequest: (r: { method: string; path: string; status: number; ms: number; queries?: RequestQuery[]; logs?: unknown; nplus?: boolean; spans?: unknown; user?: string | null; ip?: string | null; memKb?: number; context?: Record<string, unknown>; payload?: RequestPayload | null; error?: string | null; }) => void | undefined; readonly recordException: (error: Error | { type: string; message: string; }, location?: string | undefined, user?: string | null | undefined) => void | undefined; readonly recordQuery: (q: { sql: string; ms: number; location?: string; }) => void | undefined; readonly recordHttp: (h: { host: string; ms: number; error?: boolean; }) => void | undefined; readonly recordCache: (hit: boolean, key?: string | undefined) => void | undefined; readonly recordMail: (m: Omit<MailEntry, 'id' | 'when'> & { when?: string; }) => void | undefined; readonly recordDeploy: (sha: string) => void | undefined; readonly recordJob: (job: { status: string; className?: string; queue?: string; ms?: number; error?: string | null; }) => void | undefined; readonly context: (data: Record<string, unknown>) => void; readonly snapshot: (range?: MonitorRange | undefined) => Promise<MonitorSnapshot> | undefined; readonly store: MonitorStore | undefined;}
69
+
70
+ const MonitorPanel = { configure(sections: Record<string, boolean> | undefined): void; host(): MonitorPanelHost; sections(): MonitorSection[]; find(id: string): MonitorSection | undefined; reset(): void;}
71
+
72
+ function evaluateAlerts = (snap: MonitorSnapshot, thresholds?: AlertThresholds) => AlertNotice[]
73
+
74
+ function installMonitorEventBridge = (store: MonitorStore) => () => void
75
+
76
+ function MonitorConfig = (options?: Partial<MonitorConfigShape>) => ResolvedMonitorConfig
77
+
78
+ function onAlert = (fn: AlertHandler) => () => void
79
+
80
+ function renderPrometheus = (snap: MonitorSnapshot) => string
81
+
82
+ interface Alert = {
83
+ text: string
84
+ tone: 'red' | 'amber'
85
+ }
86
+
87
+ interface AlertContext = {
88
+ apdex: number
89
+ errorRate: number
90
+ p50: number
91
+ p95: number
92
+ p99: number
93
+ pending: number
94
+ rolledBack: number
95
+ rpm: number
96
+ slowRoutes: RouteStat[]
97
+ topException: string | null
98
+ }
99
+
100
+ interface AlertEntry = {
101
+ context: AlertContext
102
+ count: number
103
+ detail: string
104
+ firstSeen: string
105
+ id: string
106
+ lastSeen: string
107
+ level: 'warning' | 'critical'
108
+ metric: string
109
+ occurrences: { when: string; detail: string; value: number;}[]
110
+ status: 'info' | 'ok' | 'warn' | 'bad'
111
+ threshold: number
112
+ title: string
113
+ unit: string
114
+ value: number
115
+ }
116
+
117
+ interface AlertNotice = {
118
+ detail: string
119
+ id: string
120
+ level: 'warning' | 'critical'
121
+ metric: string
122
+ threshold: number
123
+ title: string
124
+ unit: string
125
+ value: number
126
+ }
127
+
128
+ interface AlertThresholds = {
129
+ errorRatePct?: number
130
+ p95Ms?: number
131
+ queuePending?: number
132
+ rolledBackInWindow?: number
133
+ }
134
+
135
+ interface CacheKey = {
136
+ hits: number
137
+ key: string
138
+ rate: number
139
+ }
140
+
141
+ interface CacheStats = {
142
+ evictions: number
143
+ hitRate: number
144
+ hits: number
145
+ keys: CacheKey[]
146
+ misses: number
147
+ }
148
+
149
+ interface CheckIn = {
150
+ cron: string
151
+ last: string
152
+ name: string
153
+ status: 'ok' | 'late' | 'missed'
154
+ }
155
+
156
+ interface CommandEntry = {
157
+ code: number
158
+ ms: number
159
+ name: string
160
+ status: 'ok' | 'bad'
161
+ when: string
162
+ }
163
+
164
+ interface ConnectedClient = {
165
+ actions: number
166
+ connectedFor: string
167
+ id: string
168
+ ip: string
169
+ lastActivity: string
170
+ user: string | null
171
+ }
172
+
173
+ interface DbStat = {
174
+ label: string
175
+ sub: string
176
+ tone?: Tone
177
+ value: string
178
+ }
179
+
180
+ interface DeadJob = {
181
+ attempts: number
182
+ deadAt: string
183
+ error: string
184
+ id: number
185
+ name: string
186
+ }
187
+
188
+ interface Deploy = {
189
+ at: number
190
+ sha: string
191
+ when: string
192
+ }
193
+
194
+ interface ExceptionGroup = {
195
+ count: number
196
+ d1: number
197
+ d30: number
198
+ d7: number
199
+ frames: string[]
200
+ lastSeen: string
201
+ location: string
202
+ message: string
203
+ series: number[]
204
+ type: string
205
+ users: number
206
+ }
207
+
208
+ interface FailedJob = {
209
+ attempts: number
210
+ error: string
211
+ failedAt: string
212
+ id: number
213
+ name: string
214
+ tags: string[]
215
+ }
216
+
217
+ interface FeedEvent = {
218
+ detail: string
219
+ label: string
220
+ route: string | null
221
+ status: 'info' | 'ok' | 'warn' | 'bad'
222
+ when: string
223
+ }
224
+
225
+ interface Gauge = {
226
+ label: string
227
+ sub: string
228
+ value: number
229
+ }
230
+
231
+ interface HealthEntry = {
232
+ detail: string
233
+ name: string
234
+ ok: boolean
235
+ }
236
+
237
+ interface JobEntry = {
238
+ className: string
239
+ error: string | null
240
+ ms: number
241
+ queue: string
242
+ status: string
243
+ when: string
244
+ }
245
+
246
+ interface MailEntry = {
247
+ body: string
248
+ id: number
249
+ mailer: string
250
+ ms: number
251
+ status: 'queued' | 'failed' | 'sent'
252
+ subject: string
253
+ to: string
254
+ when: string
255
+ }
256
+
257
+ interface MemoryRoute = {
258
+ count: number
259
+ memKb: number
260
+ method: string
261
+ path: string
262
+ }
263
+
264
+ interface MigrationEntry = {
265
+ direction: string
266
+ ms: number
267
+ name: string
268
+ ok: boolean
269
+ when: string
270
+ }
271
+
272
+ interface ModelEvent = {
273
+ model: string
274
+ operation: 'created' | 'updated' | 'deleted'
275
+ table: string
276
+ when: string
277
+ }
278
+
279
+ interface ModelStat = {
280
+ created: number
281
+ deleted: number
282
+ model: string
283
+ table: string
284
+ total: number
285
+ updated: number
286
+ }
287
+
288
+ interface MonitorConfigShape = {
289
+ accent?: string
290
+ alertCooldownMs?: number
291
+ alertThresholds?: AlertThresholds
292
+ alertWebhook?: string
293
+ alerts?: boolean
294
+ apdexTargetMs?: number
295
+ auth?: (user: unknown) => boolean | Promise<boolean>
296
+ capturePayloads?: boolean
297
+ deploy?: string
298
+ metrics?: boolean
299
+ metricsPath?: string
300
+ path?: string
301
+ payloadMaxBytes?: number
302
+ record?: boolean
303
+ refreshMs?: number
304
+ region?: string
305
+ retentionDays?: number
306
+ retentionMode?: RetentionMode
307
+ sections?: Record<string, boolean>
308
+ slowQueryMs?: number
309
+ slowRequestMs?: number
310
+ snapshotCacheMs?: number
311
+ storage?: string
312
+ subtitle?: string
313
+ title?: string
314
+ zerotalVersion?: string
315
+ }
316
+
317
+ interface MonitorPanelHost = {
318
+ enabled: (id: string) => boolean
319
+ section: (section: MonitorSection) => void
320
+ }
321
+
322
+ interface MonitorSection = {
323
+ group?: string
324
+ icon?: string
325
+ id: string
326
+ label: string
327
+ resolve: (range: MonitorRange) => Promise<MonitorSectionData> | MonitorSectionData
328
+ sort?: number
329
+ }
330
+
331
+ interface MonitorSectionData = {
332
+ stats?: MonitorStat[]
333
+ tables?: MonitorTable[]
334
+ }
335
+
336
+ interface MonitorSnapshot = {
337
+ alertHistory: AlertEntry[]
338
+ alerts: Alert[]
339
+ apdex: number
340
+ cache: CacheStats
341
+ checkins: CheckIn[]
342
+ commands: CommandEntry[]
343
+ dbStats: DbStat[]
344
+ deadLetter: DeadJob[]
345
+ deploys: Deploy[]
346
+ exceptions: ExceptionGroup[]
347
+ failedJobs: FailedJob[]
348
+ gauges: Gauge[]
349
+ health: HealthEntry[]
350
+ jobTags: string[]
351
+ jobsSeries: number[]
352
+ logs: FeedEvent[]
353
+ mail: MailEntry[]
354
+ meta: SystemMeta
355
+ migrations: MigrationEntry[]
356
+ models: ModelStat[]
357
+ notifications: NotificationEntry[]
358
+ nplusOnes: NPlusOne[]
359
+ outgoingHttp: OutgoingHttp[]
360
+ percentiles: Percentile[]
361
+ pulse: PulseStats
362
+ queueStats: QueueMetric[]
363
+ queues: QueueRow[]
364
+ range: MonitorRange
365
+ realtime: RealtimeStats
366
+ recentModels: ModelEvent[]
367
+ requests: RequestEntry[]
368
+ scheduledJobs: ScheduledJob[]
369
+ scheduledRuns: FeedEvent[]
370
+ security: FeedEvent[]
371
+ slowJobs: JobEntry[]
372
+ slowQueries: SlowQuery[]
373
+ slowRequests: RequestEntry[]
374
+ slowRoutes: RouteStat[]
375
+ statCards: StatCard[]
376
+ storage: StorageInfo
377
+ throughput: number[]
378
+ topMemory: MemoryRoute[]
379
+ topUsers: UserUsage[]
380
+ transactions: TxStats
381
+ uptimeChecks: UptimeCheck[]
382
+ workers: Worker[]
383
+ }
384
+
385
+ interface MonitorStat = {
386
+ detail?: string
387
+ label: string
388
+ percent?: number
389
+ tone?: MonitorTone
390
+ value: string | number
391
+ }
392
+
393
+ interface MonitorStoreOptions = {
394
+ apdexTargetMs?: number
395
+ deploy?: string
396
+ region?: string
397
+ retentionDays?: number
398
+ retentionMode?: RetentionMode
399
+ slowQueryMs?: number
400
+ slowRequestMs?: number
401
+ snapshotCacheMs?: number
402
+ storage?: string
403
+ zerotalVersion?: string
404
+ }
405
+
406
+ interface MonitorTable = {
407
+ columns: MonitorTableColumn[]
408
+ empty?: string
409
+ rows: MonitorRow[]
410
+ title: string
411
+ }
412
+
413
+ interface MonitorTableColumn = {
414
+ align?: 'start' | 'end'
415
+ format?: (value: unknown, row: MonitorRow) => string
416
+ key: string
417
+ label: string
418
+ mono?: boolean
419
+ tone?: (value: unknown, row: MonitorRow) => MonitorTone | null
420
+ }
421
+
422
+ interface NotificationEntry = {
423
+ channel: string
424
+ ms: number
425
+ notification: string
426
+ recipient: string
427
+ status: 'ok' | 'bad'
428
+ when: string
429
+ }
430
+
431
+ interface NPlusOne = {
432
+ fingerprint: string
433
+ lastSeen: string
434
+ occurrences: number
435
+ route: string | null
436
+ worstCount: number
437
+ }
438
+
439
+ interface OutgoingHttp = {
440
+ calls: number
441
+ errRate: number
442
+ host: string
443
+ p95: number
444
+ }
445
+
446
+ interface Percentile = {
447
+ label: string
448
+ value: number
449
+ }
450
+
451
+ interface PulseStats = {
452
+ activeConnections: number
453
+ activeRequests: number
454
+ errorRatePct: number
455
+ requestsPerSec: number
456
+ }
457
+
458
+ interface QueueMetric = {
459
+ label: string
460
+ sub: string
461
+ tone?: Tone
462
+ value: string
463
+ }
464
+
465
+ interface QueueRow = {
466
+ name: string
467
+ paused: boolean
468
+ pending: number
469
+ series: number[]
470
+ throughput: number
471
+ wait: number
472
+ }
473
+
474
+ interface RealtimeStats = {
475
+ actionsPerMin: number
476
+ activeConnections: number
477
+ avgActionMs: number
478
+ avgMemKb: number
479
+ clients: ConnectedClient[]
480
+ closed: number
481
+ components: { name: string; actions: number; avgMs: number;}[]
482
+ opened: number
483
+ recentActions: WsAction[]
484
+ series: number[]
485
+ slowActions: { component: string; action: string; ms: number; when: string;}[]
486
+ }
487
+
488
+ interface RequestEntry = {
489
+ context: Record<string, unknown>
490
+ error: string | null
491
+ id: number
492
+ ip: string | null
493
+ logs: RequestLog[]
494
+ memKb: number
495
+ method: string
496
+ ms: number
497
+ nplus: boolean
498
+ path: string
499
+ payload: RequestPayload | null
500
+ queries: RequestQuery[]
501
+ spans: RequestSpan[]
502
+ status: number
503
+ user: string | null
504
+ when: string
505
+ }
506
+
507
+ interface RequestLog = {
508
+ level: 'error' | 'info' | 'warn'
509
+ msg: string
510
+ }
511
+
512
+ interface RequestPayload = {
513
+ reqBody: string
514
+ reqHeaders: Record<string, string>
515
+ resBody: string
516
+ }
517
+
518
+ interface RequestQuery = {
519
+ ms: number
520
+ sql: string
521
+ }
522
+
523
+ interface RequestSpan = {
524
+ dur: number
525
+ kind: SpanKind
526
+ label: string
527
+ start: number
528
+ }
529
+
530
+ interface ResolvedMonitorConfig = {
531
+ accent: string
532
+ alertCooldownMs: number
533
+ alertThresholds?: AlertThresholds
534
+ alertWebhook?: string
535
+ alerts: boolean
536
+ apdexTargetMs: number
537
+ auth: (user: unknown) => boolean | Promise<boolean>
538
+ capturePayloads: boolean
539
+ deploy?: string
540
+ metrics: boolean
541
+ metricsPath: string
542
+ path: string
543
+ payloadMaxBytes: number
544
+ record: boolean
545
+ refreshMs: number
546
+ region?: string
547
+ retentionDays: number
548
+ retentionMode: RetentionMode
549
+ sections?: Record<string, boolean>
550
+ slowQueryMs: number
551
+ slowRequestMs: number
552
+ snapshotCacheMs: number
553
+ storage: string
554
+ subtitle: string
555
+ title: string
556
+ zerotalVersion?: string
557
+ }
558
+
559
+ interface RouteDetail = {
560
+ avgMs: number
561
+ errorCount: number
562
+ errorRate: number
563
+ errors: number[]
564
+ latency: number[]
565
+ maxMs: number
566
+ method: string
567
+ p50: number
568
+ p95: number
569
+ p99: number
570
+ path: string
571
+ range: MonitorRange
572
+ recent: RequestEntry[]
573
+ rpm: number
574
+ slowest: RequestEntry[]
575
+ statusDist: StatusClassCount[]
576
+ throughput: number[]
577
+ total: number
578
+ }
579
+
580
+ interface RouteStat = {
581
+ method: string
582
+ ms: number
583
+ path: string
584
+ }
585
+
586
+ interface ScheduledJob = {
587
+ name: string
588
+ queue: string
589
+ runsIn: string
590
+ tag: string
591
+ }
592
+
593
+ interface SlowQuery = {
594
+ callers: number
595
+ location: string
596
+ ms: number
597
+ sql: string
598
+ }
599
+
600
+ interface StatCard = {
601
+ delta: number
602
+ label: string
603
+ series: number[]
604
+ value: string
605
+ }
606
+
607
+ interface StatusClassCount = {
608
+ count: number
609
+ label: '2xx' | '3xx' | '4xx' | '5xx'
610
+ }
611
+
612
+ interface StorageInfo = {
613
+ archived: number
614
+ cacheEvents: number
615
+ deploys: number
616
+ exceptions: number
617
+ httpCalls: number
618
+ jobs: number
619
+ mail: number
620
+ oldestMs: number | null
621
+ queries: number
622
+ requests: number
623
+ }
624
+
625
+ interface SystemMeta = {
626
+ bun: string
627
+ deploy: string
628
+ environment: string
629
+ region: string
630
+ uptime: string
631
+ zerotal: string
632
+ }
633
+
634
+ interface TxStats = {
635
+ avgMs: number
636
+ committed: number
637
+ rolledBack: number
638
+ }
639
+
640
+ interface UptimeCheck = {
641
+ ms: number
642
+ name: string
643
+ ok: boolean
644
+ uptime: string
645
+ }
646
+
647
+ interface UserUsage = {
648
+ id: string
649
+ requests: number
650
+ }
651
+
652
+ interface Worker = {
653
+ jobsPerMin: number
654
+ name: string
655
+ processes: number
656
+ series: number[]
657
+ status: 'running' | 'paused' | 'stopped'
658
+ }
659
+
660
+ interface WsAction = {
661
+ action: string
662
+ component: string
663
+ context: Record<string, unknown>
664
+ id: number
665
+ ip: string | null
666
+ memKb: number
667
+ ms: number
668
+ nplus: boolean
669
+ ok: boolean
670
+ queries: RequestQuery[]
671
+ user: string | null
672
+ when: string
673
+ }
674
+
675
+ type MonitorRange = 'live' | '1h' | '24h' | '7d'
676
+
677
+ type MonitorRow = { [x: string]: unknown;}
678
+
679
+ type MonitorTone = 'default' | 'warn' | 'good' | 'bad'
680
+
681
+ type SpanKind = 'query' | 'cache' | 'middleware' | 'http' | 'boot' | 'controller' | 'view'
682
+
683
+ type Tone = 'ok' | 'warn' | 'bad' | 'neutral'
684
+
685
+ value MonitorLayout = unknown
686
+
687
+ value MonitorPage = unknown
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerotal/monitor",
3
- "version": "1.6.3",
3
+ "version": "1.7.0",
4
4
  "license": "MIT",
5
5
  "maturity": "stable",
6
6
  "private": false,
@@ -12,6 +12,7 @@
12
12
  },
13
13
  "files": [
14
14
  "CHANGELOG.md",
15
+ "api-surface.md",
15
16
  "src",
16
17
  "!src/**/*.test.ts",
17
18
  "!src/**/*.test.tsx",
@@ -29,14 +30,14 @@
29
30
  "typecheck": "tsc --noEmit"
30
31
  },
31
32
  "dependencies": {
32
- "@zerotal/core": "1.6.3",
33
- "@zerotal/flow-ui": "1.6.3",
34
- "@zerotal/flow": "1.6.3"
33
+ "@zerotal/core": "1.7.0",
34
+ "@zerotal/flow-ui": "1.7.0",
35
+ "@zerotal/flow": "1.7.0"
35
36
  },
36
37
  "devDependencies": {
37
- "@zerotal/queue": "1.6.3",
38
- "@zerotal/scheduler": "1.6.3",
39
- "@zerotal/telemetry": "1.6.3"
38
+ "@zerotal/queue": "1.7.0",
39
+ "@zerotal/scheduler": "1.7.0",
40
+ "@zerotal/telemetry": "1.7.0"
40
41
  },
41
42
  "peerDependencies": {
42
43
  "@zerotal/queue": "^1.0.0",