@extk/expressive 0.3.0 → 0.4.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/dist/index.d.mts CHANGED
@@ -1,10 +1,10 @@
1
- import winston, { Logger as Logger$1 } from 'winston';
2
1
  import * as express from 'express';
3
- import { RequestHandler, Request } from 'express';
2
+ import express__default, { RequestHandler, Request } from 'express';
4
3
  import * as express_serve_static_core from 'express-serve-static-core';
5
4
  import { RouteParameters } from 'express-serve-static-core';
6
- import * as morgan from 'morgan';
7
- import * as helmet from 'helmet';
5
+ import winston, { Logger as Logger$1 } from 'winston';
6
+ import { HelmetOptions } from 'helmet';
7
+ import morgan from 'morgan';
8
8
 
9
9
  type ExpressRoute = string;
10
10
  type ExpressLocalsObj = Record<string, any>;
@@ -162,6 +162,23 @@ type SwaggerConfig = {
162
162
  security?: AuthMethod[];
163
163
  };
164
164
 
165
+ type SwaggerOptions = {
166
+ path?: ExpressRoute;
167
+ doc: SwaggerConfig;
168
+ };
169
+ declare class ServerBuilder {
170
+ private app;
171
+ private container;
172
+ constructor(app: express__default.Express, container: Container);
173
+ get(): express__default.Express;
174
+ withHelmet(options?: Readonly<HelmetOptions>): this;
175
+ withQs(): this;
176
+ withMorgan(format?: string, // TODO: FormatFn
177
+ options?: Parameters<typeof morgan>[1]): this;
178
+ withSwagger(swagger: SwaggerOptions, ...handlers: ExpressHandler[]): this;
179
+ withDefaults(swagger: SwaggerOptions): express__default.Express;
180
+ }
181
+
165
182
  declare class ApiError extends Error {
166
183
  readonly code: string;
167
184
  readonly httpStatusCode: number;
@@ -206,27 +223,16 @@ declare class UserUnauthorizedError extends ApiError {
206
223
  constructor(message?: string);
207
224
  }
208
225
 
209
- declare function parsePositiveInteger<T>(v: T, defaultValue: number, max?: number): number;
210
- declare function parseIdOrFail(v: unknown): number;
211
- declare function slugify(text: string): string;
212
- declare function getTmpDir(): string;
213
- declare function getTmpPath(...steps: string[]): string;
214
- declare function parseDefaultPagination(query: PaginationQuery): Pagination;
215
- declare function createReqSnapshot(req: Request & {
216
- user?: {
217
- id?: string | number;
218
- };
219
- }): ReqSnapshot;
220
-
221
- declare function isDev(): boolean;
222
- declare function isProd(): boolean;
223
- declare function getEnvVar(configName: string): string;
224
- type Env = 'dev' | 'prod' | OtherString;
225
-
226
- declare const createLogger: (options?: winston.LoggerOptions) => winston.Logger;
227
- declare const getDefaultFileLogger: (name?: string) => winston.Logger;
228
- declare const getDefaultConsoleLogger: (name?: string) => winston.Logger;
229
-
226
+ declare class SwaggerBuilder {
227
+ private swaggerDoc;
228
+ constructor(swaggerDoc: SwaggerConfig);
229
+ withInfo(info: SwaggerConfig['info']): this;
230
+ withServers(servers: Servers): this;
231
+ withSecuritySchemes(schemes: Record<string, SecurityScheme>): this;
232
+ withSchemas(schemas: Record<string, Schema>): this;
233
+ withDefaultSecurity(globalAuthMethods: AuthMethod[]): this;
234
+ get(): SwaggerConfig;
235
+ }
230
236
  declare function jsonSchema(schema: Schema): Content;
231
237
  declare function jsonSchemaRef(name: string): Content;
232
238
  declare function param(inP: Param['in'], id: string, schema: Schema, required?: boolean, description?: string, name?: string): Param;
@@ -250,6 +256,27 @@ declare const SWG: {
250
256
  };
251
257
  };
252
258
 
