@emmett-community/emmett-expressjs-with-openapi 0.1.0 → 0.3.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 CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  Express.js utilities for Emmett applications that want OpenAPI 3.x validation without pulling the whole Emmett core. This package wires [`express-openapi-validator`](https://github.com/cdimascio/express-openapi-validator) into the Emmett application builder so you can validate requests, responses, security handlers, file uploads, and formats from a single OpenAPI document.
4
4
 
5
+ [![npm version](https://img.shields.io/npm/v/@emmett-community/emmett-expressjs-with-openapi.svg)](https://www.npmjs.com/package/@emmett-community/emmett-expressjs-with-openapi) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Build and test](https://github.com/emmett-community/emmett-expressjs-with-openapi/actions/workflows/build_and_test.yml/badge.svg)](https://github.com/emmett-community/emmett-expressjs-with-openapi/actions/workflows/build_and_test.yml)
6
+
7
+ ## Features
8
+
9
+ - ✅ **OpenAPI 3.x validation** - Validate requests, responses, security, and file uploads.
10
+ - ✅ **Operation handlers** - Auto-wire handlers from `operationId` or `x-eov-operation-handler`.
11
+ - ✅ **Problem Details middleware** - RFC 7807 error responses out of the box.
12
+ - ✅ **ETag helpers** - Built-in optimistic concurrency utilities.
13
+ - ✅ **Testing helpers** - `ApiSpecification` and `ApiE2ESpecification` for tests.
14
+ - ✅ **Optional add-ons** - Firebase Auth security handlers and Pino HTTP logging.
15
+
5
16
  ## Why this package?
6
17
 
7
18
  - Built as a standalone module extracted from the original `@event-driven-io/emmett` repo so it can evolve independently.
@@ -12,10 +23,30 @@ Express.js utilities for Emmett applications that want OpenAPI 3.x validation wi
12
23
 
13
24
  ```bash
14
25
  npm install @emmett-community/emmett-expressjs-with-openapi
15
- npm install express-openapi-validator # optional peer dependency
26
+ npm install express-openapi-validator # optional: OpenAPI validation
27
+ npm install pino-http # optional: HTTP logging
28
+ npm install @my-f-startup/firebase-auth-express # optional: Firebase Auth handlers
16
29
  ```
17
30
 
18
- Other peer requirements (`express`, `@event-driven-io/emmett`, etc.) follow the versions listed in `package.json`.
31
+ ### Peer Dependencies
32
+
33
+ Required:
34
+ - `@event-driven-io/emmett` ^0.39.1
35
+ - `express` ^4.19.2
36
+ - `express-async-errors` ^3.1.1
37
+ - `http-problem-details` ^0.1.5
38
+
39
+ TypeScript types:
40
+ - `@types/express` ^4.17.21
41
+ - `@types/supertest` ^6.0.2 (if using testing helpers)
42
+
43
+ Optional (feature-gated):
44
+ - `express-openapi-validator` ^5.3.7 (OpenAPI validation)
45
+ - `pino-http` ^9.0.0 (HTTP logging)
46
+ - `@my-f-startup/firebase-auth-express` 0.1.0 (Firebase Auth handlers)
47
+ - `supertest` ^7.0.0 (required by testing helpers)
48
+
49
+ Versions follow what is listed in `package.json`.
19
50
 
20
51
  ## Quick start
21
52
 
@@ -23,15 +54,33 @@ Other peer requirements (`express`, `@event-driven-io/emmett`, etc.) follow the
23
54
  import {
24
55
  getApplication,
25
56
  createOpenApiValidatorOptions,
57
+ startAPI,
26
58
  } from '@emmett-community/emmett-expressjs-with-openapi';
27
59
 
28
- const app = getApplication({
60
+ const app = await getApplication({
29
61
  apis: [myApi],
30
62
  openApiValidator: createOpenApiValidatorOptions('./openapi.yaml', {
31
63
  validateRequests: true,
32
64
  validateResponses: process.env.NODE_ENV === 'development',
33
65
  }),
34
66
  });
67
+
68
+ startAPI(app, { port: 3000 });
69
+ ```
70
+
71
+ ## Configuration
72
+
73
+ ### OpenAPI validation
74
+
75
+ ```typescript
76
+ const app = await getApplication({
77
+ apis: [myApi],
78
+ openApiValidator: createOpenApiValidatorOptions('./openapi.yaml', {
79
+ validateRequests: true,
80
+ validateResponses: true,
81
+ operationHandlers: './handlers',
82
+ }),
83
+ });
35
84
  ```
36
85
 
37
86
  Prefer to parse the spec once and share it? Load the `.yml` document manually and reuse it for routing, validation, and automatic `operationHandlers`.
@@ -41,9 +90,11 @@ import path from 'node:path';
41
90
  import { readFileSync } from 'node:fs';
42
91
  import { parse } from 'yaml';
43
92
 
44
- const spec = parse(readFileSync(new URL('./openapi.yml', import.meta.url), 'utf-8'));
93
+ const spec = parse(
94
+ readFileSync(new URL('./openapi.yml', import.meta.url), 'utf-8'),
95
+ );
45
96
 
46
- const app = getApplication({
97
+ const app = await getApplication({
47
98
  apis: [usersApi],
48
99
  openApiValidator: createOpenApiValidatorOptions(spec, {
49
100
  operationHandlers: path.join(path.dirname(import.meta.url), './handlers'),
@@ -51,28 +102,85 @@ const app = getApplication({
51
102
  });
52
103
  ```
53
104
 
54
- ## Configuration highlights
55
-
56
- `createOpenApiValidatorOptions` forwards every option from `express-openapi-validator`, so you can:
57
-
105
+ Highlights:
58
106
  - Enable/disable request or response validation, including per-field tweaks (coercion, unknown query params, removing additional fields, etc.).
59
107
  - Register custom security handlers with `validateSecurity.handlers`.
60
108
  - Serve the parsed spec via `serveSpec`, configure file upload limits, ignore health-check routes, or validate the spec itself.
61
109
  - Reuse `$ref` parsing, custom formats, and file upload middleware exactly as in the upstream validator.
62
110
 
63
- Head to [`docs/openapi-validation.md`](docs/openapi-validation.md) for the full matrix of options, extended explanations, and complete examples. Keeping that document allows us to document advanced scenarios without bloating the README.
111
+ ### Logging (optional)
64
112
 
65
- ## Examples
113
+ Install the optional peer to enable HTTP request/response logging:
66
114
 
67
- Working examples live under `examples/`:
115
+ ```bash
116
+ npm install pino-http
117
+ ```
68
118
 
69
- - `examples/shopping-cart` – feature-complete Emmett sample (business logic, memory store/publisher, security handlers, OpenAPI file, unit/int/e2e tests, `.http` scripts).
70
- - Legacy quick starts:
71
- - `examples/basic` manual routes + validation (minimal scaffolding).
72
- - `examples/with-security` – standalone security handler demo.
73
- - `examples/operation-handlers` barebones `operationHandlers` showcase.
119
+ ```typescript
120
+ const app = await getApplication({
121
+ pinoHttp: true, // defaults
122
+ // or:
123
+ pinoHttp: { autoLogging: false },
124
+ });
125
+ ```
126
+
127
+ See the full options in the [`pino-http` docs](https://github.com/pinojs/pino-http).
74
128
 
75
- ## Tests
129
+ ### Firebase Auth (optional)
130
+
131
+ If you use Firebase Authentication, install the optional peer and plug it into OpenAPI security handlers:
132
+
133
+ ```bash
134
+ npm install @my-f-startup/firebase-auth-express
135
+ ```
136
+
137
+ ```typescript
138
+ import admin from 'firebase-admin';
139
+ import {
140
+ createFirebaseAuthSecurityHandlers,
141
+ createOpenApiValidatorOptions,
142
+ getApplication,
143
+ } from '@emmett-community/emmett-expressjs-with-openapi';
144
+
145
+ admin.initializeApp();
146
+
147
+ const app = await getApplication({
148
+ apis: [myApi],
149
+ openApiValidator: createOpenApiValidatorOptions('./openapi.yaml', {
150
+ validateSecurity: {
151
+ handlers: createFirebaseAuthSecurityHandlers(),
152
+ },
153
+ }),
154
+ });
155
+ ```
156
+
157
+ `@my-f-startup/firebase-auth-express` relies on `firebase-admin`. Make sure the Admin SDK is installed, initialized, and configured for your environment (credentials or emulator).
158
+
159
+ ## API Reference
160
+
161
+ ### Application
162
+ - `getApplication(options)` - Creates and configures the Express app.
163
+ - `startAPI(app, options)` - Starts the HTTP server.
164
+
165
+ ### OpenAPI
166
+ - `createOpenApiValidatorOptions(apiSpec, options)` - Helper to assemble OpenAPI validator config.
167
+ - `isOpenApiValidatorAvailable()` - Type guard for optional validator dependency.
168
+ - `createFirebaseAuthSecurityHandlers(options)` - Firebase Auth security handlers.
169
+ - `registerHandlerModule(handlersPath, module)` - Manual registration for operation handlers.
170
+
171
+ ### HTTP helpers
172
+ - `send`, `sendCreated`, `sendAccepted`, `sendProblem` - Standard HTTP responses.
173
+
174
+ ### ETag helpers
175
+ - `toWeakETag`, `getETagFromIfMatch`, `getETagFromIfNotMatch`, `getETagValueFromIfMatch`, `setETag`.
176
+
177
+ ### Testing helpers
178
+ - `ApiSpecification`, `ApiE2ESpecification`
179
+ - `expect`, `expectNewEvents`, `expectResponse`, `expectError`
180
+
181
+ See [`docs/openapi-validation.md`](docs/openapi-validation.md) for the full matrix of options and extended examples.
182
+
183
+ ## Testing
76
184
 
77
185
  The package includes comprehensive test coverage:
78
186
 
@@ -80,21 +188,96 @@ The package includes comprehensive test coverage:
80
188
  - **Integration tests** (`test/integration/`) - Basic routing, OpenAPI validation, operation handlers, optimistic concurrency
81
189
  - **E2E tests** (`test/e2e/`) - End-to-end workflows for all features
82
190
 
83
- Run `npm test` to execute the whole suite (unit + integration + e2e) or use:
191
+ ### Running tests
84
192
 
85
- - `npm run test:unit` - Unit tests only
86
- - `npm run test:int` - Integration tests only
87
- - `npm run test:e2e` - E2E tests only
193
+ ```bash
194
+ # Unit tests
195
+ npm run test:unit
196
+
197
+ # Integration tests
198
+ npm run test:int
199
+
200
+ # E2E tests
201
+ npm run test:e2e
202
+
203
+ # All tests
204
+ npm test
205
+ ```
206
+
207
+ ## Examples
208
+
209
+ Working examples live under `examples/`:
210
+
211
+ - `examples/shopping-cart` – feature-complete Emmett sample (business logic, memory store/publisher, security handlers, OpenAPI file, unit/int/e2e tests, `.http` scripts).
212
+ - Legacy quick starts:
213
+ - `examples/basic` – manual routes + validation (minimal scaffolding).
214
+ - `examples/with-security` – standalone security handler demo.
215
+ - `examples/operation-handlers` – barebones `operationHandlers` showcase.
216
+ - `examples/firebase-auth` – Firebase Auth security handlers with operation handlers.
88
217
 
89
218
  ## Documentation
90
219
 
91
220
  - **Guide:** [`docs/openapi-validation.md`](docs/openapi-validation.md) – authoritative reference for configuration, advanced usage, and troubleshooting.
92
221
  - **Emmett docs:** <https://event-driven-io.github.io/emmett/>
93
222
 
223
+ ## Compatibility
224
+
225
+ - **Node.js**: tested in CI with 24.x
226
+ - **Emmett**: ^0.39.1
227
+ - **Express**: ^4.19.2
228
+
94
229
  ## Contributing
95
230
 
96
- Issues and PRs are welcome! Please open a discussion or ticket if you are unsure about the direction of a change before coding.
231
+ Contributions are welcome! Please:
232
+
233
+ 1. Fork the repository
234
+ 2. Create a feature branch
235
+ 3. Add tests for new functionality
236
+ 4. Ensure all tests pass
237
+ 5. Submit a pull request
238
+
239
+ ## Development
240
+
241
+ ```bash
242
+ # Install dependencies
243
+ npm install
244
+
245
+ # Build
246
+ npm run build
247
+
248
+ # Type-check
249
+ npm run build:ts
250
+
251
+ # Run tests
252
+ npm test
253
+
254
+ # Run unit tests only
255
+ npm run test:unit
256
+
257
+ # Run integration tests
258
+ npm run test:int
259
+
260
+ # Run E2E tests
261
+ npm run test:e2e
262
+ ```
97
263
 
98
264
  ## License
99
265
 
100
266
  MIT
267
+
268
+ ## Related Packages
269
+
270
+ - [@event-driven-io/emmett](https://github.com/event-driven-io/emmett) - Core Emmett framework
271
+ - [@emmett-community/emmett-google-firestore](https://github.com/emmett-community/emmett-google-firestore) - Firestore event store
272
+ - [@emmett-community/emmett-google-realtime-db](https://github.com/emmett-community/emmett-google-realtime-db) - Realtime Database inline projections
273
+ - [@emmett-community/emmett-google-pubsub](https://github.com/emmett-community/emmett-google-pubsub) - Pub/Sub message bus
274
+ - [@event-driven-io/emmett-mongodb](https://github.com/event-driven-io/emmett/tree/main/src/packages/emmett-mongodb) - MongoDB event store
275
+
276
+ ## Support
277
+
278
+ - [GitHub Issues](https://github.com/emmett-community/emmett-expressjs-with-openapi/issues)
279
+ - [Emmett Documentation](https://event-driven-io.github.io/emmett/)
280
+
281
+ ---
282
+
283
+ Made with ❤️ by the Emmett Community
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/axcosta/Git/pessoal/oss/emmett-community/emmett-expressjs-with-openapi/dist/chunk-GS7T56RP.cjs","../node_modules/tsup/assets/cjs_shims.js"],"names":[],"mappings":"AAAA;ACKA,IAAM,iBAAA,EAAmB,CAAA,EAAA,GACvB,OAAO,SAAA,IAAa,YAAA,EAChB,IAAI,GAAA,CAAI,CAAA,KAAA,EAAQ,UAAU,CAAA,CAAA;AAK8B;ADT4B;AACA;AACA;AACA","file":"/Users/axcosta/Git/pessoal/oss/emmett-community/emmett-expressjs-with-openapi/dist/chunk-GS7T56RP.cjs","sourcesContent":[null,"// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n"]}
1
+ {"version":3,"sources":["/home/runner/work/emmett-expressjs-with-openapi/emmett-expressjs-with-openapi/dist/chunk-GS7T56RP.cjs","../node_modules/tsup/assets/cjs_shims.js"],"names":[],"mappings":"AAAA;ACKA,IAAM,iBAAA,EAAmB,CAAA,EAAA,GACvB,OAAO,SAAA,IAAa,YAAA,EAChB,IAAI,GAAA,CAAI,CAAA,KAAA,EAAQ,UAAU,CAAA,CAAA;AAK8B;ADT4B;AACA;AACA;AACA","file":"/home/runner/work/emmett-expressjs-with-openapi/emmett-expressjs-with-openapi/dist/chunk-GS7T56RP.cjs","sourcesContent":[null,"// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/axcosta/Git/pessoal/oss/emmett-community/emmett-expressjs-with-openapi/dist/chunk-MRSGTROW.cjs","../src/internal/esm-resolver.ts"],"names":["require"],"mappings":"AAAA;AACE;AACF,wDAA6B;AAC7B;AACA;AC6BA,gCAA8B;AAC9B,wEAAiB;AAEjB,IAAI,UAAA,EAAY,KAAA;AAChB,IAAM,YAAA,kBAAc,IAAI,GAAA,CAAiB,CAAA;AAMlC,IAAM,sBAAA,EAAwB,CAAC,UAAA,EAAoB,aAAA,EAAA,GAA6B;AACrF,EAAA,WAAA,CAAY,GAAA,CAAI,UAAA,EAAY,aAAa,CAAA;AAC3C,CAAA;AAKO,IAAM,oBAAA,EAAsB,CAAA,EAAA,GAAY;AAC7C,EAAA,GAAA,CAAI,SAAA,EAAW;AACb,IAAA,MAAA;AAAA,EACF;AAEA,EAAA,MAAMA,SAAAA,EAAU,mCAAA,+BAA6B,CAAA;AAC7C,EAAA,MAAM,OAAA,EAASA,QAAAA,CAAQ,QAAQ,CAAA;AAC/B,EAAA,MAAM,aAAA,EAAe,MAAA,CAAO,KAAA;AAE5B,EAAA,MAAA,CAAO,MAAA,EAAQ,QAAA,CAAU,OAAA,EAAiB,MAAA,EAAa,MAAA,EAAiB;AACtE,IAAA,MAAM,OAAA,kBAAS,MAAA,2BAAQ,UAAA;AACvB,IAAA,MAAM,mBAAA,kBAAqB,MAAA,6BAAQ,QAAA,mBAAS,2BAA2B,GAAA;AACvE,IAAA,MAAM,gBAAA,EAAkB,OAAA,CAAQ,QAAA,CAAS,UAAU,CAAA;AAEnD,IAAA,GAAA,CAAI,mBAAA,GAAsB,eAAA,EAAiB;AACzC,MAAA,MAAM,aAAA,EAAe,cAAA,CAAK,UAAA,CAAW,OAAO,EAAA,EACxC,QAAA,EACA,cAAA,CAAK,OAAA,CAAQ,cAAA,CAAK,OAAA,CAAQ,MAAM,CAAA,EAAG,OAAO,CAAA;AAG9C,MAAA,GAAA,CAAI,WAAA,CAAY,GAAA,CAAI,YAAY,CAAA,EAAG;AACjC,QAAA,OAAO,WAAA,CAAY,GAAA,CAAI,YAAY,CAAA;AAAA,MACrC;AAEA,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,+BAAA,EAAkC,YAAY,CAAA,gEAAA;AAAA,MAEhD,CAAA;AAAA,IACF;AAEA,IAAA,OAAO,YAAA,CAAa,IAAA,CAAK,IAAA,EAAM,OAAA,EAAS,MAAA,EAAQ,MAAM,CAAA;AAAA,EACxD,CAAA;AAEA,EAAA,UAAA,EAAY,IAAA;AACd,CAAA;ADhDA;AACA;AACE;AACA;AACF,yGAAC","file":"/Users/axcosta/Git/pessoal/oss/emmett-community/emmett-expressjs-with-openapi/dist/chunk-MRSGTROW.cjs","sourcesContent":[null,"/**\n * ESM Resolver for express-openapi-validator operation handlers.\n *\n * INTERNAL MODULE - Not part of public API.\n *\n * PROBLEM:\n * When using TypeScript runtime (tsx) with express-openapi-validator's operationHandlers:\n * - Our code uses `import()` to load handlers (ESM)\n * - express-openapi-validator uses `require()` to load handlers (CJS)\n * - Node.js maintains separate module caches for ESM and CJS\n * - This creates TWO separate instances of the same handler module\n * - Dependencies injected via module-level variables in one instance don't reach the other\n *\n * SOLUTION:\n * This module monkey-patches Module.prototype.require to intercept when\n * express-openapi-validator loads operation handlers and forces it to use\n * dynamic import() instead of require(). This ensures both sides share the\n * same ESM module instance, allowing module-level variables to work correctly.\n *\n * USAGE:\n * This module is automatically activated by getApplication() when operationHandlers\n * are configured. Applications don't need to import or configure anything.\n *\n * LIMITATIONS:\n * - Relies on heuristic detection (caller path includes 'express-openapi-validator')\n * - May break if express-openapi-validator changes its internal loading mechanism\n * - Adds \"magic\" behavior that may not be immediately obvious to developers\n *\n * FUTURE:\n * If express-openapi-validator migrates to native ESM, this resolver becomes\n * unnecessary and will safely become a no-op.\n */\n\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\n\nlet isPatched = false;\nconst moduleCache = new Map<string, any>();\n\n/**\n * Registers a pre-loaded ESM module so it can be returned synchronously\n * when express-openapi-validator tries to require() it.\n */\nexport const registerHandlerModule = (modulePath: string, moduleExports: any): void => {\n moduleCache.set(modulePath, moduleExports);\n};\n\n/**\n * Activates the ESM resolver for express-openapi-validator handler loading.\n */\nexport const activateESMResolver = (): void => {\n if (isPatched) {\n return;\n }\n\n const require = createRequire(import.meta.url);\n const Module = require('module');\n const originalLoad = Module._load;\n\n Module._load = function (request: string, parent: any, isMain: boolean) {\n const caller = parent?.filename;\n const isValidatorLoading = caller?.includes('express-openapi-validator');\n const isHandlerModule = request.includes('handlers');\n\n if (isValidatorLoading && isHandlerModule) {\n const absolutePath = path.isAbsolute(request)\n ? request\n : path.resolve(path.dirname(caller), request);\n\n // Check if we have this module pre-registered\n if (moduleCache.has(absolutePath)) {\n return moduleCache.get(absolutePath);\n }\n\n throw new Error(\n `Handler module not registered: ${absolutePath}. ` +\n `Make sure initializeHandlers imports and registers the module.`\n );\n }\n\n return originalLoad.call(this, request, parent, isMain);\n };\n\n isPatched = true;\n};\n"]}
1
+ {"version":3,"sources":["/home/runner/work/emmett-expressjs-with-openapi/emmett-expressjs-with-openapi/dist/chunk-MRSGTROW.cjs","../src/internal/esm-resolver.ts"],"names":["require"],"mappings":"AAAA;AACE;AACF,wDAA6B;AAC7B;AACA;AC6BA,gCAA8B;AAC9B,wEAAiB;AAEjB,IAAI,UAAA,EAAY,KAAA;AAChB,IAAM,YAAA,kBAAc,IAAI,GAAA,CAAiB,CAAA;AAMlC,IAAM,sBAAA,EAAwB,CAAC,UAAA,EAAoB,aAAA,EAAA,GAA6B;AACrF,EAAA,WAAA,CAAY,GAAA,CAAI,UAAA,EAAY,aAAa,CAAA;AAC3C,CAAA;AAKO,IAAM,oBAAA,EAAsB,CAAA,EAAA,GAAY;AAC7C,EAAA,GAAA,CAAI,SAAA,EAAW;AACb,IAAA,MAAA;AAAA,EACF;AAEA,EAAA,MAAMA,SAAAA,EAAU,mCAAA,+BAA6B,CAAA;AAC7C,EAAA,MAAM,OAAA,EAASA,QAAAA,CAAQ,QAAQ,CAAA;AAC/B,EAAA,MAAM,aAAA,EAAe,MAAA,CAAO,KAAA;AAE5B,EAAA,MAAA,CAAO,MAAA,EAAQ,QAAA,CAAU,OAAA,EAAiB,MAAA,EAAa,MAAA,EAAiB;AACtE,IAAA,MAAM,OAAA,kBAAS,MAAA,2BAAQ,UAAA;AACvB,IAAA,MAAM,mBAAA,kBAAqB,MAAA,6BAAQ,QAAA,mBAAS,2BAA2B,GAAA;AACvE,IAAA,MAAM,gBAAA,EAAkB,OAAA,CAAQ,QAAA,CAAS,UAAU,CAAA;AAEnD,IAAA,GAAA,CAAI,mBAAA,GAAsB,eAAA,EAAiB;AACzC,MAAA,MAAM,aAAA,EAAe,cAAA,CAAK,UAAA,CAAW,OAAO,EAAA,EACxC,QAAA,EACA,cAAA,CAAK,OAAA,CAAQ,cAAA,CAAK,OAAA,CAAQ,MAAM,CAAA,EAAG,OAAO,CAAA;AAG9C,MAAA,GAAA,CAAI,WAAA,CAAY,GAAA,CAAI,YAAY,CAAA,EAAG;AACjC,QAAA,OAAO,WAAA,CAAY,GAAA,CAAI,YAAY,CAAA;AAAA,MACrC;AAEA,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,+BAAA,EAAkC,YAAY,CAAA,gEAAA;AAAA,MAEhD,CAAA;AAAA,IACF;AAEA,IAAA,OAAO,YAAA,CAAa,IAAA,CAAK,IAAA,EAAM,OAAA,EAAS,MAAA,EAAQ,MAAM,CAAA;AAAA,EACxD,CAAA;AAEA,EAAA,UAAA,EAAY,IAAA;AACd,CAAA;ADhDA;AACA;AACE;AACA;AACF,yGAAC","file":"/home/runner/work/emmett-expressjs-with-openapi/emmett-expressjs-with-openapi/dist/chunk-MRSGTROW.cjs","sourcesContent":[null,"/**\n * ESM Resolver for express-openapi-validator operation handlers.\n *\n * INTERNAL MODULE - Not part of public API.\n *\n * PROBLEM:\n * When using TypeScript runtime (tsx) with express-openapi-validator's operationHandlers:\n * - Our code uses `import()` to load handlers (ESM)\n * - express-openapi-validator uses `require()` to load handlers (CJS)\n * - Node.js maintains separate module caches for ESM and CJS\n * - This creates TWO separate instances of the same handler module\n * - Dependencies injected via module-level variables in one instance don't reach the other\n *\n * SOLUTION:\n * This module monkey-patches Module.prototype.require to intercept when\n * express-openapi-validator loads operation handlers and forces it to use\n * dynamic import() instead of require(). This ensures both sides share the\n * same ESM module instance, allowing module-level variables to work correctly.\n *\n * USAGE:\n * This module is automatically activated by getApplication() when operationHandlers\n * are configured. Applications don't need to import or configure anything.\n *\n * LIMITATIONS:\n * - Relies on heuristic detection (caller path includes 'express-openapi-validator')\n * - May break if express-openapi-validator changes its internal loading mechanism\n * - Adds \"magic\" behavior that may not be immediately obvious to developers\n *\n * FUTURE:\n * If express-openapi-validator migrates to native ESM, this resolver becomes\n * unnecessary and will safely become a no-op.\n */\n\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\n\nlet isPatched = false;\nconst moduleCache = new Map<string, any>();\n\n/**\n * Registers a pre-loaded ESM module so it can be returned synchronously\n * when express-openapi-validator tries to require() it.\n */\nexport const registerHandlerModule = (modulePath: string, moduleExports: any): void => {\n moduleCache.set(modulePath, moduleExports);\n};\n\n/**\n * Activates the ESM resolver for express-openapi-validator handler loading.\n */\nexport const activateESMResolver = (): void => {\n if (isPatched) {\n return;\n }\n\n const require = createRequire(import.meta.url);\n const Module = require('module');\n const originalLoad = Module._load;\n\n Module._load = function (request: string, parent: any, isMain: boolean) {\n const caller = parent?.filename;\n const isValidatorLoading = caller?.includes('express-openapi-validator');\n const isHandlerModule = request.includes('handlers');\n\n if (isValidatorLoading && isHandlerModule) {\n const absolutePath = path.isAbsolute(request)\n ? request\n : path.resolve(path.dirname(caller), request);\n\n // Check if we have this module pre-registered\n if (moduleCache.has(absolutePath)) {\n return moduleCache.get(absolutePath);\n }\n\n throw new Error(\n `Handler module not registered: ${absolutePath}. ` +\n `Make sure initializeHandlers imports and registers the module.`\n );\n }\n\n return originalLoad.call(this, request, parent, isMain);\n };\n\n isPatched = true;\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/axcosta/Git/pessoal/oss/emmett-community/emmett-expressjs-with-openapi/dist/esm-resolver-I5MW2PIQ.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACF,wDAA6B;AAC7B,gCAA6B;AAC7B;AACE;AACA;AACF,6IAAC","file":"/Users/axcosta/Git/pessoal/oss/emmett-community/emmett-expressjs-with-openapi/dist/esm-resolver-I5MW2PIQ.cjs"}
1
+ {"version":3,"sources":["/home/runner/work/emmett-expressjs-with-openapi/emmett-expressjs-with-openapi/dist/esm-resolver-I5MW2PIQ.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACF,wDAA6B;AAC7B,gCAA6B;AAC7B;AACE;AACA;AACF,6IAAC","file":"/home/runner/work/emmett-expressjs-with-openapi/emmett-expressjs-with-openapi/dist/esm-resolver-I5MW2PIQ.cjs"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/axcosta/Git/pessoal/oss/emmett-community/emmett-expressjs-with-openapi/dist/handler-importer-4BVBIZX3.cjs","../src/internal/handler-importer.ts"],"names":[],"mappings":"AAAA;AACE;AACF,wDAA6B;AAC7B,gCAA6B;AAC7B;AACA;ACIA,0BAA8B;AAY9B,MAAA,SAAsB,yBAAA,CACpB,OAAA,EACiC;AACjC,EAAA,MAAM,iBAAA,EAA2C,CAAC,CAAA;AAElD,EAAA,IAAA,CAAA,MAAW,OAAA,GAAU,OAAA,EAAS;AAC5B,IAAA,IAAI;AAEF,MAAA,MAAM,QAAA,EAAU,gCAAA,MAAc,CAAO,YAAY,CAAA,CAAE,IAAA;AAGnD,MAAA,MAAM,eAAA,EAAiB,MAAM,4DAAA,CAAO,OAAA,GAAA;AAGpC,MAAA,qDAAA,MAAsB,CAAO,YAAA,EAAc,cAAc,CAAA;AAGzD,MAAA,gBAAA,CAAiB,MAAA,CAAO,UAAU,EAAA,EAAI,cAAA;AAAA,IACxC,EAAA,MAAA,CAAS,KAAA,EAAO;AACd,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,iCAAA,EAAoC,MAAA,CAAO,UAAU,CAAA,OAAA,EAAU,MAAA,CAAO,YAAY,CAAA,EAAA,EAC/E,KAAA,CAAgB,OACnB,CAAA;AAAA,MAAA;AACF,IAAA;AACF,EAAA;AAGF,EAAA;AACF;AD1BA;AACA;AACA","file":"/Users/axcosta/Git/pessoal/oss/emmett-community/emmett-expressjs-with-openapi/dist/handler-importer-4BVBIZX3.cjs","sourcesContent":[null,"/**\n * Handler module importer.\n *\n * INTERNAL MODULE - Not part of public API.\n *\n * Dynamically imports handler modules and registers them in the ESM resolver cache,\n * enabling automatic handler discovery without manual registration.\n */\n\nimport { pathToFileURL } from 'node:url';\nimport { registerHandlerModule } from './esm-resolver.js';\nimport type { HandlerModuleInfo } from './openapi-parser.js';\n\nexport type ImportedHandlerModules = Record<string, any>;\n\n/**\n * Dynamically import and register all handler modules.\n *\n * @param modules - Handler module information from OpenAPI parser\n * @returns Object containing all imported modules, keyed by module name\n */\nexport async function importAndRegisterHandlers(\n modules: HandlerModuleInfo[],\n): Promise<ImportedHandlerModules> {\n const importedHandlers: ImportedHandlerModules = {};\n\n for (const module of modules) {\n try {\n // Convert to file:// URL for dynamic import\n const fileUrl = pathToFileURL(module.absolutePath).href;\n\n // Dynamically import the handler module\n const importedModule = await import(fileUrl);\n\n // Register in ESM resolver cache\n registerHandlerModule(module.absolutePath, importedModule);\n\n // Store in result object keyed by module name\n importedHandlers[module.moduleName] = importedModule;\n } catch (error) {\n throw new Error(\n `Failed to import handler module \"${module.moduleName}\" from ${module.absolutePath}: ${\n (error as Error).message\n }`,\n );\n }\n }\n\n return importedHandlers;\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/emmett-expressjs-with-openapi/emmett-expressjs-with-openapi/dist/handler-importer-4BVBIZX3.cjs","../src/internal/handler-importer.ts"],"names":[],"mappings":"AAAA;AACE;AACF,wDAA6B;AAC7B,gCAA6B;AAC7B;AACA;ACIA,0BAA8B;AAY9B,MAAA,SAAsB,yBAAA,CACpB,OAAA,EACiC;AACjC,EAAA,MAAM,iBAAA,EAA2C,CAAC,CAAA;AAElD,EAAA,IAAA,CAAA,MAAW,OAAA,GAAU,OAAA,EAAS;AAC5B,IAAA,IAAI;AAEF,MAAA,MAAM,QAAA,EAAU,gCAAA,MAAc,CAAO,YAAY,CAAA,CAAE,IAAA;AAGnD,MAAA,MAAM,eAAA,EAAiB,MAAM,4DAAA,CAAO,OAAA,GAAA;AAGpC,MAAA,qDAAA,MAAsB,CAAO,YAAA,EAAc,cAAc,CAAA;AAGzD,MAAA,gBAAA,CAAiB,MAAA,CAAO,UAAU,EAAA,EAAI,cAAA;AAAA,IACxC,EAAA,MAAA,CAAS,KAAA,EAAO;AACd,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,iCAAA,EAAoC,MAAA,CAAO,UAAU,CAAA,OAAA,EAAU,MAAA,CAAO,YAAY,CAAA,EAAA,EAC/E,KAAA,CAAgB,OACnB,CAAA;AAAA,MAAA;AACF,IAAA;AACF,EAAA;AAGF,EAAA;AACF;AD1BA;AACA;AACA","file":"/home/runner/work/emmett-expressjs-with-openapi/emmett-expressjs-with-openapi/dist/handler-importer-4BVBIZX3.cjs","sourcesContent":[null,"/**\n * Handler module importer.\n *\n * INTERNAL MODULE - Not part of public API.\n *\n * Dynamically imports handler modules and registers them in the ESM resolver cache,\n * enabling automatic handler discovery without manual registration.\n */\n\nimport { pathToFileURL } from 'node:url';\nimport { registerHandlerModule } from './esm-resolver.js';\nimport type { HandlerModuleInfo } from './openapi-parser.js';\n\nexport type ImportedHandlerModules = Record<string, any>;\n\n/**\n * Dynamically import and register all handler modules.\n *\n * @param modules - Handler module information from OpenAPI parser\n * @returns Object containing all imported modules, keyed by module name\n */\nexport async function importAndRegisterHandlers(\n modules: HandlerModuleInfo[],\n): Promise<ImportedHandlerModules> {\n const importedHandlers: ImportedHandlerModules = {};\n\n for (const module of modules) {\n try {\n // Convert to file:// URL for dynamic import\n const fileUrl = pathToFileURL(module.absolutePath).href;\n\n // Dynamically import the handler module\n const importedModule = await import(fileUrl);\n\n // Register in ESM resolver cache\n registerHandlerModule(module.absolutePath, importedModule);\n\n // Store in result object keyed by module name\n importedHandlers[module.moduleName] = importedModule;\n } catch (error) {\n throw new Error(\n `Failed to import handler module \"${module.moduleName}\" from ${module.absolutePath}: ${\n (error as Error).message\n }`,\n );\n }\n }\n\n return importedHandlers;\n}\n"]}
package/dist/index.cjs CHANGED
@@ -51,10 +51,31 @@ var getApplication = async (options) => {
51
51
  disableJsonMiddleware,
52
52
  disableUrlEncodingMiddleware,
53
53
  disableProblemDetailsMiddleware,
54
+ pinoHttp,
54
55
  openApiValidator
55
56
  } = options;
56
57
  const router = _express.Router.call(void 0, );
57
58
  app.set("etag", _nullishCoalesce(enableDefaultExpressEtag, () => ( false)));
59
+ if (pinoHttp !== void 0 && pinoHttp !== false) {
60
+ try {
61
+ const require2 = _module.createRequire.call(void 0, _chunkGS7T56RPcjs.importMetaUrl);
62
+ const mod = require2("pino-http");
63
+ const provider = _nullishCoalesce(mod.default, () => ( mod));
64
+ if (typeof provider !== "function") {
65
+ throw new Error("Invalid pino-http module: missing default export");
66
+ }
67
+ const options2 = pinoHttp === true ? void 0 : pinoHttp;
68
+ const middleware = provider(options2);
69
+ app.use(middleware);
70
+ } catch (e) {
71
+ console.warn(
72
+ "Pino HTTP configuration provided but pino-http package is not installed. Install it with: npm install pino-http"
73
+ );
74
+ throw new Error(
75
+ "pino-http package is required when pinoHttp option is used"
76
+ );
77
+ }
78
+ }
58
79
  if (!disableJsonMiddleware) app.use(_express2.default.json());
59
80
  if (!disableUrlEncodingMiddleware)
60
81
  app.use(
@@ -68,7 +89,7 @@ var getApplication = async (options) => {
68
89
  activateESMResolver();
69
90
  const handlersBasePath = typeof openApiValidator.operationHandlers === "string" ? openApiValidator.operationHandlers : openApiValidator.operationHandlers.basePath;
70
91
  if (handlersBasePath) {
71
- const { extractHandlerModules } = await Promise.resolve().then(() => _interopRequireWildcard(require("./openapi-parser-KI7BS3DC.cjs")));
92
+ const { extractHandlerModules } = await Promise.resolve().then(() => _interopRequireWildcard(require("./openapi-parser-NFUD7ZGZ.cjs")));
72
93
  const { importAndRegisterHandlers } = await Promise.resolve().then(() => _interopRequireWildcard(require("./handler-importer-4BVBIZX3.cjs")));
73
94
  try {
74
95
  const modules = await extractHandlerModules(
@@ -117,7 +138,7 @@ var getApplication = async (options) => {
117
138
  } else {
118
139
  app.use(middleware);
119
140
  }
120
- } catch (e) {
141
+ } catch (e2) {
121
142
  console.warn(
122
143
  "OpenAPI validator configuration provided but express-openapi-validator package is not installed. Install it with: npm install express-openapi-validator"
123
144
  );
@@ -220,28 +241,86 @@ var HttpProblem = (statusCode, options) => (response) => {
220
241
  sendProblem(response, statusCode, options);
221
242
  };
222
243
 
244
+ // src/openapi/firebase-auth.ts
245
+ var loadFirebaseAuth = async () => {
246
+ try {
247
+ const mod = await Promise.resolve().then(() => _interopRequireWildcard(require("@my-f-startup/firebase-auth-express")));
248
+ const provider = _nullishCoalesce(mod.default, () => ( mod));
249
+ const firebaseAuthMiddleware = provider.firebaseAuthMiddleware;
250
+ if (typeof firebaseAuthMiddleware !== "function") {
251
+ throw new Error(
252
+ "Invalid @my-f-startup/firebase-auth-express module: missing firebaseAuthMiddleware export"
253
+ );
254
+ }
255
+ return provider;
256
+ } catch (error) {
257
+ const message = "@my-f-startup/firebase-auth-express is required for createFirebaseAuthSecurityHandlers. Install it with: npm install @my-f-startup/firebase-auth-express";
258
+ throw new Error(message, { cause: error });
259
+ }
260
+ };
261
+ var createNullResponse = () => {
262
+ const res = {};
263
+ res.status = () => res;
264
+ res.json = () => res;
265
+ res.send = () => res;
266
+ res.end = () => res;
267
+ res.set = () => res;
268
+ return res;
269
+ };
270
+ var runMiddleware = async (middleware, req) => {
271
+ return new Promise((resolve) => {
272
+ let nextCalled = false;
273
+ const res = createNullResponse();
274
+ const next = () => {
275
+ nextCalled = true;
276
+ resolve(true);
277
+ };
278
+ Promise.resolve(middleware(req, res, next)).then(() => {
279
+ if (!nextCalled) resolve(false);
280
+ }).catch(() => resolve(false));
281
+ });
282
+ };
283
+ var createFirebaseAuthSecurityHandlers = (options = {}) => {
284
+ const securitySchemeName = _nullishCoalesce(options.securitySchemeName, () => ( "bearerAuth"));
285
+ const roleClaim = _nullishCoalesce(options.roleClaim, () => ( "roles"));
286
+ return {
287
+ [securitySchemeName]: async (req, scopes, _schema) => {
288
+ const { firebaseAuthMiddleware } = await loadFirebaseAuth();
289
+ const middleware = firebaseAuthMiddleware({
290
+ authClient: options.authClient
291
+ });
292
+ const isAuthenticated = await runMiddleware(middleware, req);
293
+ if (!isAuthenticated) return false;
294
+ if (!scopes.length) return true;
295
+ const roles = _optionalChain([req, 'optionalAccess', _ => _.auth, 'optionalAccess', _2 => _2.token, 'optionalAccess', _3 => _3[roleClaim]]);
296
+ if (!Array.isArray(roles)) return false;
297
+ return scopes.every((scope) => roles.includes(scope));
298
+ }
299
+ };
300
+ };
301
+
223
302
  // src/openapi/index.ts
224
303
  var createOpenApiValidatorOptions = (apiSpec, options) => {
225
304
  return {
226
305
  apiSpec,
227
- validateRequests: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _ => _.validateRequests]), () => ( true)),
228
- validateResponses: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _2 => _2.validateResponses]), () => ( false)),
229
- validateSecurity: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _3 => _3.validateSecurity]), () => ( true)),
230
- validateFormats: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _4 => _4.validateFormats]), () => ( true)),
231
- operationHandlers: _optionalChain([options, 'optionalAccess', _5 => _5.operationHandlers]),
232
- ignorePaths: _optionalChain([options, 'optionalAccess', _6 => _6.ignorePaths]),
233
- validateApiSpec: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _7 => _7.validateApiSpec]), () => ( true)),
234
- $refParser: _optionalChain([options, 'optionalAccess', _8 => _8.$refParser]),
235
- serveSpec: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _9 => _9.serveSpec]), () => ( false)),
236
- fileUploader: _optionalChain([options, 'optionalAccess', _10 => _10.fileUploader]),
237
- initializeHandlers: _optionalChain([options, 'optionalAccess', _11 => _11.initializeHandlers])
306
+ validateRequests: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _4 => _4.validateRequests]), () => ( true)),
307
+ validateResponses: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _5 => _5.validateResponses]), () => ( false)),
308
+ validateSecurity: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _6 => _6.validateSecurity]), () => ( true)),
309
+ validateFormats: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _7 => _7.validateFormats]), () => ( true)),
310
+ operationHandlers: _optionalChain([options, 'optionalAccess', _8 => _8.operationHandlers]),
311
+ ignorePaths: _optionalChain([options, 'optionalAccess', _9 => _9.ignorePaths]),
312
+ validateApiSpec: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _10 => _10.validateApiSpec]), () => ( true)),
313
+ $refParser: _optionalChain([options, 'optionalAccess', _11 => _11.$refParser]),
314
+ serveSpec: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _12 => _12.serveSpec]), () => ( false)),
315
+ fileUploader: _optionalChain([options, 'optionalAccess', _13 => _13.fileUploader]),
316
+ initializeHandlers: _optionalChain([options, 'optionalAccess', _14 => _14.initializeHandlers])
238
317
  };
