@stratusagent/gateway 0.13.7 → 0.14.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.
@@ -0,0 +1,159 @@
1
+ import { type EventIngestResult, type JsonObject } from '@stratusagent/core';
2
+ import { type EventFilter, type InboundEvent } from '@stratusagent/agents';
3
+ import type { EventSourceConfig } from '@stratusagent/state';
4
+ import { type EventSourceActivity, type SqliteEventStore } from './events.ts';
5
+ export type { EventSourceConfig };
6
+ /** A trigger as matching sees it: the schedule's id, its agent, and its event cadence's source and filter. */
7
+ export interface EventTrigger {
8
+ triggerId: string;
9
+ agentId: string;
10
+ source: string;
11
+ filter: EventFilter;
12
+ }
13
+ export interface EventIntakeRequest {
14
+ /** The `<source>` in `/events/<source>`. */
15
+ sourceId: string;
16
+ /** As node:http gives them: lowercase names. */
17
+ headers: Readonly<Record<string, string | string[] | undefined>>;
18
+ /** The raw body, read no further than one byte past `maxBodyBytes`. */
19
+ body: Buffer;
20
+ }
21
+ export interface EventIntakeResponse {
22
+ status: number;
23
+ body: JsonObject;
24
+ }
25
+ export interface EventSourceCounters {
26
+ tooLarge: number;
27
+ badSignature: number;
28
+ rateLimited: number;
29
+ notReady: number;
30
+ lastRefusal?: {
31
+ at: string;
32
+ reason: string;
33
+ };
34
+ }
35
+ export interface EventIntakeCounters {
36
+ /** Requests to a path no source is configured for, all paths together. */
37
+ unknownSource: number;
38
+ /** Per configured source: requests refused before they could leave a row. */
39
+ sources: Record<string, EventSourceCounters>;
40
+ }
41
+ /** One configured source in the events summary (`stratus events`, `/health`). */
42
+ export interface EventSourceSummary extends Omit<EventSourceActivity, 'lastRefused'> {
43
+ /** The plugin that feeds this source, for one a plugin declared rather than the config. */
44
+ plugin?: string;
45
+ /** Requests refused before they could leave a row, since this daemon started. */
46
+ refusedBeforeRow: Omit<EventSourceCounters, 'lastRefusal'>;
47
+ /** The newest refusal of any kind: a refused row, or one this daemon refused before a row. */
48
+ lastRefusal?: {
49
+ at: string;
50
+ reason: string;
51
+ };
52
+ }
53
+ export interface EventsSummary {
54
+ /** Where the row counts start: 24 hours before the summary. */
55
+ since: string;
56
+ /** Every configured source, with or without activity. */
57
+ sources: Record<string, EventSourceSummary>;
58
+ /** Requests to a path no source is configured for, since this daemon started. */
59
+ unknownSource: number;
60
+ }
61
+ /**
62
+ * The rows' view (it survives restarts) and the listener's counters (they
63
+ * hold what never got a row) as one answer per configured source.
64
+ */
65
+ export declare const summarizeEvents: (input: {
66
+ sourceIds: readonly string[];
67
+ /** Plugin sources: source id to the package that feeds it. */
68
+ plugins?: Readonly<Record<string, string>>;
69
+ since: string;
70
+ activity: Readonly<Record<string, EventSourceActivity>>;
71
+ counters: EventIntakeCounters;
72
+ }) => EventsSummary;
73
+ export interface EventIntakeOptions {
74
+ store: Pick<SqliteEventStore, 'accept' | 'refuse'>;
75
+ /** The configured sources, read per request. */
76
+ sources(): Readonly<Record<string, EventSourceConfig>>;
77
+ /**
78
+ * The sources plugins feed through `ingest` (card 590 phase 2), read per
79
+ * event. Never served over HTTP: they have no secret to check a request
80
+ * against. Default none.
81
+ */
82
+ pluginSources?(): readonly string[];
83
+ /**
84
+ * A stored credential's value by name, or undefined when it is not set.
85
+ * Asked per request, so `stratus credential set` takes effect on the next
86
+ * delivery, with no restart.
87
+ */
88
+ secret(name: string): Promise<string | undefined>;
89
+ /** The event triggers on a source, read per delivery. Empty until triggers exist. */
90
+ triggers(sourceId: string): readonly EventTrigger[];
91
+ maxBodyBytes?: number;
92
+ now?(): Date;
93
+ warn(line: string): void;
94
+ }
95
+ export interface EventIntake {
96
+ receive(request: EventIntakeRequest): Promise<EventIntakeResponse>;
97
+ /**
98
+ * One event a plugin source fed (card 590 phase 2), under the same size
99
+ * limit, per-source rate, dedup, rule filter and firings as a signed
100
+ * delivery, with no signature to check: the plugin is code the operator
101
+ * installed, and the loader held it to the sources its manifest declares.
102
+ * Throws a sentence naming the reason for anything refused.
103
+ */
104
+ ingest(sourceId: string, event: JsonObject): EventIngestResult;
105
+ counters(): EventIntakeCounters;
106
+ }
107
+ export declare const DEFAULT_EVENT_MAX_BODY_BYTES = 1048576;
108
+ /** Signed requests a source may make in any minute before it hears 429. */
109
+ export declare const EVENT_SOURCE_REQUESTS_PER_MINUTE = 120;
110
+ /**
111
+ * Standard Webhooks 1.0 symmetric verification: `v1,<base64 HMAC-SHA256 of
112
+ * "id.timestamp.body">` keyed with the base64 secret (the `whsec_` prefix is
113
+ * optional). The header may carry several space-separated signatures, and any
114
+ * one valid `v1` under any one secret passes, which is how a sender rotates
115
+ * keys. Does not check the timestamp's age; the intake does.
116
+ */
117
+ export declare const verifyStandardWebhookSignature: (input: {
118
+ id: string;
119
+ timestamp: string;
120
+ body: Buffer;
121
+ signature: string | undefined;
122
+ }, secrets: readonly string[]) => boolean;
123
+ /** GitHub's `X-Hub-Signature-256: sha256=<hex HMAC-SHA256 of the raw body>`, keyed with the secret as text. */
124
+ export declare const verifyGithubSignature: (input: {
125
+ body: Buffer;
126
+ signature: string | undefined;
127
+ }, secrets: readonly string[]) => boolean;
128
+ /**
129
+ * A Standard Webhooks body as an event. A structured CloudEvent (it has
130
+ * `specversion`) keeps its attributes, and its `id` must be the `webhook-id`
131
+ * it was signed under, or one signed delivery could be replayed as another
132
+ * event. A plain `{ type, timestamp?, data? }` payload takes its id from
133
+ * `webhook-id` and its source from the configured source. Extension
134
+ * attributes keep only valid names with scalar values, as strings; anything
135
+ * else is dropped, not refused. An empty `webhook-id` and `data_base64` are
136
+ * refused: one would make every such delivery share a dedup key, the other
137
+ * would arrive with its payload gone.
138
+ */
139
+ export declare const parseStandardWebhookEvent: (input: {
140
+ sourceId: string;
141
+ webhookId: string;
142
+ body: Buffer | string;
143
+ }) => InboundEvent;
144
+ /**
145
+ * A GitHub webhook delivery as a CloudEvent. The subject is `pull/<n>` for
146
+ * anything on a PR, an issue comment on a PR included, so a review and a
147
+ * comment on one PR share a session; `issues/<n>` for an issue. `actor` is
148
+ * who acted, `author` who owns the PR or issue: what a trigger names to wake
149
+ * only the PR's owner. GitHub sends no event time, so `time` is when it
150
+ * arrived.
151
+ */
152
+ export declare const mapGithubDelivery: (input: {
153
+ event: string;
154
+ delivery: string;
155
+ payload: unknown;
156
+ receivedAt: string;
157
+ }) => InboundEvent;
158
+ export declare const createEventIntake: (options: EventIntakeOptions) => EventIntake;
159
+ //# sourceMappingURL=event-intake.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-intake.d.ts","sourceRoot":"","sources":["../src/event-intake.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,445 @@
1
+ import { createHmac, timingSafeEqual } from 'node:crypto';
2
+ import { escapeControlCharacters } from '@stratusagent/core';
3
+ import { matchesEventFilter } from '@stratusagent/agents';
4
+ import { eventCoalescingKey, eventDispatchKey, eventSessionId, renderEventBlock, } from "./events.js";
5
+ /**
6
+ * The rows' view (it survives restarts) and the listener's counters (they
7
+ * hold what never got a row) as one answer per configured source.
8
+ */
9
+ export const summarizeEvents = (input) => ({
10
+ since: input.since,
11
+ unknownSource: input.counters.unknownSource,
12
+ sources: Object.fromEntries(input.sourceIds.map((sourceId) => {
13
+ const { lastRefused, ...rows } = input.activity[sourceId] ?? { deliveries: {}, firings: {} };
14
+ const { lastRefusal: counted, ...refusedBeforeRow } = input.counters.sources[sourceId]
15
+ ?? { tooLarge: 0, badSignature: 0, rateLimited: 0, notReady: 0 };
16
+ // ISO instants compare as strings.
17
+ const lastRefusal = lastRefused !== undefined && (counted === undefined || lastRefused.at > counted.at) ? lastRefused : counted;
18
+ const plugin = input.plugins !== undefined && Object.hasOwn(input.plugins, sourceId) ? input.plugins[sourceId] : undefined;
19
+ return [sourceId, {
20
+ ...(plugin !== undefined ? { plugin } : {}),
21
+ ...rows,
22
+ refusedBeforeRow,
23
+ ...(lastRefusal !== undefined ? { lastRefusal: { ...lastRefusal } } : {}),
24
+ }];
25
+ })),
26
+ });
27
+ export const DEFAULT_EVENT_MAX_BODY_BYTES = 1_048_576;
28
+ /** Signed requests a source may make in any minute before it hears 429. */
29
+ export const EVENT_SOURCE_REQUESTS_PER_MINUTE = 120;
30
+ /** How far a Standard Webhooks timestamp may be from our clock: the replay window. */
31
+ const TIMESTAMP_TOLERANCE_MS = 5 * 60 * 1_000;
32
+ /** A refusal is warned in the daemon log at most this often per source. */
33
+ const REFUSAL_WARN_INTERVAL_MS = 10 * 60 * 1_000;
34
+ const headerOf = (headers, name) => {
35
+ const value = headers[name];
36
+ return Array.isArray(value) ? value.join(', ') : value;
37
+ };
38
+ const constantTimeEqual = (a, b) => a.length === b.length && timingSafeEqual(a, b);
39
+ /**
40
+ * Standard Webhooks 1.0 symmetric verification: `v1,<base64 HMAC-SHA256 of
41
+ * "id.timestamp.body">` keyed with the base64 secret (the `whsec_` prefix is
42
+ * optional). The header may carry several space-separated signatures, and any
43
+ * one valid `v1` under any one secret passes, which is how a sender rotates
44
+ * keys. Does not check the timestamp's age; the intake does.
45
+ */
46
+ export const verifyStandardWebhookSignature = (input, secrets) => {
47
+ const offered = (input.signature ?? '')
48
+ .split(' ')
49
+ .filter((entry) => entry.startsWith('v1,'))
50
+ .map((entry) => Buffer.from(entry.slice(3), 'base64'));
51
+ if (offered.length === 0) {
52
+ return false;
53
+ }
54
+ const signed = Buffer.concat([Buffer.from(`${input.id}.${input.timestamp}.`), input.body]);
55
+ return secrets.some((secret) => {
56
+ const key = Buffer.from(secret.startsWith('whsec_') ? secret.slice(6) : secret, 'base64');
57
+ if (key.length === 0) {
58
+ return false;
59
+ }
60
+ const expected = createHmac('sha256', key).update(signed).digest();
61
+ return offered.some((candidate) => constantTimeEqual(candidate, expected));
62
+ });
63
+ };
64
+ /** GitHub's `X-Hub-Signature-256: sha256=<hex HMAC-SHA256 of the raw body>`, keyed with the secret as text. */
65
+ export const verifyGithubSignature = (input, secrets) => {
66
+ const signature = input.signature ?? '';
67
+ if (!signature.startsWith('sha256=')) {
68
+ return false;
69
+ }
70
+ const offered = Buffer.from(signature.slice('sha256='.length), 'utf8');
71
+ return secrets.some((secret) => secret.length > 0
72
+ && constantTimeEqual(offered, Buffer.from(createHmac('sha256', secret).update(input.body).digest('hex'), 'utf8')));
73
+ };
74
+ /** A body that parsed but isn't an event; its message is the 400's. */
75
+ class MalformedEventError extends Error {
76
+ constructor(message) {
77
+ super(message);
78
+ this.name = 'MalformedEventError';
79
+ }
80
+ }
81
+ const isPlainObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
82
+ const parseJsonObject = (body) => {
83
+ let parsed;
84
+ try {
85
+ parsed = JSON.parse(typeof body === 'string' ? body : body.toString('utf8'));
86
+ }
87
+ catch {
88
+ throw new MalformedEventError('The body is not JSON.');
89
+ }
90
+ if (!isPlainObject(parsed)) {
91
+ throw new MalformedEventError('The body must be a JSON object.');
92
+ }
93
+ return parsed;
94
+ };
95
+ const ATTRIBUTE_NAME = /^[a-z0-9]+$/;
96
+ /**
97
+ * A Standard Webhooks body as an event. A structured CloudEvent (it has
98
+ * `specversion`) keeps its attributes, and its `id` must be the `webhook-id`
99
+ * it was signed under, or one signed delivery could be replayed as another
100
+ * event. A plain `{ type, timestamp?, data? }` payload takes its id from
101
+ * `webhook-id` and its source from the configured source. Extension
102
+ * attributes keep only valid names with scalar values, as strings; anything
103
+ * else is dropped, not refused. An empty `webhook-id` and `data_base64` are
104
+ * refused: one would make every such delivery share a dedup key, the other
105
+ * would arrive with its payload gone.
106
+ */
107
+ export const parseStandardWebhookEvent = (input) => {
108
+ if (input.webhookId.length === 0) {
109
+ throw new MalformedEventError('The webhook-id header is empty; every delivery needs its own id.');
110
+ }
111
+ const object = parseJsonObject(input.body);
112
+ if (object.specversion === undefined) {
113
+ if (typeof object.type !== 'string' || object.type.length === 0) {
114
+ throw new MalformedEventError('A Standard Webhooks payload needs a string "type".');
115
+ }
116
+ return {
117
+ attributes: {
118
+ specversion: '1.0',
119
+ id: input.webhookId,
120
+ source: `stratus:source/${input.sourceId}`,
121
+ type: object.type,
122
+ ...(typeof object.timestamp === 'string' ? { time: object.timestamp } : {}),
123
+ },
124
+ ...(object.data !== undefined ? { data: object.data } : {}),
125
+ };
126
+ }
127
+ const event = parseCloudEvent(object);
128
+ if (event.attributes.id !== input.webhookId) {
129
+ throw new MalformedEventError('The CloudEvent id must equal the webhook-id header it was signed under.');
130
+ }
131
+ return event;
132
+ };
133
+ /**
134
+ * A structured CloudEvents 1.0 object as an event: what a Standard Webhooks
135
+ * body with `specversion` carries, and what a plugin source feeds. Extension
136
+ * attributes keep only valid names with scalar values, as strings; anything
137
+ * else is dropped, not refused.
138
+ */
139
+ const parseCloudEvent = (object) => {
140
+ if (object.specversion !== '1.0') {
141
+ throw new MalformedEventError(`CloudEvents specversion "${String(object.specversion)}" is not supported; send "1.0".`);
142
+ }
143
+ for (const required of ['id', 'source', 'type']) {
144
+ const value = object[required];
145
+ if (typeof value !== 'string' || value.length === 0) {
146
+ throw new MalformedEventError(`A CloudEvent needs a non-empty string "${required}".`);
147
+ }
148
+ }
149
+ // Refused, not dropped: accepting it would hand triggers an event whose
150
+ // payload silently vanished. Events here are JSON.
151
+ if (object.data_base64 !== undefined) {
152
+ throw new MalformedEventError('data_base64 is not supported; send the payload as JSON in "data".');
153
+ }
154
+ const attributes = {};
155
+ for (const [name, value] of Object.entries(object)) {
156
+ if (name === 'data' || !ATTRIBUTE_NAME.test(name)) {
157
+ continue;
158
+ }
159
+ if (typeof value === 'string') {
160
+ attributes[name] = value;
161
+ }
162
+ else if (typeof value === 'number' || typeof value === 'boolean') {
163
+ attributes[name] = String(value);
164
+ }
165
+ }
166
+ return { attributes, ...(object.data !== undefined ? { data: object.data } : {}) };
167
+ };
168
+ const stringAt = (value, ...path) => {
169
+ let cursor = value;
170
+ for (const key of path) {
171
+ if (!isPlainObject(cursor)) {
172
+ return undefined;
173
+ }
174
+ cursor = cursor[key];
175
+ }
176
+ return typeof cursor === 'string' && cursor.length > 0 ? cursor : undefined;
177
+ };
178
+ const numberAt = (value, ...path) => {
179
+ let cursor = value;
180
+ for (const key of path) {
181
+ if (!isPlainObject(cursor)) {
182
+ return undefined;
183
+ }
184
+ cursor = cursor[key];
185
+ }
186
+ return typeof cursor === 'number' && Number.isSafeInteger(cursor) ? cursor : undefined;
187
+ };
188
+ /**
189
+ * A GitHub webhook delivery as a CloudEvent. The subject is `pull/<n>` for
190
+ * anything on a PR, an issue comment on a PR included, so a review and a
191
+ * comment on one PR share a session; `issues/<n>` for an issue. `actor` is
192
+ * who acted, `author` who owns the PR or issue: what a trigger names to wake
193
+ * only the PR's owner. GitHub sends no event time, so `time` is when it
194
+ * arrived.
195
+ */
196
+ export const mapGithubDelivery = (input) => {
197
+ const payload = (isPlainObject(input.payload) ? input.payload : {});
198
+ const action = stringAt(payload, 'action');
199
+ const repository = stringAt(payload, 'repository', 'full_name');
200
+ const organization = stringAt(payload, 'organization', 'login');
201
+ const pullNumber = numberAt(payload, 'pull_request', 'number');
202
+ const issueNumber = numberAt(payload, 'issue', 'number');
203
+ const issueIsPull = isPlainObject(payload.issue) && payload.issue.pull_request !== undefined;
204
+ const subject = pullNumber !== undefined
205
+ ? `pull/${pullNumber}`
206
+ : issueNumber !== undefined ? `${issueIsPull ? 'pull' : 'issues'}/${issueNumber}` : undefined;
207
+ const actor = stringAt(payload, 'sender', 'login');
208
+ const author = stringAt(payload, 'pull_request', 'user', 'login') ?? stringAt(payload, 'issue', 'user', 'login');
209
+ return {
210
+ attributes: {
211
+ specversion: '1.0',
212
+ id: input.delivery,
213
+ source: `https://github.com${repository ? `/${repository}` : organization ? `/${organization}` : ''}`,
214
+ type: `com.github.${input.event}${action ? `.${action}` : ''}`,
215
+ ...(subject !== undefined ? { subject } : {}),
216
+ time: input.receivedAt,
217
+ ...(actor !== undefined ? { actor } : {}),
218
+ ...(author !== undefined ? { author } : {}),
219
+ },
220
+ data: payload,
221
+ };
222
+ };
223
+ const mediaType = (contentType) => (contentType ?? '').split(';')[0].trim().toLowerCase();
224
+ export const createEventIntake = (options) => {
225
+ const maxBodyBytes = options.maxBodyBytes ?? DEFAULT_EVENT_MAX_BODY_BYTES;
226
+ const now = options.now ?? (() => new Date());
227
+ let unknownSource = 0;
228
+ const counters = new Map();
229
+ const signedRequests = new Map();
230
+ const lastWarned = new Map();
231
+ const countersFor = (sourceId) => {
232
+ let entry = counters.get(sourceId);
233
+ if (!entry) {
234
+ entry = { tooLarge: 0, badSignature: 0, rateLimited: 0, notReady: 0 };
235
+ counters.set(sourceId, entry);
236
+ }
237
+ return entry;
238
+ };
239
+ const refusal = (sourceId, reason) => {
240
+ const at = now();
241
+ countersFor(sourceId).lastRefusal = { at: at.toISOString(), reason };
242
+ const last = lastWarned.get(sourceId);
243
+ if (last === undefined || at.getTime() - last >= REFUSAL_WARN_INTERVAL_MS) {
244
+ lastWarned.set(sourceId, at.getTime());
245
+ // Escaped: a reason can quote a sender's content type or field, and a
246
+ // raw control character there would forge or recolor a log line.
247
+ options.warn(`events: refused a request to source "${sourceId}": ${escapeControlCharacters(reason)}`);
248
+ }
249
+ };
250
+ const answer = (status, body) => ({ status, body });
251
+ /**
252
+ * Count a signed request, or a plugin's event, against its source's
253
+ * minute; false when the minute is full.
254
+ */
255
+ const admit = (sourceId) => {
256
+ const at = now().getTime();
257
+ const recent = (signedRequests.get(sourceId) ?? []).filter((time) => at - time < 60_000);
258
+ if (recent.length >= EVENT_SOURCE_REQUESTS_PER_MINUTE) {
259
+ signedRequests.set(sourceId, recent);
260
+ return false;
261
+ }
262
+ recent.push(at);
263
+ signedRequests.set(sourceId, recent);
264
+ return true;
265
+ };
266
+ const receive = async (request) => {
267
+ const { sourceId, headers, body } = request;
268
+ const sources = options.sources();
269
+ const source = Object.hasOwn(sources, sourceId) ? sources[sourceId] : undefined;
270
+ if (!source) {
271
+ unknownSource += 1;
272
+ return answer(404, { error: 'unknown_source', message: 'No event source is configured at this path.' });
273
+ }
274
+ const count = countersFor(sourceId);
275
+ if (body.length > maxBodyBytes) {
276
+ count.tooLarge += 1;
277
+ refusal(sourceId, `body over ${maxBodyBytes} bytes`);
278
+ return answer(413, { error: 'too_large', message: `The body is over ${maxBodyBytes} bytes.` });
279
+ }
280
+ const secrets = (await Promise.all(source.secrets.map((name) => options.secret(name))))
281
+ .filter((value) => typeof value === 'string' && value.length > 0);
282
+ if (secrets.length === 0) {
283
+ count.notReady += 1;
284
+ const reason = `No secret is set for event source "${sourceId}". Run \`stratus credential set ${source.secrets[0] ?? `events.${sourceId}`}\` on the daemon's host.`;
285
+ refusal(sourceId, reason);
286
+ return answer(503, { error: 'source_not_ready', message: reason });
287
+ }
288
+ const receivedAt = now().toISOString();
289
+ let eventId;
290
+ let signatureProblem;
291
+ if (source.verify === 'github') {
292
+ eventId = headerOf(headers, 'x-github-delivery');
293
+ if (!verifyGithubSignature({ body, signature: headerOf(headers, 'x-hub-signature-256') }, secrets)) {
294
+ signatureProblem = 'missing or wrong X-Hub-Signature-256 signature';
295
+ }
296
+ }
297
+ else {
298
+ eventId = headerOf(headers, 'webhook-id');
299
+ const timestamp = headerOf(headers, 'webhook-timestamp');
300
+ if (eventId === undefined || timestamp === undefined
301
+ || !verifyStandardWebhookSignature({ id: eventId, timestamp, body, signature: headerOf(headers, 'webhook-signature') }, secrets)) {
302
+ signatureProblem = 'missing or wrong webhook-signature (Standard Webhooks v1)';
303
+ }
304
+ else if (!/^\d+$/.test(timestamp) || Math.abs(now().getTime() - Number(timestamp) * 1_000) > TIMESTAMP_TOLERANCE_MS) {
305
+ signatureProblem = 'webhook-timestamp is more than 5 minutes from this host\'s clock';
306
+ }
307
+ }
308
+ if (signatureProblem !== undefined) {
309
+ count.badSignature += 1;
310
+ refusal(sourceId, signatureProblem);
311
+ return answer(401, { error: 'bad_signature', message: `Refused: ${signatureProblem}.` });
312
+ }
313
+ if (!admit(sourceId)) {
314
+ count.rateLimited += 1;
315
+ refusal(sourceId, `over ${EVENT_SOURCE_REQUESTS_PER_MINUTE} signed requests a minute`);
316
+ return answer(429, { error: 'rate_limited', message: `Over ${EVENT_SOURCE_REQUESTS_PER_MINUTE} requests a minute for this source.` });
317
+ }
318
+ // Signed from here on: refusals leave a row, without a tombstone, so the
319
+ // sender can fix the request and retry under the same id.
320
+ const refuse = (status, error, reason, type) => {
321
+ options.store.refuse({ source: sourceId, eventId: eventId ?? '', ...(type !== undefined ? { type } : {}), reason, receivedAt });
322
+ refusal(sourceId, reason);
323
+ return answer(status, { error, message: reason });
324
+ };
325
+ const type = mediaType(headerOf(headers, 'content-type'));
326
+ let event;
327
+ try {
328
+ if (source.verify === 'github') {
329
+ const githubEvent = headerOf(headers, 'x-github-event');
330
+ if (type !== 'application/json') {
331
+ return refuse(415, 'unsupported_content_type', `Content type "${type || 'none'}" is not supported. In the GitHub webhook's settings, set Content type to application/json.`, githubEvent !== undefined ? `com.github.${githubEvent}` : undefined);
332
+ }
333
+ if (githubEvent === undefined || githubEvent.length === 0 || eventId === undefined || eventId.length === 0) {
334
+ throw new MalformedEventError('A GitHub delivery needs X-GitHub-Event and X-GitHub-Delivery headers.');
335
+ }
336
+ event = mapGithubDelivery({ event: githubEvent, delivery: eventId, payload: parseJsonObject(body), receivedAt });
337
+ }
338
+ else {
339
+ if (type !== 'application/json' && type !== 'application/cloudevents+json') {
340
+ return refuse(415, 'unsupported_content_type', `Content type "${type || 'none'}" is not supported. Send application/cloudevents+json or application/json.`);
341
+ }
342
+ event = parseStandardWebhookEvent({ sourceId, webhookId: eventId, body });
343
+ }
344
+ }
345
+ catch (error) {
346
+ if (error instanceof MalformedEventError) {
347
+ return refuse(400, 'malformed', error.message);
348
+ }
349
+ throw error;
350
+ }
351
+ return answer(200, { status: storeEvent(sourceId, event, receivedAt) });
352
+ };
353
+ /**
354
+ * The rule filter, before anything that could cost a model call, then one
355
+ * write for the delivery and a pending firing per matched trigger. The
356
+ * same for a webhook's event and a plugin's.
357
+ */
358
+ const storeEvent = (sourceId, event, receivedAt) => {
359
+ const matched = options.triggers(sourceId)
360
+ .filter((trigger) => trigger.source === sourceId && matchesEventFilter(trigger.filter, event));
361
+ const coalescingKey = eventCoalescingKey(sourceId, event);
362
+ const block = matched.length > 0 ? renderEventBlock(sourceId, event) : '';
363
+ const firings = matched.map((trigger) => ({
364
+ triggerId: trigger.triggerId,
365
+ agentId: trigger.agentId,
366
+ coalescingKey,
367
+ sessionId: eventSessionId(trigger.triggerId, coalescingKey),
368
+ dispatchKey: eventDispatchKey(trigger.triggerId, sourceId, event.attributes.id ?? ''),
369
+ block,
370
+ }));
371
+ return options.store.accept({
372
+ source: sourceId,
373
+ eventId: event.attributes.id ?? '',
374
+ type: event.attributes.type ?? '',
375
+ ...(event.attributes.subject !== undefined ? { subject: event.attributes.subject } : {}),
376
+ receivedAt,
377
+ firings,
378
+ }).status;
379
+ };
380
+ const ingest = (sourceId, raw) => {
381
+ if (!(options.pluginSources?.() ?? []).includes(sourceId)) {
382
+ throw new Error(`No plugin feeds an event source "${sourceId}" on this daemon.`);
383
+ }
384
+ const count = countersFor(sourceId);
385
+ const receivedAt = now().toISOString();
386
+ // Serialized once: the size limit is the one a webhook's body is held
387
+ // to, and what is matched and stored is what the same JSON posted to
388
+ // the events port would give (no undefined, no Date, no prototype).
389
+ let serialized;
390
+ try {
391
+ serialized = JSON.stringify(raw);
392
+ }
393
+ catch (error) {
394
+ throw new Error(`The event is not JSON: ${error instanceof Error ? error.message : String(error)}.`);
395
+ }
396
+ if (serialized !== undefined && Buffer.byteLength(serialized) > maxBodyBytes) {
397
+ count.tooLarge += 1;
398
+ refusal(sourceId, `event over ${maxBodyBytes} bytes`);
399
+ throw new Error(`The event is over ${maxBodyBytes} bytes as JSON.`);
400
+ }
401
+ if (!admit(sourceId)) {
402
+ count.rateLimited += 1;
403
+ refusal(sourceId, `over ${EVENT_SOURCE_REQUESTS_PER_MINUTE} events a minute`);
404
+ throw new Error(`Over ${EVENT_SOURCE_REQUESTS_PER_MINUTE} events a minute for source "${sourceId}". Feed this one again later; its id keeps it from counting twice.`);
405
+ }
406
+ let event;
407
+ try {
408
+ event = parseCloudEvent(parseJsonObject(serialized ?? ''));
409
+ }
410
+ catch (error) {
411
+ if (!(error instanceof MalformedEventError)) {
412
+ throw error;
413
+ }
414
+ // A row, like a signed body the listener refused, so `stratus events`
415
+ // shows it; no tombstone, so the corrected event under the same id
416
+ // gets through.
417
+ const object = typeof raw === 'object' && raw !== null && !Array.isArray(raw) ? raw : {};
418
+ options.store.refuse({
419
+ source: sourceId,
420
+ eventId: typeof object.id === 'string' ? object.id : '',
421
+ ...(typeof object.type === 'string' ? { type: object.type } : {}),
422
+ reason: error.message,
423
+ receivedAt,
424
+ });
425
+ refusal(sourceId, error.message);
426
+ throw new Error(error.message);
427
+ }
428
+ return { status: storeEvent(sourceId, event, receivedAt) };
429
+ };
430
+ return {
431
+ receive,
432
+ ingest,
433
+ counters: () => ({
434
+ unknownSource,
435
+ sources: Object.fromEntries([...Object.keys(options.sources()), ...(options.pluginSources?.() ?? [])].map((sourceId) => {
436
+ const entry = countersFor(sourceId);
437
+ return [sourceId, {
438
+ ...entry,
439
+ ...(entry.lastRefusal ? { lastRefusal: { ...entry.lastRefusal } } : {}),
440
+ }];
441
+ })),
442
+ }),
443
+ };
444
+ };
445
+ //# sourceMappingURL=event-intake.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-intake.js","sourceRoot":"","sources":["../src/event-intake.ts"],"names":[],"mappings":"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"}