@nifrajs/middleware 4.0.0 → 5.0.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.
Files changed (81) hide show
  1. package/README.md +3 -0
  2. package/dist/_utils.d.ts +15 -9
  3. package/dist/_utils.d.ts.map +1 -1
  4. package/dist/_utils.js +39 -40
  5. package/dist/_utils.js.map +1 -1
  6. package/dist/basic-auth.d.ts.map +1 -1
  7. package/dist/basic-auth.js +8 -13
  8. package/dist/basic-auth.js.map +1 -1
  9. package/dist/cache-control.d.ts.map +1 -1
  10. package/dist/cache-control.js +4 -2
  11. package/dist/cache-control.js.map +1 -1
  12. package/dist/cache.d.ts +7 -4
  13. package/dist/cache.d.ts.map +1 -1
  14. package/dist/cache.js +58 -25
  15. package/dist/cache.js.map +1 -1
  16. package/dist/compression.d.ts.map +1 -1
  17. package/dist/compression.js +58 -1
  18. package/dist/compression.js.map +1 -1
  19. package/dist/conditional.d.ts.map +1 -1
  20. package/dist/conditional.js +1 -1
  21. package/dist/conditional.js.map +1 -1
  22. package/dist/content-negotiation.d.ts.map +1 -1
  23. package/dist/content-negotiation.js +3 -1
  24. package/dist/content-negotiation.js.map +1 -1
  25. package/dist/csrf.d.ts.map +1 -1
  26. package/dist/csrf.js +10 -5
  27. package/dist/csrf.js.map +1 -1
  28. package/dist/healthcheck.d.ts.map +1 -1
  29. package/dist/healthcheck.js +3 -1
  30. package/dist/healthcheck.js.map +1 -1
  31. package/dist/idempotency.d.ts +10 -2
  32. package/dist/idempotency.d.ts.map +1 -1
  33. package/dist/idempotency.js +8 -4
  34. package/dist/idempotency.js.map +1 -1
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +1 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/jwt.d.ts +10 -2
  40. package/dist/jwt.d.ts.map +1 -1
  41. package/dist/jwt.js +52 -31
  42. package/dist/jwt.js.map +1 -1
  43. package/dist/language.d.ts.map +1 -1
  44. package/dist/language.js +12 -0
  45. package/dist/language.js.map +1 -1
  46. package/dist/openapi.d.ts +3 -0
  47. package/dist/openapi.d.ts.map +1 -1
  48. package/dist/openapi.js +4 -1
  49. package/dist/openapi.js.map +1 -1
  50. package/dist/rate-limit.d.ts +31 -0
  51. package/dist/rate-limit.d.ts.map +1 -1
  52. package/dist/rate-limit.js +160 -26
  53. package/dist/rate-limit.js.map +1 -1
  54. package/dist/request-id.d.ts.map +1 -1
  55. package/dist/request-id.js +1 -1
  56. package/dist/request-id.js.map +1 -1
  57. package/dist/timing.d.ts.map +1 -1
  58. package/dist/timing.js +1 -1
  59. package/dist/timing.js.map +1 -1
  60. package/dist/token-auth.d.ts.map +1 -1
  61. package/dist/token-auth.js +8 -13
  62. package/dist/token-auth.js.map +1 -1
  63. package/package.json +3 -3
  64. package/src/_utils.ts +61 -35
  65. package/src/basic-auth.ts +15 -13
  66. package/src/cache-control.ts +5 -2
  67. package/src/cache.ts +68 -28
  68. package/src/compression.ts +84 -4
  69. package/src/conditional.ts +8 -4
  70. package/src/content-negotiation.ts +3 -1
  71. package/src/csrf.ts +10 -6
  72. package/src/healthcheck.ts +4 -1
  73. package/src/idempotency.ts +30 -7
  74. package/src/index.ts +3 -0
  75. package/src/jwt.ts +76 -34
  76. package/src/language.ts +11 -0
  77. package/src/openapi.ts +13 -2
  78. package/src/rate-limit.ts +233 -41
  79. package/src/request-id.ts +7 -3
  80. package/src/timing.ts +8 -4
  81. package/src/token-auth.ts +18 -16
