@nifrajs/middleware 0.1.0-alpha.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.
Files changed (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +79 -0
  3. package/dist/_utils.d.ts +27 -0
  4. package/dist/_utils.d.ts.map +1 -0
  5. package/dist/_utils.js +141 -0
  6. package/dist/_utils.js.map +1 -0
  7. package/dist/basic-auth.d.ts +27 -0
  8. package/dist/basic-auth.d.ts.map +1 -0
  9. package/dist/basic-auth.js +64 -0
  10. package/dist/basic-auth.js.map +1 -0
  11. package/dist/body-limit.d.ts +19 -0
  12. package/dist/body-limit.d.ts.map +1 -0
  13. package/dist/body-limit.js +42 -0
  14. package/dist/body-limit.js.map +1 -0
  15. package/dist/cache-control.d.ts +23 -0
  16. package/dist/cache-control.d.ts.map +1 -0
  17. package/dist/cache-control.js +35 -0
  18. package/dist/cache-control.js.map +1 -0
  19. package/dist/cache.d.ts +60 -0
  20. package/dist/cache.d.ts.map +1 -0
  21. package/dist/cache.js +224 -0
  22. package/dist/cache.js.map +1 -0
  23. package/dist/combine.d.ts +7 -0
  24. package/dist/combine.d.ts.map +1 -0
  25. package/dist/combine.js +21 -0
  26. package/dist/combine.js.map +1 -0
  27. package/dist/compression.d.ts +29 -0
  28. package/dist/compression.d.ts.map +1 -0
  29. package/dist/compression.js +105 -0
  30. package/dist/compression.js.map +1 -0
  31. package/dist/context-storage.d.ts +14 -0
  32. package/dist/context-storage.d.ts.map +1 -0
  33. package/dist/context-storage.js +30 -0
  34. package/dist/context-storage.js.map +1 -0
  35. package/dist/cors.d.ts +25 -0
  36. package/dist/cors.d.ts.map +1 -0
  37. package/dist/cors.js +75 -0
  38. package/dist/cors.js.map +1 -0
  39. package/dist/csrf.d.ts +23 -0
  40. package/dist/csrf.d.ts.map +1 -0
  41. package/dist/csrf.js +68 -0
  42. package/dist/csrf.js.map +1 -0
  43. package/dist/etag.d.ts +14 -0
  44. package/dist/etag.d.ts.map +1 -0
  45. package/dist/etag.js +95 -0
  46. package/dist/etag.js.map +1 -0
  47. package/dist/healthcheck.d.ts +25 -0
  48. package/dist/healthcheck.d.ts.map +1 -0
  49. package/dist/healthcheck.js +41 -0
  50. package/dist/healthcheck.js.map +1 -0
  51. package/dist/idempotency.d.ts +83 -0
  52. package/dist/idempotency.d.ts.map +1 -0
  53. package/dist/idempotency.js +217 -0
  54. package/dist/idempotency.js.map +1 -0
  55. package/dist/index.d.ts +33 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +33 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/ip-restriction.d.ts +21 -0
  60. package/dist/ip-restriction.d.ts.map +1 -0
  61. package/dist/ip-restriction.js +161 -0
  62. package/dist/ip-restriction.js.map +1 -0
  63. package/dist/jwt.d.ts +82 -0
  64. package/dist/jwt.d.ts.map +1 -0
  65. package/dist/jwt.js +327 -0
  66. package/dist/jwt.js.map +1 -0
  67. package/dist/language.d.ts +20 -0
  68. package/dist/language.d.ts.map +1 -0
  69. package/dist/language.js +94 -0
  70. package/dist/language.js.map +1 -0
  71. package/dist/logger.d.ts +19 -0
  72. package/dist/logger.d.ts.map +1 -0
  73. package/dist/logger.js +28 -0
  74. package/dist/logger.js.map +1 -0
  75. package/dist/method-override.d.ts +28 -0
  76. package/dist/method-override.d.ts.map +1 -0
  77. package/dist/method-override.js +67 -0
  78. package/dist/method-override.js.map +1 -0
  79. package/dist/openapi.d.ts +83 -0
  80. package/dist/openapi.d.ts.map +1 -0
  81. package/dist/openapi.js +100 -0
  82. package/dist/openapi.js.map +1 -0
  83. package/dist/powered-by.d.ts +15 -0
  84. package/dist/powered-by.d.ts.map +1 -0
  85. package/dist/powered-by.js +23 -0
  86. package/dist/powered-by.js.map +1 -0
  87. package/dist/pretty-json.d.ts +18 -0
  88. package/dist/pretty-json.d.ts.map +1 -0
  89. package/dist/pretty-json.js +88 -0
  90. package/dist/pretty-json.js.map +1 -0
  91. package/dist/rate-limit.d.ts +92 -0
  92. package/dist/rate-limit.d.ts.map +1 -0
  93. package/dist/rate-limit.js +172 -0
  94. package/dist/rate-limit.js.map +1 -0
  95. package/dist/request-id.d.ts +18 -0
  96. package/dist/request-id.d.ts.map +1 -0
  97. package/dist/request-id.js +21 -0
  98. package/dist/request-id.js.map +1 -0
  99. package/dist/security-headers.d.ts +23 -0
  100. package/dist/security-headers.d.ts.map +1 -0
  101. package/dist/security-headers.js +36 -0
  102. package/dist/security-headers.js.map +1 -0
  103. package/dist/timing.d.ts +25 -0
  104. package/dist/timing.d.ts.map +1 -0
  105. package/dist/timing.js +101 -0
  106. package/dist/timing.js.map +1 -0
  107. package/dist/token-auth.d.ts +65 -0
  108. package/dist/token-auth.d.ts.map +1 -0
  109. package/dist/token-auth.js +90 -0
  110. package/dist/token-auth.js.map +1 -0
  111. package/dist/trailing-slash.d.ts +23 -0
  112. package/dist/trailing-slash.d.ts.map +1 -0
  113. package/dist/trailing-slash.js +70 -0
  114. package/dist/trailing-slash.js.map +1 -0
  115. package/package.json +68 -0
  116. package/src/_utils.ts +163 -0
  117. package/src/basic-auth.ts +109 -0
  118. package/src/body-limit.ts +53 -0
  119. package/src/cache-control.ts +45 -0
  120. package/src/cache.ts +277 -0
  121. package/src/combine.ts +24 -0
  122. package/src/compression.ts +111 -0
  123. package/src/context-storage.ts +36 -0
  124. package/src/cors.ts +90 -0
  125. package/src/csrf.ts +102 -0
  126. package/src/etag.ts +99 -0
  127. package/src/healthcheck.ts +59 -0
  128. package/src/idempotency.ts +313 -0
  129. package/src/index.ts +110 -0
  130. package/src/ip-restriction.ts +187 -0
  131. package/src/jwt.ts +441 -0
  132. package/src/language.ts +109 -0
  133. package/src/logger.ts +44 -0
  134. package/src/method-override.ts +87 -0
  135. package/src/openapi.ts +174 -0
  136. package/src/powered-by.ts +31 -0
  137. package/src/pretty-json.ts +97 -0
  138. package/src/rate-limit.ts +248 -0
  139. package/src/request-id.ts +30 -0
  140. package/src/security-headers.ts +51 -0
  141. package/src/timing.ts +133 -0
  142. package/src/token-auth.ts +172 -0
  143. package/src/trailing-slash.ts +94 -0
@@ -0,0 +1,94 @@
1
+ import { definePlugin } from "@nifrajs/core"
2
+
3
+ export interface TrailingSlashOptions {
4
+ /** Redirect (default) or route internally with a rewritten URL. */
5
+ readonly mode?: "redirect" | "rewrite"
6
+ /** Redirect status. Default `308` (method-preserving permanent redirect). */
7
+ readonly status?: 301 | 302 | 307 | 308
8
+ /** Methods affected. Default `["GET", "HEAD"]`; add write methods only when you want 308 redirects. */
9
+ readonly methods?: readonly string[]
10
+ /** Skip paths whose last segment looks like a file (`/app.css`). Default `true` for append mode. */
11
+ readonly ignoreFileExtensions?: boolean
12
+ /** App-specific skip predicate. */
13
+ readonly ignore?: (path: string, request: Request) => boolean
14
+ }
15
+
16
+ const DEFAULT_METHODS = ["GET", "HEAD"] as const
17
+ const REDIRECT_STATUSES = new Set([301, 302, 307, 308])
18
+
19
+ function validateStatus(status: number): asserts status is 301 | 302 | 307 | 308 {
20
+ if (!REDIRECT_STATUSES.has(status)) {
21
+ throw new Error("trailingSlash: status must be 301, 302, 307, or 308")
22
+ }
23
+ }
24
+
25
+ function hasFileExtension(path: string): boolean {
26
+ const slash = path.lastIndexOf("/")
27
+ const segment = path.slice(slash + 1)
28
+ return segment.includes(".")
29
+ }
30
+
31
+ function withPath(req: Request, path: string): URL {
32
+ const url = new URL(req.url)
33
+ url.pathname = path
34
+ return url
35
+ }
36
+
37
+ function route(
38
+ req: Request,
39
+ url: URL,
40
+ mode: "redirect" | "rewrite",
41
+ status: 301 | 302 | 307 | 308,
42
+ ) {
43
+ return mode === "rewrite"
44
+ ? new Request(url.toString(), req)
45
+ : new Response(null, { status, headers: { location: url.toString() } })
46
+ }
47
+
48
+ function methodsOf(methods: readonly string[] | undefined): ReadonlySet<string> {
49
+ return new Set((methods ?? DEFAULT_METHODS).map((m) => m.toUpperCase()))
50
+ }
51
+
52
+ /**
53
+ * Remove trailing slashes from non-root paths. Redirect mode is the production default because it
54
+ * canonicalizes URLs for clients and caches; rewrite mode is available for compatibility migrations.
55
+ */
56
+ export function trimTrailingSlash(options: TrailingSlashOptions = {}) {
57
+ const mode = options.mode ?? "redirect"
58
+ const status = options.status ?? 308
59
+ validateStatus(status)
60
+ const methods = methodsOf(options.methods)
61
+
62
+ return definePlugin("trimTrailingSlash", (app) =>
63
+ app.onRequest((req) => {
64
+ if (!methods.has(req.method.toUpperCase())) return undefined
65
+ const path = new URL(req.url).pathname
66
+ if (path === "/" || !path.endsWith("/")) return undefined
67
+ if (options.ignore?.(path, req) === true) return undefined
68
+ return route(req, withPath(req, path.replace(/\/+$/, "") || "/"), mode, status)
69
+ }),
70
+ )
71
+ }
72
+
73
+ /**
74
+ * Append a trailing slash to non-root paths. By default it skips file-looking paths such as
75
+ * `/app.css`, which keeps static assets and extensionful API routes stable.
76
+ */
77
+ export function appendTrailingSlash(options: TrailingSlashOptions = {}) {
78
+ const mode = options.mode ?? "redirect"
79
+ const status = options.status ?? 308
80
+ const ignoreFileExtensions = options.ignoreFileExtensions !== false
81
+ validateStatus(status)
82
+ const methods = methodsOf(options.methods)
83
+
84
+ return definePlugin("appendTrailingSlash", (app) =>
85
+ app.onRequest((req) => {
86
+ if (!methods.has(req.method.toUpperCase())) return undefined
87
+ const path = new URL(req.url).pathname
88
+ if (path === "/" || path.endsWith("/")) return undefined
89
+ if (ignoreFileExtensions && hasFileExtension(path)) return undefined
90
+ if (options.ignore?.(path, req) === true) return undefined
91
+ return route(req, withPath(req, `${path}/`), mode, status)
92
+ }),
93
+ )
94
+ }