@tclohm/yoban 1.0.0 → 1.0.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 (3) hide show
  1. package/README.MD +84 -12
  2. package/package.json +1 -1
  3. package/src/yoban.js +58 -20
package/README.MD CHANGED
@@ -1,20 +1,26 @@
1
1
  # @tclohm/yoban
2
+ > Lightweight, universal middleware for real-time API performance monitoring and SLA alerting.
2
3
 
3
- > Lightweight Express middleware for real-time API performance monitoring and SLA alerting.
4
+ [![npm version](https://badge.fury.io/js/%40tclohm%2Fyoban.svg)](https://www.npmjs.com/package/@tclohm/yoban)
5
+ [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+
7
+ ---
4
8
 
5
9
  ## Install
6
- ```
7
- npm install @tclohm/yoban
10
+ ```bash
11
+ npm install @tclohm/yoban
8
12
  ```
9
13
 
10
- ## Usage
14
+ ---
15
+
16
+ ## Quick Start
11
17
  ```javascript
12
- import { yoban } from '@tclohm/yoban';
18
+ import { Yoban } from '@tclohm/yoban';
13
19
 
14
- const metrics = new yoban({
20
+ const yoban = new Yoban({
15
21
  service: "payments",
16
- flushInterval: 10000, // flush every 10s
17
- violationThreshold: 0.5, // alert if >50% of requests violate SLA
22
+ flushInterval: 10000,
23
+ violationThreshold: 0.5,
18
24
  sla: { premium: 400, standard: 800 },
19
25
  notify: {
20
26
  slack: process.env.SLACK_WEBHOOK,
@@ -24,20 +30,86 @@ const metrics = new yoban({
24
30
  tier: req.user?.tier ?? 'standard'
25
31
  })
26
32
  });
33
+ ```
27
34
 
28
- app.use(metrics.middleware());
35
+ ---
36
+
37
+ ## Framework Support
38
+
39
+ ### Express
40
+ ```javascript
41
+ app.use(yoban.middleware());
29
42
  ```
30
43
 
44
+ ### Fastify
45
+ ```javascript
46
+ fastify.addHook('onRequest', yoban.fastify().onRequest);
47
+ fastify.addHook('onResponse', yoban.fastify().onResponse);
48
+ ```
49
+
50
+ ### Koa
51
+ ```javascript
52
+ app.use(yoban.koa());
53
+ ```
54
+
55
+ ### Hapi
56
+ ```javascript
57
+ await server.register(yoban.hapi());
58
+ ```
59
+
60
+ ---
61
+
31
62
  ## Config
63
+
32
64
  | Option | Type | Default | Description |
33
65
  |---|---|---|---|
34
66
  | `service` | string | required | Name of your service |
35
67
  | `flushInterval` | number | 10000 | How often to flush in ms |
36
- | `violationThreshold` | number | 0.5 | Violation rate to trigger alert |
68
+ | `violationThreshold` | number | 0.5 | Violation rate to trigger alert (0-1) |
37
69
  | `sla` | object | — | SLA thresholds per tier in ms |
38
70
  | `notify.slack` | string | — | Slack webhook URL |
39
71
  | `notify.pagerduty` | string | — | PagerDuty routing key |
40
- | `enrichEvent` | function | — | Add custom metadata per request |
72
+ | `enrichEvent` | function | — | Attach custom metadata per request |
73
+
74
+ ---
75
+
76
+ ## How It Works
77
+ ```
78
+ Request → Adapter (Express/Fastify/Koa/Hapi)
79
+ → Buffer
80
+ → Flush every N seconds
81
+ → Aggregate (mean, median, violation rate)
82
+ → Alert if violation rate exceeds threshold
83
+ → Notify (Slack, PagerDuty)
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Roadmap
89
+
90
+ ### v1.1
91
+ - [ ] TypeScript support
92
+ - [ ] Config file support (`.yobanrc`)
93
+
94
+ ### v1.2
95
+ - [ ] p50 / p90 / p95 percentiles in output
96
+ - [ ] Email notifications via SendGrid
97
+ - [ ] SMS notifications via Twilio
98
+ - [ ] Discord webhook support
99
+
100
+ ### v2.0
101
+ - [ ] Persistent storage — keep metrics across restarts
102
+ - [ ] Dashboard UI to visualize metrics and violation rates
103
+ - [ ] Anomaly detection — alert when something is unusually slow
104
+ - [ ] Trend detection — "this endpoint has been getting slower over 24 hours"
105
+ - [ ] Auto-tune SLA thresholds based on historical baselines
106
+
107
+ ### v2.1
108
+ - [ ] Export to Datadog, Prometheus, Grafana
109
+ - [ ] Kubernetes health check endpoint
110
+ - [ ] CLI tool to replay and analyze log files
111
+
112
+ ---
41
113
 
42
114
  ## License
43
- MIT © tclohm
115
+ MIT © [tclohm](https://github.com/tclohm)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tclohm/yoban",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Lightweight middleware for real-time API performance monitoring and SLA alerting",
5
5
  "keywords": [
6
6
  "monitoring",
package/src/yoban.js CHANGED
@@ -9,25 +9,17 @@ export class yoban {
9
9
  this.config = config;
10
10
  this.#startFlushing();
11
11
  }
12
-
13
- middleware() {
14
- return (req, res, next) => {
15
- const start = Date.now();
16
- res.on('finish', () => {
17
- const duration = Date.now() - start;
18
- const extra = this.config.enrichEvent ? this.config.enrichEvent(req) : {};
19
- this.#buffer.push({
20
- service: this.config.service,
21
- method: req.method,
22
- route: req.route?.path ?? req.path,
23
- status: res.statusCode,
24
- duration,
25
- timestamp: Date.now(),
26
- ...extra
27
- });
28
- });
29
- next();
30
- };
12
+ // --- Core ---
13
+ #record({ route, method, status, duration, extra = {} }) {
14
+ this.#buffer.push({
15
+ server: this.config.service,
16
+ method,
17
+ route,
18
+ status,
19
+ duration,
20
+ timestamp: Date.now(),
21
+ ...extra
22
+ });
31
23
  }
32
24
 
33
25
  #startFlushing() {
@@ -68,7 +60,7 @@ export class yoban {
68
60
  const violationRate = violations / entry.durations.length;
69
61
 
70
62
  if (violationRate > (this.config.violationThreshold ?? 0.5)) {
71
- console.log(`[ yoban ALERT ]: ${entry.service} ${entry.route} (${entry.tier}) violation rate ${(violationRate * 100).toFixed(2)}%`);
63
+ console.log(`[ YOBAN ALERT ]: ${entry.service} ${entry.route} (${entry.tier}) violation rate ${(violationRate * 100).toFixed(2)}%`);
72
64
 
73
65
  if (this.config.notify?.slack) {
74
66
  await notifySlack(this.config.notify.slack, entry, violationRate);
@@ -79,4 +71,50 @@ export class yoban {
79
71
  }
80
72
  }
81
73
  }
74
+
75
+ // --- Framework Adapters ---
76
+ middleware() {
77
+ return (req, res, next) => {
78
+ const start = Date.now();
79
+ res.on('finish', () => {
80
+ const extra = this.config.enrichEvent ? this.config.enrichEvent(req) : {};
81
+ this.#record({ route: req.route?.path ?? req.path, method: req.method, status: res.statusCode, duration: Date.now() - start, extra });
82
+ });
83
+ next();
84
+ };
85
+ }
86
+
87
+ fastify() {
88
+ return {
89
+ onRequest: (request, reply, done) => { requet.startTime = Date.now(); done(); },
90
+ onResponse: (request, reply, done) => {
91
+ const extra = this.config.enrichEvent ? this.config.enrichEvent(request) : {};
92
+ this.#record({ route: request.routerPath, method: request.method, status: reply.statusCode, duration: Date.now() - request.startTime, extra });
93
+ done();
94
+ }
95
+ };
96
+ }
97
+
98
+ koa() {
99
+ return async (ctx, next) => {
100
+ const start = Date.now();
101
+ await next();
102
+ const extra = this.config.enrichEvent ? this.config.enrichEvent(ctx) : {};
103
+ this.#record({ route: ctx.path , method: ctx.method, status: ctx.status, duration: Date.now() - start, extra });
104
+ };
105
+ }
106
+
107
+ hapi() {
108
+ return {
109
+ name: 'yoban',
110
+ register: (server) => {
111
+ server.ext('onPreResponse', (request, h) => {
112
+ const extra = this.config.enrichEvent > this.config.enrichEvent(request) : {};
113
+ this.#record({ route: request.method, status: request.response.statusCode, duration: Date.now() - request.infor.received, extra });
114
+ return h.continue;
115
+ })
116
+ }
117
+ }
118
+ }
119
+
82
120
  }