pipework 0.95.0 → 0.97.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.
- package/CHANGELOG.md +15 -0
- package/dist/data/migrate/internal-definitions.d.ts.map +1 -1
- package/dist/data/migrate/internal-definitions.js +2 -1
- package/dist/data/migrate/internal-definitions.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/infra/alerts/handle.d.ts +108 -7
- package/dist/infra/alerts/handle.d.ts.map +1 -1
- package/dist/infra/alerts/handle.js +291 -26
- package/dist/infra/alerts/handle.js.map +1 -1
- package/dist/infra/alerts/http.d.ts +19 -0
- package/dist/infra/alerts/http.d.ts.map +1 -0
- package/dist/infra/alerts/http.js +172 -0
- package/dist/infra/alerts/http.js.map +1 -0
- package/dist/infra/alerts/index.d.ts +4 -2
- package/dist/infra/alerts/index.d.ts.map +1 -1
- package/dist/infra/alerts/index.js +1 -0
- package/dist/infra/alerts/index.js.map +1 -1
- package/dist/infra/alerts/namespace.d.ts +3 -0
- package/dist/infra/alerts/namespace.d.ts.map +1 -1
- package/dist/infra/alerts/namespace.js +3 -0
- package/dist/infra/alerts/namespace.js.map +1 -1
- package/dist/infra/alerts/schema.d.ts +91 -5
- package/dist/infra/alerts/schema.d.ts.map +1 -1
- package/dist/infra/alerts/schema.js +29 -3
- package/dist/infra/alerts/schema.js.map +1 -1
- package/dist/infra/alerts/sinks.d.ts +37 -3
- package/dist/infra/alerts/sinks.d.ts.map +1 -1
- package/dist/infra/alerts/sinks.js.map +1 -1
- package/dist/request/http/rate-limit-classes.d.ts.map +1 -1
- package/dist/request/http/rate-limit-classes.js +6 -4
- package/dist/request/http/rate-limit-classes.js.map +1 -1
- package/dist/request/http/types.d.ts +13 -1
- package/dist/request/http/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { createHash, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
import { Builder } from '../../request/di/builder.js';
|
|
3
|
+
import { schema } from '../../data/schema/namespace.js';
|
|
4
|
+
import { PipeworkError, NotFoundError, UnauthorizedError } from '../../core/errors/index.js';
|
|
5
|
+
class BadRequestError extends PipeworkError {
|
|
6
|
+
code = 'BAD_REQUEST';
|
|
7
|
+
httpStatus = 400;
|
|
8
|
+
}
|
|
9
|
+
const STATUSES = ['open', 'acknowledged', 'resolved'];
|
|
10
|
+
const SEVERITIES = ['info', 'warning', 'error', 'critical'];
|
|
11
|
+
const sha = (s) => createHash('sha256').update(s).digest();
|
|
12
|
+
function authenticate(credentials, header) {
|
|
13
|
+
const match = header !== undefined ? /^Bearer (.+)$/.exec(header) : null;
|
|
14
|
+
const given = sha(match?.[1] ?? '');
|
|
15
|
+
let name = null;
|
|
16
|
+
for (const [credName, digest] of credentials) {
|
|
17
|
+
if (timingSafeEqual(given, digest) && match !== null && name === null)
|
|
18
|
+
name = credName;
|
|
19
|
+
}
|
|
20
|
+
if (name === null)
|
|
21
|
+
throw new UnauthorizedError('A valid service credential is required: send Authorization: Bearer <secret>.');
|
|
22
|
+
return name;
|
|
23
|
+
}
|
|
24
|
+
function bad(field, problem) {
|
|
25
|
+
throw new BadRequestError(`Invalid ${field}: ${problem}.`, { field });
|
|
26
|
+
}
|
|
27
|
+
function optString(source, field) {
|
|
28
|
+
const value = source?.[field];
|
|
29
|
+
if (value === undefined)
|
|
30
|
+
return undefined;
|
|
31
|
+
if (typeof value !== 'string')
|
|
32
|
+
bad(field, 'must be a string');
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
function body(raw) {
|
|
36
|
+
if (raw === undefined || raw === null)
|
|
37
|
+
return {};
|
|
38
|
+
if (typeof raw !== 'object' || Array.isArray(raw))
|
|
39
|
+
bad('body', 'must be a JSON object');
|
|
40
|
+
return raw;
|
|
41
|
+
}
|
|
42
|
+
function csv(raw, field, allowed) {
|
|
43
|
+
if (raw === undefined || raw === '')
|
|
44
|
+
return undefined;
|
|
45
|
+
const out = [];
|
|
46
|
+
for (const part of raw.split(',')) {
|
|
47
|
+
if (!allowed.includes(part))
|
|
48
|
+
bad(field, `"${part}" is not one of ${allowed.join(', ')}`);
|
|
49
|
+
out.push(part);
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
function limitOf(raw) {
|
|
54
|
+
if (raw === undefined)
|
|
55
|
+
return undefined;
|
|
56
|
+
if (!/^[1-9][0-9]*$/.test(raw))
|
|
57
|
+
bad('limit', 'must be a positive integer');
|
|
58
|
+
return Number(raw);
|
|
59
|
+
}
|
|
60
|
+
function pageQuery(query) {
|
|
61
|
+
const limit = optString(query, 'limit');
|
|
62
|
+
const cursor = optString(query, 'cursor');
|
|
63
|
+
const out = {};
|
|
64
|
+
const n = limitOf(limit);
|
|
65
|
+
if (n !== undefined)
|
|
66
|
+
out.limit = n;
|
|
67
|
+
if (cursor !== undefined)
|
|
68
|
+
out.cursor = cursor;
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
function validateOptions(options) {
|
|
72
|
+
if (!options.path.startsWith('/') || options.path.length < 2 || options.path.endsWith('/')) {
|
|
73
|
+
throw new Error(`alerts.http: path "${options.path}" must start with "/" and have no trailing slash, e.g. "/ops/alerts".`);
|
|
74
|
+
}
|
|
75
|
+
const entries = Object.entries(options.credentials);
|
|
76
|
+
if (entries.length === 0) {
|
|
77
|
+
throw new Error('alerts.http: credentials needs at least one entry, name -> secret (the secret is at least 32 characters).');
|
|
78
|
+
}
|
|
79
|
+
for (const [name, secret] of entries) {
|
|
80
|
+
if (typeof secret !== 'string' || secret.length < 32) {
|
|
81
|
+
throw new Error(`alerts.http: the secret for credential "${name}" is under 32 characters; use a long random value.`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Routes for an operations agent, under `options.path` (all JSON, no session, no tenant):
|
|
87
|
+
* GET list (`status`, `severity` comma lists, `limit`, `cursor`), GET `/totals`, GET `/health`,
|
|
88
|
+
* GET `/:key` (an alert keyed `totals` or `health` is not reachable here), GET `/:key/occurrences`, and POST `/:key/acknowledge`, `/:key/resolve`, `/:key/link`.
|
|
89
|
+
* `:key` is URL-encoded. Every request needs `Authorization: Bearer <secret>` matching one of
|
|
90
|
+
* `credentials`; the credential's name is the default `by` for acknowledge and resolve.
|
|
91
|
+
* Reads cross tenants (the handle reads through `pipe.system()`). Resolve never notifies:
|
|
92
|
+
* the agent does not hear its own change. Dates are ISO strings. A bad value is 400 naming the field.
|
|
93
|
+
*/
|
|
94
|
+
export function alertsHttp(handle, options) {
|
|
95
|
+
validateOptions(options);
|
|
96
|
+
const credentials = Object.entries(options.credentials).map(([name, secret]) => [name, sha(secret)]);
|
|
97
|
+
const base = options.path;
|
|
98
|
+
const any = schema.check.unknown();
|
|
99
|
+
const get = (path) => new Builder().public().request().query(any).params(any).route('GET', path);
|
|
100
|
+
const post = (path) => new Builder().public().request().query(any).params(any).input(any).route('POST', path);
|
|
101
|
+
// Dates inside the results serialize through JSON.stringify as ISO strings.
|
|
102
|
+
const keyOf = (params) => String(params.key);
|
|
103
|
+
const known = async (key) => {
|
|
104
|
+
if ((await handle.get(key)) === null)
|
|
105
|
+
throw new NotFoundError(`Alert "${key}"`);
|
|
106
|
+
};
|
|
107
|
+
return [
|
|
108
|
+
get(base).fit(async ({ request, query }) => {
|
|
109
|
+
authenticate(credentials, request.headers['authorization']);
|
|
110
|
+
const q = pageQuery(query);
|
|
111
|
+
const status = csv(optString(query, 'status'), 'status', STATUSES);
|
|
112
|
+
const severity = csv(optString(query, 'severity'), 'severity', SEVERITIES);
|
|
113
|
+
if (status !== undefined)
|
|
114
|
+
q.status = status;
|
|
115
|
+
if (severity !== undefined)
|
|
116
|
+
q.severity = severity;
|
|
117
|
+
return handle.list(q);
|
|
118
|
+
}),
|
|
119
|
+
get(`${base}/totals`).fit(async ({ request }) => {
|
|
120
|
+
authenticate(credentials, request.headers['authorization']);
|
|
121
|
+
return handle.totals();
|
|
122
|
+
}),
|
|
123
|
+
get(`${base}/health`).fit(async ({ request }) => {
|
|
124
|
+
authenticate(credentials, request.headers['authorization']);
|
|
125
|
+
return handle.health();
|
|
126
|
+
}),
|
|
127
|
+
get(`${base}/:key`).fit(async ({ request, params }) => {
|
|
128
|
+
authenticate(credentials, request.headers['authorization']);
|
|
129
|
+
const found = await handle.get(keyOf(params));
|
|
130
|
+
if (found === null)
|
|
131
|
+
throw new NotFoundError(`Alert "${keyOf(params)}"`);
|
|
132
|
+
return found;
|
|
133
|
+
}),
|
|
134
|
+
get(`${base}/:key/occurrences`).fit(async ({ request, params, query }) => {
|
|
135
|
+
authenticate(credentials, request.headers['authorization']);
|
|
136
|
+
const page = pageQuery(query);
|
|
137
|
+
await known(keyOf(params));
|
|
138
|
+
return handle.occurrences(keyOf(params), page);
|
|
139
|
+
}),
|
|
140
|
+
post(`${base}/:key/acknowledge`).fit(async ({ request, params, input }) => {
|
|
141
|
+
const name = authenticate(credentials, request.headers['authorization']);
|
|
142
|
+
const b = body(input);
|
|
143
|
+
const by = optString(b, 'by') ?? name;
|
|
144
|
+
const note = optString(b, 'note');
|
|
145
|
+
return { acknowledged: await handle.acknowledge(keyOf(params), note === undefined ? { by } : { by, note }) };
|
|
146
|
+
}),
|
|
147
|
+
post(`${base}/:key/resolve`).fit(async ({ request, params, input }) => {
|
|
148
|
+
const name = authenticate(credentials, request.headers['authorization']);
|
|
149
|
+
const b = body(input);
|
|
150
|
+
const by = optString(b, 'by') ?? name;
|
|
151
|
+
const note = optString(b, 'note');
|
|
152
|
+
const release = optString(b, 'release');
|
|
153
|
+
return {
|
|
154
|
+
resolved: await handle.resolve(keyOf(params), {
|
|
155
|
+
by, notify: false,
|
|
156
|
+
...(note === undefined ? {} : { note }),
|
|
157
|
+
...(release === undefined ? {} : { release }),
|
|
158
|
+
}),
|
|
159
|
+
};
|
|
160
|
+
}),
|
|
161
|
+
post(`${base}/:key/link`).fit(async ({ request, params, input }) => {
|
|
162
|
+
authenticate(credentials, request.headers['authorization']);
|
|
163
|
+
const url = optString(body(input), 'url');
|
|
164
|
+
if (url === undefined)
|
|
165
|
+
bad('url', 'is required');
|
|
166
|
+
if (!/^https?:\/\/[^\s]+$/i.test(url))
|
|
167
|
+
bad('url', 'must be an http or https URL');
|
|
168
|
+
return { linked: await handle.link(keyOf(params), url) };
|
|
169
|
+
}),
|
|
170
|
+
];
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/infra/alerts/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { createAlerts } from './handle.js';
|
|
2
|
-
export type { Alerts, AlertsConfig, Alert, AlertSeverity, AlertSubject, RaiseOptions, DeliveryRow, TickResult, } from './handle.js';
|
|
3
|
-
export type { AlertSink, AlertDelivery, AlertPayload, AlertWebhookConfig, MemoryAlertSink } from './sinks.js';
|
|
2
|
+
export type { Alerts, AlertsConfig, Alert, AlertSeverity, AlertSubject, RaiseOptions, DeliveryRow, TickResult, AlertStatus, JsonValue, AlertOccurrence, Page, AlertTotals, DeliveryHealth, ResolveOptions, } from './handle.js';
|
|
3
|
+
export type { AlertSink, AlertDelivery, AlertPayload, AlertEventPayload, AlertDigestPayload, AlertWebhookConfig, MemoryAlertSink } from './sinks.js';
|
|
4
4
|
export type { AlertSource, AlertCondition } from './sources.js';
|
|
5
|
+
export { alertsHttp } from './http.js';
|
|
6
|
+
export type { AlertsHttpOptions } from './http.js';
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/infra/alerts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,YAAY,EACV,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/infra/alerts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,YAAY,EACV,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAC/F,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,WAAW,EAAE,cAAc,EAAE,cAAc,GAC3F,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACpJ,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/infra/alerts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/infra/alerts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAO1C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA"}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { createAlerts } from './handle.js';
|
|
2
|
+
import { alertsHttp } from './http.js';
|
|
2
3
|
import { webhookSink, memorySink } from './sinks.js';
|
|
3
4
|
import { deadLetterSource, longRunningSource, backlogSource, healthSource } from './sources.js';
|
|
4
5
|
/** Alerts namespace — raise and resolve keyed conditions, grouped, delivered to sinks through an outbox, traced. */
|
|
5
6
|
export declare const alerts: {
|
|
6
7
|
/** Creates an alerts handle. */
|
|
7
8
|
readonly create: typeof createAlerts;
|
|
9
|
+
/** Routes for an operations agent: list, get, totals, delivery health, acknowledge, resolve, link; bearer credentials. */
|
|
10
|
+
readonly http: typeof alertsHttp;
|
|
8
11
|
/** A sink that POSTs the alert as signed JSON to a URL. */
|
|
9
12
|
readonly webhook: typeof webhookSink;
|
|
10
13
|
/** A sink that keeps deliveries in `.delivered`, for tests. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"namespace.d.ts","sourceRoot":"","sources":["../../../src/infra/alerts/namespace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAE/F,oHAAoH;AACpH,eAAO,MAAM,MAAM;IACjB,gCAAgC;;IAEhC,2DAA2D;;IAE3D,+DAA+D;;;QAG7D,4EAA4E;;QAE5E,iFAAiF;;QAEjF,mGAAmG;;QAEnG,yDAAyD;;;CAGnD,CAAA"}
|
|
1
|
+
{"version":3,"file":"namespace.d.ts","sourceRoot":"","sources":["../../../src/infra/alerts/namespace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAE/F,oHAAoH;AACpH,eAAO,MAAM,MAAM;IACjB,gCAAgC;;IAEhC,0HAA0H;;IAE1H,2DAA2D;;IAE3D,+DAA+D;;;QAG7D,4EAA4E;;QAE5E,iFAAiF;;QAEjF,mGAAmG;;QAEnG,yDAAyD;;;CAGnD,CAAA"}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { createAlerts } from './handle.js';
|
|
2
|
+
import { alertsHttp } from './http.js';
|
|
2
3
|
import { webhookSink, memorySink } from './sinks.js';
|
|
3
4
|
import { deadLetterSource, longRunningSource, backlogSource, healthSource } from './sources.js';
|
|
4
5
|
/** Alerts namespace — raise and resolve keyed conditions, grouped, delivered to sinks through an outbox, traced. */
|
|
5
6
|
export const alerts = {
|
|
6
7
|
/** Creates an alerts handle. */
|
|
7
8
|
create: createAlerts,
|
|
9
|
+
/** Routes for an operations agent: list, get, totals, delivery health, acknowledge, resolve, link; bearer credentials. */
|
|
10
|
+
http: alertsHttp,
|
|
8
11
|
/** A sink that POSTs the alert as signed JSON to a URL. */
|
|
9
12
|
webhook: webhookSink,
|
|
10
13
|
/** A sink that keeps deliveries in `.delivered`, for tests. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"namespace.js","sourceRoot":"","sources":["../../../src/infra/alerts/namespace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAE/F,oHAAoH;AACpH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,gCAAgC;IAChC,MAAM,EAAE,YAAY;IACpB,2DAA2D;IAC3D,OAAO,EAAE,WAAW;IACpB,+DAA+D;IAC/D,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE;QACN,4EAA4E;QAC5E,UAAU,EAAE,gBAAgB;QAC5B,iFAAiF;QACjF,WAAW,EAAE,iBAAiB;QAC9B,mGAAmG;QACnG,OAAO,EAAE,aAAa;QACtB,yDAAyD;QACzD,MAAM,EAAE,YAAY;KACrB;CACO,CAAA"}
|
|
1
|
+
{"version":3,"file":"namespace.js","sourceRoot":"","sources":["../../../src/infra/alerts/namespace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAE/F,oHAAoH;AACpH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,gCAAgC;IAChC,MAAM,EAAE,YAAY;IACpB,0HAA0H;IAC1H,IAAI,EAAE,UAAU;IAChB,2DAA2D;IAC3D,OAAO,EAAE,WAAW;IACpB,+DAA+D;IAC/D,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE;QACN,4EAA4E;QAC5E,UAAU,EAAE,gBAAgB;QAC5B,iFAAiF;QACjF,WAAW,EAAE,iBAAiB;QAC9B,mGAAmG;QACnG,OAAO,EAAE,aAAa;QACtB,yDAAyD;QACzD,MAAM,EAAE,YAAY;KACrB;CACO,CAAA"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
export declare const ALERT_STATUSES: readonly ["open", "resolved"];
|
|
1
|
+
export declare const ALERT_STATUSES: readonly ["open", "acknowledged", "resolved"];
|
|
2
2
|
export declare const ALERT_SEVERITIES: readonly ["info", "warning", "error", "critical"];
|
|
3
|
-
export declare const ALERT_DELIVERY_KINDS: readonly ["raise", "repeat", "resolve"];
|
|
3
|
+
export declare const ALERT_DELIVERY_KINDS: readonly ["raise", "repeat", "resolve", "reopen", "digest"];
|
|
4
4
|
export declare const alerts: import("../../data/domain/types.js").DefinedTable<{
|
|
5
5
|
key: import("../../data/domain/types.js").FieldDescriptor<string, {
|
|
6
6
|
primaryKey: true;
|
|
7
7
|
}> & import("../../data/domain/field.js").FieldModifiers<string, {
|
|
8
8
|
primaryKey: true;
|
|
9
9
|
}>;
|
|
10
|
-
status: import("../../data/domain/types.js").FieldDescriptor<"open" | "resolved", {
|
|
10
|
+
status: import("../../data/domain/types.js").FieldDescriptor<"open" | "acknowledged" | "resolved", {
|
|
11
11
|
hasDefault: true;
|
|
12
|
-
}> & import("../../data/domain/field.js").FieldModifiers<"open" | "resolved", {
|
|
12
|
+
}> & import("../../data/domain/field.js").FieldModifiers<"open" | "acknowledged" | "resolved", {
|
|
13
13
|
hasDefault: true;
|
|
14
14
|
}>;
|
|
15
15
|
severity: import("../../data/domain/types.js").FieldDescriptor<"error" | "info" | "warning" | "critical", {}> & import("../../data/domain/field.js").FieldModifiers<"error" | "info" | "warning" | "critical", {}>;
|
|
@@ -19,6 +19,21 @@ export declare const alerts: import("../../data/domain/types.js").DefinedTable<{
|
|
|
19
19
|
}> & import("../../data/domain/field.js").FieldModifiers<import("zod/v4").JSONType, {
|
|
20
20
|
nullable: true;
|
|
21
21
|
}>;
|
|
22
|
+
owner: import("../../data/domain/types.js").FieldDescriptor<string | null, {
|
|
23
|
+
nullable: true;
|
|
24
|
+
}> & import("../../data/domain/field.js").FieldModifiers<string | null, {
|
|
25
|
+
nullable: true;
|
|
26
|
+
}>;
|
|
27
|
+
runbook: import("../../data/domain/types.js").FieldDescriptor<string | null, {
|
|
28
|
+
nullable: true;
|
|
29
|
+
}> & import("../../data/domain/field.js").FieldModifiers<string | null, {
|
|
30
|
+
nullable: true;
|
|
31
|
+
}>;
|
|
32
|
+
context: import("../../data/domain/types.js").FieldDescriptor<import("zod/v4").JSONType, {
|
|
33
|
+
nullable: true;
|
|
34
|
+
}> & import("../../data/domain/field.js").FieldModifiers<import("zod/v4").JSONType, {
|
|
35
|
+
nullable: true;
|
|
36
|
+
}>;
|
|
22
37
|
count: import("../../data/domain/types.js").FieldDescriptor<number, {
|
|
23
38
|
hasDefault: true;
|
|
24
39
|
}> & import("../../data/domain/field.js").FieldModifiers<number, {
|
|
@@ -44,6 +59,46 @@ export declare const alerts: import("../../data/domain/types.js").DefinedTable<{
|
|
|
44
59
|
}> & import("../../data/domain/field.js").FieldModifiers<Date | null, {
|
|
45
60
|
nullable: true;
|
|
46
61
|
}>;
|
|
62
|
+
reopenCount: import("../../data/domain/types.js").FieldDescriptor<number, {
|
|
63
|
+
hasDefault: true;
|
|
64
|
+
}> & import("../../data/domain/field.js").FieldModifiers<number, {
|
|
65
|
+
hasDefault: true;
|
|
66
|
+
}>;
|
|
67
|
+
reopenedAt: import("../../data/domain/types.js").FieldDescriptor<Date | null, {
|
|
68
|
+
nullable: true;
|
|
69
|
+
}> & import("../../data/domain/field.js").FieldModifiers<Date | null, {
|
|
70
|
+
nullable: true;
|
|
71
|
+
}>;
|
|
72
|
+
acknowledgedAt: import("../../data/domain/types.js").FieldDescriptor<Date | null, {
|
|
73
|
+
nullable: true;
|
|
74
|
+
}> & import("../../data/domain/field.js").FieldModifiers<Date | null, {
|
|
75
|
+
nullable: true;
|
|
76
|
+
}>;
|
|
77
|
+
acknowledgedBy: import("../../data/domain/types.js").FieldDescriptor<string | null, {
|
|
78
|
+
nullable: true;
|
|
79
|
+
}> & import("../../data/domain/field.js").FieldModifiers<string | null, {
|
|
80
|
+
nullable: true;
|
|
81
|
+
}>;
|
|
82
|
+
resolvedBy: import("../../data/domain/types.js").FieldDescriptor<string | null, {
|
|
83
|
+
nullable: true;
|
|
84
|
+
}> & import("../../data/domain/field.js").FieldModifiers<string | null, {
|
|
85
|
+
nullable: true;
|
|
86
|
+
}>;
|
|
87
|
+
resolveNote: import("../../data/domain/types.js").FieldDescriptor<string | null, {
|
|
88
|
+
nullable: true;
|
|
89
|
+
}> & import("../../data/domain/field.js").FieldModifiers<string | null, {
|
|
90
|
+
nullable: true;
|
|
91
|
+
}>;
|
|
92
|
+
resolvedRelease: import("../../data/domain/types.js").FieldDescriptor<string | null, {
|
|
93
|
+
nullable: true;
|
|
94
|
+
}> & import("../../data/domain/field.js").FieldModifiers<string | null, {
|
|
95
|
+
nullable: true;
|
|
96
|
+
}>;
|
|
97
|
+
issueUrl: import("../../data/domain/types.js").FieldDescriptor<string | null, {
|
|
98
|
+
nullable: true;
|
|
99
|
+
}> & import("../../data/domain/field.js").FieldModifiers<string | null, {
|
|
100
|
+
nullable: true;
|
|
101
|
+
}>;
|
|
47
102
|
traceIds: import("../../data/domain/types.js").FieldDescriptor<string[], {
|
|
48
103
|
hasDefault: true;
|
|
49
104
|
}> & import("../../data/domain/field.js").FieldModifiers<string[], {
|
|
@@ -65,6 +120,37 @@ export declare const alerts: import("../../data/domain/types.js").DefinedTable<{
|
|
|
65
120
|
hasDefault: true;
|
|
66
121
|
}>;
|
|
67
122
|
}, "pipework_alerts">;
|
|
123
|
+
export declare const alertOccurrences: import("../../data/domain/types.js").DefinedTable<{
|
|
124
|
+
id: import("../../data/domain/types.js").FieldDescriptor<string, {
|
|
125
|
+
defaultRandom: true;
|
|
126
|
+
hasDefault: true;
|
|
127
|
+
} & {
|
|
128
|
+
primaryKey: true;
|
|
129
|
+
}> & import("../../data/domain/field.js").FieldModifiers<string, {
|
|
130
|
+
defaultRandom: true;
|
|
131
|
+
hasDefault: true;
|
|
132
|
+
} & {
|
|
133
|
+
primaryKey: true;
|
|
134
|
+
}>;
|
|
135
|
+
alertKey: import("../../data/domain/types.js").FieldDescriptor<string, {}> & import("../../data/domain/field.js").FieldModifiers<string, {}>;
|
|
136
|
+
at: import("../../data/domain/types.js").FieldDescriptor<Date, {
|
|
137
|
+
hasDefault: true;
|
|
138
|
+
}> & import("../../data/domain/field.js").FieldModifiers<Date, {
|
|
139
|
+
hasDefault: true;
|
|
140
|
+
}>;
|
|
141
|
+
severity: import("../../data/domain/types.js").FieldDescriptor<"error" | "info" | "warning" | "critical", {}> & import("../../data/domain/field.js").FieldModifiers<"error" | "info" | "warning" | "critical", {}>;
|
|
142
|
+
message: import("../../data/domain/types.js").FieldDescriptor<string, {}> & import("../../data/domain/field.js").FieldModifiers<string, {}>;
|
|
143
|
+
context: import("../../data/domain/types.js").FieldDescriptor<import("zod/v4").JSONType, {
|
|
144
|
+
nullable: true;
|
|
145
|
+
}> & import("../../data/domain/field.js").FieldModifiers<import("zod/v4").JSONType, {
|
|
146
|
+
nullable: true;
|
|
147
|
+
}>;
|
|
148
|
+
traceId: import("../../data/domain/types.js").FieldDescriptor<string | null, {
|
|
149
|
+
nullable: true;
|
|
150
|
+
}> & import("../../data/domain/field.js").FieldModifiers<string | null, {
|
|
151
|
+
nullable: true;
|
|
152
|
+
}>;
|
|
153
|
+
}, "pipework_alert_occurrences">;
|
|
68
154
|
export declare const alertDeliveries: import("../../data/domain/types.js").DefinedTable<{
|
|
69
155
|
id: import("../../data/domain/types.js").FieldDescriptor<string, {
|
|
70
156
|
defaultRandom: true;
|
|
@@ -78,7 +164,7 @@ export declare const alertDeliveries: import("../../data/domain/types.js").Defin
|
|
|
78
164
|
primaryKey: true;
|
|
79
165
|
}>;
|
|
80
166
|
alertKey: import("../../data/domain/types.js").FieldDescriptor<string, {}> & import("../../data/domain/field.js").FieldModifiers<string, {}>;
|
|
81
|
-
kind: import("../../data/domain/types.js").FieldDescriptor<"repeat" | "raise" | "resolve", {}> & import("../../data/domain/field.js").FieldModifiers<"repeat" | "raise" | "resolve", {}>;
|
|
167
|
+
kind: import("../../data/domain/types.js").FieldDescriptor<"repeat" | "raise" | "resolve" | "reopen" | "digest", {}> & import("../../data/domain/field.js").FieldModifiers<"repeat" | "raise" | "resolve" | "reopen" | "digest", {}>;
|
|
82
168
|
sink: import("../../data/domain/types.js").FieldDescriptor<string, {}> & import("../../data/domain/field.js").FieldModifiers<string, {}>;
|
|
83
169
|
payload: import("../../data/domain/types.js").FieldDescriptor<import("zod/v4").JSONType, {}> & import("../../data/domain/field.js").FieldModifiers<import("zod/v4").JSONType, {}>;
|
|
84
170
|
attempts: import("../../data/domain/types.js").FieldDescriptor<number, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/infra/alerts/schema.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,cAAc,+
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/infra/alerts/schema.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,cAAc,+CAAgD,CAAA;AAC3E,eAAO,MAAM,gBAAgB,mDAAoD,CAAA;AACjF,eAAO,MAAM,oBAAoB,6DAA8D,CAAA;AAE/F,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA8BjB,CAAA;AAGF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAa3B,CAAA;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAmB1B,CAAA;AAEF,eAAO,MAAM,gBAAgB;;;;;;;iCAG3B,CAAA"}
|
|
@@ -1,24 +1,35 @@
|
|
|
1
|
-
// The tables behind alerts: one row per alert key, the outbox of deliveries (one row per
|
|
1
|
+
// The tables behind alerts: one row per alert key, one per raise (occurrences), the outbox of deliveries (one row per
|
|
2
2
|
// event and sink), and the cursor a source keeps between evaluations. Not tenant-scoped.
|
|
3
3
|
import { define } from '../../data/domain/index.js';
|
|
4
4
|
import { field } from '../../data/domain/field.js';
|
|
5
5
|
import { schema } from '../../data/schema/namespace.js';
|
|
6
6
|
import { index } from '../../data/db/idx/index.js';
|
|
7
7
|
import { sql } from '../../data/db/sql.js';
|
|
8
|
-
export const ALERT_STATUSES = ['open', 'resolved'];
|
|
8
|
+
export const ALERT_STATUSES = ['open', 'acknowledged', 'resolved'];
|
|
9
9
|
export const ALERT_SEVERITIES = ['info', 'warning', 'error', 'critical'];
|
|
10
|
-
export const ALERT_DELIVERY_KINDS = ['raise', 'repeat', 'resolve'];
|
|
10
|
+
export const ALERT_DELIVERY_KINDS = ['raise', 'repeat', 'resolve', 'reopen', 'digest'];
|
|
11
11
|
export const alerts = define('pipework_alerts', {
|
|
12
12
|
key: field.text().primaryKey(),
|
|
13
13
|
status: field.enum(ALERT_STATUSES).default('open'),
|
|
14
14
|
severity: field.enum(ALERT_SEVERITIES),
|
|
15
15
|
message: field.text(),
|
|
16
16
|
subject: field.jsonb(schema.check.json()).nullable(),
|
|
17
|
+
owner: field.text().nullable(),
|
|
18
|
+
runbook: field.text().nullable(),
|
|
19
|
+
context: field.jsonb(schema.check.json()).nullable(),
|
|
17
20
|
count: field.integer().default(1),
|
|
18
21
|
firstSeenAt: field.timestamp().default('now'),
|
|
19
22
|
lastSeenAt: field.timestamp().default('now'),
|
|
20
23
|
lastSentAt: field.timestamp().nullable(),
|
|
21
24
|
resolvedAt: field.timestamp().nullable(),
|
|
25
|
+
reopenCount: field.integer().default(0),
|
|
26
|
+
reopenedAt: field.timestamp().nullable(),
|
|
27
|
+
acknowledgedAt: field.timestamp().nullable(),
|
|
28
|
+
acknowledgedBy: field.text().nullable(),
|
|
29
|
+
resolvedBy: field.text().nullable(),
|
|
30
|
+
resolveNote: field.text().nullable(),
|
|
31
|
+
resolvedRelease: field.text().nullable(),
|
|
32
|
+
issueUrl: field.text().nullable(),
|
|
22
33
|
traceIds: field.custom(schema.col.text('trace_ids').array(), schema.check.array(schema.check.string())).default('{}'),
|
|
23
34
|
resendAfterMs: field.integer().nullable(),
|
|
24
35
|
resolveAfterQuietMs: field.integer().nullable(),
|
|
@@ -28,6 +39,21 @@ export const alerts = define('pipework_alerts', {
|
|
|
28
39
|
byStatus: index('idx_pipework_alerts_status').on(t['status']),
|
|
29
40
|
}),
|
|
30
41
|
});
|
|
42
|
+
// One row per raise, kept for `occurrenceRetentionMs`.
|
|
43
|
+
export const alertOccurrences = define('pipework_alert_occurrences', {
|
|
44
|
+
id: field.uuid().defaultRandom().primaryKey(),
|
|
45
|
+
alertKey: field.text(),
|
|
46
|
+
at: field.timestamp().default('now'),
|
|
47
|
+
severity: field.enum(ALERT_SEVERITIES),
|
|
48
|
+
message: field.text(),
|
|
49
|
+
context: field.jsonb(schema.check.json()).nullable(),
|
|
50
|
+
traceId: field.text().nullable(),
|
|
51
|
+
}, {
|
|
52
|
+
indexes: (t) => ({
|
|
53
|
+
byKey: index('idx_pipework_alert_occurrences_key').on(t['alertKey'], t['at'], t['id']),
|
|
54
|
+
byAt: index('idx_pipework_alert_occurrences_at').on(t['at']),
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
31
57
|
export const alertDeliveries = define('pipework_alert_deliveries', {
|
|
32
58
|
id: field.uuid().defaultRandom().primaryKey(),
|
|
33
59
|
alertKey: field.text(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/infra/alerts/schema.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/infra/alerts/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { WebhookSignatureOptions } from '../webhook/sign.js';
|
|
2
2
|
import type { Sink, SinkDelivery } from '../outbox/core.js';
|
|
3
|
-
/**
|
|
4
|
-
export interface
|
|
5
|
-
readonly kind: 'raise' | 'repeat' | 'resolve';
|
|
3
|
+
/** One alert's event, delivered at once. */
|
|
4
|
+
export interface AlertEventPayload {
|
|
5
|
+
readonly kind: 'raise' | 'repeat' | 'resolve' | 'reopen';
|
|
6
6
|
readonly key: string;
|
|
7
7
|
readonly severity: 'info' | 'warning' | 'error' | 'critical';
|
|
8
8
|
readonly message: string;
|
|
@@ -11,13 +11,47 @@ export interface AlertPayload {
|
|
|
11
11
|
readonly entity?: string;
|
|
12
12
|
readonly entityId?: string;
|
|
13
13
|
} | null;
|
|
14
|
+
readonly owner: string | null;
|
|
15
|
+
readonly runbook: string | null;
|
|
16
|
+
readonly context: Readonly<Record<string, unknown>> | null;
|
|
14
17
|
readonly count: number;
|
|
18
|
+
/** Times a raise came after a resolve. */
|
|
19
|
+
readonly reopenCount: number;
|
|
15
20
|
readonly firstSeenAt: string;
|
|
16
21
|
readonly lastSeenAt: string;
|
|
17
22
|
readonly resolvedAt: string | null;
|
|
23
|
+
readonly acknowledgedAt: string | null;
|
|
24
|
+
readonly acknowledgedBy: string | null;
|
|
25
|
+
/** On a `reopen`, those of the resolve it reopens. */
|
|
26
|
+
readonly resolvedBy: string | null;
|
|
27
|
+
readonly resolveNote: string | null;
|
|
28
|
+
readonly resolvedRelease: string | null;
|
|
29
|
+
readonly issueUrl: string | null;
|
|
30
|
+
readonly environment: string;
|
|
18
31
|
/** The latest traces that raised it, newest first. */
|
|
19
32
|
readonly traceIds: readonly string[];
|
|
20
33
|
}
|
|
34
|
+
/** The alerts of the digest severities that changed in one window, sent once per sink. */
|
|
35
|
+
export interface AlertDigestPayload {
|
|
36
|
+
readonly kind: 'digest';
|
|
37
|
+
readonly key: 'pipework.alerts.digest';
|
|
38
|
+
readonly environment: string;
|
|
39
|
+
/** The previous digest's time; null on the first. */
|
|
40
|
+
readonly since: string | null;
|
|
41
|
+
readonly until: string;
|
|
42
|
+
readonly alerts: readonly {
|
|
43
|
+
readonly key: string;
|
|
44
|
+
readonly severity: 'info' | 'warning' | 'error' | 'critical';
|
|
45
|
+
readonly status: 'open' | 'acknowledged' | 'resolved';
|
|
46
|
+
readonly message: string;
|
|
47
|
+
readonly owner: string | null;
|
|
48
|
+
readonly count: number;
|
|
49
|
+
readonly reopenCount: number;
|
|
50
|
+
readonly lastSeenAt: string;
|
|
51
|
+
}[];
|
|
52
|
+
}
|
|
53
|
+
/** What a sink receives, and what the webhook sink POSTs as its body; tell them apart by `kind`. */
|
|
54
|
+
export type AlertPayload = AlertEventPayload | AlertDigestPayload;
|
|
21
55
|
export type AlertDelivery = SinkDelivery<AlertPayload>;
|
|
22
56
|
/** A place alerts are sent; see `Sink`. */
|
|
23
57
|
export type AlertSink = Sink<AlertPayload>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sinks.d.ts","sourceRoot":"","sources":["../../../src/infra/alerts/sinks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAA;AACjE,OAAO,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAE3D,
|
|
1
|
+
{"version":3,"file":"sinks.d.ts","sourceRoot":"","sources":["../../../src/infra/alerts/sinks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAA;AACjE,OAAO,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAE3D,4CAA4C;AAC5C,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAA;IACxD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,CAAA;IAC5D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC7G,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,CAAA;IAC1D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,0CAA0C;IAC1C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IACtC,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IACtC,sDAAsD;IACtD,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,sDAAsD;IACtD,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CACrC;AAED,0FAA0F;AAC1F,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;IACvB,QAAQ,CAAC,GAAG,EAAE,wBAAwB,CAAA;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS;QACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;QACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,CAAA;QAC5D,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,UAAU,CAAA;QACrD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;QAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;QACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;QAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;KAC5B,EAAE,CAAA;CACJ;AAED,oGAAoG;AACpG,MAAM,MAAM,YAAY,GAAG,iBAAiB,GAAG,kBAAkB,CAAA;AAEjE,MAAM,MAAM,aAAa,GAAG,YAAY,CAAC,YAAY,CAAC,CAAA;AAEtD,2CAA2C;AAC3C,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,CAAA;AAE1C,MAAM,WAAW,kBAAkB;IACjC,mFAAmF;IACnF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,kHAAkH;IAClH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,uBAAuB,CAAA;CAC3C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,EAAE,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAAC,CAAC,CAAC,CA8BnH;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,CAAE,SAAQ,IAAI,CAAC,CAAC,CAAC;IAClG,yCAAyC;IACzC,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAA;IACrC,KAAK,IAAI,IAAI,CAAA;CACd;AAED,+LAA+L;AAC/L,wBAAgB,UAAU,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,EAAE,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,eAAe,CAAC,CAAC,CAAC,CAAA;AAC/H,wBAAgB,UAAU,CAAC,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,eAAe,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sinks.js","sourceRoot":"","sources":["../../../src/infra/alerts/sinks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"sinks.js","sourceRoot":"","sources":["../../../src/infra/alerts/sinks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAsEhD;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAqD,MAA0B;IACxG,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,MAAM,CAAA;IAC5C,IAAI,SAAS,GAAG,MAAM,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,wCAAwC,MAAM,CAAC,SAAS,CAAC,kHAAkH,CAAC,CAAA;IAC9L,CAAC;IACD,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,SAAS;QAC9B,KAAK,CAAC,IAAI,CAAC,QAAQ;YACjB,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,GAAG,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAA;YAC1G,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;YACxC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAA;YAC7D,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE;oBACvC,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE;wBACP,cAAc,EAAE,kBAAkB;wBAClC,cAAc,EAAE,MAAM,CAAC,SAAS;wBAChC,qBAAqB,EAAE,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE;wBAClD,qBAAqB,EAAE,MAAM,CAAC,SAAS;qBACxC;oBACD,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,MAAM,EAAE,UAAU,CAAC,MAAM;iBAC1B,CAAC,CAAA;gBACF,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAA;gBACrC,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG;oBAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YAC1H,CAAC;oBAAS,CAAC;gBACT,YAAY,CAAC,KAAK,CAAC,CAAA;YACrB,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC;AAWD,MAAM,UAAU,UAAU,CAAC,UAA6B,EAAE;IACxD,MAAM,SAAS,GAA8C,EAAE,CAAA;IAC/D,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,QAAQ;QAC9B,SAAS;QACT,0FAA0F;QAC1F,KAAK,CAAC,IAAI,CAAC,QAAQ,IAAI,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA,CAAC,CAAC;QACjD,KAAK,KAAK,SAAS,CAAC,MAAM,GAAG,CAAC,CAAA,CAAC,CAAC;KACjC,CAAA;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit-classes.d.ts","sourceRoot":"","sources":["../../../src/request/http/rate-limit-classes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"rate-limit-classes.d.ts","sourceRoot":"","sources":["../../../src/request/http/rate-limit-classes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAO/C,OAAO,KAAK,EAAE,sBAAsB,EAAyC,MAAM,YAAY,CAAA;AAG/F,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;gCAI1B,CAAA;AAKF,MAAM,WAAW,gBAAgB;IAC/B,sFAAsF;IACtF,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAAA;IACjE,qFAAqF;IACrF,KAAK,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAChH;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,sBAAsB,GAAG,gBAAgB,CA2G3G"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { runInContext } from '../context/store.js';
|
|
1
2
|
import { sql } from '../../data/db/sql.js';
|
|
2
3
|
import { define } from '../../data/domain/index.js';
|
|
3
4
|
import { field } from '../../data/domain/field.js';
|
|
@@ -53,12 +54,12 @@ export function createRateLimitClasses(instance, config) {
|
|
|
53
54
|
void Promise.resolve(db.execute(sql `DELETE FROM pipework_rate_limit_counts WHERE window_start < now() - ${longest}::int * interval '1 second'`))
|
|
54
55
|
.catch((error) => req.log.error(error, 'Rate limit cleanup failed'));
|
|
55
56
|
}
|
|
56
|
-
function report(req, event) {
|
|
57
|
+
function report(req, ctx, event) {
|
|
57
58
|
const hook = config.onRefused;
|
|
58
59
|
if (hook === undefined)
|
|
59
60
|
return;
|
|
60
61
|
try {
|
|
61
|
-
const result = hook(event);
|
|
62
|
+
const result = runInContext(ctx, () => hook(event));
|
|
62
63
|
if (result !== undefined && typeof result.catch === 'function') {
|
|
63
64
|
;
|
|
64
65
|
result.catch((error) => req.log.error(error, 'rateLimits.onRefused threw'));
|
|
@@ -102,7 +103,8 @@ export function createRateLimitClasses(instance, config) {
|
|
|
102
103
|
const got = await count(db, `${resolved.name}:${limit}:${value}`, win.windowSeconds);
|
|
103
104
|
if (got.count > win.max) {
|
|
104
105
|
refused.push({
|
|
105
|
-
class: resolved.name, limit, key: value,
|
|
106
|
+
class: resolved.name, limit, key: value, tenantId: ctx.tenant ?? null, userId,
|
|
107
|
+
requestId: ctx.requestId, traceId: ctx.trace?.id ?? null, count: got.count, max: win.max,
|
|
106
108
|
windowSeconds: win.windowSeconds, retryAfterSeconds: got.retryAfter, route,
|
|
107
109
|
});
|
|
108
110
|
// A refused request is not counted against the wider windows: one user over
|
|
@@ -114,7 +116,7 @@ export function createRateLimitClasses(instance, config) {
|
|
|
114
116
|
if (refused.length === 0)
|
|
115
117
|
return;
|
|
116
118
|
for (const event of refused)
|
|
117
|
-
report(req, event);
|
|
119
|
+
report(req, ctx, event);
|
|
118
120
|
throw new TooManyRequestsError(Math.max(...refused.map((e) => e.retryAfterSeconds)));
|
|
119
121
|
},
|
|
120
122
|
};
|