@ancplua/qyl-api-schema 11.6.0-rc.1 → 12.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,8 +27,9 @@ The contract covers every client-visible surface of a qyl collector and runner:
27
27
  (`api/workbench.tsp`, `models/workbench.tsp`).
28
28
  - **Runner** — the local runner's loopback-only `/runner/resources` snapshot, SSE
29
29
  streams, logs and restart/stop actions (`api/runner.tsp`, `models/runner.tsp`).
30
- - **Shared** — `ProblemDetails` errors, cursor pagination and the common scalars
31
- (`common/`), plus the OTel resource, span and log projections (`otel/`).
30
+ - **Shared** — RFC 9457 problem details (`common/errors.tsp`), cursor pagination
31
+ (`common/pagination.tsp`) and the common scalars (`common/`), plus the OTel
32
+ resource, span and log projections (`otel/`).
32
33
 
33
34
  Telemetry itself is never changed or deleted through this contract; retention
34
35
  removes it. The only writable resources are the ones a user creates:
@@ -41,6 +42,21 @@ extend the shared write base in `common/resource.tsp`: server-assigned `id`,
41
42
  missing and `412` when stale. Collector keys carry the roles `ingest`, `read`,
42
43
  `write` and `delete` (`CollectorKeyRole`); writes need `write`, deletes `delete`.
43
44
 
45
+ ## Errors and pages
46
+
47
+ Every error body is an RFC 9457 problem served as `application/problem+json`: `type`,
48
+ `title`, `status`, `detail` and `instance`, plus the extension member `code`. Each
49
+ problem type fixes its `type` URI (`https://qyl.at/problems/<name>`) and its `code`
50
+ (`not_found`, `validation_failed`, …), so a client branches on either and never on
51
+ `title` or `detail`. Problem bodies carry no headers. A response header is declared on
52
+ the operations whose server sends it: `X-Trace-Id` on the collector's 500 responses,
53
+ `WWW-Authenticate` on the workbench's 401 responses.
54
+
55
+ Every list operation pages forward with an opaque cursor. It takes `limit`
56
+ (`PageLimit`: 1 to 1000, 100 when omitted) and `cursor`, and its page carries
57
+ `has_more` and, on every page but the last, `next_cursor`, which the next request
58
+ sends back as `cursor`.
59
+
44
60
  ## Contract pipeline
45
61
 