package/src/token-auth.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { NIFRA_ASSURANCE, withRouteAssurance } from "@nifrajs/core/assurance"
2
2
  import { defineIdentityPlugin, type IdentityPlugin } from "@nifrajs/core/server"
3
- import { bearerToken, guardName } from "./_utils.ts"
3
+ import { bearerToken, guardName, type HeaderGet, installAuthGuard } from "./_utils.ts"
4
4
 
5
5
  type MaybePromise<T> = T | Promise<T>
6
6
 
@@ -29,8 +29,8 @@ export type AuthPlugin<P> = IdentityPlugin & {
29
29
 
30
30
  interface TokenAuthConfig<P> {
31
31
  readonly name: string
32
- /** Pull the credential out of the request (e.g. the `Bearer` token or an `x-api-key` header). */
33
- readonly extract: (request: Request) => string | undefined
32
+ /** Pull the credential out of the request's headers (the `Bearer` token, an `x-api-key`). */
33
+ readonly extract: (header: HeaderGet) => string | undefined
34
34
  /** Verify the credential → a principal (truthy) or `null`/`undefined` (rejected). */
35
35
  readonly verify: (token: string) => MaybePromise<P | null | undefined>
36
36
  readonly optional: boolean
@@ -39,7 +39,7 @@ interface TokenAuthConfig<P> {
39
39
  }
40
40
 
41
41
  function createTokenAuth<P>(config: TokenAuthConfig<P>): AuthPlugin<P> {
42
- // Per-request principal cache: verify runs once (in beforeHandle), reads are free + can't desync.
42
+ // Per-request principal cache: verify runs once, in the guard; reads are free and can't desync.
43
43
  const store = new WeakMap<Request, P>()
44
44
  const reject = (): Response =>
45
45
  Response.json(
@@ -50,16 +50,18 @@ function createTokenAuth<P>(config: TokenAuthConfig<P>): AuthPlugin<P> {
50
50
  },
51
51
  )
52
52
  const plugin = defineIdentityPlugin(guardName(config.name), (app) =>
53
- app.beforeHandle(async (c: { readonly req: Request }) => {
54
- const token = config.extract(c.req)
55
- // Empty string is treated as "no credential" - never passed to verify.
56
- const principal = token !== undefined && token !== "" ? await config.verify(token) : null
57
- if (principal !== null && principal !== undefined) {
58
- store.set(c.req, principal)
59
- return undefined // authorized - continue to the handler
60
- }
61
- return config.optional ? undefined : reject() // 401 short-circuits (skips the handler)
62
- }),
53
+ installAuthGuard(
54
+ app,
55
+ config.name,
56
+ config.optional,
57
+ store,
58
+ (header) => {
59
+ const token = config.extract(header)
60
+ // Empty string is treated as "no credential" - never passed to verify.
61
+ return token !== undefined && token !== "" ? config.verify(token) : null
62
+ },
63
+ reject,
64
+ ),
63
65
  )
64
66
  const instrumented = config.optional
65
67
  ? plugin
@@ -97,7 +99,7 @@ export function bearer<P>(options: BearerOptions<P>): AuthPlugin<P> {
97
99
  const realm = options.realm ?? "api"
98
100
  return createTokenAuth({
99
101
  name: "bearer",
100
- extract: (request) => bearerToken(request.headers.get("authorization")) ?? undefined,
102
+ extract: (header) => bearerToken(header("authorization")) ?? undefined,
101
103
  verify: options.verify,
102
104
  optional: options.optional === true,
103
105
  challenge: `Bearer realm="${realm}"`,
@@ -171,7 +173,7 @@ export function apiKey<P>(
171
173
  const verify = "keys" in options ? staticKeyVerify(options.keys) : options.verify
172
174
  return createTokenAuth<P | string>({
173
175
  name: "apiKey",
174
- extract: (request) => request.headers.get(header) ?? undefined,
176
+ extract: (get) => get(header) ?? undefined,
175
177
  verify,
176
178
  optional: options.optional === true,
177
179
  })