239
318
  };
240
319
  var isOpenApiValidatorAvailable = async () => {
241
320
  try {
242
321
  await Promise.resolve().then(() => _interopRequireWildcard(require("express-openapi-validator")));
243
322
  return true;
244
- } catch (e2) {
323
+ } catch (e3) {
245
324
  return false;
246
325
  }
247
326
  };
@@ -424,5 +503,6 @@ var ApiSpecification = {
424
503
 
425
504
 
426
505
 
427
- exports.Accepted = Accepted; exports.ApiE2ESpecification = ApiE2ESpecification; exports.ApiSpecification = ApiSpecification; exports.BadRequest = BadRequest; exports.Conflict = Conflict; exports.Created = Created; exports.DefaultHttpProblemResponseOptions = DefaultHttpProblemResponseOptions; exports.DefaultHttpResponseOptions = DefaultHttpResponseOptions; exports.ETagErrors = ETagErrors; exports.Forbidden = Forbidden; exports.HeaderNames = HeaderNames; exports.HttpProblem = HttpProblem; exports.HttpResponse = HttpResponse; exports.NoContent = NoContent; exports.NotFound = NotFound; exports.OK = OK; exports.PreconditionFailed = PreconditionFailed; exports.WeakETagRegex = WeakETagRegex; exports.createOpenApiValidatorOptions = createOpenApiValidatorOptions; exports.existingStream = existingStream; exports.expect = expect; exports.expectError = expectError; exports.expectNewEvents = expectNewEvents; exports.expectResponse = expectResponse; exports.getApplication = getApplication; exports.getETagFromIfMatch = getETagFromIfMatch; exports.getETagFromIfNotMatch = getETagFromIfNotMatch; exports.getETagValueFromIfMatch = getETagValueFromIfMatch; exports.getWeakETagValue = getWeakETagValue; exports.isOpenApiValidatorAvailable = isOpenApiValidatorAvailable; exports.isWeakETag = isWeakETag; exports.on = on; exports.registerHandlerModule = _chunkMRSGTROWcjs.registerHandlerModule; exports.send = send; exports.sendAccepted = sendAccepted; exports.sendCreated = sendCreated; exports.sendProblem = sendProblem; exports.setETag = setETag; exports.startAPI = startAPI; exports.toWeakETag = toWeakETag;
506
+
507
+ exports.Accepted = Accepted; exports.ApiE2ESpecification = ApiE2ESpecification; exports.ApiSpecification = ApiSpecification; exports.BadRequest = BadRequest; exports.Conflict = Conflict; exports.Created = Created; exports.DefaultHttpProblemResponseOptions = DefaultHttpProblemResponseOptions; exports.DefaultHttpResponseOptions = DefaultHttpResponseOptions; exports.ETagErrors = ETagErrors; exports.Forbidden = Forbidden; exports.HeaderNames = HeaderNames; exports.HttpProblem = HttpProblem; exports.HttpResponse = HttpResponse; exports.NoContent = NoContent; exports.NotFound = NotFound; exports.OK = OK; exports.PreconditionFailed = PreconditionFailed; exports.WeakETagRegex = WeakETagRegex; exports.createFirebaseAuthSecurityHandlers = createFirebaseAuthSecurityHandlers; exports.createOpenApiValidatorOptions = createOpenApiValidatorOptions; exports.existingStream = existingStream; exports.expect = expect; exports.expectError = expectError; exports.expectNewEvents = expectNewEvents; exports.expectResponse = expectResponse; exports.getApplication = getApplication; exports.getETagFromIfMatch = getETagFromIfMatch; exports.getETagFromIfNotMatch = getETagFromIfNotMatch; exports.getETagValueFromIfMatch = getETagValueFromIfMatch; exports.getWeakETagValue = getWeakETagValue; exports.isOpenApiValidatorAvailable = isOpenApiValidatorAvailable; exports.isWeakETag = isWeakETag; exports.on = on; exports.registerHandlerModule = _chunkMRSGTROWcjs.registerHandlerModule; exports.send = send; exports.sendAccepted = sendAccepted; exports.sendCreated = sendCreated; exports.sendProblem = sendProblem; exports.setETag = setETag; exports.startAPI = startAPI; exports.toWeakETag = toWeakETag;
428
508
  //# sourceMappingURL=index.cjs.map