@lensmcp/protocol-types 1.25.8 → 1.25.10
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/lib/dashboard.d.ts +2 -1
- package/lib/event.d.ts +2 -0
- package/lib/event.js +1 -1
- package/lib/sources.d.ts +524 -16
- package/lib/sources.js +1 -1
- package/package.json +1 -1
package/lib/dashboard.d.ts
CHANGED
|
@@ -2518,7 +2518,8 @@ export interface DashAiRun {
|
|
|
2518
2518
|
label: string;
|
|
2519
2519
|
why: string;
|
|
2520
2520
|
}>;
|
|
2521
|
-
turns?: number;
|
|
2521
|
+
turns?: number; /** Why its last turn ended, the provider's word (`end_turn`, `max_tokens`). */
|
|
2522
|
+
stopReason?: string;
|
|
2522
2523
|
};
|
|
2523
2524
|
/**
|
|
2524
2525
|
* How the frontier model worked, turn by turn, as it streamed: its reasoning (summarized), what it wrote, each tool it
|
package/lib/event.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export declare const EventSourceSchema: z.ZodEnum<{
|
|
|
22
22
|
external: "external";
|
|
23
23
|
ai: "ai";
|
|
24
24
|
lens: "lens";
|
|
25
|
+
custom: "custom";
|
|
25
26
|
}>;
|
|
26
27
|
export type EventSource = z.infer<typeof EventSourceSchema>;
|
|
27
28
|
export declare const EventCategorySchema: z.ZodEnum<{
|
|
@@ -81,6 +82,7 @@ export declare const BaseEventSchema: z.ZodObject<{
|
|
|
81
82
|
external: "external";
|
|
82
83
|
ai: "ai";
|
|
83
84
|
lens: "lens";
|
|
85
|
+
custom: "custom";
|
|
84
86
|
}>;
|
|
85
87
|
category: z.ZodEnum<{
|
|
86
88
|
db: "db";
|
package/lib/event.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{z as e}from"zod";import{SourceLocationSchema as t}from"./source-location.js";import{TraceContextSchema as r}from"./context.js";export const EventSourceSchema=e.enum(["nx","vite","typescript","eslint","rollup","client-runtime","chrome","react","valtio","nestjs","nextjs","db","redis","queue","memory","visual","perf","security","gateway","external","ai","lens"]),EventCategorySchema=e.enum(["build","lint","typecheck","test","runtime","render","visual","trace","state","network","backend","db","memory","performance","security","deps","cluster","ai","agent"]),SeveritySchema=e.enum(["debug","info","warning","error","fatal"]),BaseEventSchema=e.object({id:e.string(),sessionId:e.string(),timestamp:e.number().int().nonnegative(),source:EventSourceSchema,category:EventCategorySchema,severity:SeveritySchema,context:r,fingerprint:e.string(),title:e.string(),message:e.string().optional(),location:t.optional(),relatedFiles:e.array(e.string()).optional(),relatedUrls:e.array(e.string()).optional(),raw:e.unknown().optional()});
|
|
1
|
+
"use strict";import{z as e}from"zod";import{SourceLocationSchema as t}from"./source-location.js";import{TraceContextSchema as r}from"./context.js";export const EventSourceSchema=e.enum(["nx","vite","typescript","eslint","rollup","client-runtime","chrome","react","valtio","nestjs","nextjs","db","redis","queue","memory","visual","perf","security","gateway","external","ai","lens","custom"]),EventCategorySchema=e.enum(["build","lint","typecheck","test","runtime","render","visual","trace","state","network","backend","db","memory","performance","security","deps","cluster","ai","agent"]),SeveritySchema=e.enum(["debug","info","warning","error","fatal"]),BaseEventSchema=e.object({id:e.string(),sessionId:e.string(),timestamp:e.number().int().nonnegative(),source:EventSourceSchema,category:EventCategorySchema,severity:SeveritySchema,context:r,fingerprint:e.string(),title:e.string(),message:e.string().optional(),location:t.optional(),relatedFiles:e.array(e.string()).optional(),relatedUrls:e.array(e.string()).optional(),raw:e.unknown().optional()});
|
package/lib/sources.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CUSTOM SOURCES (issues/
|
|
2
|
+
* CUSTOM SOURCES (issues/closed/foodguard-81) — an application REPORTS what the lens cannot observe, as one of a closed
|
|
3
3
|
* set of typed kinds the lens knows how to draw, threshold and explain to an agent: `queue` · `loop` · `store` ·
|
|
4
4
|
* `traffic`. Phase 1 reads `queue` only — work a service keeps waiting in its OWN storage (an outbox table), which no
|
|
5
5
|
* event stream can show: FoodGuard's lens showed its BullMQ queues nearly empty while 6,389 outbox rows waited.
|
|
@@ -19,26 +19,103 @@
|
|
|
19
19
|
* 3. The READ — `apps/agent` folds them into `process://sources` ({@link SourcesReport}); the `observe.sources` and
|
|
20
20
|
* `source.get` tools, the status signal and the dashboard read that.
|
|
21
21
|
*
|
|
22
|
+
* Phase 2 adds:
|
|
23
|
+
* - the `loop` kind — a background loop, scheduler or sweep answering `lensmcp.loop/v1` ({@link LoopSnapshotRaw});
|
|
24
|
+
* `feeds` links it to the queue source it drains;
|
|
25
|
+
* - PUSHED events — `lensEmitCustom` (`@lensmcp/node-instrumentation`) writes a `source: 'custom'` event
|
|
26
|
+
* ({@link SourceEventRaw}) with the flow context of the request or job it ran in, so an outbox row's `enqueued` shows
|
|
27
|
+
* in the flow of the answer that wrote it;
|
|
28
|
+
* - reports ON CHANGE: a poll whose snapshot did not change carries `same` ({@link SourceSameRaw}) instead of the whole
|
|
29
|
+
* snapshot, and a full one goes at least every {@link SOURCE_FULL_REPORT_MS};
|
|
30
|
+
* - the lens's history of each source, and the findings it needs: `queue/stalled`, `loop/overdue`, `loop/failing`,
|
|
31
|
+
* `loop/idle-while-fed`.
|
|
32
|
+
*
|
|
33
|
+
* Phase 3 adds the last two kinds:
|
|
34
|
+
* - `store` — a storage backend the taps do not model (document storage on disk or in a bucket, a chunk store):
|
|
35
|
+
* `lensmcp.store/v1` ({@link StoreSnapshotRaw}) says how many objects and bytes it holds against its quota, and its
|
|
36
|
+
* window's writes, deletes and errors. Findings `store/near-quota`, `store/errors`, `store/orphans` (it grows and
|
|
37
|
+
* nothing is deleted);
|
|
38
|
+
* - `traffic` — messages over a channel the taps do not classify (a partner's API answering 429s, a webhook, a custom
|
|
39
|
+
* transport): `lensmcp.traffic/v1` ({@link TrafficSnapshotRaw}) per channel — messages, failures, rate-limited,
|
|
40
|
+
* p95 — or, with no `path`, PUSH-ONLY: the lens counts what the app pushes (`inbound` / `outbound`) over the last
|
|
41
|
+
* {@link TRAFFIC_PUSH_WINDOW_MS}. Findings `traffic/failures`, `traffic/latency`, `traffic/rate-limited`.
|
|
42
|
+
*
|
|
22
43
|
* Everything here is REPORTED by the app, never measured by the lens: every read carries `provenance: 'reported'`.
|
|
23
44
|
* Additive only.
|
|
24
45
|
*/
|
|
25
46
|
/** The closed set of source kinds. */
|
|
26
47
|
export declare const SOURCE_KINDS: readonly ["queue", "loop", "store", "traffic"];
|
|
27
48
|
export type SourceKind = (typeof SOURCE_KINDS)[number];
|
|
28
|
-
/** The kinds this release reads; a
|
|
29
|
-
export declare const SOURCE_KINDS_READ: readonly ["queue"];
|
|
49
|
+
/** The kinds this release reads — all of them since phase 3; a kind outside the set is said, not polled. */
|
|
50
|
+
export declare const SOURCE_KINDS_READ: readonly ["queue", "loop", "store", "traffic"];
|
|
30
51
|
export type SourceKindRead = (typeof SOURCE_KINDS_READ)[number];
|
|
31
52
|
/** Every snapshot's schema: `lensmcp.<kind>/v1`. */
|
|
32
53
|
export declare const sourceWireSchema: (kind: SourceKind) => string;
|
|
33
54
|
export declare const QUEUE_WIRE_SCHEMA = "lensmcp.queue/v1";
|
|
55
|
+
export declare const LOOP_WIRE_SCHEMA = "lensmcp.loop/v1";
|
|
56
|
+
export declare const STORE_WIRE_SCHEMA = "lensmcp.store/v1";
|
|
57
|
+
export declare const TRAFFIC_WIRE_SCHEMA = "lensmcp.traffic/v1";
|
|
58
|
+
/** Where each kind's last good snapshot rides on a `source-poll` raw — never another kind's field. */
|
|
59
|
+
export declare const SOURCE_SNAPSHOT_FIELD: {
|
|
60
|
+
readonly queue: "snapshot";
|
|
61
|
+
readonly loop: "loop";
|
|
62
|
+
readonly store: "store";
|
|
63
|
+
readonly traffic: "traffic";
|
|
64
|
+
};
|
|
34
65
|
/** The resource the lens folds the polls into. */
|
|
35
66
|
export declare const URI_SOURCES = "process://sources";
|
|
36
67
|
/** Said on every read of a source: the app's claim, not the lens's measurement. */
|
|
37
68
|
export declare const SOURCE_PROVENANCE: "reported";
|
|
38
|
-
/**
|
|
69
|
+
/** A queue group whose oldest pending item has waited longer than `thresholds.oldestWaitMin`. */
|
|
39
70
|
export declare const QUEUE_OLDEST_WAIT_RULE = "queue/oldest-wait";
|
|
40
|
-
|
|
71
|
+
/** A queue group with pending work that has not moved for `thresholds.stalledMin` (nothing taken, nothing finished). */
|
|
72
|
+
export declare const QUEUE_STALLED_RULE = "queue/stalled";
|
|
73
|
+
/** A loop whose next run is late by more than {@link LOOP_OVERDUE_INTERVALS} of its intervals. */
|
|
74
|
+
export declare const LOOP_OVERDUE_RULE = "loop/overdue";
|
|
75
|
+
/** A loop whose last {@link LOOP_FAILING_RUNS} runs all failed. */
|
|
76
|
+
export declare const LOOP_FAILING_RULE = "loop/failing";
|
|
77
|
+
/** A loop that runs and takes nothing, for `thresholds.idleMin`, while the queue it `feeds` has work. */
|
|
78
|
+
export declare const LOOP_IDLE_RULE = "loop/idle-while-fed";
|
|
79
|
+
/** A store whose bytes are at or over `thresholds.quotaPct` of its quota. */
|
|
80
|
+
export declare const STORE_QUOTA_RULE = "store/near-quota";
|
|
81
|
+
/** A store with errors in its window — over `thresholds.errorRatePct` of its operations when it says how many. */
|
|
82
|
+
export declare const STORE_ERRORS_RULE = "store/errors";
|
|
83
|
+
/** A store that has grown for `thresholds.orphanMin` and deleted nothing — what nothing cleans up. */
|
|
84
|
+
export declare const STORE_ORPHANS_RULE = "store/orphans";
|
|
85
|
+
/** A channel whose failures are over `thresholds.failurePct` of at least {@link TRAFFIC_MIN_MESSAGES} messages. */
|
|
86
|
+
export declare const TRAFFIC_FAILURES_RULE = "traffic/failures";
|
|
87
|
+
/** A channel whose p95 is over `thresholds.p95Ms`. */
|
|
88
|
+
export declare const TRAFFIC_LATENCY_RULE = "traffic/latency";
|
|
89
|
+
/** A channel whose counterpart answered «too many requests» `thresholds.rateLimited` times or more in the window. */
|
|
90
|
+
export declare const TRAFFIC_RATE_LIMITED_RULE = "traffic/rate-limited";
|
|
91
|
+
export declare const SOURCE_RULES: readonly ["queue/oldest-wait", "queue/stalled", "loop/overdue", "loop/failing", "loop/idle-while-fed", "store/near-quota", "store/errors", "store/orphans", "traffic/failures", "traffic/latency", "traffic/rate-limited"];
|
|
92
|
+
export type SourceRule = (typeof SOURCE_RULES)[number];
|
|
93
|
+
export declare const SOURCE_EVENT_KINDS: readonly ["source-poll", "source-declaration", "source-event"];
|
|
41
94
|
export type SourceEventKind = (typeof SOURCE_EVENT_KINDS)[number];
|
|
95
|
+
/** A pushed event's `source` — the app's own words, never a tap's. */
|
|
96
|
+
export declare const CUSTOM_EVENT_SOURCE: "custom";
|
|
97
|
+
/** What a queue source's app may push: an item written, taken, finished, failed, or set aside. */
|
|
98
|
+
export declare const QUEUE_EVENTS: readonly ["enqueued", "admitted", "completed", "failed", "parked"];
|
|
99
|
+
export type QueueEventName = (typeof QUEUE_EVENTS)[number];
|
|
100
|
+
/** What a loop source's app may push: a run began, a run ended. */
|
|
101
|
+
export declare const LOOP_EVENTS: readonly ["run-start", "run-end"];
|
|
102
|
+
export type LoopEventName = (typeof LOOP_EVENTS)[number];
|
|
103
|
+
/** How a loop's run ended: it worked, it failed, or it chose not to (a gate held it). */
|
|
104
|
+
export declare const LOOP_OUTCOMES: readonly ["ok", "failed", "skipped"];
|
|
105
|
+
export type LoopOutcome = (typeof LOOP_OUTCOMES)[number];
|
|
106
|
+
/** What a store source's app may push: an object written, deleted, or an operation that failed. */
|
|
107
|
+
export declare const STORE_EVENTS: readonly ["write", "delete", "error"];
|
|
108
|
+
export type StoreEventName = (typeof STORE_EVENTS)[number];
|
|
109
|
+
/** What a traffic source's app may push: a message that came in, a message that went out. */
|
|
110
|
+
export declare const TRAFFIC_EVENTS: readonly ["inbound", "outbound"];
|
|
111
|
+
export type TrafficEventName = (typeof TRAFFIC_EVENTS)[number];
|
|
112
|
+
/** How a message went: answered, failed, or refused as too many (an HTTP 429, a quota). */
|
|
113
|
+
export declare const TRAFFIC_OUTCOMES: readonly ["ok", "failed", "rate-limited"];
|
|
114
|
+
export type TrafficOutcome = (typeof TRAFFIC_OUTCOMES)[number];
|
|
115
|
+
/** The events each kind may push. */
|
|
116
|
+
export declare const SOURCE_PUSH_EVENTS: Readonly<Record<SourceKindRead, readonly string[]>>;
|
|
117
|
+
/** The outcomes each kind's pushed events may say (a queue's and a store's say none). */
|
|
118
|
+
export declare const SOURCE_PUSH_OUTCOMES: Readonly<Record<SourceKindRead, readonly string[]>>;
|
|
42
119
|
/** What ONE poll found. */
|
|
43
120
|
export declare const SOURCE_POLL_STATES: readonly ["current", "unreachable", "refused", "malformed", "not-running"];
|
|
44
121
|
export type SourcePollState = (typeof SOURCE_POLL_STATES)[number];
|
|
@@ -52,6 +129,39 @@ export type SourceState = (typeof SOURCE_STATES)[number];
|
|
|
52
129
|
export declare const SOURCE_DEFAULT_INTERVAL_SEC = 10;
|
|
53
130
|
export declare const SOURCE_MIN_INTERVAL_SEC = 2;
|
|
54
131
|
export declare const QUEUE_DEFAULT_OLDEST_WAIT_MIN = 10;
|
|
132
|
+
export declare const QUEUE_DEFAULT_STALLED_MIN = 15;
|
|
133
|
+
export declare const LOOP_DEFAULT_IDLE_MIN = 10;
|
|
134
|
+
/** `loop/overdue`: its next run is late by more than this many of its own intervals. */
|
|
135
|
+
export declare const LOOP_OVERDUE_INTERVALS = 2;
|
|
136
|
+
/** `loop/failing`: this many runs in a row failed. */
|
|
137
|
+
export declare const LOOP_FAILING_RUNS = 3;
|
|
138
|
+
/**
|
|
139
|
+
* A poll whose snapshot did not change since the one last sent in full carries {@link SourceSameRaw} instead — but a
|
|
140
|
+
* full snapshot goes at least this often, so a lens that starts later (its replay is a few MB of the bus) has one
|
|
141
|
+
* within a minute. Before this, every poll carried the whole snapshot: ~2 MB an hour at FoodGuard's size, ~60 MB at
|
|
142
|
+
* the 500-group cap.
|
|
143
|
+
*/
|
|
144
|
+
export declare const SOURCE_FULL_REPORT_MS = 60000;
|
|
145
|
+
/** History points the lens keeps per source (in memory; a lens restart starts it again). */
|
|
146
|
+
export declare const SOURCE_HISTORY_POINTS = 60;
|
|
147
|
+
/** A loop's runs the lens keeps. */
|
|
148
|
+
export declare const SOURCE_RUNS_KEPT = 30;
|
|
149
|
+
/** Pushed events the lens keeps per source. */
|
|
150
|
+
export declare const SOURCE_PUSHED_KEPT = 20;
|
|
151
|
+
export declare const STORE_DEFAULT_QUOTA_PCT = 90;
|
|
152
|
+
export declare const STORE_DEFAULT_ERROR_RATE_PCT = 5;
|
|
153
|
+
/** `store/orphans`: growing this long with nothing deleted. An append-only store by design raises it (at most 10080). */
|
|
154
|
+
export declare const STORE_DEFAULT_ORPHAN_MIN = 60;
|
|
155
|
+
export declare const TRAFFIC_DEFAULT_FAILURE_PCT = 5;
|
|
156
|
+
export declare const TRAFFIC_DEFAULT_P95_MS = 2000;
|
|
157
|
+
export declare const TRAFFIC_DEFAULT_RATE_LIMITED = 1;
|
|
158
|
+
/** `traffic/failures` is judged on at least this many messages in the window — 1 failure of 2 is not a rate. */
|
|
159
|
+
export declare const TRAFFIC_MIN_MESSAGES = 10;
|
|
160
|
+
/** A push-only traffic source: the lens counts what was pushed over this window. */
|
|
161
|
+
export declare const TRAFFIC_PUSH_WINDOW_MS: number;
|
|
162
|
+
/** A push-only traffic source: channels and events per channel the lens keeps to count from. */
|
|
163
|
+
export declare const TRAFFIC_PUSH_CHANNELS = 50;
|
|
164
|
+
export declare const TRAFFIC_PUSH_EVENTS_PER_CHANNEL = 1000;
|
|
55
165
|
/** A snapshot holds at most this many groups; a producer with more caps it and says `truncated: { groups }`. */
|
|
56
166
|
export declare const SOURCE_MAX_GROUPS = 500;
|
|
57
167
|
export declare const SOURCE_MAX_BYTES: number;
|
|
@@ -60,18 +170,55 @@ export declare const SOURCE_STALE_PERIODS = 3;
|
|
|
60
170
|
export declare const SOURCE_STALE_MIN_MS = 30000;
|
|
61
171
|
/** When a source's newest report stops being trusted. */
|
|
62
172
|
export declare function sourceStaleAfterMs(reportEveryMs: number): number;
|
|
63
|
-
/** A queue source's thresholds
|
|
173
|
+
/** A queue source's thresholds, in minutes. The gateway fills both defaults; a 1.25.8 gateway sent no `stalledMin`. */
|
|
64
174
|
export interface QueueThresholds {
|
|
65
175
|
oldestWaitMin: number;
|
|
66
176
|
stalledMin?: number;
|
|
67
177
|
}
|
|
178
|
+
/** A loop source's thresholds, in minutes (the gateway fills the default). */
|
|
179
|
+
export interface LoopThresholds {
|
|
180
|
+
idleMin?: number;
|
|
181
|
+
}
|
|
182
|
+
/** A store source's thresholds (the gateway fills the defaults). */
|
|
183
|
+
export interface StoreThresholds {
|
|
184
|
+
/** Percent of `quotaBytes` (0–100). */
|
|
185
|
+
quotaPct?: number;
|
|
186
|
+
/** Percent of the window's operations (0–100). */
|
|
187
|
+
errorRatePct?: number;
|
|
188
|
+
/** Minutes. */
|
|
189
|
+
orphanMin?: number;
|
|
190
|
+
}
|
|
191
|
+
/** A traffic source's thresholds (the gateway fills the defaults). */
|
|
192
|
+
export interface TrafficThresholds {
|
|
193
|
+
/** Percent of a channel's messages in the window (0–100). */
|
|
194
|
+
failurePct?: number;
|
|
195
|
+
/** Milliseconds. */
|
|
196
|
+
p95Ms?: number;
|
|
197
|
+
/** «Too many requests» answers in the window, at least 1. */
|
|
198
|
+
rateLimited?: number;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* A source's thresholds, any kind's: a queue has `oldestWaitMin` (always) and `stalledMin`; a loop `idleMin`; a store
|
|
202
|
+
* `quotaPct`, `errorRatePct`, `orphanMin`; a traffic source `failurePct`, `p95Ms`, `rateLimited`.
|
|
203
|
+
*/
|
|
204
|
+
export interface SourceThresholds extends StoreThresholds, TrafficThresholds {
|
|
205
|
+
oldestWaitMin?: number;
|
|
206
|
+
stalledMin?: number;
|
|
207
|
+
idleMin?: number;
|
|
208
|
+
}
|
|
68
209
|
/** One declared source, as the gateway polls it. */
|
|
69
210
|
export interface SourceDeclRaw {
|
|
70
211
|
sourceKind: SourceKindRead;
|
|
71
212
|
name: string;
|
|
72
|
-
|
|
213
|
+
/**
|
|
214
|
+
* Absent only on a PUSH-ONLY loop or traffic source: never polled; the lens reads what the app pushes. A push-only
|
|
215
|
+
* loop's `intervalSec` is the loop's OWN period (the lens judges «overdue» by it); a polled one's is the poll's.
|
|
216
|
+
*/
|
|
217
|
+
path?: string;
|
|
73
218
|
intervalSec: number;
|
|
74
|
-
thresholds:
|
|
219
|
+
thresholds: SourceThresholds;
|
|
220
|
+
/** A loop: the NAME of the queue source on the same service that it drains — what `loop/idle-while-fed` reads. */
|
|
221
|
+
feeds?: string;
|
|
75
222
|
}
|
|
76
223
|
/** One group of a queue snapshot, as the bus carries it. */
|
|
77
224
|
export interface QueueGroupRaw {
|
|
@@ -106,6 +253,114 @@ export interface QueueSnapshotRaw {
|
|
|
106
253
|
truncated?: {
|
|
107
254
|
groups: number;
|
|
108
255
|
};
|
|
256
|
+
/** Names the snapshot's content (not its times): a later poll that read the same says so with {@link SourceSameRaw}. */
|
|
257
|
+
digest?: string;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* A loop snapshot that parsed — what a background loop, scheduler or sweep says of itself. The wire
|
|
261
|
+
* (`lensmcp.loop/v1`) is the same fields plus `schema`, without `receivedAt`/`digest`; only `at`, `intervalSec` and
|
|
262
|
+
* `lastRunAt` are required.
|
|
263
|
+
*/
|
|
264
|
+
export interface LoopSnapshotRaw {
|
|
265
|
+
/** When the SERVICE measured it (ISO). */
|
|
266
|
+
at: string;
|
|
267
|
+
/** When the gateway received it (epoch ms). */
|
|
268
|
+
receivedAt: number;
|
|
269
|
+
digest?: string;
|
|
270
|
+
/** The loop's own period, in seconds (not the poll's). */
|
|
271
|
+
intervalSec: number;
|
|
272
|
+
/** When its last run began (ISO); `null`: it has not run since the service started. */
|
|
273
|
+
lastRunAt: string | null;
|
|
274
|
+
lastDurationMs?: number;
|
|
275
|
+
lastOutcome?: LoopOutcome;
|
|
276
|
+
/** Items its last run took. */
|
|
277
|
+
lastItems?: number;
|
|
278
|
+
/** When it will run next (ISO), if it knows. */
|
|
279
|
+
nextRunAt?: string | null;
|
|
280
|
+
/** Over the service's own window of `windowSec`. */
|
|
281
|
+
runsInWindow?: number;
|
|
282
|
+
itemsInWindow?: number;
|
|
283
|
+
failuresInWindow?: number;
|
|
284
|
+
windowSec?: number;
|
|
285
|
+
/** The last failed run's error, at most 500 characters. */
|
|
286
|
+
lastError?: string;
|
|
287
|
+
}
|
|
288
|
+
/** One group of a store — a bucket, a tenant's folder — as the bus carries it (the wire's `key` travels as `group`). */
|
|
289
|
+
export interface StoreGroupRaw {
|
|
290
|
+
group: string;
|
|
291
|
+
labels?: Record<string, string>;
|
|
292
|
+
objects: number;
|
|
293
|
+
bytes: number;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* A store snapshot that parsed — what a storage backend the taps do not model says of itself. The wire
|
|
297
|
+
* (`lensmcp.store/v1`) is the same fields plus `schema`, without `receivedAt`/`digest`, its groups keyed `key`; only
|
|
298
|
+
* `at`, `objects` and `bytes` are required.
|
|
299
|
+
*/
|
|
300
|
+
export interface StoreSnapshotRaw {
|
|
301
|
+
at: string;
|
|
302
|
+
receivedAt: number;
|
|
303
|
+
digest?: string;
|
|
304
|
+
objects: number;
|
|
305
|
+
bytes: number;
|
|
306
|
+
/** What it may hold; absent or `null`: no quota it knows of. */
|
|
307
|
+
quotaBytes?: number | null;
|
|
308
|
+
/** Operations of every kind over the service's window of `windowSec` — what `errorsInWindow` is a rate of. */
|
|
309
|
+
opsInWindow?: number;
|
|
310
|
+
writesInWindow?: number;
|
|
311
|
+
deletesInWindow?: number;
|
|
312
|
+
errorsInWindow?: number;
|
|
313
|
+
windowSec?: number;
|
|
314
|
+
lastWriteAt?: string | null;
|
|
315
|
+
/** The last failed operation's error, at most 500 characters. */
|
|
316
|
+
lastError?: string;
|
|
317
|
+
/** At most {@link SOURCE_MAX_GROUPS}, the largest first. */
|
|
318
|
+
groups?: StoreGroupRaw[];
|
|
319
|
+
truncated?: {
|
|
320
|
+
groups: number;
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
/** One channel of a traffic source, as the bus carries it (the wire's `key` travels as `channel`). */
|
|
324
|
+
export interface TrafficChannelRaw {
|
|
325
|
+
channel: string;
|
|
326
|
+
labels?: Record<string, string>;
|
|
327
|
+
direction?: 'inbound' | 'outbound';
|
|
328
|
+
/** Who is at the other end — a partner, a host, a queue — at most 200 characters. */
|
|
329
|
+
counterpart?: string;
|
|
330
|
+
/** Over the service's window of `windowSec`. */
|
|
331
|
+
messagesInWindow?: number;
|
|
332
|
+
failuresInWindow?: number;
|
|
333
|
+
/** Answered «too many requests» (an HTTP 429, a quota) — counted apart from `failuresInWindow`. */
|
|
334
|
+
rateLimitedInWindow?: number;
|
|
335
|
+
p95Ms?: number;
|
|
336
|
+
lastAt?: string | null;
|
|
337
|
+
lastError?: string;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* A traffic snapshot that parsed — messages over channels the taps do not classify. The wire (`lensmcp.traffic/v1`) is
|
|
341
|
+
* the same plus `schema`, each channel keyed `key`; only `at` and `channels` are required.
|
|
342
|
+
*/
|
|
343
|
+
export interface TrafficSnapshotRaw {
|
|
344
|
+
at: string;
|
|
345
|
+
receivedAt: number;
|
|
346
|
+
digest?: string;
|
|
347
|
+
windowSec?: number;
|
|
348
|
+
/** At most {@link SOURCE_MAX_GROUPS}. */
|
|
349
|
+
channels: TrafficChannelRaw[];
|
|
350
|
+
truncated?: {
|
|
351
|
+
channels: number;
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* In place of the snapshot, on a poll that read what an earlier report carried in full (the same `digest`): the lens
|
|
356
|
+
* takes the one it holds, measured again at `at` and received at `receivedAt`. On a poll that did not read (`unreachable`
|
|
357
|
+
* …) `at`/`receivedAt` are the held snapshot's own. A lens that holds no snapshot of that digest (it started after the
|
|
358
|
+
* full report) says the source is not read yet — never «nothing pending» — until the next full report.
|
|
359
|
+
*/
|
|
360
|
+
export interface SourceSameRaw {
|
|
361
|
+
digest: string;
|
|
362
|
+
at: string;
|
|
363
|
+
receivedAt: number;
|
|
109
364
|
}
|
|
110
365
|
/** One poll of one declared source (`raw.kind: 'source-poll'`). */
|
|
111
366
|
export interface SourcePollRaw extends SourceDeclRaw {
|
|
@@ -124,12 +379,62 @@ export interface SourcePollRaw extends SourceDeclRaw {
|
|
|
124
379
|
reportEveryMs: number;
|
|
125
380
|
/** Polls in a row that failed (`unreachable`/`refused`/`malformed`) — the gateway backs off while it grows. */
|
|
126
381
|
failures?: number;
|
|
127
|
-
/**
|
|
382
|
+
/**
|
|
383
|
+
* A QUEUE source's LAST GOOD snapshot: this poll's when `current`, else the one before (kept, with its age), if any.
|
|
384
|
+
* Absent with `same` when it is the one an earlier report carried.
|
|
385
|
+
*/
|
|
128
386
|
snapshot?: QueueSnapshotRaw;
|
|
387
|
+
/** A LOOP source's last good snapshot — the same rules as `snapshot`. */
|
|
388
|
+
loop?: LoopSnapshotRaw;
|
|
389
|
+
/** A STORE source's. */
|
|
390
|
+
store?: StoreSnapshotRaw;
|
|
391
|
+
/** A TRAFFIC source's (a push-only one is never polled). */
|
|
392
|
+
traffic?: TrafficSnapshotRaw;
|
|
393
|
+
/** In place of the kind's snapshot ({@link SOURCE_SNAPSHOT_FIELD}): unchanged since the report that carried it in full. */
|
|
394
|
+
same?: SourceSameRaw;
|
|
129
395
|
/** The owning workspace (stamped by the gateway on every service event). */
|
|
130
396
|
wsKey?: string;
|
|
131
397
|
floodSuppressed?: number;
|
|
132
398
|
}
|
|
399
|
+
/**
|
|
400
|
+
* One event an app PUSHED about a source (`source: 'custom'`, `category: 'backend'`, `raw.kind: 'source-event'`),
|
|
401
|
+
* written by `lensEmitCustom` in the app's own process with the flow context it ran in (`context.flowId`/`requestId`/
|
|
402
|
+
* `runId`) — so it joins that request's or job's flow like any tapped event. Bounded: one flood bucket per (service,
|
|
403
|
+
* kind, name, event) — and per channel for traffic — so a burst of `enqueued` never starves `completed`.
|
|
404
|
+
*/
|
|
405
|
+
export interface SourceEventRaw {
|
|
406
|
+
kind: 'source-event';
|
|
407
|
+
provenance: typeof SOURCE_PROVENANCE;
|
|
408
|
+
/** The service (its Nx project) — what the source's declaration is under. */
|
|
409
|
+
project: string;
|
|
410
|
+
sourceKind: SourceKindRead;
|
|
411
|
+
/** The declared source's `name`. */
|
|
412
|
+
name: string;
|
|
413
|
+
/** One of the kind's {@link SOURCE_PUSH_EVENTS}. */
|
|
414
|
+
event: string;
|
|
415
|
+
/** The item's own id (an outbox row), at most 200 characters. */
|
|
416
|
+
item?: string;
|
|
417
|
+
/** The snapshot group it belongs to (the wire's group `key`), at most 200 characters. */
|
|
418
|
+
group?: string;
|
|
419
|
+
/** A loop's `run-end`: items the run took. */
|
|
420
|
+
items?: number;
|
|
421
|
+
durationMs?: number;
|
|
422
|
+
/** A loop's `run-end` ({@link LOOP_OUTCOMES}); a traffic message's ({@link TRAFFIC_OUTCOMES}). */
|
|
423
|
+
outcome?: LoopOutcome | TrafficOutcome;
|
|
424
|
+
/** A store's: the object — an id or a hash, never a name that holds personal data — at most 200 characters. */
|
|
425
|
+
object?: string;
|
|
426
|
+
/** A store's `write`; a traffic message's size. */
|
|
427
|
+
bytes?: number;
|
|
428
|
+
/** A traffic message's channel (the snapshot channel's key), at most 200 characters. */
|
|
429
|
+
channel?: string;
|
|
430
|
+
/** A traffic message's other end, at most 200 characters. */
|
|
431
|
+
counterpart?: string;
|
|
432
|
+
/** A traffic message's correlation id (what joins an inbound to the outbound it caused), at most 200 characters. */
|
|
433
|
+
correlation?: string;
|
|
434
|
+
/** A `failed` item or a failed run: why, at most 500 characters. */
|
|
435
|
+
error?: string;
|
|
436
|
+
floodSuppressed?: number;
|
|
437
|
+
}
|
|
133
438
|
/** A service's `cluster.sources`, as the gateway read it (`raw.kind: 'source-declaration'`). */
|
|
134
439
|
export interface SourceDeclarationRaw {
|
|
135
440
|
kind: 'source-declaration';
|
|
@@ -142,6 +447,8 @@ export interface SourceDeclarationRaw {
|
|
|
142
447
|
}
|
|
143
448
|
/** A `source-poll` event's `raw`, checked just enough to be read safely (telemetry is only partly trusted). */
|
|
144
449
|
export declare function asSourcePollRaw(raw: unknown): SourcePollRaw | undefined;
|
|
450
|
+
/** A `source-event` event's `raw` (pushed by an app), checked just enough to be read safely. */
|
|
451
|
+
export declare function asSourceEventRaw(raw: unknown): SourceEventRaw | undefined;
|
|
145
452
|
/** A `source-declaration` event's `raw`, checked just enough to be read safely. */
|
|
146
453
|
export declare function asSourceDeclarationRaw(raw: unknown): SourceDeclarationRaw | undefined;
|
|
147
454
|
/** One queue group, as the lens shows it. */
|
|
@@ -150,6 +457,14 @@ export interface QueueGroupView extends QueueGroupRaw {
|
|
|
150
457
|
oldestWaitMs?: number;
|
|
151
458
|
/** That wait is longer than the source's `thresholds.oldestWaitMin`. */
|
|
152
459
|
overThreshold: boolean;
|
|
460
|
+
/**
|
|
461
|
+
* How long its pending work has not moved, as far as the lens has watched it (since this lens started, or since the
|
|
462
|
+
* work last moved): nothing taken (`pending` did not fall, `oldestPendingAt` did not advance), nothing finished
|
|
463
|
+
* (`completedInWindow` 0), no `admitted`/`completed` pushed. Absent when nothing is pending or it moved just now.
|
|
464
|
+
*/
|
|
465
|
+
stillMs?: number;
|
|
466
|
+
/** `stillMs` is at least the source's `thresholds.stalledMin`. */
|
|
467
|
+
stalled: boolean;
|
|
153
468
|
}
|
|
154
469
|
/** A queue source's headline numbers. */
|
|
155
470
|
export interface QueueHeadline extends QueueTotals {
|
|
@@ -157,6 +472,95 @@ export interface QueueHeadline extends QueueTotals {
|
|
|
157
472
|
oldestWaitMs?: number;
|
|
158
473
|
/** Groups whose oldest wait is over the threshold. */
|
|
159
474
|
overThreshold: number;
|
|
475
|
+
/** Groups stalled. */
|
|
476
|
+
stalled: number;
|
|
477
|
+
}
|
|
478
|
+
/** One point of a queue source's history: what one `current` read said. */
|
|
479
|
+
export interface QueueHistoryPoint {
|
|
480
|
+
/** When the gateway received it (epoch ms). */
|
|
481
|
+
t: number;
|
|
482
|
+
pending: number;
|
|
483
|
+
inFlight: number;
|
|
484
|
+
failed: number;
|
|
485
|
+
oldestWaitMs?: number;
|
|
486
|
+
}
|
|
487
|
+
/** One run of a loop: seen in a snapshot (its `lastRunAt` moved) or pushed (`run-end`). */
|
|
488
|
+
export interface LoopRunView {
|
|
489
|
+
/** When it began (epoch ms) — `lastRunAt`, or the pushed `run-end`'s time less its duration. */
|
|
490
|
+
at: number;
|
|
491
|
+
outcome?: LoopOutcome;
|
|
492
|
+
items?: number;
|
|
493
|
+
durationMs?: number;
|
|
494
|
+
error?: string;
|
|
495
|
+
via: 'snapshot' | 'pushed';
|
|
496
|
+
}
|
|
497
|
+
/** A loop source's headline, from its last good snapshot and the runs the lens saw. */
|
|
498
|
+
export interface LoopView {
|
|
499
|
+
intervalSec: number;
|
|
500
|
+
lastRunAt: string | null;
|
|
501
|
+
lastDurationMs?: number;
|
|
502
|
+
lastOutcome?: LoopOutcome;
|
|
503
|
+
lastItems?: number;
|
|
504
|
+
nextRunAt?: string | null;
|
|
505
|
+
runsInWindow?: number;
|
|
506
|
+
itemsInWindow?: number;
|
|
507
|
+
failuresInWindow?: number;
|
|
508
|
+
windowSec?: number;
|
|
509
|
+
lastError?: string;
|
|
510
|
+
/** How late its next run was when the service measured it — past `nextRunAt` (or `lastRunAt` + its interval). */
|
|
511
|
+
lateMs?: number;
|
|
512
|
+
/** Late by more than {@link LOOP_OVERDUE_INTERVALS} of its intervals. */
|
|
513
|
+
overdue: boolean;
|
|
514
|
+
/** Runs in a row that failed, the newest back. */
|
|
515
|
+
failingRuns: number;
|
|
516
|
+
/** Since when (epoch ms) it has run and taken nothing while the queue it feeds had work — when it does now. */
|
|
517
|
+
idleSince?: number;
|
|
518
|
+
/** The queue source it `feeds`, as read now (absent: it declares none, or none of that name). */
|
|
519
|
+
fed?: {
|
|
520
|
+
name: string;
|
|
521
|
+
state: SourceState;
|
|
522
|
+
pending?: number;
|
|
523
|
+
};
|
|
524
|
+
/**
|
|
525
|
+
* PUSH-ONLY (declared with no route): built from the runs the app pushed (`run-start` / `run-end`), judged on the
|
|
526
|
+
* lens's own clock — `lateMs` is how long after its period its next run is now, with `intervalSec` its declared period.
|
|
527
|
+
*/
|
|
528
|
+
pushOnly?: boolean;
|
|
529
|
+
/** Push-only: a run began (`run-start`) and has not ended — since when (epoch ms). */
|
|
530
|
+
runningSince?: number;
|
|
531
|
+
}
|
|
532
|
+
/** One event an app pushed about a source. */
|
|
533
|
+
export interface SourcePushedEvent {
|
|
534
|
+
at: number;
|
|
535
|
+
event: string;
|
|
536
|
+
item?: string;
|
|
537
|
+
group?: string;
|
|
538
|
+
items?: number;
|
|
539
|
+
durationMs?: number;
|
|
540
|
+
outcome?: LoopOutcome | TrafficOutcome;
|
|
541
|
+
/** A store's object (an id or a hash). */
|
|
542
|
+
object?: string;
|
|
543
|
+
bytes?: number;
|
|
544
|
+
/** A traffic message's channel, other end and correlation id. */
|
|
545
|
+
channel?: string;
|
|
546
|
+
counterpart?: string;
|
|
547
|
+
correlation?: string;
|
|
548
|
+
error?: string;
|
|
549
|
+
/** The flow it ran in — open it with flow.get. */
|
|
550
|
+
flowId?: string;
|
|
551
|
+
requestId?: string;
|
|
552
|
+
}
|
|
553
|
+
/** What an app pushed about one source since this lens started. */
|
|
554
|
+
export interface SourcePushedView {
|
|
555
|
+
/** Per event name. */
|
|
556
|
+
counts: Record<string, number>;
|
|
557
|
+
/** When the first one reached this lens (epoch ms). */
|
|
558
|
+
since: number;
|
|
559
|
+
lastAt: number;
|
|
560
|
+
/** The newest first, at most {@link SOURCE_PUSHED_KEPT}. */
|
|
561
|
+
recent: SourcePushedEvent[];
|
|
562
|
+
/** Events the app's flood guard held back (they are in no count). */
|
|
563
|
+
suppressed?: number;
|
|
160
564
|
}
|
|
161
565
|
/** One declared source, as the lens shows it. */
|
|
162
566
|
export interface SourceView extends SourceDeclRaw {
|
|
@@ -173,25 +577,121 @@ export interface SourceView extends SourceDeclRaw {
|
|
|
173
577
|
ageMs?: number;
|
|
174
578
|
/** When the service measured the last good snapshot (its `at`). */
|
|
175
579
|
snapshotAt?: string;
|
|
580
|
+
/** A queue's. */
|
|
176
581
|
headline?: QueueHeadline;
|
|
177
|
-
/**
|
|
582
|
+
/** A queue's, the oldest-waiting first. Empty with `state: 'current'` and a headline is a real «nothing pending». */
|
|
178
583
|
groups: QueueGroupView[];
|
|
179
584
|
truncated?: {
|
|
180
585
|
groups: number;
|
|
181
586
|
};
|
|
587
|
+
/** A queue's `current` reads, oldest first, at most {@link SOURCE_HISTORY_POINTS}. */
|
|
588
|
+
history?: QueueHistoryPoint[];
|
|
589
|
+
/** A loop's, from its last good snapshot. */
|
|
590
|
+
loop?: LoopView;
|
|
591
|
+
/** A loop's runs, the newest first, at most {@link SOURCE_RUNS_KEPT}. */
|
|
592
|
+
runs?: LoopRunView[];
|
|
593
|
+
/** A store's, from its last good snapshot. */
|
|
594
|
+
store?: StoreView;
|
|
595
|
+
/** A store's `current` reads, oldest first, at most {@link SOURCE_HISTORY_POINTS}. */
|
|
596
|
+
storeHistory?: StoreHistoryPoint[];
|
|
597
|
+
/** A traffic source's: from its last good snapshot, or — push-only — from what the app pushed in the window. */
|
|
598
|
+
traffic?: TrafficView;
|
|
599
|
+
/** What the app pushed about it (`lensEmitCustom`), when it pushed anything. */
|
|
600
|
+
pushed?: SourcePushedView;
|
|
601
|
+
}
|
|
602
|
+
/** A store's headline, from its last good snapshot and the reads the lens watched. */
|
|
603
|
+
export interface StoreView {
|
|
604
|
+
objects: number;
|
|
605
|
+
bytes: number;
|
|
606
|
+
quotaBytes?: number | null;
|
|
607
|
+
/** `bytes` as a percent of `quotaBytes` (one decimal). */
|
|
608
|
+
usedPct?: number;
|
|
609
|
+
/** `usedPct` is at or over `thresholds.quotaPct`. */
|
|
610
|
+
nearQuota: boolean;
|
|
611
|
+
opsInWindow?: number;
|
|
612
|
+
writesInWindow?: number;
|
|
613
|
+
deletesInWindow?: number;
|
|
614
|
+
errorsInWindow?: number;
|
|
615
|
+
/** `errorsInWindow` as a percent of `opsInWindow`, when it says both. */
|
|
616
|
+
errorRatePct?: number;
|
|
617
|
+
windowSec?: number;
|
|
618
|
+
lastWriteAt?: string | null;
|
|
619
|
+
lastError?: string;
|
|
620
|
+
/**
|
|
621
|
+
* Since when (epoch ms) it has grown with nothing deleted, as the lens watched it: its objects rose, never fell, no
|
|
622
|
+
* `deletesInWindow`, no pushed `delete`. Absent when it deleted lately, did not grow, or was not watched long enough.
|
|
623
|
+
*/
|
|
624
|
+
growingSince?: number;
|
|
625
|
+
/** Its objects when that spell began. */
|
|
626
|
+
growingFrom?: number;
|
|
627
|
+
/** The largest first. */
|
|
628
|
+
groups?: StoreGroupRaw[];
|
|
629
|
+
truncated?: {
|
|
630
|
+
groups: number;
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
/** One point of a store's history: what one `current` read said. */
|
|
634
|
+
export interface StoreHistoryPoint {
|
|
635
|
+
t: number;
|
|
636
|
+
objects: number;
|
|
637
|
+
bytes: number;
|
|
638
|
+
}
|
|
639
|
+
/** One channel of a traffic source, as the lens shows it. */
|
|
640
|
+
export interface TrafficChannelView extends TrafficChannelRaw {
|
|
641
|
+
/** `failuresInWindow` as a percent of `messagesInWindow` (one decimal). */
|
|
642
|
+
failurePct?: number;
|
|
643
|
+
/** Over `thresholds.failurePct`, on at least {@link TRAFFIC_MIN_MESSAGES} messages. */
|
|
644
|
+
overFailure: boolean;
|
|
645
|
+
/** `p95Ms` over `thresholds.p95Ms`. */
|
|
646
|
+
overLatency: boolean;
|
|
647
|
+
/** `rateLimitedInWindow` at or over `thresholds.rateLimited`. */
|
|
648
|
+
rateLimited: boolean;
|
|
649
|
+
}
|
|
650
|
+
/** A traffic source's headline. */
|
|
651
|
+
export interface TrafficView {
|
|
652
|
+
/** Counted by the lens from the app's pushed events (no route declared), not answered by the service. */
|
|
653
|
+
pushOnly: boolean;
|
|
654
|
+
/** The window its counts are over, in seconds — the service's, or {@link TRAFFIC_PUSH_WINDOW_MS} push-only. */
|
|
655
|
+
windowSec?: number;
|
|
656
|
+
/** The channel with the most messages first. */
|
|
657
|
+
channels: TrafficChannelView[];
|
|
658
|
+
truncated?: {
|
|
659
|
+
channels: number;
|
|
660
|
+
};
|
|
661
|
+
totals: {
|
|
662
|
+
channels: number;
|
|
663
|
+
messages: number;
|
|
664
|
+
failures: number;
|
|
665
|
+
rateLimited: number;
|
|
666
|
+
};
|
|
667
|
+
/** Push-only: events the app's flood guard held back in the window — every count is then a floor. */
|
|
668
|
+
heldBack?: number;
|
|
182
669
|
}
|
|
183
|
-
/**
|
|
670
|
+
/**
|
|
671
|
+
* Something a source's numbers say is wrong — from what was read NOW (`current`) only: anything older is not known to
|
|
672
|
+
* be true. Which fields are set depends on the rule.
|
|
673
|
+
*/
|
|
184
674
|
export interface SourceFinding {
|
|
185
|
-
rule:
|
|
675
|
+
rule: SourceRule;
|
|
186
676
|
provenance: typeof SOURCE_PROVENANCE;
|
|
187
677
|
project: string;
|
|
188
678
|
name: string;
|
|
189
679
|
sourceKind: SourceKindRead;
|
|
190
|
-
group
|
|
680
|
+
/** A queue rule's group. */
|
|
681
|
+
group?: string;
|
|
682
|
+
/** A traffic rule's channel. */
|
|
683
|
+
channel?: string;
|
|
191
684
|
labels?: Record<string, string>;
|
|
192
|
-
pending
|
|
193
|
-
|
|
194
|
-
|
|
685
|
+
pending?: number;
|
|
686
|
+
/** `queue/oldest-wait`. */
|
|
687
|
+
oldestWaitMs?: number;
|
|
688
|
+
/** How long it has held: the stall, the idle spell, how late the run is, how long the runs have failed, the growth. */
|
|
689
|
+
forMs?: number;
|
|
690
|
+
/** The threshold it is over, in minutes (`loop/overdue` and `loop/failing` have none). */
|
|
691
|
+
thresholdMin?: number;
|
|
692
|
+
/** A store or traffic rule's measure — a percent, milliseconds or a count, as its title says — and its threshold. */
|
|
693
|
+
value?: number;
|
|
694
|
+
threshold?: number;
|
|
195
695
|
title: string;
|
|
196
696
|
fix: string[];
|
|
197
697
|
verify: string;
|
|
@@ -215,6 +715,14 @@ export interface SourcesReport {
|
|
|
215
715
|
project: string;
|
|
216
716
|
problem: string;
|
|
217
717
|
}>;
|
|
718
|
+
/** Sources an app pushes events about that no `cluster.sources` entry of that service declares — read nowhere. */
|
|
719
|
+
undeclared?: Array<{
|
|
720
|
+
project: string;
|
|
721
|
+
sourceKind: SourceKindRead;
|
|
722
|
+
name: string;
|
|
723
|
+
events: number;
|
|
724
|
+
lastAt: number;
|
|
725
|
+
}>;
|
|
218
726
|
counts: Record<SourceState, number>;
|
|
219
727
|
/** Over the `current` queue snapshots only. */
|
|
220
728
|
totals: {
|
package/lib/sources.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var T=Object.defineProperty;var a=(t,r)=>T(t,"name",{value:r,configurable:!0});var U=Object.defineProperty,e=a((t,r)=>U(t,"name",{value:r,configurable:!0}),"r");export const SOURCE_KINDS=["queue","loop","store","traffic"],SOURCE_KINDS_READ=["queue","loop","store","traffic"],sourceWireSchema=e(t=>`lensmcp.${t}/v1`,"sourceWireSchema"),QUEUE_WIRE_SCHEMA="lensmcp.queue/v1",LOOP_WIRE_SCHEMA="lensmcp.loop/v1",STORE_WIRE_SCHEMA="lensmcp.store/v1",TRAFFIC_WIRE_SCHEMA="lensmcp.traffic/v1",SOURCE_SNAPSHOT_FIELD={queue:"snapshot",loop:"loop",store:"store",traffic:"traffic"},URI_SOURCES="process://sources",SOURCE_PROVENANCE="reported",QUEUE_OLDEST_WAIT_RULE="queue/oldest-wait",QUEUE_STALLED_RULE="queue/stalled",LOOP_OVERDUE_RULE="loop/overdue",LOOP_FAILING_RULE="loop/failing",LOOP_IDLE_RULE="loop/idle-while-fed",STORE_QUOTA_RULE="store/near-quota",STORE_ERRORS_RULE="store/errors",STORE_ORPHANS_RULE="store/orphans",TRAFFIC_FAILURES_RULE="traffic/failures",TRAFFIC_LATENCY_RULE="traffic/latency",TRAFFIC_RATE_LIMITED_RULE="traffic/rate-limited",SOURCE_RULES=[QUEUE_OLDEST_WAIT_RULE,QUEUE_STALLED_RULE,LOOP_OVERDUE_RULE,LOOP_FAILING_RULE,LOOP_IDLE_RULE,STORE_QUOTA_RULE,STORE_ERRORS_RULE,STORE_ORPHANS_RULE,TRAFFIC_FAILURES_RULE,TRAFFIC_LATENCY_RULE,TRAFFIC_RATE_LIMITED_RULE],SOURCE_EVENT_KINDS=["source-poll","source-declaration","source-event"],CUSTOM_EVENT_SOURCE="custom",QUEUE_EVENTS=["enqueued","admitted","completed","failed","parked"],LOOP_EVENTS=["run-start","run-end"],LOOP_OUTCOMES=["ok","failed","skipped"],STORE_EVENTS=["write","delete","error"],TRAFFIC_EVENTS=["inbound","outbound"],TRAFFIC_OUTCOMES=["ok","failed","rate-limited"],SOURCE_PUSH_EVENTS={queue:QUEUE_EVENTS,loop:LOOP_EVENTS,store:STORE_EVENTS,traffic:TRAFFIC_EVENTS},SOURCE_PUSH_OUTCOMES={queue:[],loop:LOOP_OUTCOMES,store:[],traffic:TRAFFIC_OUTCOMES},SOURCE_POLL_STATES=["current","unreachable","refused","malformed","not-running"],SOURCE_STATES=[...SOURCE_POLL_STATES,"stale","never-polled"],SOURCE_DEFAULT_INTERVAL_SEC=10,SOURCE_MIN_INTERVAL_SEC=2,QUEUE_DEFAULT_OLDEST_WAIT_MIN=10,QUEUE_DEFAULT_STALLED_MIN=15,LOOP_DEFAULT_IDLE_MIN=10,LOOP_OVERDUE_INTERVALS=2,LOOP_FAILING_RUNS=3,SOURCE_FULL_REPORT_MS=6e4,SOURCE_HISTORY_POINTS=60,SOURCE_RUNS_KEPT=30,SOURCE_PUSHED_KEPT=20,STORE_DEFAULT_QUOTA_PCT=90,STORE_DEFAULT_ERROR_RATE_PCT=5,STORE_DEFAULT_ORPHAN_MIN=60,TRAFFIC_DEFAULT_FAILURE_PCT=5,TRAFFIC_DEFAULT_P95_MS=2e3,TRAFFIC_DEFAULT_RATE_LIMITED=1,TRAFFIC_MIN_MESSAGES=10,TRAFFIC_PUSH_WINDOW_MS=10*6e4,TRAFFIC_PUSH_CHANNELS=50,TRAFFIC_PUSH_EVENTS_PER_CHANNEL=1e3,SOURCE_MAX_GROUPS=500,SOURCE_MAX_BYTES=256*1024,SOURCE_STALE_PERIODS=3,SOURCE_STALE_MIN_MS=3e4;export function sourceStaleAfterMs(t){return Math.max(SOURCE_STALE_MIN_MS,SOURCE_STALE_PERIODS*Math.max(0,t))}a(sourceStaleAfterMs,"sourceStaleAfterMs"),e(sourceStaleAfterMs,"sourceStaleAfterMs");const n=e(t=>typeof t=="object"&&t!==null&&!Array.isArray(t),"isObj"),s=e(t=>typeof t=="number"&&Number.isInteger(t)&&t>=0,"isCount"),E=e(t=>typeof t=="number"&&Number.isFinite(t)&&t>0,"isTime"),u=e((t,r)=>typeof t=="string"&&t.length>0&&t.length<=r,"isStr"),v=e(t=>t===void 0||typeof t=="number"&&t>0,"isMin");function _(t){if(!SOURCE_KINDS_READ.includes(t.sourceKind)||typeof t.path!="string"&&!(t.path===void 0&&(t.sourceKind==="traffic"||t.sourceKind==="loop"))||!u(t.name,200)||typeof t.intervalSec!="number"||t.feeds!==void 0&&!u(t.feeds,200))return!1;const r=t.thresholds;if(!n(r))return!1;for(const o of["stalledMin","idleMin","oldestWaitMin","quotaPct","errorRatePct","orphanMin","failurePct","p95Ms","rateLimited"])if(!v(r[o]))return!1;return t.sourceKind!=="queue"||typeof r.oldestWaitMin=="number"}a(_,"l"),e(_,"asDecl");const l=e(t=>t===null||typeof t=="string","isIsoOrNull"),c=e(t=>t===void 0||s(t),"isOptCount");function d(t){if(!n(t)||typeof t.at!="string"||!E(t.receivedAt)||!E(t.intervalSec)||!l(t.lastRunAt)||t.nextRunAt!==void 0&&!l(t.nextRunAt))return!1;for(const r of["lastDurationMs","lastItems","runsInWindow","itemsInWindow","failuresInWindow","windowSec"])if(!c(t[r]))return!1;return t.lastOutcome!==void 0&&!LOOP_OUTCOMES.includes(t.lastOutcome)?!1:t.lastError===void 0||typeof t.lastError=="string"}a(d,"_"),e(d,"asLoopSnapshot");const f=e(t=>t===void 0||n(t)&&Object.values(t).every(r=>typeof r=="string"),"isLabels");function S(t){if(!n(t)||typeof t.at!="string"||!E(t.receivedAt)||!s(t.objects)||!s(t.bytes)||t.quotaBytes!==void 0&&t.quotaBytes!==null&&!s(t.quotaBytes))return!1;for(const i of["opsInWindow","writesInWindow","deletesInWindow","errorsInWindow","windowSec"])if(!c(t[i]))return!1;if(t.lastWriteAt!==void 0&&!l(t.lastWriteAt)||t.lastError!==void 0&&typeof t.lastError!="string")return!1;const r=t.truncated;if(r!==void 0&&!(n(r)&&s(r.groups)))return!1;const o=t.groups;return o===void 0?!0:Array.isArray(o)&&o.length<=SOURCE_MAX_GROUPS&&o.every(i=>n(i)&&u(i.group,1e3)&&s(i.objects)&&s(i.bytes)&&f(i.labels))}a(S,"S"),e(S,"asStoreSnapshot");function p(t){if(!n(t)||typeof t.at!="string"||!E(t.receivedAt)||!Array.isArray(t.channels)||!c(t.windowSec))return!1;const r=t.truncated;return r!==void 0&&!(n(r)&&s(r.channels))?!1:t.channels.length<=SOURCE_MAX_GROUPS&&t.channels.every(o=>{if(!n(o)||!u(o.channel,1e3)||!f(o.labels)||o.direction!==void 0&&o.direction!=="inbound"&&o.direction!=="outbound"||o.counterpart!==void 0&&!u(o.counterpart,200))return!1;for(const i of["messagesInWindow","failuresInWindow","rateLimitedInWindow"])if(!c(o[i]))return!1;return o.p95Ms!==void 0&&!(typeof o.p95Ms=="number"&&Number.isFinite(o.p95Ms)&&o.p95Ms>=0)||o.lastAt!==void 0&&!l(o.lastAt)?!1:o.lastError===void 0||typeof o.lastError=="string"})}a(p,"R"),e(p,"asTrafficSnapshot");function R(t){return n(t)&&u(t.digest,100)&&typeof t.at=="string"&&E(t.receivedAt)}a(R,"A"),e(R,"asSame");function A(t){if(!n(t)||!u(t.group,1e3)||!s(t.pending))return!1;for(const i of["inFlight","failed","completedInWindow"])if(t[i]!==void 0&&!s(t[i]))return!1;const r=t.oldestPendingAt;if(r!=null&&typeof r!="string")return!1;const o=t.labels;return o===void 0||n(o)&&Object.values(o).every(i=>typeof i=="string")}a(A,"O"),e(A,"asGroup");function O(t){if(!n(t)||typeof t.at!="string"||!E(t.receivedAt)||!Array.isArray(t.groups))return!1;const r=t.totals;if(!n(r)||!s(r.groups)||!s(r.pending)||!s(r.inFlight)||!s(r.failed))return!1;const o=t.truncated;return o!==void 0&&!(n(o)&&s(o.groups))?!1:t.groups.length<=SOURCE_MAX_GROUPS&&t.groups.every(A)}a(O,"T"),e(O,"asSnapshot");export function asSourcePollRaw(t){if(!n(t)||t.kind!=="source-poll"||!u(t.project,200)||!_(t)||!SOURCE_POLL_STATES.includes(t.state)||!E(t.polledAt)||!E(t.reportEveryMs)||t.path===void 0)return;const r=SOURCE_SNAPSHOT_FIELD[t.sourceKind];for(const i of Object.values(SOURCE_SNAPSHOT_FIELD))if(i!==r&&t[i]!==void 0)return;const o={snapshot:O,loop:d,store:S,traffic:p}[r];if(!(t[r]!==void 0&&!o(t[r]))&&!(t.same!==void 0&&(!R(t.same)||t[r]!==void 0))&&!(t.state==="current"&&t[r]===void 0&&t.same===void 0))return t}a(asSourcePollRaw,"asSourcePollRaw"),e(asSourcePollRaw,"asSourcePollRaw");export function asSourceEventRaw(t){if(!n(t)||t.kind!=="source-event"||!u(t.project,200)||!u(t.name,200))return;const r=t.sourceKind;if(SOURCE_KINDS_READ.includes(r)&&SOURCE_PUSH_EVENTS[r].includes(t.event)&&!(t.item!==void 0&&!u(t.item,200)||t.group!==void 0&&!u(t.group,200))&&!(!c(t.items)||!c(t.durationMs)||!c(t.bytes))&&!(t.outcome!==void 0&&!SOURCE_PUSH_OUTCOMES[r].includes(t.outcome))){for(const o of["object","channel","counterpart","correlation"])if(t[o]!==void 0&&!u(t[o],200))return;if(!(t.error!==void 0&&typeof t.error!="string"))return t}}a(asSourceEventRaw,"asSourceEventRaw"),e(asSourceEventRaw,"asSourceEventRaw");export function asSourceDeclarationRaw(t){if(!(!n(t)||t.kind!=="source-declaration"||!u(t.project,200))&&!(!Array.isArray(t.sources)||!t.sources.every(r=>n(r)&&_(r)))&&!(!Array.isArray(t.problems)||!t.problems.every(r=>typeof r=="string")))return t}a(asSourceDeclarationRaw,"asSourceDeclarationRaw"),e(asSourceDeclarationRaw,"asSourceDeclarationRaw");
|