@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.
- package/LICENSE +21 -0
- package/README.md +79 -0
- package/dist/_utils.d.ts +27 -0
- package/dist/_utils.d.ts.map +1 -0
- package/dist/_utils.js +141 -0
- package/dist/_utils.js.map +1 -0
- package/dist/basic-auth.d.ts +27 -0
- package/dist/basic-auth.d.ts.map +1 -0
- package/dist/basic-auth.js +64 -0
- package/dist/basic-auth.js.map +1 -0
- package/dist/body-limit.d.ts +19 -0
- package/dist/body-limit.d.ts.map +1 -0
- package/dist/body-limit.js +42 -0
- package/dist/body-limit.js.map +1 -0
- package/dist/cache-control.d.ts +23 -0
- package/dist/cache-control.d.ts.map +1 -0
- package/dist/cache-control.js +35 -0
- package/dist/cache-control.js.map +1 -0
- package/dist/cache.d.ts +60 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +224 -0
- package/dist/cache.js.map +1 -0
- package/dist/combine.d.ts +7 -0
- package/dist/combine.d.ts.map +1 -0
- package/dist/combine.js +21 -0
- package/dist/combine.js.map +1 -0
- package/dist/compression.d.ts +29 -0
- package/dist/compression.d.ts.map +1 -0
- package/dist/compression.js +105 -0
- package/dist/compression.js.map +1 -0
- package/dist/context-storage.d.ts +14 -0
- package/dist/context-storage.d.ts.map +1 -0
- package/dist/context-storage.js +30 -0
- package/dist/context-storage.js.map +1 -0
- package/dist/cors.d.ts +25 -0
- package/dist/cors.d.ts.map +1 -0
- package/dist/cors.js +75 -0
- package/dist/cors.js.map +1 -0
- package/dist/csrf.d.ts +23 -0
- package/dist/csrf.d.ts.map +1 -0
- package/dist/csrf.js +68 -0
- package/dist/csrf.js.map +1 -0
- package/dist/etag.d.ts +14 -0
- package/dist/etag.d.ts.map +1 -0
- package/dist/etag.js +95 -0
- package/dist/etag.js.map +1 -0
- package/dist/healthcheck.d.ts +25 -0
- package/dist/healthcheck.d.ts.map +1 -0
- package/dist/healthcheck.js +41 -0
- package/dist/healthcheck.js.map +1 -0
- package/dist/idempotency.d.ts +83 -0
- package/dist/idempotency.d.ts.map +1 -0
- package/dist/idempotency.js +217 -0
- package/dist/idempotency.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/ip-restriction.d.ts +21 -0
- package/dist/ip-restriction.d.ts.map +1 -0
- package/dist/ip-restriction.js +161 -0
- package/dist/ip-restriction.js.map +1 -0
- package/dist/jwt.d.ts +82 -0
- package/dist/jwt.d.ts.map +1 -0
- package/dist/jwt.js +327 -0
- package/dist/jwt.js.map +1 -0
- package/dist/language.d.ts +20 -0
- package/dist/language.d.ts.map +1 -0
- package/dist/language.js +94 -0
- package/dist/language.js.map +1 -0
- package/dist/logger.d.ts +19 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +28 -0
- package/dist/logger.js.map +1 -0
- package/dist/method-override.d.ts +28 -0
- package/dist/method-override.d.ts.map +1 -0
- package/dist/method-override.js +67 -0
- package/dist/method-override.js.map +1 -0
- package/dist/openapi.d.ts +83 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +100 -0
- package/dist/openapi.js.map +1 -0
- package/dist/powered-by.d.ts +15 -0
- package/dist/powered-by.d.ts.map +1 -0
- package/dist/powered-by.js +23 -0
- package/dist/powered-by.js.map +1 -0
- package/dist/pretty-json.d.ts +18 -0
- package/dist/pretty-json.d.ts.map +1 -0
- package/dist/pretty-json.js +88 -0
- package/dist/pretty-json.js.map +1 -0
- package/dist/rate-limit.d.ts +92 -0
- package/dist/rate-limit.d.ts.map +1 -0
- package/dist/rate-limit.js +172 -0
- package/dist/rate-limit.js.map +1 -0
- package/dist/request-id.d.ts +18 -0
- package/dist/request-id.d.ts.map +1 -0
- package/dist/request-id.js +21 -0
- package/dist/request-id.js.map +1 -0
- package/dist/security-headers.d.ts +23 -0
- package/dist/security-headers.d.ts.map +1 -0
- package/dist/security-headers.js +36 -0
- package/dist/security-headers.js.map +1 -0
- package/dist/timing.d.ts +25 -0
- package/dist/timing.d.ts.map +1 -0
- package/dist/timing.js +101 -0
- package/dist/timing.js.map +1 -0
- package/dist/token-auth.d.ts +65 -0
- package/dist/token-auth.d.ts.map +1 -0
- package/dist/token-auth.js +90 -0
- package/dist/token-auth.js.map +1 -0
- package/dist/trailing-slash.d.ts +23 -0
- package/dist/trailing-slash.d.ts.map +1 -0
- package/dist/trailing-slash.js +70 -0
- package/dist/trailing-slash.js.map +1 -0
- package/package.json +68 -0
- package/src/_utils.ts +163 -0
- package/src/basic-auth.ts +109 -0
- package/src/body-limit.ts +53 -0
- package/src/cache-control.ts +45 -0
- package/src/cache.ts +277 -0
- package/src/combine.ts +24 -0
- package/src/compression.ts +111 -0
- package/src/context-storage.ts +36 -0
- package/src/cors.ts +90 -0
- package/src/csrf.ts +102 -0
- package/src/etag.ts +99 -0
- package/src/healthcheck.ts +59 -0
- package/src/idempotency.ts +313 -0
- package/src/index.ts +110 -0
- package/src/ip-restriction.ts +187 -0
- package/src/jwt.ts +441 -0
- package/src/language.ts +109 -0
- package/src/logger.ts +44 -0
- package/src/method-override.ts +87 -0
- package/src/openapi.ts +174 -0
- package/src/powered-by.ts +31 -0
- package/src/pretty-json.ts +97 -0
- package/src/rate-limit.ts +248 -0
- package/src/request-id.ts +30 -0
- package/src/security-headers.ts +51 -0
- package/src/timing.ts +133 -0
- package/src/token-auth.ts +172 -0
- 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
|
+
}
|