skuse-ui 0.1.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/LICENSE +21 -0
- package/README.md +63 -0
- package/dist/SkuseDocumentation.d.ts +10 -0
- package/dist/components/Skeletons/EndpointSkeleton.d.ts +2 -0
- package/dist/components/Skeletons/HomeSkeleton.d.ts +2 -0
- package/dist/components/Skeletons/LayoutSkeleton.d.ts +2 -0
- package/dist/components/Skeletons/SidebarSkeleton.d.ts +1 -0
- package/dist/components/layouts/MinimifiedInfo.d.ts +6 -0
- package/dist/components/layouts/Sidebar.d.ts +3 -0
- package/dist/components/openapi/Auth/AuthButton.d.ts +11 -0
- package/dist/components/openapi/Auth/AuthCard.d.ts +7 -0
- package/dist/components/openapi/Auth/AuthDialog.d.ts +8 -0
- package/dist/components/openapi/Auth/AuthMethods.d.ts +14 -0
- package/dist/components/openapi/Endpoint/CallbackViewer.d.ts +6 -0
- package/dist/components/openapi/Endpoint/CodeExamples.d.ts +16 -0
- package/dist/components/openapi/Endpoint/EndpointDetails.d.ts +3 -0
- package/dist/components/openapi/Endpoint/ExternalDocsLink.d.ts +6 -0
- package/dist/components/openapi/Endpoint/ParametersViewer.d.ts +7 -0
- package/dist/components/openapi/Endpoint/PlaygroundForm.d.ts +23 -0
- package/dist/components/openapi/Endpoint/PlaygroundResponse.d.ts +13 -0
- package/dist/components/openapi/Endpoint/RequestBodyViewer.d.ts +8 -0
- package/dist/components/openapi/Endpoint/ResponseViewer.d.ts +9 -0
- package/dist/components/openapi/Endpoint/SchemaBadges.d.ts +8 -0
- package/dist/components/openapi/Endpoint/SchemaExpandContext.d.ts +6 -0
- package/dist/components/openapi/Endpoint/SchemaProperty.d.ts +11 -0
- package/dist/components/openapi/Endpoint/SchemaViewer.d.ts +13 -0
- package/dist/components/openapi/FormattedMarkdown.d.ts +12 -0
- package/dist/components/openapi/Information.d.ts +3 -0
- package/dist/components/openapi/Models.d.ts +3 -0
- package/dist/components/openapi/Servers.d.ts +7 -0
- package/dist/components/openapi/TagsOverview.d.ts +3 -0
- package/dist/components/openapi/WebhookDetails.d.ts +3 -0
- package/dist/components/theme-provider.d.ts +13 -0
- package/dist/components/ui/accordion.d.ts +7 -0
- package/dist/components/ui/alert.d.ts +8 -0
- package/dist/components/ui/badge.d.ts +9 -0
- package/dist/components/ui/button.d.ts +11 -0
- package/dist/components/ui/card.d.ts +8 -0
- package/dist/components/ui/carousel.d.ts +18 -0
- package/dist/components/ui/checkbox.d.ts +4 -0
- package/dist/components/ui/collapsible.d.ts +5 -0
- package/dist/components/ui/command.d.ts +80 -0
- package/dist/components/ui/dialog.d.ts +19 -0
- package/dist/components/ui/input.d.ts +3 -0
- package/dist/components/ui/label.d.ts +5 -0
- package/dist/components/ui/popover.d.ts +6 -0
- package/dist/components/ui/select.d.ts +13 -0
- package/dist/components/ui/sheet.d.ts +25 -0
- package/dist/components/ui/skeleton.d.ts +2 -0
- package/dist/components/ui/sonner.d.ts +4 -0
- package/dist/components/ui/switch.d.ts +4 -0
- package/dist/components/ui/tabs.d.ts +7 -0
- package/dist/components/ui/tooltip.d.ts +7 -0
- package/dist/hooks/OpenAPIContext.d.ts +24 -0
- package/dist/hooks/usePlayground.d.ts +40 -0
- package/dist/hooks/useSpec.d.ts +10 -0
- package/dist/index.d.ts +2 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/main.d.ts +0 -0
- package/dist/router/routes.d.ts +2 -0
- package/dist/skuse-ui.cjs.js +459 -0
- package/dist/skuse-ui.es.js +61257 -0
- package/dist/style.css +1 -0
- package/dist/test-spec.json +779 -0
- package/dist/types/openapi.d.ts +2 -0
- package/dist/types/unified-openapi-types.d.ts +402 -0
- package/dist/utils/openapi.d.ts +18 -0
- package/dist/utils/pkce.d.ts +2 -0
- package/package.json +94 -0
|
@@ -0,0 +1,779 @@
|
|
|
1
|
+
{
|
|
2
|
+
"openapi": "3.1.0",
|
|
3
|
+
"info": {
|
|
4
|
+
"title": "Skuse Test API",
|
|
5
|
+
"summary": "A test spec covering OAS 3.1 features",
|
|
6
|
+
"version": "1.0.0",
|
|
7
|
+
"description": "Local test spec to validate Skuse features — schema.examples, global security, tag descriptions, models, etc."
|
|
8
|
+
},
|
|
9
|
+
"security": [{ "bearerAuth": [] }],
|
|
10
|
+
"tags": [
|
|
11
|
+
{
|
|
12
|
+
"name": "books",
|
|
13
|
+
"description": "Operations about books in the library",
|
|
14
|
+
"externalDocs": {
|
|
15
|
+
"description": "Books documentation",
|
|
16
|
+
"url": "https://example.com/docs/books"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "authors",
|
|
21
|
+
"description": "Author management endpoints"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "media",
|
|
25
|
+
"description": "Polymorphic media items — tests discriminator rendering"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "oas31",
|
|
29
|
+
"description": "OAS 3.1 edge cases — prefixItems, if/then/else, additionalProperties:false, titled variants, canExpand on non-property schemas"
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"servers": [
|
|
33
|
+
{ "url": "https://api.example.com/v1", "description": "Production" },
|
|
34
|
+
{ "url": "https://staging.example.com/v1", "description": "Staging" }
|
|
35
|
+
],
|
|
36
|
+
"paths": {
|
|
37
|
+
"/books": {
|
|
38
|
+
"get": {
|
|
39
|
+
"tags": ["books"],
|
|
40
|
+
"operationId": "getBooks",
|
|
41
|
+
"summary": "List all books",
|
|
42
|
+
"description": "Returns a paginated list of books. Supports filtering by author and genre.",
|
|
43
|
+
"parameters": [
|
|
44
|
+
{
|
|
45
|
+
"name": "page",
|
|
46
|
+
"in": "query",
|
|
47
|
+
"schema": { "type": "integer", "default": 1 },
|
|
48
|
+
"description": "Page number"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "limit",
|
|
52
|
+
"in": "query",
|
|
53
|
+
"schema": { "type": "integer", "default": 20 },
|
|
54
|
+
"description": "Items per page"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"name": "author",
|
|
58
|
+
"in": "query",
|
|
59
|
+
"schema": { "type": "string" },
|
|
60
|
+
"description": "Filter by author name",
|
|
61
|
+
"deprecated": true
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
"responses": {
|
|
65
|
+
"200": {
|
|
66
|
+
"description": "A list of books",
|
|
67
|
+
"content": {
|
|
68
|
+
"application/json": {
|
|
69
|
+
"schema": {
|
|
70
|
+
"$ref": "#/components/schemas/BookList"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"links": {
|
|
75
|
+
"GetBookById": {
|
|
76
|
+
"operationId": "getBook",
|
|
77
|
+
"parameters": { "id": "$response.body#/data/0/id" },
|
|
78
|
+
"description": "Use the id of the first book to fetch its details"
|
|
79
|
+
},
|
|
80
|
+
"ListAuthors": {
|
|
81
|
+
"operationId": "getAuthors",
|
|
82
|
+
"description": "Browse authors of the returned books"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"post": {
|
|
89
|
+
"tags": ["books"],
|
|
90
|
+
"operationId": "createBook",
|
|
91
|
+
"summary": "Create a book",
|
|
92
|
+
"security": [{ "bearerAuth": [] }],
|
|
93
|
+
"callbacks": {
|
|
94
|
+
"onBookIndexed": {
|
|
95
|
+
"{$request.body#/callbackUrl}": {
|
|
96
|
+
"post": {
|
|
97
|
+
"summary": "Book indexed notification",
|
|
98
|
+
"description": "Sent when the newly created book has been indexed and is searchable.",
|
|
99
|
+
"requestBody": {
|
|
100
|
+
"required": true,
|
|
101
|
+
"content": {
|
|
102
|
+
"application/json": {
|
|
103
|
+
"schema": {
|
|
104
|
+
"type": "object",
|
|
105
|
+
"properties": {
|
|
106
|
+
"bookId": { "type": "integer", "description": "ID of the indexed book" },
|
|
107
|
+
"indexedAt": { "type": "string", "format": "date-time" }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"responses": {
|
|
114
|
+
"200": { "description": "Callback received" }
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"requestBody": {
|
|
121
|
+
"required": true,
|
|
122
|
+
"content": {
|
|
123
|
+
"application/json": {
|
|
124
|
+
"schema": {
|
|
125
|
+
"$ref": "#/components/schemas/BookInput"
|
|
126
|
+
},
|
|
127
|
+
"examples": {
|
|
128
|
+
"fiction": {
|
|
129
|
+
"summary": "Fiction book",
|
|
130
|
+
"value": { "title": "Dune", "author": "Frank Herbert", "genre": "fiction", "year": 1965 }
|
|
131
|
+
},
|
|
132
|
+
"nonfiction": {
|
|
133
|
+
"summary": "Non-fiction book",
|
|
134
|
+
"value": { "title": "Sapiens", "author": "Yuval Noah Harari", "genre": "history", "year": 2011 }
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"responses": {
|
|
141
|
+
"201": {
|
|
142
|
+
"description": "Book created",
|
|
143
|
+
"content": {
|
|
144
|
+
"application/json": {
|
|
145
|
+
"schema": { "$ref": "#/components/schemas/Book" }
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
"/books/{id}": {
|
|
153
|
+
"summary": "Operations on a specific book",
|
|
154
|
+
"description": "All endpoints under this path operate on a single book identified by its numeric `id`.",
|
|
155
|
+
"get": {
|
|
156
|
+
"tags": ["books"],
|
|
157
|
+
"operationId": "getBook",
|
|
158
|
+
"summary": "Get a book",
|
|
159
|
+
"parameters": [
|
|
160
|
+
{
|
|
161
|
+
"name": "id",
|
|
162
|
+
"in": "path",
|
|
163
|
+
"required": true,
|
|
164
|
+
"schema": { "type": "integer" },
|
|
165
|
+
"description": "Book ID"
|
|
166
|
+
}
|
|
167
|
+
],
|
|
168
|
+
"responses": {
|
|
169
|
+
"200": {
|
|
170
|
+
"description": "A single book. The schema.examples array (OAS 3.1) is used here to test the multi-example selector.",
|
|
171
|
+
"content": {
|
|
172
|
+
"application/json": {
|
|
173
|
+
"schema": {
|
|
174
|
+
"type": "object",
|
|
175
|
+
"properties": {
|
|
176
|
+
"id": { "type": "integer" },
|
|
177
|
+
"title": { "type": "string" },
|
|
178
|
+
"author": { "type": "string" },
|
|
179
|
+
"genre": { "type": "string", "enum": ["fiction", "nonfiction", "history", "science"] },
|
|
180
|
+
"year": { "type": "integer" },
|
|
181
|
+
"available": { "type": "boolean" }
|
|
182
|
+
},
|
|
183
|
+
"examples": [
|
|
184
|
+
{ "id": 1, "title": "Dune", "author": "Frank Herbert", "genre": "fiction", "year": 1965, "available": true },
|
|
185
|
+
{ "id": 2, "title": "Sapiens", "author": "Yuval Noah Harari", "genre": "history", "year": 2011, "available": false },
|
|
186
|
+
{ "id": 3, "title": "A Brief History of Time", "author": "Stephen Hawking", "genre": "science", "year": 1988, "available": true }
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
"404": {
|
|
193
|
+
"description": "Book not found"
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
"delete": {
|
|
198
|
+
"tags": ["books"],
|
|
199
|
+
"operationId": "deleteBook",
|
|
200
|
+
"summary": "Delete a book",
|
|
201
|
+
"description": "Permanently deletes a book. This action cannot be undone.",
|
|
202
|
+
"security": [],
|
|
203
|
+
"parameters": [
|
|
204
|
+
{
|
|
205
|
+
"name": "id",
|
|
206
|
+
"in": "path",
|
|
207
|
+
"required": true,
|
|
208
|
+
"schema": { "type": "integer" }
|
|
209
|
+
}
|
|
210
|
+
],
|
|
211
|
+
"responses": {
|
|
212
|
+
"204": { "description": "Deleted successfully" },
|
|
213
|
+
"403": { "description": "Forbidden" }
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
"/authors": {
|
|
218
|
+
"get": {
|
|
219
|
+
"tags": ["authors"],
|
|
220
|
+
"operationId": "getAuthors",
|
|
221
|
+
"summary": "List authors",
|
|
222
|
+
"responses": {
|
|
223
|
+
"200": {
|
|
224
|
+
"description": "List of authors",
|
|
225
|
+
"content": {
|
|
226
|
+
"application/json": {
|
|
227
|
+
"schema": { "$ref": "#/components/schemas/AuthorList" }
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
"/authors/{id}": {
|
|
235
|
+
"get": {
|
|
236
|
+
"tags": ["authors"],
|
|
237
|
+
"operationId": "getAuthor",
|
|
238
|
+
"summary": "Get an author",
|
|
239
|
+
"parameters": [
|
|
240
|
+
{
|
|
241
|
+
"name": "id",
|
|
242
|
+
"in": "path",
|
|
243
|
+
"required": true,
|
|
244
|
+
"schema": { "type": "integer" }
|
|
245
|
+
}
|
|
246
|
+
],
|
|
247
|
+
"responses": {
|
|
248
|
+
"200": {
|
|
249
|
+
"description": "Author details",
|
|
250
|
+
"content": {
|
|
251
|
+
"application/json": {
|
|
252
|
+
"schema": { "$ref": "#/components/schemas/Author" }
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
"/books/{id}/cover": {
|
|
260
|
+
"put": {
|
|
261
|
+
"tags": ["books"],
|
|
262
|
+
"operationId": "uploadBookCover",
|
|
263
|
+
"summary": "Upload a book cover image",
|
|
264
|
+
"description": "Tests `contentMediaType` and `contentEncoding` rendering (OAS 3.1).",
|
|
265
|
+
"parameters": [
|
|
266
|
+
{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }
|
|
267
|
+
],
|
|
268
|
+
"requestBody": {
|
|
269
|
+
"required": true,
|
|
270
|
+
"content": {
|
|
271
|
+
"application/json": {
|
|
272
|
+
"schema": {
|
|
273
|
+
"type": "object",
|
|
274
|
+
"required": ["filename", "data"],
|
|
275
|
+
"properties": {
|
|
276
|
+
"filename": { "type": "string", "description": "Original filename" },
|
|
277
|
+
"data": {
|
|
278
|
+
"type": "string",
|
|
279
|
+
"contentMediaType": "image/png",
|
|
280
|
+
"contentEncoding": "base64",
|
|
281
|
+
"description": "Base64-encoded PNG image"
|
|
282
|
+
},
|
|
283
|
+
"thumbnail": {
|
|
284
|
+
"type": "string",
|
|
285
|
+
"contentMediaType": "image/jpeg",
|
|
286
|
+
"contentEncoding": "base64",
|
|
287
|
+
"description": "Optional base64-encoded JPEG thumbnail"
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
"responses": {
|
|
295
|
+
"200": { "description": "Cover uploaded" }
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
"/validate": {
|
|
300
|
+
"post": {
|
|
301
|
+
"tags": ["media"],
|
|
302
|
+
"operationId": "validateId",
|
|
303
|
+
"summary": "Validate a strict identifier",
|
|
304
|
+
"description": "Tests `not` schema rendering — the request body uses `StrictId` which contains `not` constraints.",
|
|
305
|
+
"requestBody": {
|
|
306
|
+
"required": true,
|
|
307
|
+
"content": {
|
|
308
|
+
"application/json": {
|
|
309
|
+
"schema": { "$ref": "#/components/schemas/StrictId" }
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
"responses": {
|
|
314
|
+
"200": { "description": "Valid" },
|
|
315
|
+
"422": { "description": "Validation error" }
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
"/geo/track": {
|
|
320
|
+
"get": {
|
|
321
|
+
"tags": ["oas31"],
|
|
322
|
+
"operationId": "getGeoTrack",
|
|
323
|
+
"summary": "Get a GPS track",
|
|
324
|
+
"description": "Returns an array of `GeoPoint` tuples. Tests **prefixItems** rendering — each point is a `[latitude, longitude, elevation]` tuple. The extra `items: false` means no additional positional items are allowed beyond the three defined.",
|
|
325
|
+
"responses": {
|
|
326
|
+
"200": {
|
|
327
|
+
"description": "Array of GPS points",
|
|
328
|
+
"content": {
|
|
329
|
+
"application/json": {
|
|
330
|
+
"schema": {
|
|
331
|
+
"type": "array",
|
|
332
|
+
"items": { "$ref": "#/components/schemas/GeoPoint" }
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
"/events": {
|
|
341
|
+
"post": {
|
|
342
|
+
"tags": ["oas31"],
|
|
343
|
+
"operationId": "createEvent",
|
|
344
|
+
"summary": "Create an event",
|
|
345
|
+
"description": "Tests **if/then/else** conditional schemas. If `type` is `online`, the `url` field becomes required. Otherwise, `location` is required instead.",
|
|
346
|
+
"requestBody": {
|
|
347
|
+
"required": true,
|
|
348
|
+
"content": {
|
|
349
|
+
"application/json": {
|
|
350
|
+
"schema": { "$ref": "#/components/schemas/EventPayload" }
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
"responses": {
|
|
355
|
+
"201": { "description": "Event created" }
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
"/config": {
|
|
360
|
+
"get": {
|
|
361
|
+
"tags": ["oas31"],
|
|
362
|
+
"operationId": "getConfig",
|
|
363
|
+
"summary": "Get user configuration",
|
|
364
|
+
"description": "Tests **additionalProperties: false** — the response schema is a closed object. No properties beyond `theme` and `language` are permitted.",
|
|
365
|
+
"responses": {
|
|
366
|
+
"200": {
|
|
367
|
+
"description": "User configuration",
|
|
368
|
+
"content": {
|
|
369
|
+
"application/json": {
|
|
370
|
+
"schema": { "$ref": "#/components/schemas/StrictConfig" }
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
"put": {
|
|
377
|
+
"tags": ["oas31"],
|
|
378
|
+
"operationId": "updateConfig",
|
|
379
|
+
"summary": "Update user configuration",
|
|
380
|
+
"description": "Same closed schema on the request body.",
|
|
381
|
+
"requestBody": {
|
|
382
|
+
"required": true,
|
|
383
|
+
"content": {
|
|
384
|
+
"application/json": {
|
|
385
|
+
"schema": { "$ref": "#/components/schemas/StrictConfig" }
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
"responses": {
|
|
390
|
+
"200": { "description": "Configuration updated" }
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
"/metrics": {
|
|
395
|
+
"post": {
|
|
396
|
+
"tags": ["oas31"],
|
|
397
|
+
"operationId": "pushMetrics",
|
|
398
|
+
"summary": "Push a metric bag",
|
|
399
|
+
"description": "Tests **patternProperties** + **additionalProperties as object** together. `MetricBag` has one fixed field (`timestamp`), any key matching `^metric_` must be a number, and all other extra keys must be strings. The childCount badge should reflect all three categories.",
|
|
400
|
+
"requestBody": {
|
|
401
|
+
"required": true,
|
|
402
|
+
"content": {
|
|
403
|
+
"application/json": {
|
|
404
|
+
"schema": { "$ref": "#/components/schemas/MetricBag" }
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
"responses": {
|
|
409
|
+
"204": { "description": "Metrics recorded" }
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
},
|
|
413
|
+
"/shapes": {
|
|
414
|
+
"post": {
|
|
415
|
+
"tags": ["oas31"],
|
|
416
|
+
"operationId": "createShape",
|
|
417
|
+
"summary": "Create a shape",
|
|
418
|
+
"description": "Tests **title in oneOf variants** and **required-first sort inside renderCompositeOption**. Each variant has a `title` (`Circle`, `Rectangle`) and a mix of required / optional properties — required ones should appear first in the expanded view.",
|
|
419
|
+
"requestBody": {
|
|
420
|
+
"required": true,
|
|
421
|
+
"content": {
|
|
422
|
+
"application/json": {
|
|
423
|
+
"schema": { "$ref": "#/components/schemas/Shape" }
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
"responses": {
|
|
428
|
+
"201": { "description": "Shape created" }
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
"/payloads": {
|
|
433
|
+
"post": {
|
|
434
|
+
"tags": ["oas31"],
|
|
435
|
+
"operationId": "sendPayload",
|
|
436
|
+
"summary": "Send a flexible payload",
|
|
437
|
+
"description": "Tests **canExpand on a variant with no direct properties**. The `Freeform` variant has only `additionalProperties: {type: string}` and no `properties` object — it must still be expandable and show the `[key: string]` row.",
|
|
438
|
+
"requestBody": {
|
|
439
|
+
"required": true,
|
|
440
|
+
"content": {
|
|
441
|
+
"application/json": {
|
|
442
|
+
"schema": { "$ref": "#/components/schemas/FlexPayload" }
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
"responses": {
|
|
447
|
+
"200": { "description": "Payload accepted" }
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
"/media": {
|
|
452
|
+
"post": {
|
|
453
|
+
"tags": ["media"],
|
|
454
|
+
"operationId": "createMedia",
|
|
455
|
+
"summary": "Add a media item",
|
|
456
|
+
"description": "Creates a media item. The `mediaType` field acts as a discriminator to determine which schema variant to use.",
|
|
457
|
+
"requestBody": {
|
|
458
|
+
"required": true,
|
|
459
|
+
"content": {
|
|
460
|
+
"application/json": {
|
|
461
|
+
"schema": { "$ref": "#/components/schemas/Media" }
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
},
|
|
465
|
+
"responses": {
|
|
466
|
+
"201": { "description": "Media item created" }
|
|
467
|
+
}
|
|
468
|
+
},
|
|
469
|
+
"get": {
|
|
470
|
+
"tags": ["media"],
|
|
471
|
+
"operationId": "listMedia",
|
|
472
|
+
"summary": "List media items",
|
|
473
|
+
"responses": {
|
|
474
|
+
"200": {
|
|
475
|
+
"description": "A list of media items",
|
|
476
|
+
"content": {
|
|
477
|
+
"application/json": {
|
|
478
|
+
"schema": {
|
|
479
|
+
"type": "array",
|
|
480
|
+
"items": { "$ref": "#/components/schemas/Media" }
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
},
|
|
489
|
+
"webhooks": {
|
|
490
|
+
"newBook": {
|
|
491
|
+
"post": {
|
|
492
|
+
"operationId": "webhookNewBook",
|
|
493
|
+
"summary": "New book created",
|
|
494
|
+
"description": "Fired whenever a new book is added to the library. Your endpoint should respond with a 2xx status to acknowledge receipt.",
|
|
495
|
+
"requestBody": {
|
|
496
|
+
"required": true,
|
|
497
|
+
"content": {
|
|
498
|
+
"application/json": {
|
|
499
|
+
"schema": { "$ref": "#/components/schemas/Book" }
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
},
|
|
503
|
+
"responses": {
|
|
504
|
+
"200": { "description": "Webhook acknowledged" }
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
},
|
|
508
|
+
"bookDeleted": {
|
|
509
|
+
"post": {
|
|
510
|
+
"operationId": "webhookBookDeleted",
|
|
511
|
+
"summary": "Book deleted",
|
|
512
|
+
"description": "Fired when a book is permanently removed from the system.",
|
|
513
|
+
"requestBody": {
|
|
514
|
+
"required": true,
|
|
515
|
+
"content": {
|
|
516
|
+
"application/json": {
|
|
517
|
+
"schema": {
|
|
518
|
+
"type": "object",
|
|
519
|
+
"properties": {
|
|
520
|
+
"id": { "type": "integer" },
|
|
521
|
+
"deletedAt": { "type": "string", "format": "date-time" }
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
},
|
|
527
|
+
"responses": {
|
|
528
|
+
"200": { "description": "Acknowledged" }
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
"components": {
|
|
534
|
+
"securitySchemes": {
|
|
535
|
+
"bearerAuth": {
|
|
536
|
+
"type": "http",
|
|
537
|
+
"scheme": "bearer",
|
|
538
|
+
"bearerFormat": "JWT"
|
|
539
|
+
}
|
|
540
|
+
},
|
|
541
|
+
"schemas": {
|
|
542
|
+
"Book": {
|
|
543
|
+
"type": "object",
|
|
544
|
+
"title": "Book",
|
|
545
|
+
"description": "Represents a book in the library system",
|
|
546
|
+
"required": ["id", "title", "author"],
|
|
547
|
+
"properties": {
|
|
548
|
+
"id": { "type": "integer", "description": "Unique identifier" },
|
|
549
|
+
"title": { "type": "string", "description": "Book title" },
|
|
550
|
+
"author": { "type": "string", "description": "Author name" },
|
|
551
|
+
"genre": {
|
|
552
|
+
"type": "string",
|
|
553
|
+
"title": "BookGenre",
|
|
554
|
+
"enum": ["fiction", "nonfiction", "history", "science"],
|
|
555
|
+
"description": "Book genre"
|
|
556
|
+
},
|
|
557
|
+
"year": { "type": "integer", "description": "Publication year" },
|
|
558
|
+
"available": { "type": "boolean", "description": "Whether the book is available for borrowing" }
|
|
559
|
+
}
|
|
560
|
+
},
|
|
561
|
+
"BookInput": {
|
|
562
|
+
"type": "object",
|
|
563
|
+
"description": "Payload for creating or updating a book",
|
|
564
|
+
"required": ["title", "author"],
|
|
565
|
+
"properties": {
|
|
566
|
+
"title": { "type": "string" },
|
|
567
|
+
"author": { "type": "string" },
|
|
568
|
+
"genre": { "type": "string", "enum": ["fiction", "nonfiction", "history", "science"] },
|
|
569
|
+
"year": { "type": "integer" }
|
|
570
|
+
}
|
|
571
|
+
},
|
|
572
|
+
"BookList": {
|
|
573
|
+
"type": "object",
|
|
574
|
+
"properties": {
|
|
575
|
+
"data": {
|
|
576
|
+
"type": "array",
|
|
577
|
+
"items": { "$ref": "#/components/schemas/Book" }
|
|
578
|
+
},
|
|
579
|
+
"total": { "type": "integer" },
|
|
580
|
+
"page": { "type": "integer" },
|
|
581
|
+
"limit": { "type": "integer" }
|
|
582
|
+
}
|
|
583
|
+
},
|
|
584
|
+
"Author": {
|
|
585
|
+
"type": "object",
|
|
586
|
+
"description": "An author in the library system",
|
|
587
|
+
"required": ["id", "name"],
|
|
588
|
+
"properties": {
|
|
589
|
+
"id": { "type": "integer" },
|
|
590
|
+
"name": { "type": "string" },
|
|
591
|
+
"bio": { "type": "string" },
|
|
592
|
+
"birthYear": { "type": "integer" },
|
|
593
|
+
"nationality": { "type": "string" }
|
|
594
|
+
}
|
|
595
|
+
},
|
|
596
|
+
"AuthorList": {
|
|
597
|
+
"type": "object",
|
|
598
|
+
"properties": {
|
|
599
|
+
"data": {
|
|
600
|
+
"type": "array",
|
|
601
|
+
"items": { "$ref": "#/components/schemas/Author" }
|
|
602
|
+
},
|
|
603
|
+
"total": { "type": "integer" }
|
|
604
|
+
}
|
|
605
|
+
},
|
|
606
|
+
"Media": {
|
|
607
|
+
"description": "A polymorphic media item. Use `mediaType` to select the correct variant.",
|
|
608
|
+
"oneOf": [
|
|
609
|
+
{ "$ref": "#/components/schemas/AudioBook" },
|
|
610
|
+
{ "$ref": "#/components/schemas/EBook" },
|
|
611
|
+
{ "$ref": "#/components/schemas/PrintBook" }
|
|
612
|
+
],
|
|
613
|
+
"discriminator": {
|
|
614
|
+
"propertyName": "mediaType",
|
|
615
|
+
"mapping": {
|
|
616
|
+
"audio": "#/components/schemas/AudioBook",
|
|
617
|
+
"ebook": "#/components/schemas/EBook",
|
|
618
|
+
"print": "#/components/schemas/PrintBook"
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
},
|
|
622
|
+
"AudioBook": {
|
|
623
|
+
"type": "object",
|
|
624
|
+
"description": "An audio book with a narrator and duration",
|
|
625
|
+
"required": ["mediaType", "title", "narrator", "durationMinutes"],
|
|
626
|
+
"properties": {
|
|
627
|
+
"mediaType": { "type": "string", "enum": ["audio"] },
|
|
628
|
+
"title": { "type": "string" },
|
|
629
|
+
"narrator": { "type": "string", "description": "Name of the narrator" },
|
|
630
|
+
"durationMinutes": { "type": "integer", "description": "Total duration in minutes" }
|
|
631
|
+
}
|
|
632
|
+
},
|
|
633
|
+
"EBook": {
|
|
634
|
+
"type": "object",
|
|
635
|
+
"description": "A digital e-book",
|
|
636
|
+
"required": ["mediaType", "title", "format"],
|
|
637
|
+
"properties": {
|
|
638
|
+
"mediaType": { "type": "string", "enum": ["ebook"] },
|
|
639
|
+
"title": { "type": "string" },
|
|
640
|
+
"format": { "type": "string", "enum": ["epub", "pdf", "mobi"], "description": "File format" },
|
|
641
|
+
"fileSizeKb": { "type": "integer", "description": "File size in kilobytes" }
|
|
642
|
+
}
|
|
643
|
+
},
|
|
644
|
+
"NonEmptyString": {
|
|
645
|
+
"type": "string",
|
|
646
|
+
"description": "A string that must not be empty or null",
|
|
647
|
+
"not": { "type": "string", "maxLength": 0 }
|
|
648
|
+
},
|
|
649
|
+
"StrictId": {
|
|
650
|
+
"type": "object",
|
|
651
|
+
"title": "StrictIdentifier",
|
|
652
|
+
"description": "An identifier that must not be a negative number",
|
|
653
|
+
"properties": {
|
|
654
|
+
"id": {
|
|
655
|
+
"type": "integer",
|
|
656
|
+
"not": { "minimum": -1, "maximum": -1 }
|
|
657
|
+
},
|
|
658
|
+
"label": { "$ref": "#/components/schemas/NonEmptyString" }
|
|
659
|
+
}
|
|
660
|
+
},
|
|
661
|
+
"GeoPoint": {
|
|
662
|
+
"type": "array",
|
|
663
|
+
"title": "GeoPoint",
|
|
664
|
+
"description": "A GPS coordinate tuple `[latitude, longitude, elevation]`. Uses **prefixItems** — each position has its own type and description. `items: false` forbids extra positions beyond the three defined.",
|
|
665
|
+
"prefixItems": [
|
|
666
|
+
{ "type": "number", "description": "Latitude in decimal degrees", "minimum": -90, "maximum": 90 },
|
|
667
|
+
{ "type": "number", "description": "Longitude in decimal degrees", "minimum": -180, "maximum": 180 },
|
|
668
|
+
{ "type": "number", "description": "Elevation in metres above sea level" }
|
|
669
|
+
],
|
|
670
|
+
"items": false,
|
|
671
|
+
"minItems": 3,
|
|
672
|
+
"maxItems": 3
|
|
673
|
+
},
|
|
674
|
+
"EventPayload": {
|
|
675
|
+
"type": "object",
|
|
676
|
+
"title": "EventPayload",
|
|
677
|
+
"description": "An event. Uses **if/then/else** — `url` is required for online events, `location` is required for in-person events.",
|
|
678
|
+
"required": ["type", "name"],
|
|
679
|
+
"properties": {
|
|
680
|
+
"type": { "type": "string", "enum": ["online", "in-person"], "description": "Event delivery mode" },
|
|
681
|
+
"name": { "type": "string", "description": "Event name" },
|
|
682
|
+
"url": { "type": "string", "format": "uri", "description": "Stream URL (online events only)" },
|
|
683
|
+
"location": { "type": "string", "description": "Physical location (in-person events only)" }
|
|
684
|
+
},
|
|
685
|
+
"if": {
|
|
686
|
+
"properties": { "type": { "const": "online" } }
|
|
687
|
+
},
|
|
688
|
+
"then": {
|
|
689
|
+
"required": ["url"],
|
|
690
|
+
"properties": { "url": { "type": "string", "format": "uri" } }
|
|
691
|
+
},
|
|
692
|
+
"else": {
|
|
693
|
+
"required": ["location"],
|
|
694
|
+
"properties": { "location": { "type": "string" } }
|
|
695
|
+
}
|
|
696
|
+
},
|
|
697
|
+
"StrictConfig": {
|
|
698
|
+
"type": "object",
|
|
699
|
+
"title": "StrictConfig",
|
|
700
|
+
"description": "User configuration object. **additionalProperties: false** — no fields beyond `theme` and `language` are accepted.",
|
|
701
|
+
"additionalProperties": false,
|
|
702
|
+
"required": ["theme"],
|
|
703
|
+
"properties": {
|
|
704
|
+
"theme": { "type": "string", "enum": ["light", "dark", "system"], "description": "UI colour scheme" },
|
|
705
|
+
"language": { "type": "string", "description": "BCP-47 language tag, e.g. `en-US`" }
|
|
706
|
+
}
|
|
707
|
+
},
|
|
708
|
+
"MetricBag": {
|
|
709
|
+
"type": "object",
|
|
710
|
+
"title": "MetricBag",
|
|
711
|
+
"description": "A named bag of metrics. Tests **patternProperties** + **additionalProperties as object**. Keys starting with `metric_` must be numbers; all other extra keys must be strings. The collapsed childCount badge should reflect all three entry types.",
|
|
712
|
+
"properties": {
|
|
713
|
+
"timestamp": { "type": "string", "format": "date-time", "description": "Collection timestamp" }
|
|
714
|
+
},
|
|
715
|
+
"patternProperties": {
|
|
716
|
+
"^metric_": { "type": "number", "description": "A numeric metric value" }
|
|
717
|
+
},
|
|
718
|
+
"additionalProperties": { "type": "string", "description": "Arbitrary string metadata" }
|
|
719
|
+
},
|
|
720
|
+
"Shape": {
|
|
721
|
+
"description": "A 2-D shape. Tests **title on oneOf variants** and **required-first sort** — required fields (`radius` / `width`+`height`) should appear before optional ones (`color`, `opacity`) in the expanded view.",
|
|
722
|
+
"oneOf": [
|
|
723
|
+
{
|
|
724
|
+
"title": "Circle",
|
|
725
|
+
"type": "object",
|
|
726
|
+
"required": ["radius"],
|
|
727
|
+
"properties": {
|
|
728
|
+
"color": { "type": "string", "description": "Fill colour" },
|
|
729
|
+
"opacity": { "type": "number", "minimum": 0, "maximum": 1, "description": "Opacity 0–1" },
|
|
730
|
+
"radius": { "type": "number", "description": "Radius in pixels" }
|
|
731
|
+
}
|
|
732
|
+
},
|
|
733
|
+
{
|
|
734
|
+
"title": "Rectangle",
|
|
735
|
+
"type": "object",
|
|
736
|
+
"required": ["width", "height"],
|
|
737
|
+
"properties": {
|
|
738
|
+
"color": { "type": "string", "description": "Fill colour" },
|
|
739
|
+
"width": { "type": "number", "description": "Width in pixels" },
|
|
740
|
+
"height": { "type": "number", "description": "Height in pixels" }
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
]
|
|
744
|
+
},
|
|
745
|
+
"FlexPayload": {
|
|
746
|
+
"description": "Tests **canExpand on a variant without direct properties**. `Freeform` has only `additionalProperties` (no `properties` key) — it must still be expandable and display a `[key: string]: string` row.",
|
|
747
|
+
"oneOf": [
|
|
748
|
+
{
|
|
749
|
+
"title": "Fixed",
|
|
750
|
+
"type": "object",
|
|
751
|
+
"description": "A payload with well-known keys",
|
|
752
|
+
"required": ["key", "value"],
|
|
753
|
+
"properties": {
|
|
754
|
+
"key": { "type": "string" },
|
|
755
|
+
"value": { "type": "string" }
|
|
756
|
+
}
|
|
757
|
+
},
|
|
758
|
+
{
|
|
759
|
+
"title": "Freeform",
|
|
760
|
+
"type": "object",
|
|
761
|
+
"description": "Any string key-value pairs — no fixed properties",
|
|
762
|
+
"additionalProperties": { "type": "string" }
|
|
763
|
+
}
|
|
764
|
+
]
|
|
765
|
+
},
|
|
766
|
+
"PrintBook": {
|
|
767
|
+
"type": "object",
|
|
768
|
+
"description": "A physical print book",
|
|
769
|
+
"required": ["mediaType", "title", "isbn"],
|
|
770
|
+
"properties": {
|
|
771
|
+
"mediaType": { "type": "string", "enum": ["print"] },
|
|
772
|
+
"title": { "type": "string" },
|
|
773
|
+
"isbn": { "type": "string", "description": "ISBN-13 identifier" },
|
|
774
|
+
"pageCount": { "type": "integer" }
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
}
|