@extk/expressive 0.7.1 → 0.9.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.js CHANGED
@@ -91,9 +91,6 @@ var SwaggerBuilder = class {
91
91
  this.swaggerDoc.security = globalAuthMethods;
92
92
  return this;
93
93
  }
94
- get() {
95
- return this.swaggerDoc;
96
- }
97
94
  };
98
95
  var securitySchemes = {
99
96
  BasicAuth: () => ({
@@ -131,6 +128,22 @@ var security = (name) => {
131
128
  }
132
129
  return securityRegistry[name];
133
130
  };
131
+ function singleFileSchema(field = "file", required = true) {
132
+ const schema = {
133
+ type: "object",
134
+ properties: {
135
+ [field]: { type: "string", format: "binary" }
136
+ },
137
+ ...required && { required: [field] }
138
+ };
139
+ return {
140
+ content: {
141
+ "multipart/form-data": {
142
+ schema
143
+ }
144
+ }
145
+ };
146
+ }
134
147
  function formDataSchema(schema) {
135
148
  return {
136
149
  content: {
@@ -168,7 +181,7 @@ function queryParam(id, schema, required = true, description = "", name) {
168
181
  return param("query", id, schema, required, description, name);
169
182
  }
170
183
  function headerParam(id, schema, required = true, description = "", name) {
171
- return param("headers", id, schema, required, description, name);
184
+ return param("header", id, schema, required, description, name);
172
185
  }
173
186
  function convertExpressPath(path2) {
174
187
  return path2.replace(/:([a-zA-Z0-9_*]+)/g, "{$1}");
@@ -188,17 +201,20 @@ var SWG = {
188
201
  formDataSchema,
189
202
  jsonSchema,
190
203
  jsonSchemaRef,
204
+ singleFileSchema,
191
205
  security,
192
206
  securitySchemes
193
207
  };
194
208
 
195
209
  // src/expressive.ts
196
210
  var ServerBuilder = class {
197
- constructor(app, container) {
211
+ constructor(app, container, swaggerRef) {
198
212
  this.app = app;
199
213
  this.container = container;
214
+ this.swaggerRef = swaggerRef;
200
215
  }
201
216
  build() {
217
+ this.swaggerRef.doc = null;
202
218
  return this.app;
203
219
  }
204
220
  withHelmet(options) {
@@ -216,6 +232,7 @@ var ServerBuilder = class {
216
232
  withMorgan(format, options) {
217
233
  this.app.use((0, import_morgan.default)(
218
234
  format ?? ":req[x-real-ip] :method :url :status :res[content-length] - :response-time ms",
235
+ // TODO: ip or x-real-ip; also, default to json?
219
236
  options ?? { stream: { write: (message) => {
220
237
  this.container.logger.info(message.trim());
221
238
  } } }
@@ -233,18 +250,45 @@ var ServerBuilder = class {
233
250
  fn(this.app, this.container);
234
251
  return this;
235
252
  }
236
- withSwagger(swagger, ...handlers) {
237
- this.app.use(swagger.path ?? "/api-docs", ...handlers, import_swagger_ui_express.default.serve, import_swagger_ui_express.default.setup(swagger.config, {
238
- customSiteTitle: swagger.config.info?.title
239
- }));
253
+ withSwagger(configure, opts, ...handlers) {
254
+ const config = this.swaggerRef.doc;
255
+ if (!config) throw new Error("withSwagger must be called before build()");
256
+ configure(new SwaggerBuilder(config));
257
+ const { path: path2, uiOpts, options, customCss, customfavIcon, swaggerUrl, customSiteTitle } = opts;
258
+ const uiOptsWithDefaults = {
259
+ customSiteTitle: config.info?.title,
260
+ ...uiOpts
261
+ };
262
+ this.app.use(
263
+ path2,
264
+ ...handlers,
265
+ import_swagger_ui_express.default.serve,
266
+ import_swagger_ui_express.default.setup(
267
+ config,
268
+ uiOptsWithDefaults,
269
+ options,
270
+ customCss,
271
+ customfavIcon,
272
+ swaggerUrl,
273
+ customSiteTitle
274
+ )
275
+ );
240
276
  return this;
241
277
  }
242
278
  };
243
- function buildExpressive(container, swaggerDoc) {
279
+ function buildExpressive(container) {
280
+ const swaggerRef = {
281
+ doc: {
282
+ openapi: "3.1.0",
283
+ info: {},
284
+ paths: {},
285
+ components: {}
286
+ }
287
+ };
244
288
  return {
245
289
  expressiveServer(configs) {
246
290
  const app = configs?.app ?? (0, import_express.default)();
247
- return new ServerBuilder(app, container);
291
+ return new ServerBuilder(app, container, swaggerRef);
248
292
  },
249
293
  expressiveRouter(configs) {
250
294
  const router = import_express.default.Router();
@@ -287,10 +331,12 @@ function buildExpressive(container, swaggerDoc) {
287
331
  } else {
288
332
  pathItem.parameters.push(...tryParsePathParameters(route));
289
333
  }
290
- if (!swaggerDoc.paths[route]) {
291
- swaggerDoc.paths[route] = {};
334
+ if (swaggerRef.doc) {
335
+ if (!swaggerRef.doc.paths[route]) {
336
+ swaggerRef.doc.paths[route] = {};
337
+ }
338
+ swaggerRef.doc.paths[route][context.method] = pathItem;
292
339
  }
293
- swaggerDoc.paths[route][context.method] = pathItem;
294
340
  return router;
295
341
  }
296
342
  };
@@ -528,17 +574,9 @@ var ApiResponse = class {
528
574
 
529
575
  // src/index.ts
530
576
  function bootstrap(container) {
531
- const swaggerDoc = {
532
- openapi: "3.1.0",
533
- // TODO
534
- info: {},
535
- paths: {},
536
- components: {}
537
- };
538
577
  return {
539
- ...buildExpressive(container, swaggerDoc),
578
+ ...buildExpressive(container),
540
579
  ...buildMiddleware(container),
541
- swaggerBuilder: () => new SwaggerBuilder(swaggerDoc),
542
580
  silently: async (fn) => {
543
581
  try {
544
582
  await fn();
package/dist/index.mjs CHANGED
@@ -30,9 +30,6 @@ var SwaggerBuilder = class {
30
30
  this.swaggerDoc.security = globalAuthMethods;
31
31
  return this;
32
32
  }
33
- get() {
34
- return this.swaggerDoc;
35
- }
36
33
  };
37
34
  var securitySchemes = {
38
35
  BasicAuth: () => ({
@@ -70,6 +67,22 @@ var security = (name) => {
70
67
  }
71
68
  return securityRegistry[name];
72
69
  };
70
+ function singleFileSchema(field = "file", required = true) {
71
+ const schema = {
72
+ type: "object",
73
+ properties: {
74
+ [field]: { type: "string", format: "binary" }
75
+ },
76
+ ...required && { required: [field] }
77
+ };
78
+ return {
79
+ content: {
80
+ "multipart/form-data": {
81
+ schema
82
+ }
83
+ }
84
+ };
85
+ }
73
86
  function formDataSchema(schema) {
74
87
  return {
75
88
  content: {
@@ -107,7 +120,7 @@ function queryParam(id, schema, required = true, description = "", name) {
107
120
  return param("query", id, schema, required, description, name);
108
121
  }
109
122
  function headerParam(id, schema, required = true, description = "", name) {
110
- return param("headers", id, schema, required, description, name);
123
+ return param("header", id, schema, required, description, name);
111
124
  }
112
125
  function convertExpressPath(path2) {
113
126
  return path2.replace(/:([a-zA-Z0-9_*]+)/g, "{$1}");
@@ -127,17 +140,20 @@ var SWG = {
127
140
  formDataSchema,
128
141
  jsonSchema,
129
142
  jsonSchemaRef,
143
+ singleFileSchema,
130
144
  security,
131
145
  securitySchemes
132
146
  };
133
147
 
134
148
  // src/expressive.ts
135
149
  var ServerBuilder = class {
136
- constructor(app, container) {
150
+ constructor(app, container, swaggerRef) {
137
151
  this.app = app;
138
152
  this.container = container;
153
+ this.swaggerRef = swaggerRef;
139
154
  }
140
155
  build() {
156
+ this.swaggerRef.doc = null;
141
157
  return this.app;
142
158
  }
143
159
  withHelmet(options) {
@@ -155,6 +171,7 @@ var ServerBuilder = class {
155
171
  withMorgan(format, options) {
156
172
  this.app.use(morgan(
157
173
  format ?? ":req[x-real-ip] :method :url :status :res[content-length] - :response-time ms",
174
+ // TODO: ip or x-real-ip; also, default to json?
158
175
  options ?? { stream: { write: (message) => {
159
176
  this.container.logger.info(message.trim());
160
177
  } } }
@@ -172,18 +189,45 @@ var ServerBuilder = class {
172
189
  fn(this.app, this.container);
173
190
  return this;
174
191
  }
175
- withSwagger(swagger, ...handlers) {
176
- this.app.use(swagger.path ?? "/api-docs", ...handlers, swaggerUi.serve, swaggerUi.setup(swagger.config, {
177
- customSiteTitle: swagger.config.info?.title
178
- }));
192
+ withSwagger(configure, opts, ...handlers) {
193
+ const config = this.swaggerRef.doc;
194
+ if (!config) throw new Error("withSwagger must be called before build()");
195
+ configure(new SwaggerBuilder(config));
196
+ const { path: path2, uiOpts, options, customCss, customfavIcon, swaggerUrl, customSiteTitle } = opts;
197
+ const uiOptsWithDefaults = {
198
+ customSiteTitle: config.info?.title,
199
+ ...uiOpts
200
+ };
201
+ this.app.use(
202
+ path2,
203
+ ...handlers,
204
+ swaggerUi.serve,
205
+ swaggerUi.setup(
206
+ config,
207
+ uiOptsWithDefaults,
208
+ options,
209
+ customCss,
210
+ customfavIcon,
211
+ swaggerUrl,
212
+ customSiteTitle
213
+ )
214
+ );
179
215
  return this;
180
216
  }
181
217
  };
182
- function buildExpressive(container, swaggerDoc) {
218
+ function buildExpressive(container) {
219
+ const swaggerRef = {
220
+ doc: {
221
+ openapi: "3.1.0",
222
+ info: {},
223
+ paths: {},
224
+ components: {}
225
+ }
226
+ };
183
227
  return {
184
228
  expressiveServer(configs) {
185
229
  const app = configs?.app ?? express();
186
- return new ServerBuilder(app, container);
230
+ return new ServerBuilder(app, container, swaggerRef);
187
231
  },
188
232
  expressiveRouter(configs) {
189
233
  const router = express.Router();
@@ -226,10 +270,12 @@ function buildExpressive(container, swaggerDoc) {
226
270
  } else {
227
271
  pathItem.parameters.push(...tryParsePathParameters(route));
228
272
  }
229
- if (!swaggerDoc.paths[route]) {
230
- swaggerDoc.paths[route] = {};
273
+ if (swaggerRef.doc) {
274
+ if (!swaggerRef.doc.paths[route]) {
275
+ swaggerRef.doc.paths[route] = {};
276
+ }
277
+ swaggerRef.doc.paths[route][context.method] = pathItem;
231
278
  }
232
- swaggerDoc.paths[route][context.method] = pathItem;
233
279
  return router;
234
280
  }
235
281
  };
@@ -467,17 +513,9 @@ var ApiResponse = class {
467
513
 
468
514
  // src/index.ts
469
515
  function bootstrap(container) {
470
- const swaggerDoc = {
471
- openapi: "3.1.0",
472
- // TODO
473
- info: {},
474
- paths: {},
475
- components: {}
476
- };
477
516
  return {
478
- ...buildExpressive(container, swaggerDoc),
517
+ ...buildExpressive(container),
479
518
  ...buildMiddleware(container),
480
- swaggerBuilder: () => new SwaggerBuilder(swaggerDoc),
481
519
  silently: async (fn) => {
482
520
  try {
483
521
  await fn();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@extk/expressive",
3
- "version": "0.7.1",
3
+ "version": "0.9.0",
4
4
  "type": "commonjs",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -25,7 +25,7 @@
25
25
  "lint": "eslint ./"
26
26
  },
27
27
  "devDependencies": {
28
- "@extk/eslint-config": "^0.2.1",
28
+ "@extk/eslint-config": "^0.3.0",
29
29
  "@extk/tsconfig": "0.1.1",
30
30
  "@types/chance": "^1.1.7",
31
31
  "@types/express": "^5.0.1",
@@ -33,7 +33,7 @@
33
33
  "@types/node": "^20.9.3",
34
34
  "@types/swagger-ui-express": "^4.1.8",
35
35
  "chance": "^1.1.13",
36
- "eslint": "^9.36.0",
36
+ "eslint": "^10.0.3",
37
37
  "tsup": "^8.5.0",
38
38
  "tsx": "^4.20.3",
39
39
  "typescript": "^5.9.2"