@extk/expressive 0.5.4 → 0.6.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.
package/README.md CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  - **Auto-generated OpenAPI 3.1 docs** from your route definitions
24
24
  - **Structured error handling** with typed error classes and consistent JSON responses
25
- - **Winston logging** with daily file rotation and dev/prod modes
25
+ - **Bring-your-own logger** any object with `info/warn/error/debug` works
26
26
  - **Security defaults** via Helmet, safe query parsing, and morgan request logging
27
27
  - **Standardized responses** (`ApiResponse` / `ApiErrorResponse`) across your entire API
28
28
 
@@ -58,13 +58,9 @@ const {
58
58
  const swaggerDoc = swaggerBuilder()
59
59
  .withInfo({ title: 'My API', version: '1.0.0' })
60
60
  .withServers([{ url: 'http://localhost:3000' }])
61
- .get();
61
+ .build();
62
62
 
63
- // 3. Build the Express app with sensible defaults (helmet, morgan, swagger UI)
64
- const app = expressiveServer()
65
- .withDefaults({ path: '/api-docs', doc: swaggerDoc });
66
-
67
- // 4. Define routes — they auto-register in the OpenAPI spec
63
+ // 3. Define routes they auto-register in the OpenAPI spec
68
64
  const { router, addRoute } = expressiveRouter({
69
65
  oapi: { tags: ['Users'] },
70
66
  });
@@ -85,10 +81,24 @@ addRoute(
85
81
  },
86
82
  );
87
83
 
88
- // 5. Mount the router and error handling
89
- app.use(router);
90
- app.use(getErrorHandlerMiddleware());
91
- app.use(notFoundMiddleware);
84
+ ```
85
+
86
+ > [!IMPORTANT]
87
+ > Method call order on `ServerBuilder` matters — middleware is registered in the order you chain it.
88
+
89
+ ```ts
90
+ // 4. Build the Express app
91
+ const app = expressiveServer()
92
+ .withHelmet()
93
+ .withQs()
94
+ .withMorgan()
95
+ .withRoutes(router)
96
+ .withSwagger({ path: '/api-docs', config: swaggerDoc })
97
+ .with((app) => {
98
+ app.use(getErrorHandlerMiddleware());
99
+ app.use(notFoundMiddleware);
100
+ })
101
+ .build();
92
102
 
93
103
  app.listen(3000);
94
104
  ```
@@ -203,15 +213,19 @@ export const loginSchema = z.object({
203
213
  import z from 'zod';
204
214
 
205
215
  const app = expressiveServer()
206
- .withDefaults({
207
- doc: swaggerBuilder()
216
+ .withHelmet()
217
+ .withQs()
218
+ .withMorgan()
219
+ .withSwagger({
220
+ config: swaggerBuilder()
208
221
  .withInfo({ title: 'My API' })
209
222
  .withServers([{ url: 'http://localhost:3000/api' }])
210
223
  .withSchemas(z.toJSONSchema(z.globalRegistry).schemas) // all Zod schemas -> OpenAPI
211
224
  .withSecuritySchemes({ auth: SWG.securitySchemes.BearerAuth() })
212
225
  .withDefaultSecurity([SWG.security('auth')])
213
226
  .get(),
214
- });
227
+ })
228
+ .build();
215
229
  ```
216
230
 
217
231
  **3. Reference them in routes with `SWG.jsonSchemaRef`:**
