@lucaapp/service-utils 5.29.1 → 5.29.2

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.
@@ -225,27 +225,6 @@ const hoistCombinatorRequiredFields = (spec) => {
225
225
  visit(schemas);
226
226
  };
227
227
  exports.hoistCombinatorRequiredFields = hoistCombinatorRequiredFields;
228
- /**
229
- * Turn each middleware's declared schemes into OpenAPI security requirements.
230
- *
231
- * OpenAPI expresses the two relations differently: separate objects in the
232
- * `security` array are alternatives (OR), while several schemes inside one
233
- * object are all required (AND). A middleware's own `security: [a, b]` means
234
- * "a or b" -- it accepts either credential -- but two middlewares on the same
235
- * route both run, so their requirements are combined with AND.
236
- *
237
- * That makes the result the cartesian product across middlewares:
238
- *
239
- * [[a, b], [c]] -> [{a, c}, {b, c}]
240
- *
241
- * A single middleware therefore still renders as plain alternatives, which is
242
- * what it did before, and stacked middlewares no longer render as if presenting
243
- * any one of their credentials were enough.
244
- */
245
- const buildSecurityRequirements = (securityByMiddleware) => securityByMiddleware.reduce((requirements, alternatives) => requirements.flatMap(requirement =>
246
- // Duplicates collapse on their own: the same scheme required twice is
247
- // still one entry in the object.
248
- alternatives.map(scheme => ({ ...requirement, [scheme]: [] }))), [{}]);
249
228
  const registerEndpoint = (registry, method, prefixPath, rootPrefixPath, path, summary,
250
229
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
251
230
  options, tags, debug) => {
@@ -254,11 +233,15 @@ options, tags, debug) => {
254
233
  let querySchema = options.schemas?.query || undefined;
255
234
  let headersSchema = options.schemas?.headers || undefined;
256
235
  let responseSchemas = options.responses;
257
- // One entry per security-declaring middleware, each holding that middleware's
258
- // alternatives. Kept separate because the two levels mean different things:
259
- // within a middleware the schemes are alternatives, across middlewares they
260
- // are all enforced. See buildSecurityRequirements.
261
- const securityByMiddleware = [];
236
+ // Union across middlewares, one scheme per requirement object, which OpenAPI
237
+ // reads as "any one of these". Deliberately not one object holding all of
238
+ // them, which would read as "all of these at once": jwt_operator,
239
+ // jwt_support, jwt_operator_device and jwt_consumer are all apiKey in the
240
+ // same X-Auth header, so requiring two of them is unsatisfiable. Nearly every
241
+ // location-guarded route stacks requireOperatorOROperatorDevice with
242
+ // authorizeLocation(Group), and 5.29.1 documented those 281 routes as needing
243
+ // an operator token and an operator-device token simultaneously.
244
+ const securitySchemes = new Set();
262
245
  if (options.errors) {
263
246
  for (const errorType of Object.keys(options.errors)) {
264
247
  const statusCode = options.errors[errorType];
@@ -319,9 +302,8 @@ options, tags, debug) => {
319
302
  });
320
303
  }
321
304
  }
322
- const middlewareSecurity = middleware.options.security || [];
323
- if (middlewareSecurity.length > 0) {
324
- securityByMiddleware.push([...middlewareSecurity]);
305
+ for (const scheme of middleware.options.security || []) {
306
+ securitySchemes.add(scheme);
325
307
  }
326
308
  }
327
309
  // Add ZodError response
@@ -381,8 +363,8 @@ options, tags, debug) => {
381
363
  responses: responseMap,
382
364
  operationId: options.operationId ||
383
365
  deriveOperationId(registry, method, prefixPath.slice(rootPrefixPath.length) + path),
384
- ...(securityByMiddleware.length > 0 && {
385
- security: buildSecurityRequirements(securityByMiddleware),
366
+ ...(securitySchemes.size > 0 && {
367
+ security: [...securitySchemes].map(scheme => ({ [scheme]: [] })),
386
368
  }),
387
369
  });
388
370
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucaapp/service-utils",
3
- "version": "5.29.1",
3
+ "version": "5.29.2",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [