@marinoscar/platform-contract 0.0.0-stage → 0.1.0-next.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +145 -2
  4. package/dist/cjs/doctor/constants.d.ts +59 -0
  5. package/dist/cjs/doctor/constants.d.ts.map +1 -0
  6. package/dist/cjs/doctor/constants.js +57 -0
  7. package/dist/cjs/doctor/constants.js.map +1 -0
  8. package/dist/cjs/doctor/index.d.ts +5 -0
  9. package/dist/cjs/doctor/index.d.ts.map +1 -0
  10. package/dist/cjs/doctor/index.js +24 -0
  11. package/dist/cjs/doctor/index.js.map +1 -0
  12. package/dist/cjs/doctor/schemas.d.ts +186 -0
  13. package/dist/cjs/doctor/schemas.d.ts.map +1 -0
  14. package/dist/cjs/doctor/schemas.js +183 -0
  15. package/dist/cjs/doctor/schemas.js.map +1 -0
  16. package/dist/cjs/index.d.ts +13 -0
  17. package/dist/cjs/index.d.ts.map +1 -0
  18. package/dist/cjs/index.js +16 -0
  19. package/dist/cjs/index.js.map +1 -0
  20. package/dist/cjs/package.json +3 -0
  21. package/dist/cjs/telemetry/assistant.d.ts +173 -0
  22. package/dist/cjs/telemetry/assistant.d.ts.map +1 -0
  23. package/dist/cjs/telemetry/assistant.js +43 -0
  24. package/dist/cjs/telemetry/assistant.js.map +1 -0
  25. package/dist/cjs/telemetry/config.d.ts +92 -0
  26. package/dist/cjs/telemetry/config.d.ts.map +1 -0
  27. package/dist/cjs/telemetry/config.js +101 -0
  28. package/dist/cjs/telemetry/config.js.map +1 -0
  29. package/dist/cjs/telemetry/connection.d.ts +355 -0
  30. package/dist/cjs/telemetry/connection.d.ts.map +1 -0
  31. package/dist/cjs/telemetry/connection.js +451 -0
  32. package/dist/cjs/telemetry/connection.js.map +1 -0
  33. package/dist/cjs/telemetry/constants.d.ts +442 -0
  34. package/dist/cjs/telemetry/constants.d.ts.map +1 -0
  35. package/dist/cjs/telemetry/constants.js +400 -0
  36. package/dist/cjs/telemetry/constants.js.map +1 -0
  37. package/dist/cjs/telemetry/dashboard.d.ts +826 -0
  38. package/dist/cjs/telemetry/dashboard.d.ts.map +1 -0
  39. package/dist/cjs/telemetry/dashboard.js +697 -0
  40. package/dist/cjs/telemetry/dashboard.js.map +1 -0
  41. package/dist/cjs/telemetry/enum.d.ts +5 -0
  42. package/dist/cjs/telemetry/enum.d.ts.map +1 -0
  43. package/dist/cjs/telemetry/enum.js +12 -0
  44. package/dist/cjs/telemetry/enum.js.map +1 -0
  45. package/dist/cjs/telemetry/index.d.ts +5 -0
  46. package/dist/cjs/telemetry/index.d.ts.map +1 -0
  47. package/dist/cjs/telemetry/index.js +128 -0
  48. package/dist/cjs/telemetry/index.js.map +1 -0
  49. package/dist/cjs/telemetry/query.d.ts +147 -0
  50. package/dist/cjs/telemetry/query.d.ts.map +1 -0
  51. package/dist/cjs/telemetry/query.js +141 -0
  52. package/dist/cjs/telemetry/query.js.map +1 -0
  53. package/dist/cjs/telemetry/schemas.d.ts +17 -0
  54. package/dist/cjs/telemetry/schemas.d.ts.map +1 -0
  55. package/dist/cjs/telemetry/schemas.js +89 -0
  56. package/dist/cjs/telemetry/schemas.js.map +1 -0
  57. package/dist/cjs/telemetry/settings.d.ts +65 -0
  58. package/dist/cjs/telemetry/settings.d.ts.map +1 -0
  59. package/dist/cjs/telemetry/settings.js +77 -0
  60. package/dist/cjs/telemetry/settings.js.map +1 -0
  61. package/dist/cjs/telemetry/stack.d.ts +87 -0
  62. package/dist/cjs/telemetry/stack.d.ts.map +1 -0
  63. package/dist/cjs/telemetry/stack.js +93 -0
  64. package/dist/cjs/telemetry/stack.js.map +1 -0
  65. package/dist/cjs/telemetry/status.d.ts +65 -0
  66. package/dist/cjs/telemetry/status.d.ts.map +1 -0
  67. package/dist/cjs/telemetry/status.js +65 -0
  68. package/dist/cjs/telemetry/status.js.map +1 -0
  69. package/dist/esm/doctor/constants.d.ts +59 -0
  70. package/dist/esm/doctor/constants.d.ts.map +1 -0
  71. package/dist/esm/doctor/constants.js +54 -0
  72. package/dist/esm/doctor/constants.js.map +1 -0
  73. package/dist/esm/doctor/index.d.ts +5 -0
  74. package/dist/esm/doctor/index.d.ts.map +1 -0
  75. package/dist/esm/doctor/index.js +10 -0
  76. package/dist/esm/doctor/index.js.map +1 -0
  77. package/dist/esm/doctor/schemas.d.ts +186 -0
  78. package/dist/esm/doctor/schemas.d.ts.map +1 -0
  79. package/dist/esm/doctor/schemas.js +180 -0
  80. package/dist/esm/doctor/schemas.js.map +1 -0
  81. package/dist/esm/index.d.ts +13 -0
  82. package/dist/esm/index.d.ts.map +1 -0
  83. package/dist/esm/index.js +13 -0
  84. package/dist/esm/index.js.map +1 -0
  85. package/dist/esm/package.json +3 -0
  86. package/dist/esm/telemetry/assistant.d.ts +173 -0
  87. package/dist/esm/telemetry/assistant.d.ts.map +1 -0
  88. package/dist/esm/telemetry/assistant.js +40 -0
  89. package/dist/esm/telemetry/assistant.js.map +1 -0
  90. package/dist/esm/telemetry/config.d.ts +92 -0
  91. package/dist/esm/telemetry/config.d.ts.map +1 -0
  92. package/dist/esm/telemetry/config.js +98 -0
  93. package/dist/esm/telemetry/config.js.map +1 -0
  94. package/dist/esm/telemetry/connection.d.ts +355 -0
  95. package/dist/esm/telemetry/connection.d.ts.map +1 -0
  96. package/dist/esm/telemetry/connection.js +447 -0
  97. package/dist/esm/telemetry/connection.js.map +1 -0
  98. package/dist/esm/telemetry/constants.d.ts +442 -0
  99. package/dist/esm/telemetry/constants.d.ts.map +1 -0
  100. package/dist/esm/telemetry/constants.js +397 -0
  101. package/dist/esm/telemetry/constants.js.map +1 -0
  102. package/dist/esm/telemetry/dashboard.d.ts +826 -0
  103. package/dist/esm/telemetry/dashboard.d.ts.map +1 -0
  104. package/dist/esm/telemetry/dashboard.js +690 -0
  105. package/dist/esm/telemetry/dashboard.js.map +1 -0
  106. package/dist/esm/telemetry/enum.d.ts +5 -0
  107. package/dist/esm/telemetry/enum.d.ts.map +1 -0
  108. package/dist/esm/telemetry/enum.js +9 -0
  109. package/dist/esm/telemetry/enum.js.map +1 -0
  110. package/dist/esm/telemetry/index.d.ts +5 -0
  111. package/dist/esm/telemetry/index.d.ts.map +1 -0
  112. package/dist/esm/telemetry/index.js +10 -0
  113. package/dist/esm/telemetry/index.js.map +1 -0
  114. package/dist/esm/telemetry/query.d.ts +147 -0
  115. package/dist/esm/telemetry/query.d.ts.map +1 -0
  116. package/dist/esm/telemetry/query.js +138 -0
  117. package/dist/esm/telemetry/query.js.map +1 -0
  118. package/dist/esm/telemetry/schemas.d.ts +17 -0
  119. package/dist/esm/telemetry/schemas.d.ts.map +1 -0
  120. package/dist/esm/telemetry/schemas.js +12 -0
  121. package/dist/esm/telemetry/schemas.js.map +1 -0
  122. package/dist/esm/telemetry/settings.d.ts +65 -0
  123. package/dist/esm/telemetry/settings.d.ts.map +1 -0
  124. package/dist/esm/telemetry/settings.js +74 -0
  125. package/dist/esm/telemetry/settings.js.map +1 -0
  126. package/dist/esm/telemetry/stack.d.ts +87 -0
  127. package/dist/esm/telemetry/stack.d.ts.map +1 -0
  128. package/dist/esm/telemetry/stack.js +90 -0
  129. package/dist/esm/telemetry/stack.js.map +1 -0
  130. package/dist/esm/telemetry/status.d.ts +65 -0
  131. package/dist/esm/telemetry/status.d.ts.map +1 -0
  132. package/dist/esm/telemetry/status.js +62 -0
  133. package/dist/esm/telemetry/status.js.map +1 -0
  134. package/package.json +78 -4