package/dist/index.d.mts CHANGED
@@ -163,19 +163,23 @@ type SwaggerConfig = {
163
163
 
164
164
  type SwaggerOptions = {
165
165
  path?: ExpressRoute;
166
- doc: SwaggerConfig;
166
+ config: SwaggerConfig;
167
167
  };
168
168
  declare class ServerBuilder {
169
169
  private app;
170
170
  private container;
171
171
  constructor(app: express__default.Express, container: Container);
172
- get(): express__default.Express;
172
+ build(): express__default.Express;
173
173
  withHelmet(options?: Readonly<HelmetOptions>): this;
174
174
  withQs(): this;
175
175
  withMorgan(format?: string, // TODO: FormatFn
176
176
  options?: Parameters<typeof morgan>[1]): this;
177
+ withRoutes(routes: ExpressRoute): this;
178
+ /**
179
+ * Helper function for fluent design
180
+ */
181
+ with(fn: (app: express__default.Express, container: Container) => void): this;
177
182
  withSwagger(swagger: SwaggerOptions, ...handlers: ExpressHandler[]): this;
178
- withDefaults(swagger: SwaggerOptions): express__default.Express;
179
183
  }
180
184
 
181
185
  declare class ApiError extends Error {
package/dist/index.d.ts CHANGED
@@ -163,19 +163,23 @@ type SwaggerConfig = {
163
163
 
164
164
  type SwaggerOptions = {
165
165
  path?: ExpressRoute;
166
- doc: SwaggerConfig;
166
+ config: SwaggerConfig;
167
167
  };
168
168
  declare class ServerBuilder {
169
169
  private app;
170
170
  private container;
171
171
  constructor(app: express__default.Express, container: Container);
172
- get(): express__default.Express;
172
+ build(): express__default.Express;
173
173
  withHelmet(options?: Readonly<HelmetOptions>): this;
174
174
  withQs(): this;
175
175
  withMorgan(format?: string, // TODO: FormatFn
176
176
  options?: Parameters<typeof morgan>[1]): this;
177
+ withRoutes(routes: ExpressRoute): this;
178
+ /**
179
+ * Helper function for fluent design
180
+ */
181
+ with(fn: (app: express__default.Express, container: Container) => void): this;
177
182
  withSwagger(swagger: SwaggerOptions, ...handlers: ExpressHandler[]): this;
178
- withDefaults(swagger: SwaggerOptions): express__default.Express;
179
183
  }
180
184
 
181
185
  declare class ApiError extends Error {
package/dist/index.js CHANGED
@@ -198,7 +198,7 @@ var ServerBuilder = class {
198
198
  this.app = app;
199
199
  this.container = container;
200
200
  }
201
- get() {
201
+ build() {
202
202
  return this.app;
203
203
  }
204
204
  withHelmet(options) {
@@ -222,15 +222,23 @@ var ServerBuilder = class {
222
222
  ));
223
223
  return this;
224
224
  }
225
+ withRoutes(routes) {
226
+ this.app.use(routes);
227
+ return this;
228
+ }
229
+ /**
230
+ * Helper function for fluent design
231
+ */
232
+ with(fn) {
233
+ fn(this.app, this.container);
234
+ return this;
235
+ }
225
236
  withSwagger(swagger, ...handlers) {
226
- this.app.use(swagger.path ?? "/api-docs", ...handlers, import_swagger_ui_express.default.serve, import_swagger_ui_express.default.setup(swagger.doc, {
227
- customSiteTitle: swagger.doc.info?.title
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
228
239
  }));
229
240
  return this;
230
241
  }
231
- withDefaults(swagger) {
232
- return this.withHelmet().withQs().withMorgan().withSwagger(swagger).get();
233
- }
234
242
  };
235
243
  function buildExpressive(container, swaggerDoc) {
236
244
  return {
package/dist/index.mjs CHANGED
@@ -137,7 +137,7 @@ var ServerBuilder = class {
137
137
  this.app = app;
138
138
  this.container = container;
139
139
  }
140
- get() {
140
+ build() {
141
141
  return this.app;
142
142
  }
143
143
  withHelmet(options) {
@@ -161,15 +161,23 @@ var ServerBuilder = class {
161
161
  ));
162
162
  return this;
163
163
  }
164
+ withRoutes(routes) {
165
+ this.app.use(routes);
166
+ return this;
167
+ }
168
+ /**
169
+ * Helper function for fluent design
170
+ */
171
+ with(fn) {
172
+ fn(this.app, this.container);
173
+ return this;
174
+ }
164
175
  withSwagger(swagger, ...handlers) {
165
- this.app.use(swagger.path ?? "/api-docs", ...handlers, swaggerUi.serve, swaggerUi.setup(swagger.doc, {
166
- customSiteTitle: swagger.doc.info?.title
176
+ this.app.use(swagger.path ?? "/api-docs", ...handlers, swaggerUi.serve, swaggerUi.setup(swagger.config, {
177
+ customSiteTitle: swagger.config.info?.title
167
178
  }));
168
179
  return this;
169
180
  }
170
- withDefaults(swagger) {
171
- return this.withHelmet().withQs().withMorgan().withSwagger(swagger).get();
172
- }
173
181
  };
174
182
  function buildExpressive(container, swaggerDoc) {
175
183
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@extk/expressive",
3
- "version": "0.5.4",
3
+ "version": "0.6.1",
4
4
  "type": "commonjs",
5
5
  "publishConfig": {
6
6
  "access": "public"