@zmdb/web 1.0.0-beta.1

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 (179) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +49 -0
  3. package/dist/app/bridge.d.ts +12 -0
  4. package/dist/app/bridge.d.ts.map +1 -0
  5. package/dist/app/bridge.js +16 -0
  6. package/dist/app/bridge.js.map +1 -0
  7. package/dist/app/index.d.ts +23 -0
  8. package/dist/app/index.d.ts.map +1 -0
  9. package/dist/app/index.js +47 -0
  10. package/dist/app/index.js.map +1 -0
  11. package/dist/bench/index.d.ts +68 -0
  12. package/dist/bench/index.d.ts.map +1 -0
  13. package/dist/bench/index.js +250 -0
  14. package/dist/bench/index.js.map +1 -0
  15. package/dist/compression/index.d.ts +13 -0
  16. package/dist/compression/index.d.ts.map +1 -0
  17. package/dist/compression/index.js +211 -0
  18. package/dist/compression/index.js.map +1 -0
  19. package/dist/context/index.d.ts +74 -0
  20. package/dist/context/index.d.ts.map +1 -0
  21. package/dist/context/index.js +118 -0
  22. package/dist/context/index.js.map +1 -0
  23. package/dist/contract/__fixtures__/http-client.generated.d.ts +70 -0
  24. package/dist/contract/__fixtures__/http-client.generated.d.ts.map +1 -0
  25. package/dist/contract/__fixtures__/http-client.generated.js +86 -0
  26. package/dist/contract/__fixtures__/http-client.generated.js.map +1 -0
  27. package/dist/contract/__fixtures__/http-convergence.d.ts +396 -0
  28. package/dist/contract/__fixtures__/http-convergence.d.ts.map +1 -0
  29. package/dist/contract/__fixtures__/http-convergence.js +425 -0
  30. package/dist/contract/__fixtures__/http-convergence.js.map +1 -0
  31. package/dist/contract/compiler/client.d.ts +12 -0
  32. package/dist/contract/compiler/client.d.ts.map +1 -0
  33. package/dist/contract/compiler/client.js +1293 -0
  34. package/dist/contract/compiler/client.js.map +1 -0
  35. package/dist/contract/compiler/index.d.ts +18 -0
  36. package/dist/contract/compiler/index.d.ts.map +1 -0
  37. package/dist/contract/compiler/index.js +1058 -0
  38. package/dist/contract/compiler/index.js.map +1 -0
  39. package/dist/contract/index.d.ts +237 -0
  40. package/dist/contract/index.d.ts.map +1 -0
  41. package/dist/contract/index.js +22 -0
  42. package/dist/contract/index.js.map +1 -0
  43. package/dist/csrf/index.d.ts +15 -0
  44. package/dist/csrf/index.d.ts.map +1 -0
  45. package/dist/csrf/index.js +218 -0
  46. package/dist/csrf/index.js.map +1 -0
  47. package/dist/data/index.d.ts +35 -0
  48. package/dist/data/index.d.ts.map +1 -0
  49. package/dist/data/index.js +58 -0
  50. package/dist/data/index.js.map +1 -0
  51. package/dist/devtools/index.d.ts +74 -0
  52. package/dist/devtools/index.d.ts.map +1 -0
  53. package/dist/devtools/index.js +552 -0
  54. package/dist/devtools/index.js.map +1 -0
  55. package/dist/dto-pipes/index.d.ts +45 -0
  56. package/dist/dto-pipes/index.d.ts.map +1 -0
  57. package/dist/dto-pipes/index.js +78 -0
  58. package/dist/dto-pipes/index.js.map +1 -0
  59. package/dist/gateways/index.d.ts +31 -0
  60. package/dist/gateways/index.d.ts.map +1 -0
  61. package/dist/gateways/index.js +138 -0
  62. package/dist/gateways/index.js.map +1 -0
  63. package/dist/health/index.d.ts +20 -0
  64. package/dist/health/index.d.ts.map +1 -0
  65. package/dist/health/index.js +148 -0
  66. package/dist/health/index.js.map +1 -0
  67. package/dist/http-token.d.ts +2 -0
  68. package/dist/http-token.d.ts.map +1 -0
  69. package/dist/http-token.js +21 -0
  70. package/dist/http-token.js.map +1 -0
  71. package/dist/index.d.ts +18 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +40 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/integrations/index.d.ts +11 -0
  76. package/dist/integrations/index.d.ts.map +1 -0
  77. package/dist/integrations/index.js +39 -0
  78. package/dist/integrations/index.js.map +1 -0
  79. package/dist/middleware/errors.d.ts +14 -0
  80. package/dist/middleware/errors.d.ts.map +1 -0
  81. package/dist/middleware/errors.js +18 -0
  82. package/dist/middleware/errors.js.map +1 -0
  83. package/dist/middleware/index.d.ts +46 -0
  84. package/dist/middleware/index.d.ts.map +1 -0
  85. package/dist/middleware/index.js +64 -0
  86. package/dist/middleware/index.js.map +1 -0
  87. package/dist/modules/__fixtures__/large-graph.d.ts +239 -0
  88. package/dist/modules/__fixtures__/large-graph.d.ts.map +1 -0
  89. package/dist/modules/__fixtures__/large-graph.js +483 -0
  90. package/dist/modules/__fixtures__/large-graph.js.map +1 -0
  91. package/dist/openapi/__fixtures__/entities.d.ts +8 -0
  92. package/dist/openapi/__fixtures__/entities.d.ts.map +1 -0
  93. package/dist/openapi/__fixtures__/entities.js +4 -0
  94. package/dist/openapi/__fixtures__/entities.js.map +1 -0
  95. package/dist/openapi/__fixtures__/openapi-tools.fixture.d.ts +38 -0
  96. package/dist/openapi/__fixtures__/openapi-tools.fixture.d.ts.map +1 -0
  97. package/dist/openapi/__fixtures__/openapi-tools.fixture.js +172 -0
  98. package/dist/openapi/__fixtures__/openapi-tools.fixture.js.map +1 -0
  99. package/dist/openapi/__fixtures__/route-schemas.d.ts +2 -0
  100. package/dist/openapi/__fixtures__/route-schemas.d.ts.map +1 -0
  101. package/dist/openapi/__fixtures__/route-schemas.js +17 -0
  102. package/dist/openapi/__fixtures__/route-schemas.js.map +1 -0
  103. package/dist/openapi/index.d.ts +61 -0
  104. package/dist/openapi/index.d.ts.map +1 -0
  105. package/dist/openapi/index.js +314 -0
  106. package/dist/openapi/index.js.map +1 -0
  107. package/dist/pipeline/guards.d.ts +9 -0
  108. package/dist/pipeline/guards.d.ts.map +1 -0
  109. package/dist/pipeline/guards.js +11 -0
  110. package/dist/pipeline/guards.js.map +1 -0
  111. package/dist/pipeline/index.d.ts +141 -0
  112. package/dist/pipeline/index.d.ts.map +1 -0
  113. package/dist/pipeline/index.js +1624 -0
  114. package/dist/pipeline/index.js.map +1 -0
  115. package/dist/routing/index.d.ts +40 -0
  116. package/dist/routing/index.d.ts.map +1 -0
  117. package/dist/routing/index.js +162 -0
  118. package/dist/routing/index.js.map +1 -0
  119. package/dist/static/index.d.ts +14 -0
  120. package/dist/static/index.d.ts.map +1 -0
  121. package/dist/static/index.js +348 -0
  122. package/dist/static/index.js.map +1 -0
  123. package/dist/testing/index.d.ts +20 -0
  124. package/dist/testing/index.d.ts.map +1 -0
  125. package/dist/testing/index.js +32 -0
  126. package/dist/testing/index.js.map +1 -0
  127. package/dist/traced-router.d.ts +5 -0
  128. package/dist/traced-router.d.ts.map +1 -0
  129. package/dist/traced-router.js +6 -0
  130. package/dist/traced-router.js.map +1 -0
  131. package/dist/upload/index.d.ts +28 -0
  132. package/dist/upload/index.d.ts.map +1 -0
  133. package/dist/upload/index.js +410 -0
  134. package/dist/upload/index.js.map +1 -0
  135. package/dist/versioning/index.d.ts +35 -0
  136. package/dist/versioning/index.d.ts.map +1 -0
  137. package/dist/versioning/index.js +66 -0
  138. package/dist/versioning/index.js.map +1 -0
  139. package/dist/versioning/runtime.d.ts +5 -0
  140. package/dist/versioning/runtime.d.ts.map +1 -0
  141. package/dist/versioning/runtime.js +34 -0
  142. package/dist/versioning/runtime.js.map +1 -0
  143. package/package.json +143 -0
  144. package/src/app/bridge.ts +39 -0
  145. package/src/app/index.ts +76 -0
  146. package/src/bench/index.ts +329 -0
  147. package/src/compression/index.ts +255 -0
  148. package/src/context/index.ts +181 -0
  149. package/src/contract/__fixtures__/http-client.generated.ts +73 -0
  150. package/src/contract/__fixtures__/http-client.generated.ts.map +1 -0
  151. package/src/contract/__fixtures__/http-convergence.ts +564 -0
  152. package/src/contract/compiler/client.ts +1518 -0
  153. package/src/contract/compiler/index.ts +1457 -0
  154. package/src/contract/index.ts +266 -0
  155. package/src/csrf/index.ts +264 -0
  156. package/src/data/index.ts +65 -0
  157. package/src/devtools/index.ts +727 -0
  158. package/src/dto-pipes/index.ts +93 -0
  159. package/src/gateways/index.ts +180 -0
  160. package/src/health/index.ts +198 -0
  161. package/src/http-token.ts +22 -0
  162. package/src/index.ts +167 -0
  163. package/src/integrations/index.ts +50 -0
  164. package/src/middleware/errors.ts +17 -0
  165. package/src/middleware/index.ts +108 -0
  166. package/src/modules/__fixtures__/large-graph.ts +540 -0
  167. package/src/openapi/__fixtures__/entities.ts +19 -0
  168. package/src/openapi/__fixtures__/openapi-tools.fixture.ts +212 -0
  169. package/src/openapi/__fixtures__/route-schemas.ts +27 -0
  170. package/src/openapi/index.ts +483 -0
  171. package/src/pipeline/guards.ts +23 -0
  172. package/src/pipeline/index.ts +2041 -0
  173. package/src/routing/index.ts +201 -0
  174. package/src/static/index.ts +443 -0
  175. package/src/testing/index.ts +58 -0
  176. package/src/traced-router.ts +8 -0
  177. package/src/upload/index.ts +489 -0
  178. package/src/versioning/index.ts +106 -0
  179. package/src/versioning/runtime.ts +38 -0
