@extk/expressive 0.10.0 → 0.11.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 +11 -0
- package/dist/index.d.mts +10 -5
- package/dist/index.d.ts +10 -5
- package/dist/index.js +66 -58
- package/dist/index.mjs +66 -58
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -224,6 +224,17 @@ addRoute({
|
|
|
224
224
|
}, handler);
|
|
225
225
|
```
|
|
226
226
|
|
|
227
|
+
Pass `enabled: false` to skip swagger registration conditionally without breaking the chain:
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
.withSwagger(
|
|
231
|
+
b => b.withInfo({ title: 'My API', version: '1.0' }),
|
|
232
|
+
{ path: '/api-docs', enabled: isDev() },
|
|
233
|
+
)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
When `enabled` is `false`, `withSwagger` is a no-op and the chain continues normally. Omitting `enabled` (or passing `true`) keeps existing behavior.
|
|
237
|
+
|
|
227
238
|
Configure security schemes via the `configure` callback in `withSwagger`:
|
|
228
239
|
|
|
229
240
|
```ts
|
package/dist/index.d.mts
CHANGED
|
@@ -225,10 +225,12 @@ declare const SWG: {
|
|
|
225
225
|
};
|
|
226
226
|
|
|
227
227
|
type SwaggerRef = {
|
|
228
|
-
doc
|
|
228
|
+
doc?: SwaggerConfig | null;
|
|
229
|
+
bootstrapOptions?: SwaggerBootstrapOpts | null;
|
|
229
230
|
};
|
|
230
|
-
type
|
|
231
|
-
|
|
231
|
+
type SwaggerBootstrapOpts = {
|
|
232
|
+
enabled?: boolean;
|
|
233
|
+
configure?: (builder: SwaggerBuilder) => void;
|
|
232
234
|
uiOpts?: SwaggerUiOptions;
|
|
233
235
|
options?: SwaggerOptions;
|
|
234
236
|
customCss?: string;
|
|
@@ -236,6 +238,9 @@ type ExpressiveSwaggerOptions = {
|
|
|
236
238
|
swaggerUrl?: string;
|
|
237
239
|
customSiteTitle?: string;
|
|
238
240
|
};
|
|
241
|
+
type BuildExpressiveOpts = {
|
|
242
|
+
swagger?: SwaggerBootstrapOpts;
|
|
243
|
+
};
|
|
239
244
|
declare class ServerBuilder {
|
|
240
245
|
private app;
|
|
241
246
|
private container;
|
|
@@ -249,7 +254,7 @@ declare class ServerBuilder {
|
|
|
249
254
|
* Helper function for fluent design
|
|
250
255
|
*/
|
|
251
256
|
with(fn: (app: express__default.Express, container: Container) => void): this;
|
|
252
|
-
withSwagger(
|
|
257
|
+
withSwagger(path?: string, ...handlers: ExpressHandler[]): this;
|
|
253
258
|
}
|
|
254
259
|
|
|
255
260
|
declare class ApiError extends Error {
|
|
@@ -323,7 +328,7 @@ declare class ApiResponse<T = undefined> {
|
|
|
323
328
|
constructor(result?: T);
|
|
324
329
|
}
|
|
325
330
|
|
|
326
|
-
declare function bootstrap(container: Container): {
|
|
331
|
+
declare function bootstrap(container: Container, opts?: BuildExpressiveOpts): {
|
|
327
332
|
silently: (fn: () => Promise<void> | void) => Promise<void>;
|
|
328
333
|
getGlobalNotFoundMiddleware: (content?: string) => (_req: express.Request, res: express.Response, _next: express.NextFunction) => void;
|
|
329
334
|
getApiNotFoundMiddleware: () => (req: express.Request, res: express.Response, _next: express.NextFunction) => void;
|
package/dist/index.d.ts
CHANGED
|
@@ -225,10 +225,12 @@ declare const SWG: {
|
|
|
225
225
|
};
|
|
226
226
|
|
|
227
227
|
type SwaggerRef = {
|
|
228
|
-
doc
|
|
228
|
+
doc?: SwaggerConfig | null;
|
|
229
|
+
bootstrapOptions?: SwaggerBootstrapOpts | null;
|
|
229
230
|
};
|
|
230
|
-
type
|
|
231
|
-
|
|
231
|
+
type SwaggerBootstrapOpts = {
|
|
232
|
+
enabled?: boolean;
|
|
233
|
+
configure?: (builder: SwaggerBuilder) => void;
|
|
232
234
|
uiOpts?: SwaggerUiOptions;
|
|
233
235
|
options?: SwaggerOptions;
|
|
234
236
|
customCss?: string;
|
|
@@ -236,6 +238,9 @@ type ExpressiveSwaggerOptions = {
|
|
|
236
238
|
swaggerUrl?: string;
|
|
237
239
|
customSiteTitle?: string;
|
|
238
240
|
};
|
|
241
|
+
type BuildExpressiveOpts = {
|
|
242
|
+
swagger?: SwaggerBootstrapOpts;
|
|
243
|
+
};
|
|
239
244
|
declare class ServerBuilder {
|
|
240
245
|
private app;
|
|
241
246
|
private container;
|
|
@@ -249,7 +254,7 @@ declare class ServerBuilder {
|
|
|
249
254
|
* Helper function for fluent design
|
|
250
255
|
*/
|
|
251
256
|
with(fn: (app: express__default.Express, container: Container) => void): this;
|
|
252
|
-
withSwagger(
|
|
257
|
+
withSwagger(path?: string, ...handlers: ExpressHandler[]): this;
|
|
253
258
|
}
|
|
254
259
|
|
|
255
260
|
declare class ApiError extends Error {
|
|
@@ -323,7 +328,7 @@ declare class ApiResponse<T = undefined> {
|
|
|
323
328
|
constructor(result?: T);
|
|
324
329
|
}
|
|
325
330
|
|
|
326
|
-
declare function bootstrap(container: Container): {
|
|
331
|
+
declare function bootstrap(container: Container, opts?: BuildExpressiveOpts): {
|
|
327
332
|
silently: (fn: () => Promise<void> | void) => Promise<void>;
|
|
328
333
|
getGlobalNotFoundMiddleware: (content?: string) => (_req: express.Request, res: express.Response, _next: express.NextFunction) => void;
|
|
329
334
|
getApiNotFoundMiddleware: () => (req: express.Request, res: express.Response, _next: express.NextFunction) => void;
|
package/dist/index.js
CHANGED
|
@@ -213,7 +213,10 @@ var ServerBuilder = class {
|
|
|
213
213
|
this.swaggerRef = swaggerRef;
|
|
214
214
|
}
|
|
215
215
|
build() {
|
|
216
|
-
this.swaggerRef
|
|
216
|
+
if (this.swaggerRef) {
|
|
217
|
+
this.swaggerRef.doc = null;
|
|
218
|
+
this.swaggerRef.bootstrapOptions = null;
|
|
219
|
+
}
|
|
217
220
|
return this.app;
|
|
218
221
|
}
|
|
219
222
|
withHelmet(options) {
|
|
@@ -240,22 +243,30 @@ var ServerBuilder = class {
|
|
|
240
243
|
fn(this.app, this.container);
|
|
241
244
|
return this;
|
|
242
245
|
}
|
|
243
|
-
withSwagger(
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
246
|
+
withSwagger(path2 = "/api-docs", ...handlers) {
|
|
247
|
+
if (!this.swaggerRef || !this.swaggerRef.doc) {
|
|
248
|
+
return this;
|
|
249
|
+
}
|
|
250
|
+
const doc = this.swaggerRef.doc;
|
|
251
|
+
const {
|
|
252
|
+
configure,
|
|
253
|
+
uiOpts,
|
|
254
|
+
options,
|
|
255
|
+
customCss,
|
|
256
|
+
customfavIcon,
|
|
257
|
+
swaggerUrl,
|
|
258
|
+
customSiteTitle
|
|
259
|
+
} = this.swaggerRef.bootstrapOptions ?? {};
|
|
260
|
+
if (configure) {
|
|
261
|
+
configure(new SwaggerBuilder(doc));
|
|
262
|
+
}
|
|
252
263
|
this.app.use(
|
|
253
264
|
path2,
|
|
254
265
|
...handlers,
|
|
255
266
|
import_swagger_ui_express.default.serve,
|
|
256
267
|
import_swagger_ui_express.default.setup(
|
|
257
|
-
|
|
258
|
-
|
|
268
|
+
doc,
|
|
269
|
+
{ customSiteTitle: doc.info?.title, ...uiOpts },
|
|
259
270
|
options,
|
|
260
271
|
customCss,
|
|
261
272
|
customfavIcon,
|
|
@@ -266,14 +277,11 @@ var ServerBuilder = class {
|
|
|
266
277
|
return this;
|
|
267
278
|
}
|
|
268
279
|
};
|
|
269
|
-
function buildExpressive(container) {
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
paths: {},
|
|
275
|
-
components: {}
|
|
276
|
-
}
|
|
280
|
+
function buildExpressive(container, opts) {
|
|
281
|
+
const swaggerBootstrapOpts = opts?.swagger;
|
|
282
|
+
const swaggerRef = !swaggerBootstrapOpts || swaggerBootstrapOpts.enabled === false ? {} : {
|
|
283
|
+
doc: { openapi: "3.1.0", info: {}, paths: {}, components: {} },
|
|
284
|
+
bootstrapOptions: swaggerBootstrapOpts
|
|
277
285
|
};
|
|
278
286
|
return {
|
|
279
287
|
expressiveServer(configs) {
|
|
@@ -286,42 +294,42 @@ function buildExpressive(container) {
|
|
|
286
294
|
router,
|
|
287
295
|
addRoute(context, ...handlers) {
|
|
288
296
|
router[context.method](context.path, ...handlers);
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
297
|
+
if (swaggerRef?.doc) {
|
|
298
|
+
const {
|
|
299
|
+
pathOverride,
|
|
300
|
+
pathParameters,
|
|
301
|
+
headerParameters,
|
|
302
|
+
queryParameters,
|
|
303
|
+
...pathItemConfig
|
|
304
|
+
} = context.oapi || {};
|
|
305
|
+
const route = pathOverride ?? convertExpressPath(context.path);
|
|
306
|
+
const pathItem = {
|
|
307
|
+
// -- defaults --
|
|
308
|
+
responses: {
|
|
309
|
+
// has to be defined or else responses are not documented... ¯\_(ツ)_/¯
|
|
310
|
+
"200": { description: "OK" },
|
|
311
|
+
"201": { description: "Created" },
|
|
312
|
+
"204": { description: "No Content" },
|
|
313
|
+
"400": { description: "Bad Request" },
|
|
314
|
+
"401": { description: "User Unauthorized" },
|
|
315
|
+
"403": { description: "Forbidden" },
|
|
316
|
+
"500": { description: "Internal Server Error" }
|
|
317
|
+
},
|
|
318
|
+
// -- group defaults --
|
|
319
|
+
...configs?.oapi || {},
|
|
320
|
+
// -- overrides --
|
|
321
|
+
...pathItemConfig || {},
|
|
322
|
+
parameters: [
|
|
323
|
+
// ...(contract.pathParameters || []),
|
|
324
|
+
...headerParameters || [],
|
|
325
|
+
...queryParameters || []
|
|
326
|
+
]
|
|
327
|
+
};
|
|
328
|
+
if (pathParameters?.length) {
|
|
329
|
+
pathItem.parameters.push(...pathParameters);
|
|
330
|
+
} else {
|
|
331
|
+
pathItem.parameters.push(...tryParsePathParameters(route));
|
|
332
|
+
}
|
|
325
333
|
if (!swaggerRef.doc.paths[route]) {
|
|
326
334
|
swaggerRef.doc.paths[route] = {};
|
|
327
335
|
}
|
|
@@ -563,9 +571,9 @@ var ApiResponse = class {
|
|
|
563
571
|
};
|
|
564
572
|
|
|
565
573
|
// src/index.ts
|
|
566
|
-
function bootstrap(container) {
|
|
574
|
+
function bootstrap(container, opts) {
|
|
567
575
|
return {
|
|
568
|
-
...buildExpressive(container),
|
|
576
|
+
...buildExpressive(container, opts),
|
|
569
577
|
...buildMiddleware(container),
|
|
570
578
|
silently: async (fn) => {
|
|
571
579
|
try {
|
package/dist/index.mjs
CHANGED
|
@@ -152,7 +152,10 @@ var ServerBuilder = class {
|
|
|
152
152
|
this.swaggerRef = swaggerRef;
|
|
153
153
|
}
|
|
154
154
|
build() {
|
|
155
|
-
this.swaggerRef
|
|
155
|
+
if (this.swaggerRef) {
|
|
156
|
+
this.swaggerRef.doc = null;
|
|
157
|
+
this.swaggerRef.bootstrapOptions = null;
|
|
158
|
+
}
|
|
156
159
|
return this.app;
|
|
157
160
|
}
|
|
158
161
|
withHelmet(options) {
|
|
@@ -179,22 +182,30 @@ var ServerBuilder = class {
|
|
|
179
182
|
fn(this.app, this.container);
|
|
180
183
|
return this;
|
|
181
184
|
}
|
|
182
|
-
withSwagger(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
185
|
+
withSwagger(path2 = "/api-docs", ...handlers) {
|
|
186
|
+
if (!this.swaggerRef || !this.swaggerRef.doc) {
|
|
187
|
+
return this;
|
|
188
|
+
}
|
|
189
|
+
const doc = this.swaggerRef.doc;
|
|
190
|
+
const {
|
|
191
|
+
configure,
|
|
192
|
+
uiOpts,
|
|
193
|
+
options,
|
|
194
|
+
customCss,
|
|
195
|
+
customfavIcon,
|
|
196
|
+
swaggerUrl,
|
|
197
|
+
customSiteTitle
|
|
198
|
+
} = this.swaggerRef.bootstrapOptions ?? {};
|
|
199
|
+
if (configure) {
|
|
200
|
+
configure(new SwaggerBuilder(doc));
|
|
201
|
+
}
|
|
191
202
|
this.app.use(
|
|
192
203
|
path2,
|
|
193
204
|
...handlers,
|
|
194
205
|
swaggerUi.serve,
|
|
195
206
|
swaggerUi.setup(
|
|
196
|
-
|
|
197
|
-
|
|
207
|
+
doc,
|
|
208
|
+
{ customSiteTitle: doc.info?.title, ...uiOpts },
|
|
198
209
|
options,
|
|
199
210
|
customCss,
|
|
200
211
|
customfavIcon,
|
|
@@ -205,14 +216,11 @@ var ServerBuilder = class {
|
|
|
205
216
|
return this;
|
|
206
217
|
}
|
|
207
218
|
};
|
|
208
|
-
function buildExpressive(container) {
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
paths: {},
|
|
214
|
-
components: {}
|
|
215
|
-
}
|
|
219
|
+
function buildExpressive(container, opts) {
|
|
220
|
+
const swaggerBootstrapOpts = opts?.swagger;
|
|
221
|
+
const swaggerRef = !swaggerBootstrapOpts || swaggerBootstrapOpts.enabled === false ? {} : {
|
|
222
|
+
doc: { openapi: "3.1.0", info: {}, paths: {}, components: {} },
|
|
223
|
+
bootstrapOptions: swaggerBootstrapOpts
|
|
216
224
|
};
|
|
217
225
|
return {
|
|
218
226
|
expressiveServer(configs) {
|
|
@@ -225,42 +233,42 @@ function buildExpressive(container) {
|
|
|
225
233
|
router,
|
|
226
234
|
addRoute(context, ...handlers) {
|
|
227
235
|
router[context.method](context.path, ...handlers);
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
236
|
+
if (swaggerRef?.doc) {
|
|
237
|
+
const {
|
|
238
|
+
pathOverride,
|
|
239
|
+
pathParameters,
|
|
240
|
+
headerParameters,
|
|
241
|
+
queryParameters,
|
|
242
|
+
...pathItemConfig
|
|
243
|
+
} = context.oapi || {};
|
|
244
|
+
const route = pathOverride ?? convertExpressPath(context.path);
|
|
245
|
+
const pathItem = {
|
|
246
|
+
// -- defaults --
|
|
247
|
+
responses: {
|
|
248
|
+
// has to be defined or else responses are not documented... ¯\_(ツ)_/¯
|
|
249
|
+
"200": { description: "OK" },
|
|
250
|
+
"201": { description: "Created" },
|
|
251
|
+
"204": { description: "No Content" },
|
|
252
|
+
"400": { description: "Bad Request" },
|
|
253
|
+
"401": { description: "User Unauthorized" },
|
|
254
|
+
"403": { description: "Forbidden" },
|
|
255
|
+
"500": { description: "Internal Server Error" }
|
|
256
|
+
},
|
|
257
|
+
// -- group defaults --
|
|
258
|
+
...configs?.oapi || {},
|
|
259
|
+
// -- overrides --
|
|
260
|
+
...pathItemConfig || {},
|
|
261
|
+
parameters: [
|
|
262
|
+
// ...(contract.pathParameters || []),
|
|
263
|
+
...headerParameters || [],
|
|
264
|
+
...queryParameters || []
|
|
265
|
+
]
|
|
266
|
+
};
|
|
267
|
+
if (pathParameters?.length) {
|
|
268
|
+
pathItem.parameters.push(...pathParameters);
|
|
269
|
+
} else {
|
|
270
|
+
pathItem.parameters.push(...tryParsePathParameters(route));
|
|
271
|
+
}
|
|
264
272
|
if (!swaggerRef.doc.paths[route]) {
|
|
265
273
|
swaggerRef.doc.paths[route] = {};
|
|
266
274
|
}
|
|
@@ -502,9 +510,9 @@ var ApiResponse = class {
|
|
|
502
510
|
};
|
|
503
511
|
|
|
504
512
|
// src/index.ts
|
|
505
|
-
function bootstrap(container) {
|
|
513
|
+
function bootstrap(container, opts) {
|
|
506
514
|
return {
|
|
507
|
-
...buildExpressive(container),
|
|
515
|
+
...buildExpressive(container, opts),
|
|
508
516
|
...buildMiddleware(container),
|
|
509
517
|
silently: async (fn) => {
|
|
510
518
|
try {
|