@ozanarslan/corpus 0.0.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 (87) hide show
  1. package/LICENSE.txt +20 -0
  2. package/README.md +337 -0
  3. package/dist/App/index.d.ts +377 -0
  4. package/dist/App/index.d.ts.map +1 -0
  5. package/dist/C.namespace.d.ts +27 -0
  6. package/dist/C.namespace.d.ts.map +1 -0
  7. package/dist/Config/index.d.ts +163 -0
  8. package/dist/Config/index.d.ts.map +1 -0
  9. package/dist/Context/ContextAccess/index.d.ts +50 -0
  10. package/dist/Context/ContextAccess/index.d.ts.map +1 -0
  11. package/dist/Context/index.d.ts +162 -0
  12. package/dist/Context/index.d.ts.map +1 -0
  13. package/dist/Controller/index.d.ts +164 -0
  14. package/dist/Controller/index.d.ts.map +1 -0
  15. package/dist/Cookies/index.d.ts +81 -0
  16. package/dist/Cookies/index.d.ts.map +1 -0
  17. package/dist/Cors/index.d.ts +135 -0
  18. package/dist/Cors/index.d.ts.map +1 -0
  19. package/dist/Exception/index.d.ts +85 -0
  20. package/dist/Exception/index.d.ts.map +1 -0
  21. package/dist/Globals/AppsRegistry/index.d.ts +48 -0
  22. package/dist/Globals/AppsRegistry/index.d.ts.map +1 -0
  23. package/dist/Globals/ParsersRegistry/index.d.ts +93 -0
  24. package/dist/Globals/ParsersRegistry/index.d.ts.map +1 -0
  25. package/dist/Globals/index.d.ts +109 -0
  26. package/dist/Globals/index.d.ts.map +1 -0
  27. package/dist/Headers/index.d.ts +208 -0
  28. package/dist/Headers/index.d.ts.map +1 -0
  29. package/dist/Middleware/index.d.ts +125 -0
  30. package/dist/Middleware/index.d.ts.map +1 -0
  31. package/dist/ParserBase/BodyParser/index.d.ts +138 -0
  32. package/dist/ParserBase/BodyParser/index.d.ts.map +1 -0
  33. package/dist/ParserBase/FormDataParser/index.d.ts +57 -0
  34. package/dist/ParserBase/FormDataParser/index.d.ts.map +1 -0
  35. package/dist/ParserBase/SchemaParser/index.d.ts +143 -0
  36. package/dist/ParserBase/SchemaParser/index.d.ts.map +1 -0
  37. package/dist/ParserBase/SearchParamsParser/index.d.ts +61 -0
  38. package/dist/ParserBase/SearchParamsParser/index.d.ts.map +1 -0
  39. package/dist/ParserBase/URLParamsParser/index.d.ts +32 -0
  40. package/dist/ParserBase/URLParamsParser/index.d.ts.map +1 -0
  41. package/dist/ParserBase/index.d.ts +92 -0
  42. package/dist/ParserBase/index.d.ts.map +1 -0
  43. package/dist/RateLimiter/index.d.ts +321 -0
  44. package/dist/RateLimiter/index.d.ts.map +1 -0
  45. package/dist/Request/index.d.ts +81 -0
  46. package/dist/Request/index.d.ts.map +1 -0
  47. package/dist/Res/index.d.ts +353 -0
  48. package/dist/Res/index.d.ts.map +1 -0
  49. package/dist/RouteBase/BundleRoute/index.d.ts +268 -0
  50. package/dist/RouteBase/BundleRoute/index.d.ts.map +1 -0
  51. package/dist/RouteBase/FileRoute/index.d.ts +121 -0
  52. package/dist/RouteBase/FileRoute/index.d.ts.map +1 -0
  53. package/dist/RouteBase/Route/index.d.ts +83 -0
  54. package/dist/RouteBase/Route/index.d.ts.map +1 -0
  55. package/dist/RouteBase/StaticRoute/index.d.ts +149 -0
  56. package/dist/RouteBase/StaticRoute/index.d.ts.map +1 -0
  57. package/dist/RouteBase/WebSocketRoute/index.d.ts +117 -0
  58. package/dist/RouteBase/WebSocketRoute/index.d.ts.map +1 -0
  59. package/dist/RouteBase/index.d.ts +206 -0
  60. package/dist/RouteBase/index.d.ts.map +1 -0
  61. package/dist/Server/index.d.ts +44 -0
  62. package/dist/Server/index.d.ts.map +1 -0
  63. package/dist/XFile/index.d.ts +202 -0
  64. package/dist/XFile/index.d.ts.map +1 -0
  65. package/dist/exports.d.ts +11 -0
  66. package/dist/exports.d.ts.map +1 -0
  67. package/dist/index.d.ts +5 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +12 -0
  70. package/dist/index.js.map +47 -0
  71. package/dist/initialize.d.ts +22 -0
  72. package/dist/initialize.d.ts.map +1 -0
  73. package/dist/utils/assert.d.ts +7 -0
  74. package/dist/utils/assert.d.ts.map +1 -0
  75. package/dist/utils/is.d.ts +17 -0
  76. package/dist/utils/is.d.ts.map +1 -0
  77. package/dist/utils/lazy.d.ts +27 -0
  78. package/dist/utils/lazy.d.ts.map +1 -0
  79. package/dist/utils/logger.d.ts +31 -0
  80. package/dist/utils/logger.d.ts.map +1 -0
  81. package/dist/utils/object.d.ts +20 -0
  82. package/dist/utils/object.d.ts.map +1 -0
  83. package/dist/utils/path.d.ts +6 -0
  84. package/dist/utils/path.d.ts.map +1 -0
  85. package/dist/utils/tuple.d.ts +3 -0
  86. package/dist/utils/tuple.d.ts.map +1 -0
  87. package/package.json +57 -0
