@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
package/dist/cache.js ADDED
@@ -0,0 +1,224 @@
1
+ export class MemoryResponseCache {
2
+ entries = new Map();
3
+ maxEntries;
4
+ constructor(options = {}) {
5
+ const env = globalThis.process?.env?.NODE_ENV;
6
+ if (options.allowInProduction !== true && env === "production") {
7
+ throw new Error("MemoryResponseCache is per-instance and unsafe in production. Use a shared cache store, " +
8
+ "or pass { allowInProduction: true } for a single-instance deploy.");
9
+ }
10
+ this.maxEntries = options.maxEntries ?? 1000;
11
+ if (!Number.isInteger(this.maxEntries) || this.maxEntries < 1) {
12
+ throw new Error("MemoryResponseCache: maxEntries must be a positive integer");
13
+ }
14
+ }
15
+ get(key) {
16
+ const entry = this.entries.get(key);
17
+ if (entry === undefined)
18
+ return undefined;
19
+ if (Date.now() >= entry.expiresAt) {
20
+ this.entries.delete(key);
21
+ return undefined;
22
+ }
23
+ return entry;
24
+ }
25
+ set(key, response) {
26
+ if (!this.entries.has(key) && this.entries.size >= this.maxEntries) {
27
+ const oldest = this.entries.keys().next().value;
28
+ if (oldest !== undefined)
29
+ this.entries.delete(oldest);
30
+ }
31
+ this.entries.set(key, response);
32
+ }
33
+ delete(key) {
34
+ this.entries.delete(key);
35
+ }
36
+ }
37
+ function parseLength(value) {
38
+ if (value === null)
39
+ return undefined;
40
+ if (!/^(?:0|[1-9]\d*)$/.test(value))
41
+ return undefined;
42
+ return Number(value);
43
+ }
44
+ function cacheControlHas(headers, names) {
45
+ const value = headers.get("cache-control");
46
+ if (value === null)
47
+ return false;
48
+ const parts = value
49
+ .toLowerCase()
50
+ .split(",")
51
+ .map((part) => part.trim().split("=", 1)[0]);
52
+ return names.some((name) => parts.includes(name));
53
+ }
54
+ function appendVary(headers, vary) {
55
+ if (vary.length === 0)
56
+ return;
57
+ const existing = headers
58
+ .get("vary")
59
+ ?.split(",")
60
+ .map((v) => v.trim().toLowerCase());
61
+ const seen = new Set(existing ?? []);
62
+ const additions = [];
63
+ for (const header of vary) {
64
+ const normalized = header.toLowerCase();
65
+ if (!seen.has(normalized)) {
66
+ seen.add(normalized);
67
+ additions.push(header);
68
+ }
69
+ }
70
+ if (additions.length === 0)
71
+ return;
72
+ const current = headers.get("vary");
73
+ headers.set("vary", current === null ? additions.join(", ") : `${current}, ${additions.join(", ")}`);
74
+ }
75
+ function defaultKey(req, vary) {
76
+ let key = `${req.method.toUpperCase()} ${req.url}`;
77
+ for (const header of vary)
78
+ key += `\n${header.toLowerCase()}:${req.headers.get(header) ?? ""}`;
79
+ return key;
80
+ }
81
+ async function readBytesCapped(res, maxBytes) {
82
+ const body = res.clone().body;
83
+ if (body === null)
84
+ return new Uint8Array();
85
+ const reader = body.getReader();
86
+ const chunks = [];
87
+ let total = 0;
88
+ try {
89
+ while (true) {
90
+ const { done, value } = await reader.read();
91
+ if (done) {
92
+ const out = new Uint8Array(total);
93
+ let offset = 0;
94
+ for (const chunk of chunks) {
95
+ out.set(chunk, offset);
96
+ offset += chunk.byteLength;
97
+ }
98
+ return out;
99
+ }
100
+ total += value.byteLength;
101
+ if (total > maxBytes) {
102
+ await reader.cancel();
103
+ return null;
104
+ }
105
+ chunks.push(value);
106
+ }
107
+ }
108
+ catch {
109
+ return null;
110
+ }
111
+ }
112
+ function withStatusHeader(res, header, status) {
113
+ if (header === false)
114
+ return res;
115
+ const headers = new Headers(res.headers);
116
+ headers.set(header, status);
117
+ return new Response(res.body, { status: res.status, statusText: res.statusText, headers });
118
+ }
119
+ /**
120
+ * Full response cache for small, cacheable responses. Use a shared `store` in production. The
121
+ * middleware honors `Cache-Control` by default, avoids `Set-Cookie`, caps stored bytes, emits `Age`,
122
+ * and keeps `Vary` headers aligned with the cache key.
123
+ */
124
+ export function cache(options) {
125
+ const { store } = options;
126
+ const ttlMs = options.ttlMs;
127
+ if (!Number.isInteger(ttlMs) || ttlMs < 1)
128
+ throw new Error("cache: ttlMs must be a positive integer");
129
+ const methods = new Set((options.methods ?? ["GET", "HEAD"]).map((m) => m.toUpperCase()));
130
+ const statusOk = options.status ?? ((status) => status === 200);
131
+ const vary = options.vary ?? [];
132
+ const keyOf = options.key ?? ((req) => defaultKey(req, vary));
133
+ const maxBytes = options.maxBytes ?? 1_000_000;
134
+ if (!Number.isInteger(maxBytes) || maxBytes < 0) {
135
+ throw new Error("cache: maxBytes must be a non-negative integer");
136
+ }
137
+ const respectRequestCacheControl = options.respectRequestCacheControl !== false;
138
+ const respectResponseCacheControl = options.respectResponseCacheControl !== false;
139
+ const cacheSetCookie = options.cacheSetCookie === true;
140
+ const cacheStatusHeader = options.cacheStatusHeader === undefined ? "x-nifra-cache" : options.cacheStatusHeader;
141
+ if (cacheStatusHeader !== false && cacheStatusHeader.trim() === "") {
142
+ throw new Error("cache: cacheStatusHeader is empty");
143
+ }
144
+ const hits = new WeakSet();
145
+ return {
146
+ name: "cache",
147
+ async onRequest(req) {
148
+ if (!methods.has(req.method.toUpperCase()))
149
+ return undefined;
150
+ if (respectRequestCacheControl && cacheControlHas(req.headers, ["no-cache", "no-store"])) {
151
+ return undefined;
152
+ }
153
+ const key = keyOf(req);
154
+ const entry = await store.get(key);
155
+ if (entry === undefined)
156
+ return undefined;
157
+ if (Date.now() >= entry.expiresAt) {
158
+ await store.delete?.(key);
159
+ return undefined;
160
+ }
161
+ hits.add(req);
162
+ const headers = new Headers([...entry.headers]);
163
+ headers.set("age", String(Math.max(0, Math.floor((Date.now() - entry.storedAt) / 1000))));
164
+ if (cacheStatusHeader !== false)
165
+ headers.set(cacheStatusHeader, "HIT");
166
+ return new Response(req.method === "HEAD" ? null : entry.body.slice(), {
167
+ status: entry.status,
168
+ statusText: entry.statusText,
169
+ headers,
170
+ });
171
+ },
172
+ async onResponse(res, req) {
173
+ if (hits.has(req)) {
174
+ hits.delete(req);
175
+ return res;
176
+ }
177
+ if (!methods.has(req.method.toUpperCase()))
178
+ return res;
179
+ if (!statusOk(res.status))
180
+ return res;
181
+ if (respectRequestCacheControl && cacheControlHas(req.headers, ["no-store"])) {
182
+ return withStatusHeader(res, cacheStatusHeader, "BYPASS");
183
+ }
184
+ if (respectResponseCacheControl && cacheControlHas(res.headers, ["private", "no-store"])) {
185
+ return withStatusHeader(res, cacheStatusHeader, "BYPASS");
186
+ }
187
+ if (!cacheSetCookie && res.headers.has("set-cookie")) {
188
+ return withStatusHeader(res, cacheStatusHeader, "BYPASS");
189
+ }
190
+ const declared = parseLength(res.headers.get("content-length"));
191
+ if (declared !== undefined && declared > maxBytes) {
192
+ return withStatusHeader(res, cacheStatusHeader, "BYPASS");
193
+ }
194
+ const body = await readBytesCapped(res, maxBytes);
195
+ if (body === null)
196
+ return withStatusHeader(res, cacheStatusHeader, "BYPASS");
197
+ const headers = new Headers(res.headers);
198
+ headers.delete("age");
199
+ if (cacheStatusHeader !== false)
200
+ headers.delete(cacheStatusHeader);
201
+ appendVary(headers, vary);
202
+ const now = Date.now();
203
+ await store.set(keyOf(req), {
204
+ status: res.status,
205
+ statusText: res.statusText,
206
+ headers: [...headers.entries()],
207
+ body,
208
+ expiresAt: now + ttlMs,
209
+ storedAt: now,
210
+ });
211
+ const outgoing = new Headers(res.headers);
212
+ appendVary(outgoing, vary);
213
+ if (cacheStatusHeader !== false)
214
+ outgoing.set(cacheStatusHeader, "MISS");
215
+ return new Response(res.body, {
216
+ status: res.status,
217
+ statusText: res.statusText,
218
+ headers: outgoing,
219
+ });
220
+ },
221
+ };
222
+ }
223
+ export const responseCache = cache;
224
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { type Middleware, type NifraPlugin } from "@nifrajs/core";
2
+ export type Composable = Middleware | NifraPlugin;
3
+ /** Compose middleware/plugins into one reusable bundle. Individual named plugins still dedupe. */
4
+ export declare function combine(...items: readonly Composable[]): NifraPlugin;
5
+ /** Compose middleware/plugins into one idempotent named bundle. */
6
+ export declare function namedCombine(name: string, ...items: readonly Composable[]): NifraPlugin;
7
+ //# sourceMappingURL=combine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"combine.d.ts","sourceRoot":"","sources":["../src/combine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAA;AAE/E,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,WAAW,CAAA;AAYjD,kGAAkG;AAClG,wBAAgB,OAAO,CAAC,GAAG,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,WAAW,CAEpE;AAED,mEAAmE;AACnE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,WAAW,CAGvF"}
@@ -0,0 +1,21 @@
1
+ import { definePlugin } from "@nifrajs/core";
2
+ function applyAll(app, items) {
3
+ let current = app;
4
+ for (const item of items) {
5
+ // The public `use` overload accepts both shapes; this helper intentionally preserves runtime
6
+ // composition while leaving advanced context type threading to direct `.use(...)` chains.
7
+ current = current.use(item);
8
+ }
9
+ return current;
10
+ }
11
+ /** Compose middleware/plugins into one reusable bundle. Individual named plugins still dedupe. */
12
+ export function combine(...items) {
13
+ return ((app) => applyAll(app, items));
14
+ }
15
+ /** Compose middleware/plugins into one idempotent named bundle. */
16
+ export function namedCombine(name, ...items) {
17
+ if (name.trim() === "")
18
+ throw new Error("namedCombine: name is empty");
19
+ return definePlugin(name, (app) => applyAll(app, items));
20
+ }
21
+ //# sourceMappingURL=combine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"combine.js","sourceRoot":"","sources":["../src/combine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAqC,MAAM,eAAe,CAAA;AAI/E,SAAS,QAAQ,CAAC,GAA+B,EAAE,KAA4B;IAC7E,IAAI,OAAO,GAAG,GAAG,CAAA;IACjB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,6FAA6F;QAC7F,0FAA0F;QAC1F,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,IAAa,CAAC,CAAA;IACtC,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,OAAO,CAAC,GAAG,KAA4B;IACrD,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,CAAgB,CAAA;AACvD,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,GAAG,KAA4B;IACxE,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAA;IACtE,OAAO,YAAY,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAA;AAC1D,CAAC"}
@@ -0,0 +1,29 @@
1
+ export interface CompressionOptions {
2
+ /** Don't compress bodies smaller than this many bytes. Default `1024`. Enforced by peeking the body
3
+ * (see below) since runtimes rarely expose `Content-Length` on a constructed `Response`. */
4
+ readonly threshold?: number;
5
+ /** Decide whether a `Content-Type` is worth compressing. Default: text, JSON/+json, JS, XML/+xml,
6
+ * NDJSON, wasm, SVG. Already-compressed media (images, video, archives) is skipped. */
7
+ readonly compressible?: (contentType: string) => boolean;
8
+ }
9
+ /**
10
+ * Transparently **gzip** responses when the client sends `Accept-Encoding: gzip` and the body is a
11
+ * compressible type larger than `threshold`. Uses the Web-standard `CompressionStream` (streaming, no
12
+ * full-body buffering), so it runs on every nifra runtime including the edge. gzip is the one encoding
13
+ * `CompressionStream` guarantees everywhere; brotli isn't part of the standard, so it's not offered.
14
+ *
15
+ * The body is **peeked** up to `threshold` bytes to enforce the size floor: a response that ends below
16
+ * the threshold is sent uncompressed (gzip's ~20-byte overhead would enlarge it), and only larger
17
+ * bodies are compressed — the buffered prefix is replayed and the remainder streamed. (Runtimes rarely
18
+ * set `Content-Length` on a constructed `Response`, so the header alone can't gate this.)
19
+ *
20
+ * Skips: clients that don't accept gzip, already-encoded responses, bodyless responses (204/304/HEAD),
21
+ * `Range` responses (206 / `Content-Range`), `Cache-Control: no-transform`, and non-compressible types.
22
+ * Adds `Vary: Accept-Encoding`.
23
+ *
24
+ * ```ts
25
+ * app.use(compression())
26
+ * ```
27
+ */
28
+ export declare function compression(options?: CompressionOptions): import("@nifrajs/core").NifraPlugin<import("@nifrajs/core").AnyServer, import("@nifrajs/core").AnyServer>;
29
+ //# sourceMappingURL=compression.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compression.d.ts","sourceRoot":"","sources":["../src/compression.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,kBAAkB;IACjC;gGAC4F;IAC5F,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B;2FACuF;IACvF,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAA;CACzD;AA6BD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,6GAqD3D"}
@@ -0,0 +1,105 @@
1
+ import { definePlugin } from "@nifrajs/core";
2
+ // Text-like payloads benefit from gzip; binary media (images/video/archives) is already compressed.
3
+ const COMPRESSIBLE = /^(?:text\/|application\/(?:json|[\w.-]+\+json|javascript|xml|[\w.-]+\+xml|wasm|x-ndjson)|image\/svg\+xml)/i;
4
+ const defaultCompressible = (contentType) => COMPRESSIBLE.test(contentType);
5
+ const concat = (chunks, total) => {
6
+ const out = new Uint8Array(total);
7
+ let offset = 0;
8
+ for (const chunk of chunks) {
9
+ out.set(chunk, offset);
10
+ offset += chunk.byteLength;
11
+ }
12
+ return out;
13
+ };
14
+ const gzipHeaders = (source) => {
15
+ const headers = new Headers(source);
16
+ headers.set("content-encoding", "gzip");
17
+ headers.delete("content-length"); // compressed length is unknown up front → chunked
18
+ const vary = headers.get("vary");
19
+ if (vary === null)
20
+ headers.set("vary", "Accept-Encoding");
21
+ else if (!vary.toLowerCase().split(",").includes("accept-encoding"))
22
+ headers.set("vary", `${vary}, Accept-Encoding`);
23
+ return headers;
24
+ };
25
+ /**
26
+ * Transparently **gzip** responses when the client sends `Accept-Encoding: gzip` and the body is a
27
+ * compressible type larger than `threshold`. Uses the Web-standard `CompressionStream` (streaming, no
28
+ * full-body buffering), so it runs on every nifra runtime including the edge. gzip is the one encoding
29
+ * `CompressionStream` guarantees everywhere; brotli isn't part of the standard, so it's not offered.
30
+ *
31
+ * The body is **peeked** up to `threshold` bytes to enforce the size floor: a response that ends below
32
+ * the threshold is sent uncompressed (gzip's ~20-byte overhead would enlarge it), and only larger
33
+ * bodies are compressed — the buffered prefix is replayed and the remainder streamed. (Runtimes rarely
34
+ * set `Content-Length` on a constructed `Response`, so the header alone can't gate this.)
35
+ *
36
+ * Skips: clients that don't accept gzip, already-encoded responses, bodyless responses (204/304/HEAD),
37
+ * `Range` responses (206 / `Content-Range`), `Cache-Control: no-transform`, and non-compressible types.
38
+ * Adds `Vary: Accept-Encoding`.
39
+ *
40
+ * ```ts
41
+ * app.use(compression())
42
+ * ```
43
+ */
44
+ export function compression(options = {}) {
45
+ const threshold = options.threshold ?? 1024;
46
+ const isCompressible = options.compressible ?? defaultCompressible;
47
+ return definePlugin("compression", (app) => app.onResponse(async (res, req) => {
48
+ const body = res.body;
49
+ if (body === null)
50
+ return res; // 204/304/HEAD — nothing to compress
51
+ if (!(req.headers.get("accept-encoding") ?? "").toLowerCase().includes("gzip"))
52
+ return res;
53
+ if (res.headers.has("content-encoding"))
54
+ return res; // already encoded
55
+ if (res.status === 206 || res.headers.has("content-range"))
56
+ return res; // ranges pass through
57
+ if ((res.headers.get("cache-control") ?? "").includes("no-transform"))
58
+ return res;
59
+ if (!isCompressible(res.headers.get("content-type") ?? ""))
60
+ return res;
61
+ const declared = res.headers.get("content-length");
62
+ if (declared !== null && Number(declared) < threshold)
63
+ return res; // fast path when length is known
64
+ // Peek up to `threshold` bytes to decide whether compressing is worth it.
65
+ const reader = body.getReader();
66
+ const buffered = [];
67
+ let total = 0;
68
+ while (total < threshold) {
69
+ const { done, value } = await reader.read();
70
+ if (done) {
71
+ // Body ended below the threshold — too small to be worth gzipping. Emit as-is.
72
+ return new Response(concat(buffered, total), {
73
+ status: res.status,
74
+ statusText: res.statusText,
75
+ headers: res.headers,
76
+ });
77
+ }
78
+ buffered.push(value);
79
+ total += value.byteLength;
80
+ }
81
+ // Over the threshold: replay the buffered prefix, then stream the rest — all through gzip.
82
+ // (No explicit generic: it lets the chunk type infer from the non-shared reader so the stream
83
+ // matches `CompressionStream`'s `Uint8Array` typing.)
84
+ const source = new ReadableStream({
85
+ start(controller) {
86
+ for (const chunk of buffered)
87
+ controller.enqueue(chunk);
88
+ },
89
+ async pull(controller) {
90
+ const { done, value } = await reader.read();
91
+ if (done)
92
+ controller.close();
93
+ else
94
+ controller.enqueue(value);
95
+ },
96
+ cancel: (reason) => reader.cancel(reason),
97
+ });
98
+ return new Response(source.pipeThrough(new CompressionStream("gzip")), {
99
+ status: res.status,
100
+ statusText: res.statusText,
101
+ headers: gzipHeaders(res.headers),
102
+ });
103
+ }));
104
+ }
105
+ //# sourceMappingURL=compression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compression.js","sourceRoot":"","sources":["../src/compression.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { Context, Middleware } from "@nifrajs/core";
2
+ /**
3
+ * Store the current nifra `Context` in `AsyncLocalStorage` for helpers that run away from the handler
4
+ * argument, e.g. repository/logger functions called deep in the stack.
5
+ *
6
+ * Import from `@nifrajs/middleware/context-storage` so ordinary `@nifrajs/middleware` imports stay
7
+ * node-compat-free on edge runtimes. The runtime must support `node:async_hooks` AsyncLocalStorage.
8
+ */
9
+ export declare function contextStorage(): Middleware;
10
+ /** Return the current request context, or throw when no context-storage wrapper is active. */
11
+ export declare function getContext<C extends Context = Context>(): C;
12
+ /** Return the current request context, or `undefined` outside a context-storage request. */
13
+ export declare function tryGetContext<C extends Context = Context>(): C | undefined;
14
+ //# sourceMappingURL=context-storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-storage.d.ts","sourceRoot":"","sources":["../src/context-storage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAIxD;;;;;;GAMG;AACH,wBAAgB,cAAc,IAAI,UAAU,CAO3C;AAED,8FAA8F;AAC9F,wBAAgB,UAAU,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,KAAK,CAAC,CAQ3D;AAED,4FAA4F;AAC5F,wBAAgB,aAAa,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,KAAK,CAAC,GAAG,SAAS,CAE1E"}
@@ -0,0 +1,30 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ const storage = new AsyncLocalStorage();
3
+ /**
4
+ * Store the current nifra `Context` in `AsyncLocalStorage` for helpers that run away from the handler
5
+ * argument, e.g. repository/logger functions called deep in the stack.
6
+ *
7
+ * Import from `@nifrajs/middleware/context-storage` so ordinary `@nifrajs/middleware` imports stay
8
+ * node-compat-free on edge runtimes. The runtime must support `node:async_hooks` AsyncLocalStorage.
9
+ */
10
+ export function contextStorage() {
11
+ return {
12
+ name: "context-storage",
13
+ around(context, next) {
14
+ return storage.run(context, next);
15
+ },
16
+ };
17
+ }
18
+ /** Return the current request context, or throw when no context-storage wrapper is active. */
19
+ export function getContext() {
20
+ const context = tryGetContext();
21
+ if (context === undefined) {
22
+ throw new Error("contextStorage: no active context. Add app.use(contextStorage()) before the route and call getContext() during that request.");
23
+ }
24
+ return context;
25
+ }
26
+ /** Return the current request context, or `undefined` outside a context-storage request. */
27
+ export function tryGetContext() {
28
+ return storage.getStore();
29
+ }
30
+ //# sourceMappingURL=context-storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-storage.js","sourceRoot":"","sources":["../src/context-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAGpD,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAW,CAAA;AAEhD;;;;;;GAMG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,MAAM,CAAC,OAAO,EAAE,IAAI;YAClB,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QACnC,CAAC;KACF,CAAA;AACH,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,UAAU;IACxB,MAAM,OAAO,GAAG,aAAa,EAAK,CAAA;IAClC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,8HAA8H,CAC/H,CAAA;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,aAAa;IAC3B,OAAO,OAAO,CAAC,QAAQ,EAAmB,CAAA;AAC5C,CAAC"}
package/dist/cors.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ import type { Middleware } from "@nifrajs/core";
2
+ export interface CorsOptions {
3
+ /** Allowed origin(s): `"*"`, an exact origin, a list, or a predicate. Default `"*"`. */
4
+ readonly origin?: string | ReadonlyArray<string> | ((origin: string) => boolean);
5
+ /** Methods advertised in the preflight response. Default the common verbs. */
6
+ readonly methods?: ReadonlyArray<string>;
7
+ /** Headers allowed on the actual request. Default: reflect the preflight's requested headers. */
8
+ readonly allowedHeaders?: ReadonlyArray<string>;
9
+ /** Response headers exposed to the browser. */
10
+ readonly exposedHeaders?: ReadonlyArray<string>;
11
+ /** Allow credentials (cookies / `Authorization`). Cannot be combined with `origin: "*"`. Default false. */
12
+ readonly credentials?: boolean;
13
+ /** Preflight cache duration, in seconds. */
14
+ readonly maxAge?: number;
15
+ }
16
+ /**
17
+ * CORS as a {@link Middleware}. Preflight (`OPTIONS` + `Access-Control-Request-Method`)
18
+ * short-circuits to `204` via `onRequest`; the origin/credentials headers are added in
19
+ * `onResponse`, so they also land on errors, 404s, and the preflight itself.
20
+ *
21
+ * Throws at construction if `credentials: true` is paired with `origin: "*"` — the
22
+ * browser rejects that combination, so we fail loud instead of shipping dead CORS.
23
+ */
24
+ export declare function cors(options?: CorsOptions): Middleware;
25
+ //# sourceMappingURL=cors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../src/cors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAG/C,MAAM,WAAW,WAAW;IAC1B,wFAAwF;IACxF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,CAAA;IAChF,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACxC,iGAAiG;IACjG,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IAC/C,+CAA+C;IAC/C,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IAC/C,2GAA2G;IAC3G,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAA;IAC9B,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAwBD;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,UAAU,CAyC1D"}
package/dist/cors.js ADDED
@@ -0,0 +1,75 @@
1
+ import { withHeaders } from "./_utils.js";
2
+ const DEFAULT_METHODS = [
3
+ "GET",
4
+ "HEAD",
5
+ "POST",
6
+ "PUT",
7
+ "PATCH",
8
+ "DELETE",
9
+ "OPTIONS",
10
+ ];
11
+ /** Resolve the `Access-Control-Allow-Origin` value for a request, or `null` to omit it. */
12
+ function resolveAllowOrigin(option, requestOrigin) {
13
+ if (option === "*")
14
+ return "*";
15
+ if (requestOrigin === null)
16
+ return null;
17
+ if (typeof option === "function")
18
+ return option(requestOrigin) ? requestOrigin : null;
19
+ if (Array.isArray(option))
20
+ return option.includes(requestOrigin) ? requestOrigin : null;
21
+ return option === requestOrigin ? requestOrigin : null;
22
+ }
23
+ /**
24
+ * CORS as a {@link Middleware}. Preflight (`OPTIONS` + `Access-Control-Request-Method`)
25
+ * short-circuits to `204` via `onRequest`; the origin/credentials headers are added in
26
+ * `onResponse`, so they also land on errors, 404s, and the preflight itself.
27
+ *
28
+ * Throws at construction if `credentials: true` is paired with `origin: "*"` — the
29
+ * browser rejects that combination, so we fail loud instead of shipping dead CORS.
30
+ */
31
+ export function cors(options = {}) {
32
+ const origin = options.origin ?? "*";
33
+ const credentials = options.credentials ?? false;
34
+ if (credentials && origin === "*") {
35
+ throw new Error('cors: `credentials: true` cannot be combined with `origin: "*"` — list explicit origin(s).');
36
+ }
37
+ const methods = (options.methods ?? DEFAULT_METHODS).join(", ");
38
+ const allowedHeaders = options.allowedHeaders?.join(", ");
39
+ const exposedHeaders = options.exposedHeaders?.join(", ");
40
+ const maxAge = options.maxAge;
41
+ return {
42
+ name: "cors",
43
+ onRequest(req) {
44
+ const isPreflight = req.method === "OPTIONS" && req.headers.has("access-control-request-method");
45
+ if (!isPreflight)
46
+ return undefined;
47
+ const headers = new Headers();
48
+ headers.set("Access-Control-Allow-Methods", methods);
49
+ const requested = allowedHeaders ?? req.headers.get("access-control-request-headers");
50
+ if (requested)
51
+ headers.set("Access-Control-Allow-Headers", requested);
52
+ if (maxAge !== undefined)
53
+ headers.set("Access-Control-Max-Age", String(maxAge));
54
+ // Allow-Origin / Allow-Credentials are added by onResponse (runs on every response).
55
+ return new Response(null, { status: 204, headers });
56
+ },
57
+ onResponse(res, req) {
58
+ const allowOrigin = resolveAllowOrigin(origin, req.headers.get("origin"));
59
+ if (allowOrigin === null)
60
+ return res;
61
+ // Mutate in place on the common (mutable-headers) response; clone only for an immutable one.
62
+ return withHeaders(res, (headers) => {
63
+ headers.set("Access-Control-Allow-Origin", allowOrigin);
64
+ if (allowOrigin !== "*")
65
+ headers.append("Vary", "Origin");
66
+ if (credentials)
67
+ headers.set("Access-Control-Allow-Credentials", "true");
68
+ if (exposedHeaders !== undefined) {
69
+ headers.set("Access-Control-Expose-Headers", exposedHeaders);
70
+ }
71
+ });
72
+ },
73
+ };
74
+ }
75
+ //# sourceMappingURL=cors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cors.js","sourceRoot":"","sources":["../src/cors.ts"],"names":[],"mappings":"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"}
package/dist/csrf.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ import type { Middleware } from "@nifrajs/core";
2
+ export interface CsrfOptions {
3
+ /** HMAC secret. Must be at least 32 bytes. */
4
+ readonly secret: string | Uint8Array;
5
+ /** Cookie carrying the signed token. Default `"csrf-token"`. */
6
+ readonly cookie?: string;
7
+ /** Header carrying the same signed token. Default `"x-csrf-token"`. */
8
+ readonly header?: string;
9
+ /** Unsafe methods to protect. Default: every method except GET/HEAD/OPTIONS/TRACE. */
10
+ readonly methods?: readonly string[];
11
+ /** Allowed request origins. Default: same-origin derived from the request URL. */
12
+ readonly origins?: readonly string[];
13
+ /** Check Origin/Referer on protected requests. Default true. */
14
+ readonly checkOrigin?: boolean;
15
+ }
16
+ export declare function createCsrfToken(secret: string | Uint8Array, nonce?: string): Promise<string>;
17
+ export declare function verifyCsrfToken(token: string, secret: string | Uint8Array): Promise<boolean>;
18
+ /**
19
+ * Signed double-submit CSRF protection. A protected request must carry the same signed token in a
20
+ * cookie and a header, and must come from an allowed Origin/Referer unless `checkOrigin:false` is set.
21
+ */
22
+ export declare function csrf(options: CsrfOptions): Middleware;
23
+ //# sourceMappingURL=csrf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../src/csrf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAY/C,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAAA;IACpC,gEAAgE;IAChE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,uEAAuE;IACvE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,sFAAsF;IACtF,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,kFAAkF;IAClF,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,gEAAgE;IAChE,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAC/B;AAsBD,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,GAAG,UAAU,EAC3B,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,UAAU,GAC1B,OAAO,CAAC,OAAO,CAAC,CAQlB;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,UAAU,CAwBrD"}