@orieljs/http 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.
@@ -0,0 +1,480 @@
1
+ import { HttpRequest, CookieJar, Session, Container, RedirectResponse, HeadersInit, Redirector, UploadedFile, Rules, OrielError, ResponseFactory, BodyInit, UrlGenerator, HttpKernel, Application, MiddlewareClass, Middleware, Next, MiddlewareConfigurator, Router, ConfigRepository, ExceptionHandler, ExceptionsConfigurator, ConsoleKernel, Route } from '@orieljs/contracts';
2
+ import { IncomingMessage, ServerResponse } from 'node:http';
3
+ import { ServiceProvider } from '@orieljs/support';
4
+
5
+ /** Reads a request body into memory, refusing more than `limit` bytes (413), like PHP's post_max_size. */
6
+ declare function readBody(raw: Request, limit: number | null): Promise<Uint8Array>;
7
+
8
+ /** The current container, only when it is a request scope (the kernel binds HttpRequest there). */
9
+ declare function requestScope(): Container | undefined;
10
+ declare function currentRequest(): HttpRequest | undefined;
11
+ /** The request's session, or undefined outside a request or when no Session provider is registered. */
12
+ declare function optionalSession(): Session | undefined;
13
+ declare function optionalCookieJar(): CookieJar | undefined;
14
+
15
+ type ErrorsInput = Record<string, string | string[]> | {
16
+ toObject(): Record<string, string[]>;
17
+ };
18
+ /**
19
+ * Laravel's RedirectResponse. with()/withErrors()/withInput() flash to the request's Session immediately, like
20
+ * Laravel; without a bound Session (an API-only app) they are skipped silently.
21
+ */
22
+ declare class HttpRedirectResponse implements RedirectResponse {
23
+ #private;
24
+ readonly targetUrl: string;
25
+ readonly status: number;
26
+ constructor(targetUrl: string, status?: number, headers?: HeadersInit);
27
+ with(key: string | Record<string, unknown>, value?: unknown): this;
28
+ /** Flashes `errors` as { [bag]: { field: string[] } }, keeping the other bags already flashed. */
29
+ withErrors(errors: ErrorsInput, bag?: string): this;
30
+ /** Flashes `input`, or the current request's input (files are never part of input()). */
31
+ withInput(input?: Record<string, unknown>): this;
32
+ /**
33
+ * Always a Set-Cookie header on this response (Laravel's RedirectResponse::withCookie). A bound CookieJar only
34
+ * supplies the defaults (path, domain, secure, same-site); queueing would lose the cookie outside the web group.
35
+ */
36
+ withCookie(name: string, value: string, minutes?: number): this;
37
+ header(name: string, value: string): this;
38
+ toResponse(): Response;
39
+ }
40
+
41
+ /** Laravel's Redirector. Stateless: the URL generator and session come from the current container. */
42
+ declare class HttpRedirector implements Redirector {
43
+ to(path: string, status?: number, headers?: HeadersInit): HttpRedirectResponse;
44
+ route(name: string, parameters?: unknown, status?: number): HttpRedirectResponse;
45
+ back(fallback?: string, status?: number): HttpRedirectResponse;
46
+ /** Pulls url.intended from the session (put there by guest()), else goes to `fallback`. */
47
+ intended(fallback?: string, status?: number): HttpRedirectResponse;
48
+ away(url: string, status?: number): HttpRedirectResponse;
49
+ /** Remembers where a guest was going (a GET page, else the previous URL), then redirects to `path`. */
50
+ guest(path: string, status?: number): HttpRedirectResponse;
51
+ setIntendedUrl(url: string): void;
52
+ refresh(status?: number): HttpRedirectResponse;
53
+ }
54
+
55
+ declare function setClientAddress(request: Request, address: string | undefined): void;
56
+ declare function clientAddress(request: Request): string | undefined;
57
+
58
+ /** An uploaded file from a multipart body. store()/storeAs() go through the FilesystemManager. */
59
+ declare class FormUploadedFile implements UploadedFile {
60
+ private readonly file;
61
+ readonly clientName: string;
62
+ readonly mimeType: string;
63
+ readonly size: number;
64
+ constructor(file: Blob & {
65
+ readonly name?: string;
66
+ });
67
+ /** Guessed from the MIME type, falling back to the client's extension (Laravel's extension()). */
68
+ extension(): string;
69
+ clientExtension(): string;
70
+ /** A random 40-character name with the guessed extension. */
71
+ hashName(): string;
72
+ arrayBuffer(): Promise<ArrayBuffer>;
73
+ text(): Promise<string>;
74
+ stream(): ReadableStream<Uint8Array>;
75
+ store(directory: string, disk?: string): Promise<string>;
76
+ storeAs(directory: string, name: string, disk?: string): Promise<string>;
77
+ }
78
+
79
+ interface IncomingRequestOptions {
80
+ /** Proxy addresses whose X-Forwarded-* headers are believed: exact IPs, IPv4 CIDRs, or '*'. */
81
+ trustedProxies?: readonly string[];
82
+ /** Largest request body in bytes before a 413 (config http.max_body_size); null is unlimited. Default 8 MB. */
83
+ maxBodySize?: number | null;
84
+ }
85
+ /** Exact match, IPv4 CIDR ('10.0.0.0/8') or '*'. */
86
+ declare function ipMatches(ip: string, patterns: readonly string[]): boolean;
87
+ /**
88
+ * The HttpRequest implementation (Laravel's Illuminate\Http\Request). The kernel calls load() once, before any
89
+ * middleware, so every accessor below is synchronous.
90
+ *
91
+ * `http.max_body_size` applies to the bodies this class parses (JSON, urlencoded and multipart). A handler that reads
92
+ * `request.raw` directly bypasses it and must enforce its own limit.
93
+ */
94
+ declare class IncomingRequest implements HttpRequest {
95
+ #private;
96
+ readonly raw: Request;
97
+ constructor(raw: Request, options?: IncomingRequestOptions);
98
+ /** Reads and parses the body (JSON, urlencoded or multipart) once, then applies method spoofing. */
99
+ load(): Promise<this>;
100
+ method(): string;
101
+ isMethod(method: string): boolean;
102
+ /** The scheme and host, honouring X-Forwarded-Proto/Host from trusted proxies. */
103
+ root(): string;
104
+ /** The URL without the query string or a trailing slash. */
105
+ url(): string;
106
+ fullUrl(): string;
107
+ /** 'posts/1', or '/' for the root. */
108
+ path(): string;
109
+ decodedPath(): string;
110
+ secure(): boolean;
111
+ /** request.is('admin/*'): wildcard match against the decoded path. */
112
+ is(...patterns: string[]): boolean;
113
+ routeIs(...names: string[]): boolean;
114
+ header(name: string): string | undefined;
115
+ header(name: string, defaultValue: string): string;
116
+ bearerToken(): string | undefined;
117
+ userAgent(): string | undefined;
118
+ /** The socket address, or the right-most untrusted X-Forwarded-For entry when the socket is a trusted proxy. */
119
+ ip(): string | undefined;
120
+ ajax(): boolean;
121
+ pjax(): boolean;
122
+ /** The first Accept type is JSON. */
123
+ wantsJson(): boolean;
124
+ /** Laravel: (ajax and not pjax and accepts anything) or wantsJson. */
125
+ expectsJson(): boolean;
126
+ /** The raw body text for JSON and urlencoded requests ('' otherwise; the raw stream stays unread for other types). */
127
+ content(): string;
128
+ query<T = unknown>(key?: string, defaultValue?: T): T;
129
+ /** Body wins over the query string (PHP's $body + $query). Files are not input. */
130
+ input<T = unknown>(key?: string, defaultValue?: T): T;
131
+ /** Input plus files (array_replace_recursive). */
132
+ all(): Record<string, unknown>;
133
+ only(...keys: Array<string | string[]>): Record<string, unknown>;
134
+ except(...keys: Array<string | string[]>): Record<string, unknown>;
135
+ has(...keys: Array<string | string[]>): boolean;
136
+ hasAny(...keys: Array<string | string[]>): boolean;
137
+ missing(...keys: Array<string | string[]>): boolean;
138
+ filled(key: string): boolean;
139
+ string(key: string, defaultValue?: string): string;
140
+ /** PHP's FILTER_VALIDATE_BOOLEAN: '1', 'true', 'on', 'yes' (any case) and true are true. */
141
+ boolean(key: string, defaultValue?: boolean): boolean;
142
+ /** PHP's intval: leading digits, else 0. */
143
+ integer(key: string, defaultValue?: number): number;
144
+ /** Adds or replaces top-level body values. */
145
+ merge(values: Record<string, unknown>): this;
146
+ /** Rewrites every scalar in the query and the body (TrimStrings and ConvertEmptyStringsToNull use this). */
147
+ transformInput(transform: (key: string, value: unknown) => unknown): this;
148
+ file(key: string): UploadedFile | undefined;
149
+ hasFile(key: string): boolean;
150
+ allFiles(): Record<string, unknown>;
151
+ cookie(name: string): string | undefined;
152
+ cookies(): Record<string, string>;
153
+ /** Replaces the parsed cookies (EncryptCookies calls this after decrypting). */
154
+ setCookies(cookies: Record<string, string>): void;
155
+ /** One route parameter (after model binding), or all of them. */
156
+ route<T = unknown>(key?: string): T;
157
+ session(): Session;
158
+ user<T = unknown>(guard?: string): T | undefined;
159
+ setUserResolver(resolver: (guard?: string) => unknown): void;
160
+ /** Validates all() through the ValidationFactory; throws its Validation error on failure. */
161
+ validate<T = Record<string, unknown>>(rules: Rules, messages?: Record<string, string>, attributes?: Record<string, string>): Promise<T>;
162
+ }
163
+
164
+ /** Helpers for request input: PHP-style bracket keys, safe cloning (no prototype pollution) and blank checks. */
165
+ type Tree = Record<string, unknown>;
166
+ /** 'user[name]' → ['user', 'name']; 'tags[]' → ['tags', '']; a malformed key stays whole. */
167
+ declare function parseBracketKey(name: string): string[];
168
+ /** Objects whose keys are exactly 0..n-1 become arrays, recursively (PHP arrays → JS lists). */
169
+ declare function normalizeLists(value: unknown): unknown;
170
+ /**
171
+ * Builds nested input from flat form entries, PHP style: 'user[name]', 'tags[]', 'a[b][]'.
172
+ * Keys containing __proto__/prototype/constructor are dropped.
173
+ */
174
+ declare function fromEntries(entries: Iterable<readonly [string, unknown]>): Tree;
175
+ /** Deep copy of parsed JSON without dangerous keys (JSON.parse creates an own "__proto__" property). */
176
+ declare function sanitize(value: unknown): unknown;
177
+ /** array_replace_recursive: `override` wins, nested plain objects merge. */
178
+ declare function mergeRecursive(base: Tree, override: Tree): Tree;
179
+ /** Laravel's blank(): null, undefined, whitespace-only strings, and empty arrays/objects. */
180
+ declare function isBlank(value: unknown): boolean;
181
+ /** Applies `transform(dottedKey, value)` to every scalar leaf, inside nested objects and lists; the result replaces the leaf. */
182
+ declare function transformLeaves(tree: Tree, transform: (key: string, value: unknown) => unknown, prefix?: string): Tree;
183
+
184
+ /** 'report.PDF' or 'pdf' → 'application/pdf'; unknown → 'application/octet-stream'. */
185
+ declare function mimeFromExtension(pathOrExtension: string): string;
186
+ /** 'image/jpeg; charset=…' → 'jpg'; unknown → undefined. */
187
+ declare function extensionFromMime(type: string): string | undefined;
188
+
189
+ /** Symfony's HttpException: abort(404), abort(403, 'Nope'). An empty message renders as the status text. */
190
+ declare class HttpException extends Error implements OrielError {
191
+ readonly status: number;
192
+ readonly headers: Record<string, string>;
193
+ readonly kind: "Http";
194
+ readonly name = "HttpException";
195
+ constructor(status: number, message?: string, headers?: Record<string, string>);
196
+ }
197
+ /** Carries a ready Response out of deep code: abort(response). The handler returns it as is. */
198
+ declare class HttpResponseException extends Error implements OrielError {
199
+ readonly response: Response;
200
+ readonly kind: "Http";
201
+ readonly name = "HttpResponseException";
202
+ readonly status: number;
203
+ constructor(response: Response);
204
+ }
205
+ /** Http's internal failures (not thrown by this package itself; used by the kernel and error rendering). */
206
+ declare class HttpServerError extends Error implements OrielError {
207
+ readonly kind: "Server";
208
+ readonly status = 500;
209
+ readonly name = "HttpServerError";
210
+ }
211
+
212
+ /** request() → the current HttpRequest; request('key', default) → its input. */
213
+ declare function request(): HttpRequest;
214
+ declare function request<T = unknown>(key: string, defaultValue?: T): T;
215
+ /** response() → the ResponseFactory; response(content, status, headers) → a Response. */
216
+ declare function response(): ResponseFactory;
217
+ declare function response(content: BodyInit | null, status?: number, headers?: HeadersInit): Response;
218
+ /** redirect() → the Redirector; redirect('/path', status) → a RedirectResponse. */
219
+ declare function redirect(): Redirector;
220
+ declare function redirect(to: string, status?: number): RedirectResponse;
221
+ /** Redirect to the previous URL (same argument order as Redirector.back()). */
222
+ declare function back(fallback?: string, status?: number): RedirectResponse;
223
+ /** url() → the UrlGenerator; url('/path', query, absolute) → a URL. */
224
+ declare function url(): UrlGenerator;
225
+ declare function url(path: string, query?: Record<string, unknown>, absolute?: boolean): string;
226
+ /** The URL of a named route. */
227
+ declare function route(name: string, parameters?: unknown, absolute?: boolean): string;
228
+ /** abort(404), abort(403, 'Nope', headers), or abort(response) to send a ready response. */
229
+ declare function abort(status: number | Response, message?: string, headers?: Record<string, string>): never;
230
+ declare function abortIf(condition: unknown, status: number | Response, message?: string, headers?: Record<string, string>): void;
231
+ declare function abortUnless(condition: unknown, status: number | Response, message?: string, headers?: Record<string, string>): void;
232
+
233
+ /** 'attachment; filename="report.pdf"' plus filename* for non-ASCII names (RFC 6266). */
234
+ declare function contentDisposition(type: 'attachment' | 'inline', name: string): string;
235
+ /** Laravel's ResponseFactory (the response() helper). */
236
+ declare class HttpResponseFactory implements ResponseFactory {
237
+ #private;
238
+ /** Strings default to text/html; charset=utf-8, as in Laravel. */
239
+ make(content?: BodyInit | null, status?: number, headers?: HeadersInit): Response;
240
+ json(data: unknown, status?: number, headers?: HeadersInit): Response;
241
+ noContent(status?: number): Response;
242
+ /** Renders a view (through the ViewFactory) into an HTML response. */
243
+ view(name: string, data?: Record<string, unknown>, status?: number, headers?: HeadersInit): Promise<Response>;
244
+ /** Streams a file as an attachment. A missing file is a 404. */
245
+ download(path: string, name?: string, headers?: HeadersInit): Promise<Response>;
246
+ /** Streams a file for the browser to display (Laravel's response()->file()). */
247
+ file(path: string, headers?: HeadersInit): Promise<Response>;
248
+ stream(body: ReadableStream, status?: number, headers?: HeadersInit): Response;
249
+ }
250
+
251
+ /**
252
+ * Laravel's Http Kernel: wraps the raw Request, binds it in the request scope, loads the body, then sends it through
253
+ * the global middleware to the router. Every stage renders its own errors through the ExceptionHandler.
254
+ */
255
+ declare class Kernel implements HttpKernel {
256
+ #private;
257
+ protected readonly app: Application;
258
+ constructor(app: Application);
259
+ getGlobalMiddleware(): MiddlewareClass[];
260
+ setGlobalMiddleware(middleware: MiddlewareClass[]): this;
261
+ appendMiddleware(...middleware: MiddlewareClass[]): this;
262
+ prependMiddleware(...middleware: MiddlewareClass[]): this;
263
+ hasMiddleware(middleware: MiddlewareClass): boolean;
264
+ /** Runs in the current request scope (Application.handle() opens one); called directly, it opens its own. */
265
+ handle(raw: Request): Promise<Response>;
266
+ /** Runs terminate() on the global and route middleware (inside the request's scope), then Application.terminate(), inside the same scope, so terminating callbacks see the request's bindings. */
267
+ terminate(raw: Request, response: Response): Promise<void>;
268
+ }
269
+
270
+ /** '' becomes null in the query and body, so `nullable` validation behaves as in Laravel. */
271
+ declare class ConvertEmptyStringsToNull implements Middleware {
272
+ handle(request: HttpRequest, next: Next): Promise<Response>;
273
+ }
274
+
275
+ /** Trims every string in the query and body, except password fields (Laravel's TrimStrings). */
276
+ declare class TrimStrings implements Middleware {
277
+ /** Dotted input keys left untouched. Override in a subclass to change. */
278
+ protected except: string[];
279
+ handle(request: HttpRequest, next: Next): Promise<Response>;
280
+ }
281
+
282
+ interface GroupOptions {
283
+ append?: MiddlewareClass[];
284
+ prepend?: MiddlewareClass[];
285
+ remove?: MiddlewareClass[];
286
+ }
287
+ /** The `m` in withMiddleware((m) => …): edits the kernel's global middleware and the router's groups and aliases. */
288
+ declare class MiddlewareConfiguration implements MiddlewareConfigurator {
289
+ #private;
290
+ private readonly kernel;
291
+ private readonly router;
292
+ private readonly config?;
293
+ constructor(kernel: Kernel, router: Router, config?: ConfigRepository | undefined);
294
+ append(...middleware: MiddlewareClass[]): this;
295
+ prepend(...middleware: MiddlewareClass[]): this;
296
+ web(options: GroupOptions): this;
297
+ api(options: GroupOptions): this;
298
+ alias(aliases: Record<string, MiddlewareClass>): this;
299
+ group(name: string, middleware: Array<MiddlewareClass | string>): this;
300
+ /** Stored in config('http.csrf_except'), which the Session component's VerifyCsrfToken reads. */
301
+ validateCsrfTokens(options: {
302
+ except: string[];
303
+ }): this;
304
+ /** Stored in config('http.redirect_guests_to'), which the Auth middleware and the exception handler read. */
305
+ redirectGuestsTo(url: string | ((request: HttpRequest) => string)): this;
306
+ /** Laravel 11's redirectUsersTo(): stored in config('http.redirect_users_to') for Auth's RedirectIfAuthenticated. */
307
+ redirectUsersTo(url: string | ((request: HttpRequest) => string)): this;
308
+ }
309
+ /** Runs the withMiddleware() callbacks collected by the ApplicationBuilder (HttpServiceProvider calls this once booted). */
310
+ declare function applyMiddlewareCallbacks(app: Application, kernel: Kernel): void;
311
+
312
+ type ReportCallback = (error: unknown) => void | boolean | Promise<void | boolean>;
313
+ type RenderCallback = (error: unknown, request: unknown) => Response | undefined | Promise<Response | undefined>;
314
+ type ErrorClass = abstract new (...args: never[]) => Error;
315
+ /** HTTP status for an error (spec §7). */
316
+ declare function statusFor(error: unknown): number;
317
+ /** "The title field is required. (and 2 more errors)" (Laravel's ValidationException::summarize). */
318
+ declare function summarizeValidation(errors: Record<string, string[]>): string;
319
+ /** The exception handler (spec §7): report through the LogManager, render by error kind. */
320
+ declare class ErrorHandler implements ExceptionHandler {
321
+ #private;
322
+ protected readonly app: Application;
323
+ /** Input keys never flashed back on a validation redirect. */
324
+ protected dontFlash: string[];
325
+ constructor(app: Application);
326
+ reportUsing(callback: ReportCallback): void;
327
+ renderUsing(callback: RenderCallback): void;
328
+ ignore(...classes: ErrorClass[]): void;
329
+ shouldReport(error: unknown): boolean;
330
+ /** Report callbacks first (returning false stops the default log), then LogManager.error(), else console.error. Once per error. */
331
+ report(error: unknown): Promise<void>;
332
+ render(request: unknown, error: unknown): Promise<Response>;
333
+ }
334
+
335
+ /** The `e` in withExceptions((e) => …). */
336
+ declare class ExceptionsConfiguration implements ExceptionsConfigurator {
337
+ private readonly handler;
338
+ constructor(handler: ErrorHandler);
339
+ report(callback: ReportCallback): this;
340
+ render(callback: RenderCallback): this;
341
+ dontReport(...classes: ErrorClass[]): this;
342
+ }
343
+ /** Runs the withExceptions() callbacks against a handler (the provider does this when the handler is built). */
344
+ declare function applyExceptionCallbacks(app: Application, handler: ErrorHandler): void;
345
+
346
+ /** Laravel's wording for the status (its error pages say "Server Error" and "Page Expired"). */
347
+ declare function statusText(status: number): string;
348
+ declare function escapeHtml(value: string): string;
349
+ /** Laravel's minimal error page: "404 | Not Found". */
350
+ declare function minimalPage(status: number, message: string): string;
351
+ interface StackFrame {
352
+ readonly file: string;
353
+ readonly line: number;
354
+ readonly column: number;
355
+ readonly text: string;
356
+ }
357
+ /** Parses V8/JavaScriptCore stack lines into frames that point at files. */
358
+ declare function stackFrames(error: Error): StackFrame[];
359
+ /** The APP_DEBUG page: class, message, request, a source excerpt of the first app frame, the stack and causes. */
360
+ declare function debugPage(error: unknown, method: string, url: string): Promise<string>;
361
+
362
+ type Runtime = 'node' | 'bun';
363
+ interface ServeOptions {
364
+ /** Default: PORT, then SERVER_PORT, then 8000 (Laravel's serve). 0 picks a free port. */
365
+ port?: number;
366
+ /** Default: 127.0.0.1. */
367
+ hostname?: string;
368
+ /** Close gracefully on SIGINT/SIGTERM, then exit. Default: true. */
369
+ signals?: boolean;
370
+ /** How long close() waits for in-flight requests before cutting connections (ms). Default: 10000. */
371
+ shutdownTimeout?: number;
372
+ /** Default: detected (Bun when globalThis.Bun exists). */
373
+ runtime?: Runtime;
374
+ /** Called once listening. Default: prints "Server running on [url]." */
375
+ onListen?: (server: RunningServer) => void;
376
+ }
377
+ interface ResolvedServeOptions {
378
+ readonly port: number;
379
+ readonly hostname: string;
380
+ readonly signals: boolean;
381
+ readonly shutdownTimeout: number;
382
+ }
383
+ interface RunningServer {
384
+ readonly runtime: Runtime;
385
+ readonly hostname: string;
386
+ readonly port: number;
387
+ /** 'http://127.0.0.1:8000' */
388
+ readonly url: string;
389
+ /** Stops accepting connections, waits for in-flight requests (up to shutdownTimeout), then resolves. */
390
+ close(): Promise<void>;
391
+ /** Resolves once the server has closed. */
392
+ readonly closed: Promise<void>;
393
+ }
394
+
395
+ /** The slice of Bun's API used here (typed locally: there is no Bun lib in the build). */
396
+ interface BunServer {
397
+ readonly port: number;
398
+ stop(closeActiveConnections?: boolean): Promise<void> | void;
399
+ requestIP(request: Request): {
400
+ address: string;
401
+ } | null;
402
+ }
403
+ interface BunRuntime {
404
+ serve(options: {
405
+ port: number;
406
+ hostname: string;
407
+ fetch(request: Request, server: BunServer): Promise<Response>;
408
+ error(error: Error): Response;
409
+ }): BunServer;
410
+ }
411
+ declare function bunRuntime(): BunRuntime | undefined;
412
+ declare function serveBun(app: Application, options: ResolvedServeOptions): Promise<RunningServer>;
413
+
414
+ /** node:http IncomingMessage → web Request (the body streams; the signal aborts when the client goes away). */
415
+ declare function toWebRequest(req: IncomingMessage, res: ServerResponse, fallbackHost: string): Request;
416
+ /** Web Response → ServerResponse, streaming the body with backpressure. Several Set-Cookie headers stay separate. */
417
+ declare function writeResponse(res: ServerResponse, response: Response): Promise<void>;
418
+ declare function serveNode(app: Application, options: ResolvedServeOptions): Promise<RunningServer>;
419
+
420
+ declare function detectRuntime(): Runtime;
421
+ /** Boots the app and serves it with node:http or Bun.serve (public/index.ts: `await serve(app)`). */
422
+ declare function serve(app: Application, options?: ServeOptions): Promise<RunningServer>;
423
+
424
+ interface RouteListRow {
425
+ /** 'GET|HEAD' */
426
+ readonly method: string;
427
+ readonly uri: string;
428
+ readonly name: string | null;
429
+ /** 'PostController@show' or 'Closure' */
430
+ readonly action: string;
431
+ readonly middleware: string[];
432
+ }
433
+ /** One row per route, sorted by URI (Laravel's default --sort=uri; ties keep registration order). */
434
+ declare function routeListRows(routes: readonly Route[]): RouteListRow[];
435
+ interface RouteListFilters {
436
+ method?: string;
437
+ name?: string;
438
+ path?: string;
439
+ /** Comma-separated. */
440
+ exceptPath?: string;
441
+ }
442
+ /** Laravel's RouteListCommand::filterRoute: substring matches, method compared uppercased. */
443
+ declare function filterRouteList(rows: readonly RouteListRow[], filters: RouteListFilters): RouteListRow[];
444
+ /**
445
+ * Laravel's route:list layout: the method column padded, the URI, a dotted leader, then `name › action`
446
+ * (closures show only the name), and a right-aligned "Showing [n] routes" footer.
447
+ */
448
+ declare function formatRouteList(rows: readonly RouteListRow[], width: number): string[];
449
+ /** The routes/api.ts that install:api writes (Laravel's api.stub, with the token guard). */
450
+ declare const API_ROUTES_STUB = "import { request, Route } from '@orieljs/framework'\n\nRoute.get('/user', () => request().user()).middleware('auth:token')\n";
451
+ /**
452
+ * Adds `api: 'routes/api.ts'` to withRouting() in bootstrap/app.ts: uncomments a commented `// api:` entry,
453
+ * else inserts it after the `web:` entry, else at the start of withRouting({, else adds a withRouting() call
454
+ * before create(). Returns the source unchanged when api is already there, and undefined when it can't tell where.
455
+ * (Function replacers, so a `$` in the file is never read as a replacement pattern.)
456
+ */
457
+ declare function addApiRouting(source: string): string | undefined;
458
+ interface HttpCommandOptions {
459
+ /** Replaces serve() (tests). */
460
+ serve?: (app: Application, options: ServeOptions) => Promise<RunningServer>;
461
+ /** The terminal width for route:list. Default: process.stdout.columns, else 120. */
462
+ terminalWidth?: () => number;
463
+ }
464
+ /** Registers `serve`, `route:list` and `install:api` as closure commands (PC1). */
465
+ declare function registerHttpCommands(kernel: ConsoleKernel, app: Application, options?: HttpCommandOptions): void;
466
+
467
+ /**
468
+ * Binds the HTTP kernel (replacing any kernel bound before, such as Foundation's ClosureKernel), the exception
469
+ * handler, the response factory and the redirector, and merges the `http` config defaults.
470
+ *
471
+ * The HttpRequest is deliberately NOT bound on the application: the kernel creates one per request and puts it in
472
+ * the request scope with scope.instance(). A root `scoped()` binding would make bound(HttpRequest) true everywhere,
473
+ * and that check is how the URL generator, the redirects and the helpers know they are inside a request.
474
+ */
475
+ declare class HttpServiceProvider extends ServiceProvider {
476
+ register(): void;
477
+ boot(): void;
478
+ }
479
+
480
+ export { API_ROUTES_STUB, ConvertEmptyStringsToNull, type ErrorClass, ErrorHandler, ExceptionsConfiguration, FormUploadedFile, type HttpCommandOptions, HttpException, HttpRedirectResponse, HttpRedirector, HttpResponseException, HttpResponseFactory, HttpServerError, HttpServiceProvider, IncomingRequest, type IncomingRequestOptions, Kernel, MiddlewareConfiguration, type RenderCallback, type ReportCallback, type ResolvedServeOptions, type RouteListFilters, type RouteListRow, type RunningServer, type Runtime, type ServeOptions, type StackFrame, TrimStrings, abort, abortIf, abortUnless, addApiRouting, applyExceptionCallbacks, applyMiddlewareCallbacks, back, bunRuntime, clientAddress, contentDisposition, currentRequest, debugPage, detectRuntime, escapeHtml, extensionFromMime, filterRouteList, formatRouteList, fromEntries, ipMatches, isBlank, mergeRecursive, mimeFromExtension, minimalPage, normalizeLists, optionalCookieJar, optionalSession, parseBracketKey, readBody, redirect, registerHttpCommands, request, requestScope, response, route, routeListRows, sanitize, serve, serveBun, serveNode, setClientAddress, stackFrames, statusFor, statusText, summarizeValidation, toWebRequest, transformLeaves, url, writeResponse };