@usetoki/toki 0.1.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.
- package/LICENSE +21 -0
- package/README.md +177 -0
- package/dist/app.d.ts +137 -0
- package/dist/app.js +608 -0
- package/dist/app.js.map +1 -0
- package/dist/cookies.d.ts +17 -0
- package/dist/cookies.js +54 -0
- package/dist/cookies.js.map +1 -0
- package/dist/forms.d.ts +13 -0
- package/dist/forms.js +64 -0
- package/dist/forms.js.map +1 -0
- package/dist/group.d.ts +19 -0
- package/dist/group.js +51 -0
- package/dist/group.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/inject.d.ts +19 -0
- package/dist/inject.js +56 -0
- package/dist/inject.js.map +1 -0
- package/dist/jwt.d.ts +57 -0
- package/dist/jwt.js +128 -0
- package/dist/jwt.js.map +1 -0
- package/dist/logger.d.ts +7 -0
- package/dist/logger.js +45 -0
- package/dist/logger.js.map +1 -0
- package/dist/middleware.d.ts +38 -0
- package/dist/middleware.js +133 -0
- package/dist/middleware.js.map +1 -0
- package/dist/native.d.ts +81 -0
- package/dist/native.js +38 -0
- package/dist/native.js.map +1 -0
- package/dist/pipeline.d.ts +16 -0
- package/dist/pipeline.js +125 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/request.d.ts +65 -0
- package/dist/request.js +170 -0
- package/dist/request.js.map +1 -0
- package/dist/response.d.ts +33 -0
- package/dist/response.js +92 -0
- package/dist/response.js.map +1 -0
- package/dist/schema.d.ts +45 -0
- package/dist/schema.js +179 -0
- package/dist/schema.js.map +1 -0
- package/dist/static.d.ts +20 -0
- package/dist/static.js +105 -0
- package/dist/static.js.map +1 -0
- package/dist/types.d.ts +88 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +63 -0
package/dist/cookies.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const COOKIE_NAME = /^[\w!#$%&'*.^`|~+-]+$/;
|
|
2
|
+
/** Parses a `Cookie` header into a name → value map. Duplicate names: first wins. */
|
|
3
|
+
export function parseCookies(header) {
|
|
4
|
+
const out = {};
|
|
5
|
+
for (const part of header.split(";")) {
|
|
6
|
+
const eq = part.indexOf("=");
|
|
7
|
+
const name = (eq === -1 ? part : part.slice(0, eq)).trim();
|
|
8
|
+
if (name.length === 0 || name in out) {
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
let value = eq === -1 ? "" : part.slice(eq + 1).trim();
|
|
12
|
+
if (value.length >= 2 && value.startsWith('"') && value.endsWith('"')) {
|
|
13
|
+
value = value.slice(1, -1);
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
out[name] = decodeURIComponent(value);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
out[name] = value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return Object.freeze(out);
|
|
23
|
+
}
|
|
24
|
+
/** Serializes one `Set-Cookie` header value. Throws on an invalid name. */
|
|
25
|
+
export function serializeCookie(name, value, options = {}) {
|
|
26
|
+
if (!COOKIE_NAME.test(name)) {
|
|
27
|
+
throw new TypeError(`Invalid cookie name: ${name}`);
|
|
28
|
+
}
|
|
29
|
+
let cookie = `${name}=${encodeURIComponent(value)}`;
|
|
30
|
+
if (options.maxAge !== undefined) {
|
|
31
|
+
cookie += `; Max-Age=${Math.trunc(options.maxAge)}`;
|
|
32
|
+
}
|
|
33
|
+
if (options.domain) {
|
|
34
|
+
cookie += `; Domain=${options.domain}`;
|
|
35
|
+
}
|
|
36
|
+
cookie += `; Path=${options.path ?? "/"}`;
|
|
37
|
+
if (options.expires) {
|
|
38
|
+
cookie += `; Expires=${options.expires.toUTCString()}`;
|
|
39
|
+
}
|
|
40
|
+
if (options.httpOnly) {
|
|
41
|
+
cookie += "; HttpOnly";
|
|
42
|
+
}
|
|
43
|
+
if (options.secure) {
|
|
44
|
+
cookie += "; Secure";
|
|
45
|
+
}
|
|
46
|
+
if (options.partitioned) {
|
|
47
|
+
cookie += "; Partitioned";
|
|
48
|
+
}
|
|
49
|
+
if (options.sameSite) {
|
|
50
|
+
cookie += `; SameSite=${options.sameSite}`;
|
|
51
|
+
}
|
|
52
|
+
return cookie;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=cookies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookies.js","sourceRoot":"","sources":["../ts/cookies.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,GAAG,uBAAuB,CAAC;AAE5C,qFAAqF;AACrF,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,MAAM,GAAG,GAAuC,EAAE,CAAC;IACnD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;YACrC,SAAS;QACX,CAAC;QACD,IAAI,KAAK,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACvD,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACtE,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;QACD,IAAI,CAAC;YACH,GAAG,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;QACxC,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QACpB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,KAAa,EAAE,UAAyB,EAAE;IACtF,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,SAAS,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,MAAM,GAAG,GAAG,IAAI,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;IACpD,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,IAAI,aAAa,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;IACtD,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,IAAI,YAAY,OAAO,CAAC,MAAM,EAAE,CAAC;IACzC,CAAC;IACD,MAAM,IAAI,UAAU,OAAO,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;IAC1C,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,aAAa,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;IACzD,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,IAAI,YAAY,CAAC;IACzB,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,IAAI,UAAU,CAAC;IACvB,CAAC;IACD,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,IAAI,eAAe,CAAC;IAC5B,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,IAAI,cAAc,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC7C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/forms.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** An uploaded file from a multipart form. */
|
|
2
|
+
export interface FormFile {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly filename: string;
|
|
5
|
+
readonly contentType: string;
|
|
6
|
+
readonly data: Uint8Array;
|
|
7
|
+
}
|
|
8
|
+
export interface ParsedForm {
|
|
9
|
+
readonly fields: Record<string, string>;
|
|
10
|
+
readonly files: ReadonlyArray<FormFile>;
|
|
11
|
+
}
|
|
12
|
+
/** Parse a request body by content type; null for unrecognized types. */
|
|
13
|
+
export declare function parseForm(contentType: string, body: Uint8Array): ParsedForm | null;
|
package/dist/forms.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** Parse a request body by content type; null for unrecognized types. */
|
|
2
|
+
export function parseForm(contentType, body) {
|
|
3
|
+
const type = contentType.toLowerCase();
|
|
4
|
+
if (type.startsWith("application/x-www-form-urlencoded")) {
|
|
5
|
+
return parseUrlencoded(body);
|
|
6
|
+
}
|
|
7
|
+
if (type.startsWith("multipart/form-data")) {
|
|
8
|
+
const boundary = /boundary=("?)([^";]+)\1/i.exec(contentType)?.[2];
|
|
9
|
+
return boundary ? parseMultipart(body, boundary) : { fields: {}, files: [] };
|
|
10
|
+
}
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
function parseUrlencoded(body) {
|
|
14
|
+
const params = new URLSearchParams(Buffer.from(body).toString("utf8"));
|
|
15
|
+
const fields = {};
|
|
16
|
+
for (const [name, value] of params) {
|
|
17
|
+
fields[name] = value;
|
|
18
|
+
}
|
|
19
|
+
return { fields, files: [] };
|
|
20
|
+
}
|
|
21
|
+
const DASH_DASH = Buffer.from("--");
|
|
22
|
+
const CRLF = Buffer.from("\r\n");
|
|
23
|
+
const HEADER_END = Buffer.from("\r\n\r\n");
|
|
24
|
+
function parseMultipart(body, boundary) {
|
|
25
|
+
const buf = Buffer.from(body.buffer, body.byteOffset, body.byteLength);
|
|
26
|
+
const delimiter = Buffer.from(`--${boundary}`);
|
|
27
|
+
const fields = {};
|
|
28
|
+
const files = [];
|
|
29
|
+
let pos = buf.indexOf(delimiter);
|
|
30
|
+
while (pos !== -1) {
|
|
31
|
+
pos += delimiter.length;
|
|
32
|
+
// trailing `--` marks the final boundary
|
|
33
|
+
if (buf[pos] === DASH_DASH[0] && buf[pos + 1] === DASH_DASH[1]) {
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
if (buf[pos] === CRLF[0] && buf[pos + 1] === CRLF[1]) {
|
|
37
|
+
pos += 2;
|
|
38
|
+
}
|
|
39
|
+
const headerEnd = buf.indexOf(HEADER_END, pos);
|
|
40
|
+
if (headerEnd === -1) {
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
const headerText = buf.toString("utf8", pos, headerEnd);
|
|
44
|
+
const dataStart = headerEnd + HEADER_END.length;
|
|
45
|
+
const next = buf.indexOf(delimiter, dataStart);
|
|
46
|
+
if (next === -1) {
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
// data ends just before the CRLF preceding the next delimiter
|
|
50
|
+
const data = buf.subarray(dataStart, next - CRLF.length);
|
|
51
|
+
const name = /name="([^"]*)"/i.exec(headerText)?.[1] ?? "";
|
|
52
|
+
const filename = /filename="([^"]*)"/i.exec(headerText)?.[1];
|
|
53
|
+
if (filename !== undefined) {
|
|
54
|
+
const contentType = /content-type:\s*([^\r\n]+)/i.exec(headerText)?.[1] ?? "application/octet-stream";
|
|
55
|
+
files.push({ name, filename, contentType, data: new Uint8Array(data) });
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
fields[name] = data.toString("utf8");
|
|
59
|
+
}
|
|
60
|
+
pos = next;
|
|
61
|
+
}
|
|
62
|
+
return { fields, files };
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=forms.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forms.js","sourceRoot":"","sources":["../ts/forms.ts"],"names":[],"mappings":"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"}
|
package/dist/group.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Handler, Middleware, RouteMethod } from "./types.js";
|
|
2
|
+
export declare function joinPaths(prefix: string, path: string): string;
|
|
3
|
+
type RegisterRoute = (method: RouteMethod, path: string, handler: Handler, middleware: Middleware[]) => void;
|
|
4
|
+
/** Prefixed route group; its middleware runs after the app's. */
|
|
5
|
+
export declare class RouteGroup {
|
|
6
|
+
#private;
|
|
7
|
+
constructor(prefix: string, register: RegisterRoute);
|
|
8
|
+
/** Add middleware scoped to this group. */
|
|
9
|
+
use(middleware: Middleware): this;
|
|
10
|
+
get(path: string, handler: Handler): this;
|
|
11
|
+
post(path: string, handler: Handler): this;
|
|
12
|
+
put(path: string, handler: Handler): this;
|
|
13
|
+
patch(path: string, handler: Handler): this;
|
|
14
|
+
delete(path: string, handler: Handler): this;
|
|
15
|
+
head(path: string, handler: Handler): this;
|
|
16
|
+
options(path: string, handler: Handler): this;
|
|
17
|
+
route(method: RouteMethod, path: string, handler: Handler): this;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
package/dist/group.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export function joinPaths(prefix, path) {
|
|
2
|
+
const left = prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
|
|
3
|
+
const right = path.startsWith("/") ? path : `/${path}`;
|
|
4
|
+
return `${left}${right}` || "/";
|
|
5
|
+
}
|
|
6
|
+
/** Prefixed route group; its middleware runs after the app's. */
|
|
7
|
+
export class RouteGroup {
|
|
8
|
+
#prefix;
|
|
9
|
+
#register;
|
|
10
|
+
// shared by ref with every registered route, so `use` after a route still
|
|
11
|
+
// applies (resolves at listen)
|
|
12
|
+
#middleware = [];
|
|
13
|
+
constructor(prefix, register) {
|
|
14
|
+
this.#prefix = prefix;
|
|
15
|
+
this.#register = register;
|
|
16
|
+
}
|
|
17
|
+
/** Add middleware scoped to this group. */
|
|
18
|
+
use(middleware) {
|
|
19
|
+
this.#middleware.push(middleware);
|
|
20
|
+
return this;
|
|
21
|
+
}
|
|
22
|
+
get(path, handler) {
|
|
23
|
+
return this.#add("GET", path, handler);
|
|
24
|
+
}
|
|
25
|
+
post(path, handler) {
|
|
26
|
+
return this.#add("POST", path, handler);
|
|
27
|
+
}
|
|
28
|
+
put(path, handler) {
|
|
29
|
+
return this.#add("PUT", path, handler);
|
|
30
|
+
}
|
|
31
|
+
patch(path, handler) {
|
|
32
|
+
return this.#add("PATCH", path, handler);
|
|
33
|
+
}
|
|
34
|
+
delete(path, handler) {
|
|
35
|
+
return this.#add("DELETE", path, handler);
|
|
36
|
+
}
|
|
37
|
+
head(path, handler) {
|
|
38
|
+
return this.#add("HEAD", path, handler);
|
|
39
|
+
}
|
|
40
|
+
options(path, handler) {
|
|
41
|
+
return this.#add("OPTIONS", path, handler);
|
|
42
|
+
}
|
|
43
|
+
route(method, path, handler) {
|
|
44
|
+
return this.#add(method, path, handler);
|
|
45
|
+
}
|
|
46
|
+
#add(method, path, handler) {
|
|
47
|
+
this.#register(method, joinPaths(this.#prefix, path), handler, this.#middleware);
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=group.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group.js","sourceRoot":"","sources":["../ts/group.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,SAAS,CAAC,MAAc,EAAE,IAAY;IACpD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACjE,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IACvD,OAAO,GAAG,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,CAAC;AAClC,CAAC;AASD,iEAAiE;AACjE,MAAM,OAAO,UAAU;IACZ,OAAO,CAAS;IAChB,SAAS,CAAgB;IAClC,0EAA0E;IAC1E,+BAA+B;IACtB,WAAW,GAAiB,EAAE,CAAC;IAExC,YAAY,MAAc,EAAE,QAAuB;QACjD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;IAC5B,CAAC;IAED,2CAA2C;IAC3C,GAAG,CAAC,UAAsB;QACxB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,GAAG,CAAC,IAAY,EAAE,OAAgB;QAChC,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IACD,IAAI,CAAC,IAAY,EAAE,OAAgB;QACjC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IACD,GAAG,CAAC,IAAY,EAAE,OAAgB;QAChC,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IACD,KAAK,CAAC,IAAY,EAAE,OAAgB;QAClC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;IACD,MAAM,CAAC,IAAY,EAAE,OAAgB;QACnC,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IACD,IAAI,CAAC,IAAY,EAAE,OAAgB;QACjC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,CAAC,IAAY,EAAE,OAAgB;QACpC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IACD,KAAK,CAAC,MAAmB,EAAE,IAAY,EAAE,OAAgB;QACvD,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,CAAC,MAAmB,EAAE,IAAY,EAAE,OAAgB;QACtD,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACjF,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { createApp, Scope, Toki } from "./app.js";
|
|
2
|
+
export type { TokiInstance, TokiPlugin } from "./app.js";
|
|
3
|
+
export { RouteGroup } from "./group.js";
|
|
4
|
+
export type { InjectOptions, InjectResponse } from "./inject.js";
|
|
5
|
+
export { TokiRequest } from "./request.js";
|
|
6
|
+
export { reply } from "./response.js";
|
|
7
|
+
export { parseCookies, serializeCookie } from "./cookies.js";
|
|
8
|
+
export type { CookieOptions } from "./cookies.js";
|
|
9
|
+
export { createConsoleLogger, silentLogger } from "./logger.js";
|
|
10
|
+
export { compression, corsHeaders, corsPreflight, securityHeaders } from "./middleware.js";
|
|
11
|
+
export type { CompressionOptions, CorsOptions, SecurityOptions } from "./middleware.js";
|
|
12
|
+
export { serialize, validate } from "./schema.js";
|
|
13
|
+
export type { ErrorMessages, JSONSchema, RouteSchema } from "./schema.js";
|
|
14
|
+
export { JwtError, jwtAuth, signJwt, verifyJwt } from "./jwt.js";
|
|
15
|
+
export type { JwtAlgorithm, JwtAuthOptions, JwtPayload, SignOptions, VerifyOptions, } from "./jwt.js";
|
|
16
|
+
export type { FormFile, ParsedForm } from "./forms.js";
|
|
17
|
+
export type { StaticOptions } from "./static.js";
|
|
18
|
+
export type { ServerOptions } from "./native.js";
|
|
19
|
+
export type { BodyParser, ContentTypeParserEntry, ErrorHandler, Handler, HandlerResult, HookName, JsonResult, LifecycleHook, ListenHandle, Logger, LogLevel, Middleware, PluginOptions, ResponseHook, RouteMethod, RouteOptions, SerializationHook, StreamResponse, StreamSource, TokiOptions, TokiResponse, } from "./types.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Public API surface.
|
|
2
|
+
export { createApp, Scope, Toki } from "./app.js";
|
|
3
|
+
export { RouteGroup } from "./group.js";
|
|
4
|
+
export { TokiRequest } from "./request.js";
|
|
5
|
+
export { reply } from "./response.js";
|
|
6
|
+
export { parseCookies, serializeCookie } from "./cookies.js";
|
|
7
|
+
export { createConsoleLogger, silentLogger } from "./logger.js";
|
|
8
|
+
export { compression, corsHeaders, corsPreflight, securityHeaders } from "./middleware.js";
|
|
9
|
+
export { serialize, validate } from "./schema.js";
|
|
10
|
+
export { JwtError, jwtAuth, signJwt, verifyJwt } from "./jwt.js";
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../ts/index.ts"],"names":[],"mappings":"AAAA,sBAAsB;AACtB,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAElD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE7D,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAE3F,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/inject.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** What to inject. A bare string is shorthand for `{ url }` (a GET). */
|
|
2
|
+
export interface InjectOptions {
|
|
3
|
+
method?: string;
|
|
4
|
+
url?: string;
|
|
5
|
+
headers?: Record<string, string>;
|
|
6
|
+
payload?: string | Uint8Array | Record<string, unknown> | unknown[];
|
|
7
|
+
}
|
|
8
|
+
/** Captured response, shaped after Fastify's `inject` result. */
|
|
9
|
+
export interface InjectResponse {
|
|
10
|
+
statusCode: number;
|
|
11
|
+
statusMessage: string;
|
|
12
|
+
headers: Record<string, string | string[] | undefined>;
|
|
13
|
+
body: string;
|
|
14
|
+
payload: string;
|
|
15
|
+
rawPayload: Buffer;
|
|
16
|
+
json<T = unknown>(): T;
|
|
17
|
+
}
|
|
18
|
+
/** Sends one request to `127.0.0.1:port` and resolves the captured response. */
|
|
19
|
+
export declare function inject(port: number, options: InjectOptions | string): Promise<InjectResponse>;
|
package/dist/inject.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// real HTTP/1.1 over loopback rather than a fake request, so tests hit the actual
|
|
2
|
+
// native path (parse, route, dispatch, stream, rate-limit) end to end.
|
|
3
|
+
import { request as httpRequest } from "node:http";
|
|
4
|
+
function normalize(options) {
|
|
5
|
+
const opts = typeof options === "string" ? { url: options } : options;
|
|
6
|
+
const headers = { ...(opts.headers ?? {}) };
|
|
7
|
+
let payload;
|
|
8
|
+
if (opts.payload !== undefined) {
|
|
9
|
+
if (typeof opts.payload === "string" || opts.payload instanceof Uint8Array) {
|
|
10
|
+
payload = opts.payload;
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
payload = JSON.stringify(opts.payload);
|
|
14
|
+
if (!hasHeader(headers, "content-type")) {
|
|
15
|
+
headers["content-type"] = "application/json";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
// engine reads Content-Length, not chunked request bodies — force fixed framing
|
|
19
|
+
if (!hasHeader(headers, "content-length")) {
|
|
20
|
+
headers["content-length"] = String(Buffer.byteLength(payload));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return { method: opts.method ?? "GET", url: opts.url ?? "/", headers, payload };
|
|
24
|
+
}
|
|
25
|
+
function hasHeader(headers, name) {
|
|
26
|
+
return Object.keys(headers).some((k) => k.toLowerCase() === name);
|
|
27
|
+
}
|
|
28
|
+
/** Sends one request to `127.0.0.1:port` and resolves the captured response. */
|
|
29
|
+
export function inject(port, options) {
|
|
30
|
+
const { method, url, headers, payload } = normalize(options);
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
const req = httpRequest({ host: "127.0.0.1", port, method, path: url, headers }, (res) => {
|
|
33
|
+
const chunks = [];
|
|
34
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
35
|
+
res.on("end", () => {
|
|
36
|
+
const rawPayload = Buffer.concat(chunks);
|
|
37
|
+
const body = rawPayload.toString("utf8");
|
|
38
|
+
resolve({
|
|
39
|
+
statusCode: res.statusCode ?? 0,
|
|
40
|
+
statusMessage: res.statusMessage ?? "",
|
|
41
|
+
headers: res.headers,
|
|
42
|
+
body,
|
|
43
|
+
payload: body,
|
|
44
|
+
rawPayload,
|
|
45
|
+
json: () => JSON.parse(body),
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
req.on("error", reject);
|
|
50
|
+
if (payload !== undefined) {
|
|
51
|
+
req.write(payload);
|
|
52
|
+
}
|
|
53
|
+
req.end();
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=inject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inject.js","sourceRoot":"","sources":["../ts/inject.ts"],"names":[],"mappings":"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"}
|
package/dist/jwt.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Middleware } from "./types.js";
|
|
2
|
+
declare const ALGORITHMS: {
|
|
3
|
+
readonly HS256: "sha256";
|
|
4
|
+
readonly HS384: "sha384";
|
|
5
|
+
readonly HS512: "sha512";
|
|
6
|
+
};
|
|
7
|
+
export type JwtAlgorithm = keyof typeof ALGORITHMS;
|
|
8
|
+
/** Decoded payload; registered claims typed, rest open. */
|
|
9
|
+
export interface JwtPayload {
|
|
10
|
+
iss?: string;
|
|
11
|
+
sub?: string;
|
|
12
|
+
aud?: string | string[];
|
|
13
|
+
exp?: number;
|
|
14
|
+
nbf?: number;
|
|
15
|
+
iat?: number;
|
|
16
|
+
[claim: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
export declare class JwtError extends Error {
|
|
19
|
+
constructor(message: string);
|
|
20
|
+
}
|
|
21
|
+
export interface SignOptions {
|
|
22
|
+
algorithm?: JwtAlgorithm;
|
|
23
|
+
/** Seconds until the token expires (sets `exp`). */
|
|
24
|
+
expiresIn?: number;
|
|
25
|
+
/** Seconds until the token becomes valid (sets `nbf`). */
|
|
26
|
+
notBefore?: number;
|
|
27
|
+
issuer?: string;
|
|
28
|
+
audience?: string | string[];
|
|
29
|
+
subject?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface VerifyOptions {
|
|
32
|
+
/** Accepted algs. Defaults to whatever the token claims, restricted to HS*. */
|
|
33
|
+
algorithms?: JwtAlgorithm[];
|
|
34
|
+
/** Require this `iss`. */
|
|
35
|
+
issuer?: string;
|
|
36
|
+
/** Must equal `aud`, or be in it when `aud` is an array. */
|
|
37
|
+
audience?: string;
|
|
38
|
+
/** Clock-skew tolerance in seconds for `exp`/`nbf`. Default 0. */
|
|
39
|
+
clockTolerance?: number;
|
|
40
|
+
}
|
|
41
|
+
/** Sign `payload` into a compact JWS string. */
|
|
42
|
+
export declare function signJwt(payload: JwtPayload, secret: string, options?: SignOptions): string;
|
|
43
|
+
/** Verify `token`, returning its payload or throwing {@link JwtError}. */
|
|
44
|
+
export declare function verifyJwt(token: string, secret: string, options?: VerifyOptions): JwtPayload;
|
|
45
|
+
export interface JwtAuthOptions extends VerifyOptions {
|
|
46
|
+
secret: string;
|
|
47
|
+
/** Custom token extraction (e.g. cookie); null when absent. Defaults to Bearer header. */
|
|
48
|
+
getToken?: (req: {
|
|
49
|
+
headers: Headers;
|
|
50
|
+
cookies: Readonly<Record<string, string | undefined>>;
|
|
51
|
+
}) => string | null;
|
|
52
|
+
/** Request property to attach the payload to. Default `"user"`. */
|
|
53
|
+
decorateAs?: string;
|
|
54
|
+
}
|
|
55
|
+
/** Middleware: verify JWT, attach payload (default `req.user`), or 401. */
|
|
56
|
+
export declare function jwtAuth(options: JwtAuthOptions): Middleware;
|
|
57
|
+
export {};
|
package/dist/jwt.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// HMAC-SHA JWT (HS256/384/512). signing stays in node:crypto's native C; no win re-doing SHA in Zig
|
|
2
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
3
|
+
import { reply } from "./response.js";
|
|
4
|
+
const ALGORITHMS = { HS256: "sha256", HS384: "sha384", HS512: "sha512" };
|
|
5
|
+
export class JwtError extends Error {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "JwtError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function b64urlEncode(input) {
|
|
12
|
+
return Buffer.from(input, "utf8").toString("base64url");
|
|
13
|
+
}
|
|
14
|
+
function b64urlDecode(input) {
|
|
15
|
+
return Buffer.from(input, "base64url").toString("utf8");
|
|
16
|
+
}
|
|
17
|
+
function sign(alg, secret, data) {
|
|
18
|
+
return createHmac(ALGORITHMS[alg], secret).update(data).digest("base64url");
|
|
19
|
+
}
|
|
20
|
+
function nowSeconds() {
|
|
21
|
+
return Math.floor(Date.now() / 1000);
|
|
22
|
+
}
|
|
23
|
+
/** Sign `payload` into a compact JWS string. */
|
|
24
|
+
export function signJwt(payload, secret, options = {}) {
|
|
25
|
+
const alg = options.algorithm ?? "HS256";
|
|
26
|
+
const claims = { iat: nowSeconds(), ...payload };
|
|
27
|
+
if (options.expiresIn !== undefined)
|
|
28
|
+
claims.exp = nowSeconds() + options.expiresIn;
|
|
29
|
+
if (options.notBefore !== undefined)
|
|
30
|
+
claims.nbf = nowSeconds() + options.notBefore;
|
|
31
|
+
if (options.issuer !== undefined)
|
|
32
|
+
claims.iss = options.issuer;
|
|
33
|
+
if (options.audience !== undefined)
|
|
34
|
+
claims.aud = options.audience;
|
|
35
|
+
if (options.subject !== undefined)
|
|
36
|
+
claims.sub = options.subject;
|
|
37
|
+
const header = b64urlEncode(JSON.stringify({ alg, typ: "JWT" }));
|
|
38
|
+
const body = b64urlEncode(JSON.stringify(claims));
|
|
39
|
+
const data = `${header}.${body}`;
|
|
40
|
+
return `${data}.${sign(alg, secret, data)}`;
|
|
41
|
+
}
|
|
42
|
+
// constant-time compare; timingSafeEqual throws on length mismatch, so length-check first
|
|
43
|
+
function safeEqual(a, b) {
|
|
44
|
+
const ba = Buffer.from(a);
|
|
45
|
+
const bb = Buffer.from(b);
|
|
46
|
+
if (ba.length !== bb.length) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return timingSafeEqual(ba, bb);
|
|
50
|
+
}
|
|
51
|
+
/** Verify `token`, returning its payload or throwing {@link JwtError}. */
|
|
52
|
+
export function verifyJwt(token, secret, options = {}) {
|
|
53
|
+
const parts = token.split(".");
|
|
54
|
+
if (parts.length !== 3) {
|
|
55
|
+
throw new JwtError("malformed token");
|
|
56
|
+
}
|
|
57
|
+
const [header, body, signature] = parts;
|
|
58
|
+
let alg;
|
|
59
|
+
try {
|
|
60
|
+
alg = JSON.parse(b64urlDecode(header)).alg;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
throw new JwtError("malformed header");
|
|
64
|
+
}
|
|
65
|
+
if (!(alg in ALGORITHMS)) {
|
|
66
|
+
throw new JwtError(`unsupported algorithm: ${alg}`);
|
|
67
|
+
}
|
|
68
|
+
if (options.algorithms && !options.algorithms.includes(alg)) {
|
|
69
|
+
throw new JwtError(`algorithm not allowed: ${alg}`);
|
|
70
|
+
}
|
|
71
|
+
if (!safeEqual(signature, sign(alg, secret, `${header}.${body}`))) {
|
|
72
|
+
throw new JwtError("invalid signature");
|
|
73
|
+
}
|
|
74
|
+
let payload;
|
|
75
|
+
try {
|
|
76
|
+
payload = JSON.parse(b64urlDecode(body));
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
throw new JwtError("malformed payload");
|
|
80
|
+
}
|
|
81
|
+
const skew = options.clockTolerance ?? 0;
|
|
82
|
+
const now = nowSeconds();
|
|
83
|
+
if (typeof payload.exp === "number" && now >= payload.exp + skew) {
|
|
84
|
+
throw new JwtError("token expired");
|
|
85
|
+
}
|
|
86
|
+
if (typeof payload.nbf === "number" && now < payload.nbf - skew) {
|
|
87
|
+
throw new JwtError("token not yet active");
|
|
88
|
+
}
|
|
89
|
+
if (options.issuer !== undefined && payload.iss !== options.issuer) {
|
|
90
|
+
throw new JwtError("issuer mismatch");
|
|
91
|
+
}
|
|
92
|
+
if (options.audience !== undefined) {
|
|
93
|
+
const aud = payload.aud;
|
|
94
|
+
const ok = Array.isArray(aud) ? aud.includes(options.audience) : aud === options.audience;
|
|
95
|
+
if (!ok) {
|
|
96
|
+
throw new JwtError("audience mismatch");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return payload;
|
|
100
|
+
}
|
|
101
|
+
function bearerToken(req) {
|
|
102
|
+
const auth = req.headers.get("authorization");
|
|
103
|
+
if (!auth) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
const match = /^Bearer\s+(.+)$/i.exec(auth);
|
|
107
|
+
return match ? match[1] : null;
|
|
108
|
+
}
|
|
109
|
+
/** Middleware: verify JWT, attach payload (default `req.user`), or 401. */
|
|
110
|
+
export function jwtAuth(options) {
|
|
111
|
+
const getToken = options.getToken ?? bearerToken;
|
|
112
|
+
const property = options.decorateAs ?? "user";
|
|
113
|
+
return (req) => {
|
|
114
|
+
const token = getToken(req);
|
|
115
|
+
if (!token) {
|
|
116
|
+
return reply.json({ statusCode: 401, error: "Unauthorized", message: "missing token" }, 401);
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
req[property] = verifyJwt(token, options.secret, options);
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
const message = error instanceof JwtError ? error.message : "invalid token";
|
|
124
|
+
return reply.json({ statusCode: 401, error: "Unauthorized", message }, 401);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=jwt.js.map
|
package/dist/jwt.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.js","sourceRoot":"","sources":["../ts/jwt.ts"],"names":[],"mappings":"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"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Logger, LogLevel, TokiOptions } from "./types.js";
|
|
2
|
+
/** no-op logger; default so logging costs nothing unless opted in */
|
|
3
|
+
export declare const silentLogger: Logger;
|
|
4
|
+
/** JSON-per-line logger; drops below `level`, carries `bindings` */
|
|
5
|
+
export declare function createConsoleLogger(level?: LogLevel, bindings?: Record<string, unknown>): Logger;
|
|
6
|
+
/** resolve the `logger` option to a concrete {@link Logger} */
|
|
7
|
+
export declare function resolveLogger(option: TokiOptions["logger"]): Logger;
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const LEVELS = { debug: 10, info: 20, warn: 30, error: 40 };
|
|
2
|
+
/** no-op logger; default so logging costs nothing unless opted in */
|
|
3
|
+
export const silentLogger = {
|
|
4
|
+
debug() { },
|
|
5
|
+
info() { },
|
|
6
|
+
warn() { },
|
|
7
|
+
error() { },
|
|
8
|
+
child() {
|
|
9
|
+
return silentLogger;
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
/** JSON-per-line logger; drops below `level`, carries `bindings` */
|
|
13
|
+
export function createConsoleLogger(level = "info", bindings = {}) {
|
|
14
|
+
const threshold = LEVELS[level];
|
|
15
|
+
function log(at, message, fields) {
|
|
16
|
+
if (LEVELS[at] < threshold) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const line = JSON.stringify({ level: at, msg: message, ...bindings, ...fields });
|
|
20
|
+
if (at === "error" || at === "warn") {
|
|
21
|
+
process.stderr.write(line + "\n");
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
process.stdout.write(line + "\n");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
debug: (m, f) => log("debug", m, f),
|
|
29
|
+
info: (m, f) => log("info", m, f),
|
|
30
|
+
warn: (m, f) => log("warn", m, f),
|
|
31
|
+
error: (m, f) => log("error", m, f),
|
|
32
|
+
child: (extra) => createConsoleLogger(level, { ...bindings, ...extra }),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** resolve the `logger` option to a concrete {@link Logger} */
|
|
36
|
+
export function resolveLogger(option) {
|
|
37
|
+
if (option === undefined || option === false) {
|
|
38
|
+
return silentLogger;
|
|
39
|
+
}
|
|
40
|
+
if (typeof option === "string") {
|
|
41
|
+
return createConsoleLogger(option);
|
|
42
|
+
}
|
|
43
|
+
return option;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../ts/logger.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,GAA6B,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AAEtF,qEAAqE;AACrE,MAAM,CAAC,MAAM,YAAY,GAAW;IAClC,KAAK,KAAI,CAAC;IACV,IAAI,KAAI,CAAC;IACT,IAAI,KAAI,CAAC;IACT,KAAK,KAAI,CAAC;IACV,KAAK;QACH,OAAO,YAAY,CAAC;IACtB,CAAC;CACF,CAAC;AAEF,oEAAoE;AACpE,MAAM,UAAU,mBAAmB,CACjC,QAAkB,MAAM,EACxB,WAAoC,EAAE;IAEtC,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAEhC,SAAS,GAAG,CAAC,EAAY,EAAE,OAAe,EAAE,MAAgC;QAC1E,IAAI,MAAM,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC;YAC3B,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;QACjF,IAAI,EAAE,KAAK,OAAO,IAAI,EAAE,KAAK,MAAM,EAAE,CAAC;YACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QACnC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QACjC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QACjC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QACnC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,mBAAmB,CAAC,KAAK,EAAE,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE,CAAC;KACxE,CAAC;AACJ,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,aAAa,CAAC,MAA6B;IACzD,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QAC7C,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Handler, Middleware, ResponseHook } from "./types.js";
|
|
2
|
+
export interface CorsOptions {
|
|
3
|
+
/** `"*"`, a fixed origin, a list, or a predicate. Default `"*"`. */
|
|
4
|
+
origin?: string | string[] | ((origin: string) => boolean);
|
|
5
|
+
methods?: string[];
|
|
6
|
+
/** preflight allow-headers; defaults to reflecting the request's */
|
|
7
|
+
allowedHeaders?: string[];
|
|
8
|
+
exposedHeaders?: string[];
|
|
9
|
+
credentials?: boolean;
|
|
10
|
+
maxAge?: number;
|
|
11
|
+
}
|
|
12
|
+
/** CORS headers for actual (non-preflight) requests. */
|
|
13
|
+
export declare function corsHeaders(options?: CorsOptions): Middleware;
|
|
14
|
+
/** Answers a CORS preflight `OPTIONS` with `204`. */
|
|
15
|
+
export declare function corsPreflight(options?: CorsOptions): Handler;
|
|
16
|
+
export interface SecurityOptions {
|
|
17
|
+
/** `X-Frame-Options`. Default `"DENY"`. */
|
|
18
|
+
frameOptions?: string;
|
|
19
|
+
/** `Referrer-Policy`. Default `"no-referrer"`. */
|
|
20
|
+
referrerPolicy?: string;
|
|
21
|
+
/** HSTS max-age in seconds, or `true` for ~180 days. Off by default. */
|
|
22
|
+
hsts?: number | true;
|
|
23
|
+
/** `Content-Security-Policy`. Off by default. */
|
|
24
|
+
csp?: string;
|
|
25
|
+
}
|
|
26
|
+
/** Defaults favor speed over ratio. */
|
|
27
|
+
export interface CompressionOptions {
|
|
28
|
+
/** min body bytes to compress. Default 1024. */
|
|
29
|
+
threshold?: number;
|
|
30
|
+
/** gzip level 0–9. Default 6. */
|
|
31
|
+
gzipLevel?: number;
|
|
32
|
+
/** brotli quality 0–11. Default 5. */
|
|
33
|
+
brotliQuality?: number;
|
|
34
|
+
}
|
|
35
|
+
/** onResponse hook: brotli/gzip per `Accept-Encoding`, off the event loop (libuv pool). */
|
|
36
|
+
export declare function compression(options?: CompressionOptions): ResponseHook;
|
|
37
|
+
/** Baseline hardening headers on every response. */
|
|
38
|
+
export declare function securityHeaders(options?: SecurityOptions): Middleware;
|