46
62
  ```text
@@ -130,6 +146,11 @@ contract instead of discovering the mismatch one malformed field at a time. Read
130
146
  current value from a running collector or the generated artifacts; it is derived, never
131
147
  hand-maintained.
132
148
 
149
+ The OpenAPI `info.version` is the release version: `prepack` stamps it into the packed
150
+ document from the release tag, and the tracked document keeps TypeSpec's `0.0.0`. The
151
+ digest excludes `info.version`, so a release that changes nothing but its version keeps
152
+ the revision.
153
+
133
154
  ## Contributing
134
155
 
135
156
  How to build, lint, regenerate and publish is in [CONTRIBUTING.md](CONTRIBUTING.md).
package/api/routes.tsp CHANGED
@@ -41,6 +41,20 @@ model ProjectScopeHeader {
41
41
  projectId?: string;
42
42
  }
43
43
 
44
+ // Problem bodies carry no headers (common/errors.tsp). The one header a
45
+ // collector error response carries is declared here, on the collector's own
46
+ // operations: its unhandled-exception handler names the trace of the failed
47
+ // request.
48
+ @doc("The collector failed while handling the request (500). `X-Trace-Id` names the collector's own trace of the failed request.")
49
+ @error
50
+ model CollectorServerErrorResponse {
51
+ @doc("Trace id of the collector's own trace of the failed request, for finding it in the collector's telemetry.")
52
+ @header("X-Trace-Id")
53
+ traceId?: TraceId;
54
+
55
+ @bodyRoot problem: InternalServerError;
56
+ }
57
+
44
58
  // -----------------------------------------------------------------------------
45
59
  // Traces
46
60
  // -----------------------------------------------------------------------------
@@ -49,6 +63,7 @@ model ProjectScopeHeader {
49
63
  @tag("Traces")
50
64
  @useAuth(QylApiKeyHeaderAuth)
51
65
  interface TracesApi {
66
+ @list
52
67
  @get
53
68
  list(
54
69
  ...ProjectScopeHeader,
@@ -69,17 +84,12 @@ interface TracesApi {
69
84
  @query("errors_only")
70
85
  errorsOnly?: boolean,
71
86
 
72
- @query
73
- @minValue(1)
74
- @maxValue(1000)
75
- limit?: int32 = 100,
76
-
77
- @query cursor?: Cursor,
87
+ ...CursorPageQuery,
78
88
  ):
79
89
  | CursorPage<Trace>
80
90
  | ValidationError
81
91
  | UnauthorizedError
82
- | InternalServerError;
92
+ | CollectorServerErrorResponse;
83
93
 
84
94
  @get
85
95
  @route("/{trace_id}")
@@ -87,27 +97,23 @@ interface TracesApi {
87
97
  | Trace
88
98
  | NotFoundError
89
99
  | UnauthorizedError
90
- | InternalServerError;
100
+ | CollectorServerErrorResponse;
91
101
 
102
+ @doc("Page through the spans of one trace. `GET /api/v1/traces/{trace_id}` returns the whole trace at once.")
103
+ @list
92
104
  @get
93
105
  @route("/{trace_id}/spans")
94
106
  getSpans(
95
107
  ...ProjectScopeHeader,
96
108
  @path("trace_id") traceId: TraceId,
97
109
 
98
- @doc("Page size. Omitted, every span of the trace is returned in one page.")
99
- @query
100
- @minValue(1)
101
- @maxValue(10000)
102
- limit?: int32,
103
-
104
- @query cursor?: Cursor,
110
+ ...CursorPageQuery,
105
111
  ):
106
112
  | CursorPage<Span>
107
113
  | ValidationError
108
114
  | NotFoundError
109
115
  | UnauthorizedError
110
- | InternalServerError;
116
+ | CollectorServerErrorResponse;
111
117
  }
112
118
 
113
119
  // -----------------------------------------------------------------------------
@@ -118,6 +124,7 @@ interface TracesApi {
118
124
  @tag("Logs")
119
125
  @useAuth(QylApiKeyHeaderAuth)
120
126
  interface LogsApi {
127
+ @list
121
128
  @get
122
129
  list(
123
130
  ...ProjectScopeHeader,
@@ -130,17 +137,12 @@ interface LogsApi {
130
137
  @query("end_time") endTime?: utcDateTime,
131
138
  @query query?: string,
132
139
 
133
- @query
134
- @minValue(1)
135
- @maxValue(10000)
136
- limit?: int32 = 100,
137
-
138
- @query cursor?: Cursor,
140
+ ...CursorPageQuery,
139
141
  ):
140
142
  | CursorPage<LogRecord>
141
143
  | ValidationError
142
144
  | UnauthorizedError
143
- | InternalServerError;
145
+ | CollectorServerErrorResponse;
144
146
  }
145
147
 
146
148
  // -----------------------------------------------------------------------------
@@ -157,6 +159,7 @@ interface LogsApi {
157
159
  @useAuth(QylApiKeyHeaderAuth)
158
160
  interface MetricsApi {
159
161
  @doc("List the metric names recorded for a project.")
162
+ @list
160
163
  @get
161
164
  list(
162
165
  ...ProjectScopeHeader,
@@ -165,19 +168,15 @@ interface MetricsApi {
165
168
  @query("name_prefix")
166
169
  namePrefix?: string,
167
170
 
168
- @query
169
- @minValue(1)
170
- @maxValue(1000)
171
- limit?: int32 = 200,
172
-
173
- @query cursor?: Cursor,
171
+ ...CursorPageQuery,
174
172
  ):
175
173
  | CursorPage<MetricDescriptor>
176
174
  | ValidationError
177
175
  | UnauthorizedError
178
- | InternalServerError;
176
+ | CollectorServerErrorResponse;
179
177
 
180
178
  @doc("List the distinct attribute streams recorded under one metric name.")
179
+ @list
181
180
  @get
182
181
  @route("/{metric_name}/series")
183
182
  listSeries(
@@ -195,18 +194,13 @@ interface MetricsApi {
195
194
  @query(#{ name: "attr_prefix", explode: true })
196
195
  attrPrefix?: string[],
197
196
 
198
- @query
199
- @minValue(1)
200
- @maxValue(1000)
201
- limit?: int32 = 200,
202
-
203
- @query cursor?: Cursor,
197
+ ...CursorPageQuery,
204
198
  ):
205
199
  | CursorPage<MetricSeries>
206
200
  | ValidationError
207
201
  | NotFoundError
208
202
  | UnauthorizedError
209
- | InternalServerError;
203
+ | CollectorServerErrorResponse;
210
204
 
211
205
  @doc("""
212
206
  Aggregate one metric over a time range into buckets of `step_ms`.
@@ -250,7 +244,7 @@ interface MetricsApi {
250
244
  | ValidationError
251
245
  | NotFoundError
252
246
  | UnauthorizedError
253
- | InternalServerError;
247
+ | CollectorServerErrorResponse;
254
248
  }
255
249
 
256
250
  // -----------------------------------------------------------------------------
@@ -261,6 +255,7 @@ interface MetricsApi {
261
255
  @tag("Sessions")
262
256
  @useAuth(QylApiKeyHeaderAuth)
263
257
  interface SessionsApi {
258
+ @list
264
259
  @get
265
260
  list(
266
261
  ...ProjectScopeHeader,
@@ -268,17 +263,12 @@ interface SessionsApi {
268
263
  @query("start_time") startTime?: utcDateTime,
269
264
  @query("end_time") endTime?: utcDateTime,
270
265
 
271
- @query
272
- @minValue(1)
273
- @maxValue(1000)
274
- limit?: int32 = 100,
275
-
276
- @query cursor?: Cursor,
266
+ ...CursorPageQuery,
277
267
  ):
278
268
  | CursorPage<SessionEntity>
279
269
  | ValidationError
280
270
  | UnauthorizedError
281
- | InternalServerError;
271
+ | CollectorServerErrorResponse;
282
272
 
283
273
  @get
284
274
  @route("/{session_id}")
@@ -286,27 +276,22 @@ interface SessionsApi {
286
276
  | SessionEntity
287
277
  | NotFoundError
288
278
  | UnauthorizedError
289
- | InternalServerError;
279
+ | CollectorServerErrorResponse;
290
280
 
281
+ @list
291
282
  @get
292
283
  @route("/{session_id}/traces")
293
284
  getTraces(
294
285
  ...ProjectScopeHeader,
295
286
  @path("session_id") sessionId: SessionId,
296
287
 
297
- @doc("Page size; the response is bounded even when omitted.")
298
- @query
299
- @minValue(1)
300
- @maxValue(1000)
301
- limit?: int32 = 100,
302
-
303
- @query cursor?: Cursor,
288
+ ...CursorPageQuery,
304
289
  ):
305
290
  | CursorPage<Trace>
306
291
  | ValidationError
307
292
  | NotFoundError
308
293
  | UnauthorizedError
309
- | InternalServerError;
294
+ | CollectorServerErrorResponse;
310
295
 
311
296
  @get
312
297
  @route("/stats")
@@ -314,7 +299,7 @@ interface SessionsApi {
314
299
  ...ProjectScopeHeader,
315
300
  @query("start_time") startTime?: utcDateTime,
316
301
  @query("end_time") endTime?: utcDateTime,
317
- ): SessionStats | ValidationError | UnauthorizedError | InternalServerError;
302
+ ): SessionStats | ValidationError | UnauthorizedError | CollectorServerErrorResponse;
318
303
  }
319
304
 
320
305
  // -----------------------------------------------------------------------------
@@ -350,10 +335,11 @@ interface AnnotationsApi {
350
335
  | ForbiddenError
351
336
  | NotFoundError
352
337
  | ConflictError
353
- | InternalServerError;
338
+ | CollectorServerErrorResponse;
354
339
 
355
340
  @doc("List annotations, newest first, optionally only those attached to one trace, span or session.")
356
341
  @useAuth(QylApiKeyHeaderAuth)
342
+ @list
357
343
  @get
358
344
  list(
359
345
  ...ProjectScopeHeader,
@@ -368,17 +354,12 @@ interface AnnotationsApi {
368
354
 
369
355
  @query("session_id") sessionId?: SessionId,
370
356
 
371
- @query
372
- @minValue(1)
373
- @maxValue(1000)
374
- limit?: int32 = 100,
375
-
376
- @query cursor?: Cursor,
357
+ ...CursorPageQuery,
377
358
  ):
378
359
  | CursorPage<Annotation>
379
360
  | ValidationError
380
361
  | UnauthorizedError
381
- | InternalServerError;
362
+ | CollectorServerErrorResponse;
382
363
 
383
364
  @useAuth(QylApiKeyHeaderAuth)
384
365
  @get
@@ -390,7 +371,7 @@ interface AnnotationsApi {
390
371
  }
391
372
  | NotFoundError
392
373
  | UnauthorizedError
393
- | InternalServerError;
374
+ | CollectorServerErrorResponse;
394
375
 
395
376
  @doc("Replace the text of an annotation. The target is fixed at creation.")
396
377
  @useAuth(QylWriteKeyAuth)
@@ -412,7 +393,7 @@ interface AnnotationsApi {
412
393
  | NotFoundError
413
394
  | PreconditionFailedError
414
395
  | PreconditionRequiredError
415
- | InternalServerError;
396
+ | CollectorServerErrorResponse;
416
397
 
417
398
  @doc("Delete one annotation. Telemetry is never deleted.")
418
399
  @useAuth(QylDeleteKeyAuth)
@@ -429,7 +410,7 @@ interface AnnotationsApi {
429
410
  | NotFoundError
430
411
  | PreconditionFailedError
431
412
  | PreconditionRequiredError
432
- | InternalServerError;
413
+ | CollectorServerErrorResponse;
433
414
  }
434
415
 
435
416
  // -----------------------------------------------------------------------------
@@ -464,26 +445,22 @@ interface SavedQueriesApi {
464
445
  | UnauthorizedError
465
446
  | ForbiddenError
466
447
  | ConflictError
467
- | InternalServerError;
448
+ | CollectorServerErrorResponse;
468
449
 
469
450
  @doc("List the project's saved queries by name.")
470
451
  @useAuth(QylApiKeyHeaderAuth)
452
+ @list
471
453
  @get
472
454
  list(
473
455
  ...ProjectScopeHeader,
474
456
  @query signal?: SavedQuerySignal,
475
457
 
476
- @query
477
- @minValue(1)
478
- @maxValue(1000)
479
- limit?: int32 = 100,
480
-
481
- @query cursor?: Cursor,
458
+ ...CursorPageQuery,
482
459
  ):
483
460
  | CursorPage<SavedQuery>
484
461
  | ValidationError
485
462
  | UnauthorizedError
486
- | InternalServerError;
463
+ | CollectorServerErrorResponse;
487
464
 
488
465
  @useAuth(QylApiKeyHeaderAuth)
489
466
  @get
@@ -495,7 +472,7 @@ interface SavedQueriesApi {
495
472
  }
496
473
  | NotFoundError
497
474
  | UnauthorizedError
498
- | InternalServerError;
475
+ | CollectorServerErrorResponse;
499
476
 
500
477
  @doc("Change a saved query. Renaming onto a name already used in the project is refused with 409.")
501
478
  @useAuth(QylWriteKeyAuth)
@@ -518,7 +495,7 @@ interface SavedQueriesApi {
518
495
  | ConflictError
519
496
  | PreconditionFailedError
520
497
  | PreconditionRequiredError
521
- | InternalServerError;
498
+ | CollectorServerErrorResponse;
522
499
 
523
500
  @doc("Delete one saved query.")
524
501
  @useAuth(QylDeleteKeyAuth)
@@ -535,7 +512,7 @@ interface SavedQueriesApi {
535
512
  | NotFoundError
536
513
  | PreconditionFailedError
537
514
  | PreconditionRequiredError
538
- | InternalServerError;
515
+ | CollectorServerErrorResponse;
539
516
 
540
517
  @doc("Evaluate a saved query against current telemetry. Read-only.")
541
518
  @useAuth(QylApiKeyHeaderAuth)
@@ -550,7 +527,7 @@ interface SavedQueriesApi {
550
527
  | ValidationError
551
528
  | UnauthorizedError
552
529
  | NotFoundError
553
- | InternalServerError;
530
+ | CollectorServerErrorResponse;
554
531
  }
555
532
 
556
533
  // -----------------------------------------------------------------------------
package/api/streaming.tsp CHANGED
@@ -46,5 +46,10 @@ interface StreamingApi {
46
46
  @query("service_name") serviceName?: string,
47
47
  @query("min_severity") @minValue(1) @maxValue(24) minSeverity?: int32,
48
48
  @query query?: string,
49
- ): SSEStream<LogEvents> | ValidationError | UnauthorizedError | ServiceUnavailableError | InternalServerError;
49
+ ):
50
+ | SSEStream<LogEvents>
51
+ | ValidationError
52
+ | UnauthorizedError
53
+ | ServiceUnavailableError
54
+ | Qyl.Api.Contracts.CollectorServerErrorResponse;
50
55
  }