@@ -0,0 +1,697 @@
1
+ "use strict";
2
+ // =============================================================================
3
+ // Telemetry dashboard (issue #577; moved here from the API's
4
+ // `telemetry/dto/telemetry-dashboard.dto.ts` by #702)
5
+ // =============================================================================
6
+ //
7
+ // GET /api/admin/telemetry/dashboard/summary → telemetryDashboardSummarySchema
8
+ // GET /api/admin/telemetry/dashboard/timeseries → telemetryDashboardTimeseriesSchema
9
+ // GET /api/admin/telemetry/dashboard/top → telemetryDashboardTopSchema
10
+ // GET /api/admin/telemetry/dashboard/events → telemetryDashboardEventsSchema
11
+ // GET /api/admin/telemetry/dashboard/filters → telemetryDashboardFiltersSchema
12
+ // GET /api/admin/telemetry/dashboard/metrics → telemetryDashboardMetricsSchema (#601)
13
+ // GET /api/admin/telemetry/dashboard/metric-groups → telemetryDashboardMetricGroupsSchema (#680)
14
+ //
15
+ // Common query: `range` (15m|1h|6h|24h|7d, default 1h) OR `from`+`to` (ISO,
16
+ // from < to, to <= now + 1 min, span <= 30 days); `service`, `instance`
17
+ // (checked by the service against the values seen in the range);
18
+ // `buckets` (30|60, default 60). Every query value arrives as a string.
19
+ //
20
+ // METRIC GROUP IDS ARE AN OPEN SET (#680): the platform registers six and an
21
+ // app may register more, so the contract types `group` as an id (a string
22
+ // matching `METRIC_GROUP_ID_PATTERN`). A server that knows its registered set
23
+ // builds its own `/metrics` schemas with `createTelemetryDashboardMetricsQuerySchema`
24
+ // and `createTelemetryDashboardMetricsSchema`, passing the group schema it
25
+ // documents and checks (the API passes one read from its live registry).
26
+ //
27
+ // ⚠ OpenAPI is generated from these schemas. Field order, `.describe()` texts
28
+ // and enum order are part of the published document.
29
+ // =============================================================================
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.telemetryDashboardMetricGroupsSchema = exports.telemetryDashboardMetricGroupSchema = exports.telemetryDashboardMetricsSchema = exports.metricTableSchema = exports.metricCellSchema = exports.metricColumnSchema = exports.metricSeriesSchema = exports.metricPointSchema = exports.telemetryDashboardFiltersSchema = exports.telemetryDashboardEventsSchema = exports.dashboardEventSchema = exports.telemetryDashboardTopSchema = exports.topErrorSchema = exports.topRouteSchema = exports.telemetryDashboardTimeseriesSchema = exports.logsBucketSchema = exports.apiBucketSchema = exports.telemetryDashboardSummarySchema = exports.telemetryDashboardUnknownRoutesSchema = exports.unknownRouteSchema = exports.telemetryDashboardTileSchema = exports.telemetryDashboardEnvelopeSchema = exports.telemetryDashboardMetricsQuerySchema = exports.metricGroupIdSchema = exports.telemetryDashboardEventsQuerySchema = exports.telemetryDashboardTopQuerySchema = exports.telemetryDashboardTimeseriesQuerySchema = exports.telemetryDashboardQuerySchema = void 0;
32
+ exports.refineWindow = refineWindow;
33
+ exports.metricGroupQuerySchema = metricGroupQuerySchema;
34
+ exports.createTelemetryDashboardMetricsQuerySchema = createTelemetryDashboardMetricsQuerySchema;
35
+ exports.createTelemetryDashboardMetricsSchema = createTelemetryDashboardMetricsSchema;
36
+ const zod_1 = require("zod");
37
+ const constants_js_1 = require("./constants.js");
38
+ const enum_js_1 = require("./enum.js");
39
+ // ---- queries -----------------------------------------------------------------
40
+ const commonShape = {
41
+ /** Relative window ending now. Default `1h`. Not with `from`/`to`. */
42
+ range: (0, enum_js_1.wireEnum)(constants_js_1.DASHBOARD_RANGES).optional().describe('Relative window ending now. Default `1h`. Not with `from`/`to`.'),
43
+ /** Absolute window start (ISO 8601). Requires `to`. */
44
+ from: zod_1.z.iso.datetime({ offset: true }).optional().describe('Absolute window start (ISO 8601). Requires `to`.'),
45
+ /** Absolute window end (ISO 8601), at most 1 minute in the future. Requires `from`; span at most 30 days. */
46
+ to: zod_1.z.iso
47
+ .datetime({ offset: true })
48
+ .optional()
49
+ .describe('Absolute window end (ISO 8601), at most 1 minute in the future. Requires `from`; span <= 30 days.'),
50
+ /** Only this service. Must be one of `/filters` `services` for the range. */
51
+ service: zod_1.z
52
+ .string()
53
+ .min(1)
54
+ .max(constants_js_1.DASHBOARD_FILTER_VALUE_MAX)
55
+ .optional()
56
+ .describe('Only this service. Must be one of `/filters` `services` for the range.'),
57
+ /** Only this instance (`app.instance.id`). Must be one of `/filters` `instances` for the range. */
58
+ instance: zod_1.z
59
+ .string()
60
+ .min(1)
61
+ .max(constants_js_1.DASHBOARD_FILTER_VALUE_MAX)
62
+ .optional()
63
+ .describe('Only this instance (`app.instance.id`). Must be one of `/filters` `instances` for the range.'),
64
+ /** Target number of buckets: `30` or `60` (default). */
65
+ buckets: (0, enum_js_1.wireEnum)(constants_js_1.DASHBOARD_BUCKET_COUNTS).optional().describe('Target number of buckets: `30` or `60` (default).'),
66
+ };
67
+ /**
68
+ * The cross-field rules of a dashboard window, as a `superRefine`: `range`
69
+ * or `from`+`to` (never both, never one of the pair), `from < to`, `to` at
70
+ * most 1 minute in the future and a span of at most 30 days. Every dashboard
71
+ * query schema applies it; an app's own dashboard query applies it too.
72
+ *
73
+ * @stability stable
74
+ */
75
+ function refineWindow(value, ctx) {
76
+ const hasFrom = value.from !== undefined;
77
+ const hasTo = value.to !== undefined;
78
+ if (value.range !== undefined && (hasFrom || hasTo)) {
79
+ ctx.addIssue({ code: 'custom', path: ['range'], message: 'Use either `range` or `from`/`to`, not both.' });
80
+ return;
81
+ }
82
+ if (hasFrom !== hasTo) {
83
+ ctx.addIssue({ code: 'custom', path: [hasFrom ? 'to' : 'from'], message: '`from` and `to` go together.' });
84
+ return;
85
+ }
86
+ if (!hasFrom)
87
+ return;
88
+ const from = Date.parse(value.from);
89
+ const to = Date.parse(value.to);
90
+ if (!(from < to)) {
91
+ ctx.addIssue({ code: 'custom', path: ['from'], message: '`from` must be before `to`.' });
92
+ return;
93
+ }
94
+ if (to > Date.now() + constants_js_1.DASHBOARD_FUTURE_SKEW_MS) {
95
+ ctx.addIssue({ code: 'custom', path: ['to'], message: '`to` may be at most 1 minute in the future.' });
96
+ }
97
+ if (to - from > constants_js_1.DASHBOARD_MAX_SPAN_MS) {
98
+ ctx.addIssue({ code: 'custom', path: ['from'], message: 'The window may span at most 30 days.' });
99
+ }
100
+ }
101
+ /**
102
+ * The query every dashboard route shares: `range` or `from`+`to`, `service`,
103
+ * `instance` and `buckets`, with {@link refineWindow}.
104
+ *
105
+ * @extensionPoint schema
106
+ * @stability stable
107
+ */
108
+ exports.telemetryDashboardQuerySchema = zod_1.z.object(commonShape).superRefine(refineWindow);
109
+ /**
110
+ * `GET …/dashboard/timeseries` query: the common query plus `panel`
111
+ * (`api` or `logs`).
112
+ *
113
+ * @extensionPoint schema
114
+ * @stability stable
115
+ */
116
+ exports.telemetryDashboardTimeseriesQuerySchema = zod_1.z
117
+ .object({
118
+ ...commonShape,
119
+ /** `api` (status classes, p95) or `logs` (severity bands). */
120
+ panel: (0, enum_js_1.wireEnum)(constants_js_1.DASHBOARD_PANELS).describe('`api` (status classes, p95) or `logs` (severity bands).'),
121
+ })
122
+ .superRefine(refineWindow);
123
+ /**
124
+ * `GET …/dashboard/top` query: the common query plus `kind` (`routes` or
125
+ * `errors`).
126
+ *
127
+ * @extensionPoint schema
128
+ * @stability stable
129
+ */
130
+ exports.telemetryDashboardTopQuerySchema = zod_1.z
131
+ .object({
132
+ ...commonShape,
133
+ /** `routes` (by 5xx, then 4xx except 401, then p95) or `errors` (log messages). */
134
+ kind: (0, enum_js_1.wireEnum)(constants_js_1.DASHBOARD_TOP_KINDS).describe('`routes` (by 5xx, then 4xx except 401, then p95) or `errors` (log messages).'),
135
+ })
136
+ .superRefine(refineWindow);
137
+ const SEVERITY_LIST = new RegExp(`^(${constants_js_1.DASHBOARD_EVENT_SEVERITIES.join('|')})(,(${constants_js_1.DASHBOARD_EVENT_SEVERITIES.join('|')}))*$`);
138
+ /**
139
+ * `GET …/dashboard/events` query: the common query plus `severity` (a comma
140
+ * list of {@link DASHBOARD_EVENT_SEVERITIES}), `q` (a log body substring) and
141
+ * `cursor`.
142
+ *
143
+ * @extensionPoint schema
144
+ * @stability stable
145
+ */
146
+ exports.telemetryDashboardEventsQuerySchema = zod_1.z
147
+ .object({
148
+ ...commonShape,
149
+ /** Comma-separated severities: `error`, `warn`, `info`. Default `error,warn`. */
150
+ severity: zod_1.z
151
+ .string()
152
+ .regex(SEVERITY_LIST, 'A comma-separated list of error, warn, info.')
153
+ .optional()
154
+ .describe('Comma-separated severities: `error`, `warn`, `info`. Default `error,warn`.'),
155
+ /** Case-insensitive substring of the log body (at most 200 characters; `%` and `_` are literal). */
156
+ q: zod_1.z
157
+ .string()
158
+ .max(constants_js_1.DASHBOARD_SEARCH_MAX_LENGTH)
159
+ .optional()
160
+ .describe('Case-insensitive substring of the log body (at most 200 characters; `%` and `_` are literal).'),
161
+ /** `nextCursor` of the previous page. */
162
+ cursor: zod_1.z
163
+ .string()
164
+ .max(constants_js_1.DASHBOARD_CURSOR_MAX)
165
+ .optional()
166
+ .describe('`nextCursor` of the previous page.'),
167
+ })
168
+ .superRefine(refineWindow);
169
+ /** `a`, `a or b`, `a, b or c`. */
170
+ function orList(items) {
171
+ return items.length <= 1 ? items.join('') : `${items.slice(0, -1).join(', ')} or ${items[items.length - 1]}`;
172
+ }
173
+ /**
174
+ * A metric group id as the contract knows it: any lower snake-case id
175
+ * ({@link METRIC_GROUP_ID_PATTERN}). The set is open; a server checks it
176
+ * against what it registered.
177
+ *
178
+ * @extensionPoint schema
179
+ * @stability stable
180
+ */
181
+ exports.metricGroupIdSchema = zod_1.z.string().regex(constants_js_1.METRIC_GROUP_ID_PATTERN);
182
+ /**
183
+ * The `/metrics` `group` query value of a server with a registry: checked
184
+ * against the LIVE set (`isKnown`), so a group registered after the schema
185
+ * was built is accepted, and DOCUMENTED as the enum of `documented`, exactly
186
+ * as a `z.enum` would be, so the OpenAPI document reads the same.
187
+ *
188
+ * @extensionPoint schema
189
+ * @stability stable
190
+ */
191
+ function metricGroupQuerySchema(options) {
192
+ const { documented, isKnown, knownIds } = options;
193
+ return zod_1.z
194
+ .string()
195
+ .refine(isKnown, {
196
+ error: () => `Invalid option: expected one of ${knownIds().map((id) => `"${id}"`).join('|')}`,
197
+ })
198
+ .meta({ enum: [...documented] })
199
+ .describe(`The metric group: ${orList(documented.map((id) => `\`${id}\``))}.`);
200
+ }
201
+ /**
202
+ * Builds the `GET …/dashboard/metrics` query schema around a `group` schema:
203
+ * the common query plus `group` and `host`, with {@link refineWindow}.
204
+ *
205
+ * @extensionPoint schema
206
+ * @stability stable
207
+ */
208
+ function createTelemetryDashboardMetricsQuerySchema(group) {
209
+ return zod_1.z
210
+ .object({
211
+ ...commonShape,
212
+ /** The metric group: the schema passed in. */
213
+ group,
214
+ /** Only this host (`host_name`). Must be one of `/filters` `hosts` for the range. */
215
+ host: zod_1.z
216
+ .string()
217
+ .min(1)
218
+ .max(constants_js_1.DASHBOARD_FILTER_VALUE_MAX)
219
+ .optional()
220
+ .describe('Only this host (`host_name`). Must be one of `/filters` `hosts` for the range.'),
221
+ })
222
+ .superRefine(refineWindow);
223
+ }
224
+ /**
225
+ * `GET …/dashboard/metrics` query, with `group` any metric group id
226
+ * ({@link metricGroupIdSchema}).
227
+ *
228
+ * @extensionPoint schema
229
+ * @stability stable
230
+ */
231
+ exports.telemetryDashboardMetricsQuerySchema = createTelemetryDashboardMetricsQuerySchema(exports.metricGroupIdSchema);
232
+ // ---- responses ---------------------------------------------------------------
233
+ const envelope = {
234
+ /** Window start, ISO 8601. */
235
+ range: zod_1.z.object({
236
+ /** Window start, ISO 8601. */
237
+ from: zod_1.z.string().describe('Window start, ISO 8601.'),
238
+ /** Window end (exclusive), ISO 8601. */
239
+ to: zod_1.z.string().describe('Window end (exclusive), ISO 8601.'),
240
+ /** Bucket size used for series and sparklines. */
241
+ bucketSeconds: zod_1.z.number().int().describe('Bucket size used for series and sparklines.'),
242
+ }),
243
+ /** When the telemetry store was read (results are cached for 15 s). */
244
+ generatedAt: zod_1.z.string().describe('When the telemetry store was read (results are cached for 15 s).'),
245
+ /** A row cap cut a list short. */
246
+ truncated: zod_1.z.boolean().describe('A row cap cut a list short.'),
247
+ /** The exact statement(s) run, primary first. */
248
+ sql: zod_1.z
249
+ .union([zod_1.z.string(), zod_1.z.array(zod_1.z.string())])
250
+ .describe('The exact statement(s) run, primary first.'),
251
+ };
252
+ /**
253
+ * The fields every dashboard response except `/metrics` starts with:
254
+ * `range` (`from`, `to`, `bucketSeconds`), `generatedAt`, `truncated` and
255
+ * `sql` (the statement or statements run, primary first).
256
+ *
257
+ * @extensionPoint schema
258
+ * @stability stable
259
+ */
260
+ exports.telemetryDashboardEnvelopeSchema = zod_1.z.object(envelope);
261
+ const tileValue = zod_1.z.union([zod_1.z.number(), zod_1.z.string()]).nullable();
262
+ /**
263
+ * One tile: `key`, `label`, `value`, `previous` (the previous window of equal
264
+ * length), `unit` and `sparkline` (one value per bucket, `null` a gap).
265
+ *
266
+ * @extensionPoint schema
267
+ * @stability stable
268
+ */
269
+ exports.telemetryDashboardTileSchema = zod_1.z.object({
270
+ /** Stable tile key. */
271
+ key: zod_1.z.string(),
272
+ /** Display label. */
273
+ label: zod_1.z.string(),
274
+ /** Current window value; null when there is nothing to measure. */
275
+ value: tileValue.describe('Current window value; null when there is nothing to measure.'),
276
+ /** Same measure over the previous window of equal length. */
277
+ previous: tileValue.describe('Same measure over the previous window of equal length.'),
278
+ /** `req/min`, `%`, `ms`, `count`, `bytes` or `timestamp`; metric tiles (`/metrics`) also use `bytes/s`, `per_s`, `per_min`, `seconds`, `hours`, `days`, `cores` and `load`. */
279
+ unit: zod_1.z
280
+ .string()
281
+ .describe('`req/min`, `%`, `ms`, `count`, `bytes` or `timestamp`; metric tiles (`/metrics`) also use ' +
282
+ '`bytes/s`, `per_s`, `per_min`, `seconds`, `hours`, `days`, `cores` and `load`.'),
283
+ /** One value per bucket of the window; null where unmeasurable. */
284
+ sparkline: zod_1.z.array(zod_1.z.number().nullable()).describe('One value per bucket of the window; null where unmeasurable.'),
285
+ });
286
+ /**
287
+ * One unknown API route of the summary (#650): `method`, the normalized
288
+ * `route`, `count`, and how many were `bearer` or `anonymous`.
289
+ *
290
+ * @extensionPoint schema
291
+ * @stability stable
292
+ */
293
+ exports.unknownRouteSchema = zod_1.z.object({
294
+ /** The HTTP method, or `null`. */
295
+ method: zod_1.z.string().nullable(),
296
+ /** The request path with numeric/UUID/hex segments normalized to `:id` (a route shape, not a value). */
297
+ route: zod_1.z
298
+ .string()
299
+ .nullable()
300
+ .describe('The request path with numeric/UUID/hex segments normalized to `:id` (a route shape, not a value).'),
301
+ /** Requests to this unknown route in the window. */
302
+ count: zod_1.z.number().describe('Requests to this unknown route in the window.'),
303
+ /** Of those, requests carrying an `Authorization: Bearer` header (the application's own clients). */
304
+ bearer: zod_1.z.number().describe('Of those, requests carrying an `Authorization: Bearer` header (the application\'s own clients).'),
305
+ /** Of those, requests without a bearer (typically internet scanners). */
306
+ anonymous: zod_1.z.number().describe('Of those, requests without a bearer (typically internet scanners).'),
307
+ });
308
+ /**
309
+ * Requests to API routes that do not exist (#650): totals, the previous
310
+ * window's, the top routes and the statements run.
311
+ *
312
+ * @extensionPoint schema
313
+ * @stability stable
314
+ */
315
+ exports.telemetryDashboardUnknownRoutesSchema = zod_1.z
316
+ .object({
317
+ /** Requests answered by the not-found handler (404, no matched route) in the window. */
318
+ requests: zod_1.z.number().describe('Requests answered by the not-found handler (404, no matched route) in the window.'),
319
+ /** Of those, requests with an `Authorization: Bearer` header. Any of these degrades the verdict. */
320
+ bearer: zod_1.z.number().describe('Of those, requests with an `Authorization: Bearer` header. Any of these degrades the verdict.'),
321
+ /** Of those, requests without a bearer. Counted, never alarming. */
322
+ anonymous: zod_1.z.number().describe('Of those, requests without a bearer. Counted, never alarming.'),
323
+ /** `requests` over the previous window of equal length. */
324
+ previousRequests: zod_1.z.number().describe('`requests` over the previous window of equal length.'),
325
+ /** `bearer` over the previous window of equal length. */
326
+ previousBearer: zod_1.z.number().describe('`bearer` over the previous window of equal length.'),
327
+ /** Most-hit unknown routes by `METHOD /normalized-path`, bearer requests first (at most 5). */
328
+ topRoutes: zod_1.z
329
+ .array(exports.unknownRouteSchema)
330
+ .describe('Most-hit unknown routes by `METHOD /normalized-path`, bearer requests first (at most 5).'),
331
+ /** More unknown routes exist than `topRoutes` lists. */
332
+ truncated: zod_1.z.boolean().describe('More unknown routes exist than `topRoutes` lists.'),
333
+ /** The exact statements run for this block, per-route list first, then the window totals (the same text that also appears in the summary's `sql`), for "Open in Explorer". */
334
+ sql: zod_1.z
335
+ .array(zod_1.z.string())
336
+ .describe('The exact statements run for this block, per-route list first, then the window totals ' +
337
+ '(the same text that also appears in the summary\'s `sql`), for "Open in Explorer".'),
338
+ })
339
+ .describe('Requests to API routes that do not exist (issue #650). Absent when the store has no ' +
340
+ '`span_attributes.app.route.matched` column yet (no unknown route recorded since the API started ' +
341
+ 'writing it): the figure is then unknown, not zero.');
342
+ /**
343
+ * `GET …/dashboard/summary`: the envelope plus `verdict` (`level` and
344
+ * `reasons`), `tiles`, `runtime` (optional) and `unknownRoutes` (optional).
345
+ *
346
+ * @extensionPoint schema
347
+ * @stability stable
348
+ */
349
+ exports.telemetryDashboardSummarySchema = zod_1.z.object({
350
+ ...envelope,
351
+ /** The overall health verdict. */
352
+ verdict: zod_1.z.object({
353
+ /** How healthy the window is. */
354
+ level: (0, enum_js_1.wireEnum)(constants_js_1.VERDICT_LEVELS),
355
+ /** Why, one line per rule that fired. */
356
+ reasons: zod_1.z.array(zod_1.z.string()),
357
+ }),
358
+ /** Fixed tiles: `requestsPerMin`, `errorRatePct`, `p95Ms`, `errorLogs`, `warnLogs`, `unknownRoutes` (requests to unknown API routes; value null when the store cannot tell yet, see `unknownRoutes`) and `lastDataAt`. */
359
+ tiles: zod_1.z
360
+ .array(exports.telemetryDashboardTileSchema)
361
+ .describe('Fixed tiles: `requestsPerMin`, `errorRatePct`, `p95Ms`, `errorLogs`, `warnLogs`, `unknownRoutes` ' +
362
+ '(requests to unknown API routes; value null when the store cannot tell yet, see `unknownRoutes`) and `lastDataAt`.'),
363
+ /** Heap used and event-loop delay p99, when the runtime metric tables exist. Not filtered by instance. */
364
+ runtime: zod_1.z
365
+ .array(exports.telemetryDashboardTileSchema)
366
+ .optional()
367
+ .describe('Heap used and event-loop delay p99, when the runtime metric tables exist. Not filtered by instance.'),
368
+ /** Requests to unknown API routes; absent while the store cannot tell. */
369
+ unknownRoutes: exports.telemetryDashboardUnknownRoutesSchema.optional(),
370
+ });
371
+ /**
372
+ * One `api` timeseries bucket: `t`, the status classes and `p95Ms`.
373
+ *
374
+ * @extensionPoint schema
375
+ * @stability stable
376
+ */
377
+ exports.apiBucketSchema = zod_1.z.object({
378
+ /** Bucket start, ISO 8601. */
379
+ t: zod_1.z.string(),
380
+ /** 2xx responses. */
381
+ s2xx: zod_1.z.number(),
382
+ /** 3xx responses. */
383
+ s3xx: zod_1.z.number(),
384
+ /** 4xx responses. */
385
+ s4xx: zod_1.z.number(),
386
+ /** 5xx responses. */
387
+ s5xx: zod_1.z.number(),
388
+ /** 95th percentile latency in ms, or `null` with no requests. */
389
+ p95Ms: zod_1.z.number().nullable(),
390
+ });
391
+ /**
392
+ * One `logs` timeseries bucket: `t` and the severity bands.
393
+ *
394
+ * @extensionPoint schema
395
+ * @stability stable
396
+ */
397
+ exports.logsBucketSchema = zod_1.z.object({
398
+ /** Bucket start, ISO 8601. */
399
+ t: zod_1.z.string(),
400
+ /** Error-level log records. */
401
+ error: zod_1.z.number(),
402
+ /** Warn-level log records. */
403
+ warn: zod_1.z.number(),
404
+ /** Info-level log records. */
405
+ info: zod_1.z.number(),
406
+ /** Records of any other (or no) severity. */
407
+ other: zod_1.z.number(),
408
+ });
409
+ /**
410
+ * `GET …/dashboard/timeseries`: the envelope plus `panel` and `buckets` (api
411
+ * buckets for `api`, logs buckets for `logs`).
412
+ *
413
+ * @extensionPoint schema
414
+ * @stability stable
415
+ */
416
+ exports.telemetryDashboardTimeseriesSchema = zod_1.z.object({
417
+ ...envelope,
418
+ /** The panel requested. */
419
+ panel: (0, enum_js_1.wireEnum)(constants_js_1.DASHBOARD_PANELS),
420
+ /** One entry per bucket: api buckets for `api`, logs buckets for `logs`. */
421
+ buckets: zod_1.z.union([zod_1.z.array(exports.apiBucketSchema), zod_1.z.array(exports.logsBucketSchema)]),
422
+ });
423
+ /**
424
+ * One route of `top?kind=routes`: request counts, 5xx `errors`, 4xx
425
+ * `clientErrors`, `unknownRequests`, `unknown` and `p95Ms`.
426
+ *
427
+ * @extensionPoint schema
428
+ * @stability stable
429
+ */
430
+ exports.topRouteSchema = zod_1.z.object({
431
+ /** The HTTP method, or `null`. */
432
+ method: zod_1.z.string().nullable(),
433
+ /** The request path with numeric/UUID/hex segments normalized to `:id`. */
434
+ route: zod_1.z.string().nullable().describe('The request path with numeric/UUID/hex segments normalized to `:id`.'),
435
+ /** Requests in the window. */
436
+ count: zod_1.z.number(),
437
+ /** 5xx responses. */
438
+ errors: zod_1.z.number().describe('5xx responses.'),
439
+ /** `errors` as a percentage of `count`. */
440
+ errorRatePct: zod_1.z.number(),
441
+ /** 4xx responses except 401 (an expired access token is routine), unknown routes included. */
442
+ clientErrors: zod_1.z.number().describe('4xx responses except 401 (an expired access token is routine), unknown routes included.'),
443
+ /** Requests answered by the not-found handler: no API route matches this method and path. 0 when the store cannot tell yet. */
444
+ unknownRequests: zod_1.z
445
+ .number()
446
+ .describe('Requests answered by the not-found handler: no API route matches this method and path. 0 when the store cannot tell yet.'),
447
+ /** `unknownRequests > 0`: this method + path is not a route of the running API build. */
448
+ unknown: zod_1.z.boolean().describe('`unknownRequests > 0`: this method + path is not a route of the running API build.'),
449
+ /** 95th percentile latency in ms, or `null`. */
450
+ p95Ms: zod_1.z.number().nullable(),
451
+ });
452
+ /**
453
+ * One error message of `top?kind=errors`: `message`, `count`, first and last
454
+ * seen, a sample trace and the `service`.
455
+ *
456
+ * @extensionPoint schema
457
+ * @stability stable
458
+ */
459
+ exports.topErrorSchema = zod_1.z.object({
460
+ /** The grouped log message, or `null`. */
461
+ message: zod_1.z.string().nullable(),
462
+ /** Occurrences in the window. */
463
+ count: zod_1.z.number(),
464
+ /** First occurrence in the window, or `null`. */
465
+ firstSeen: zod_1.z.string().nullable(),
466
+ /** Last occurrence in the window, or `null`. */
467
+ lastSeen: zod_1.z.string().nullable(),
468
+ /** A trace of one occurrence, or `null`. */
469
+ sampleTraceId: zod_1.z.string().nullable(),
470
+ /** The service that logged it, or `null`. */
471
+ service: zod_1.z.string().nullable(),
472
+ });
473
+ /**
474
+ * `GET …/dashboard/top`: the envelope plus `kind` and `items` (routes for
475
+ * `routes`, errors for `errors`).
476
+ *
477
+ * @extensionPoint schema
478
+ * @stability stable
479
+ */
480
+ exports.telemetryDashboardTopSchema = zod_1.z.object({
481
+ ...envelope,
482
+ /** The kind requested. */
483
+ kind: (0, enum_js_1.wireEnum)(constants_js_1.DASHBOARD_TOP_KINDS),
484
+ /** Routes for `routes`, error messages for `errors`. */
485
+ items: zod_1.z.union([zod_1.z.array(exports.topRouteSchema), zod_1.z.array(exports.topErrorSchema)]),
486
+ });
487
+ /**
488
+ * One log event: `timestamp` (full precision, UTC), `severity`, `service`,
489
+ * `body`, `traceId` and `spanId`.
490
+ *
491
+ * @extensionPoint schema
492
+ * @stability stable
493
+ */
494
+ exports.dashboardEventSchema = zod_1.z.object({
495
+ /** Full precision (up to nanoseconds), UTC. */
496
+ timestamp: zod_1.z.string().describe('Full precision (up to nanoseconds), UTC.'),
497
+ /** Lower-case severity text (`error`, `warn`, `info`, `debug`, …). */
498
+ severity: zod_1.z.string(),
499
+ /** The emitting service, or `null`. */
500
+ service: zod_1.z.string().nullable(),
501
+ /** The log body, or `null`. */
502
+ body: zod_1.z.string().nullable(),
503
+ /** The trace it belongs to, or `null`. */
504
+ traceId: zod_1.z.string().nullable(),
505
+ /** The span it belongs to, or `null`. */
506
+ spanId: zod_1.z.string().nullable(),
507
+ });
508
+ /**
509
+ * `GET …/dashboard/events`: the envelope plus `items` and `nextCursor`.
510
+ *
511
+ * @extensionPoint schema
512
+ * @stability stable
513
+ */
514
+ exports.telemetryDashboardEventsSchema = zod_1.z.object({
515
+ ...envelope,
516
+ /** The events, newest first. */
517
+ items: zod_1.z.array(exports.dashboardEventSchema),
518
+ /** The `cursor` of the next page, or `null` on the last. */
519
+ nextCursor: zod_1.z.string().nullable(),
520
+ });
521
+ /**
522
+ * `GET …/dashboard/filters`: the envelope plus the `services`, `instances`
523
+ * and `hosts` seen in the window.
524
+ *
525
+ * @extensionPoint schema
526
+ * @stability stable
527
+ */
528
+ exports.telemetryDashboardFiltersSchema = zod_1.z.object({
529
+ ...envelope,
530
+ /** Services seen in the window: the values `service` accepts. */
531
+ services: zod_1.z.array(zod_1.z.string()),
532
+ /** Instances (`app.instance.id`) seen in the window: the values `instance` accepts. */
533
+ instances: zod_1.z.array(zod_1.z.string()),
534
+ /** Host names (`host_name`) seen in the host metrics — the values `/metrics` `host` accepts. */
535
+ hosts: zod_1.z
536
+ .array(zod_1.z.string())
537
+ .describe('Host names (`host_name`) seen in the host metrics — the values `/metrics` `host` accepts.'),
538
+ });
539
+ // ---- metrics (#601) ------------------------------------------------------------
540
+ const metricUnit = (0, enum_js_1.wireEnum)(constants_js_1.METRIC_UNITS);
541
+ /**
542
+ * One point of a metric series: `t` (bucket start) and `v` (`null` where
543
+ * nothing was measured).
544
+ *
545
+ * @extensionPoint schema
546
+ * @stability stable
547
+ */
548
+ exports.metricPointSchema = zod_1.z.object({
549
+ /** Bucket start, ISO 8601. */
550
+ t: zod_1.z.string().describe('Bucket start, ISO 8601.'),
551
+ /** The value, or `null` where nothing was measured: a gap, not a zero. */
552
+ v: zod_1.z.number().nullable(),
553
+ });
554
+ /**
555
+ * One metric series: `key`, `label`, `unit`, `dimension`, `groupBy` and
556
+ * `points` (one per bucket).
557
+ *
558
+ * @extensionPoint schema
559
+ * @stability stable
560
+ */
561
+ exports.metricSeriesSchema = zod_1.z.object({
562
+ /** The catalog family or ratio key. */
563
+ key: zod_1.z.string().describe('The catalog family or ratio key.'),
564
+ /** Display label. */
565
+ label: zod_1.z.string(),
566
+ /** Display unit of `points`. */
567
+ unit: metricUnit,
568
+ /** The label column the family is split by (e.g. `mountpoint`), or null. */
569
+ dimension: zod_1.z.string().nullable().describe('The label column the family is split by (e.g. `mountpoint`), or null.'),
570
+ /** This series' value of `dimension` (e.g. `/`), or null. */
571
+ groupBy: zod_1.z.string().nullable().describe("This series' value of `dimension` (e.g. `/`), or null."),
572
+ /** One point per bucket of the window; null where nothing was measured. */
573
+ points: zod_1.z
574
+ .array(exports.metricPointSchema)
575
+ .describe('One point per bucket of the window; null where nothing was measured.'),
576
+ });
577
+ /**
578
+ * One column of a metric table: `key`, `label` and `unit`.
579
+ *
580
+ * @extensionPoint schema
581
+ * @stability stable
582
+ */
583
+ exports.metricColumnSchema = zod_1.z.object({
584
+ /** The column key (a key of each row). */
585
+ key: zod_1.z.string(),
586
+ /** Display label. */
587
+ label: zod_1.z.string(),
588
+ /** Display unit of the column's values. */
589
+ unit: metricUnit,
590
+ });
591
+ /**
592
+ * One cell of a metric table row: a string, number, boolean or `null`.
593
+ *
594
+ * @extensionPoint schema
595
+ * @stability stable
596
+ */
597
+ exports.metricCellSchema = zod_1.z.union([zod_1.z.string(), zod_1.z.number(), zod_1.z.boolean(), zod_1.z.null()]);
598
+ /**
599
+ * One per-key metric table: `key`, `label`, `columns` and `rows`.
600
+ *
601
+ * @extensionPoint schema
602
+ * @stability stable
603
+ */
604
+ exports.metricTableSchema = zod_1.z.object({
605
+ /** The table key. */
606
+ key: zod_1.z.string(),
607
+ /** Display label. */
608
+ label: zod_1.z.string(),
609
+ /** The columns, `key` first. */
610
+ columns: zod_1.z.array(exports.metricColumnSchema),
611
+ /** One row per key; `key` holds the key column, then one entry per column. At most 50 rows (500 for `largestTables`); `truncated` says a cap cut the list. */
612
+ rows: zod_1.z
613
+ .array(zod_1.z.record(zod_1.z.string(), exports.metricCellSchema))
614
+ .describe('One row per key; `key` holds the key column, then one entry per column. At most 50 rows ' +
615
+ '(500 for `largestTables`); `truncated` says a cap cut the list.'),
616
+ });
617
+ /**
618
+ * Builds the `GET …/dashboard/metrics` response schema around a `group`
619
+ * schema: `range`, `generatedAt`, `truncated`, `sql`, `group`, `available`,
620
+ * `tiles`, `series`, `tables`, `skipped` and the optional `freshMs`.
621
+ *
622
+ * @extensionPoint schema
623
+ * @stability stable
624
+ */
625
+ function createTelemetryDashboardMetricsSchema(group) {
626
+ return zod_1.z.object({
627
+ /** The window read. */
628
+ range: envelope.range,
629
+ /** When the telemetry store was read. */
630
+ generatedAt: envelope.generatedAt,
631
+ /** A series, table or histogram row cap cut a list short. */
632
+ truncated: zod_1.z.boolean().describe('A series, table or histogram row cap cut a list short.'),
633
+ /** The exact statements run, in order — for "Open in Explorer". */
634
+ sql: zod_1.z.array(zod_1.z.string()).describe('The exact statements run, in order — for "Open in Explorer".'),
635
+ /** The metric group served: the schema passed in. */
636
+ group,
637
+ /** At least one family or table of the group has its table in the store. */
638
+ available: zod_1.z.boolean().describe('At least one family or table of the group has its table in the store.'),
639
+ /** The group's tiles. */
640
+ tiles: zod_1.z.array(exports.telemetryDashboardTileSchema),
641
+ /** The group's series. */
642
+ series: zod_1.z.array(exports.metricSeriesSchema),
643
+ /** The group's per-key tables. */
644
+ tables: zod_1.z.array(exports.metricTableSchema),
645
+ /** Catalog keys (families, ratios, tables) skipped because a table or column they need is absent. */
646
+ skipped: zod_1.z
647
+ .array(zod_1.z.string())
648
+ .describe('Catalog keys (families, ratios, tables) skipped because a table or column they need is absent.'),
649
+ /** The freshness window in milliseconds: a table cell older than its table's newest reading by more than this is not current. Absent from servers that predate it. */
650
+ freshMs: zod_1.z
651
+ .number()
652
+ .int()
653
+ .positive()
654
+ .optional()
655
+ .describe("The freshness window in milliseconds: a table cell older than its table's newest reading by more than " +
656
+ 'this is not current. Absent from servers that predate it.'),
657
+ });
658
+ }
659
+ /**
660
+ * `GET …/dashboard/metrics`, with `group` any metric group id
661
+ * ({@link metricGroupIdSchema}).
662
+ *
663
+ * @extensionPoint schema
664
+ * @stability stable
665
+ */
666
+ exports.telemetryDashboardMetricsSchema = createTelemetryDashboardMetricsSchema(exports.metricGroupIdSchema);
667
+ // ---- metric groups (#680) ------------------------------------------------------
668
+ /**
669
+ * One registered metric group: `id`, `label`, `title` and `order`.
670
+ *
671
+ * @extensionPoint schema
672
+ * @stability stable
673
+ */
674
+ exports.telemetryDashboardMetricGroupSchema = zod_1.z.object({
675
+ /** The group id: the `/metrics` `group` value and the section anchor. */
676
+ id: zod_1.z.string().describe('The group id: the `/metrics` `group` value and the section anchor.'),
677
+ /** The API label (e.g. `Host`). */
678
+ label: zod_1.z.string().describe('The API label (e.g. `Host`).'),
679
+ /** The dashboard section title (e.g. `Infrastructure`). */
680
+ title: zod_1.z.string().describe('The dashboard section title (e.g. `Infrastructure`).'),
681
+ /** Dashboard order, ascending; `data` is already sorted by it (ties by id). */
682
+ order: zod_1.z.number().describe('Dashboard order, ascending; `data` is already sorted by it (ties by id).'),
683
+ });
684
+ /**
685
+ * `GET …/dashboard/metric-groups`: `data`, every registered group in
686
+ * dashboard order.
687
+ *
688
+ * @extensionPoint schema
689
+ * @stability stable
690
+ */
691
+ exports.telemetryDashboardMetricGroupsSchema = zod_1.z.object({
692
+ /** Every registered metric group (the platform's and the app's), in dashboard order. */
693
+ data: zod_1.z
694
+ .array(exports.telemetryDashboardMetricGroupSchema)
695
+ .describe('Every registered metric group (the platform\'s and the app\'s), in dashboard order.'),
696
+ });
697
+ //# sourceMappingURL=dashboard.js.map