@backstage/backend-openapi-utils 0.0.0-nightly-20230407021743

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/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @backstage/backend-openapi-utils
2
+
3
+ ## 0.0.0-nightly-20230407021743
4
+
5
+ ### Patch Changes
6
+
7
+ - 62fe726fdc5: New plugin! Primary focus is to support types on `Router`s in backend packages. Developers can use the `ApiRouter` from this package in their packages to support a typed experience based on their OpenAPI specs. The `ApiRouter` supports request bodies, response bodies, query parameters and path parameters, as well as full path-based context of the above. This means no more guessing on an endpoint like `req.post('/not-my-route', (req, res)=>{res.send(req.body.badparam)})`. Typescript would catch `/not-my-route`, `req.body.badparam`, `res.send(req.body.badparam)`.
package/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # @backstage/openapi-utils
2
+
3
+ ## Summary
4
+
5
+ This package is meant to provide a typed Express router for an OpenAPI spec. Based on the [`oatx`](https://github.com/varanauskas/oatx) library and adapted to override Express values.
6
+
7
+ ## Getting Started
8
+
9
+ ### Configuration
10
+
11
+ 1. Run `yarn --cwd <package-dir> backstage-cli package schema:openapi:generate` to translate your `src/schema/openapi.yaml` to a new Typescript file in `src/schema/openapi.ts`. In the case of projects that require linting + a license header, you will need to do this manually.
12
+
13
+ 2. In your plugin's `src/service/createRouter.ts`,
14
+
15
+ ```ts
16
+ import {ApiRouter} from `@backstage/backend-openapi-utils`;
17
+ import spec from '../schema/openapi'
18
+ ...
19
+
20
+ export function createRouter(){
21
+ const router = Router() as ApiRouter<typeof spec>;
22
+ ...
23
+ }
24
+ ```
25
+
26
+ ### Limitations
27
+
28
+ 1. `as const` makes all fields `readonly`
29
+ To ensure a good DX of using a simple imported JSON spec, we want to remove any type issues between `readonly` arrays and mutable arrays. Typescript does not allow them to be compared, so converting all imports from the `openapi3-ts` library to `readonly` is important. This is achieved through the `ImmutableObject` type in `types/immutable.ts`.
30
+
31
+ ```ts
32
+ ...
33
+ // We want an interface like this,
34
+ Router() as ApiRouter<typeof spec>
35
+
36
+ // Not an interface like this,
37
+ Router() as ApiRouter<DeepWriteable<typeof spec>>
38
+ ...
39
+ ```
40
+
41
+ ## Future Work
42
+
43
+ ### Runtime validation
44
+
45
+ Using a package like [`express-openapi-validator`](https://www.npmjs.com/package/express-openapi-validator), would allow us to remove [validation of request bodies with `AJV`](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend/src/service/util.ts#L58). However, `AJV` currently doesn't have support for OpenAPI 3.1 and `express-openapi-validator` enforces full URL matching for paths, meaning it cannot be mounted at the router level.
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var index = /*#__PURE__*/Object.freeze({
6
+ __proto__: null
7
+ });
8
+
9
+ exports.internal = index;
10
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
@@ -0,0 +1,539 @@
1
+ import { JSONSchema7, FromSchema } from 'json-schema-to-ts';
2
+ import { ReferenceObject, OpenAPIObject, ContentObject, RequestBodyObject, ResponseObject, ParameterObject, SchemaObject } from 'openapi3-ts';
3
+ import core from 'express-serve-static-core';
4
+ import { Router } from 'express';
5
+
6
+ /**
7
+ * This file is meant to hold Immutable overwrites of the values provided by the `openapi3-ts`
8
+ * package due to issues with `as const` supporting only readonly values.
9
+ */
10
+ /**
11
+ * From {@link https://github.com/microsoft/TypeScript/issues/13923#issuecomment-653675557}, allows
12
+ * us to convert from `as const` to the various OpenAPI types documented in `openapi3-ts`.
13
+ *
14
+ * @public
15
+ */
16
+ type Immutable<T> = T extends Function | boolean | number | string | null | undefined ? T : T extends Map<infer K, infer V> ? ReadonlyMap<Immutable<K>, Immutable<V>> : T extends Set<infer S> ? ReadonlySet<Immutable<S>> : {
17
+ readonly [P in keyof T]: Immutable<T[P]>;
18
+ };
19
+ /**
20
+ * @public
21
+ */
22
+ type ImmutableObject<T> = {
23
+ readonly [K in keyof T]: Immutable<T[K]>;
24
+ };
25
+ /**
26
+ * @public
27
+ */
28
+ type ImmutableReferenceObject = ImmutableObject<ReferenceObject>;
29
+ /**
30
+ * @public
31
+ */
32
+ type ImmutableOpenAPIObject = ImmutableObject<OpenAPIObject>;
33
+ /**
34
+ * @public
35
+ */
36
+ type ImmutableContentObject = ImmutableObject<ContentObject>;
37
+ /**
38
+ * @public
39
+ */
40
+ type ImmutableRequestBodyObject = ImmutableObject<RequestBodyObject>;
41
+ /**
42
+ * @public
43
+ */
44
+ type ImmutableResponseObject = ImmutableObject<ResponseObject>;
45
+ /**
46
+ * @public
47
+ */
48
+ type ImmutableParameterObject = ImmutableObject<ParameterObject>;
49
+ /**
50
+ * @public
51
+ */
52
+ interface HeaderObject extends ParameterObject {
53
+ in: 'header';
54
+ style: 'simple';
55
+ }
56
+ /**
57
+ * @public
58
+ */
59
+ type ImmutableHeaderObject = ImmutableObject<HeaderObject>;
60
+ /**
61
+ * @public
62
+ */
63
+ interface CookieObject extends ParameterObject {
64
+ in: 'cookie';
65
+ style?: 'form';
66
+ }
67
+ /**
68
+ * @public
69
+ */
70
+ type ImmutableCookieObject = ImmutableObject<CookieObject>;
71
+ /**
72
+ * @public
73
+ */
74
+ interface QueryObject extends ParameterObject {
75
+ in: 'query';
76
+ style?: 'form' | 'deepObject' | 'pipeDelimited' | 'spaceDelimited';
77
+ }
78
+ /**
79
+ * @public
80
+ */
81
+ type ImmutableQueryObject = ImmutableObject<QueryObject>;
82
+ /**
83
+ * @public
84
+ */
85
+ interface PathObject extends ParameterObject {
86
+ in: 'path';
87
+ style?: 'simple' | 'label' | 'matrix';
88
+ }
89
+ /**
90
+ * @public
91
+ */
92
+ type ImmutablePathObject = ImmutableObject<PathObject>;
93
+ /**
94
+ * @public
95
+ */
96
+ type ImmutableSchemaObject = ImmutableObject<SchemaObject>;
97
+
98
+ /**
99
+ * Pulled from https://github.com/varanauskas/oatx.
100
+ */
101
+
102
+ /**
103
+ * Basic OpenAPI spec with paths and components properties enforced.
104
+ * @public
105
+ */
106
+ type RequiredDoc = Pick<ImmutableOpenAPIObject, 'paths' | 'components'>;
107
+ /**
108
+ * @public
109
+ */
110
+ type PathDoc = Pick<ImmutableOpenAPIObject, 'paths'>;
111
+ /**
112
+ * Get value types of `T`.
113
+ * @public
114
+ */
115
+ type ValueOf<T> = T[keyof T];
116
+ /**
117
+ * Validate a string against OpenAPI path template, {@link https://spec.openapis.org/oas/v3.1.0#path-templating-matching}.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * const path: PathTemplate<"/posts/{postId}/comments/{commentId}"> = "/posts/:postId/comments/:commentId";
122
+ * const pathWithoutParams: PathTemplate<"/posts/comments"> = "/posts/comments";
123
+ * ```
124
+ *
125
+ * @public
126
+ */
127
+ type PathTemplate<Path extends string> = Path extends `${infer Prefix}{${infer PathName}}${infer Suffix}` ? `${Prefix}:${PathName}${PathTemplate<Suffix>}` : Path;
128
+ /**
129
+ * Extract path as specified in OpenAPI `Doc` based on request path
130
+ * @example
131
+ * ```ts
132
+ * const spec = {
133
+ * paths: {
134
+ * "/posts/{postId}/comments/{commentId}": {},
135
+ * "/posts/comments": {},
136
+ * }
137
+ * };
138
+ * const specPathWithParams: DocPath<typeof spec, "/posts/:postId/comments/:commentId"> = "/posts/{postId}/comments/{commentId}";
139
+ * const specPathWithoutParams: DocPath<typeof spec, "/posts/comments"> = "/posts/comments";
140
+ * ```
141
+ *
142
+ * @public
143
+ */
144
+ type DocPath<Doc extends PathDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>> = ValueOf<{
145
+ [Template in Extract<keyof Doc['paths'], string>]: Path extends PathTemplate<Template> ? Template : never;
146
+ }>;
147
+ /**
148
+ * @public
149
+ */
150
+ type DocPathTemplate<Doc extends PathDoc> = PathTemplate<Extract<keyof Doc['paths'], string>>;
151
+ /**
152
+ * @public
153
+ */
154
+ type DocPathMethod<Doc extends Pick<RequiredDoc, 'paths'>, Path extends DocPathTemplate<Doc>> = keyof Doc['paths'][DocPath<Doc, Path>];
155
+ /**
156
+ * @public
157
+ */
158
+ type MethodAwareDocPath<Doc extends PathDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends keyof Doc['paths'][Path]> = ValueOf<{
159
+ [Template in Extract<keyof Doc['paths'], string>]: Path extends PathTemplate<Template> ? Method extends DocPathMethod<Doc, Path> ? PathTemplate<Template> : never : never;
160
+ }>;
161
+ /**
162
+ * @public
163
+ */
164
+ type DocOperation<Doc extends RequiredDoc, Path extends keyof Doc['paths'], Method extends keyof Doc['paths'][Path]> = Doc['paths'][Path][Method];
165
+ /**
166
+ * @public
167
+ */
168
+ type ComponentTypes<Doc extends RequiredDoc> = Extract<keyof Doc['components'], string>;
169
+ /**
170
+ * @public
171
+ */
172
+ type ComponentRef<Doc extends RequiredDoc, Type extends ComponentTypes<Doc>, Ref extends ImmutableReferenceObject> = Ref extends {
173
+ $ref: `#/components/${Type}/${infer Name}`;
174
+ } ? Name extends keyof Doc['components'][Type] ? Doc['components'][Type][Name] extends ImmutableReferenceObject ? ComponentRef<Doc, Type, Doc['components'][Type][Name]> : Doc['components'][Type][Name] : never : never;
175
+ /**
176
+ * @public
177
+ */
178
+ type SchemaRef<Doc extends RequiredDoc, Schema> = Schema extends {
179
+ $ref: `#/components/schemas/${infer Name}`;
180
+ } ? 'schemas' extends keyof Doc['components'] ? Name extends keyof Doc['components']['schemas'] ? SchemaRef<Doc, Doc['components']['schemas'][Name]> : never : never : {
181
+ [Key in keyof Schema]: SchemaRef<Doc, Schema[Key]>;
182
+ };
183
+ /**
184
+ * @public
185
+ */
186
+ type ObjectWithContentSchema<Doc extends RequiredDoc, Object extends {
187
+ content?: ImmutableContentObject;
188
+ }> = Object['content'] extends ImmutableContentObject ? SchemaRef<Doc, Object['content']['application/json']['schema']> : never;
189
+ /**
190
+ * From {@link https://stackoverflow.com/questions/71393738/typescript-intersection-not-union-type-from-json-schema}
191
+ *
192
+ * StackOverflow says not to do this, but union types aren't possible any other way.
193
+ *
194
+ * @public
195
+ */
196
+ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
197
+ /**
198
+ * @public
199
+ */
200
+ type LastOf<T> = UnionToIntersection<T extends any ? () => T : never> extends () => infer R ? R : never;
201
+ /**
202
+ * @public
203
+ */
204
+ type Push<T extends any[], V> = [...T, V];
205
+ /**
206
+ * @public
207
+ */
208
+ type TuplifyUnion<T, L = LastOf<T>, N = [T] extends [never] ? true : false> = true extends N ? [] : Push<TuplifyUnion<Exclude<T, L>>, L>;
209
+ /**
210
+ * @public
211
+ */
212
+ type ConvertAll<T, R extends ReadonlyArray<unknown> = []> = T extends [
213
+ infer First extends JSONSchema7,
214
+ ...infer Rest
215
+ ] ? ConvertAll<Rest, [...R, FromSchema<First>]> : R;
216
+ /**
217
+ * @public
218
+ */
219
+ type UnknownIfNever<P> = [P] extends [never] ? unknown : P;
220
+ /**
221
+ * @public
222
+ */
223
+ type ToTypeSafe<T> = UnknownIfNever<ConvertAll<TuplifyUnion<T>>[number]>;
224
+ /**
225
+ * @public
226
+ */
227
+ type DiscriminateUnion<T, K extends keyof T, V extends T[K]> = Extract<T, Record<K, V>>;
228
+ /**
229
+ * @public
230
+ */
231
+ type MapDiscriminatedUnion<T extends Record<K, string>, K extends keyof T> = {
232
+ [V in T[K]]: DiscriminateUnion<T, K, V>;
233
+ };
234
+ /**
235
+ * @public
236
+ */
237
+ type PickOptionalKeys<T extends {
238
+ [key: string]: any;
239
+ }> = {
240
+ [K in keyof T]: true extends T[K]['required'] ? never : K;
241
+ }[keyof T];
242
+ /**
243
+ * @public
244
+ */
245
+ type PickRequiredKeys<T extends {
246
+ [key: string]: any;
247
+ }> = {
248
+ [K in keyof T]: true extends T[K]['required'] ? K : never;
249
+ }[keyof T];
250
+ /**
251
+ * @public
252
+ */
253
+ type OptionalMap<T extends {
254
+ [key: string]: any;
255
+ }> = {
256
+ [P in Exclude<PickOptionalKeys<T>, undefined>]?: NonNullable<T[P]>;
257
+ };
258
+ /**
259
+ * @public
260
+ */
261
+ type RequiredMap<T extends {
262
+ [key: string]: any;
263
+ }> = {
264
+ [P in Exclude<PickRequiredKeys<T>, undefined>]: NonNullable<T[P]>;
265
+ };
266
+ /**
267
+ * @public
268
+ */
269
+ type FullMap<T extends {
270
+ [key: string]: any;
271
+ }> = RequiredMap<T> & OptionalMap<T>;
272
+ /**
273
+ * @public
274
+ */
275
+ type Filter<T, U> = T extends U ? T : never;
276
+
277
+ /**
278
+ * @public
279
+ */
280
+ type DocParameter<Doc extends RequiredDoc, Path extends Extract<keyof Doc['paths'], string>, Method extends keyof Doc['paths'][Path], Parameter extends keyof Doc['paths'][Path][Method]['parameters']> = DocOperation<Doc, Path, Method>['parameters'][Parameter] extends ImmutableReferenceObject ? 'parameters' extends ComponentTypes<Doc> ? ComponentRef<Doc, 'parameters', DocOperation<Doc, Path, Method>['parameters'][Parameter]> : never : DocOperation<Doc, Path, Method>['parameters'][Parameter];
281
+ /**
282
+ * @public
283
+ */
284
+ type DocParameters<Doc extends RequiredDoc, Path extends Extract<keyof Doc['paths'], string>, Method extends keyof Doc['paths'][Path]> = DocOperation<Doc, Path, Method>['parameters'] extends ReadonlyArray<any> ? {
285
+ [Index in keyof DocOperation<Doc, Path, Method>['parameters']]: DocParameter<Doc, Path, Method, Index>;
286
+ } : never;
287
+ /**
288
+ * @public
289
+ */
290
+ type ResolveDocParameterSchema<Doc extends RequiredDoc, Schema extends ImmutableParameterObject['schema']> = Schema extends ImmutableReferenceObject ? 'parameters' extends ComponentTypes<Doc> ? ComponentRef<Doc, 'parameters', Schema> : never : Schema;
291
+ /**
292
+ * @public
293
+ */
294
+ type ParameterSchema<Doc extends RequiredDoc, Schema extends ImmutableParameterObject['schema']> = ResolveDocParameterSchema<Doc, Schema> extends infer R ? R extends ImmutableSchemaObject ? R extends JSONSchema7 ? FromSchema<R> : never : never : never;
295
+ /**
296
+ * @public
297
+ */
298
+ type MapToSchema<Doc extends RequiredDoc, T extends Record<string, ImmutableParameterObject>> = {
299
+ [V in keyof T]: NonNullable<T[V]> extends ImmutableParameterObject ? ParameterSchema<Doc, NonNullable<T[V]>['schema']> : never;
300
+ };
301
+ /**
302
+ * @public
303
+ */
304
+ type ParametersSchema<Doc extends RequiredDoc, Path extends Extract<keyof Doc['paths'], string>, Method extends keyof Doc['paths'][Path], FilterType extends ImmutableParameterObject> = number extends keyof DocParameters<Doc, Path, Method> ? MapToSchema<Doc, FullMap<MapDiscriminatedUnion<Filter<DocParameters<Doc, Path, Method>[number], FilterType>, 'name'>>> : never;
305
+ /**
306
+ * @public
307
+ */
308
+ type HeaderSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = ParametersSchema<Doc, DocPath<Doc, Path>, Method, ImmutableHeaderObject>;
309
+ /**
310
+ * @public
311
+ */
312
+ type CookieSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = ParametersSchema<Doc, DocPath<Doc, Path>, Method, ImmutableCookieObject>;
313
+ /**
314
+ * @public
315
+ */
316
+ type PathSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = ParametersSchema<Doc, DocPath<Doc, Path>, Method, ImmutablePathObject>;
317
+ /**
318
+ * @public
319
+ */
320
+ type QuerySchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = ParametersSchema<Doc, DocPath<Doc, Path>, Method, ImmutableQueryObject>;
321
+
322
+ /**
323
+ * Pulled from https://github.com/varanauskas/oatx.
324
+ */
325
+
326
+ /**
327
+ * @public
328
+ */
329
+ type RequestBody<Doc extends RequiredDoc, Path extends Extract<keyof Doc['paths'], string>, Method extends keyof Doc['paths'][Path]> = DocOperation<Doc, Path, Method>['requestBody'] extends ImmutableReferenceObject ? 'requestBodies' extends ComponentTypes<Doc> ? ComponentRef<Doc, 'requestBodies', DocOperation<Doc, Path, Method>['requestBody']> : never : DocOperation<Doc, Path, Method>['requestBody'];
330
+ /**
331
+ * @public
332
+ */
333
+ type RequestBodySchema<Doc extends RequiredDoc, Path extends DocPathTemplate<Doc>, Method extends DocPathMethod<Doc, Path>> = RequestBody<Doc, DocPath<Doc, Path>, Method> extends ImmutableRequestBodyObject ? ObjectWithContentSchema<Doc, RequestBody<Doc, DocPath<Doc, Path>, Method>> : never;
334
+ /**
335
+ * Transform the OpenAPI request body schema to a typesafe JSON schema.
336
+ * @public
337
+ */
338
+ type RequestBodyToJsonSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = ToTypeSafe<RequestBodySchema<Doc, Path, Method>>;
339
+
340
+ /**
341
+ * Pulled from https://github.com/varanauskas/oatx.
342
+ */
343
+
344
+ /**
345
+ * @public
346
+ */
347
+ type Response<Doc extends RequiredDoc, Path extends keyof Doc['paths'], Method extends keyof Doc['paths'][Path], StatusCode extends keyof DocOperation<Doc, Path, Method>['responses']> = DocOperation<Doc, Path, Method>['responses'][StatusCode] extends ImmutableReferenceObject ? 'responses' extends ComponentTypes<Doc> ? ComponentRef<Doc, 'responses', DocOperation<Doc, Path, Method>['responses'][StatusCode]> : never : DocOperation<Doc, Path, Method>['responses'][StatusCode];
348
+ /**
349
+ * @public
350
+ */
351
+ type ResponseSchemas<Doc extends RequiredDoc, Path extends DocPathTemplate<Doc>, Method extends DocPathMethod<Doc, Path>> = {
352
+ [StatusCode in keyof DocOperation<Doc, Path, Method>['responses']]: Response<Doc, Path, Method, StatusCode> extends ImmutableResponseObject ? ObjectWithContentSchema<Doc, Response<Doc, Path, Method, StatusCode>> : never;
353
+ };
354
+ /**
355
+ * Transform the OpenAPI request body schema to a typesafe JSON schema.
356
+ * @public
357
+ */
358
+ type ResponseBodyToJsonSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = ToTypeSafe<ValueOf<ResponseSchemas<Doc, Path, Method>>>;
359
+
360
+ /**
361
+ * Typed express request handler.
362
+ * @public
363
+ */
364
+ type DocRequestHandler<Doc extends RequiredDoc, Path extends DocPathTemplate<Doc>, Method extends keyof Doc['paths'][Path]> = core.RequestHandler<PathSchema<Doc, Path, Method>, ResponseBodyToJsonSchema<Doc, Path, Method>, RequestBodyToJsonSchema<Doc, Path, Method>, QuerySchema<Doc, Path, Method>, Record<string, string>>;
365
+ /**
366
+ * Typed express error handler / request handler union type.
367
+ * @public
368
+ */
369
+ type DocRequestHandlerParams<Doc extends RequiredDoc, Path extends DocPathTemplate<Doc>, Method extends keyof Doc['paths'][Path]> = core.RequestHandlerParams<PathSchema<Doc, Path, Method>, ResponseBodyToJsonSchema<Doc, Path, Method>, RequestBodyToJsonSchema<Doc, Path, Method>, QuerySchema<Doc, Path, Method>, Record<string, string>>;
370
+ /**
371
+ * Superset of the express router path matcher that enforces typed request and response bodies.
372
+ * @public
373
+ */
374
+ interface DocRequestMatcher<Doc extends RequiredDoc, T, Method extends 'all' | 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options' | 'head'> {
375
+ <Path extends MethodAwareDocPath<Doc, DocPathTemplate<Doc>, Method>>(path: Path, ...handlers: Array<DocRequestHandler<Doc, Path, Method>>): T;
376
+ <Path extends MethodAwareDocPath<Doc, DocPathTemplate<Doc>, Method>>(path: Path, ...handlers: Array<DocRequestHandlerParams<Doc, Path, Method>>): T;
377
+ }
378
+
379
+ type index_d_RequiredDoc = RequiredDoc;
380
+ type index_d_PathDoc = PathDoc;
381
+ type index_d_ValueOf<T> = ValueOf<T>;
382
+ type index_d_PathTemplate<Path extends string> = PathTemplate<Path>;
383
+ type index_d_DocPath<Doc extends PathDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>> = DocPath<Doc, Path>;
384
+ type index_d_DocPathTemplate<Doc extends PathDoc> = DocPathTemplate<Doc>;
385
+ type index_d_DocPathMethod<Doc extends Pick<RequiredDoc, 'paths'>, Path extends DocPathTemplate<Doc>> = DocPathMethod<Doc, Path>;
386
+ type index_d_MethodAwareDocPath<Doc extends PathDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends keyof Doc['paths'][Path]> = MethodAwareDocPath<Doc, Path, Method>;
387
+ type index_d_DocOperation<Doc extends RequiredDoc, Path extends keyof Doc['paths'], Method extends keyof Doc['paths'][Path]> = DocOperation<Doc, Path, Method>;
388
+ type index_d_ComponentTypes<Doc extends RequiredDoc> = ComponentTypes<Doc>;
389
+ type index_d_ComponentRef<Doc extends RequiredDoc, Type extends ComponentTypes<Doc>, Ref extends ImmutableReferenceObject> = ComponentRef<Doc, Type, Ref>;
390
+ type index_d_SchemaRef<Doc extends RequiredDoc, Schema> = SchemaRef<Doc, Schema>;
391
+ type index_d_ObjectWithContentSchema<Doc extends RequiredDoc, Object extends {
392
+ content?: ImmutableContentObject;
393
+ }> = ObjectWithContentSchema<Doc, Object>;
394
+ type index_d_UnionToIntersection<U> = UnionToIntersection<U>;
395
+ type index_d_LastOf<T> = LastOf<T>;
396
+ type index_d_Push<T extends any[], V> = Push<T, V>;
397
+ type index_d_TuplifyUnion<T, L = LastOf<T>, N = [T] extends [never] ? true : false> = TuplifyUnion<T, L, N>;
398
+ type index_d_ConvertAll<T, R extends ReadonlyArray<unknown> = []> = ConvertAll<T, R>;
399
+ type index_d_UnknownIfNever<P> = UnknownIfNever<P>;
400
+ type index_d_ToTypeSafe<T> = ToTypeSafe<T>;
401
+ type index_d_DiscriminateUnion<T, K extends keyof T, V extends T[K]> = DiscriminateUnion<T, K, V>;
402
+ type index_d_MapDiscriminatedUnion<T extends Record<K, string>, K extends keyof T> = MapDiscriminatedUnion<T, K>;
403
+ type index_d_PickOptionalKeys<T extends {
404
+ [key: string]: any;
405
+ }> = PickOptionalKeys<T>;
406
+ type index_d_PickRequiredKeys<T extends {
407
+ [key: string]: any;
408
+ }> = PickRequiredKeys<T>;
409
+ type index_d_OptionalMap<T extends {
410
+ [key: string]: any;
411
+ }> = OptionalMap<T>;
412
+ type index_d_RequiredMap<T extends {
413
+ [key: string]: any;
414
+ }> = RequiredMap<T>;
415
+ type index_d_FullMap<T extends {
416
+ [key: string]: any;
417
+ }> = FullMap<T>;
418
+ type index_d_Filter<T, U> = Filter<T, U>;
419
+ type index_d_DocRequestHandler<Doc extends RequiredDoc, Path extends DocPathTemplate<Doc>, Method extends keyof Doc['paths'][Path]> = DocRequestHandler<Doc, Path, Method>;
420
+ type index_d_DocRequestHandlerParams<Doc extends RequiredDoc, Path extends DocPathTemplate<Doc>, Method extends keyof Doc['paths'][Path]> = DocRequestHandlerParams<Doc, Path, Method>;
421
+ type index_d_DocRequestMatcher<Doc extends RequiredDoc, T, Method extends 'all' | 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options' | 'head'> = DocRequestMatcher<Doc, T, Method>;
422
+ type index_d_Immutable<T> = Immutable<T>;
423
+ type index_d_ImmutableObject<T> = ImmutableObject<T>;
424
+ type index_d_ImmutableReferenceObject = ImmutableReferenceObject;
425
+ type index_d_ImmutableOpenAPIObject = ImmutableOpenAPIObject;
426
+ type index_d_ImmutableContentObject = ImmutableContentObject;
427
+ type index_d_ImmutableRequestBodyObject = ImmutableRequestBodyObject;
428
+ type index_d_ImmutableResponseObject = ImmutableResponseObject;
429
+ type index_d_ImmutableParameterObject = ImmutableParameterObject;
430
+ type index_d_HeaderObject = HeaderObject;
431
+ type index_d_ImmutableHeaderObject = ImmutableHeaderObject;
432
+ type index_d_CookieObject = CookieObject;
433
+ type index_d_ImmutableCookieObject = ImmutableCookieObject;
434
+ type index_d_QueryObject = QueryObject;
435
+ type index_d_ImmutableQueryObject = ImmutableQueryObject;
436
+ type index_d_PathObject = PathObject;
437
+ type index_d_ImmutablePathObject = ImmutablePathObject;
438
+ type index_d_ImmutableSchemaObject = ImmutableSchemaObject;
439
+ type index_d_DocParameter<Doc extends RequiredDoc, Path extends Extract<keyof Doc['paths'], string>, Method extends keyof Doc['paths'][Path], Parameter extends keyof Doc['paths'][Path][Method]['parameters']> = DocParameter<Doc, Path, Method, Parameter>;
440
+ type index_d_DocParameters<Doc extends RequiredDoc, Path extends Extract<keyof Doc['paths'], string>, Method extends keyof Doc['paths'][Path]> = DocParameters<Doc, Path, Method>;
441
+ type index_d_ResolveDocParameterSchema<Doc extends RequiredDoc, Schema extends ImmutableParameterObject['schema']> = ResolveDocParameterSchema<Doc, Schema>;
442
+ type index_d_ParameterSchema<Doc extends RequiredDoc, Schema extends ImmutableParameterObject['schema']> = ParameterSchema<Doc, Schema>;
443
+ type index_d_MapToSchema<Doc extends RequiredDoc, T extends Record<string, ImmutableParameterObject>> = MapToSchema<Doc, T>;
444
+ type index_d_ParametersSchema<Doc extends RequiredDoc, Path extends Extract<keyof Doc['paths'], string>, Method extends keyof Doc['paths'][Path], FilterType extends ImmutableParameterObject> = ParametersSchema<Doc, Path, Method, FilterType>;
445
+ type index_d_HeaderSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = HeaderSchema<Doc, Path, Method>;
446
+ type index_d_CookieSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = CookieSchema<Doc, Path, Method>;
447
+ type index_d_PathSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = PathSchema<Doc, Path, Method>;
448
+ type index_d_QuerySchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = QuerySchema<Doc, Path, Method>;
449
+ type index_d_RequestBody<Doc extends RequiredDoc, Path extends Extract<keyof Doc['paths'], string>, Method extends keyof Doc['paths'][Path]> = RequestBody<Doc, Path, Method>;
450
+ type index_d_RequestBodySchema<Doc extends RequiredDoc, Path extends DocPathTemplate<Doc>, Method extends DocPathMethod<Doc, Path>> = RequestBodySchema<Doc, Path, Method>;
451
+ type index_d_RequestBodyToJsonSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = RequestBodyToJsonSchema<Doc, Path, Method>;
452
+ type index_d_Response<Doc extends RequiredDoc, Path extends keyof Doc['paths'], Method extends keyof Doc['paths'][Path], StatusCode extends keyof DocOperation<Doc, Path, Method>['responses']> = Response<Doc, Path, Method, StatusCode>;
453
+ type index_d_ResponseSchemas<Doc extends RequiredDoc, Path extends DocPathTemplate<Doc>, Method extends DocPathMethod<Doc, Path>> = ResponseSchemas<Doc, Path, Method>;
454
+ type index_d_ResponseBodyToJsonSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = ResponseBodyToJsonSchema<Doc, Path, Method>;
455
+ declare namespace index_d {
456
+ export {
457
+ index_d_RequiredDoc as RequiredDoc,
458
+ index_d_PathDoc as PathDoc,
459
+ index_d_ValueOf as ValueOf,
460
+ index_d_PathTemplate as PathTemplate,
461
+ index_d_DocPath as DocPath,
462
+ index_d_DocPathTemplate as DocPathTemplate,
463
+ index_d_DocPathMethod as DocPathMethod,
464
+ index_d_MethodAwareDocPath as MethodAwareDocPath,
465
+ index_d_DocOperation as DocOperation,
466
+ index_d_ComponentTypes as ComponentTypes,
467
+ index_d_ComponentRef as ComponentRef,
468
+ index_d_SchemaRef as SchemaRef,
469
+ index_d_ObjectWithContentSchema as ObjectWithContentSchema,
470
+ index_d_UnionToIntersection as UnionToIntersection,
471
+ index_d_LastOf as LastOf,
472
+ index_d_Push as Push,
473
+ index_d_TuplifyUnion as TuplifyUnion,
474
+ index_d_ConvertAll as ConvertAll,
475
+ index_d_UnknownIfNever as UnknownIfNever,
476
+ index_d_ToTypeSafe as ToTypeSafe,
477
+ index_d_DiscriminateUnion as DiscriminateUnion,
478
+ index_d_MapDiscriminatedUnion as MapDiscriminatedUnion,
479
+ index_d_PickOptionalKeys as PickOptionalKeys,
480
+ index_d_PickRequiredKeys as PickRequiredKeys,
481
+ index_d_OptionalMap as OptionalMap,
482
+ index_d_RequiredMap as RequiredMap,
483
+ index_d_FullMap as FullMap,
484
+ index_d_Filter as Filter,
485
+ index_d_DocRequestHandler as DocRequestHandler,
486
+ index_d_DocRequestHandlerParams as DocRequestHandlerParams,
487
+ index_d_DocRequestMatcher as DocRequestMatcher,
488
+ index_d_Immutable as Immutable,
489
+ index_d_ImmutableObject as ImmutableObject,
490
+ index_d_ImmutableReferenceObject as ImmutableReferenceObject,
491
+ index_d_ImmutableOpenAPIObject as ImmutableOpenAPIObject,
492
+ index_d_ImmutableContentObject as ImmutableContentObject,
493
+ index_d_ImmutableRequestBodyObject as ImmutableRequestBodyObject,
494
+ index_d_ImmutableResponseObject as ImmutableResponseObject,
495
+ index_d_ImmutableParameterObject as ImmutableParameterObject,
496
+ index_d_HeaderObject as HeaderObject,
497
+ index_d_ImmutableHeaderObject as ImmutableHeaderObject,
498
+ index_d_CookieObject as CookieObject,
499
+ index_d_ImmutableCookieObject as ImmutableCookieObject,
500
+ index_d_QueryObject as QueryObject,
501
+ index_d_ImmutableQueryObject as ImmutableQueryObject,
502
+ index_d_PathObject as PathObject,
503
+ index_d_ImmutablePathObject as ImmutablePathObject,
504
+ index_d_ImmutableSchemaObject as ImmutableSchemaObject,
505
+ index_d_DocParameter as DocParameter,
506
+ index_d_DocParameters as DocParameters,
507
+ index_d_ResolveDocParameterSchema as ResolveDocParameterSchema,
508
+ index_d_ParameterSchema as ParameterSchema,
509
+ index_d_MapToSchema as MapToSchema,
510
+ index_d_ParametersSchema as ParametersSchema,
511
+ index_d_HeaderSchema as HeaderSchema,
512
+ index_d_CookieSchema as CookieSchema,
513
+ index_d_PathSchema as PathSchema,
514
+ index_d_QuerySchema as QuerySchema,
515
+ index_d_RequestBody as RequestBody,
516
+ index_d_RequestBodySchema as RequestBodySchema,
517
+ index_d_RequestBodyToJsonSchema as RequestBodyToJsonSchema,
518
+ index_d_Response as Response,
519
+ index_d_ResponseSchemas as ResponseSchemas,
520
+ index_d_ResponseBodyToJsonSchema as ResponseBodyToJsonSchema,
521
+ };
522
+ }
523
+
524
+ /**
525
+ * Typed Express router based on an OpenAPI 3.1 spec.
526
+ * @public
527
+ */
528
+ interface ApiRouter<Doc extends RequiredDoc> extends Router {
529
+ get: DocRequestMatcher<Doc, this, 'get'>;
530
+ post: DocRequestMatcher<Doc, this, 'post'>;
531
+ all: DocRequestMatcher<Doc, this, 'all'>;
532
+ put: DocRequestMatcher<Doc, this, 'put'>;
533
+ delete: DocRequestMatcher<Doc, this, 'delete'>;
534
+ patch: DocRequestMatcher<Doc, this, 'patch'>;
535
+ options: DocRequestMatcher<Doc, this, 'options'>;
536
+ head: DocRequestMatcher<Doc, this, 'head'>;
537
+ }
538
+
539
+ export { ApiRouter, index_d as internal };
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@backstage/backend-openapi-utils",
3
+ "description": "OpenAPI typescript support.",
4
+ "version": "0.0.0-nightly-20230407021743",
5
+ "main": "dist/index.cjs.js",
6
+ "types": "dist/index.d.ts",
7
+ "license": "Apache-2.0",
8
+ "publishConfig": {
9
+ "access": "public",
10
+ "main": "dist/index.cjs.js",
11
+ "module": "dist/index.esm.js",
12
+ "types": "dist/index.d.ts"
13
+ },
14
+ "backstage": {
15
+ "role": "node-library"
16
+ },
17
+ "scripts": {
18
+ "start": "backstage-cli package start",
19
+ "build": "backstage-cli package build",
20
+ "lint": "backstage-cli package lint",
21
+ "test": "backstage-cli package test",
22
+ "clean": "backstage-cli package clean",
23
+ "prepack": "backstage-cli package prepack",
24
+ "postpack": "backstage-cli package postpack"
25
+ },
26
+ "devDependencies": {
27
+ "@backstage/cli": "^0.0.0-nightly-20230407021743"
28
+ },
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "dependencies": {
33
+ "@types/express": "^4.17.6",
34
+ "@types/express-serve-static-core": "^4.17.5",
35
+ "express": "^4.17.1",
36
+ "express-promise-router": "^4.1.0",
37
+ "json-schema-to-ts": "^2.6.2",
38
+ "openapi3-ts": "^3.1.2"
39
+ },
40
+ "module": "dist/index.esm.js"
41
+ }