@ancplua/qyl-api-schema 11.6.0 → 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 +23 -2
- package/api/routes.tsp +55 -78
- package/api/streaming.tsp +6 -1
- package/api/workbench.tsp +70 -75
- package/common/errors.tsp +113 -140
- package/common/pagination.tsp +25 -228
- package/common/resource.tsp +0 -7
- package/common/types.tsp +10 -2
- package/generated/json-schema/qyl-api-schema.json +293 -412
- package/generated/openapi/qyl.openapi.json +944 -7597
- package/generated/ts-runtime/api.d.ts +60 -78
- package/generated/ts-runtime/api.js +24 -13
- package/generated/ts-runtime/schemas.d.ts +5 -12
- package/generated/ts-runtime/schemas.js +3 -10
- package/models/mcp-tools.tsp +2 -2
- package/models/saved-queries.tsp +8 -4
- package/models/workbench.tsp +20 -5
- package/otel/span.tsp +0 -49
- package/package.json +3 -2
package/common/errors.tsp
CHANGED
|
@@ -1,251 +1,224 @@
|
|
|
1
1
|
// =============================================================================
|
|
2
|
-
// qyl product API
|
|
2
|
+
// qyl product API problem details (RFC 9457)
|
|
3
3
|
// =============================================================================
|
|
4
|
-
//
|
|
4
|
+
// Every error body is an RFC 9457 problem: the five standard members plus the
|
|
5
|
+
// qyl extension member `code`. A problem type is named twice, by its `type` URI
|
|
6
|
+
// and by its `code`, and each error model below fixes both, so a client branches
|
|
7
|
+
// on either and never on `title` or `detail`.
|
|
8
|
+
//
|
|
9
|
+
// Bodies carry no HTTP headers. The media type is a property of the body type
|
|
10
|
+
// (`@mediaTypeHint`), and a header an error response carries is declared on the
|
|
11
|
+
// operations whose server sends it: `X-Trace-Id` on the collector's 500
|
|
12
|
+
// (api/routes.tsp) and `WWW-Authenticate` on the workbench's 401
|
|
13
|
+
// (api/workbench.tsp).
|
|
5
14
|
// =============================================================================
|
|
6
15
|
|
|
7
16
|
import "@typespec/http";
|
|
8
|
-
import "./types.tsp";
|
|
9
17
|
|
|
10
18
|
using TypeSpec.Http;
|
|
11
19
|
|
|
12
20
|
namespace Qyl.Api.Contracts.Common.Errors;
|
|
13
21
|
|
|
22
|
+
@doc("""
|
|
23
|
+
Problem type URI, the RFC 9457 `type` member: one per problem a qyl server
|
|
24
|
+
reports. `code` names the same problem type.
|
|
25
|
+
""")
|
|
26
|
+
enum ProblemType {
|
|
27
|
+
validationFailed: "https://qyl.at/problems/validation-failed",
|
|
28
|
+
unauthorized: "https://qyl.at/problems/unauthorized",
|
|
29
|
+
forbidden: "https://qyl.at/problems/forbidden",
|
|
30
|
+
notFound: "https://qyl.at/problems/not-found",
|
|
31
|
+
conflict: "https://qyl.at/problems/conflict",
|
|
32
|
+
preconditionFailed: "https://qyl.at/problems/precondition-failed",
|
|
33
|
+
preconditionRequired: "https://qyl.at/problems/precondition-required",
|
|
34
|
+
internalError: "https://qyl.at/problems/internal-error",
|
|
35
|
+
badGateway: "https://qyl.at/problems/bad-gateway",
|
|
36
|
+
serviceUnavailable: "https://qyl.at/problems/service-unavailable",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@doc("""
|
|
40
|
+
Stable machine-readable code of a problem type, the qyl `code` extension
|
|
41
|
+
member. `type` names the same problem type as a URI.
|
|
42
|
+
""")
|
|
43
|
+
enum ProblemCode {
|
|
44
|
+
validationFailed: "validation_failed",
|
|
45
|
+
unauthorized: "unauthorized",
|
|
46
|
+
forbidden: "forbidden",
|
|
47
|
+
notFound: "not_found",
|
|
48
|
+
conflict: "conflict",
|
|
49
|
+
preconditionFailed: "precondition_failed",
|
|
50
|
+
preconditionRequired: "precondition_required",
|
|
51
|
+
internalError: "internal_error",
|
|
52
|
+
badGateway: "bad_gateway",
|
|
53
|
+
serviceUnavailable: "service_unavailable",
|
|
54
|
+
}
|
|
55
|
+
|
|
14
56
|
// =============================================================================
|
|
15
|
-
// RFC
|
|
57
|
+
// RFC 9457 Problem Details Base
|
|
16
58
|
// =============================================================================
|
|
17
59
|
|
|
18
|
-
@doc("RFC
|
|
60
|
+
@doc("RFC 9457 problem details, served as application/problem+json: the standard members plus the qyl `code` extension.")
|
|
61
|
+
@mediaTypeHint("application/problem+json")
|
|
19
62
|
@error
|
|
20
63
|
model ProblemDetails {
|
|
21
|
-
@doc("
|
|
22
|
-
|
|
64
|
+
@doc("URI of the problem type.")
|
|
65
|
+
type: ProblemType;
|
|
23
66
|
|
|
24
|
-
@doc("
|
|
25
|
-
@encodedName("application/json", "type")
|
|
26
|
-
problemType: url = "about:blank";
|
|
27
|
-
|
|
28
|
-
@doc("A short, human-readable summary of the problem type")
|
|
67
|
+
@doc("Short summary of the problem type; the same for every occurrence.")
|
|
29
68
|
title: string;
|
|
30
69
|
|
|
31
|
-
@doc("
|
|
70
|
+
@doc("HTTP status code of this response, repeated for the reader of the body.")
|
|
32
71
|
status: int32;
|
|
33
72
|
|
|
34
|
-
@doc("
|
|
73
|
+
@doc("Explanation specific to this occurrence.")
|
|
35
74
|
detail?: string;
|
|
36
75
|
|
|
37
|
-
@doc("
|
|
76
|
+
@doc("URI reference identifying this occurrence.")
|
|
38
77
|
instance?: url;
|
|
39
78
|
|
|
40
|
-
@doc("
|
|
41
|
-
|
|
42
|
-
@header("X-Trace-Id")
|
|
43
|
-
traceId?: TraceId;
|
|
44
|
-
|
|
45
|
-
@doc("Request ID for support")
|
|
46
|
-
@encodedName("application/json", "request_id")
|
|
47
|
-
@header("X-Request-Id")
|
|
48
|
-
requestId?: string;
|
|
49
|
-
|
|
50
|
-
@doc("Timestamp of the error")
|
|
51
|
-
timestamp?: utcDateTime;
|
|
79
|
+
@doc("Stable code of the problem type.")
|
|
80
|
+
code: ProblemCode;
|
|
52
81
|
}
|
|
53
82
|
|
|
54
83
|
// =============================================================================
|
|
55
|
-
//
|
|
84
|
+
// Problem Types
|
|
56
85
|
// =============================================================================
|
|
57
86
|
|
|
58
|
-
@doc("
|
|
59
|
-
@error
|
|
60
|
-
model NotFoundError extends ProblemDetails {
|
|
61
|
-
@statusCode _: 404;
|
|
62
|
-
title: "Not Found";
|
|
63
|
-
|
|
64
|
-
@doc("The type of resource that was not found")
|
|
65
|
-
@encodedName("application/json", "resource_type")
|
|
66
|
-
resourceType?: string;
|
|
67
|
-
|
|
68
|
-
@doc("The identifier that was not found")
|
|
69
|
-
@encodedName("application/json", "resource_id")
|
|
70
|
-
resourceId?: string;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
@doc("Bad request - validation failed (400)")
|
|
87
|
+
@doc("The request failed validation (400).")
|
|
74
88
|
@error
|
|
75
89
|
model ValidationError extends ProblemDetails {
|
|
76
90
|
@statusCode _: 400;
|
|
91
|
+
type: ProblemType.validationFailed;
|
|
92
|
+
code: ProblemCode.validationFailed;
|
|
77
93
|
title: "Validation Failed";
|
|
78
94
|
|
|
79
|
-
@doc("
|
|
95
|
+
@doc("Each rule the request broke.")
|
|
80
96
|
errors: ValidationErrorDetail[];
|
|
81
97
|
}
|
|
82
98
|
|
|
83
|
-
@doc("
|
|
99
|
+
@doc("One rule a request broke.")
|
|
84
100
|
model ValidationErrorDetail {
|
|
85
|
-
@doc("The field
|
|
101
|
+
@doc("The field or parameter that failed validation.")
|
|
86
102
|
field: string;
|
|
87
103
|
|
|
88
|
-
@doc("
|
|
104
|
+
@doc("What is wrong with it.")
|
|
89
105
|
message: string;
|
|
90
106
|
|
|
91
|
-
@doc("The validation rule that failed")
|
|
107
|
+
@doc("The validation rule that failed.")
|
|
92
108
|
code: string;
|
|
93
109
|
|
|
94
|
-
@doc("The rejected value
|
|
110
|
+
@doc("The rejected value, when it is safe to repeat.")
|
|
95
111
|
@encodedName("application/json", "rejected_value")
|
|
96
112
|
rejectedValue?: string;
|
|
97
113
|
}
|
|
98
114
|
|
|
99
|
-
@doc("
|
|
115
|
+
@doc("The request carries no valid credential (401).")
|
|
100
116
|
@error
|
|
101
117
|
model UnauthorizedError extends ProblemDetails {
|
|
102
118
|
@statusCode _: 401;
|
|
119
|
+
type: ProblemType.unauthorized;
|
|
120
|
+
code: ProblemCode.unauthorized;
|
|
103
121
|
title: "Unauthorized";
|
|
104
|
-
|
|
105
|
-
@doc("Authentication scheme expected")
|
|
106
|
-
@header("WWW-Authenticate")
|
|
107
|
-
@encodedName("application/json", "www_authenticate")
|
|
108
|
-
wwwAuthenticate?: string;
|
|
109
122
|
}
|
|
110
123
|
|
|
111
|
-
@doc("
|
|
124
|
+
@doc("The credential is valid but not allowed to do this (403).")
|
|
112
125
|
@error
|
|
113
126
|
model ForbiddenError extends ProblemDetails {
|
|
114
127
|
@statusCode _: 403;
|
|
128
|
+
type: ProblemType.forbidden;
|
|
129
|
+
code: ProblemCode.forbidden;
|
|
115
130
|
title: "Forbidden";
|
|
116
131
|
|
|
117
|
-
@doc("
|
|
132
|
+
@doc("The permission the credential lacks.")
|
|
118
133
|
@encodedName("application/json", "required_permission")
|
|
119
134
|
requiredPermission?: string;
|
|
120
135
|
}
|
|
121
136
|
|
|
122
|
-
@doc("
|
|
137
|
+
@doc("The addressed resource does not exist (404).")
|
|
138
|
+
@error
|
|
139
|
+
model NotFoundError extends ProblemDetails {
|
|
140
|
+
@statusCode _: 404;
|
|
141
|
+
type: ProblemType.notFound;
|
|
142
|
+
code: ProblemCode.notFound;
|
|
143
|
+
title: "Not Found";
|
|
144
|
+
|
|
145
|
+
@doc("The kind of resource that was not found.")
|
|
146
|
+
@encodedName("application/json", "resource_type")
|
|
147
|
+
resourceType?: string;
|
|
148
|
+
|
|
149
|
+
@doc("The identifier that was not found.")
|
|
150
|
+
@encodedName("application/json", "resource_id")
|
|
151
|
+
resourceId?: string;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@doc("The request conflicts with the current state of a resource (409).")
|
|
123
155
|
@error
|
|
124
156
|
model ConflictError extends ProblemDetails {
|
|
125
157
|
@statusCode _: 409;
|
|
158
|
+
type: ProblemType.conflict;
|
|
159
|
+
code: ProblemCode.conflict;
|
|
126
160
|
title: "Conflict";
|
|
127
161
|
|
|
128
|
-
@doc("The conflicting resource
|
|
162
|
+
@doc("The identifier of the conflicting resource.")
|
|
129
163
|
@encodedName("application/json", "conflicting_resource")
|
|
130
164
|
conflictingResource?: string;
|
|
131
165
|
}
|
|
132
166
|
|
|
133
|
-
@doc("
|
|
167
|
+
@doc("The If-Match entity tag is no longer current (412).")
|
|
134
168
|
@error
|
|
135
169
|
model PreconditionFailedError extends ProblemDetails {
|
|
136
170
|
@statusCode _: 412;
|
|
171
|
+
type: ProblemType.preconditionFailed;
|
|
172
|
+
code: ProblemCode.preconditionFailed;
|
|
137
173
|
title: "Precondition Failed";
|
|
138
174
|
|
|
139
|
-
@doc("Entity tag of the current version, when the caller may read it")
|
|
175
|
+
@doc("Entity tag of the current version, when the caller may read it.")
|
|
140
176
|
@encodedName("application/json", "current_etag")
|
|
141
177
|
currentEtag?: string;
|
|
142
178
|
}
|
|
143
179
|
|
|
144
|
-
@doc("
|
|
180
|
+
@doc("The request must send If-Match (428).")
|
|
145
181
|
@error
|
|
146
182
|
model PreconditionRequiredError extends ProblemDetails {
|
|
147
183
|
@statusCode _: 428;
|
|
184
|
+
type: ProblemType.preconditionRequired;
|
|
185
|
+
code: ProblemCode.preconditionRequired;
|
|
148
186
|
title: "Precondition Required";
|
|
149
187
|
|
|
150
|
-
@doc("The header the request must carry")
|
|
188
|
+
@doc("The header the request must carry.")
|
|
151
189
|
@encodedName("application/json", "required_header")
|
|
152
190
|
requiredHeader?: "If-Match";
|
|
153
191
|
}
|
|
154
192
|
|
|
155
|
-
@doc("
|
|
156
|
-
@error
|
|
157
|
-
model RateLimitError extends ProblemDetails {
|
|
158
|
-
@statusCode _: 429;
|
|
159
|
-
title: "Too Many Requests";
|
|
160
|
-
|
|
161
|
-
@doc("Seconds until the rate limit resets")
|
|
162
|
-
@header("Retry-After")
|
|
163
|
-
@encodedName("application/json", "retry_after")
|
|
164
|
-
retryAfter: int32;
|
|
165
|
-
|
|
166
|
-
@doc("Maximum requests allowed per window")
|
|
167
|
-
@header("X-RateLimit-Limit")
|
|
168
|
-
@encodedName("application/json", "rate_limit")
|
|
169
|
-
rateLimit?: int32;
|
|
170
|
-
|
|
171
|
-
@doc("Remaining requests in current window")
|
|
172
|
-
@header("X-RateLimit-Remaining")
|
|
173
|
-
@encodedName("application/json", "rate_limit_remaining")
|
|
174
|
-
rateLimitRemaining?: int32;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
@doc("Internal server error (500)")
|
|
193
|
+
@doc("The server failed while handling the request (500).")
|
|
178
194
|
@error
|
|
179
195
|
model InternalServerError extends ProblemDetails {
|
|
180
196
|
@statusCode _: 500;
|
|
197
|
+
type: ProblemType.internalError;
|
|
198
|
+
code: ProblemCode.internalError;
|
|
181
199
|
title: "Internal Server Error";
|
|
182
|
-
|
|
183
|
-
@doc("Error code for support reference")
|
|
184
|
-
@encodedName("application/json", "error_code")
|
|
185
|
-
errorCode?: string;
|
|
186
200
|
}
|
|
187
201
|
|
|
188
|
-
@doc("
|
|
202
|
+
@doc("An upstream dependency failed while the server handled the request (502).")
|
|
189
203
|
@error
|
|
190
204
|
model BadGatewayError extends ProblemDetails {
|
|
191
205
|
@statusCode _: 502;
|
|
206
|
+
type: ProblemType.badGateway;
|
|
207
|
+
code: ProblemCode.badGateway;
|
|
192
208
|
title: "Bad Gateway";
|
|
193
209
|
|
|
194
|
-
@doc("Stable dependency category; never
|
|
210
|
+
@doc("Stable dependency category; never raw exception text.")
|
|
195
211
|
dependency?: string;
|
|
196
212
|
}
|
|
197
213
|
|
|
198
|
-
@doc("
|
|
214
|
+
@doc("The server cannot take the request at present (503).")
|
|
199
215
|
@error
|
|
200
216
|
model ServiceUnavailableError extends ProblemDetails {
|
|
201
217
|
@statusCode _: 503;
|
|
218
|
+
type: ProblemType.serviceUnavailable;
|
|
219
|
+
code: ProblemCode.serviceUnavailable;
|
|
202
220
|
title: "Service Unavailable";
|
|
203
221
|
|
|
204
|
-
@doc("
|
|
205
|
-
@header("Retry-After")
|
|
206
|
-
@encodedName("application/json", "retry_after")
|
|
207
|
-
retryAfter?: int32;
|
|
208
|
-
|
|
209
|
-
@doc("Reason for unavailability")
|
|
222
|
+
@doc("Why the server is unavailable.")
|
|
210
223
|
reason?: "maintenance" | "overloaded" | "dependency_failure";
|
|
211
224
|
}
|
|
212
|
-
|
|
213
|
-
// =============================================================================
|
|
214
|
-
// Error Response Union
|
|
215
|
-
// =============================================================================
|
|
216
|
-
|
|
217
|
-
@doc("Standard error response types")
|
|
218
|
-
union ApiError {
|
|
219
|
-
@doc("Resource not found")
|
|
220
|
-
notFound: NotFoundError,
|
|
221
|
-
|
|
222
|
-
@doc("Validation failed")
|
|
223
|
-
validation: ValidationError,
|
|
224
|
-
|
|
225
|
-
@doc("Authentication required")
|
|
226
|
-
unauthorized: UnauthorizedError,
|
|
227
|
-
|
|
228
|
-
@doc("Permission denied")
|
|
229
|
-
forbidden: ForbiddenError,
|
|
230
|
-
|
|
231
|
-
@doc("Resource conflict")
|
|
232
|
-
conflict: ConflictError,
|
|
233
|
-
|
|
234
|
-
@doc("Entity tag no longer current")
|
|
235
|
-
preconditionFailed: PreconditionFailedError,
|
|
236
|
-
|
|
237
|
-
@doc("If-Match missing")
|
|
238
|
-
preconditionRequired: PreconditionRequiredError,
|
|
239
|
-
|
|
240
|
-
@doc("Rate limit exceeded")
|
|
241
|
-
rateLimit: RateLimitError,
|
|
242
|
-
|
|
243
|
-
@doc("Server error")
|
|
244
|
-
serverError: InternalServerError,
|
|
245
|
-
|
|
246
|
-
@doc("Upstream dependency failed")
|
|
247
|
-
badGateway: BadGatewayError,
|
|
248
|
-
|
|
249
|
-
@doc("Service unavailable")
|
|
250
|
-
unavailable: ServiceUnavailableError,
|
|
251
|
-
}
|
package/common/pagination.tsp
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
// =============================================================================
|
|
2
|
-
// Qyl API pagination
|
|
2
|
+
// Qyl API cursor pagination
|
|
3
3
|
// =============================================================================
|
|
4
|
-
//
|
|
4
|
+
// Every list operation pages the same way: it is a `@list` operation, spreads
|
|
5
|
+
// `CursorPageQuery` (one page-size rule, one cursor parameter) and answers a
|
|
6
|
+
// page whose items carry `@pageItems` and whose opaque `Cursor` carries
|
|
7
|
+
// `@continuationToken`. The cursor is a token the client passes back, never a
|
|
8
|
+
// link it follows, and the last page omits it.
|
|
5
9
|
// =============================================================================
|
|
6
10
|
|
|
7
11
|
import "@typespec/http";
|
|
@@ -11,244 +15,37 @@ using TypeSpec.Http;
|
|
|
11
15
|
|
|
12
16
|
namespace Qyl.Api.Contracts.Common.Pagination;
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
@doc("Page size of a list operation: at least 1 and at most 1000 items.")
|
|
19
|
+
@minValue(1)
|
|
20
|
+
@maxValue(1000)
|
|
21
|
+
scalar PageLimit extends int32;
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
// The query parameters of every list operation. An alias, not a model, so it
|
|
24
|
+
// reaches the wire only as the parameters of the operations that spread it.
|
|
25
|
+
alias CursorPageQuery = {
|
|
26
|
+
@doc("Page size; 100 when omitted.")
|
|
21
27
|
@query
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
@doc("Maximum number of items to return (1-1000)")
|
|
25
|
-
@query
|
|
26
|
-
@minValue(1)
|
|
27
|
-
@maxValue(1000)
|
|
28
|
-
limit?: int32 = 100;
|
|
28
|
+
@pageSize
|
|
29
|
+
limit?: PageLimit = 100;
|
|
29
30
|
|
|
30
|
-
@doc("
|
|
31
|
+
@doc("The `next_cursor` of the previous page of the same query; omitted for the first page.")
|
|
31
32
|
@query
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@doc("Sort order")
|
|
36
|
-
enum SortOrder {
|
|
37
|
-
@doc("Ascending order (oldest first)")
|
|
38
|
-
asc,
|
|
39
|
-
|
|
40
|
-
@doc("Descending order (newest first)")
|
|
41
|
-
desc,
|
|
42
|
-
}
|
|
33
|
+
@continuationToken
|
|
34
|
+
cursor?: Cursor;
|
|
35
|
+
};
|
|
43
36
|
|
|
44
|
-
@doc("
|
|
37
|
+
@doc("One page of a list operation.")
|
|
45
38
|
model CursorPage<T> {
|
|
46
|
-
@doc("
|
|
39
|
+
@doc("The items of this page.")
|
|
47
40
|
@pageItems
|
|
48
41
|
items: T[];
|
|
49
42
|
|
|
50
|
-
@doc("Cursor
|
|
43
|
+
@doc("Cursor of the next page, passed back as the `cursor` query parameter. Absent on the last page.")
|
|
51
44
|
@encodedName("application/json", "next_cursor")
|
|
52
|
-
@nextLink
|
|
53
|
-
nextCursor?: string;
|
|
54
|
-
|
|
55
|
-
@doc("Cursor for the previous page (null if first page)")
|
|
56
|
-
@encodedName("application/json", "prev_cursor")
|
|
57
|
-
prevCursor?: string;
|
|
58
|
-
|
|
59
|
-
@doc("Whether there are more items available")
|
|
60
|
-
@encodedName("application/json", "has_more")
|
|
61
|
-
hasMore: boolean;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// =============================================================================
|
|
65
|
-
// Offset-Based Pagination (For Small/Medium Datasets)
|
|
66
|
-
// =============================================================================
|
|
67
|
-
|
|
68
|
-
@doc("Offset-based pagination parameters")
|
|
69
|
-
model OffsetPaginationParams {
|
|
70
|
-
@doc("Page number (1-indexed)")
|
|
71
|
-
@query
|
|
72
|
-
@pageIndex
|
|
73
|
-
@minValue(1)
|
|
74
|
-
page?: int32 = 1;
|
|
75
|
-
|
|
76
|
-
@doc("Items per page (1-1000)")
|
|
77
|
-
@query("page_size")
|
|
78
|
-
@pageSize
|
|
79
|
-
@minValue(1)
|
|
80
|
-
@maxValue(1000)
|
|
81
|
-
@encodedName("application/json", "page_size")
|
|
82
|
-
pageSize?: int32 = 100;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
@doc("Offset-based paginated response wrapper")
|
|
86
|
-
model OffsetPage<T> {
|
|
87
|
-
@doc("List of items in this page")
|
|
88
|
-
@pageItems
|
|
89
|
-
items: T[];
|
|
90
|
-
|
|
91
|
-
@doc("Current page number")
|
|
92
|
-
page: int32;
|
|
93
|
-
|
|
94
|
-
@doc("Items per page")
|
|
95
|
-
@encodedName("application/json", "page_size")
|
|
96
|
-
pageSize: int32;
|
|
97
|
-
|
|
98
|
-
@doc("Total number of items across all pages")
|
|
99
|
-
@encodedName("application/json", "total_count")
|
|
100
|
-
totalCount: int64;
|
|
101
|
-
|
|
102
|
-
@doc("Total number of pages")
|
|
103
|
-
@encodedName("application/json", "total_pages")
|
|
104
|
-
totalPages: int32;
|
|
105
|
-
|
|
106
|
-
@doc("Whether there is a next page")
|
|
107
|
-
@encodedName("application/json", "has_next")
|
|
108
|
-
hasNext: boolean;
|
|
109
|
-
|
|
110
|
-
@doc("Whether there is a previous page")
|
|
111
|
-
@encodedName("application/json", "has_prev")
|
|
112
|
-
hasPrev: boolean;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// =============================================================================
|
|
116
|
-
// Time-Range Pagination (For Time-Series Data)
|
|
117
|
-
// =============================================================================
|
|
118
|
-
|
|
119
|
-
@doc("Time-range based query parameters")
|
|
120
|
-
model TimeRangeParams {
|
|
121
|
-
@doc("Start of time range (inclusive)")
|
|
122
|
-
@query("start_time")
|
|
123
|
-
@encodedName("application/json", "start_time")
|
|
124
|
-
startTime?: utcDateTime;
|
|
125
|
-
|
|
126
|
-
@doc("End of time range (exclusive)")
|
|
127
|
-
@query("end_time")
|
|
128
|
-
@encodedName("application/json", "end_time")
|
|
129
|
-
endTime?: utcDateTime;
|
|
130
|
-
|
|
131
|
-
@doc("Maximum number of items to return")
|
|
132
|
-
@query
|
|
133
|
-
@minValue(1)
|
|
134
|
-
@maxValue(10000)
|
|
135
|
-
limit?: int32 = 1000;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
@doc("Time-range paginated response with continuation")
|
|
139
|
-
model TimeRangePage<T> {
|
|
140
|
-
@doc("List of items in this page")
|
|
141
|
-
@pageItems
|
|
142
|
-
items: T[];
|
|
143
|
-
|
|
144
|
-
@doc("Actual start time of returned data")
|
|
145
|
-
@encodedName("application/json", "start_time")
|
|
146
|
-
startTime: utcDateTime;
|
|
147
|
-
|
|
148
|
-
@doc("Actual end time of returned data")
|
|
149
|
-
@encodedName("application/json", "end_time")
|
|
150
|
-
endTime: utcDateTime;
|
|
151
|
-
|
|
152
|
-
@doc("Continuation token for next time window")
|
|
153
|
-
@encodedName("application/json", "continuation_token")
|
|
154
45
|
@continuationToken
|
|
155
|
-
|
|
46
|
+
nextCursor?: Cursor;
|
|
156
47
|
|
|
157
|
-
@doc("Whether
|
|
48
|
+
@doc("Whether more items follow this page. `next_cursor` is present exactly when this is true.")
|
|
158
49
|
@encodedName("application/json", "has_more")
|
|
159
50
|
hasMore: boolean;
|
|
160
|
-
|
|
161
|
-
@doc("Number of items returned")
|
|
162
|
-
count: int32;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// =============================================================================
|
|
166
|
-
// Streaming Pagination (For Real-Time Data)
|
|
167
|
-
// =============================================================================
|
|
168
|
-
|
|
169
|
-
@doc("Streaming parameters for SSE endpoints")
|
|
170
|
-
model StreamParams {
|
|
171
|
-
@doc("Include historical data from this timestamp")
|
|
172
|
-
@query
|
|
173
|
-
since?: utcDateTime;
|
|
174
|
-
|
|
175
|
-
@doc("Filter by trace ID")
|
|
176
|
-
@query("trace_id")
|
|
177
|
-
@encodedName("application/json", "trace_id")
|
|
178
|
-
traceId?: TraceId;
|
|
179
|
-
|
|
180
|
-
@doc("Filter by service name")
|
|
181
|
-
@query("service_name")
|
|
182
|
-
@encodedName("application/json", "service_name")
|
|
183
|
-
serviceName?: string;
|
|
184
|
-
|
|
185
|
-
@doc("Maximum events per second (rate limiting)")
|
|
186
|
-
@query("max_events_per_second")
|
|
187
|
-
@encodedName("application/json", "max_events_per_second")
|
|
188
|
-
@minValue(1)
|
|
189
|
-
@maxValue(1000)
|
|
190
|
-
maxEventsPerSecond?: int32 = 100;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
@doc("SSE event wrapper for streaming")
|
|
194
|
-
model StreamEvent<T> {
|
|
195
|
-
@doc("Event ID for resumption")
|
|
196
|
-
id: string;
|
|
197
|
-
|
|
198
|
-
@doc("Event type")
|
|
199
|
-
@encodedName("application/json", "event_type")
|
|
200
|
-
eventType: string;
|
|
201
|
-
|
|
202
|
-
@doc("Event timestamp")
|
|
203
|
-
timestamp: utcDateTime;
|
|
204
|
-
|
|
205
|
-
@doc("Event data payload")
|
|
206
|
-
data: T;
|
|
207
|
-
|
|
208
|
-
@doc("Retry interval hint in milliseconds")
|
|
209
|
-
retry?: int32;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// =============================================================================
|
|
213
|
-
// Aggregation Parameters
|
|
214
|
-
// =============================================================================
|
|
215
|
-
|
|
216
|
-
@doc("Time bucket size for aggregations")
|
|
217
|
-
enum TimeBucket {
|
|
218
|
-
@doc("1 minute buckets")
|
|
219
|
-
minute: "1m",
|
|
220
|
-
|
|
221
|
-
@doc("5 minute buckets")
|
|
222
|
-
fiveMinutes: "5m",
|
|
223
|
-
|
|
224
|
-
@doc("15 minute buckets")
|
|
225
|
-
fifteenMinutes: "15m",
|
|
226
|
-
|
|
227
|
-
@doc("1 hour buckets")
|
|
228
|
-
hour: "1h",
|
|
229
|
-
|
|
230
|
-
@doc("1 day buckets")
|
|
231
|
-
day: "1d",
|
|
232
|
-
|
|
233
|
-
@doc("1 week buckets")
|
|
234
|
-
week: "1w",
|
|
235
|
-
|
|
236
|
-
@doc("Auto-select based on time range")
|
|
237
|
-
auto: "auto",
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
@doc("Aggregation query parameters")
|
|
241
|
-
model AggregationParams {
|
|
242
|
-
@doc("Time bucket size")
|
|
243
|
-
@query
|
|
244
|
-
bucket?: TimeBucket = TimeBucket.auto;
|
|
245
|
-
|
|
246
|
-
@doc("Group by these dimensions")
|
|
247
|
-
@query("group_by")
|
|
248
|
-
@encodedName("application/json", "group_by")
|
|
249
|
-
groupBy?: string[];
|
|
250
|
-
|
|
251
|
-
@doc("Filter expression")
|
|
252
|
-
@query
|
|
253
|
-
filter?: string;
|
|
254
51
|
}
|
package/common/resource.tsp
CHANGED
|
@@ -32,13 +32,6 @@ scalar ResourceId extends string;
|
|
|
32
32
|
@maxLength(128)
|
|
33
33
|
scalar ETag extends string;
|
|
34
34
|
|
|
35
|
-
@doc("""
|
|
36
|
-
Opaque pagination cursor. Pass the `next_cursor` of one page to receive the
|
|
37
|
-
next page of the same query. Its content is not part of the contract and
|
|
38
|
-
must not be parsed or built by a client.
|
|
39
|
-
""")
|
|
40
|
-
scalar Cursor extends string;
|
|
41
|
-
|
|
42
35
|
@doc("""
|
|
43
36
|
Collector API key roles. Every key sent in `x-otlp-api-key` carries one or
|
|
44
37
|
more roles: `ingest` accepts OTLP, `read` serves the query routes, `write`
|
package/common/types.tsp
CHANGED
|
@@ -159,10 +159,18 @@ scalar Temperature extends float64;
|
|
|
159
159
|
@maxLength(64)
|
|
160
160
|
scalar Sha256Hash extends string;
|
|
161
161
|
|
|
162
|
+
@doc("""
|
|
163
|
+
Opaque pagination cursor. Pass the `next_cursor` of one page to receive the
|
|
164
|
+
next page of the same query. Its content is not part of the contract and
|
|
165
|
+
must not be parsed or built by a client.
|
|
166
|
+
""")
|
|
167
|
+
scalar Cursor extends string;
|
|
168
|
+
|
|
162
169
|
// The revision is a canonical digest of the semantic OpenAPI projection and the
|
|
163
170
|
// exported telemetry-key projection, not a package version. Presentation-only
|
|
164
|
-
// fields
|
|
165
|
-
// for equality, never used
|
|
171
|
+
// fields and the release version stamped into `info.version` do not change it.
|
|
172
|
+
// Truncated to 16 hex characters because it is compared for equality, never used
|
|
173
|
+
// as a security boundary.
|
|
166
174
|
@doc("Deterministic revision of the generated API contract: 'sha256:' followed by the first 16 hex characters of its canonical semantic digest.")
|
|
167
175
|
@pattern("^sha256:[a-f0-9]{16}$")
|
|
168
176
|
@minLength(23)
|