@@ -0,0 +1,321 @@
1
+ /**
2
+ * Request rate limiting, as a ready-made {@link Middleware}.
3
+ *
4
+ * {@link RateLimiter} counts requests per caller within a rolling window and
5
+ * rejects anything over the limit with {@link Status.TOO_MANY_REQUESTS}. Who
6
+ * "the caller" is depends on what the request proves about itself: an
7
+ * authenticated request is identified by its token, an unauthenticated one by
8
+ * its IP, and one with neither by a fingerprint of its headers. Each tier gets
9
+ * its own limit, since they differ in how accountable and how forgeable they
10
+ * are.
11
+ *
12
+ * Identifiers are hashed with a rotating salt before being stored, so the
13
+ * limiter never holds a token or an IP in memory.
14
+ *
15
+ * ```ts
16
+ * import { RateLimiter } from "@ozanarslan/corpus";
17
+ *
18
+ * new RateLimiter({ windowMs: 60_000, limits: { authenticated: 120, ipBased: 60, fingerprint: 20 } });
19
+ * ```
20
+ *
21
+ * Counting is backed by {@link RateLimiterStoreInterface}; the default
22
+ * {@link RateLimiterMemoryStore} is per-process, so a multi-instance deployment
23
+ * wants a shared store instead.
24
+ *
25
+ * @module RateLimiter
26
+ */
27
+ import { Middleware, type MiddlewareHandler } from "../Middleware";
28
+ import { type MaybePromise, type OrString } from "../utils/is";
29
+ import { type Tuple } from "../utils/tuple";
30
+ /** One caller's counter for the current window. */
31
+ interface RateLimiterEntry {
32
+ /** Requests seen in this window, including the one being handled. */
33
+ hits: number;
34
+ /** Unix milliseconds at which the window ends and the count resets. */
35
+ resetAt: number;
36
+ }
37
+ /**
38
+ * The storage contract for rate limit counters.
39
+ *
40
+ * Implement it to back the limiter with Redis or anything else shared across
41
+ * processes — the default {@link RateLimiterMemoryStore} only counts within one.
42
+ * Every method may be synchronous or asynchronous; the limiter awaits either.
43
+ */
44
+ interface RateLimiterStoreInterface {
45
+ /**
46
+ * Reads a caller's entry.
47
+ *
48
+ * @param id - The hashed caller identifier.
49
+ * @returns The entry, or `undefined` when the caller has none.
50
+ */
51
+ get(id: string): MaybePromise<RateLimiterEntry | undefined>;
52
+ /**
53
+ * Writes a caller's entry, replacing any existing one.
54
+ *
55
+ * @param id - The hashed caller identifier.
56
+ * @param entry - The counter to store.
57
+ */
58
+ set(id: string, entry: RateLimiterEntry): MaybePromise<void>;
59
+ /**
60
+ * Removes a caller's entry.
61
+ *
62
+ * @param id - The hashed caller identifier.
63
+ */
64
+ delete(id: string): MaybePromise<void>;
65
+ /**
66
+ * Removes every entry whose window has ended.
67
+ *
68
+ * @param now - Unix milliseconds to compare against
69
+ * {@link RateLimiterEntry.resetAt}.
70
+ */
71
+ cleanup(now: number): MaybePromise<void>;
72
+ /** Removes every entry, expired or not. */
73
+ clear(): MaybePromise<void>;
74
+ /**
75
+ * Reports how many entries are held.
76
+ *
77
+ * @returns The entry count, used to decide when a cleanup is forced.
78
+ */
79
+ size(): MaybePromise<number>;
80
+ }
81
+ /**
82
+ * In-process counter storage, used when no store is configured.
83
+ *
84
+ * Writes are serialised per identifier through a promise lock, so concurrent
85
+ * requests from the same caller cannot interleave their read-modify-write and
86
+ * lose a hit.
87
+ *
88
+ * State lives in one process's memory, so it is lost on restart and not shared
89
+ * between instances — behind a load balancer, each instance enforces the limit
90
+ * separately. Use a shared {@link RateLimiterStoreInterface} when that matters.
91
+ */
92
+ declare class RateLimiterMemoryStore implements RateLimiterStoreInterface {
93
+ /** The counters, keyed by hashed identifier. */
94
+ protected readonly map: Map<string, RateLimiterEntry>;
95
+ /** In-flight write locks, keyed by identifier. Present only while a write is running. */
96
+ protected readonly locks: Map<string, Promise<void>>;
97
+ /**
98
+ * Reads a caller's entry.
99
+ *
100
+ * @param id - The hashed caller identifier.
101
+ * @returns The entry, or `undefined` when absent. Expired entries are returned
102
+ * as-is; the limiter checks {@link RateLimiterEntry.resetAt} itself.
103
+ */
104
+ get(id: string): RateLimiterEntry | undefined;
105
+ /**
106
+ * Writes a caller's entry, waiting for any write already in progress for the
107
+ * same identifier.
108
+ *
109
+ * @param id - The hashed caller identifier.
110
+ * @param entry - The counter to store.
111
+ */
112
+ set(id: string, entry: RateLimiterEntry): Promise<void>;
113
+ /**
114
+ * Removes a caller's entry.
115
+ *
116
+ * @param id - The hashed caller identifier.
117
+ */
118
+ delete(id: string): void;
119
+ /**
120
+ * Removes every entry whose window has already ended.
121
+ *
122
+ * @param now - Unix milliseconds to compare against.
123
+ */
124
+ cleanup(now: number): void;
125
+ /** Removes every entry, resetting all counters. */
126
+ clear(): void;
127
+ /**
128
+ * @returns How many entries are currently held.
129
+ */
130
+ size(): number;
131
+ }
132
+ /**
133
+ * The limiter's settings. {@link RateLimiter} merges what you pass over
134
+ * {@link defaultConfig}, so every field is optional at the call site.
135
+ */
136
+ type RateLimiterConfig = {
137
+ /** Limits based on identifier type: */
138
+ limits: {
139
+ /** Authenticated users — higher limit, accountable identity (e.g., 120 requests) */
140
+ authenticated: number;
141
+ /** IP-based — moderate, may be shared (NAT, proxies) (e.g., 60 requests) */
142
+ ipBased: number;
143
+ /** Fingerprint / anonymous — lowest, least trustworthy (e.g., 20 requests) */
144
+ fingerprint: number;
145
+ };
146
+ /**
147
+ * You can pass a different header key to check for authenticated users.
148
+ * "Bearer " string is only sliced for Authorization.
149
+ * */
150
+ authHeader?: OrString<"Authorization">;
151
+ /** Time window in milliseconds during which the rate limit applies (default: 60,000ms = 1 minute) */
152
+ windowMs: number;
153
+ /**
154
+ * How often to rotate the salt used for hashing identifiers (default: 24h)
155
+ * Prevents long-term tracking and adds an extra layer of privacy
156
+ * */
157
+ saltRotateMs: number;
158
+ /**
159
+ * Probability (0-1) of triggering a cleanup of expired entries on each request
160
+ * Balances memory usage against performance (default: 0.005 = 0.5%)
161
+ * */
162
+ cleanProbability: number;
163
+ /**
164
+ * Maximum number of entries before forcing a cleanup
165
+ * Prevents unbounded memory growth (default: 50,000)
166
+ * */
167
+ maxStoreSize: number;
168
+ /**
169
+ * Bring your own store implementation like redis.
170
+ * Uses {@link RateLimiterMemoryStore} by default.
171
+ * */
172
+ store?: RateLimiterStoreInterface;
173
+ /**
174
+ * Customizable HTTP header names for rate limit information.
175
+ * Allows integration with different API conventions or frontend expectations.
176
+ *
177
+ * @example
178
+ * // Custom header names (e.g., for legacy systems)
179
+ * headerNames: {
180
+ * limit: "X-RateLimit-Limit",
181
+ * remaining: "X-RateLimit-Remaining",
182
+ * reset: "X-RateLimit-Reset",
183
+ * retryAfter: "Retry-After"
184
+ * }
185
+ *
186
+ * @default Uses standard RateLimit-* headers as defined in IETF draft:
187
+ * - limit: "RateLimit-Limit"
188
+ * - remaining: "RateLimit-Remaining"
189
+ * - reset: "RateLimit-Reset"
190
+ * - retryAfter: "Retry-After"
191
+ */
192
+ headerNames: {
193
+ /** Header name for the maximum allowed requests in the current window */
194
+ limit: string;
195
+ /** Header name for the remaining requests in the current window */
196
+ remaining: string;
197
+ /** Header name for the timestamp (Unix seconds) when the window resets */
198
+ reset: string;
199
+ /** Header name for seconds to wait before retrying when rate limited */
200
+ retryAfter: string;
201
+ };
202
+ };
203
+ /**
204
+ * A {@link Middleware} that limits how often a caller may make requests.
205
+ *
206
+ * Every response carries the limit, the remaining allowance and the reset time,
207
+ * and those header names are added to
208
+ * {@link HeaderKey.AccessControlExposeHeaders} so browser clients can actually
209
+ * read them. Exceeding the limit throws an {@link Exception} carrying the
210
+ * response built so far, so the rejection keeps its rate limit headers.
211
+ */
212
+ declare class RateLimiter extends Middleware {
213
+ /**
214
+ * Creates a limiter and registers it on the nearest {@link App}.
215
+ *
216
+ * It targets the routes registered so far, minus
217
+ * {@link RouteVariant.bundle} ones — a single page load pulls dozens of
218
+ * assets, which would exhaust any sensible limit. Construct it after your
219
+ * routes; routes registered later are not covered.
220
+ *
221
+ * @param config - Overrides for {@link defaultConfig}. Merged shallowly, so
222
+ * supplying `limits` or `headerNames` replaces that group whole.
223
+ */
224
+ constructor(config?: Partial<RateLimiterConfig>);
225
+ /**
226
+ * Counts the request and either continues the chain or rejects it.
227
+ *
228
+ * @param c - The {@link Context} for the request.
229
+ * @param next - Runs the rest of the chain.
230
+ * @throws {@link Exception} with {@link Status.TOO_MANY_REQUESTS} when the
231
+ * limit is exceeded. The current {@link Res} is passed as the exception data,
232
+ * so the rejection carries the rate limit headers already set on it.
233
+ */
234
+ handler: MiddlewareHandler;
235
+ /**
236
+ * Counts one request against its caller's allowance and writes the rate limit
237
+ * headers.
238
+ *
239
+ * A window is created on the first request and reused until
240
+ * {@link RateLimiterEntry.resetAt} passes, at which point the counter starts
241
+ * over — a fixed window, not a sliding one. The hit is counted whether or not
242
+ * it is allowed, so a caller that keeps hammering a closed window stays closed
243
+ * until it resets.
244
+ *
245
+ * Exposed separately from {@link RateLimiter.handler} so the same accounting
246
+ * can be driven from outside a request chain, in tests or a custom handler.
247
+ *
248
+ * @param reqHeaders - The request headers, used to identify the caller.
249
+ * @param resHeaders - The response headers to write the limit, remaining,
250
+ * reset and — when rejected — retry-after values into.
251
+ * @returns `true` when the request is within the limit.
252
+ */
253
+ getResult(reqHeaders: Headers, resHeaders: Headers): Promise<boolean>;
254
+ /** The merged settings this limiter runs with. */
255
+ protected readonly config: RateLimiterConfig;
256
+ /** Where counters are kept. The configured store, or a {@link RateLimiterMemoryStore}. */
257
+ protected readonly store: RateLimiterStoreInterface;
258
+ /** The current hashing salt. Rotated by {@link RateLimiter.salt}. */
259
+ protected storedSalt: string;
260
+ /** Unix milliseconds at which {@link RateLimiter.storedSalt} is replaced. */
261
+ protected saltRotatesAt: number;
262
+ /**
263
+ * Identifies the caller and picks the limit that applies to it.
264
+ *
265
+ * Three tiers are tried in order of how much the request proves about itself.
266
+ * A bearer token of plausible length identifies an authenticated caller and
267
+ * earns the highest limit. Failing that, a valid address from the proxy
268
+ * headers earns the IP limit — shared by everyone behind a NAT, hence lower.
269
+ * Failing that, a fingerprint of the user agent and accept headers earns the
270
+ * lowest limit, since it is trivially forgeable.
271
+ *
272
+ * Tokens are hashed without the salt so a caller keeps one bucket across
273
+ * rotations; addresses and fingerprints are salted, so they cannot be
274
+ * correlated across rotation windows.
275
+ *
276
+ * The prefixes (`u:`, `i:`, `f:`) keep the tiers in separate namespaces, so a
277
+ * collision across tiers is impossible.
278
+ *
279
+ * @param headers - The request headers.
280
+ * @returns A {@link Tuple} of the hashed identifier and the applicable limit.
281
+ */
282
+ protected getIdAndLimit(headers: Headers): Tuple<string, number>;
283
+ /**
284
+ * Returns the current hashing salt, rotating it when it has expired.
285
+ *
286
+ * Rotation is lazy rather than scheduled, so no timer is held open. A rotation
287
+ * changes every derived identifier at once, which resets the affected
288
+ * counters — acceptable at a daily cadence, and the point: it bounds how long
289
+ * any caller can be tracked.
290
+ *
291
+ * @returns The salt to mix into address and fingerprint hashes.
292
+ */
293
+ protected salt(): string;
294
+ /**
295
+ * Decides whether to sweep expired entries before handling a request.
296
+ *
297
+ * Cleanup runs on a small random fraction of requests, so the cost is spread
298
+ * out instead of landing on a timer, and unconditionally once the store passes
299
+ * {@link RateLimiterConfig.maxStoreSize}, which bounds memory under a flood of
300
+ * one-off callers.
301
+ */
302
+ protected maybeCleanStore(): Promise<void>;
303
+ /**
304
+ * Removes every entry whose window has ended.
305
+ *
306
+ * @returns How many entries remain.
307
+ */
308
+ protected cleanStore(): Promise<number>;
309
+ /**
310
+ * Clears every counter, expired or not, resetting all callers to a full
311
+ * allowance. Mainly useful between tests.
312
+ */
313
+ clearStore(): Promise<void>;
314
+ /**
315
+ * @returns How many counters are currently held, expired ones included until
316
+ * the next cleanup.
317
+ */
318
+ getStoreSize(): Promise<number>;
319
+ }
320
+ export { RateLimiter, RateLimiterMemoryStore, type RateLimiterStoreInterface, type RateLimiterConfig, };
321
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/RateLimiter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAOH,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGlE,OAAO,EAAuB,KAAK,YAAY,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AACnF,OAAO,EAAS,KAAK,KAAK,EAAE,MAAM,eAAe,CAAC;AAElD,mDAAmD;AACnD,UAAU,gBAAgB;IACzB,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;CAChB;AAGD;;;;;;GAMG;AACH,UAAU,yBAAyB;IAClC;;;;;OAKG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAC;IAC5D;;;;;OAKG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC7D;;;;OAIG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACvC;;;;;OAKG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACzC,2CAA2C;IAC3C,KAAK,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;IAC5B;;;;OAIG;IACH,IAAI,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;CAC7B;AAED;;;;;;;;;;GAUG;AACH,cAAM,sBAAuB,YAAW,yBAAyB;IAChE,gDAAgD;IAChD,SAAS,CAAC,QAAQ,CAAC,GAAG,gCAAuC;IAE7D,yFAAyF;IACzF,SAAS,CAAC,QAAQ,CAAC,KAAK,6BAAoC;IAE5D;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAI7C;;;;;;OAMG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB7D;;;;OAIG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIxB;;;;OAIG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAQ1B,mDAAmD;IACnD,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,IAAI,IAAI,MAAM;CAGd;AAED;;;GAGG;AACH,KAAK,iBAAiB,GAAG;IACxB,uCAAuC;IACvC,MAAM,EAAE;QACP,oFAAoF;QACpF,aAAa,EAAE,MAAM,CAAC;QACtB,4EAA4E;QAC5E,OAAO,EAAE,MAAM,CAAC;QAChB,8EAA8E;QAC9E,WAAW,EAAE,MAAM,CAAC;KACpB,CAAC;IAEF;;;SAGK;IACL,UAAU,CAAC,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IAEvC,qGAAqG;IACrG,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;SAGK;IACL,YAAY,EAAE,MAAM,CAAC;IAErB;;;SAGK;IACL,gBAAgB,EAAE,MAAM,CAAC;IAEzB;;;SAGK;IACL,YAAY,EAAE,MAAM,CAAC;IAErB;;;SAGK;IACL,KAAK,CAAC,EAAE,yBAAyB,CAAC;IAElC;;;;;;;;;;;;;;;;;;OAkBG;IACH,WAAW,EAAE;QACZ,yEAAyE;QACzE,KAAK,EAAE,MAAM,CAAC;QACd,mEAAmE;QACnE,SAAS,EAAE,MAAM,CAAC;QAClB,0EAA0E;QAC1E,KAAK,EAAE,MAAM,CAAC;QACd,wEAAwE;QACxE,UAAU,EAAE,MAAM,CAAC;KACnB,CAAC;CACF,CAAC;AAkFF;;;;;;;;GAQG;AACH,cAAM,WAAY,SAAQ,UAAU;IACnC;;;;;;;;;;OAUG;gBACS,MAAM,GAAE,OAAO,CAAC,iBAAiB,CAAM;IAYnD;;;;;;;;OAQG;IACM,OAAO,EAAE,iBAAiB,CAIjC;IAEF;;;;;;;;;;;;;;;;;OAiBG;IACG,SAAS,CAAC,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAuC3E,kDAAkD;IAClD,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IAE7C,0FAA0F;IAC1F,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,yBAAyB,CAAC;IAEpD,qEAAqE;IACrE,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC;IAE7B,6EAA6E;IAC7E,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC;IAEhC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,SAAS,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC;IA6BhE;;;;;;;;;OASG;IACH,SAAS,CAAC,IAAI,IAAI,MAAM;IAQxB;;;;;;;OAOG;cACa,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAQhD;;;;OAIG;cACa,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAO7C;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;;OAGG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;CAGrC;AAED,OAAO,EACN,WAAW,EACX,sBAAsB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,iBAAiB,GACtB,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * HTTP method constants, and the `Request` extensions the framework relies on.
3
+ *
4
+ * {@link Method} gives the verbs as documented constants. {@link patchGlobalRequest}
5
+ * then adds two properties to the global `Request`: `params`, which {@link App}
6
+ * fills with the matched path parameters before parsing, and `cookies`, which
7
+ * parses the `Cookie` header into a {@link Cookies} map on first access.
8
+ *
9
+ * Like {@link patchGlobalHeaders}, this must be installed once at startup,
10
+ * before any request is served.
11
+ *
12
+ * @module Request
13
+ */
14
+ import { Cookies } from "../Cookies";
15
+ import type { OrString } from "../utils/is";
16
+ import { type ValueOf } from "../utils/object";
17
+ /** Commonly used HTTP verbs. See [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods) for the full spec. */
18
+ declare const Method: {
19
+ /** Retrieve a resource from the server. */
20
+ readonly GET: "GET";
21
+ /** Submit data to create a new resource. */
22
+ readonly POST: "POST";
23
+ /** Replace an entire resource with new data. */
24
+ readonly PUT: "PUT";
25
+ /** Apply partial modifications to a resource. */
26
+ readonly PATCH: "PATCH";
27
+ /** Remove a resource from the server. */
28
+ readonly DELETE: "DELETE";
29
+ /** Get response headers without body. */
30
+ readonly HEAD: "HEAD";
31
+ /** Discover communication options. */
32
+ readonly OPTIONS: "OPTIONS";
33
+ /** Establish tunnel to server. */
34
+ readonly CONNECT: "CONNECT";
35
+ /** Echo back received request. */
36
+ readonly TRACE: "TRACE";
37
+ };
38
+ /**
39
+ * An HTTP method. The {@link Method} constants are suggested, but
40
+ * {@link OrString} keeps any custom verb assignable.
41
+ */
42
+ type Method = OrString<ValueOf<typeof Method>>;
43
+ /**
44
+ * Installs `params` and `cookies` on the global `Request`. Call it once at
45
+ * startup, before any request is served.
46
+ *
47
+ * The patch is applied twice over, for the same reason as
48
+ * {@link patchGlobalHeaders}. The prototype is extended so requests *the runtime*
49
+ * creates — every incoming request Bun hands to the server — carry the
50
+ * properties, since those never pass through a constructor the framework
51
+ * controls. The global class is then replaced too, so manually constructed
52
+ * requests can seed their cookies from {@link RequestInit.cookies}, which the
53
+ * prototype path has no access to.
54
+ *
55
+ * The subclass overrides `Symbol.hasInstance` to defer to the native class, so
56
+ * `instanceof Request` stays true for requests created outside the patch.
57
+ */
58
+ declare function patchGlobalRequest(): void;
59
+ declare global {
60
+ interface RequestInit {
61
+ /**
62
+ * Cookies to seed the request with. Anything in the `Cookie` header is
63
+ * layered on top of these.
64
+ */
65
+ cookies?: Cookies;
66
+ }
67
+ /** The `Request` surface after {@link patchGlobalRequest} has run. */
68
+ interface Request {
69
+ /**
70
+ * The raw path parameters matched by the route, populated by Bun's router.
71
+ * {@link Context.params} holds the parsed, validated version.
72
+ */
73
+ params: {
74
+ [x: string]: string;
75
+ };
76
+ /** The request's cookies, parsed from the `Cookie` header on first access. */
77
+ cookies: Cookies;
78
+ }
79
+ }
80
+ export { patchGlobalRequest, Method };
81
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Request/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAqB,MAAM,WAAW,CAAC;AAEvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,EAAoB,KAAK,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEhE,4IAA4I;AAC5I,QAAA,MAAM,MAAM;IACX,2CAA2C;;IAE3C,4CAA4C;;IAE5C,gDAAgD;;IAEhD,iDAAiD;;IAEjD,yCAAyC;;IAEzC,yCAAyC;;IAEzC,sCAAsC;;IAEtC,kCAAkC;;IAElC,kCAAkC;;CAEzB,CAAC;AAEX;;;GAGG;AACH,KAAK,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,MAAM,CAAC,CAAC,CAAC;AA2B/C;;;;;;;;;;;;;;GAcG;AACH,iBAAS,kBAAkB,SA4F1B;AAED,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,WAAW;QACpB;;;WAGG;QACH,OAAO,CAAC,EAAE,OAAO,CAAC;KAClB;IACD,sEAAsE;IACtE,UAAU,OAAO;QAChB;;;WAGG;QACH,MAAM,EAAE;YAAE,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC;QAChC,8EAA8E;QAC9E,OAAO,EAAE,OAAO,CAAC;KACjB;CACD;AAED,OAAO,EAAE,kBAAkB,EAAE,MAAM,EAAE,CAAC"}