@elysiumjs/core 0.8.0 → 0.11.0
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/CHANGELOG.md +227 -0
- package/README.md +62 -4
- package/dist/app.d.ts +126 -13
- package/dist/config.d.ts +74 -0
- package/dist/console.d.ts +46 -9
- package/dist/container.d.ts +76 -14
- package/dist/errors.d.ts +37 -2
- package/dist/filter.d.ts +78 -0
- package/dist/http-client.d.ts +80 -0
- package/dist/http.d.ts +153 -45
- package/dist/index.d.ts +24 -11
- package/dist/index.js +10 -8
- package/dist/interceptor.d.ts +80 -0
- package/dist/kernel.d.ts +15 -1
- package/dist/{event-wiring.d.ts → lifecycle-wiring.d.ts} +4 -4
- package/dist/{event.d.ts → lifecycle.d.ts} +26 -18
- package/dist/logger.d.ts +15 -0
- package/dist/middleware.d.ts +30 -8
- package/dist/module-context.d.ts +6 -0
- package/dist/module-graph.d.ts +3 -2
- package/dist/module.d.ts +18 -0
- package/dist/problem.d.ts +815 -0
- package/dist/rate-limit.d.ts +194 -0
- package/dist/resource.d.ts +77 -0
- package/dist/runtime.d.ts +148 -0
- package/dist/security.d.ts +159 -0
- package/dist/service.d.ts +51 -15
- package/dist/testing.d.ts +45 -2
- package/dist/token.d.ts +22 -0
- package/dist/user.d.ts +13 -0
- package/dist/utils.d.ts +3 -3
- package/dist/websocket.d.ts +42 -16
- package/package.json +24 -8
- package/dist/redis.d.ts +0 -86
- package/tsconfig.json +0 -12
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a store answers for a hit: the count of the key in its current window, or, for stores that
|
|
3
|
+
* only decide (such as the Cloudflare rate limiting binding), whether the hit is over the limit.
|
|
4
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
5
|
+
*/
|
|
6
|
+
export type RateLimitHit = {
|
|
7
|
+
/** The number of hits in the window, this one included. */
|
|
8
|
+
count: number;
|
|
9
|
+
/** When the window ends, in milliseconds since the epoch. */
|
|
10
|
+
resetAt: number;
|
|
11
|
+
} | {
|
|
12
|
+
/** Whether the hit is over the limit. */
|
|
13
|
+
limited: boolean;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Where rate limits keep their counts. Counts use fixed windows: the first hit of a key opens a
|
|
17
|
+
* window of `windowMs`, and the count starts again once it has ended. Implement it to keep the
|
|
18
|
+
* counts anywhere; `MemoryRateLimitStore` keeps them in the process, `RedisRateLimitStore`
|
|
19
|
+
* (`@elysiumjs/redis`) in Redis, and `WorkersRateLimitStore` (`@elysiumjs/runtime-workers`) uses
|
|
20
|
+
* a Cloudflare rate limiting binding.
|
|
21
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
22
|
+
*/
|
|
23
|
+
export interface RateLimitStore {
|
|
24
|
+
/**
|
|
25
|
+
* Counts a hit of a key.
|
|
26
|
+
* @param key The key, such as the client address and the route.
|
|
27
|
+
* @param windowMs The length of the window, in milliseconds.
|
|
28
|
+
*/
|
|
29
|
+
hit(key: string, windowMs: number): Promise<RateLimitHit>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Keeps rate limit counts in the memory of the process. Counts are not shared between
|
|
33
|
+
* processes or Worker isolates: use another store when the app runs on several.
|
|
34
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
35
|
+
*/
|
|
36
|
+
export declare class MemoryRateLimitStore implements RateLimitStore {
|
|
37
|
+
#private;
|
|
38
|
+
hit(key: string, windowMs: number): Promise<{
|
|
39
|
+
count: number;
|
|
40
|
+
resetAt: number;
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* What a rate limit key is built from.
|
|
45
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
46
|
+
*/
|
|
47
|
+
export type RateLimitKeyContext = {
|
|
48
|
+
request: Request;
|
|
49
|
+
/** The client address (`ctx.ip`), when the runtime knows it. */
|
|
50
|
+
ip?: string;
|
|
51
|
+
/** The route, such as `GET /posts/:id`. */
|
|
52
|
+
route: string;
|
|
53
|
+
/** The whole request context, for keys built from the current user or tenant. */
|
|
54
|
+
context: Record<string, unknown>;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* A rate limit of a route, a controller or the app.
|
|
58
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
59
|
+
*/
|
|
60
|
+
export type RateLimitOptions = {
|
|
61
|
+
/** The length of a window, in milliseconds. */
|
|
62
|
+
window: number;
|
|
63
|
+
/** The hits a key may make in a window. */
|
|
64
|
+
max: number;
|
|
65
|
+
/**
|
|
66
|
+
* Builds the key the limit counts. Defaults to the client address and the route, so that each
|
|
67
|
+
* client has its own count on each route.
|
|
68
|
+
*/
|
|
69
|
+
key?: (context: RateLimitKeyContext) => string | Promise<string>;
|
|
70
|
+
/** Where the counts are kept. Defaults to the app's store, or one in memory. */
|
|
71
|
+
store?: RateLimitStore;
|
|
72
|
+
/** A name for the limit, in the `RateLimit-Policy` header and the keys. */
|
|
73
|
+
name?: string;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* The rate limit options of an application: the store of every limit, and a limit for every
|
|
77
|
+
* route that sets none.
|
|
78
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
79
|
+
*/
|
|
80
|
+
export type AppRateLimitOptions = Partial<RateLimitOptions>;
|
|
81
|
+
declare const TooManyRequestsError_base: {
|
|
82
|
+
new (detail?: string, options?: import("./problem").DomainErrorOptions): {
|
|
83
|
+
name: string;
|
|
84
|
+
message: string;
|
|
85
|
+
stack?: string;
|
|
86
|
+
cause?: unknown;
|
|
87
|
+
value?(): import("elysia/types").MaybePromise<unknown>;
|
|
88
|
+
readonly code: "RATE_LIMITED";
|
|
89
|
+
readonly status: 429;
|
|
90
|
+
readonly detail: string | undefined;
|
|
91
|
+
readonly title: string;
|
|
92
|
+
readonly errors: readonly import("./problem").ProblemValidationError[] | undefined;
|
|
93
|
+
readonly retryAfterSeconds: number | undefined;
|
|
94
|
+
readonly extensions: Readonly<Record<string, unknown>>;
|
|
95
|
+
readonly headers: Record<string, string> | undefined;
|
|
96
|
+
get type(): string;
|
|
97
|
+
extension(): Record<string, unknown>;
|
|
98
|
+
};
|
|
99
|
+
isError(error: unknown): error is Error;
|
|
100
|
+
isError(value: unknown): value is Error;
|
|
101
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
102
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
103
|
+
prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
|
|
104
|
+
stackTraceLimit: number;
|
|
105
|
+
id<const Type extends string>(code: Type): import("elysia").TaggedHTTPError<Type>;
|
|
106
|
+
id<const Type extends string, const S extends number | keyof import("elysia").StatusMap>(code: Type, status: S): import("elysia").TaggedHTTPError<Type, {
|
|
107
|
+
readonly status: S extends keyof import("elysia").StatusMap ? import("elysia").StatusMap[S] : S;
|
|
108
|
+
}>;
|
|
109
|
+
typeBase?: string;
|
|
110
|
+
for<const C extends import("./problem").ProblemCode, const S extends number>(code: C, status: S): {
|
|
111
|
+
new (detail?: string, options?: import("./problem").DomainErrorOptions): {
|
|
112
|
+
name: string;
|
|
113
|
+
message: string;
|
|
114
|
+
stack?: string;
|
|
115
|
+
cause?: unknown;
|
|
116
|
+
value?(): import("elysia/types").MaybePromise<unknown>;
|
|
117
|
+
readonly code: C;
|
|
118
|
+
readonly status: S;
|
|
119
|
+
readonly detail: string | undefined;
|
|
120
|
+
readonly title: string;
|
|
121
|
+
readonly errors: readonly import("./problem").ProblemValidationError[] | undefined;
|
|
122
|
+
readonly retryAfterSeconds: number | undefined;
|
|
123
|
+
readonly extensions: Readonly<Record<string, unknown>>;
|
|
124
|
+
readonly headers: Record<string, string> | undefined;
|
|
125
|
+
get type(): string;
|
|
126
|
+
extension(): Record<string, unknown>;
|
|
127
|
+
};
|
|
128
|
+
isError(error: unknown): error is Error;
|
|
129
|
+
isError(value: unknown): value is Error;
|
|
130
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
131
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
132
|
+
prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
|
|
133
|
+
stackTraceLimit: number;
|
|
134
|
+
id<const Type extends string>(code: Type): import("elysia").TaggedHTTPError<Type>;
|
|
135
|
+
id<const Type extends string, const S_1 extends number | keyof import("elysia").StatusMap>(code: Type, status: S_1): import("elysia").TaggedHTTPError<Type, {
|
|
136
|
+
readonly status: S_1 extends keyof import("elysia").StatusMap ? import("elysia").StatusMap[S_1] : S_1;
|
|
137
|
+
}>;
|
|
138
|
+
typeBase?: string;
|
|
139
|
+
for<const C extends import("./problem").ProblemCode, const S extends number>(code: C, status: S): /*elided*/ any;
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Raised when a client goes over a rate limit. Rendered as a 429 problem, with `Retry-After`.
|
|
144
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
145
|
+
*/
|
|
146
|
+
export declare class TooManyRequestsError extends TooManyRequestsError_base {
|
|
147
|
+
readonly retryAfter: number;
|
|
148
|
+
constructor(retryAfter: number);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Sets the rate limit of a route, or of every route of a controller. A limit on a route wins over
|
|
152
|
+
* the one of its controller, which wins over the app's default (`rateLimit` of
|
|
153
|
+
* `@Application.register()`). Pass `false` to turn the limit off. Each route counts on its own.
|
|
154
|
+
*
|
|
155
|
+
* The limit is counted in the route's `beforeHandle`, after the body is parsed and validated and
|
|
156
|
+
* after the `onBeforeHandle` middlewares of the application ran. A middleware that is costly for a
|
|
157
|
+
* client over the limit (a database lookup, say) runs on the routes that need it, not on the
|
|
158
|
+
* application.
|
|
159
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
160
|
+
* @param limit The limit, or `false` for none.
|
|
161
|
+
* @example
|
|
162
|
+
* ```ts
|
|
163
|
+
* @Http.controller('/auth')
|
|
164
|
+
* @RateLimit({ window: 60_000, max: 10 })
|
|
165
|
+
* class AuthController {
|
|
166
|
+
* @Http.post('/otp')
|
|
167
|
+
* @RateLimit({ window: 60_000, max: 3, name: 'otp' })
|
|
168
|
+
* public sendOtp() {}
|
|
169
|
+
* }
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
export declare const RateLimit: (limit: RateLimitOptions | false) => (target: object, propertyKey?: string | symbol, _descriptor?: PropertyDescriptor) => void;
|
|
173
|
+
/**
|
|
174
|
+
* The limit `@RateLimit()` sets on a route, else on its controller.
|
|
175
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
176
|
+
* @param controller The controller class.
|
|
177
|
+
* @param method The name of the route method.
|
|
178
|
+
*/
|
|
179
|
+
export declare const rateLimitOf: (controller: Function, method: string | symbol) => RateLimitOptions | false | undefined;
|
|
180
|
+
/**
|
|
181
|
+
* Counts a hit against a limit, sets the `RateLimit-*` headers, and throws once the limit is
|
|
182
|
+
* exceeded.
|
|
183
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
184
|
+
* @param limit The limit.
|
|
185
|
+
* @param appStore The store of the application, used when the limit sets none.
|
|
186
|
+
* @param context The request: its context, client address and route.
|
|
187
|
+
* @throws {TooManyRequestsError} When the key went over the limit in the current window.
|
|
188
|
+
*/
|
|
189
|
+
export declare const enforceRateLimit: (limit: RateLimitOptions, appStore: RateLimitStore | undefined, context: RateLimitKeyContext & {
|
|
190
|
+
set: {
|
|
191
|
+
headers: Record<string, string | number>;
|
|
192
|
+
};
|
|
193
|
+
}) => Promise<void>;
|
|
194
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { TSchema } from 'typebox';
|
|
2
|
+
/**
|
|
3
|
+
* The response schemas of a route: one schema, or one per status code.
|
|
4
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
5
|
+
*/
|
|
6
|
+
export type ResponseSchemas = TSchema | Record<number, TSchema>;
|
|
7
|
+
export declare namespace Resource {
|
|
8
|
+
/**
|
|
9
|
+
* Marks a field of a response schema as hidden: it is dropped from responses and from the
|
|
10
|
+
* OpenAPI document, even when the handler returns it.
|
|
11
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
12
|
+
* @param schema The schema of the field.
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const UserResource = t.Object({ id: t.String(), passwordHash: Resource.hidden(t.String()) });
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
const hidden: <S extends TSchema>(schema: S) => S;
|
|
19
|
+
/** Whether a schema was marked with {@link hidden}. */
|
|
20
|
+
const isHidden: (schema: unknown) => boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The schema clients see: hidden fields removed, and codecs replaced by the schema of their
|
|
23
|
+
* encoded value, since responses are serialized before they are validated.
|
|
24
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
25
|
+
* @param schema The response schema.
|
|
26
|
+
*/
|
|
27
|
+
const project: <S extends TSchema>(schema: S) => S;
|
|
28
|
+
/**
|
|
29
|
+
* Projects every schema of a route's `response` option.
|
|
30
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
31
|
+
* @param response The `response` option: one schema, or one per status code.
|
|
32
|
+
*/
|
|
33
|
+
const projectResponse: (response: ResponseSchemas) => ResponseSchemas;
|
|
34
|
+
/**
|
|
35
|
+
* The schema of the successful response: the schema itself, or the 200 (else the first 2xx)
|
|
36
|
+
* one of a status map.
|
|
37
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
38
|
+
* @param response The `response` option of a route.
|
|
39
|
+
*/
|
|
40
|
+
const successSchema: (response: ResponseSchemas) => TSchema | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Options of {@link serialize}.
|
|
43
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
44
|
+
*/
|
|
45
|
+
type SerializeOptions = {
|
|
46
|
+
/**
|
|
47
|
+
* The fields to keep, from a sparse fieldset (`?fields=id,title`). Applies to a top-level
|
|
48
|
+
* object, to each item of a top-level array, and to the items of a `data` array.
|
|
49
|
+
*/
|
|
50
|
+
fields?: string[];
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Turns a handler result into the body its response schema describes:
|
|
54
|
+
*
|
|
55
|
+
* - fields the schema does not declare are stripped, and hidden fields are dropped;
|
|
56
|
+
* - a `Date` becomes an ISO string (`YYYY-MM-DD` when the schema's format is `date`), and an
|
|
57
|
+
* object with a `toJSON()` method, such as a luxon `DateTime`, becomes what it returns;
|
|
58
|
+
* - `fields` keeps only the selected fields.
|
|
59
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
60
|
+
* @param schema The response schema.
|
|
61
|
+
* @param value The handler result.
|
|
62
|
+
* @param options The sparse fieldset.
|
|
63
|
+
* @throws {BadRequestError} A 400 problem when `fields` names a field the schema does not have.
|
|
64
|
+
*/
|
|
65
|
+
const serialize: (schema: TSchema, value: unknown, options?: SerializeOptions) => unknown;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Whether a handler result is a body to serialize, rather than a response the handler built
|
|
69
|
+
* itself (a `Response`, a thrown or returned status, a stream).
|
|
70
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
71
|
+
*/
|
|
72
|
+
export declare const isSerializable: (value: unknown) => boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Reads a sparse fieldset from a query: `fields=id,title` (or repeated `fields`).
|
|
75
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
76
|
+
*/
|
|
77
|
+
export declare const readFields: (query: Record<string, unknown> | undefined) => string[] | undefined;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type { AnyElysia } from 'elysia';
|
|
2
|
+
import { ElysiumError } from './errors';
|
|
3
|
+
/**
|
|
4
|
+
* The process signals the application shuts down on.
|
|
5
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
6
|
+
*/
|
|
7
|
+
export type ShutdownSignal = 'SIGINT' | 'SIGTERM';
|
|
8
|
+
/**
|
|
9
|
+
* A server started by {@link Runtime.serve}, closed when the application shuts down.
|
|
10
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
11
|
+
*/
|
|
12
|
+
export type ServeHandle = {
|
|
13
|
+
/** Stops accepting connections and resolves once the server is closed. */
|
|
14
|
+
close(): Promise<void> | void;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The host-specific operations the framework needs. Core never calls a host API directly
|
|
18
|
+
* (`Bun.*`, `process.exit`, a server's `listen`): it asks the current runtime.
|
|
19
|
+
*
|
|
20
|
+
* Implementations ship as packages: `@elysiumjs/runtime-bun`, `@elysiumjs/runtime-node` and
|
|
21
|
+
* `@elysiumjs/runtime-workers`. Set one with the `runtime` option of `@Application.register()`
|
|
22
|
+
* or with {@link Runtime.use}.
|
|
23
|
+
*
|
|
24
|
+
* The runtime is process-wide: the last application constructed wins.
|
|
25
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* The level of a line written to the console.
|
|
29
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
30
|
+
*/
|
|
31
|
+
export type OutputLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
32
|
+
export interface Runtime {
|
|
33
|
+
/** A short name for the runtime, used in error messages. */
|
|
34
|
+
readonly name: string;
|
|
35
|
+
/** The raw environment variables, before validation. */
|
|
36
|
+
env(): Record<string, string | undefined>;
|
|
37
|
+
/**
|
|
38
|
+
* Waits for the given duration.
|
|
39
|
+
* @param ms The duration, in milliseconds.
|
|
40
|
+
*/
|
|
41
|
+
sleep(ms: number): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Starts serving the app on the given port.
|
|
44
|
+
* @param app The root Elysia app.
|
|
45
|
+
* @param port The port to listen on.
|
|
46
|
+
* @returns A handle that closes the server, when stopping the Elysia app does not.
|
|
47
|
+
* @throws {RuntimeNotSupportedError} On runtimes where the host owns the server.
|
|
48
|
+
*/
|
|
49
|
+
serve(app: AnyElysia, port: number): ServeHandle | void;
|
|
50
|
+
/**
|
|
51
|
+
* Ends the process with the given exit code. A no-op on runtimes without a process.
|
|
52
|
+
* @param code The exit code.
|
|
53
|
+
*/
|
|
54
|
+
exit(code: number): void;
|
|
55
|
+
/**
|
|
56
|
+
* Calls `handler` when the process is asked to stop.
|
|
57
|
+
* @param handler The handler to call.
|
|
58
|
+
* @returns A function that removes the handler.
|
|
59
|
+
*/
|
|
60
|
+
onShutdown(handler: () => void): () => void;
|
|
61
|
+
/**
|
|
62
|
+
* The command line arguments after the script. Empty on runtimes without a command line.
|
|
63
|
+
*/
|
|
64
|
+
argv(): readonly string[];
|
|
65
|
+
/**
|
|
66
|
+
* Writes text to the standard output or error stream. Runtimes without streams write to
|
|
67
|
+
* the console instead.
|
|
68
|
+
* @param stream The stream to write to.
|
|
69
|
+
* @param text The text to write, as is.
|
|
70
|
+
* @param level The level of the text, for runtimes whose console keeps one per line, such as
|
|
71
|
+
* Cloudflare Workers.
|
|
72
|
+
*/
|
|
73
|
+
write(stream: 'stdout' | 'stderr', text: string, level?: OutputLevel): void;
|
|
74
|
+
/**
|
|
75
|
+
* The interactive terminal, or `undefined` on runtimes without one.
|
|
76
|
+
*/
|
|
77
|
+
terminal(): RuntimeTerminal | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* The address of the client that sent a request, as the host sees it (before any proxy
|
|
80
|
+
* headers), or `undefined` when unknown.
|
|
81
|
+
* @param request The request.
|
|
82
|
+
*/
|
|
83
|
+
clientAddress?(request: Request): string | undefined;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* An interactive terminal, as exposed by a runtime.
|
|
87
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
88
|
+
*/
|
|
89
|
+
export interface RuntimeTerminal {
|
|
90
|
+
/** The stream user input is read from. */
|
|
91
|
+
input: NodeJS.ReadableStream;
|
|
92
|
+
/** The stream output is written to. */
|
|
93
|
+
output: NodeJS.WritableStream;
|
|
94
|
+
/**
|
|
95
|
+
* Turns raw mode on or off on the input, when supported.
|
|
96
|
+
* @param on Whether raw mode is on.
|
|
97
|
+
*/
|
|
98
|
+
setRawMode?(on: boolean): void;
|
|
99
|
+
/** Clears the screen. */
|
|
100
|
+
clear(): void;
|
|
101
|
+
/**
|
|
102
|
+
* Moves the cursor relative to its current position.
|
|
103
|
+
* @param x The columns to move by.
|
|
104
|
+
* @param y The rows to move by.
|
|
105
|
+
*/
|
|
106
|
+
moveCursor(x: number, y: number): void;
|
|
107
|
+
/** Clears the current line and moves the cursor to its start. */
|
|
108
|
+
clearLine(): void;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Thrown when a feature needs a host API the current runtime does not have.
|
|
112
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
113
|
+
*/
|
|
114
|
+
export declare class RuntimeNotSupportedError extends ElysiumError {
|
|
115
|
+
constructor(feature: string, runtime: string, hint?: string);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Thrown when the framework needs the runtime before one was set.
|
|
119
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
120
|
+
*/
|
|
121
|
+
export declare class RuntimeNotConfiguredError extends ElysiumError {
|
|
122
|
+
constructor();
|
|
123
|
+
}
|
|
124
|
+
export declare namespace Runtime {
|
|
125
|
+
/**
|
|
126
|
+
* Gets the runtime in use.
|
|
127
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
128
|
+
* @throws {RuntimeNotConfiguredError} When no runtime was set.
|
|
129
|
+
*/
|
|
130
|
+
const get: () => Runtime;
|
|
131
|
+
/**
|
|
132
|
+
* Gets the runtime in use, or `undefined` when none was set.
|
|
133
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
134
|
+
*/
|
|
135
|
+
const find: () => Runtime | undefined;
|
|
136
|
+
/**
|
|
137
|
+
* Sets the runtime to use. The runtime is process-wide: when several applications are
|
|
138
|
+
* constructed, the last one to set a runtime wins.
|
|
139
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
140
|
+
* @param runtime The runtime to use.
|
|
141
|
+
*/
|
|
142
|
+
const use: (runtime: Runtime) => void;
|
|
143
|
+
/**
|
|
144
|
+
* Forgets the runtime in use.
|
|
145
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
146
|
+
*/
|
|
147
|
+
const reset: () => void;
|
|
148
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import type { AnyElysia } from 'elysia';
|
|
2
|
+
import { ElysiumError } from './errors';
|
|
3
|
+
/**
|
|
4
|
+
* Cross-origin resource sharing options.
|
|
5
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
6
|
+
*/
|
|
7
|
+
export type CorsOptions = {
|
|
8
|
+
/**
|
|
9
|
+
* The allowed origins: `*`, one origin, a list, a pattern, or a function of the origin and the
|
|
10
|
+
* request.
|
|
11
|
+
*/
|
|
12
|
+
origin: string | string[] | RegExp | ((origin: string, request: Request) => boolean);
|
|
13
|
+
/** The allowed methods. Defaults to GET, HEAD, PUT, PATCH, POST and DELETE. */
|
|
14
|
+
methods?: string[];
|
|
15
|
+
/** The allowed request headers. Defaults to the headers the preflight asks for. */
|
|
16
|
+
allowedHeaders?: string[];
|
|
17
|
+
/** The response headers the browser may read. */
|
|
18
|
+
exposedHeaders?: string[];
|
|
19
|
+
/** Whether to allow cookies and authorization headers. Not allowed with `origin: '*'`. */
|
|
20
|
+
credentials?: boolean;
|
|
21
|
+
/** How long the browser may cache a preflight answer, in seconds. */
|
|
22
|
+
maxAge?: number;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Security response headers. `true` sends the default of a header, `false` or omitting it sends
|
|
26
|
+
* nothing, and a string sends that value.
|
|
27
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
28
|
+
*/
|
|
29
|
+
export type SecurityHeadersOptions = {
|
|
30
|
+
/** No default: an API serving JSON rarely needs one. */
|
|
31
|
+
contentSecurityPolicy?: string | false;
|
|
32
|
+
/** `max-age=15552000; includeSubDomains`, only sent on HTTPS requests. */
|
|
33
|
+
strictTransportSecurity?: string | boolean;
|
|
34
|
+
/** `nosniff`. */
|
|
35
|
+
xContentTypeOptions?: boolean;
|
|
36
|
+
/** `no-referrer`. */
|
|
37
|
+
referrerPolicy?: string | boolean;
|
|
38
|
+
/** `same-origin`. */
|
|
39
|
+
crossOriginOpenerPolicy?: string | boolean;
|
|
40
|
+
/** `same-origin`. */
|
|
41
|
+
crossOriginResourcePolicy?: string | boolean;
|
|
42
|
+
/** `DENY`. */
|
|
43
|
+
xFrameOptions?: string | boolean;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* The HTTP options of an application, set with `http` on `@Application.register()`.
|
|
47
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
48
|
+
*/
|
|
49
|
+
export type HttpOptions = {
|
|
50
|
+
/** Cross-origin resource sharing. Off unless set. */
|
|
51
|
+
cors?: CorsOptions | false;
|
|
52
|
+
/** Security headers: `true` for the defaults, or per header. */
|
|
53
|
+
headers?: SecurityHeadersOptions | boolean;
|
|
54
|
+
/**
|
|
55
|
+
* The largest request body the app parses, in bytes. Defaults to 1 MiB. Counted while reading,
|
|
56
|
+
* so it holds for chunked bodies and on every runtime. `false` turns it off.
|
|
57
|
+
*/
|
|
58
|
+
bodyLimit?: number | false;
|
|
59
|
+
/**
|
|
60
|
+
* Which proxies to trust for the client address and protocol (`ctx.ip`, HSTS): `true` trusts
|
|
61
|
+
* every hop, a number trusts that many hops, and a list trusts those addresses.
|
|
62
|
+
*/
|
|
63
|
+
trustProxy?: boolean | number | string[];
|
|
64
|
+
};
|
|
65
|
+
/** The default body limit: 1 MiB. */
|
|
66
|
+
export declare const DEFAULT_BODY_LIMIT: number;
|
|
67
|
+
declare const PayloadTooLargeError_base: {
|
|
68
|
+
new (detail?: string, options?: import("./problem").DomainErrorOptions): {
|
|
69
|
+
name: string;
|
|
70
|
+
message: string;
|
|
71
|
+
stack?: string;
|
|
72
|
+
cause?: unknown;
|
|
73
|
+
value?(): import("elysia/types").MaybePromise<unknown>;
|
|
74
|
+
readonly code: "PAYLOAD_TOO_LARGE";
|
|
75
|
+
readonly status: 413;
|
|
76
|
+
readonly detail: string | undefined;
|
|
77
|
+
readonly title: string;
|
|
78
|
+
readonly errors: readonly import("./problem").ProblemValidationError[] | undefined;
|
|
79
|
+
readonly retryAfterSeconds: number | undefined;
|
|
80
|
+
readonly extensions: Readonly<Record<string, unknown>>;
|
|
81
|
+
readonly headers: Record<string, string> | undefined;
|
|
82
|
+
get type(): string;
|
|
83
|
+
extension(): Record<string, unknown>;
|
|
84
|
+
};
|
|
85
|
+
isError(error: unknown): error is Error;
|
|
86
|
+
isError(value: unknown): value is Error;
|
|
87
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
88
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
89
|
+
prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
|
|
90
|
+
stackTraceLimit: number;
|
|
91
|
+
id<const Type extends string>(code: Type): import("elysia").TaggedHTTPError<Type>;
|
|
92
|
+
id<const Type extends string, const S extends number | keyof import("elysia").StatusMap>(code: Type, status: S): import("elysia").TaggedHTTPError<Type, {
|
|
93
|
+
readonly status: S extends keyof import("elysia").StatusMap ? import("elysia").StatusMap[S] : S;
|
|
94
|
+
}>;
|
|
95
|
+
typeBase?: string;
|
|
96
|
+
for<const C extends import("./problem").ProblemCode, const S extends number>(code: C, status: S): {
|
|
97
|
+
new (detail?: string, options?: import("./problem").DomainErrorOptions): {
|
|
98
|
+
name: string;
|
|
99
|
+
message: string;
|
|
100
|
+
stack?: string;
|
|
101
|
+
cause?: unknown;
|
|
102
|
+
value?(): import("elysia/types").MaybePromise<unknown>;
|
|
103
|
+
readonly code: C;
|
|
104
|
+
readonly status: S;
|
|
105
|
+
readonly detail: string | undefined;
|
|
106
|
+
readonly title: string;
|
|
107
|
+
readonly errors: readonly import("./problem").ProblemValidationError[] | undefined;
|
|
108
|
+
readonly retryAfterSeconds: number | undefined;
|
|
109
|
+
readonly extensions: Readonly<Record<string, unknown>>;
|
|
110
|
+
readonly headers: Record<string, string> | undefined;
|
|
111
|
+
get type(): string;
|
|
112
|
+
extension(): Record<string, unknown>;
|
|
113
|
+
};
|
|
114
|
+
isError(error: unknown): error is Error;
|
|
115
|
+
isError(value: unknown): value is Error;
|
|
116
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
117
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
118
|
+
prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
|
|
119
|
+
stackTraceLimit: number;
|
|
120
|
+
id<const Type extends string>(code: Type): import("elysia").TaggedHTTPError<Type>;
|
|
121
|
+
id<const Type extends string, const S_1 extends number | keyof import("elysia").StatusMap>(code: Type, status: S_1): import("elysia").TaggedHTTPError<Type, {
|
|
122
|
+
readonly status: S_1 extends keyof import("elysia").StatusMap ? import("elysia").StatusMap[S_1] : S_1;
|
|
123
|
+
}>;
|
|
124
|
+
typeBase?: string;
|
|
125
|
+
for<const C extends import("./problem").ProblemCode, const S extends number>(code: C, status: S): /*elided*/ any;
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Raised when a request body is larger than the body limit. Rendered as a 413 problem.
|
|
130
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
131
|
+
*/
|
|
132
|
+
export declare class PayloadTooLargeError extends PayloadTooLargeError_base {
|
|
133
|
+
readonly limit: number;
|
|
134
|
+
constructor(limit: number);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Thrown at startup when CORS allows every origin with credentials, which browsers refuse.
|
|
138
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
139
|
+
*/
|
|
140
|
+
export declare class InvalidCorsOptionsError extends ElysiumError {
|
|
141
|
+
constructor();
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* The client address of a request, from the trusted proxy headers or the runtime.
|
|
145
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
146
|
+
* @param request The request.
|
|
147
|
+
* @param trustProxy Which proxies to trust.
|
|
148
|
+
*/
|
|
149
|
+
export declare const clientAddress: (request: Request, trustProxy: HttpOptions['trustProxy']) => string | undefined;
|
|
150
|
+
/**
|
|
151
|
+
* Registers the HTTP security hooks of an application on its root Elysia app: CORS, security
|
|
152
|
+
* headers, the body limit and the client address (`ctx.ip`).
|
|
153
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
154
|
+
* @param app The root Elysia app.
|
|
155
|
+
* @param options The `http` option of the application.
|
|
156
|
+
* @throws {InvalidCorsOptionsError} When CORS allows every origin with credentials.
|
|
157
|
+
*/
|
|
158
|
+
export declare const applyHttpSecurity: (app: AnyElysia, options?: HttpOptions) => void;
|
|
159
|
+
export {};
|