@rudderjs/pulse 0.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.
- package/LICENSE +21 -0
- package/README.md +107 -0
- package/boost/guidelines.md +33 -0
- package/dist/aggregators/cache.d.ts +11 -0
- package/dist/aggregators/cache.d.ts.map +1 -0
- package/dist/aggregators/cache.js +34 -0
- package/dist/aggregators/cache.js.map +1 -0
- package/dist/aggregators/exception.d.ts +11 -0
- package/dist/aggregators/exception.d.ts.map +1 -0
- package/dist/aggregators/exception.js +30 -0
- package/dist/aggregators/exception.js.map +1 -0
- package/dist/aggregators/query.d.ts +12 -0
- package/dist/aggregators/query.d.ts.map +1 -0
- package/dist/aggregators/query.js +39 -0
- package/dist/aggregators/query.js.map +1 -0
- package/dist/aggregators/queue.d.ts +12 -0
- package/dist/aggregators/queue.d.ts.map +1 -0
- package/dist/aggregators/queue.js +43 -0
- package/dist/aggregators/queue.js.map +1 -0
- package/dist/aggregators/request.d.ts +15 -0
- package/dist/aggregators/request.d.ts.map +1 -0
- package/dist/aggregators/request.js +46 -0
- package/dist/aggregators/request.js.map +1 -0
- package/dist/aggregators/server.d.ts +13 -0
- package/dist/aggregators/server.d.ts.map +1 -0
- package/dist/aggregators/server.js +35 -0
- package/dist/aggregators/server.js.map +1 -0
- package/dist/aggregators/user.d.ts +17 -0
- package/dist/aggregators/user.d.ts.map +1 -0
- package/dist/aggregators/user.js +48 -0
- package/dist/aggregators/user.js.map +1 -0
- package/dist/api/routes.d.ts +6 -0
- package/dist/api/routes.d.ts.map +1 -0
- package/dist/api/routes.js +167 -0
- package/dist/api/routes.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +143 -0
- package/dist/index.js.map +1 -0
- package/dist/storage.d.ts +28 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +219 -0
- package/dist/storage.js.map +1 -0
- package/dist/types.d.ts +77 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/dashboard.d.ts +5 -0
- package/dist/ui/dashboard.d.ts.map +1 -0
- package/dist/ui/dashboard.js +234 -0
- package/dist/ui/dashboard.js.map +1 -0
- package/dist/ui/layout.d.ts +6 -0
- package/dist/ui/layout.d.ts.map +1 -0
- package/dist/ui/layout.js +54 -0
- package/dist/ui/layout.js.map +1 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +19 -0
- package/dist/utils.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { dashboardPage } from '../ui/dashboard.js';
|
|
2
|
+
const PERIODS = {
|
|
3
|
+
'1h': 60 * 60 * 1000,
|
|
4
|
+
'6h': 6 * 60 * 60 * 1000,
|
|
5
|
+
'24h': 24 * 60 * 60 * 1000,
|
|
6
|
+
'7d': 7 * 24 * 60 * 60 * 1000,
|
|
7
|
+
};
|
|
8
|
+
function sinceFromPeriod(period) {
|
|
9
|
+
const ms = PERIODS[period] ?? PERIODS['1h'];
|
|
10
|
+
return new Date(Date.now() - ms);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Register all Pulse API routes on the router.
|
|
14
|
+
*/
|
|
15
|
+
export async function registerRoutes(storage, config) {
|
|
16
|
+
const { router } = await import('@rudderjs/router');
|
|
17
|
+
const basePath = `/${config.path ?? 'pulse'}`;
|
|
18
|
+
const prefix = `${basePath}/api`;
|
|
19
|
+
const middleware = config.auth ? [authMiddleware(config)] : [];
|
|
20
|
+
// ── Dashboard UI ─────────────────────────────────────────
|
|
21
|
+
router.get(basePath, (_req, res) => {
|
|
22
|
+
res.header('Content-Type', 'text/html').send(dashboardPage(prefix));
|
|
23
|
+
}, middleware);
|
|
24
|
+
// ── Overview ─────────────────────────────────────────────
|
|
25
|
+
router.get(`${prefix}/overview`, async (req, res) => {
|
|
26
|
+
const since = sinceFromPeriod(req.query['period'] ?? '1h');
|
|
27
|
+
const aggregates = await storage.overview(since);
|
|
28
|
+
// Group by type and compute summary stats
|
|
29
|
+
const summary = {};
|
|
30
|
+
for (const agg of aggregates) {
|
|
31
|
+
if (!summary[agg.type]) {
|
|
32
|
+
summary[agg.type] = { count: 0, sum: 0, min: null, max: null, buckets: 0 };
|
|
33
|
+
}
|
|
34
|
+
const s = summary[agg.type];
|
|
35
|
+
s.count += agg.count;
|
|
36
|
+
s.sum += agg.sum;
|
|
37
|
+
s.buckets += 1;
|
|
38
|
+
if (agg.min !== null && (s.min === null || agg.min < s.min))
|
|
39
|
+
s.min = agg.min;
|
|
40
|
+
if (agg.max !== null && (s.max === null || agg.max > s.max))
|
|
41
|
+
s.max = agg.max;
|
|
42
|
+
}
|
|
43
|
+
// Compute averages
|
|
44
|
+
const metrics = {};
|
|
45
|
+
for (const [type, s] of Object.entries(summary)) {
|
|
46
|
+
metrics[type] = {
|
|
47
|
+
total: s.count,
|
|
48
|
+
avg: s.count > 0 ? Math.round((s.sum / s.count) * 100) / 100 : 0,
|
|
49
|
+
min: s.min,
|
|
50
|
+
max: s.max,
|
|
51
|
+
buckets: s.buckets,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
res.json({ period: req.query['period'] ?? '1h', metrics });
|
|
55
|
+
}, middleware);
|
|
56
|
+
// ── Request metrics ──────────────────────────────────────
|
|
57
|
+
router.get(`${prefix}/requests`, async (req, res) => {
|
|
58
|
+
const since = sinceFromPeriod(req.query['period'] ?? '1h');
|
|
59
|
+
const counts = await storage.aggregates('request_count', since);
|
|
60
|
+
const durations = await storage.aggregates('request_duration', since);
|
|
61
|
+
res.json({
|
|
62
|
+
throughput: counts.map(bucketToJson),
|
|
63
|
+
duration: durations.map(a => ({
|
|
64
|
+
...bucketToJson(a),
|
|
65
|
+
avg: a.count > 0 ? Math.round((a.sum / a.count) * 100) / 100 : 0,
|
|
66
|
+
})),
|
|
67
|
+
});
|
|
68
|
+
}, middleware);
|
|
69
|
+
// ── Slow requests ────────────────────────────────────────
|
|
70
|
+
router.get(`${prefix}/slow-requests`, async (req, res) => {
|
|
71
|
+
const entries = await storage.entries('slow_request', {
|
|
72
|
+
page: parseInt(req.query['page'] ?? '1', 10),
|
|
73
|
+
perPage: parseInt(req.query['per_page'] ?? '50', 10),
|
|
74
|
+
});
|
|
75
|
+
res.json({ data: entries });
|
|
76
|
+
}, middleware);
|
|
77
|
+
// ── Queue metrics ────────────────────────────────────────
|
|
78
|
+
router.get(`${prefix}/queues`, async (req, res) => {
|
|
79
|
+
const since = sinceFromPeriod(req.query['period'] ?? '1h');
|
|
80
|
+
const throughput = await storage.aggregates('queue_throughput', since);
|
|
81
|
+
const waitTimes = await storage.aggregates('queue_wait_time', since);
|
|
82
|
+
res.json({
|
|
83
|
+
throughput: throughput.map(bucketToJson),
|
|
84
|
+
wait_time: waitTimes.map(a => ({
|
|
85
|
+
...bucketToJson(a),
|
|
86
|
+
avg: a.count > 0 ? Math.round((a.sum / a.count) * 100) / 100 : 0,
|
|
87
|
+
})),
|
|
88
|
+
});
|
|
89
|
+
}, middleware);
|
|
90
|
+
// ── Slow queries ─────────────────────────────────────────
|
|
91
|
+
router.get(`${prefix}/slow-queries`, async (req, res) => {
|
|
92
|
+
const entries = await storage.entries('slow_query', {
|
|
93
|
+
page: parseInt(req.query['page'] ?? '1', 10),
|
|
94
|
+
perPage: parseInt(req.query['per_page'] ?? '50', 10),
|
|
95
|
+
});
|
|
96
|
+
res.json({ data: entries });
|
|
97
|
+
}, middleware);
|
|
98
|
+
// ── Exceptions ───────────────────────────────────────────
|
|
99
|
+
router.get(`${prefix}/exceptions`, async (req, res) => {
|
|
100
|
+
const since = sinceFromPeriod(req.query['period'] ?? '1h');
|
|
101
|
+
const aggregates = await storage.aggregates('exceptions', since);
|
|
102
|
+
const entries = await storage.entries('exception', {
|
|
103
|
+
page: parseInt(req.query['page'] ?? '1', 10),
|
|
104
|
+
perPage: parseInt(req.query['per_page'] ?? '20', 10),
|
|
105
|
+
});
|
|
106
|
+
res.json({
|
|
107
|
+
over_time: aggregates.map(bucketToJson),
|
|
108
|
+
recent: entries,
|
|
109
|
+
});
|
|
110
|
+
}, middleware);
|
|
111
|
+
// ── Cache ────────────────────────────────────────────────
|
|
112
|
+
router.get(`${prefix}/cache`, async (req, res) => {
|
|
113
|
+
const since = sinceFromPeriod(req.query['period'] ?? '1h');
|
|
114
|
+
const hits = await storage.aggregates('cache_hits', since);
|
|
115
|
+
const misses = await storage.aggregates('cache_misses', since);
|
|
116
|
+
const totalHits = hits.reduce((s, a) => s + a.count, 0);
|
|
117
|
+
const totalMisses = misses.reduce((s, a) => s + a.count, 0);
|
|
118
|
+
const total = totalHits + totalMisses;
|
|
119
|
+
const hitRate = total > 0 ? Math.round((totalHits / total) * 10000) / 100 : 0;
|
|
120
|
+
res.json({
|
|
121
|
+
hit_rate: hitRate,
|
|
122
|
+
total_hits: totalHits,
|
|
123
|
+
total_misses: totalMisses,
|
|
124
|
+
hits: hits.map(bucketToJson),
|
|
125
|
+
misses: misses.map(bucketToJson),
|
|
126
|
+
});
|
|
127
|
+
}, middleware);
|
|
128
|
+
// ── Active users ─────────────────────────────────────────
|
|
129
|
+
router.get(`${prefix}/users`, async (req, res) => {
|
|
130
|
+
const since = sinceFromPeriod(req.query['period'] ?? '1h');
|
|
131
|
+
const aggregates = await storage.aggregates('active_users', since);
|
|
132
|
+
res.json({ data: aggregates.map(bucketToJson) });
|
|
133
|
+
}, middleware);
|
|
134
|
+
// ── Server stats ─────────────────────────────────────────
|
|
135
|
+
router.get(`${prefix}/servers`, async (req, res) => {
|
|
136
|
+
const since = sinceFromPeriod(req.query['period'] ?? '1h');
|
|
137
|
+
const cpu = await storage.aggregates('server_cpu', since);
|
|
138
|
+
const memory = await storage.aggregates('server_memory', since);
|
|
139
|
+
res.json({
|
|
140
|
+
cpu: cpu.map(a => ({ ...bucketToJson(a), avg: a.count > 0 ? Math.round((a.sum / a.count) * 100) / 100 : 0 })),
|
|
141
|
+
memory: memory.map(a => ({ ...bucketToJson(a), avg: a.count > 0 ? Math.round((a.sum / a.count) * 100) / 100 : 0 })),
|
|
142
|
+
});
|
|
143
|
+
}, middleware);
|
|
144
|
+
}
|
|
145
|
+
function bucketToJson(agg) {
|
|
146
|
+
return {
|
|
147
|
+
bucket: agg.bucket.toISOString(),
|
|
148
|
+
type: agg.type,
|
|
149
|
+
key: agg.key,
|
|
150
|
+
count: agg.count,
|
|
151
|
+
min: agg.min,
|
|
152
|
+
max: agg.max,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function authMiddleware(config) {
|
|
156
|
+
return async (req, res, next) => {
|
|
157
|
+
if (config.auth) {
|
|
158
|
+
const allowed = await config.auth(req);
|
|
159
|
+
if (!allowed) {
|
|
160
|
+
res.status(403).json({ message: 'Unauthorized.' });
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return next();
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD,MAAM,OAAO,GAA2B;IACtC,IAAI,EAAG,EAAE,GAAG,EAAE,GAAG,IAAI;IACrB,IAAI,EAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;IACzB,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;IAC1B,IAAI,EAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;CAC/B,CAAA;AAED,SAAS,eAAe,CAAC,MAAc;IACrC,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,IAAI,CAAE,CAAA;IAC5C,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAA;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAqB,EACrB,MAAoB;IAEpB,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAA;IAEnD,MAAM,QAAQ,GAAI,IAAI,MAAM,CAAC,IAAI,IAAI,OAAO,EAAE,CAAA;IAC9C,MAAM,MAAM,GAAM,GAAG,QAAQ,MAAM,CAAA;IACnC,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IAE9D,4DAA4D;IAC5D,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,IAAgB,EAAE,GAAgB,EAAE,EAAE;QAC1D,GAAG,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;IACrE,CAAC,EAAE,UAAU,CAAC,CAAA;IAEd,4DAA4D;IAC5D,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,WAAW,EAAE,KAAK,EAAE,GAAe,EAAE,GAAgB,EAAE,EAAE;QAC3E,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAA;QAC1D,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;QAEhD,0CAA0C;QAC1C,MAAM,OAAO,GAAkC,EAAE,CAAA;QACjD,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC7B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAA;YAC5E,CAAC;YACD,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAE,CAAA;YAC5B,CAAC,CAAC,KAAK,IAAK,GAAG,CAAC,KAAK,CAAA;YACrB,CAAC,CAAC,GAAG,IAAO,GAAG,CAAC,GAAG,CAAA;YACnB,CAAC,CAAC,OAAO,IAAI,CAAC,CAAA;YACd,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;gBAAE,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAA;YAC5E,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;gBAAE,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAA;QAC9E,CAAC;QAED,mBAAmB;QACnB,MAAM,OAAO,GAA4B,EAAE,CAAA;QAC3C,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAChD,OAAO,CAAC,IAAI,CAAC,GAAG;gBACd,KAAK,EAAI,CAAC,CAAC,KAAK;gBAChB,GAAG,EAAM,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;gBACpE,GAAG,EAAM,CAAC,CAAC,GAAG;gBACd,GAAG,EAAM,CAAC,CAAC,GAAG;gBACd,OAAO,EAAE,CAAC,CAAC,OAAO;aACnB,CAAA;QACH,CAAC;QAED,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IAC5D,CAAC,EAAE,UAAU,CAAC,CAAA;IAEd,4DAA4D;IAC5D,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,WAAW,EAAE,KAAK,EAAE,GAAe,EAAE,GAAgB,EAAE,EAAE;QAC3E,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAA;QAC1D,MAAM,MAAM,GAAM,MAAM,OAAO,CAAC,UAAU,CAAC,eAAe,EAAE,KAAK,CAAC,CAAA;QAClE,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAA;QAErE,GAAG,CAAC,IAAI,CAAC;YACP,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC;YACpC,QAAQ,EAAI,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC9B,GAAG,YAAY,CAAC,CAAC,CAAC;gBAClB,GAAG,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;aACjE,CAAC,CAAC;SACJ,CAAC,CAAA;IACJ,CAAC,EAAE,UAAU,CAAC,CAAA;IAEd,4DAA4D;IAC5D,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,gBAAgB,EAAE,KAAK,EAAE,GAAe,EAAE,GAAgB,EAAE,EAAE;QAChF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,cAAc,EAAE;YACpD,IAAI,EAAK,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC;YAC/C,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;SACrD,CAAC,CAAA;QACF,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IAC7B,CAAC,EAAE,UAAU,CAAC,CAAA;IAEd,4DAA4D;IAC5D,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,SAAS,EAAE,KAAK,EAAE,GAAe,EAAE,GAAgB,EAAE,EAAE;QACzE,MAAM,KAAK,GAAQ,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAA;QAC/D,MAAM,UAAU,GAAI,MAAM,OAAO,CAAC,UAAU,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAA;QACvE,MAAM,SAAS,GAAK,MAAM,OAAO,CAAC,UAAU,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAA;QAEtE,GAAG,CAAC,IAAI,CAAC;YACP,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC;YACxC,SAAS,EAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC9B,GAAG,YAAY,CAAC,CAAC,CAAC;gBAClB,GAAG,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;aACjE,CAAC,CAAC;SACJ,CAAC,CAAA;IACJ,CAAC,EAAE,UAAU,CAAC,CAAA;IAEd,4DAA4D;IAC5D,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,eAAe,EAAE,KAAK,EAAE,GAAe,EAAE,GAAgB,EAAE,EAAE;QAC/E,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE;YAClD,IAAI,EAAK,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC;YAC/C,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;SACrD,CAAC,CAAA;QACF,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IAC7B,CAAC,EAAE,UAAU,CAAC,CAAA;IAEd,4DAA4D;IAC5D,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,aAAa,EAAE,KAAK,EAAE,GAAe,EAAE,GAAgB,EAAE,EAAE;QAC7E,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAA;QAC1D,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;QAChE,MAAM,OAAO,GAAM,MAAM,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE;YACpD,IAAI,EAAK,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC;YAC/C,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;SACrD,CAAC,CAAA;QACF,GAAG,CAAC,IAAI,CAAC;YACP,SAAS,EAAE,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC;YACvC,MAAM,EAAK,OAAO;SACnB,CAAC,CAAA;IACJ,CAAC,EAAE,UAAU,CAAC,CAAA;IAEd,4DAA4D;IAC5D,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,QAAQ,EAAE,KAAK,EAAE,GAAe,EAAE,GAAgB,EAAE,EAAE;QACxE,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAA;QAC1D,MAAM,IAAI,GAAK,MAAM,OAAO,CAAC,UAAU,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;QAC5D,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,cAAc,EAAE,KAAK,CAAC,CAAA;QAE9D,MAAM,SAAS,GAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;QACzD,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;QAC3D,MAAM,KAAK,GAAS,SAAS,GAAG,WAAW,CAAA;QAC3C,MAAM,OAAO,GAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;QAEjF,GAAG,CAAC,IAAI,CAAC;YACP,QAAQ,EAAE,OAAO;YACjB,UAAU,EAAI,SAAS;YACvB,YAAY,EAAE,WAAW;YACzB,IAAI,EAAI,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;YAC9B,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC;SACjC,CAAC,CAAA;IACJ,CAAC,EAAE,UAAU,CAAC,CAAA;IAEd,4DAA4D;IAC5D,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,QAAQ,EAAE,KAAK,EAAE,GAAe,EAAE,GAAgB,EAAE,EAAE;QACxE,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAA;QAC1D,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,cAAc,EAAE,KAAK,CAAC,CAAA;QAClE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;IAClD,CAAC,EAAE,UAAU,CAAC,CAAA;IAEd,4DAA4D;IAC5D,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,UAAU,EAAE,KAAK,EAAE,GAAe,EAAE,GAAgB,EAAE,EAAE;QAC1E,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAA;QAC1D,MAAM,GAAG,GAAM,MAAM,OAAO,CAAC,UAAU,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;QAC5D,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,eAAe,EAAE,KAAK,CAAC,CAAA;QAE/D,GAAG,CAAC,IAAI,CAAC;YACP,GAAG,EAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAChH,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SACpH,CAAC,CAAA;IACJ,CAAC,EAAE,UAAU,CAAC,CAAA;AAChB,CAAC;AAYD,SAAS,YAAY,CAAC,GAA8G;IAClI,OAAO;QACL,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE;QAChC,IAAI,EAAI,GAAG,CAAC,IAAI;QAChB,GAAG,EAAK,GAAG,CAAC,GAAG;QACf,KAAK,EAAG,GAAG,CAAC,KAAK;QACjB,GAAG,EAAK,GAAG,CAAC,GAAG;QACf,GAAG,EAAK,GAAG,CAAC,GAAG;KAChB,CAAA;AACH,CAAC;AAED,SAAS,cAAc,CAAC,MAAmB;IACzC,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC9B,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACtC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,CAAA;gBAClD,OAAM;YACR,CAAC;QACH,CAAC;QACD,OAAO,IAAI,EAAE,CAAA;IACf,CAAC,CAAA;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ServiceProvider, type Application } from '@rudderjs/core';
|
|
2
|
+
import { type PulseConfig, type PulseStorage, type PulseAggregate, type PulseEntry, type MetricType, type EntryType, type Aggregator, type EntryListOptions } from './types.js';
|
|
3
|
+
export type { PulseConfig, PulseStorage, PulseAggregate, PulseEntry, MetricType, EntryType, Aggregator, EntryListOptions };
|
|
4
|
+
export { MemoryStorage, SqliteStorage } from './storage.js';
|
|
5
|
+
export { RequestAggregator } from './aggregators/request.js';
|
|
6
|
+
export { QueueAggregator } from './aggregators/queue.js';
|
|
7
|
+
export { CacheAggregator } from './aggregators/cache.js';
|
|
8
|
+
export { ExceptionAggregator } from './aggregators/exception.js';
|
|
9
|
+
export { UserAggregator } from './aggregators/user.js';
|
|
10
|
+
export { QueryAggregator } from './aggregators/query.js';
|
|
11
|
+
export { ServerAggregator } from './aggregators/server.js';
|
|
12
|
+
export declare class PulseRegistry {
|
|
13
|
+
private static storage;
|
|
14
|
+
static set(storage: PulseStorage): void;
|
|
15
|
+
static get(): PulseStorage | null;
|
|
16
|
+
/** @internal — clears the registered storage. Used for testing. */
|
|
17
|
+
static reset(): void;
|
|
18
|
+
}
|
|
19
|
+
export declare class Pulse {
|
|
20
|
+
private static store;
|
|
21
|
+
static record(type: MetricType, value: number, key?: string | null): void | Promise<void>;
|
|
22
|
+
static aggregates(type: MetricType, since: Date, key?: string | null): PulseAggregate[] | Promise<PulseAggregate[]>;
|
|
23
|
+
static entries(type: EntryType, options?: EntryListOptions): PulseEntry[] | Promise<PulseEntry[]>;
|
|
24
|
+
static overview(since: Date): PulseAggregate[] | Promise<PulseAggregate[]>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Returns a PulseServiceProvider class configured for the given config.
|
|
28
|
+
*
|
|
29
|
+
* Tracks request throughput/duration, queue metrics, cache hit rates,
|
|
30
|
+
* exception counts, active users, slow queries, and server resource usage.
|
|
31
|
+
*
|
|
32
|
+
* Usage in bootstrap/providers.ts:
|
|
33
|
+
* import { pulse } from '@rudderjs/pulse'
|
|
34
|
+
* export default [..., pulse(configs.pulse), ...]
|
|
35
|
+
*/
|
|
36
|
+
export declare function pulse(config?: PulseConfig): new (app: Application) => ServiceProvider;
|
|
37
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAUlE,OAAO,EAEL,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,KAAK,UAAU,EACzE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,KAAK,gBAAgB,EACxE,MAAM,YAAY,CAAA;AAInB,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,gBAAgB,EAAE,CAAA;AAC1H,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAI1D,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,OAAO,CAA4B;IAElD,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IACvC,MAAM,CAAC,GAAG,IAAI,YAAY,GAAG,IAAI;IACjC,mEAAmE;IACnE,MAAM,CAAC,KAAK,IAAI,IAAI;CACrB;AAID,qBAAa,KAAK;IAChB,OAAO,CAAC,MAAM,CAAC,KAAK;IAMpB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzF,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,cAAc,EAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAInH,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,UAAU,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAIjG,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,GAAG,cAAc,EAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;CAG3E;AAID;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CAAC,MAAM,GAAE,WAAgB,GAAG,KAAK,GAAG,EAAE,WAAW,KAAK,eAAe,CAuFzF"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { ServiceProvider } from '@rudderjs/core';
|
|
2
|
+
import { MemoryStorage, SqliteStorage } from './storage.js';
|
|
3
|
+
import { RequestAggregator } from './aggregators/request.js';
|
|
4
|
+
import { QueueAggregator } from './aggregators/queue.js';
|
|
5
|
+
import { CacheAggregator } from './aggregators/cache.js';
|
|
6
|
+
import { ExceptionAggregator } from './aggregators/exception.js';
|
|
7
|
+
import { UserAggregator } from './aggregators/user.js';
|
|
8
|
+
import { QueryAggregator } from './aggregators/query.js';
|
|
9
|
+
import { ServerAggregator } from './aggregators/server.js';
|
|
10
|
+
import { registerRoutes } from './api/routes.js';
|
|
11
|
+
import { defaultConfig, } from './types.js';
|
|
12
|
+
export { MemoryStorage, SqliteStorage } from './storage.js';
|
|
13
|
+
export { RequestAggregator } from './aggregators/request.js';
|
|
14
|
+
export { QueueAggregator } from './aggregators/queue.js';
|
|
15
|
+
export { CacheAggregator } from './aggregators/cache.js';
|
|
16
|
+
export { ExceptionAggregator } from './aggregators/exception.js';
|
|
17
|
+
export { UserAggregator } from './aggregators/user.js';
|
|
18
|
+
export { QueryAggregator } from './aggregators/query.js';
|
|
19
|
+
export { ServerAggregator } from './aggregators/server.js';
|
|
20
|
+
// ─── Pulse Registry ────────────────────────────────────────
|
|
21
|
+
export class PulseRegistry {
|
|
22
|
+
static storage = null;
|
|
23
|
+
static set(storage) { this.storage = storage; }
|
|
24
|
+
static get() { return this.storage; }
|
|
25
|
+
/** @internal — clears the registered storage. Used for testing. */
|
|
26
|
+
static reset() { this.storage = null; }
|
|
27
|
+
}
|
|
28
|
+
// ─── Pulse Facade ──────────────────────────────────────────
|
|
29
|
+
export class Pulse {
|
|
30
|
+
static store() {
|
|
31
|
+
const s = PulseRegistry.get();
|
|
32
|
+
if (!s)
|
|
33
|
+
throw new Error('[RudderJS Pulse] No storage registered. Add pulse() to providers.');
|
|
34
|
+
return s;
|
|
35
|
+
}
|
|
36
|
+
static record(type, value, key) {
|
|
37
|
+
return this.store().record(type, value, key);
|
|
38
|
+
}
|
|
39
|
+
static aggregates(type, since, key) {
|
|
40
|
+
return this.store().aggregates(type, since, key);
|
|
41
|
+
}
|
|
42
|
+
static entries(type, options) {
|
|
43
|
+
return this.store().entries(type, options);
|
|
44
|
+
}
|
|
45
|
+
static overview(since) {
|
|
46
|
+
return this.store().overview(since);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// ─── Service Provider Factory ──────────────────────────────
|
|
50
|
+
/**
|
|
51
|
+
* Returns a PulseServiceProvider class configured for the given config.
|
|
52
|
+
*
|
|
53
|
+
* Tracks request throughput/duration, queue metrics, cache hit rates,
|
|
54
|
+
* exception counts, active users, slow queries, and server resource usage.
|
|
55
|
+
*
|
|
56
|
+
* Usage in bootstrap/providers.ts:
|
|
57
|
+
* import { pulse } from '@rudderjs/pulse'
|
|
58
|
+
* export default [..., pulse(configs.pulse), ...]
|
|
59
|
+
*/
|
|
60
|
+
export function pulse(config = {}) {
|
|
61
|
+
const resolved = {
|
|
62
|
+
enabled: config.enabled ?? defaultConfig.enabled,
|
|
63
|
+
path: config.path ?? defaultConfig.path,
|
|
64
|
+
storage: config.storage ?? defaultConfig.storage,
|
|
65
|
+
sqlitePath: config.sqlitePath ?? defaultConfig.sqlitePath,
|
|
66
|
+
pruneAfterHours: config.pruneAfterHours ?? defaultConfig.pruneAfterHours,
|
|
67
|
+
slowRequestThreshold: config.slowRequestThreshold ?? defaultConfig.slowRequestThreshold,
|
|
68
|
+
slowQueryThreshold: config.slowQueryThreshold ?? defaultConfig.slowQueryThreshold,
|
|
69
|
+
recordRequests: config.recordRequests ?? defaultConfig.recordRequests,
|
|
70
|
+
recordQueues: config.recordQueues ?? defaultConfig.recordQueues,
|
|
71
|
+
recordCache: config.recordCache ?? defaultConfig.recordCache,
|
|
72
|
+
recordExceptions: config.recordExceptions ?? defaultConfig.recordExceptions,
|
|
73
|
+
recordUsers: config.recordUsers ?? defaultConfig.recordUsers,
|
|
74
|
+
recordServers: config.recordServers ?? defaultConfig.recordServers,
|
|
75
|
+
serverStatsIntervalMs: config.serverStatsIntervalMs ?? defaultConfig.serverStatsIntervalMs,
|
|
76
|
+
auth: config.auth ?? defaultConfig.auth,
|
|
77
|
+
};
|
|
78
|
+
class PulseServiceProvider extends ServiceProvider {
|
|
79
|
+
register() {
|
|
80
|
+
this.publishes({
|
|
81
|
+
from: new URL('../../boost/guidelines.md', import.meta.url).pathname,
|
|
82
|
+
to: 'boost',
|
|
83
|
+
tag: 'pulse-boost',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
async boot() {
|
|
87
|
+
if (!resolved.enabled)
|
|
88
|
+
return;
|
|
89
|
+
// ── Create storage ────────────────────────────────────
|
|
90
|
+
let storage;
|
|
91
|
+
if (resolved.storage === 'sqlite') {
|
|
92
|
+
storage = new SqliteStorage(resolved.sqlitePath);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
storage = new MemoryStorage();
|
|
96
|
+
}
|
|
97
|
+
PulseRegistry.set(storage);
|
|
98
|
+
this.app.instance('pulse', storage);
|
|
99
|
+
// ── Auto-prune ────────────────────────────────────────
|
|
100
|
+
const pruneHours = resolved.pruneAfterHours;
|
|
101
|
+
if (pruneHours > 0) {
|
|
102
|
+
const interval = Math.min(pruneHours * 60 * 60 * 1000, 3_600_000);
|
|
103
|
+
const timer = setInterval(() => {
|
|
104
|
+
const cutoff = new Date(Date.now() - pruneHours * 60 * 60 * 1000);
|
|
105
|
+
storage.pruneOlderThan(cutoff);
|
|
106
|
+
}, interval);
|
|
107
|
+
timer.unref();
|
|
108
|
+
}
|
|
109
|
+
// ── Register aggregators ──────────────────────────────
|
|
110
|
+
const requestAgg = new RequestAggregator(storage, resolved);
|
|
111
|
+
const userAgg = new UserAggregator(storage);
|
|
112
|
+
const aggregators = [];
|
|
113
|
+
if (resolved.recordQueues)
|
|
114
|
+
aggregators.push(new QueueAggregator(storage));
|
|
115
|
+
if (resolved.recordCache)
|
|
116
|
+
aggregators.push(new CacheAggregator(storage));
|
|
117
|
+
if (resolved.recordExceptions)
|
|
118
|
+
aggregators.push(new ExceptionAggregator(storage));
|
|
119
|
+
if (resolved.recordServers)
|
|
120
|
+
aggregators.push(new ServerAggregator(storage, resolved.serverStatsIntervalMs));
|
|
121
|
+
// Query aggregator for slow queries
|
|
122
|
+
aggregators.push(new QueryAggregator(storage, resolved));
|
|
123
|
+
for (const agg of aggregators) {
|
|
124
|
+
await agg.register();
|
|
125
|
+
}
|
|
126
|
+
// ── Register middleware ───────────────────────────────
|
|
127
|
+
try {
|
|
128
|
+
const { router } = await import('@rudderjs/router');
|
|
129
|
+
if (resolved.recordRequests)
|
|
130
|
+
router.use(requestAgg.middleware());
|
|
131
|
+
if (resolved.recordUsers)
|
|
132
|
+
router.use(userAgg.middleware());
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// @rudderjs/router not available
|
|
136
|
+
}
|
|
137
|
+
// ── Register API routes ───────────────────────────────
|
|
138
|
+
await registerRoutes(storage, resolved);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return PulseServiceProvider;
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { PulseAggregate, PulseEntry, PulseStorage, MetricType, EntryType, EntryListOptions } from './types.js';
|
|
2
|
+
export declare class MemoryStorage implements PulseStorage {
|
|
3
|
+
private readonly aggregates_;
|
|
4
|
+
private readonly entries_;
|
|
5
|
+
private readonly maxEntries;
|
|
6
|
+
constructor(maxEntries?: number);
|
|
7
|
+
record(type: MetricType, value: number, key?: string | null): void;
|
|
8
|
+
storeEntry(type: EntryType, content: Record<string, unknown>): void;
|
|
9
|
+
aggregates(type: MetricType, since: Date, key?: string | null): PulseAggregate[];
|
|
10
|
+
entries(type: EntryType, options?: EntryListOptions): PulseEntry[];
|
|
11
|
+
overview(since: Date): PulseAggregate[];
|
|
12
|
+
pruneOlderThan(date: Date): void;
|
|
13
|
+
}
|
|
14
|
+
export declare class SqliteStorage implements PulseStorage {
|
|
15
|
+
private readonly dbPath;
|
|
16
|
+
private db;
|
|
17
|
+
constructor(dbPath: string);
|
|
18
|
+
private getDb;
|
|
19
|
+
private migrate;
|
|
20
|
+
record(type: MetricType, value: number, key?: string | null): void;
|
|
21
|
+
storeEntry(type: EntryType, content: Record<string, unknown>): void;
|
|
22
|
+
aggregates(type: MetricType, since: Date, key?: string | null): PulseAggregate[];
|
|
23
|
+
entries(type: EntryType, options?: EntryListOptions): PulseEntry[];
|
|
24
|
+
overview(since: Date): PulseAggregate[];
|
|
25
|
+
pruneOlderThan(date: Date): void;
|
|
26
|
+
private aggFromRow;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EAAE,UAAU,EAAE,YAAY,EACxC,UAAU,EAAE,SAAS,EAAE,gBAAgB,EACxC,MAAM,YAAY,CAAA;AAiBnB,qBAAa,aAAc,YAAW,YAAY;IAChD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAyC;IACrE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmB;IAC5C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;gBAEvB,UAAU,SAAM;IAI5B,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAyBlE,UAAU,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAYnE,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,cAAc,EAAE;IAYhF,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,UAAU,EAAE;IAYlE,QAAQ,CAAC,KAAK,EAAE,IAAI,GAAG,cAAc,EAAE;IAUvC,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;CAQjC;AAID,qBAAa,aAAc,YAAW,YAAY;IAGpC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,OAAO,CAAC,EAAE,CAAiD;gBAE9B,MAAM,EAAE,MAAM;IAE3C,OAAO,CAAC,KAAK;IAcb,OAAO,CAAC,OAAO;IA0Bf,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAuBlE,UAAU,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAMnE,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,cAAc,EAAE;IAYhF,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,UAAU,EAAE;IAyBlE,QAAQ,CAAC,KAAK,EAAE,IAAI,GAAG,cAAc,EAAE;IAOvC,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAOhC,OAAO,CAAC,UAAU;CAanB"}
|
package/dist/storage.js
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
// ─── Helpers ───────────────────────────────────────────────
|
|
3
|
+
/** Round a date down to the start of its 1-minute bucket */
|
|
4
|
+
function bucketStart(date) {
|
|
5
|
+
const d = new Date(date);
|
|
6
|
+
d.setSeconds(0, 0);
|
|
7
|
+
return d;
|
|
8
|
+
}
|
|
9
|
+
function bucketKey(bucket, type, key) {
|
|
10
|
+
return `${bucket.toISOString()}|${type}|${key ?? ''}`;
|
|
11
|
+
}
|
|
12
|
+
// ─── Memory Storage ────────────────────────────────────────
|
|
13
|
+
export class MemoryStorage {
|
|
14
|
+
aggregates_ = new Map();
|
|
15
|
+
entries_ = [];
|
|
16
|
+
maxEntries;
|
|
17
|
+
constructor(maxEntries = 500) {
|
|
18
|
+
this.maxEntries = maxEntries;
|
|
19
|
+
}
|
|
20
|
+
record(type, value, key) {
|
|
21
|
+
const bucket = bucketStart(new Date());
|
|
22
|
+
const bk = bucketKey(bucket, type, key ?? null);
|
|
23
|
+
const existing = this.aggregates_.get(bk);
|
|
24
|
+
if (existing) {
|
|
25
|
+
existing.count += 1;
|
|
26
|
+
existing.sum += value;
|
|
27
|
+
if (existing.min === null || value < existing.min)
|
|
28
|
+
existing.min = value;
|
|
29
|
+
if (existing.max === null || value > existing.max)
|
|
30
|
+
existing.max = value;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
this.aggregates_.set(bk, {
|
|
34
|
+
id: randomUUID(),
|
|
35
|
+
bucket,
|
|
36
|
+
type,
|
|
37
|
+
key: key ?? null,
|
|
38
|
+
count: 1,
|
|
39
|
+
sum: value,
|
|
40
|
+
min: value,
|
|
41
|
+
max: value,
|
|
42
|
+
createdAt: new Date(),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
storeEntry(type, content) {
|
|
47
|
+
this.entries_.unshift({
|
|
48
|
+
id: randomUUID(),
|
|
49
|
+
type,
|
|
50
|
+
content,
|
|
51
|
+
createdAt: new Date(),
|
|
52
|
+
});
|
|
53
|
+
if (this.entries_.length > this.maxEntries) {
|
|
54
|
+
this.entries_.length = this.maxEntries;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
aggregates(type, since, key) {
|
|
58
|
+
const sinceTs = since.getTime();
|
|
59
|
+
const result = [];
|
|
60
|
+
for (const agg of this.aggregates_.values()) {
|
|
61
|
+
if (agg.type !== type)
|
|
62
|
+
continue;
|
|
63
|
+
if (agg.bucket.getTime() < sinceTs)
|
|
64
|
+
continue;
|
|
65
|
+
if (key !== undefined && key !== null && agg.key !== key)
|
|
66
|
+
continue;
|
|
67
|
+
result.push(agg);
|
|
68
|
+
}
|
|
69
|
+
return result.sort((a, b) => a.bucket.getTime() - b.bucket.getTime());
|
|
70
|
+
}
|
|
71
|
+
entries(type, options) {
|
|
72
|
+
let result = this.entries_.filter(e => e.type === type);
|
|
73
|
+
if (options?.search) {
|
|
74
|
+
const s = options.search.toLowerCase();
|
|
75
|
+
result = result.filter(e => JSON.stringify(e.content).toLowerCase().includes(s));
|
|
76
|
+
}
|
|
77
|
+
const page = options?.page ?? 1;
|
|
78
|
+
const perPage = options?.perPage ?? 50;
|
|
79
|
+
const start = (page - 1) * perPage;
|
|
80
|
+
return result.slice(start, start + perPage);
|
|
81
|
+
}
|
|
82
|
+
overview(since) {
|
|
83
|
+
const sinceTs = since.getTime();
|
|
84
|
+
const result = [];
|
|
85
|
+
for (const agg of this.aggregates_.values()) {
|
|
86
|
+
if (agg.bucket.getTime() < sinceTs)
|
|
87
|
+
continue;
|
|
88
|
+
result.push(agg);
|
|
89
|
+
}
|
|
90
|
+
return result.sort((a, b) => a.bucket.getTime() - b.bucket.getTime());
|
|
91
|
+
}
|
|
92
|
+
pruneOlderThan(date) {
|
|
93
|
+
const ts = date.getTime();
|
|
94
|
+
for (const [key, agg] of this.aggregates_.entries()) {
|
|
95
|
+
if (agg.bucket.getTime() < ts)
|
|
96
|
+
this.aggregates_.delete(key);
|
|
97
|
+
}
|
|
98
|
+
const idx = this.entries_.findIndex(e => e.createdAt.getTime() < ts);
|
|
99
|
+
if (idx !== -1)
|
|
100
|
+
this.entries_.length = idx;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// ─── SQLite Storage ────────────────────────────────────────
|
|
104
|
+
export class SqliteStorage {
|
|
105
|
+
dbPath;
|
|
106
|
+
db = null;
|
|
107
|
+
constructor(dbPath) {
|
|
108
|
+
this.dbPath = dbPath;
|
|
109
|
+
}
|
|
110
|
+
getDb() {
|
|
111
|
+
if (!this.db) {
|
|
112
|
+
const Database = globalThis.__betterSqlite3;
|
|
113
|
+
if (!Database) {
|
|
114
|
+
throw new Error('[RudderJS Pulse] better-sqlite3 is required for SQLite storage. Run: pnpm add better-sqlite3');
|
|
115
|
+
}
|
|
116
|
+
this.db = new Database(this.dbPath);
|
|
117
|
+
this.migrate();
|
|
118
|
+
}
|
|
119
|
+
return this.db;
|
|
120
|
+
}
|
|
121
|
+
migrate() {
|
|
122
|
+
this.db.exec(`
|
|
123
|
+
CREATE TABLE IF NOT EXISTS pulse_aggregates (
|
|
124
|
+
id TEXT PRIMARY KEY,
|
|
125
|
+
bucket TEXT NOT NULL,
|
|
126
|
+
type TEXT NOT NULL,
|
|
127
|
+
key TEXT,
|
|
128
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
129
|
+
sum REAL NOT NULL DEFAULT 0,
|
|
130
|
+
min REAL,
|
|
131
|
+
max REAL,
|
|
132
|
+
created_at TEXT NOT NULL,
|
|
133
|
+
UNIQUE(bucket, type, key)
|
|
134
|
+
);
|
|
135
|
+
CREATE INDEX IF NOT EXISTS idx_pulse_agg_type_bucket ON pulse_aggregates(type, bucket);
|
|
136
|
+
|
|
137
|
+
CREATE TABLE IF NOT EXISTS pulse_entries (
|
|
138
|
+
id TEXT PRIMARY KEY,
|
|
139
|
+
type TEXT NOT NULL,
|
|
140
|
+
content TEXT NOT NULL,
|
|
141
|
+
created_at TEXT NOT NULL
|
|
142
|
+
);
|
|
143
|
+
CREATE INDEX IF NOT EXISTS idx_pulse_entry_type_created ON pulse_entries(type, created_at);
|
|
144
|
+
`);
|
|
145
|
+
}
|
|
146
|
+
record(type, value, key) {
|
|
147
|
+
const bucket = bucketStart(new Date()).toISOString();
|
|
148
|
+
const k = key ?? null;
|
|
149
|
+
const existing = this.getDb().prepare('SELECT id, count, sum, min, max FROM pulse_aggregates WHERE bucket = ? AND type = ? AND key IS ?').get(bucket, type, k);
|
|
150
|
+
if (existing) {
|
|
151
|
+
this.getDb().prepare(`UPDATE pulse_aggregates SET count = count + 1, sum = sum + ?,
|
|
152
|
+
min = CASE WHEN min IS NULL OR ? < min THEN ? ELSE min END,
|
|
153
|
+
max = CASE WHEN max IS NULL OR ? > max THEN ? ELSE max END
|
|
154
|
+
WHERE id = ?`).run(value, value, value, value, value, existing.id);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
this.getDb().prepare(`INSERT INTO pulse_aggregates (id, bucket, type, key, count, sum, min, max, created_at)
|
|
158
|
+
VALUES (?, ?, ?, ?, 1, ?, ?, ?, ?)`).run(randomUUID(), bucket, type, k, value, value, value, new Date().toISOString());
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
storeEntry(type, content) {
|
|
162
|
+
this.getDb().prepare('INSERT INTO pulse_entries (id, type, content, created_at) VALUES (?, ?, ?, ?)').run(randomUUID(), type, JSON.stringify(content), new Date().toISOString());
|
|
163
|
+
}
|
|
164
|
+
aggregates(type, since, key) {
|
|
165
|
+
let sql = 'SELECT * FROM pulse_aggregates WHERE type = ? AND bucket >= ?';
|
|
166
|
+
const params = [type, since.toISOString()];
|
|
167
|
+
if (key !== undefined && key !== null) {
|
|
168
|
+
sql += ' AND key = ?';
|
|
169
|
+
params.push(key);
|
|
170
|
+
}
|
|
171
|
+
sql += ' ORDER BY bucket ASC';
|
|
172
|
+
const rows = this.getDb().prepare(sql).all(...params);
|
|
173
|
+
return rows.map(r => this.aggFromRow(r));
|
|
174
|
+
}
|
|
175
|
+
entries(type, options) {
|
|
176
|
+
const page = options?.page ?? 1;
|
|
177
|
+
const perPage = options?.perPage ?? 50;
|
|
178
|
+
const offset = (page - 1) * perPage;
|
|
179
|
+
let sql = 'SELECT * FROM pulse_entries WHERE type = ?';
|
|
180
|
+
const params = [type];
|
|
181
|
+
if (options?.search) {
|
|
182
|
+
sql += ' AND content LIKE ?';
|
|
183
|
+
params.push(`%${options.search}%`);
|
|
184
|
+
}
|
|
185
|
+
sql += ' ORDER BY created_at DESC LIMIT ? OFFSET ?';
|
|
186
|
+
params.push(perPage, offset);
|
|
187
|
+
const rows = this.getDb().prepare(sql).all(...params);
|
|
188
|
+
return rows.map(r => ({
|
|
189
|
+
id: r['id'],
|
|
190
|
+
type: r['type'],
|
|
191
|
+
content: JSON.parse(r['content']),
|
|
192
|
+
createdAt: new Date(r['created_at']),
|
|
193
|
+
}));
|
|
194
|
+
}
|
|
195
|
+
overview(since) {
|
|
196
|
+
const rows = this.getDb().prepare('SELECT * FROM pulse_aggregates WHERE bucket >= ? ORDER BY bucket ASC').all(since.toISOString());
|
|
197
|
+
return rows.map(r => this.aggFromRow(r));
|
|
198
|
+
}
|
|
199
|
+
pruneOlderThan(date) {
|
|
200
|
+
const iso = date.toISOString();
|
|
201
|
+
const db = this.getDb();
|
|
202
|
+
db.prepare('DELETE FROM pulse_aggregates WHERE bucket < ?').run(iso);
|
|
203
|
+
db.prepare('DELETE FROM pulse_entries WHERE created_at < ?').run(iso);
|
|
204
|
+
}
|
|
205
|
+
aggFromRow(r) {
|
|
206
|
+
return {
|
|
207
|
+
id: r['id'],
|
|
208
|
+
bucket: new Date(r['bucket']),
|
|
209
|
+
type: r['type'],
|
|
210
|
+
key: r['key'] || null,
|
|
211
|
+
count: r['count'],
|
|
212
|
+
sum: r['sum'],
|
|
213
|
+
min: r['min'] ?? null,
|
|
214
|
+
max: r['max'] ?? null,
|
|
215
|
+
createdAt: new Date(r['created_at']),
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
|