@orieljs/http 0.1.0-alpha.5 → 0.1.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +7 -0
- package/README.md +33 -0
- package/TRADEMARKS.md +33 -0
- package/dist/index.d.ts +58 -16
- package/dist/index.js +330 -17
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
package/NOTICE
CHANGED
|
@@ -7,3 +7,10 @@ This product includes software developed by the Oriel project
|
|
|
7
7
|
Oriel is licensed under the Apache License, Version 2.0 (see LICENSE).
|
|
8
8
|
The Oriel name and logo are not covered by that license; see TRADEMARKS.md
|
|
9
9
|
(https://github.com/orieljs/framework/blob/main/TRADEMARKS.md).
|
|
10
|
+
|
|
11
|
+
@orieljs/support (and @orieljs/framework, which bundles it) includes transliteration data from
|
|
12
|
+
voku/portable-ascii (https://github.com/voku/portable-ascii), Copyright (C) 2019 Lars Moelleken, MIT License.
|
|
13
|
+
|
|
14
|
+
@orieljs/notifications (and @orieljs/framework, which bundles it) includes the HTML and CSS of
|
|
15
|
+
Laravel's default notification mail (laravel/framework, https://github.com/laravel/framework),
|
|
16
|
+
Copyright (c) Taylor Otwell, MIT License.
|
package/README.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# @orieljs/http
|
|
2
|
+
|
|
3
|
+
The HTTP layer of Oriel: the request, responses and redirects, the middleware kernel, the error handler and its error pages, and the server for Node and Bun. It is Oriel's counterpart of Laravel's HTTP layer. Http is part of `@orieljs/framework`, which every Oriel app already installs, and is re-exported from it. In an app, import it from `@orieljs/framework`; `@orieljs/http` is also published on its own.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install @orieljs/framework
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```ts title="app/Http/Controllers/SearchController.ts"
|
|
10
|
+
import { request, response } from '@orieljs/framework'
|
|
11
|
+
import { Post } from '../../Models/Post'
|
|
12
|
+
import { Controller } from './Controller'
|
|
13
|
+
|
|
14
|
+
export class SearchController extends Controller {
|
|
15
|
+
async index() {
|
|
16
|
+
const term = request().input('q', '')
|
|
17
|
+
const posts = await Post.whereLike('title', `%${term}%`).latest().get()
|
|
18
|
+
return response().json({ term, posts }, 200, { 'Cache-Control': 'no-store' })
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`request()` is the current `IncomingRequest`, with `input()`, `string()`, `boolean()`, `integer()`, `only()`, `file()` and `header()`; `await request().user()` is the signed-in user, or `undefined` for a guest. `response()`, `redirect()` and `back()` build responses, and `abort()`, `abortIf()` and `abortUnless()` stop a request with an HTTP error. `await serve(app)` runs the app on Node or Bun.
|
|
24
|
+
|
|
25
|
+
Documentation: https://orieljs.vercel.app/docs/requests
|
|
26
|
+
|
|
27
|
+
Status: early alpha. APIs will change.
|
|
28
|
+
|
|
29
|
+
## License
|
|
30
|
+
|
|
31
|
+
Oriel is open-source software licensed under the Apache License 2.0 (Apache-2.0; see `LICENSE` and `NOTICE`). The Oriel name and logo are trademarks; see `TRADEMARKS.md`.
|
|
32
|
+
|
|
33
|
+
Website: https://orieljs.vercel.app
|
package/TRADEMARKS.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Oriel trademark policy
|
|
2
|
+
|
|
3
|
+
The Oriel code is open source under the Apache License 2.0. The **Oriel name and logo** are not: the license covers
|
|
4
|
+
the code only (section 6 of the license says so), and the name and logo stay with the project. This page explains
|
|
5
|
+
what you can and can't do with them. The goal is simple: people should always be able to tell what is the real Oriel
|
|
6
|
+
and what isn't.
|
|
7
|
+
|
|
8
|
+
## You can, without asking
|
|
9
|
+
|
|
10
|
+
- Use, change, ship and sell the code, as the license allows.
|
|
11
|
+
- Say that your app or package is "built with Oriel", "for Oriel" or "compatible with Oriel".
|
|
12
|
+
- Name a package `oriel-<something>` or `<something>-for-oriel` when it works with Oriel, as long as it is clear that
|
|
13
|
+
it is not official (for example, don't publish it under the `@orieljs` npm scope).
|
|
14
|
+
- Use the name and logo to write about Oriel, teach it, or link to it, in articles, talks, videos and courses.
|
|
15
|
+
- Use the unmodified logo to point to the project, as it is (no recolouring, cropping or
|
|
16
|
+
distortion).
|
|
17
|
+
|
|
18
|
+
## You can't, without written permission
|
|
19
|
+
|
|
20
|
+
- Call a fork, a modified copy or a competing product "Oriel", or anything likely to be confused with it.
|
|
21
|
+
- Use the name or logo as the name, logo or domain of your own product, company or service.
|
|
22
|
+
- Suggest that the Oriel project made, endorses or supports your work when it doesn't.
|
|
23
|
+
- Sell merchandise with the name or logo.
|
|
24
|
+
|
|
25
|
+
## Forks
|
|
26
|
+
|
|
27
|
+
Forks are welcome. Please give yours a different name and logo, keep the `LICENSE` and `NOTICE` files, and say that
|
|
28
|
+
it is based on Oriel.
|
|
29
|
+
|
|
30
|
+
## Questions
|
|
31
|
+
|
|
32
|
+
Open an issue at https://github.com/orieljs/framework or email meeeet.dev@gmail.com. If you're unsure whether a use
|
|
33
|
+
is fine, ask; the answer is usually yes.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { HttpRequest, CookieJar, Session, Container, RedirectResponse, HeadersInit, Redirector, UploadedFile, Rules, OrielError, RouteName, ResponseFactory, BodyInit, UrlGenerator, HttpKernel, Application, MiddlewareClass, Middleware, Next, MiddlewareConfigurator, Router, ConfigRepository, ExceptionHandler, ExceptionsConfigurator, ConsoleKernel, Route } from '@orieljs/contracts';
|
|
2
|
-
import { FileType, ServiceProvider } from '@orieljs/support';
|
|
1
|
+
import { HttpRequest, CookieJar, Session, Container, RedirectResponse, HeadersInit, MessageBag, Redirector, UploadedFile, Rules, InferValidatedType, OrielError, RouteName, RouteArguments, ResponseFactory, BodyInit, UrlGenerator, HttpKernel, Application, MiddlewareClass, Middleware, Next, MiddlewareConfigurator, Router, ConfigRepository, ExceptionHandler, ExceptionsConfigurator, ConsoleKernel, Route } from '@orieljs/contracts';
|
|
2
|
+
import { FileType, Stringable, ServiceProvider } from '@orieljs/support';
|
|
3
3
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
4
|
+
import { SpawnOptions, ChildProcess } from 'node:child_process';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Whether a JSON text nests objects and arrays deeper than `maxDepth`, found by scanning (no parsing, no recursion):
|
|
@@ -18,9 +19,7 @@ declare function currentRequest(): HttpRequest | undefined;
|
|
|
18
19
|
declare function optionalSession(): Session | undefined;
|
|
19
20
|
declare function optionalCookieJar(): CookieJar | undefined;
|
|
20
21
|
|
|
21
|
-
type ErrorsInput = Record<string, string | string[]> |
|
|
22
|
-
toObject(): Record<string, string[]>;
|
|
23
|
-
};
|
|
22
|
+
type ErrorsInput = Record<string, string | string[]> | MessageBag;
|
|
24
23
|
/**
|
|
25
24
|
* Laravel's RedirectResponse. with()/withErrors()/withInput() flash to the request's Session immediately, like
|
|
26
25
|
* Laravel; without a bound Session (an API-only app) they are skipped silently.
|
|
@@ -160,7 +159,10 @@ declare class IncomingRequest implements HttpRequest {
|
|
|
160
159
|
hasAny(...keys: Array<string | string[]>): boolean;
|
|
161
160
|
missing(...keys: Array<string | string[]>): boolean;
|
|
162
161
|
filled(key: string): boolean;
|
|
163
|
-
string(
|
|
162
|
+
/** Laravel's string(): the input as a Stringable (the default when it is missing or null): request().string('q').trim(). */
|
|
163
|
+
string(key: string, defaultValue?: string): Stringable;
|
|
164
|
+
/** Laravel's str(): string() under its short name. */
|
|
165
|
+
str(key: string, defaultValue?: string): Stringable;
|
|
164
166
|
/** PHP's FILTER_VALIDATE_BOOLEAN: '1', 'true', 'on', 'yes' (any case) and true are true. */
|
|
165
167
|
boolean(key: string, defaultValue?: boolean): boolean;
|
|
166
168
|
/** PHP's intval: leading digits, else 0. */
|
|
@@ -179,10 +181,17 @@ declare class IncomingRequest implements HttpRequest {
|
|
|
179
181
|
/** One route parameter (after model binding), or all of them. */
|
|
180
182
|
route<T = unknown>(key?: string): T;
|
|
181
183
|
session(): Session;
|
|
182
|
-
|
|
184
|
+
/**
|
|
185
|
+
* The signed-in user, through the resolver Auth sets, else the current scope's guard (the default, or `guard`).
|
|
186
|
+
* The guard keeps the user it found, so it is looked up once per request. Undefined for a guest or without auth.
|
|
187
|
+
*/
|
|
188
|
+
user<T = unknown>(guard?: string): Promise<T | undefined>;
|
|
183
189
|
setUserResolver(resolver: (guard?: string) => unknown): void;
|
|
184
|
-
/**
|
|
185
|
-
|
|
190
|
+
/**
|
|
191
|
+
* Validates all() through the ValidationFactory; throws its Validation error on failure. The data is typed from the
|
|
192
|
+
* rules: `validate({ title: 'required|string' })` is `{ title: string }`.
|
|
193
|
+
*/
|
|
194
|
+
validate<const R extends Rules>(rules: R, messages?: Record<string, string>, attributes?: Record<string, string>): Promise<InferValidatedType<R>>;
|
|
186
195
|
}
|
|
187
196
|
|
|
188
197
|
/** Helpers for request input: PHP-style bracket keys, safe cloning (no prototype pollution) and blank checks. */
|
|
@@ -233,15 +242,18 @@ declare class HttpServerError extends Error implements OrielError {
|
|
|
233
242
|
readonly name = "HttpServerError";
|
|
234
243
|
}
|
|
235
244
|
|
|
236
|
-
/**
|
|
237
|
-
|
|
245
|
+
/**
|
|
246
|
+
* request() → the current request (Laravel's Illuminate\Http\Request: the HttpRequest contract plus its extras, such
|
|
247
|
+
* as string()); request('key', default) → its input.
|
|
248
|
+
*/
|
|
249
|
+
declare function request(): IncomingRequest;
|
|
238
250
|
declare function request<T = unknown>(key: string, defaultValue?: T): T;
|
|
239
251
|
/** response() → the ResponseFactory; response(content, status, headers) → a Response. */
|
|
240
252
|
declare function response(): ResponseFactory;
|
|
241
253
|
declare function response(content: BodyInit | null, status?: number, headers?: HeadersInit): Response;
|
|
242
|
-
/** The Redirector with its route() typed by the generated route names. */
|
|
254
|
+
/** The Redirector with its route() typed by the generated route names and their parameters. */
|
|
243
255
|
type TypedRedirector = Omit<Redirector, 'route'> & {
|
|
244
|
-
route(name:
|
|
256
|
+
route<N extends RouteName>(name: N, ...args: RouteArguments<N, [status?: number]>): RedirectResponse;
|
|
245
257
|
};
|
|
246
258
|
/** redirect() → the Redirector; redirect('/path', status) → a RedirectResponse. */
|
|
247
259
|
declare function redirect(): TypedRedirector;
|
|
@@ -251,8 +263,11 @@ declare function back(fallback?: string, status?: number): RedirectResponse;
|
|
|
251
263
|
/** url() → the UrlGenerator; url('/path', query, absolute) → a URL. */
|
|
252
264
|
declare function url(): UrlGenerator;
|
|
253
265
|
declare function url(path: string, query?: Record<string, unknown>, absolute?: boolean): string;
|
|
254
|
-
/**
|
|
255
|
-
|
|
266
|
+
/**
|
|
267
|
+
* The URL of a named route: route('posts.show', post), route('posts.show', { post, page: 2 }). Once `oriel
|
|
268
|
+
* route:types` has run, the name and the route's parameters are checked.
|
|
269
|
+
*/
|
|
270
|
+
declare function route<N extends RouteName>(name: N, ...args: RouteArguments<N>): string;
|
|
256
271
|
/** abort(404), abort(403, 'Nope', headers), or abort(response) to send a ready response. */
|
|
257
272
|
declare function abort(status: number | Response, message?: string, headers?: Record<string, string>): never;
|
|
258
273
|
declare function abortIf(condition: unknown, status: number | Response, message?: string, headers?: Record<string, string>): void;
|
|
@@ -378,7 +393,10 @@ declare class ExceptionsConfiguration implements ExceptionsConfigurator {
|
|
|
378
393
|
/** Runs the withExceptions() callbacks against a handler (the provider does this when the handler is built). */
|
|
379
394
|
declare function applyExceptionCallbacks(app: Application, handler: ErrorHandler): void;
|
|
380
395
|
|
|
381
|
-
/**
|
|
396
|
+
/**
|
|
397
|
+
* The text an error page shows for a status: Laravel's own wording where it has a view ("Server Error", "Page
|
|
398
|
+
* Expired"), else Symfony's `Response::$statusTexts`, which Laravel shows for the others.
|
|
399
|
+
*/
|
|
382
400
|
declare function statusText(status: number): string;
|
|
383
401
|
declare function escapeHtml(value: string): string;
|
|
384
402
|
/** Laravel's minimal error page: "404 | Not Found". */
|
|
@@ -467,6 +485,28 @@ declare function serve(app: Application, options?: ServeOptions): Promise<Runnin
|
|
|
467
485
|
*/
|
|
468
486
|
declare function servePublicFile(publicPath: string, request: Request): Promise<Response | undefined>;
|
|
469
487
|
|
|
488
|
+
interface FileWatcher {
|
|
489
|
+
close(): void;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/** node:child_process's spawn(), replaceable in tests. */
|
|
493
|
+
type SpawnServer = (command: string, args: string[], options: SpawnOptions) => ChildProcess;
|
|
494
|
+
interface WatchedServerOptions {
|
|
495
|
+
/** The server's command line: the runtime, its flags, the CLI script, then `serve --host=… --port=…`. */
|
|
496
|
+
command: readonly string[];
|
|
497
|
+
cwd: string;
|
|
498
|
+
env: NodeJS.ProcessEnv;
|
|
499
|
+
/** Starts watching: calls back with the changed files (relative to the base path) once they settle. */
|
|
500
|
+
watch(onChange: (files: string[]) => void): FileWatcher;
|
|
501
|
+
info(message: string): void;
|
|
502
|
+
error(message: string): void;
|
|
503
|
+
/** How long a server may take to stop before it is killed, in ms. Default 15000 (serve gives requests 10 s). */
|
|
504
|
+
stopTimeout?: number;
|
|
505
|
+
/** The signals that stop it. Default SIGINT, SIGTERM and SIGHUP. */
|
|
506
|
+
signals?: readonly NodeJS.Signals[];
|
|
507
|
+
spawn?: SpawnServer;
|
|
508
|
+
}
|
|
509
|
+
|
|
470
510
|
interface RouteListRow {
|
|
471
511
|
/** 'GET|HEAD' */
|
|
472
512
|
readonly method: string;
|
|
@@ -506,6 +546,8 @@ interface HttpCommandOptions {
|
|
|
506
546
|
serve?: (app: Application, options: ServeOptions) => Promise<RunningServer>;
|
|
507
547
|
/** The terminal width for route:list. Default: process.stdout.columns, else 120. */
|
|
508
548
|
terminalWidth?: () => number;
|
|
549
|
+
/** Replaces `serve --watch`'s restarting server (tests). Resolves the command's exit code. */
|
|
550
|
+
watch?: (options: WatchedServerOptions) => Promise<number>;
|
|
509
551
|
}
|
|
510
552
|
/** Registers `serve`, `route:list` and `install:api` as closure commands (PC1). */
|
|
511
553
|
declare function registerHttpCommands(kernel: ConsoleKernel, app: Application, options?: HttpCommandOptions): void;
|