@@ -0,0 +1,564 @@
1
+ import { type TypeIR } from '@zmdb/schema/ir';
2
+
3
+ import { Controller, Get, Patch, Post, Public } from '../../routing/index.js';
4
+ import { Version } from '../../versioning/index.js';
5
+ import { defineHttpContract, httpOperation } from '../index.js';
6
+
7
+ interface UpdateMetadata {
8
+ readonly source: string;
9
+ }
10
+
11
+ interface UpdateAccountBody {
12
+ readonly displayName: string;
13
+ readonly metadata: UpdateMetadata | null;
14
+ }
15
+
16
+ interface Account {
17
+ readonly id: string;
18
+ readonly displayName: string;
19
+ }
20
+
21
+ interface AcceptedUpdate {
22
+ readonly jobId: string;
23
+ }
24
+
25
+ interface Problem {
26
+ readonly code: string;
27
+ readonly message: string;
28
+ }
29
+
30
+ interface UpdateAccountOperation {
31
+ readonly path: { readonly accountId: string };
32
+ readonly query: { readonly include?: readonly string[]; readonly dryRun?: boolean };
33
+ readonly headers: { readonly requestId?: string };
34
+ readonly cookies: { readonly session: string };
35
+ readonly body: UpdateAccountBody;
36
+ readonly responses: {
37
+ readonly 200: { readonly body: Account; readonly headers: { readonly etag: string } };
38
+ readonly 202: { readonly body: AcceptedUpdate };
39
+ readonly 204: { readonly body: void };
40
+ readonly 404: { readonly body: Problem };
41
+ };
42
+ }
43
+
44
+ @Version('1', '2')
45
+ @Controller('/accounts')
46
+ export class AccountsController {
47
+ @Patch('/:accountId')
48
+ update() {
49
+ return { updated: true };
50
+ }
51
+ }
52
+
53
+ export const HTTP_CONTRACT = defineHttpContract({
54
+ securitySchemes: {
55
+ bearerAuth: { type: 'http', scheme: 'bearer' },
56
+ apiKeyAuth: { type: 'apiKey', in: 'header', name: 'x-api-key' },
57
+ },
58
+ operations: {
59
+ patch_accounts_accountId: httpOperation<UpdateAccountOperation>({
60
+ controller: AccountsController,
61
+ handler: 'update',
62
+ method: 'PATCH',
63
+ path: '/accounts/:accountId',
64
+ parameters: [
65
+ { in: 'path', property: 'accountId', name: 'accountId' },
66
+ { in: 'query', property: 'include', name: 'include' },
67
+ { in: 'query', property: 'dryRun', name: 'dry-run' },
68
+ { in: 'header', property: 'requestId', name: 'x-request-id' },
69
+ { in: 'cookie', property: 'session', name: 'session' },
70
+ ],
71
+ requestBody: { kind: 'json', mediaType: 'application/json', required: true },
72
+ responses: {
73
+ 200: {
74
+ description: 'Updated',
75
+ headers: [{ property: 'etag', name: 'etag' }],
76
+ body: { kind: 'json', mediaType: 'application/json' },
77
+ },
78
+ 202: {
79
+ description: 'Accepted',
80
+ body: { kind: 'json', mediaType: 'application/json' },
81
+ },
82
+ 204: {
83
+ description: 'No change',
84
+ body: { kind: 'empty' },
85
+ },
86
+ 404: {
87
+ description: 'Account not found',
88
+ body: { kind: 'json', mediaType: 'application/problem+json' },
89
+ },
90
+ },
91
+ security: [{ bearerAuth: [] }, { apiKeyAuth: [] }],
92
+ version: {
93
+ kind: 'header',
94
+ name: 'accept-version',
95
+ values: ['1', '2'],
96
+ default: '1',
97
+ },
98
+ deprecated: true,
99
+ }),
100
+ },
101
+ });
102
+
103
+ interface ReadSharedOperation {
104
+ readonly path: { readonly id: string };
105
+ readonly responses: { readonly 200: { readonly body: Account } };
106
+ }
107
+
108
+ interface WriteSharedOperation {
109
+ readonly path: { readonly id: string };
110
+ readonly responses: { readonly 202: { readonly body: AcceptedUpdate } };
111
+ }
112
+
113
+ @Controller('/shared')
114
+ export class SharedPathController {
115
+ @Public()
116
+ @Get('/:id')
117
+ read() {
118
+ return { id: 'shared', displayName: 'Shared' };
119
+ }
120
+
121
+ @Public()
122
+ @Post('/:id')
123
+ write() {
124
+ return { jobId: 'job-shared' };
125
+ }
126
+ }
127
+
128
+ export const SHARED_PATH_CONTRACT = defineHttpContract({
129
+ securitySchemes: {},
130
+ operations: {
131
+ post_shared_id: httpOperation<WriteSharedOperation>({
132
+ controller: SharedPathController,
133
+ handler: 'write',
134
+ method: 'POST',
135
+ path: '/shared/:id',
136
+ parameters: [{ in: 'path', property: 'id', name: 'id' }],
137
+ responses: {
138
+ 202: {
139
+ description: 'Accepted',
140
+ body: { kind: 'json', mediaType: 'application/json' },
141
+ },
142
+ },
143
+ security: [],
144
+ version: { kind: 'none' },
145
+ deprecated: false,
146
+ }),
147
+ get_shared_id: httpOperation<ReadSharedOperation>({
148
+ controller: SharedPathController,
149
+ handler: 'read',
150
+ method: 'GET',
151
+ path: '/shared/:id',
152
+ parameters: [{ in: 'path', property: 'id', name: 'id' }],
153
+ responses: {
154
+ 200: {
155
+ description: 'OK',
156
+ body: { kind: 'json', mediaType: 'application/json' },
157
+ },
158
+ },
159
+ security: [],
160
+ version: { kind: 'none' },
161
+ deprecated: false,
162
+ }),
163
+ },
164
+ });
165
+
166
+ interface CollisionOperation {
167
+ readonly path: { readonly id: string };
168
+ readonly responses: { readonly 200: { readonly body: Account } };
169
+ }
170
+
171
+ @Controller('/collision')
172
+ export class CollisionController {
173
+ @Public()
174
+ @Get('/:id')
175
+ first() {
176
+ return { id: 'first', displayName: 'First' };
177
+ }
178
+
179
+ @Public()
180
+ @Get('/:id')
181
+ second() {
182
+ return { id: 'second', displayName: 'Second' };
183
+ }
184
+ }
185
+
186
+ export const COLLIDING_ROUTE_CONTRACT = defineHttpContract({
187
+ securitySchemes: {},
188
+ operations: {
189
+ z_collision_first: httpOperation<CollisionOperation>({
190
+ controller: CollisionController,
191
+ handler: 'first',
192
+ method: 'GET',
193
+ path: '/collision/:id',
194
+ parameters: [{ in: 'path', property: 'id', name: 'id' }],
195
+ responses: {
196
+ 200: { description: 'First', body: { kind: 'json', mediaType: 'application/json' } },
197
+ },
198
+ security: [],
199
+ version: { kind: 'none' },
200
+ deprecated: false,
201
+ }),
202
+ a_collision_second: httpOperation<CollisionOperation>({
203
+ controller: CollisionController,
204
+ handler: 'second',
205
+ method: 'GET',
206
+ path: '/collision/:id',
207
+ parameters: [{ in: 'path', property: 'id', name: 'id' }],
208
+ responses: {
209
+ 200: { description: 'Second', body: { kind: 'json', mediaType: 'application/json' } },
210
+ },
211
+ security: [],
212
+ version: { kind: 'none' },
213
+ deprecated: false,
214
+ }),
215
+ },
216
+ });
217
+
218
+ const DYNAMIC_ROUTE_PATH = '/dynamic/:id';
219
+
220
+ @Controller('/dynamic')
221
+ export class DynamicController {
222
+ @Public()
223
+ @Get('/:id')
224
+ read() {
225
+ return { id: 'dynamic', displayName: 'Dynamic' };
226
+ }
227
+ }
228
+
229
+ export const DYNAMIC_METADATA_CONTRACT = defineHttpContract({
230
+ securitySchemes: {},
231
+ operations: {
232
+ get_dynamic_id: httpOperation<CollisionOperation>({
233
+ controller: DynamicController,
234
+ handler: 'read',
235
+ method: 'GET',
236
+ path: DYNAMIC_ROUTE_PATH,
237
+ parameters: [{ in: 'path', property: 'id', name: 'id' }],
238
+ responses: {
239
+ 200: { description: 'Dynamic', body: { kind: 'json', mediaType: 'application/json' } },
240
+ },
241
+ security: [],
242
+ version: { kind: 'none' },
243
+ deprecated: false,
244
+ }),
245
+ },
246
+ });
247
+
248
+ type JsonValue = null | boolean | number | string | readonly JsonValue[] | { readonly [key: string]: JsonValue };
249
+
250
+ interface HttpTypeFixture {
251
+ readonly type: TypeIR;
252
+ readonly openApi: Readonly<Record<string, JsonValue>>;
253
+ }
254
+
255
+ interface HttpParameterFixture {
256
+ readonly property: string;
257
+ readonly name: string;
258
+ readonly in: 'path' | 'query' | 'header' | 'cookie';
259
+ readonly required: boolean;
260
+ readonly typeId: string;
261
+ }
262
+
263
+ type HttpBodyFixture =
264
+ | { readonly kind: 'json'; readonly mediaType: string; readonly typeId: string }
265
+ | { readonly kind: 'text' | 'bytes' | 'stream'; readonly mediaType: string }
266
+ | { readonly kind: 'empty' };
267
+
268
+ interface HttpResponseFixture {
269
+ readonly status: number;
270
+ readonly description: string;
271
+ readonly headers: readonly {
272
+ readonly property: string;
273
+ readonly name: string;
274
+ readonly required: boolean;
275
+ readonly typeId: string;
276
+ }[];
277
+ readonly body: HttpBodyFixture;
278
+ }
279
+
280
+ interface HttpContractFixture {
281
+ readonly format: 1;
282
+ readonly types: Readonly<Record<string, HttpTypeFixture>>;
283
+ readonly operations: readonly [
284
+ {
285
+ readonly operationId: 'patch_accounts_accountId';
286
+ readonly controller: 'AccountsController';
287
+ readonly handler: 'update';
288
+ readonly method: 'PATCH';
289
+ readonly path: '/accounts/:accountId';
290
+ readonly parameters: readonly HttpParameterFixture[];
291
+ readonly requestBody: {
292
+ readonly kind: 'json';
293
+ readonly mediaType: 'application/json';
294
+ readonly typeId: 'patch_accounts_accountId/request/body';
295
+ readonly required: true;
296
+ };
297
+ readonly responses: readonly HttpResponseFixture[];
298
+ readonly security: readonly [
299
+ Readonly<Record<'bearerAuth', readonly string[]>>,
300
+ Readonly<Record<'apiKeyAuth', readonly string[]>>,
301
+ ];
302
+ readonly version: {
303
+ readonly kind: 'header';
304
+ readonly name: 'accept-version';
305
+ readonly values: readonly ['1', '2'];
306
+ readonly default: '1';
307
+ };
308
+ readonly deprecated: true;
309
+ },
310
+ ];
311
+ readonly securitySchemes: {
312
+ readonly bearerAuth: { readonly type: 'http'; readonly scheme: 'bearer' };
313
+ readonly apiKeyAuth: { readonly type: 'apiKey'; readonly in: 'header'; readonly name: 'x-api-key' };
314
+ };
315
+ }
316
+
317
+ const STRING: TypeIR = { kind: 'scalar', scalar: 'string' };
318
+ const BOOLEAN: TypeIR = { kind: 'scalar', scalar: 'boolean' };
319
+ const STRING_ARRAY: TypeIR = { kind: 'array', element: STRING };
320
+ const UPDATE_BODY: TypeIR = {
321
+ kind: 'object',
322
+ name: 'UpdateAccountBody',
323
+ properties: [
324
+ { name: 'displayName', type: STRING, optional: false, readonly: true },
325
+ {
326
+ name: 'metadata',
327
+ type: { kind: 'union', members: [{ kind: 'object', properties: [] }, { kind: 'null' }] },
328
+ optional: false,
329
+ readonly: true,
330
+ },
331
+ ],
332
+ };
333
+ const ACCOUNT: TypeIR = {
334
+ kind: 'object',
335
+ name: 'Account',
336
+ properties: [
337
+ { name: 'id', type: STRING, optional: false, readonly: true },
338
+ { name: 'displayName', type: STRING, optional: false, readonly: true },
339
+ ],
340
+ };
341
+ const ACCEPTED: TypeIR = {
342
+ kind: 'object',
343
+ name: 'AcceptedUpdate',
344
+ properties: [{ name: 'jobId', type: STRING, optional: false, readonly: true }],
345
+ };
346
+ const PROBLEM: TypeIR = {
347
+ kind: 'object',
348
+ name: 'Problem',
349
+ properties: [
350
+ { name: 'code', type: STRING, optional: false, readonly: true },
351
+ { name: 'message', type: STRING, optional: false, readonly: true },
352
+ ],
353
+ };
354
+
355
+ export const REQUEST_BODY_SCHEMA = {
356
+ type: 'object',
357
+ required: ['displayName', 'metadata'],
358
+ properties: {
359
+ displayName: { type: 'string' },
360
+ metadata: { type: ['object', 'null'], additionalProperties: true },
361
+ },
362
+ } satisfies Readonly<Record<string, JsonValue>>;
363
+
364
+ export const SUCCESS_BODY_SCHEMA = {
365
+ type: 'object',
366
+ required: ['id', 'displayName'],
367
+ properties: {
368
+ id: { type: 'string' },
369
+ displayName: { type: 'string' },
370
+ },
371
+ } satisfies Readonly<Record<string, JsonValue>>;
372
+
373
+ export const HTTP_CONVERGENCE_FIXTURE = {
374
+ contract: {
375
+ format: 1,
376
+ types: {
377
+ 'patch_accounts_accountId/parameter/path/accountId': {
378
+ type: STRING,
379
+ openApi: { type: 'string' },
380
+ },
381
+ 'patch_accounts_accountId/parameter/query/include': {
382
+ type: STRING_ARRAY,
383
+ openApi: { type: 'array', items: { type: 'string' } },
384
+ },
385
+ 'patch_accounts_accountId/parameter/query/dryRun': {
386
+ type: BOOLEAN,
387
+ openApi: { type: 'boolean' },
388
+ },
389
+ 'patch_accounts_accountId/parameter/header/requestId': {
390
+ type: STRING,
391
+ openApi: { type: 'string' },
392
+ },
393
+ 'patch_accounts_accountId/parameter/cookie/session': {
394
+ type: STRING,
395
+ openApi: { type: 'string' },
396
+ },
397
+ 'patch_accounts_accountId/request/body': {
398
+ type: UPDATE_BODY,
399
+ openApi: REQUEST_BODY_SCHEMA,
400
+ },
401
+ 'patch_accounts_accountId/response/200/body': {
402
+ type: ACCOUNT,
403
+ openApi: SUCCESS_BODY_SCHEMA,
404
+ },
405
+ 'patch_accounts_accountId/response/200/header/etag': {
406
+ type: STRING,
407
+ openApi: { type: 'string' },
408
+ },
409
+ 'patch_accounts_accountId/response/202/body': {
410
+ type: ACCEPTED,
411
+ openApi: {
412
+ type: 'object',
413
+ required: ['jobId'],
414
+ properties: { jobId: { type: 'string' } },
415
+ },
416
+ },
417
+ 'patch_accounts_accountId/response/404/body': {
418
+ type: PROBLEM,
419
+ openApi: {
420
+ type: 'object',
421
+ required: ['code', 'message'],
422
+ properties: { code: { type: 'string' }, message: { type: 'string' } },
423
+ },
424
+ },
425
+ },
426
+ operations: [
427
+ {
428
+ operationId: 'patch_accounts_accountId',
429
+ controller: 'AccountsController',
430
+ handler: 'update',
431
+ method: 'PATCH',
432
+ path: '/accounts/:accountId',
433
+ parameters: [
434
+ {
435
+ property: 'accountId',
436
+ name: 'accountId',
437
+ in: 'path',
438
+ required: true,
439
+ typeId: 'patch_accounts_accountId/parameter/path/accountId',
440
+ },
441
+ {
442
+ property: 'include',
443
+ name: 'include',
444
+ in: 'query',
445
+ required: false,
446
+ typeId: 'patch_accounts_accountId/parameter/query/include',
447
+ },
448
+ {
449
+ property: 'dryRun',
450
+ name: 'dry-run',
451
+ in: 'query',
452
+ required: false,
453
+ typeId: 'patch_accounts_accountId/parameter/query/dryRun',
454
+ },
455
+ {
456
+ property: 'requestId',
457
+ name: 'x-request-id',
458
+ in: 'header',
459
+ required: false,
460
+ typeId: 'patch_accounts_accountId/parameter/header/requestId',
461
+ },
462
+ {
463
+ property: 'session',
464
+ name: 'session',
465
+ in: 'cookie',
466
+ required: true,
467
+ typeId: 'patch_accounts_accountId/parameter/cookie/session',
468
+ },
469
+ ],
470
+ requestBody: {
471
+ kind: 'json',
472
+ mediaType: 'application/json',
473
+ typeId: 'patch_accounts_accountId/request/body',
474
+ required: true,
475
+ },
476
+ responses: [
477
+ {
478
+ status: 200,
479
+ description: 'Updated',
480
+ headers: [
481
+ {
482
+ property: 'etag',
483
+ name: 'etag',
484
+ required: true,
485
+ typeId: 'patch_accounts_accountId/response/200/header/etag',
486
+ },
487
+ ],
488
+ body: {
489
+ kind: 'json',
490
+ mediaType: 'application/json',
491
+ typeId: 'patch_accounts_accountId/response/200/body',
492
+ },
493
+ },
494
+ {
495
+ status: 202,
496
+ description: 'Accepted',
497
+ headers: [],
498
+ body: {
499
+ kind: 'json',
500
+ mediaType: 'application/json',
501
+ typeId: 'patch_accounts_accountId/response/202/body',
502
+ },
503
+ },
504
+ {
505
+ status: 204,
506
+ description: 'No change',
507
+ headers: [],
508
+ body: { kind: 'empty' },
509
+ },
510
+ {
511
+ status: 404,
512
+ description: 'Account not found',
513
+ headers: [],
514
+ body: {
515
+ kind: 'json',
516
+ mediaType: 'application/problem+json',
517
+ typeId: 'patch_accounts_accountId/response/404/body',
518
+ },
519
+ },
520
+ ],
521
+ security: [{ bearerAuth: [] }, { apiKeyAuth: [] }],
522
+ version: {
523
+ kind: 'header',
524
+ name: 'accept-version',
525
+ values: ['1', '2'],
526
+ default: '1',
527
+ },
528
+ deprecated: true,
529
+ },
530
+ ],
531
+ securitySchemes: {
532
+ bearerAuth: { type: 'http', scheme: 'bearer' },
533
+ apiKeyAuth: { type: 'apiKey', in: 'header', name: 'x-api-key' },
534
+ },
535
+ } satisfies HttpContractFixture,
536
+ input: {
537
+ path: { accountId: 'acct/blue?draft#1' },
538
+ query: { include: ['roles & permissions', 'teams'], dryRun: undefined },
539
+ headers: { requestId: 'request-680' },
540
+ cookies: { session: 'session value' },
541
+ body: { displayName: 'Ada', metadata: null },
542
+ },
543
+ expectedRequest: {
544
+ path: '/accounts/acct%2Fblue%3Fdraft%231',
545
+ query: [
546
+ { name: 'include', value: 'roles & permissions' },
547
+ { name: 'include', value: 'teams' },
548
+ ],
549
+ headers: { 'x-request-id': 'request-680' },
550
+ cookies: [{ name: 'session', value: 'session value' }],
551
+ body: '{"displayName":"Ada","metadata":null}',
552
+ version: '2',
553
+ },
554
+ bodyKinds: [
555
+ { kind: 'json', mediaType: 'application/json' },
556
+ { kind: 'text', mediaType: 'text/plain' },
557
+ { kind: 'bytes', mediaType: 'application/octet-stream' },
558
+ { kind: 'stream', mediaType: 'application/x-ndjson' },
559
+ { kind: 'empty' },
560
+ ],
561
+ } as const;
562
+
563
+ export type FrozenHttpContract = typeof HTTP_CONVERGENCE_FIXTURE.contract;
564
+ export type FrozenHttpOperation = FrozenHttpContract['operations'][number];