259
+ declare function parsePositiveInteger<T>(v: T, defaultValue: number, max?: number): number;
260
+ declare function parseIdOrFail(v: unknown): number;
261
+ declare function slugify(text: string): string;
262
+ declare function getTmpDir(): string;
263
+ declare function getTmpPath(...steps: string[]): string;
264
+ declare function parseDefaultPagination(query: PaginationQuery): Pagination;
265
+ declare function createReqSnapshot(req: Request & {
266
+ user?: {
267
+ id?: string | number;
268
+ };
269
+ }): ReqSnapshot;
270
+
271
+ declare function isDev(): boolean;
272
+ declare function isProd(): boolean;
273
+ declare function getEnvVar(configName: string): string;
274
+ type Env = 'dev' | 'prod' | OtherString;
275
+
276
+ declare const createLogger: (options?: winston.LoggerOptions) => winston.Logger;
277
+ declare const getDefaultFileLogger: (name?: string) => winston.Logger;
278
+ declare const getDefaultConsoleLogger: (name?: string) => winston.Logger;
279
+
253
280
  declare class ApiErrorResponse<T = undefined> {
254
281
  readonly status = "error";
255
282
  readonly message: string;
@@ -265,42 +292,20 @@ declare class ApiResponse<T = undefined> {
265
292
  }
266
293
 
267
294
  declare function bootstrap(container: Container): {
268
- notFoundMiddleware: (_req: express.Request, res: express.Response, _next: express.NextFunction) => void;
295
+ swaggerBuilder: () => SwaggerBuilder;
269
296
  silently: (fn: () => Promise<void>, reqSnapshot?: ReqSnapshot) => void;
297
+ notFoundMiddleware: (_req: express.Request, res: express.Response, _next: express.NextFunction) => void;
270
298
  getErrorHandlerMiddleware: (errorMapper?: (err: Error & Record<string, unknown>) => ApiError | null | undefined) => (err: Error & Record<string, unknown>, req: express.Request, res: express.Response, _next: express.NextFunction) => Promise<void>;
271
- swaggerBuilder: () => {
272
- withInfo(info: SwaggerConfig["info"]): /*elided*/ any;
273
- withServers(servers: Servers): /*elided*/ any;
274
- withSecuritySchemes(schemes: Record<string, SecurityScheme>): /*elided*/ any;
275
- withSchemas(schemas: Record<string, Schema>): /*elided*/ any;
276
- withDefaultSecurity(globalAuthMethods: AuthMethod[]): /*elided*/ any;
277
- get(): SwaggerConfig;
278
- };
279
- expressiveServer(configs: {
299
+ expressiveServer: (configs?: {
280
300
  app?: express.Express;
281
- }): {
282
- get(): express.Express;
283
- withHelmet(options?: Readonly<helmet.HelmetOptions>): /*elided*/ any;
284
- withQs(): /*elided*/ any;
285
- withMorgan(format?: string, options?: Parameters<typeof morgan>[1]): /*elided*/ any;
286
- withSwagger(swagger: {
287
- path?: ExpressRoute;
288
- doc: SwaggerConfig;
289
- }, ...handlers: ExpressHandler[]): /*elided*/ any;
290
- defaults: {
291
- get(swagger: {
292
- path?: ExpressRoute;
293
- doc: SwaggerConfig;
294
- }): express.Express;
295
- };
296
- };
297
- expressiveRouter(configs: {
301
+ }) => ServerBuilder;
302
+ expressiveRouter: (configs: {
298
303
  oapi?: {
299
304
  tags?: string[];
300
305
  servers?: Servers;
301
306
  security?: AuthMethod[];
302
307
  };
303
- }): {
308
+ }) => {
304
309
  router: express_serve_static_core.Router;
305
310
  addRoute(context: {
306
311
  method: HttpMethod;
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import winston, { Logger as Logger$1 } from 'winston';
2
1
  import * as express from 'express';
3
- import { RequestHandler, Request } from 'express';
2
+ import express__default, { RequestHandler, Request } from 'express';
4
3
  import * as express_serve_static_core from 'express-serve-static-core';
5
4
  import { RouteParameters } from 'express-serve-static-core';
6
- import * as morgan from 'morgan';
7
- import * as helmet from 'helmet';
5
+ import winston, { Logger as Logger$1 } from 'winston';
6
+ import { HelmetOptions } from 'helmet';
7
+ import morgan from 'morgan';
8
8
 
9
9
  type ExpressRoute = string;
10
10
  type ExpressLocalsObj = Record<string, any>;
@@ -162,6 +162,23 @@ type SwaggerConfig = {
162
162
  security?: AuthMethod[];
163
163
  };
164
164
 
165
+ type SwaggerOptions = {
166
+ path?: ExpressRoute;
167
+ doc: SwaggerConfig;
168
+ };
169
+ declare class ServerBuilder {
170
+ private app;
171
+ private container;
172
+ constructor(app: express__default.Express, container: Container);
173
+ get(): express__default.Express;
174
+ withHelmet(options?: Readonly<HelmetOptions>): this;
175
+ withQs(): this;
176
+ withMorgan(format?: string, // TODO: FormatFn
177
+ options?: Parameters<typeof morgan>[1]): this;
178
+ withSwagger(swagger: SwaggerOptions, ...handlers: ExpressHandler[]): this;
179
+ withDefaults(swagger: SwaggerOptions): express__default.Express;
180
+ }
181
+
165
182
  declare class ApiError extends Error {
166
183
  readonly code: string;
167
184
  readonly httpStatusCode: number;
@@ -206,27 +223,16 @@ declare class UserUnauthorizedError extends ApiError {
206
223
  constructor(message?: string);
207
224
  }
208
225
 
209
- declare function parsePositiveInteger<T>(v: T, defaultValue: number, max?: number): number;
210
- declare function parseIdOrFail(v: unknown): number;
211
- declare function slugify(text: string): string;
212
- declare function getTmpDir(): string;
213
- declare function getTmpPath(...steps: string[]): string;
214
- declare function parseDefaultPagination(query: PaginationQuery): Pagination;
215
- declare function createReqSnapshot(req: Request & {
216
- user?: {
217
- id?: string | number;
218
- };
219
- }): ReqSnapshot;
220
-
221
- declare function isDev(): boolean;
222
- declare function isProd(): boolean;
223
- declare function getEnvVar(configName: string): string;
224
- type Env = 'dev' | 'prod' | OtherString;
225
-
226
- declare const createLogger: (options?: winston.LoggerOptions) => winston.Logger;
227
- declare const getDefaultFileLogger: (name?: string) => winston.Logger;
228
- declare const getDefaultConsoleLogger: (name?: string) => winston.Logger;
229
-
226
+ declare class SwaggerBuilder {
227
+ private swaggerDoc;
228
+ constructor(swaggerDoc: SwaggerConfig);
229
+ withInfo(info: SwaggerConfig['info']): this;
230
+ withServers(servers: Servers): this;
231
+ withSecuritySchemes(schemes: Record<string, SecurityScheme>): this;
232
+ withSchemas(schemas: Record<string, Schema>): this;
233
+ withDefaultSecurity(globalAuthMethods: AuthMethod[]): this;
234
+ get(): SwaggerConfig;
235
+ }
230
236
  declare function jsonSchema(schema: Schema): Content;
231
237
  declare function jsonSchemaRef(name: string): Content;
232
238
  declare function param(inP: Param['in'], id: string, schema: Schema, required?: boolean, description?: string, name?: string): Param;
@@ -250,6 +256,27 @@ declare const SWG: {
250
256
  };
251
257
  };
252
258
 
259
+ declare function parsePositiveInteger<T>(v: T, defaultValue: number, max?: number): number;
260
+ declare function parseIdOrFail(v: unknown): number;
261
+ declare function slugify(text: string): string;
262
+ declare function getTmpDir(): string;
263
+ declare function getTmpPath(...steps: string[]): string;
264
+ declare function parseDefaultPagination(query: PaginationQuery): Pagination;
265
+ declare function createReqSnapshot(req: Request & {
266
+ user?: {
267
+ id?: string | number;
268
+ };
269
+ }): ReqSnapshot;
270
+
271
+ declare function isDev(): boolean;
272
+ declare function isProd(): boolean;
273
+ declare function getEnvVar(configName: string): string;
274
+ type Env = 'dev' | 'prod' | OtherString;
275
+
276
+ declare const createLogger: (options?: winston.LoggerOptions) => winston.Logger;
277
+ declare const getDefaultFileLogger: (name?: string) => winston.Logger;
278
+ declare const getDefaultConsoleLogger: (name?: string) => winston.Logger;
279
+
253
280
  declare class ApiErrorResponse<T = undefined> {
254
281
  readonly status = "error";
255
282
  readonly message: string;
@@ -265,42 +292,20 @@ declare class ApiResponse<T = undefined> {
265
292
  }
266
293
 
267
294
  declare function bootstrap(container: Container): {
268
- notFoundMiddleware: (_req: express.Request, res: express.Response, _next: express.NextFunction) => void;
295
+ swaggerBuilder: () => SwaggerBuilder;
269
296
  silently: (fn: () => Promise<void>, reqSnapshot?: ReqSnapshot) => void;
297
+ notFoundMiddleware: (_req: express.Request, res: express.Response, _next: express.NextFunction) => void;
270
298
  getErrorHandlerMiddleware: (errorMapper?: (err: Error & Record<string, unknown>) => ApiError | null | undefined) => (err: Error & Record<string, unknown>, req: express.Request, res: express.Response, _next: express.NextFunction) => Promise<void>;
271
- swaggerBuilder: () => {
272
- withInfo(info: SwaggerConfig["info"]): /*elided*/ any;
273
- withServers(servers: Servers): /*elided*/ any;
274
- withSecuritySchemes(schemes: Record<string, SecurityScheme>): /*elided*/ any;
275
- withSchemas(schemas: Record<string, Schema>): /*elided*/ any;
276
- withDefaultSecurity(globalAuthMethods: AuthMethod[]): /*elided*/ any;
277
- get(): SwaggerConfig;
278
- };
279
- expressiveServer(configs: {
299
+ expressiveServer: (configs?: {
280
300
  app?: express.Express;
281
- }): {
282
- get(): express.Express;
283
- withHelmet(options?: Readonly<helmet.HelmetOptions>): /*elided*/ any;
284
- withQs(): /*elided*/ any;
285
- withMorgan(format?: string, options?: Parameters<typeof morgan>[1]): /*elided*/ any;
286
- withSwagger(swagger: {
287
- path?: ExpressRoute;
288
- doc: SwaggerConfig;
289
- }, ...handlers: ExpressHandler[]): /*elided*/ any;
290
- defaults: {
291
- get(swagger: {
292
- path?: ExpressRoute;
293
- doc: SwaggerConfig;
294
- }): express.Express;
295
- };
296
- };
297
- expressiveRouter(configs: {
301
+ }) => ServerBuilder;
302
+ expressiveRouter: (configs: {
298
303
  oapi?: {
299
304
  tags?: string[];
300
305
  servers?: Servers;
301
306
  security?: AuthMethod[];
302
307
  };
303
- }): {
308
+ }) => {
304
309
  router: express_serve_static_core.Router;
305
310
  addRoute(context: {
306
311
  method: HttpMethod;
package/dist/index.js CHANGED
@@ -71,36 +71,33 @@ var import_qs = __toESM(require("qs"));
71
71
  var import_swagger_ui_express = __toESM(require("swagger-ui-express"));
72
72
 
73
73
  // src/swagger.ts
74
- var buildSwaggerBuilder = (swaggerDoc) => {
75
- return {
76
- swaggerBuilder: () => {
77
- return {
78
- withInfo(info) {
79
- swaggerDoc.info = info;
80
- return this;
81
- },
82
- withServers(servers) {
83
- swaggerDoc.servers = servers;
84
- return this;
85
- },
86
- withSecuritySchemes(schemes) {
87
- swaggerDoc.components.securitySchemes = schemes;
88
- return this;
89
- },
90
- withSchemas(schemas) {
91
- swaggerDoc.components.schemas = schemas;
92
- return this;
93
- },
94
- withDefaultSecurity(globalAuthMethods) {
95
- swaggerDoc.security = globalAuthMethods;
96
- return this;
97
- },
98
- get() {
99
- return swaggerDoc;
100
- }
101
- };
102
- }
103
- };
74
+ var SwaggerBuilder = class {
75
+ constructor(swaggerDoc) {
76
+ this.swaggerDoc = swaggerDoc;
77
+ }
78
+ withInfo(info) {
79
+ this.swaggerDoc.info = info;
80
+ return this;
81
+ }
82
+ withServers(servers) {
83
+ this.swaggerDoc.servers = servers;
84
+ return this;
85
+ }
86
+ withSecuritySchemes(schemes) {
87
+ this.swaggerDoc.components.securitySchemes = schemes;
88
+ return this;
89
+ }
90
+ withSchemas(schemas) {
91
+ this.swaggerDoc.components.schemas = schemas;
92
+ return this;
93
+ }
94
+ withDefaultSecurity(globalAuthMethods) {
95
+ this.swaggerDoc.security = globalAuthMethods;
96
+ return this;
97
+ }
98
+ get() {
99
+ return this.swaggerDoc;
100
+ }
104
101
  };
105
102
  var securitySchemes = {
106
103
  BasicAuth: () => ({
@@ -190,48 +187,50 @@ var SWG = {
190
187
  };
191
188
 
192
189
  // src/expressive.ts
190
+ var ServerBuilder = class {
191
+ constructor(app, container) {
192
+ this.app = app;
193
+ this.container = container;
194
+ }
195
+ get() {
196
+ return this.app;
197
+ }
198
+ withHelmet(options) {
199
+ this.app.use((0, import_helmet.default)(options ?? {}));
200
+ return this;
201
+ }
202
+ withQs() {
203
+ this.app.set("query parser", function(str) {
204
+ return import_qs.default.parse(str, { decoder(s) {
205
+ return decodeURIComponent(s);
206
+ } });
207
+ });
208
+ return this;
209
+ }
210
+ withMorgan(format, options) {
211
+ this.app.use((0, import_morgan.default)(
212
+ format ?? ":req[x-real-ip] :method :url :status :res[content-length] - :response-time ms",
213
+ options ?? { stream: { write: (message) => {
214
+ this.container.logger.info(message.trim());
215
+ } } }
216
+ ));
217
+ return this;
218
+ }
219
+ withSwagger(swagger, ...handlers) {
220
+ this.app.use(swagger.path ?? "/api-docs", ...handlers, import_swagger_ui_express.default.serve, import_swagger_ui_express.default.setup(swagger.doc, {
221
+ customSiteTitle: swagger.doc.info?.title
222
+ }));
223
+ return this;
224
+ }
225
+ withDefaults(swagger) {
226
+ return this.withHelmet().withQs().withMorgan().withSwagger(swagger).get();
227
+ }
228
+ };
193
229
  function buildExpressive(container, swaggerDoc) {
194
230
  return {
195
231
  expressiveServer(configs) {
196
- const app = configs.app ?? (0, import_express.default)();
197
- const result = {
198
- get() {
199
- return app;
200
- },
201
- withHelmet(options) {
202
- app.use((0, import_helmet.default)(options ?? {}));
203
- return this;
204
- },
205
- withQs() {
206
- app.set("query parser", function(str) {
207
- return import_qs.default.parse(str, { decoder(s) {
208
- return decodeURIComponent(s);
209
- } });
210
- });
211
- return this;
212
- },
213
- withMorgan(format, options) {
214
- app.use((0, import_morgan.default)(
215
- format ?? ":req[x-real-ip] :method :url :status :res[content-length] - :response-time ms",
216
- options ?? { stream: { write(message) {
217
- container.logger.info(message.trim());
218
- } } }
219
- ));
220
- return this;
221
- },
222
- withSwagger(swagger, ...handlers) {
223
- app.use(swagger.path ?? "/api-docs", ...handlers, import_swagger_ui_express.default.serve, import_swagger_ui_express.default.setup(swagger.doc, {
224
- customSiteTitle: swagger.doc.info?.title
225
- }));
226
- return this;
227
- },
228
- defaults: {
229
- get(swagger) {
230
- return result.withHelmet().withQs().withMorgan().withSwagger(swagger).get();
231
- }
232
- }
233
- };
234
- return result;
232
+ const app = configs?.app ?? (0, import_express.default)();
233
+ return new ServerBuilder(app, container);
235
234
  },
236
235
  expressiveRouter(configs) {
237
236
  const router = import_express.default.Router();
@@ -277,22 +276,8 @@ function buildExpressive(container, swaggerDoc) {
277
276
  };
278
277
  }
279
278
 
280
- // src/env.ts
281
- var import_dotenv = __toESM(require("dotenv"));
282
- import_dotenv.default.config();
283
- function isDev() {
284
- return getEnvVar("ENV") === "dev";
285
- }
286
- function isProd() {
287
- return getEnvVar("ENV") === "prod";
288
- }
289
- function getEnvVar(configName) {
290
- const config = process.env[configName];
291
- if (!config) {
292
- throw new Error(`Missing config '${configName}'`);
293
- }
294
- return config;
295
- }
279
+ // src/common.ts
280
+ var import_path = __toESM(require("path"));
296
281
 
297
282
  // src/errors.ts
298
283
  var ApiError = class extends Error {
@@ -371,21 +356,7 @@ var UserUnauthorizedError = class extends ApiError {
371
356
  }
372
357
  };
373
358
 
374
- // src/response/ApiErrorResponse.ts
375
- var ApiErrorResponse = class {
376
- status = "error";
377
- message;
378
- errorCode;
379
- errors;
380
- constructor(message, errorCode, errors) {
381
- this.message = message;
382
- this.errorCode = errorCode;
383
- this.errors = errors;
384
- }
385
- };
386
-
387
359
  // src/common.ts
388
- var import_path = __toESM(require("path"));
389
360
  function parsePositiveInteger(v, defaultValue, max) {
390
361
  const value = Number(v);
391
362
  return Number.isInteger(value) && value > 0 && (!max || value <= max) ? value : defaultValue;
@@ -421,10 +392,43 @@ function createReqSnapshot(req) {
421
392
  };
422
393
  }
423
394
 
424
- // src/middleware/errorHandlerMiddleware.ts
425
- var buildErrorHandlerMiddleware = (container) => {
395
+ // src/env.ts
396
+ var import_dotenv = __toESM(require("dotenv"));
397
+ import_dotenv.default.config();
398
+ function isDev() {
399
+ return getEnvVar("ENV") === "dev";
400
+ }
401
+ function isProd() {
402
+ return getEnvVar("ENV") === "prod";
403
+ }
404
+ function getEnvVar(configName) {
405
+ const config = process.env[configName];
406
+ if (!config) {
407
+ throw new Error(`Missing config '${configName}'`);
408
+ }
409
+ return config;
410
+ }
411
+
412
+ // src/response/ApiErrorResponse.ts
413
+ var ApiErrorResponse = class {
414
+ status = "error";
415
+ message;
416
+ errorCode;
417
+ errors;
418
+ constructor(message, errorCode, errors) {
419
+ this.message = message;
420
+ this.errorCode = errorCode;
421
+ this.errors = errors;
422
+ }
423
+ };
424
+
425
+ // src/middleware.ts
426
+ var buildMiddleware = (container) => {
426
427
  const { logger, alertHandler } = container;
427
428
  return {
429
+ notFoundMiddleware: (_req, res, _next) => {
430
+ res.status(404).send("\xAF\\_(\u30C4)_/\xAF").end();
431
+ },
428
432
  getErrorHandlerMiddleware: (errorMapper) => {
429
433
  return async (err, req, res, _next) => {
430
434
  let finalError;
@@ -457,11 +461,6 @@ var buildErrorHandlerMiddleware = (container) => {
457
461
  };
458
462
  };
459
463
 
460
- // src/middleware/notFoundMiddleware.ts
461
- var notFoundMiddleware = (_req, res, _next) => {
462
- res.status(404).send("\xAF\\_(\u30C4)_/\xAF").end();
463
- };
464
-
465
464
  // src/logger.ts
466
465
  var import_winston = __toESM(require("winston"));
467
466
  var import_winston_daily_rotate_file = __toESM(require("winston-daily-rotate-file"));
@@ -540,9 +539,8 @@ function bootstrap(container) {
540
539
  };
541
540
  return {
542
541
  ...buildExpressive(container, swaggerDoc),
543
- ...buildSwaggerBuilder(swaggerDoc),
544
- ...buildErrorHandlerMiddleware(container),
545
- notFoundMiddleware,
542
+ ...buildMiddleware(container),
543
+ swaggerBuilder: () => new SwaggerBuilder(swaggerDoc),
546
544
  silently: (fn, reqSnapshot) => {
547
545
  fn().catch((e) => {
548
546
  if (container.alertHandler && e instanceof Error) {
package/dist/index.mjs CHANGED
@@ -6,36 +6,33 @@ import qs from "qs";
6
6
  import swaggerUi from "swagger-ui-express";
7
7
 
8
8
  // src/swagger.ts
9
- var buildSwaggerBuilder = (swaggerDoc) => {
10
- return {
11
- swaggerBuilder: () => {
12
- return {
13
- withInfo(info) {
14
- swaggerDoc.info = info;
15
- return this;
16
- },
17
- withServers(servers) {
18
- swaggerDoc.servers = servers;
19
- return this;
20
- },
21
- withSecuritySchemes(schemes) {
22
- swaggerDoc.components.securitySchemes = schemes;
23
- return this;
24
- },
25
- withSchemas(schemas) {
26
- swaggerDoc.components.schemas = schemas;
27
- return this;
28
- },
29
- withDefaultSecurity(globalAuthMethods) {
30
- swaggerDoc.security = globalAuthMethods;
31
- return this;
32
- },
33
- get() {
34
- return swaggerDoc;
35
- }
36
- };
37
- }
38
- };
9
+ var SwaggerBuilder = class {
10
+ constructor(swaggerDoc) {
11
+ this.swaggerDoc = swaggerDoc;
12
+ }
13
+ withInfo(info) {
14
+ this.swaggerDoc.info = info;
15
+ return this;
16
+ }
17
+ withServers(servers) {
18
+ this.swaggerDoc.servers = servers;
19
+ return this;
20
+ }
21
+ withSecuritySchemes(schemes) {
22
+ this.swaggerDoc.components.securitySchemes = schemes;
23
+ return this;
24
+ }
25
+ withSchemas(schemas) {
26
+ this.swaggerDoc.components.schemas = schemas;
27
+ return this;
28
+ }
29
+ withDefaultSecurity(globalAuthMethods) {
30
+ this.swaggerDoc.security = globalAuthMethods;
31
+ return this;
32
+ }
33
+ get() {
34
+ return this.swaggerDoc;
35
+ }
39
36
  };
40
37
  var securitySchemes = {
41
38
  BasicAuth: () => ({
@@ -125,48 +122,50 @@ var SWG = {
125
122
  };
126
123
 
127
124
  // src/expressive.ts
125
+ var ServerBuilder = class {
126
+ constructor(app, container) {
127
+ this.app = app;
128
+ this.container = container;
129
+ }
130
+ get() {
131
+ return this.app;
132
+ }
133
+ withHelmet(options) {
134
+ this.app.use(helmet(options ?? {}));
135
+ return this;
136
+ }
137
+ withQs() {
138
+ this.app.set("query parser", function(str) {
139
+ return qs.parse(str, { decoder(s) {
140
+ return decodeURIComponent(s);
141
+ } });
142
+ });
143
+ return this;
144
+ }
145
+ withMorgan(format, options) {
146
+ this.app.use(morgan(
147
+ format ?? ":req[x-real-ip] :method :url :status :res[content-length] - :response-time ms",
148
+ options ?? { stream: { write: (message) => {
149
+ this.container.logger.info(message.trim());
150
+ } } }
151
+ ));
152
+ return this;
153
+ }
154
+ withSwagger(swagger, ...handlers) {
155
+ this.app.use(swagger.path ?? "/api-docs", ...handlers, swaggerUi.serve, swaggerUi.setup(swagger.doc, {
156
+ customSiteTitle: swagger.doc.info?.title
157
+ }));
158
+ return this;
159
+ }
160
+ withDefaults(swagger) {
161
+ return this.withHelmet().withQs().withMorgan().withSwagger(swagger).get();
162
+ }
163
+ };
128
164
  function buildExpressive(container, swaggerDoc) {
129
165
  return {
130
166
  expressiveServer(configs) {
131
- const app = configs.app ?? express();
132
- const result = {
133
- get() {
134
- return app;
135
- },
136
- withHelmet(options) {
137
- app.use(helmet(options ?? {}));
138
- return this;
139
- },
140
- withQs() {
141
- app.set("query parser", function(str) {
142
- return qs.parse(str, { decoder(s) {
143
- return decodeURIComponent(s);
144
- } });
145
- });
146
- return this;
147
- },
148
- withMorgan(format, options) {
149
- app.use(morgan(
150
- format ?? ":req[x-real-ip] :method :url :status :res[content-length] - :response-time ms",
151
- options ?? { stream: { write(message) {
152
- container.logger.info(message.trim());
153
- } } }
154
- ));
155
- return this;
156
- },
157
- withSwagger(swagger, ...handlers) {
158
- app.use(swagger.path ?? "/api-docs", ...handlers, swaggerUi.serve, swaggerUi.setup(swagger.doc, {
159
- customSiteTitle: swagger.doc.info?.title
160
- }));
161
- return this;
162
- },
163
- defaults: {
164
- get(swagger) {
165
- return result.withHelmet().withQs().withMorgan().withSwagger(swagger).get();
166
- }
167
- }
168
- };
169
- return result;
167
+ const app = configs?.app ?? express();
168
+ return new ServerBuilder(app, container);
170
169
  },
171
170
  expressiveRouter(configs) {
172
171
  const router = express.Router();
@@ -212,22 +211,8 @@ function buildExpressive(container, swaggerDoc) {
212
211
  };
213
212
  }
214
213
 
215
- // src/env.ts
216
- import dotenv from "dotenv";
217
- dotenv.config();
218
- function isDev() {
219
- return getEnvVar("ENV") === "dev";
220
- }
221
- function isProd() {
222
- return getEnvVar("ENV") === "prod";
223
- }
224
- function getEnvVar(configName) {
225
- const config = process.env[configName];
226
- if (!config) {
227
- throw new Error(`Missing config '${configName}'`);
228
- }
229
- return config;
230
- }
214
+ // src/common.ts
215
+ import path from "path";
231
216
 
232
217
  // src/errors.ts
233
218
  var ApiError = class extends Error {
@@ -306,21 +291,7 @@ var UserUnauthorizedError = class extends ApiError {
306
291
  }
307
292
  };
308
293
 
309
- // src/response/ApiErrorResponse.ts
310
- var ApiErrorResponse = class {
311
- status = "error";
312
- message;
313
- errorCode;
314
- errors;
315
- constructor(message, errorCode, errors) {
316
- this.message = message;
317
- this.errorCode = errorCode;
318
- this.errors = errors;
319
- }
320
- };
321
-
322
294
  // src/common.ts
323
- import path from "path";
324
295
  function parsePositiveInteger(v, defaultValue, max) {
325
296
  const value = Number(v);
326
297
  return Number.isInteger(value) && value > 0 && (!max || value <= max) ? value : defaultValue;
@@ -356,10 +327,43 @@ function createReqSnapshot(req) {
356
327
  };
357
328
  }
358
329
 
359
- // src/middleware/errorHandlerMiddleware.ts
360
- var buildErrorHandlerMiddleware = (container) => {
330
+ // src/env.ts
331
+ import dotenv from "dotenv";
332
+ dotenv.config();
333
+ function isDev() {
334
+ return getEnvVar("ENV") === "dev";
335
+ }
336
+ function isProd() {
337
+ return getEnvVar("ENV") === "prod";
338
+ }
339
+ function getEnvVar(configName) {
340
+ const config = process.env[configName];
341
+ if (!config) {
342
+ throw new Error(`Missing config '${configName}'`);
343
+ }
344
+ return config;
345
+ }
346
+
347
+ // src/response/ApiErrorResponse.ts
348
+ var ApiErrorResponse = class {
349
+ status = "error";
350
+ message;
351
+ errorCode;
352
+ errors;
353
+ constructor(message, errorCode, errors) {
354
+ this.message = message;
355
+ this.errorCode = errorCode;
356
+ this.errors = errors;
357
+ }
358
+ };
359
+
360
+ // src/middleware.ts
361
+ var buildMiddleware = (container) => {
361
362
  const { logger, alertHandler } = container;
362
363
  return {
364
+ notFoundMiddleware: (_req, res, _next) => {
365
+ res.status(404).send("\xAF\\_(\u30C4)_/\xAF").end();
366
+ },
363
367
  getErrorHandlerMiddleware: (errorMapper) => {
364
368
  return async (err, req, res, _next) => {
365
369
  let finalError;
@@ -392,11 +396,6 @@ var buildErrorHandlerMiddleware = (container) => {
392
396
  };
393
397
  };
394
398
 
395
- // src/middleware/notFoundMiddleware.ts
396
- var notFoundMiddleware = (_req, res, _next) => {
397
- res.status(404).send("\xAF\\_(\u30C4)_/\xAF").end();
398
- };
399
-
400
399
  // src/logger.ts
401
400
  import winston from "winston";
402
401
  import DailyRotateFile from "winston-daily-rotate-file";
@@ -475,9 +474,8 @@ function bootstrap(container) {
475
474
  };
476
475
  return {
477
476
  ...buildExpressive(container, swaggerDoc),
478
- ...buildSwaggerBuilder(swaggerDoc),
479
- ...buildErrorHandlerMiddleware(container),
480
- notFoundMiddleware,
477
+ ...buildMiddleware(container),
478
+ swaggerBuilder: () => new SwaggerBuilder(swaggerDoc),
481
479
  silently: (fn, reqSnapshot) => {
482
480
  fn().catch((e) => {
483
481
  if (container.alertHandler && e instanceof Error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@extk/expressive",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "commonjs",
5
5
  "publishConfig": {
6
6
  "access": "public"