@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,353 @@
1
+ /**
2
+ * Response building: status codes, body serialization, streaming, and cookies.
3
+ *
4
+ * A {@link Res} is what a handler shapes on its way to a native `Response`. It
5
+ * is created lazily on {@link Context.res}, so a handler that just returns a
6
+ * value never constructs one; reach for it when the response needs a status,
7
+ * headers, cookies, or a body form that a plain return value cannot express —
8
+ * a file, a redirect, or a stream.
9
+ *
10
+ * Body serialization is inferred from the value's type at
11
+ * {@link Res.toNativeResponse} time, so an object becomes JSON, a typed array
12
+ * stays binary, and a stream passes through untouched — each with a matching
13
+ * `Content-Type` unless one was set explicitly.
14
+ *
15
+ * ```ts
16
+ * import { Res, Status } from "@ozanarslan/corpus";
17
+ *
18
+ * new Res({ id: 1 }, { status: Status.CREATED });
19
+ * new Res().file("./report.pdf");
20
+ * new Res().redirect("/login");
21
+ * ```
22
+ *
23
+ * @module Res
24
+ */
25
+ import { Cookies } from "../Cookies";
26
+ import { type ContentDispositionDefinition } from "../Headers";
27
+ import { type MaybePromise, type Nullable } from "../utils/is";
28
+ import type { ValueOf } from "../utils/object";
29
+ import { XFile } from "../XFile";
30
+ /** Commonly used HTTP status codes. */
31
+ declare const Status: {
32
+ /** Continue: Request received, please continue */
33
+ readonly CONTINUE: 100;
34
+ /** Switching Protocols: Protocol change request approved */
35
+ readonly SWITCHING_PROTOCOLS: 101;
36
+ /** Processing (WebDAV) */
37
+ readonly PROCESSING: 102;
38
+ /** Early Hints */
39
+ readonly EARLY_HINTS: 103;
40
+ /** OK: Request succeeded */
41
+ readonly OK: 200;
42
+ /** Created: Resource created */
43
+ readonly CREATED: 201;
44
+ /** Accepted: Request accepted but not completed */
45
+ readonly ACCEPTED: 202;
46
+ /** Non-Authoritative Information */
47
+ readonly NON_AUTHORITATIVE_INFORMATION: 203;
48
+ /** No Content: Request succeeded, no body returned */
49
+ readonly NO_CONTENT: 204;
50
+ /** Reset Content: Clear form or view */
51
+ readonly RESET_CONTENT: 205;
52
+ /** Partial Content: Partial GET successful (e.g. range requests) */
53
+ readonly PARTIAL_CONTENT: 206;
54
+ /** Multi-Status (WebDAV) */
55
+ readonly MULTI_STATUS: 207;
56
+ /** Already Reported (WebDAV) */
57
+ readonly ALREADY_REPORTED: 208;
58
+ /** IM Used (HTTP Delta encoding) */
59
+ readonly IM_USED: 226;
60
+ /** Multiple Choices */
61
+ readonly MULTIPLE_CHOICES: 300;
62
+ /** Moved Permanently: Resource moved to a new URL */
63
+ readonly MOVED_PERMANENTLY: 301;
64
+ /** Found: Resource temporarily under different URI */
65
+ readonly FOUND: 302;
66
+ /** See Other: Redirect to another URI using GET */
67
+ readonly SEE_OTHER: 303;
68
+ /** Not Modified: Cached version is still valid */
69
+ readonly NOT_MODIFIED: 304;
70
+ /** Use Proxy: Deprecated */
71
+ readonly USE_PROXY: 305;
72
+ /** Temporary Redirect: Resource temporarily at another URI */
73
+ readonly TEMPORARY_REDIRECT: 307;
74
+ /** Permanent Redirect: Resource permanently at another URI */
75
+ readonly PERMANENT_REDIRECT: 308;
76
+ /** Bad Request: Malformed request */
77
+ readonly BAD_REQUEST: 400;
78
+ /** Unauthorized: Missing or invalid auth credentials */
79
+ readonly UNAUTHORIZED: 401;
80
+ /** Payment Required: Reserved for future use */
81
+ readonly PAYMENT_REQUIRED: 402;
82
+ /** Forbidden: Authenticated but no permission */
83
+ readonly FORBIDDEN: 403;
84
+ /** Not Found: Resource does not exist */
85
+ readonly NOT_FOUND: 404;
86
+ /** Method Not Allowed: HTTP method not allowed */
87
+ readonly METHOD_NOT_ALLOWED: 405;
88
+ /** Not Acceptable: Response not acceptable by client */
89
+ readonly NOT_ACCEPTABLE: 406;
90
+ /** Proxy Authentication Required */
91
+ readonly PROXY_AUTHENTICATION_REQUIRED: 407;
92
+ /** Request Timeout: Server timeout waiting for client */
93
+ readonly REQUEST_TIMEOUT: 408;
94
+ /** Conflict: Request conflict (e.g. duplicate resource) */
95
+ readonly CONFLICT: 409;
96
+ /** Gone: Resource is no longer available */
97
+ readonly GONE: 410;
98
+ /** Length Required: Missing Content-Length header */
99
+ readonly LENGTH_REQUIRED: 411;
100
+ /** Precondition Failed */
101
+ readonly PRECONDITION_FAILED: 412;
102
+ /** Payload Too Large */
103
+ readonly PAYLOAD_TOO_LARGE: 413;
104
+ /** URI Too Long */
105
+ readonly URI_TOO_LONG: 414;
106
+ /** Unsupported Media Type */
107
+ readonly UNSUPPORTED_MEDIA_TYPE: 415;
108
+ /** Range Not Satisfiable */
109
+ readonly RANGE_NOT_SATISFIABLE: 416;
110
+ /** Expectation Failed */
111
+ readonly EXPECTATION_FAILED: 417;
112
+ /** I'm a teapot: Joke response for coffee machines */
113
+ readonly IM_A_TEAPOT: 418;
114
+ /** Misdirected Request: Sent to the wrong server */
115
+ readonly MISDIRECTED_REQUEST: 421;
116
+ /** Unprocessable Entity (WebDAV) */
117
+ readonly UNPROCESSABLE_ENTITY: 422;
118
+ /** Locked (WebDAV) */
119
+ readonly LOCKED: 423;
120
+ /** Failed Dependency (WebDAV) */
121
+ readonly FAILED_DEPENDENCY: 424;
122
+ /** Too Early: Request might be replayed */
123
+ readonly TOO_EARLY: 425;
124
+ /** Upgrade Required */
125
+ readonly UPGRADE_REQUIRED: 426;
126
+ /** Precondition Required */
127
+ readonly PRECONDITION_REQUIRED: 428;
128
+ /** Too Many Requests: Rate limiting */
129
+ readonly TOO_MANY_REQUESTS: 429;
130
+ /** Request Header Fields Too Large */
131
+ readonly REQUEST_HEADER_FIELDS_TOO_LARGE: 431;
132
+ /** Unavailable For Legal Reasons */
133
+ readonly UNAVAILABLE_FOR_LEGAL_REASONS: 451;
134
+ /** Internal Server Error: Unhandled server error */
135
+ readonly INTERNAL_SERVER_ERROR: 500;
136
+ /** Not Implemented: Endpoint/method not implemented */
137
+ readonly NOT_IMPLEMENTED: 501;
138
+ /** Bad Gateway: Invalid response from upstream server */
139
+ readonly BAD_GATEWAY: 502;
140
+ /** Service Unavailable: Server temporarily overloaded/down */
141
+ readonly SERVICE_UNAVAILABLE: 503;
142
+ /** Gateway Timeout: No response from upstream server */
143
+ readonly GATEWAY_TIMEOUT: 504;
144
+ /** HTTP Version Not Supported */
145
+ readonly HTTP_VERSION_NOT_SUPPORTED: 505;
146
+ /** Variant Also Negotiates */
147
+ readonly VARIANT_ALSO_NEGOTIATES: 506;
148
+ /** Insufficient Storage (WebDAV) */
149
+ readonly INSUFFICIENT_STORAGE: 507;
150
+ /** Loop Detected (WebDAV) */
151
+ readonly LOOP_DETECTED: 508;
152
+ /** Not Extended */
153
+ readonly NOT_EXTENDED: 510;
154
+ /** Network Authentication Required */
155
+ readonly NETWORK_AUTHENTICATION_REQUIRED: 511;
156
+ };
157
+ /**
158
+ * An HTTP status code. The {@link Status} constants are suggested, but any
159
+ * number is assignable.
160
+ */
161
+ type Status = ValueOf<typeof Status> | (number & {});
162
+ /**
163
+ * Produces the events for a server-sent event stream, used by {@link Res.sse}.
164
+ *
165
+ * @param send - Emits one event. `data` is JSON-serialized; `event` names the
166
+ * event type for a client listening on something other than `message`, and `id`
167
+ * lets a client resume from where it left off.
168
+ * @returns Nothing when the source is finite — the stream is closed for you once
169
+ * it resolves — or a cleanup function when it is open-ended, in which case the
170
+ * stream stays open and the function runs if the client disconnects.
171
+ */
172
+ type SseSource = (send: (item: {
173
+ data: unknown;
174
+ event?: string;
175
+ id?: string;
176
+ }) => void) => MaybePromise<void | (() => void)>;
177
+ /**
178
+ * Produces the lines for a newline-delimited JSON stream, used by
179
+ * {@link Res.ndjson}.
180
+ *
181
+ * @param send - Emits one item, JSON-serialized on its own line.
182
+ * @returns Nothing to close the stream when the source resolves, or a cleanup
183
+ * function to keep it open and be told when the client disconnects.
184
+ */
185
+ type NdjsonSource = (send: (item: unknown) => void) => MaybePromise<void | (() => void)>;
186
+ /** A `ResponseInit` that can also carry cookies. */
187
+ interface ResInit extends ResponseInit {
188
+ /** Cookies to seed {@link Res.cookies} with. */
189
+ cookies?: Cookies;
190
+ }
191
+ /**
192
+ * A response under construction.
193
+ *
194
+ * Everything is mutable until {@link Res.toNativeResponse} is called, so a
195
+ * {@link Middleware} can adjust a response a route handler already built. The
196
+ * body is kept as the original value rather than serialized eagerly, which is
197
+ * what lets the content type be inferred from it at the very end.
198
+ *
199
+ * Headers and cookies are both lazy, so an untouched response allocates neither.
200
+ * The chainable methods — {@link Res.file}, {@link Res.redirect},
201
+ * {@link Res.sse} and the rest — set the body and its headers together and
202
+ * return `this`.
203
+ *
204
+ * @typeParam R - The body type, carried from the route's own response type.
205
+ */
206
+ declare class Res<R = unknown> {
207
+ /**
208
+ * Creates a response.
209
+ *
210
+ * @param body - The body value. Serialized by {@link resolveResBody} at
211
+ * {@link Res.toNativeResponse} time, not now.
212
+ * @param init - Status, status text, headers and cookies. See
213
+ * {@link ResInit}.
214
+ */
215
+ constructor(body?: Nullable<BodyInit | R>, init?: ResInit);
216
+ /**
217
+ * The body to send. Assign any value — objects become JSON, typed arrays stay
218
+ * binary, streams pass through — and {@link resolveResBody} works out the rest
219
+ * at serialization time.
220
+ */
221
+ body: Nullable<BodyInit | R>;
222
+ /** The status code. Defaults to {@link Status.OK}. */
223
+ status: number;
224
+ /** The status text. Empty by default, which lets the runtime supply the standard phrase. */
225
+ statusText: string;
226
+ /** Backing store for {@link Res.headers}, created on first access. */
227
+ private _headers;
228
+ /**
229
+ * The response headers.
230
+ *
231
+ * Reading them rewrites the `Set-Cookie` lines from {@link Res.cookies} first,
232
+ * so the two views never disagree — and writing `Set-Cookie` here feeds back
233
+ * into the cookie map. Values may be numbers or booleans, since
234
+ * {@link patchGlobalHeaders} has stringified setters.
235
+ *
236
+ * @returns The headers, created on first access.
237
+ */
238
+ get headers(): Headers;
239
+ /** Backing store for {@link Res.cookies}, created on first access. */
240
+ private _cookies;
241
+ /**
242
+ * The cookies to send, as a mutable map.
243
+ *
244
+ * This is the authoritative view: the map is serialized into `Set-Cookie`
245
+ * whenever {@link Res.headers} is read, so deleting a cookie here removes its
246
+ * header. Values are percent-encoded on serialization, which is what keeps a
247
+ * CRLF in a cookie value from splitting the response.
248
+ *
249
+ * @returns The {@link Cookies} map, created on first access.
250
+ */
251
+ get cookies(): Cookies;
252
+ /**
253
+ * Serializes everything into a native `Response`.
254
+ *
255
+ * The content type inferred from the body is applied only when none was set
256
+ * explicitly, so a handler's own choice always wins. `X-Content-Type-Options:
257
+ * nosniff` is set unconditionally — without it a browser will sniff a
258
+ * `text/plain` body that looks like markup and render it as HTML, turning any
259
+ * reflected value into XSS.
260
+ *
261
+ * @returns The response to send over the wire. Called by
262
+ * {@link App.respond}.
263
+ */
264
+ toNativeResponse(): Response;
265
+ /**
266
+ * Turns the response into a server-sent event stream.
267
+ *
268
+ * Sets the body to a stream and the headers browsers require for `EventSource`
269
+ * to work — the event stream type, no caching, and a kept-alive connection.
270
+ *
271
+ * @param source - The {@link SseSource} producing events. Return a cleanup
272
+ * function from it to keep the stream open indefinitely.
273
+ * @param retry - Reconnection delay in milliseconds, sent with every event to
274
+ * tell the client how long to wait before reconnecting.
275
+ * @returns This response, for chaining.
276
+ */
277
+ sse(source: SseSource, retry?: number): this;
278
+ /**
279
+ * Turns the response into a newline-delimited JSON stream.
280
+ *
281
+ * Each item is serialized onto its own line, so a client can parse results as
282
+ * they arrive instead of waiting for a whole array. Useful for large result
283
+ * sets and progressive output where the event semantics of {@link Res.sse} are
284
+ * not needed.
285
+ *
286
+ * @param source - The {@link NdjsonSource} producing items. Return a cleanup
287
+ * function from it to keep the stream open indefinitely.
288
+ * @returns This response, for chaining.
289
+ */
290
+ ndjson(source: NdjsonSource): this;
291
+ /**
292
+ * Streams a file as the response body, without reading it into memory. Prefer
293
+ * this over {@link Res.file} for anything large.
294
+ *
295
+ * @param fileOrPath - An {@link XFile} or a path to one.
296
+ * @param disposition - `"inline"` to display in the browser, `"attachment"` to
297
+ * prompt a download under the file's own name.
298
+ * @returns This response, for chaining.
299
+ * @throws {@link Exception} with {@link Status.NOT_FOUND} when the file does
300
+ * not exist.
301
+ */
302
+ streamFile(fileOrPath: XFile | string, disposition: ContentDispositionDefinition["disposition"]): this;
303
+ /**
304
+ * Sends a file as the response body, read into memory so it can carry an exact
305
+ * `Content-Length`. Use {@link Res.streamFile} instead for large files.
306
+ *
307
+ * @param fileOrPath - An {@link XFile} or a path to one.
308
+ * @returns This response, for chaining.
309
+ * @throws {@link Exception} with {@link Status.NOT_FOUND} when the file does
310
+ * not exist.
311
+ */
312
+ file(fileOrPath: XFile | string): this;
313
+ /**
314
+ * Redirects the client to another URL.
315
+ *
316
+ * @param url - Where to send the client, absolute or relative.
317
+ * @param status - Which redirect to use. Defaults to {@link Status.FOUND}, a
318
+ * temporary redirect that browsers do not cache. See
319
+ * {@link Res.permanentRedirect}, {@link Res.temporaryRedirect} and
320
+ * {@link Res.seeOther} for the named alternatives.
321
+ * @returns This response, for chaining.
322
+ */
323
+ redirect(url: string | URL, status?: 301 | 302 | 303 | 307 | 308): this;
324
+ /**
325
+ * Redirects with {@link Status.MOVED_PERMANENTLY}, which browsers and search
326
+ * engines cache indefinitely. Use it only when the resource has really moved
327
+ * for good.
328
+ *
329
+ * @param url - Where to send the client.
330
+ * @returns This response, for chaining.
331
+ */
332
+ permanentRedirect(url: string | URL): this;
333
+ /**
334
+ * Redirects with {@link Status.TEMPORARY_REDIRECT}, which preserves the
335
+ * original method and body — unlike {@link Status.FOUND}, which clients
336
+ * commonly turn into a GET.
337
+ *
338
+ * @param url - Where to send the client.
339
+ * @returns This response, for chaining.
340
+ */
341
+ temporaryRedirect(url: string | URL): this;
342
+ /**
343
+ * Redirects with {@link Status.SEE_OTHER}, which explicitly switches the
344
+ * client to a GET. This is the correct redirect after a successful POST, since
345
+ * it stops a refresh from resubmitting the form.
346
+ *
347
+ * @param url - Where to send the client.
348
+ * @returns This response, for chaining.
349
+ */
350
+ seeOther(url: string | URL): this;
351
+ }
352
+ export { Res, Status };
353
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Res/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAGN,KAAK,4BAA4B,EACjC,MAAM,WAAW,CAAC;AACnB,OAAO,EACN,KAAK,YAAY,EACjB,KAAK,QAAQ,EAKb,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,uCAAuC;AACvC,QAAA,MAAM,MAAM;IACX,kDAAkD;;IAElD,4DAA4D;;IAE5D,0BAA0B;;IAE1B,kBAAkB;;IAElB,4BAA4B;;IAE5B,gCAAgC;;IAEhC,mDAAmD;;IAEnD,oCAAoC;;IAEpC,sDAAsD;;IAEtD,wCAAwC;;IAExC,oEAAoE;;IAEpE,4BAA4B;;IAE5B,gCAAgC;;IAEhC,oCAAoC;;IAEpC,uBAAuB;;IAEvB,qDAAqD;;IAErD,sDAAsD;;IAEtD,mDAAmD;;IAEnD,kDAAkD;;IAElD,4BAA4B;;IAE5B,8DAA8D;;IAE9D,8DAA8D;;IAE9D,qCAAqC;;IAErC,wDAAwD;;IAExD,gDAAgD;;IAEhD,iDAAiD;;IAEjD,yCAAyC;;IAEzC,kDAAkD;;IAElD,wDAAwD;;IAExD,oCAAoC;;IAEpC,yDAAyD;;IAEzD,2DAA2D;;IAE3D,4CAA4C;;IAE5C,qDAAqD;;IAErD,0BAA0B;;IAE1B,wBAAwB;;IAExB,mBAAmB;;IAEnB,6BAA6B;;IAE7B,4BAA4B;;IAE5B,yBAAyB;;IAEzB,sDAAsD;;IAEtD,oDAAoD;;IAEpD,oCAAoC;;IAEpC,sBAAsB;;IAEtB,iCAAiC;;IAEjC,2CAA2C;;IAE3C,uBAAuB;;IAEvB,4BAA4B;;IAE5B,uCAAuC;;IAEvC,sCAAsC;;IAEtC,oCAAoC;;IAEpC,oDAAoD;;IAEpD,uDAAuD;;IAEvD,yDAAyD;;IAEzD,8DAA8D;;IAE9D,wDAAwD;;IAExD,iCAAiC;;IAEjC,8BAA8B;;IAE9B,oCAAoC;;IAEpC,6BAA6B;;IAE7B,mBAAmB;;IAEnB,sCAAsC;;CAE7B,CAAC;AAEX;;;GAGG;AACH,KAAK,MAAM,GAAG,OAAO,CAAC,OAAO,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAyDrD;;;;;;;;;GASG;AACH,KAAK,SAAS,GAAG,CAChB,IAAI,EAAE,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,KAChE,YAAY,CAAC,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;AAEvC;;;;;;;GAOG;AACH,KAAK,YAAY,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,KAAK,YAAY,CAAC,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;AA0GzF,oDAAoD;AACpD,UAAU,OAAQ,SAAQ,YAAY;IACrC,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;GAcG;AACH,cAAM,GAAG,CAAC,CAAC,GAAG,OAAO;IACpB;;;;;;;OAOG;gBACS,IAAI,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,OAAO;IAiCzD;;;;OAIG;IACH,IAAI,EAAE,QAAQ,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAQ;IAEpC,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IAEf,4FAA4F;IAC5F,UAAU,EAAE,MAAM,CAAC;IAEnB,sEAAsE;IACtE,OAAO,CAAC,QAAQ,CAAmB;IAEnC;;;;;;;;;OASG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,sEAAsE;IACtE,OAAO,CAAC,QAAQ,CAAgB;IAEhC;;;;;;;;;OASG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;;;;;;;;;OAWG;IACH,gBAAgB,IAAI,QAAQ;IAkB5B;;;;;;;;;;;OAWG;IACH,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAoB5C;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAclC;;;;;;;;;;OAUG;IACH,UAAU,CACT,UAAU,EAAE,KAAK,GAAG,MAAM,EAC1B,WAAW,EAAE,4BAA4B,CAAC,aAAa,CAAC,GACtD,IAAI;IAeP;;;;;;;;OAQG;IACH,IAAI,CAAC,UAAU,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI;IAStC;;;;;;;;;OASG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,MAAM,GAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAS,GAAG,IAAI;IAO5E;;;;;;;OAOG;IACH,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAI1C;;;;;;;OAOG;IACH,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAI1C;;;;;;;OAOG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;CAGjC;AAED,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC"}
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Serving for a directory of built front-end files: hashed assets, an entry
3
+ * document, and per-file-class caching.
4
+ *
5
+ * {@link BundleRoute} is the {@link RouteVariant.bundle} member of the
6
+ * {@link RouteBase} family. It serves any directory of servable files, deriving
7
+ * cache headers from what kind of file each one is — immutable for build-hashed
8
+ * assets, revalidated for the entry document, and a configurable fallback for
9
+ * everything else. Its distinguishing behaviour is the entry-document fallback:
10
+ * a path that resolves to no file is answered with the entry HTML instead of a
11
+ * 404, which is what makes a single-page app survive a hard refresh on a client
12
+ * route. That fallback is the main use, not the only one — {@link StaticRoute}
13
+ * remains the plainer choice when a bundle's caching and fallback behaviour is
14
+ * not wanted.
15
+ *
16
+ * ```ts
17
+ * new BundleRoute("/*", "./dist");
18
+ * ```
19
+ *
20
+ * @module BundleRoute
21
+ */
22
+ import type { ContextHandler } from "../../Context";
23
+ import { type CacheControlDefinition } from "../../Headers";
24
+ import { Method } from "../../Request";
25
+ import { type Res } from "../../Res";
26
+ import { RouteBase, RouteVariant, type RouteConfig } from "..";
27
+ import { type MaybePromise } from "../../utils/is";
28
+ import { type Tuple } from "../../utils/tuple";
29
+ import { XFile } from "../../XFile";
30
+ /**
31
+ * A {@link CacheControlDefinition} that also names the path it applies to,
32
+ * relative to {@link BundleRoute.dir}.
33
+ */
34
+ interface CacheControlDefinitionWithPath extends CacheControlDefinition {
35
+ /**
36
+ * Path relative to {@link BundleRoute.dir}. Falls back to the corresponding
37
+ * {@link DEFAULT_DEFINITION} value when omitted.
38
+ */
39
+ path?: string;
40
+ }
41
+ /**
42
+ * Describes the layout of a bundle directory and the caching policy for each
43
+ * class of file within it. See {@link DEFAULT_DEFINITION} for the values used
44
+ * when this is not supplied.
45
+ */
46
+ interface BundleRouteDefinition {
47
+ /**
48
+ * The entry document — its path within the bundle, and how it should be
49
+ * cached. Also the file served by the fallback in
50
+ * {@link BundleRoute.resolveFile}.
51
+ */
52
+ indexHtml: CacheControlDefinitionWithPath;
53
+ /**
54
+ * The directory holding build-hashed assets, and how they should be cached.
55
+ * Files below it are matched by path segment, not by extension.
56
+ */
57
+ assetsDir: CacheControlDefinitionWithPath;
58
+ /**
59
+ * Caching for every file that is neither the entry document nor under the
60
+ * assets directory. Omit it to send no `Cache-Control` for those files.
61
+ */
62
+ fallback?: CacheControlDefinition;
63
+ }
64
+ /**
65
+ * What a {@link BundleRoute} handler resolves to: a stream for non-HTML files,
66
+ * bytes for HTML, or a string or {@link Res} when
67
+ * {@link BundleRoute.onFileNotFound} is overridden to return one.
68
+ */
69
+ type BundleRouteRes = ReadableStream<Uint8Array> | Uint8Array | string | Res;
70
+ /**
71
+ * Serves a directory of built files.
72
+ *
73
+ * Register it on a wildcard endpoint so every path below it reaches the route.
74
+ * A request resolves in three steps: the endpoint prefix is stripped to a
75
+ * sub-path by {@link BundleRoute.resolveSubPath}, the sub-path is joined onto
76
+ * {@link BundleRoute.dir} by {@link BundleRoute.resolveTargetPath}, and
77
+ * {@link BundleRoute.resolveFile} serves the result if it exists. When it does
78
+ * not and the request is not for an HTML file, the entry document named by
79
+ * {@link BundleRoute.indexHtmlPath} is served instead.
80
+ *
81
+ * Files are matched against {@link BundleRoute.definition} to pick their
82
+ * `Cache-Control`: the entry document, anything under
83
+ * {@link BundleRoute.assetsDirPath}, and everything else each get their own
84
+ * policy.
85
+ *
86
+ * Paths that escape {@link BundleRoute.dir} are rejected by
87
+ * {@link BundleRoute.isTraversalAttempt} before the filesystem is touched, so
88
+ * `..` segments cannot reach files outside the directory.
89
+ *
90
+ * @typeParam E - The literal endpoint type, carried so the endpoint stays
91
+ * narrowly typed at the call site.
92
+ */
93
+ declare class BundleRoute<E extends string = string> extends RouteBase<never, never, never, BundleRouteRes, E> {
94
+ /**
95
+ * Creates a bundle route for subclasses, which declare
96
+ * {@link BundleRoute.endpoint} and {@link BundleRoute.dir} as class fields and
97
+ * call {@link RouteBase.register} themselves.
98
+ */
99
+ constructor();
100
+ /**
101
+ * Creates a bundle route and registers it on the nearest {@link App}.
102
+ *
103
+ * @param endpoint - The path to serve the directory under. Use a wildcard so
104
+ * nested paths reach the route.
105
+ * @param dir - Directory to serve from. Every resolved path is confined to it.
106
+ * @param definition - Optional {@link BundleRouteDefinition} overriding the
107
+ * bundle layout and caching policy. Defaults to {@link DEFAULT_DEFINITION}.
108
+ */
109
+ constructor(endpoint: E, dir: string, definition?: BundleRouteDefinition);
110
+ /**
111
+ * Directory the files are served from. Every path resolved by the route is
112
+ * confined to it.
113
+ */
114
+ dir: string;
115
+ /**
116
+ * Sub-paths that are answered with the entry document rather than the file
117
+ * they name. A trailing `*` makes a pattern a prefix match; leading slashes
118
+ * are optional.
119
+ *
120
+ * Useful when a client-side route collides with a real file in the directory,
121
+ * or to keep a build artefact from being reachable.
122
+ */
123
+ ignore: Array<string>;
124
+ /**
125
+ * The bundle's layout and caching policy. Defaults to
126
+ * {@link DEFAULT_DEFINITION}.
127
+ */
128
+ definition: BundleRouteDefinition;
129
+ /**
130
+ * Path of the entry document within {@link BundleRoute.dir}.
131
+ *
132
+ * @returns The path from {@link BundleRouteDefinition.indexHtml}, or the
133
+ * {@link DEFAULT_DEFINITION} value when it declares none.
134
+ */
135
+ get indexHtmlPath(): string;
136
+ /**
137
+ * Path of the hashed-assets directory within {@link BundleRoute.dir}.
138
+ *
139
+ * @returns The path from {@link BundleRouteDefinition.assetsDir}, or the
140
+ * {@link DEFAULT_DEFINITION} value when it declares none.
141
+ */
142
+ get assetsDirPath(): string;
143
+ /**
144
+ * Lists every file this route can serve, as sub-paths relative to
145
+ * {@link BundleRoute.dir}.
146
+ *
147
+ * Walks {@link BundleRoute.dir} recursively and returns each file's path
148
+ * with a leading `/`, matching what {@link BundleRoute.resolveSubPath} would
149
+ * produce for a request reaching that file. Useful for generating a sitemap
150
+ * or verifying what a deployed bundle actually contains.
151
+ *
152
+ * @returns The sub-paths of every file under {@link BundleRoute.dir}.
153
+ */
154
+ getEndpoints(): Array<string>;
155
+ /**
156
+ * Decides what to serve when a request resolves to no readable file — an HTML
157
+ * file that is genuinely missing, a directory with no entry document, or a
158
+ * path rejected by {@link BundleRoute.isTraversalAttempt}.
159
+ *
160
+ * Replace it to serve a custom 404 page or redirect instead of throwing.
161
+ *
162
+ * @param subPath - The request path with the endpoint prefix stripped, as the
163
+ * client asked for it.
164
+ * @returns The {@link BundleRouteRes} to send instead.
165
+ * @throws {@link Exception} with {@link Status.NOT_FOUND} by default.
166
+ */
167
+ onFileNotFound: (subPath: string) => MaybePromise<BundleRouteRes>;
168
+ /**
169
+ * Resolves a filesystem path to a readable {@link XFile}, applying the
170
+ * entry-document fallback.
171
+ *
172
+ * A missing non-HTML path falls back to the entry document, which is what
173
+ * serves client-side routes. A missing HTML path does not fall back — asking
174
+ * for a specific document that does not exist is a real 404 rather than a
175
+ * client route.
176
+ *
177
+ * @param targetPath - Path produced by {@link BundleRoute.resolveTargetPath}.
178
+ * @returns The {@link XFile} to serve, or `null` when nothing readable was
179
+ * found, which sends the request to {@link BundleRoute.onFileNotFound}.
180
+ */
181
+ protected resolveFile(targetPath: string): XFile | null;
182
+ /**
183
+ * Strips the route's own prefix from a request pathname, leaving the path
184
+ * relative to {@link BundleRoute.dir}.
185
+ *
186
+ * Both `/*` and `*` endpoint suffixes are handled, and a pathname that does
187
+ * not start with the prefix is returned untouched. The result is percent-decoded,
188
+ * since {@link URL.pathname} leaves escapes like `%20` intact and filesystem
189
+ * paths need the literal characters.
190
+ *
191
+ * @param pathname - The pathname of the incoming request.
192
+ * @returns The bundle-relative sub-path, `""` or `/` for the route root.
193
+ */
194
+ protected resolveSubPath(pathname: string): string;
195
+ /**
196
+ * Joins a sub-path onto {@link BundleRoute.dir} to get the file to read.
197
+ *
198
+ * The route root maps to the entry document, as does any sub-path matching
199
+ * {@link BundleRoute.ignore}. The result is not yet known to be safe —
200
+ * {@link BundleRoute.isTraversalAttempt} checks it before it is opened.
201
+ *
202
+ * @param subPath - The sub-path from {@link BundleRoute.resolveSubPath}.
203
+ * @returns The joined filesystem path.
204
+ */
205
+ protected resolveTargetPath(subPath: string): string;
206
+ /**
207
+ * Reports whether a resolved path escapes {@link BundleRoute.dir}.
208
+ *
209
+ * Both sides are fully resolved before comparison, so `..` segments and
210
+ * encoded variants are normalised away rather than matched textually. The
211
+ * separator check keeps a sibling directory sharing the root's name prefix
212
+ * from passing.
213
+ *
214
+ * @param targetPath - Path from {@link BundleRoute.resolveTargetPath}.
215
+ * @returns `true` when the path lies outside the served directory, in which
216
+ * case the request goes to {@link BundleRoute.onFileNotFound} without the file
217
+ * being opened.
218
+ */
219
+ protected isTraversalAttempt(targetPath: string): boolean;
220
+ /**
221
+ * Produces the response body and headers for a resolved file.
222
+ *
223
+ * `Cache-Control` is chosen by matching the file against
224
+ * {@link BundleRoute.definition}: the entry document first, then anything
225
+ * under {@link BundleRoute.assetsDirPath}, then
226
+ * {@link BundleRouteDefinition.fallback}. No fallback means no header.
227
+ *
228
+ * Non-HTML files are streamed and carry an inline
229
+ * `Content-Disposition`, so large assets are never buffered. HTML is read into
230
+ * memory instead, which lets it carry an exact `Content-Length` — the entry
231
+ * document is small and served constantly, so the length is worth more than
232
+ * the streaming.
233
+ *
234
+ * @param file - The {@link XFile} resolved for the request.
235
+ * @returns A {@link Tuple} of the body and the headers to set on
236
+ * {@link Res.headers}.
237
+ */
238
+ protected resolveResponseData(file: XFile): Tuple<ReadableStream | Uint8Array, Record<string, string>>;
239
+ /** Marks this route as {@link RouteVariant.bundle} for {@link App} route compilation. */
240
+ readonly variant: RouteVariant;
241
+ /** Bundles answer {@link Method.GET} only. */
242
+ readonly method: Method;
243
+ /**
244
+ * The path the directory is served under. Use a wildcard so nested paths reach
245
+ * the route; {@link BundleRoute.resolveSubPath} strips the wildcard suffix.
246
+ */
247
+ endpoint: E;
248
+ /**
249
+ * Bundles take no params, search or body, so no {@link RouteConfig} schemas
250
+ * apply.
251
+ */
252
+ readonly config?: RouteConfig<never, never, never, BundleRouteRes>;
253
+ /**
254
+ * Serves the file a request resolves to.
255
+ *
256
+ * Resolves the sub-path and target path, rejects traversal attempts, reads the
257
+ * file, then sets the headers from {@link BundleRoute.resolveResponseData} on
258
+ * {@link Context.res} and returns the body. Anything that fails to resolve
259
+ * goes to {@link BundleRoute.onFileNotFound}.
260
+ *
261
+ * @param c - The {@link Context} for the request.
262
+ * @returns The file body — a stream for non-HTML, bytes for HTML — or whatever
263
+ * {@link BundleRoute.onFileNotFound} produced.
264
+ */
265
+ handler: ContextHandler<never, never, never, BundleRouteRes>;
266
+ }
267
+ export { BundleRoute };
268
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/RouteBase/BundleRoute/index.ts"],"names":[],"mappings":"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"}