better-call 0.0.0-experimental.01ff4b77
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 +265 -0
- package/dist/capability.cjs +417 -0
- package/dist/capability.cjs.map +1 -0
- package/dist/capability.d.cts +189 -0
- package/dist/capability.d.mts +189 -0
- package/dist/capability.mjs +401 -0
- package/dist/capability.mjs.map +1 -0
- package/dist/error.cjs +76 -0
- package/dist/error.cjs.map +1 -0
- package/dist/error.d.cts +51 -0
- package/dist/error.d.mts +51 -0
- package/dist/error.mjs +72 -0
- package/dist/error.mjs.map +1 -0
- package/dist/fn.cjs +350 -0
- package/dist/fn.cjs.map +1 -0
- package/dist/fn.d.cts +378 -0
- package/dist/fn.d.mts +378 -0
- package/dist/fn.mjs +350 -0
- package/dist/fn.mjs.map +1 -0
- package/dist/index.cjs +43 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +50 -0
- package/dist/index.d.mts +50 -0
- package/dist/index.mjs +24 -0
- package/dist/index.mjs.map +1 -0
- package/dist/module.cjs +176 -0
- package/dist/module.cjs.map +1 -0
- package/dist/module.d.cts +283 -0
- package/dist/module.d.mts +283 -0
- package/dist/module.mjs +166 -0
- package/dist/module.mjs.map +1 -0
- package/dist/plugins/db.cjs +24 -0
- package/dist/plugins/db.cjs.map +1 -0
- package/dist/plugins/db.d.cts +18 -0
- package/dist/plugins/db.d.mts +18 -0
- package/dist/plugins/db.mjs +19 -0
- package/dist/plugins/db.mjs.map +1 -0
- package/dist/plugins/http/attrs.cjs +91 -0
- package/dist/plugins/http/attrs.cjs.map +1 -0
- package/dist/plugins/http/attrs.d.cts +26 -0
- package/dist/plugins/http/attrs.d.mts +26 -0
- package/dist/plugins/http/attrs.mjs +87 -0
- package/dist/plugins/http/attrs.mjs.map +1 -0
- package/dist/plugins/http/cookie.cjs +117 -0
- package/dist/plugins/http/cookie.cjs.map +1 -0
- package/dist/plugins/http/cookie.d.cts +637 -0
- package/dist/plugins/http/cookie.d.mts +637 -0
- package/dist/plugins/http/cookie.mjs +113 -0
- package/dist/plugins/http/cookie.mjs.map +1 -0
- package/dist/plugins/http/error.cjs +39 -0
- package/dist/plugins/http/error.cjs.map +1 -0
- package/dist/plugins/http/error.d.cts +38 -0
- package/dist/plugins/http/error.d.mts +38 -0
- package/dist/plugins/http/error.mjs +35 -0
- package/dist/plugins/http/error.mjs.map +1 -0
- package/dist/plugins/http/handle.cjs +73 -0
- package/dist/plugins/http/handle.cjs.map +1 -0
- package/dist/plugins/http/handle.d.cts +955 -0
- package/dist/plugins/http/handle.d.mts +955 -0
- package/dist/plugins/http/handle.mjs +72 -0
- package/dist/plugins/http/handle.mjs.map +1 -0
- package/dist/plugins/http/redirect.cjs +82 -0
- package/dist/plugins/http/redirect.cjs.map +1 -0
- package/dist/plugins/http/redirect.d.cts +67 -0
- package/dist/plugins/http/redirect.d.mts +67 -0
- package/dist/plugins/http/redirect.mjs +79 -0
- package/dist/plugins/http/redirect.mjs.map +1 -0
- package/dist/plugins/http/request.cjs +63 -0
- package/dist/plugins/http/request.cjs.map +1 -0
- package/dist/plugins/http/request.d.cts +142 -0
- package/dist/plugins/http/request.d.mts +142 -0
- package/dist/plugins/http/request.mjs +61 -0
- package/dist/plugins/http/request.mjs.map +1 -0
- package/dist/plugins/http/response.cjs +13 -0
- package/dist/plugins/http/response.cjs.map +1 -0
- package/dist/plugins/http/response.d.cts +18 -0
- package/dist/plugins/http/response.d.mts +18 -0
- package/dist/plugins/http/response.mjs +13 -0
- package/dist/plugins/http/response.mjs.map +1 -0
- package/dist/plugins/http.cjs +64 -0
- package/dist/plugins/http.cjs.map +1 -0
- package/dist/plugins/http.d.cts +945 -0
- package/dist/plugins/http.d.mts +945 -0
- package/dist/plugins/http.mjs +37 -0
- package/dist/plugins/http.mjs.map +1 -0
- package/dist/plugins/read-only.cjs +19 -0
- package/dist/plugins/read-only.cjs.map +1 -0
- package/dist/plugins/read-only.d.cts +17 -0
- package/dist/plugins/read-only.d.mts +17 -0
- package/dist/plugins/read-only.mjs +19 -0
- package/dist/plugins/read-only.mjs.map +1 -0
- package/dist/schema.cjs +245 -0
- package/dist/schema.cjs.map +1 -0
- package/dist/schema.d.cts +411 -0
- package/dist/schema.d.mts +411 -0
- package/dist/schema.mjs +235 -0
- package/dist/schema.mjs.map +1 -0
- package/dist/scope.d.cts +31 -0
- package/dist/scope.d.mts +31 -0
- package/dist/storage.cjs +308 -0
- package/dist/storage.cjs.map +1 -0
- package/dist/storage.d.cts +220 -0
- package/dist/storage.d.mts +220 -0
- package/dist/storage.mjs +302 -0
- package/dist/storage.mjs.map +1 -0
- package/dist/types.d.cts +8 -0
- package/dist/types.d.mts +8 -0
- package/dist/var.cjs +186 -0
- package/dist/var.cjs.map +1 -0
- package/dist/var.d.cts +46 -0
- package/dist/var.d.mts +46 -0
- package/dist/var.mjs +177 -0
- package/dist/var.mjs.map +1 -0
- package/package.json +114 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { v } from "../../index.mjs";
|
|
2
|
+
import { res, toResponse } from "./response.mjs";
|
|
3
|
+
import { fromRequest, req } from "./request.mjs";
|
|
4
|
+
import { cookieOptions, deleteCookie, getCookie, setCookie } from "./cookie.mjs";
|
|
5
|
+
import { Redirect, applyRedirect, redirect } from "./redirect.mjs";
|
|
6
|
+
//#region src/plugins/http/handle.ts
|
|
7
|
+
const base = {
|
|
8
|
+
req,
|
|
9
|
+
res,
|
|
10
|
+
fromRequest,
|
|
11
|
+
redirect,
|
|
12
|
+
getCookie,
|
|
13
|
+
setCookie,
|
|
14
|
+
deleteCookie,
|
|
15
|
+
cookieOptions
|
|
16
|
+
};
|
|
17
|
+
const isBodyInit = (value) => typeof value === "string" || value instanceof Blob || value instanceof ArrayBuffer || ArrayBuffer.isView(value) || value instanceof ReadableStream || value instanceof FormData || value instanceof URLSearchParams;
|
|
18
|
+
const resultToResponse = (response, out) => {
|
|
19
|
+
if (out instanceof Response) return out;
|
|
20
|
+
if (out === void 0 || out === null) return toResponse(response, null);
|
|
21
|
+
if (isBodyInit(out)) return toResponse(response, out);
|
|
22
|
+
if (!response.headers.has("content-type")) response.headers.set("content-type", "application/json");
|
|
23
|
+
return toResponse(response, JSON.stringify(out));
|
|
24
|
+
};
|
|
25
|
+
const catchRedirect = (thrown, response) => {
|
|
26
|
+
if (!(thrown instanceof Redirect)) throw thrown;
|
|
27
|
+
const current = response ?? { headers: new Headers() };
|
|
28
|
+
applyRedirect(current, thrown);
|
|
29
|
+
return toResponse(current, null);
|
|
30
|
+
};
|
|
31
|
+
/** Seed req/res, run `run` on the same `c`, settle Redirect / body. */
|
|
32
|
+
const settle = async (c, request, run) => {
|
|
33
|
+
await c.fromRequest({ request });
|
|
34
|
+
try {
|
|
35
|
+
const out = await run(c);
|
|
36
|
+
return resultToResponse(c.res ?? { headers: new Headers() }, out);
|
|
37
|
+
} catch (thrown) {
|
|
38
|
+
return catchRedirect(thrown, c.res);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Mounted web edge: seed `req`/`res` from `request`, run `run` in the
|
|
43
|
+
* same scope, and turn {@link Redirect} into a 3xx Response.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* return c.handler({
|
|
48
|
+
* request: c.input.request,
|
|
49
|
+
* run: (ctx) => {
|
|
50
|
+
* ctx.redirect({ url: "/dashboard" });
|
|
51
|
+
* },
|
|
52
|
+
* });
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
const handler = v.fn({ use: [base] }).fn("http.handler", { input: {
|
|
56
|
+
request: v.any(),
|
|
57
|
+
run: v.any()
|
|
58
|
+
} }, async (c) => settle(c, c.input.request, c.input.run));
|
|
59
|
+
/**
|
|
60
|
+
* Fetch adapter: `(request) => Response`. Modules in `options.use` are
|
|
61
|
+
* mounted on the same context as `req` / `res` / `redirect`, so
|
|
62
|
+
* `createHandler((c) => c.whoami(), { use: [{ whoami }] })` works.
|
|
63
|
+
*/
|
|
64
|
+
function createHandler(run, options) {
|
|
65
|
+
const use = [base, ...options?.use ?? []];
|
|
66
|
+
const entry = v.fn({ use }).fn("http.create_handler", { input: { request: v.any() } }, async (c) => settle(c, c.input.request, run));
|
|
67
|
+
return (request) => entry({ request });
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
export { createHandler, handler };
|
|
71
|
+
|
|
72
|
+
//# sourceMappingURL=handle.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle.mjs","names":[],"sources":["../../../src/plugins/http/handle.ts"],"sourcesContent":["import type { Context, Fn } from \"../../fn\";\nimport { v } from \"../../index\";\nimport type { ApplyOns, Module, ModuleFns } from \"../../module\";\nimport type { ScopeOf } from \"../../scope\";\nimport { cookieOptions, deleteCookie, getCookie, setCookie } from \"./cookie\";\nimport { applyRedirect, Redirect, redirect } from \"./redirect\";\nimport { fromRequest, req } from \"./request\";\nimport type { HttpResponse } from \"./response\";\nimport { res, toResponse } from \"./response\";\n\nconst base = {\n\treq,\n\tres,\n\tfromRequest,\n\tredirect,\n\tgetCookie,\n\tsetCookie,\n\tdeleteCookie,\n\tcookieOptions,\n};\n\ntype EdgeModules<PL extends readonly Module[]> = readonly [typeof base, ...PL];\n\n/** Context `run` receives: HTTP base plus anything in `options.use`. */\nexport type CreateHandlerContext<PL extends readonly Module[] = readonly []> =\n\tContext<\n\t\t{ request: Request },\n\t\tScopeOf<EdgeModules<PL>>,\n\t\tnever,\n\t\tApplyOns<ModuleFns<EdgeModules<PL>>, EdgeModules<PL>>,\n\t\tFn\n\t>;\n\nconst isBodyInit = (value: unknown): value is BodyInit =>\n\ttypeof value === \"string\" ||\n\tvalue instanceof Blob ||\n\tvalue instanceof ArrayBuffer ||\n\tArrayBuffer.isView(value) ||\n\tvalue instanceof ReadableStream ||\n\tvalue instanceof FormData ||\n\tvalue instanceof URLSearchParams;\n\nconst resultToResponse = (response: HttpResponse, out: unknown): Response => {\n\tif (out instanceof Response) return out;\n\tif (out === undefined || out === null) return toResponse(response, null);\n\tif (isBodyInit(out)) return toResponse(response, out);\n\tif (!response.headers.has(\"content-type\")) {\n\t\tresponse.headers.set(\"content-type\", \"application/json\");\n\t}\n\treturn toResponse(response, JSON.stringify(out));\n};\n\nconst catchRedirect = (\n\tthrown: unknown,\n\tresponse: HttpResponse | null | undefined,\n): Response => {\n\tif (!(thrown instanceof Redirect)) throw thrown;\n\tconst current = response ?? { headers: new Headers() };\n\tapplyRedirect(current, thrown);\n\treturn toResponse(current, null);\n};\n\n/** Seed req/res, run `run` on the same `c`, settle Redirect / body. */\nconst settle = async (\n\tc: any,\n\trequest: Request,\n\trun: (c: any) => unknown | Promise<unknown>,\n): Promise<Response> => {\n\tawait c.fromRequest({ request });\n\ttry {\n\t\tconst out = await run(c);\n\t\treturn resultToResponse(c.res ?? { headers: new Headers() }, out);\n\t} catch (thrown) {\n\t\treturn catchRedirect(thrown, c.res);\n\t}\n};\n\nconst h = v.fn({ use: [base] });\n\n/**\n * Mounted web edge: seed `req`/`res` from `request`, run `run` in the\n * same scope, and turn {@link Redirect} into a 3xx Response.\n *\n * @example\n * ```ts\n * return c.handler({\n * request: c.input.request,\n * run: (ctx) => {\n * ctx.redirect({ url: \"/dashboard\" });\n * },\n * });\n * ```\n */\nexport const handler = h.fn(\n\t\"http.handler\",\n\t{\n\t\tinput: {\n\t\t\trequest: v.any<Request>(),\n\t\t\trun: v.any<(c: any) => unknown | Promise<unknown>>(),\n\t\t},\n\t},\n\tasync (c) => settle(c, c.input.request, c.input.run),\n);\n\nexport type CreateHandlerOptions<PL extends readonly Module[] = readonly []> = {\n\t/** Extra modules mounted onto the same `c` that `run` receives. */\n\tuse?: PL;\n};\n\n/**\n * Fetch adapter: `(request) => Response`. Modules in `options.use` are\n * mounted on the same context as `req` / `res` / `redirect`, so\n * `createHandler((c) => c.whoami(), { use: [{ whoami }] })` works.\n */\nexport function createHandler<\n\tconst PL extends readonly Module[] = readonly [],\n\tR = unknown,\n>(\n\trun: (c: CreateHandlerContext<PL>) => R | Promise<R>,\n\toptions?: CreateHandlerOptions<PL>,\n): (request: Request) => Promise<Response> {\n\tconst use = [base, ...(options?.use ?? [])] as EdgeModules<PL>;\n\tconst entry = v\n\t\t.fn({ use })\n\t\t.fn(\n\t\t\t\"http.create_handler\",\n\t\t\t{ input: { request: v.any<Request>() } },\n\t\t\tasync (c) => settle(c, c.input.request, run),\n\t\t);\n\n\treturn (request) => entry({ request }) as Promise<Response>;\n}\n"],"mappings":";;;;;;AAUA,MAAM,OAAO;CACZ;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;AAcA,MAAM,cAAc,UACnB,OAAO,UAAU,YACjB,iBAAiB,QACjB,iBAAiB,eACjB,YAAY,OAAO,KAAK,KACxB,iBAAiB,kBACjB,iBAAiB,YACjB,iBAAiB;AAElB,MAAM,oBAAoB,UAAwB,QAA2B;CAC5E,IAAI,eAAe,UAAU,OAAO;CACpC,IAAI,QAAQ,KAAA,KAAa,QAAQ,MAAM,OAAO,WAAW,UAAU,IAAI;CACvE,IAAI,WAAW,GAAG,GAAG,OAAO,WAAW,UAAU,GAAG;CACpD,IAAI,CAAC,SAAS,QAAQ,IAAI,cAAc,GACvC,SAAS,QAAQ,IAAI,gBAAgB,kBAAkB;CAExD,OAAO,WAAW,UAAU,KAAK,UAAU,GAAG,CAAC;AAChD;AAEA,MAAM,iBACL,QACA,aACc;CACd,IAAI,EAAE,kBAAkB,WAAW,MAAM;CACzC,MAAM,UAAU,YAAY,EAAE,SAAS,IAAI,QAAQ,EAAE;CACrD,cAAc,SAAS,MAAM;CAC7B,OAAO,WAAW,SAAS,IAAI;AAChC;;AAGA,MAAM,SAAS,OACd,GACA,SACA,QACuB;CACvB,MAAM,EAAE,YAAY,EAAE,QAAQ,CAAC;CAC/B,IAAI;EACH,MAAM,MAAM,MAAM,IAAI,CAAC;EACvB,OAAO,iBAAiB,EAAE,OAAO,EAAE,SAAS,IAAI,QAAQ,EAAE,GAAG,GAAG;CACjE,SAAS,QAAQ;EAChB,OAAO,cAAc,QAAQ,EAAE,GAAG;CACnC;AACD;;;;;;;;;;;;;;;AAkBA,MAAa,UAhBH,EAAE,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,CAgBN,CAAA,CAAE,GACxB,gBACA,EACC,OAAO;CACN,SAAS,EAAE,IAAa;CACxB,KAAK,EAAE,IAA4C;AACpD,EACD,GACA,OAAO,MAAM,OAAO,GAAG,EAAE,MAAM,SAAS,EAAE,MAAM,GAAG,CACpD;;;;;;AAYA,SAAgB,cAIf,KACA,SAC0C;CAC1C,MAAM,MAAM,CAAC,MAAM,GAAI,SAAS,OAAO,CAAC,CAAE;CAC1C,MAAM,QAAQ,EACZ,GAAG,EAAE,IAAI,CAAC,CAAC,CACX,GACA,uBACA,EAAE,OAAO,EAAE,SAAS,EAAE,IAAa,EAAE,EAAE,GACvC,OAAO,MAAM,OAAO,GAAG,EAAE,MAAM,SAAS,GAAG,CAC5C;CAED,QAAQ,YAAY,MAAM,EAAE,QAAQ,CAAC;AACtC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
const require_error = require("../../error.cjs");
|
|
2
|
+
const require_index = require("../../index.cjs");
|
|
3
|
+
const require_response = require("./response.cjs");
|
|
4
|
+
//#region src/plugins/http/redirect.ts
|
|
5
|
+
const REDIRECT_STATUSES = [
|
|
6
|
+
301,
|
|
7
|
+
302,
|
|
8
|
+
303,
|
|
9
|
+
307,
|
|
10
|
+
308
|
|
11
|
+
];
|
|
12
|
+
/** HTTP navigation control - not a domain refusal and not a defect.
|
|
13
|
+
* Thrown by {@link redirect} after writing Location + status onto `res`. */
|
|
14
|
+
var Redirect = class extends require_error.ControlFlow {
|
|
15
|
+
url;
|
|
16
|
+
status;
|
|
17
|
+
constructor(url, status = 302) {
|
|
18
|
+
super(`redirect ${status} ${url}`);
|
|
19
|
+
this.url = url;
|
|
20
|
+
this.status = status;
|
|
21
|
+
this.name = "Redirect";
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Write a redirect onto the scope's `res`, then throw {@link Redirect}
|
|
26
|
+
* so the call stack unwinds. Catch it at the web edge with
|
|
27
|
+
* {@link handler} / {@link createHandler} (or {@link asResponse} in a
|
|
28
|
+
* manual try/catch). `.try` does not catch it.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* return c.handler({
|
|
33
|
+
* request,
|
|
34
|
+
* run: (ctx) => {
|
|
35
|
+
* ctx.redirect({ url: "/dashboard" });
|
|
36
|
+
* },
|
|
37
|
+
* });
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
const redirect = require_index.v.fn({ use: [{ res: require_response.res }] }).fn("http.redirect", { input: {
|
|
41
|
+
url: require_index.v.string(),
|
|
42
|
+
status: require_index.v.number({
|
|
43
|
+
enum: REDIRECT_STATUSES,
|
|
44
|
+
default: 302
|
|
45
|
+
})
|
|
46
|
+
} }, (c) => {
|
|
47
|
+
const { url, status } = c.input;
|
|
48
|
+
let response = c.res;
|
|
49
|
+
if (!response) {
|
|
50
|
+
response = { headers: new Headers() };
|
|
51
|
+
c.res = response;
|
|
52
|
+
}
|
|
53
|
+
response.status = status;
|
|
54
|
+
response.headers.set("location", url);
|
|
55
|
+
throw new Redirect(url, status);
|
|
56
|
+
});
|
|
57
|
+
/**
|
|
58
|
+
* Write a thrown {@link Redirect} onto `res`: status + Location.
|
|
59
|
+
* Returns the same `res` for chaining.
|
|
60
|
+
*/
|
|
61
|
+
const applyRedirect = (response, redirected) => {
|
|
62
|
+
response.status = redirected.status;
|
|
63
|
+
response.headers.set("location", redirected.url);
|
|
64
|
+
return response;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Turn a thrown {@link Redirect} into a fetch Response, preserving
|
|
68
|
+
* headers already on `response`. Any other value is rethrown.
|
|
69
|
+
*/
|
|
70
|
+
const asResponse = (thrown, response) => {
|
|
71
|
+
if (!(thrown instanceof Redirect)) throw thrown;
|
|
72
|
+
const current = response ?? { headers: new Headers() };
|
|
73
|
+
applyRedirect(current, thrown);
|
|
74
|
+
return require_response.toResponse(current, null);
|
|
75
|
+
};
|
|
76
|
+
//#endregion
|
|
77
|
+
exports.Redirect = Redirect;
|
|
78
|
+
exports.applyRedirect = applyRedirect;
|
|
79
|
+
exports.asResponse = asResponse;
|
|
80
|
+
exports.redirect = redirect;
|
|
81
|
+
|
|
82
|
+
//# sourceMappingURL=redirect.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redirect.cjs","names":["ControlFlow","v","toResponse"],"sources":["../../../src/plugins/http/redirect.ts"],"sourcesContent":["import { ControlFlow } from \"../../error\";\nimport { v } from \"../../index\";\nimport type { HttpResponse } from \"./response\";\nimport { res, toResponse } from \"./response\";\n\nexport type RedirectStatus = 301 | 302 | 303 | 307 | 308;\n\nconst REDIRECT_STATUSES = [301, 302, 303, 307, 308] as const;\n\n/** HTTP navigation control - not a domain refusal and not a defect.\n * Thrown by {@link redirect} after writing Location + status onto `res`. */\nexport class Redirect extends ControlFlow {\n\tconstructor(\n\t\tpublic url: string,\n\t\tpublic status: RedirectStatus = 302,\n\t) {\n\t\tsuper(`redirect ${status} ${url}`);\n\t\tthis.name = \"Redirect\";\n\t}\n}\n\nconst h = v.fn({ use: [{ res }] });\n\n/**\n * Write a redirect onto the scope's `res`, then throw {@link Redirect}\n * so the call stack unwinds. Catch it at the web edge with\n * {@link handler} / {@link createHandler} (or {@link asResponse} in a\n * manual try/catch). `.try` does not catch it.\n *\n * @example\n * ```ts\n * return c.handler({\n * request,\n * run: (ctx) => {\n * ctx.redirect({ url: \"/dashboard\" });\n * },\n * });\n * ```\n */\nexport const redirect = h.fn(\n\t\"http.redirect\",\n\t{\n\t\tinput: {\n\t\t\turl: v.string(),\n\t\t\tstatus: v.number({\n\t\t\t\tenum: REDIRECT_STATUSES,\n\t\t\t\tdefault: 302,\n\t\t\t}),\n\t\t},\n\t},\n\t(c): never => {\n\t\tconst { url, status } = c.input;\n\t\tlet response = c.res;\n\t\tif (!response) {\n\t\t\tresponse = { headers: new Headers() };\n\t\t\tc.res = response;\n\t\t}\n\t\tresponse.status = status;\n\t\tresponse.headers.set(\"location\", url);\n\t\tthrow new Redirect(url, status as RedirectStatus);\n\t},\n);\n\n/**\n * Write a thrown {@link Redirect} onto `res`: status + Location.\n * Returns the same `res` for chaining.\n */\nexport const applyRedirect = (\n\tresponse: HttpResponse,\n\tredirected: Redirect,\n): HttpResponse => {\n\tresponse.status = redirected.status;\n\tresponse.headers.set(\"location\", redirected.url);\n\treturn response;\n};\n\n/**\n * Turn a thrown {@link Redirect} into a fetch Response, preserving\n * headers already on `response`. Any other value is rethrown.\n */\nexport const asResponse = (\n\tthrown: unknown,\n\tresponse?: HttpResponse | null,\n): Response => {\n\tif (!(thrown instanceof Redirect)) throw thrown;\n\tconst current = response ?? { headers: new Headers() };\n\tapplyRedirect(current, thrown);\n\treturn toResponse(current, null);\n};\n"],"mappings":";;;;AAOA,MAAM,oBAAoB;CAAC;CAAK;CAAK;CAAK;CAAK;AAAG;;;AAIlD,IAAa,WAAb,cAA8BA,cAAAA,YAAY;CAEjC;CACA;CAFR,YACC,KACA,SAAgC,KAC/B;EACD,MAAM,YAAY,OAAO,GAAG,KAAK;EAH1B,KAAA,MAAA;EACA,KAAA,SAAA;EAGP,KAAK,OAAO;CACb;AACD;;;;;;;;;;;;;;;;;AAoBA,MAAa,WAlBHC,cAAAA,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,KAAA,iBAAA,IAAI,CAAC,EAAE,CAkBR,CAAA,CAAE,GACzB,iBACA,EACC,OAAO;CACN,KAAKA,cAAAA,EAAE,OAAO;CACd,QAAQA,cAAAA,EAAE,OAAO;EAChB,MAAM;EACN,SAAS;CACV,CAAC;AACF,EACD,IACC,MAAa;CACb,MAAM,EAAE,KAAK,WAAW,EAAE;CAC1B,IAAI,WAAW,EAAE;CACjB,IAAI,CAAC,UAAU;EACd,WAAW,EAAE,SAAS,IAAI,QAAQ,EAAE;EACpC,EAAE,MAAM;CACT;CACA,SAAS,SAAS;CAClB,SAAS,QAAQ,IAAI,YAAY,GAAG;CACpC,MAAM,IAAI,SAAS,KAAK,MAAwB;AACjD,CACD;;;;;AAMA,MAAa,iBACZ,UACA,eACkB;CAClB,SAAS,SAAS,WAAW;CAC7B,SAAS,QAAQ,IAAI,YAAY,WAAW,GAAG;CAC/C,OAAO;AACR;;;;;AAMA,MAAa,cACZ,QACA,aACc;CACd,IAAI,EAAE,kBAAkB,WAAW,MAAM;CACzC,MAAM,UAAU,YAAY,EAAE,SAAS,IAAI,QAAQ,EAAE;CACrD,cAAc,SAAS,MAAM;CAC7B,OAAOC,iBAAAA,WAAW,SAAS,IAAI;AAChC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ControlFlow } from "../../error.cjs";
|
|
2
|
+
import { TypeDefination } from "../../schema.cjs";
|
|
3
|
+
import { FnDefination } from "../../fn.cjs";
|
|
4
|
+
import { HttpResponse } from "./response.cjs";
|
|
5
|
+
//#region src/plugins/http/redirect.d.ts
|
|
6
|
+
type RedirectStatus = 301 | 302 | 303 | 307 | 308;
|
|
7
|
+
/** HTTP navigation control - not a domain refusal and not a defect.
|
|
8
|
+
* Thrown by {@link redirect} after writing Location + status onto `res`. */
|
|
9
|
+
declare class Redirect extends ControlFlow {
|
|
10
|
+
url: string;
|
|
11
|
+
status: RedirectStatus;
|
|
12
|
+
constructor(url: string, status?: RedirectStatus);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Write a redirect onto the scope's `res`, then throw {@link Redirect}
|
|
16
|
+
* so the call stack unwinds. Catch it at the web edge with
|
|
17
|
+
* {@link handler} / {@link createHandler} (or {@link asResponse} in a
|
|
18
|
+
* manual try/catch). `.try` does not catch it.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* return c.handler({
|
|
23
|
+
* request,
|
|
24
|
+
* run: (ctx) => {
|
|
25
|
+
* ctx.redirect({ url: "/dashboard" });
|
|
26
|
+
* },
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
declare const redirect: FnDefination<{
|
|
31
|
+
readonly url: string;
|
|
32
|
+
readonly status?: number | undefined;
|
|
33
|
+
}, never, "http.redirect", {
|
|
34
|
+
readonly url: TypeDefination<string, string, never>;
|
|
35
|
+
readonly status: TypeDefination<number, number, number>;
|
|
36
|
+
}, readonly [], {}, {
|
|
37
|
+
res?: ({
|
|
38
|
+
headers: {
|
|
39
|
+
append: (name: string, value: string) => void;
|
|
40
|
+
delete: (name: string) => void;
|
|
41
|
+
get: (name: string) => string | null;
|
|
42
|
+
getSetCookie: () => string[];
|
|
43
|
+
has: (name: string) => boolean;
|
|
44
|
+
set: (name: string, value: string) => void;
|
|
45
|
+
forEach: (callbackfn: (value: string, key: string, parent: Headers) => void, thisArg?: any) => void;
|
|
46
|
+
entries: () => HeadersIterator<[string, string]>;
|
|
47
|
+
keys: () => HeadersIterator<string>;
|
|
48
|
+
values: () => HeadersIterator<string>;
|
|
49
|
+
[Symbol.iterator]: () => HeadersIterator<[string, string]>;
|
|
50
|
+
};
|
|
51
|
+
status?: number | undefined;
|
|
52
|
+
statusText?: string | undefined;
|
|
53
|
+
} & HttpResponse) | null | undefined;
|
|
54
|
+
}, unknown>;
|
|
55
|
+
/**
|
|
56
|
+
* Write a thrown {@link Redirect} onto `res`: status + Location.
|
|
57
|
+
* Returns the same `res` for chaining.
|
|
58
|
+
*/
|
|
59
|
+
declare const applyRedirect: (response: HttpResponse, redirected: Redirect) => HttpResponse;
|
|
60
|
+
/**
|
|
61
|
+
* Turn a thrown {@link Redirect} into a fetch Response, preserving
|
|
62
|
+
* headers already on `response`. Any other value is rethrown.
|
|
63
|
+
*/
|
|
64
|
+
declare const asResponse: (thrown: unknown, response?: HttpResponse | null) => Response;
|
|
65
|
+
//#endregion
|
|
66
|
+
export { Redirect, RedirectStatus, applyRedirect, asResponse, redirect };
|
|
67
|
+
//# sourceMappingURL=redirect.d.cts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ControlFlow } from "../../error.mjs";
|
|
2
|
+
import { TypeDefination } from "../../schema.mjs";
|
|
3
|
+
import { FnDefination } from "../../fn.mjs";
|
|
4
|
+
import { HttpResponse } from "./response.mjs";
|
|
5
|
+
//#region src/plugins/http/redirect.d.ts
|
|
6
|
+
type RedirectStatus = 301 | 302 | 303 | 307 | 308;
|
|
7
|
+
/** HTTP navigation control - not a domain refusal and not a defect.
|
|
8
|
+
* Thrown by {@link redirect} after writing Location + status onto `res`. */
|
|
9
|
+
declare class Redirect extends ControlFlow {
|
|
10
|
+
url: string;
|
|
11
|
+
status: RedirectStatus;
|
|
12
|
+
constructor(url: string, status?: RedirectStatus);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Write a redirect onto the scope's `res`, then throw {@link Redirect}
|
|
16
|
+
* so the call stack unwinds. Catch it at the web edge with
|
|
17
|
+
* {@link handler} / {@link createHandler} (or {@link asResponse} in a
|
|
18
|
+
* manual try/catch). `.try` does not catch it.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* return c.handler({
|
|
23
|
+
* request,
|
|
24
|
+
* run: (ctx) => {
|
|
25
|
+
* ctx.redirect({ url: "/dashboard" });
|
|
26
|
+
* },
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
declare const redirect: FnDefination<{
|
|
31
|
+
readonly url: string;
|
|
32
|
+
readonly status?: number | undefined;
|
|
33
|
+
}, never, "http.redirect", {
|
|
34
|
+
readonly url: TypeDefination<string, string, never>;
|
|
35
|
+
readonly status: TypeDefination<number, number, number>;
|
|
36
|
+
}, readonly [], {}, {
|
|
37
|
+
res?: ({
|
|
38
|
+
headers: {
|
|
39
|
+
append: (name: string, value: string) => void;
|
|
40
|
+
delete: (name: string) => void;
|
|
41
|
+
get: (name: string) => string | null;
|
|
42
|
+
getSetCookie: () => string[];
|
|
43
|
+
has: (name: string) => boolean;
|
|
44
|
+
set: (name: string, value: string) => void;
|
|
45
|
+
forEach: (callbackfn: (value: string, key: string, parent: Headers) => void, thisArg?: any) => void;
|
|
46
|
+
entries: () => HeadersIterator<[string, string]>;
|
|
47
|
+
keys: () => HeadersIterator<string>;
|
|
48
|
+
values: () => HeadersIterator<string>;
|
|
49
|
+
[Symbol.iterator]: () => HeadersIterator<[string, string]>;
|
|
50
|
+
};
|
|
51
|
+
status?: number | undefined;
|
|
52
|
+
statusText?: string | undefined;
|
|
53
|
+
} & HttpResponse) | null | undefined;
|
|
54
|
+
}, unknown>;
|
|
55
|
+
/**
|
|
56
|
+
* Write a thrown {@link Redirect} onto `res`: status + Location.
|
|
57
|
+
* Returns the same `res` for chaining.
|
|
58
|
+
*/
|
|
59
|
+
declare const applyRedirect: (response: HttpResponse, redirected: Redirect) => HttpResponse;
|
|
60
|
+
/**
|
|
61
|
+
* Turn a thrown {@link Redirect} into a fetch Response, preserving
|
|
62
|
+
* headers already on `response`. Any other value is rethrown.
|
|
63
|
+
*/
|
|
64
|
+
declare const asResponse: (thrown: unknown, response?: HttpResponse | null) => Response;
|
|
65
|
+
//#endregion
|
|
66
|
+
export { Redirect, RedirectStatus, applyRedirect, asResponse, redirect };
|
|
67
|
+
//# sourceMappingURL=redirect.d.mts.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ControlFlow } from "../../error.mjs";
|
|
2
|
+
import { v } from "../../index.mjs";
|
|
3
|
+
import { res, toResponse } from "./response.mjs";
|
|
4
|
+
//#region src/plugins/http/redirect.ts
|
|
5
|
+
const REDIRECT_STATUSES = [
|
|
6
|
+
301,
|
|
7
|
+
302,
|
|
8
|
+
303,
|
|
9
|
+
307,
|
|
10
|
+
308
|
|
11
|
+
];
|
|
12
|
+
/** HTTP navigation control - not a domain refusal and not a defect.
|
|
13
|
+
* Thrown by {@link redirect} after writing Location + status onto `res`. */
|
|
14
|
+
var Redirect = class extends ControlFlow {
|
|
15
|
+
url;
|
|
16
|
+
status;
|
|
17
|
+
constructor(url, status = 302) {
|
|
18
|
+
super(`redirect ${status} ${url}`);
|
|
19
|
+
this.url = url;
|
|
20
|
+
this.status = status;
|
|
21
|
+
this.name = "Redirect";
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Write a redirect onto the scope's `res`, then throw {@link Redirect}
|
|
26
|
+
* so the call stack unwinds. Catch it at the web edge with
|
|
27
|
+
* {@link handler} / {@link createHandler} (or {@link asResponse} in a
|
|
28
|
+
* manual try/catch). `.try` does not catch it.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* return c.handler({
|
|
33
|
+
* request,
|
|
34
|
+
* run: (ctx) => {
|
|
35
|
+
* ctx.redirect({ url: "/dashboard" });
|
|
36
|
+
* },
|
|
37
|
+
* });
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
const redirect = v.fn({ use: [{ res }] }).fn("http.redirect", { input: {
|
|
41
|
+
url: v.string(),
|
|
42
|
+
status: v.number({
|
|
43
|
+
enum: REDIRECT_STATUSES,
|
|
44
|
+
default: 302
|
|
45
|
+
})
|
|
46
|
+
} }, (c) => {
|
|
47
|
+
const { url, status } = c.input;
|
|
48
|
+
let response = c.res;
|
|
49
|
+
if (!response) {
|
|
50
|
+
response = { headers: new Headers() };
|
|
51
|
+
c.res = response;
|
|
52
|
+
}
|
|
53
|
+
response.status = status;
|
|
54
|
+
response.headers.set("location", url);
|
|
55
|
+
throw new Redirect(url, status);
|
|
56
|
+
});
|
|
57
|
+
/**
|
|
58
|
+
* Write a thrown {@link Redirect} onto `res`: status + Location.
|
|
59
|
+
* Returns the same `res` for chaining.
|
|
60
|
+
*/
|
|
61
|
+
const applyRedirect = (response, redirected) => {
|
|
62
|
+
response.status = redirected.status;
|
|
63
|
+
response.headers.set("location", redirected.url);
|
|
64
|
+
return response;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Turn a thrown {@link Redirect} into a fetch Response, preserving
|
|
68
|
+
* headers already on `response`. Any other value is rethrown.
|
|
69
|
+
*/
|
|
70
|
+
const asResponse = (thrown, response) => {
|
|
71
|
+
if (!(thrown instanceof Redirect)) throw thrown;
|
|
72
|
+
const current = response ?? { headers: new Headers() };
|
|
73
|
+
applyRedirect(current, thrown);
|
|
74
|
+
return toResponse(current, null);
|
|
75
|
+
};
|
|
76
|
+
//#endregion
|
|
77
|
+
export { Redirect, applyRedirect, asResponse, redirect };
|
|
78
|
+
|
|
79
|
+
//# sourceMappingURL=redirect.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redirect.mjs","names":[],"sources":["../../../src/plugins/http/redirect.ts"],"sourcesContent":["import { ControlFlow } from \"../../error\";\nimport { v } from \"../../index\";\nimport type { HttpResponse } from \"./response\";\nimport { res, toResponse } from \"./response\";\n\nexport type RedirectStatus = 301 | 302 | 303 | 307 | 308;\n\nconst REDIRECT_STATUSES = [301, 302, 303, 307, 308] as const;\n\n/** HTTP navigation control - not a domain refusal and not a defect.\n * Thrown by {@link redirect} after writing Location + status onto `res`. */\nexport class Redirect extends ControlFlow {\n\tconstructor(\n\t\tpublic url: string,\n\t\tpublic status: RedirectStatus = 302,\n\t) {\n\t\tsuper(`redirect ${status} ${url}`);\n\t\tthis.name = \"Redirect\";\n\t}\n}\n\nconst h = v.fn({ use: [{ res }] });\n\n/**\n * Write a redirect onto the scope's `res`, then throw {@link Redirect}\n * so the call stack unwinds. Catch it at the web edge with\n * {@link handler} / {@link createHandler} (or {@link asResponse} in a\n * manual try/catch). `.try` does not catch it.\n *\n * @example\n * ```ts\n * return c.handler({\n * request,\n * run: (ctx) => {\n * ctx.redirect({ url: \"/dashboard\" });\n * },\n * });\n * ```\n */\nexport const redirect = h.fn(\n\t\"http.redirect\",\n\t{\n\t\tinput: {\n\t\t\turl: v.string(),\n\t\t\tstatus: v.number({\n\t\t\t\tenum: REDIRECT_STATUSES,\n\t\t\t\tdefault: 302,\n\t\t\t}),\n\t\t},\n\t},\n\t(c): never => {\n\t\tconst { url, status } = c.input;\n\t\tlet response = c.res;\n\t\tif (!response) {\n\t\t\tresponse = { headers: new Headers() };\n\t\t\tc.res = response;\n\t\t}\n\t\tresponse.status = status;\n\t\tresponse.headers.set(\"location\", url);\n\t\tthrow new Redirect(url, status as RedirectStatus);\n\t},\n);\n\n/**\n * Write a thrown {@link Redirect} onto `res`: status + Location.\n * Returns the same `res` for chaining.\n */\nexport const applyRedirect = (\n\tresponse: HttpResponse,\n\tredirected: Redirect,\n): HttpResponse => {\n\tresponse.status = redirected.status;\n\tresponse.headers.set(\"location\", redirected.url);\n\treturn response;\n};\n\n/**\n * Turn a thrown {@link Redirect} into a fetch Response, preserving\n * headers already on `response`. Any other value is rethrown.\n */\nexport const asResponse = (\n\tthrown: unknown,\n\tresponse?: HttpResponse | null,\n): Response => {\n\tif (!(thrown instanceof Redirect)) throw thrown;\n\tconst current = response ?? { headers: new Headers() };\n\tapplyRedirect(current, thrown);\n\treturn toResponse(current, null);\n};\n"],"mappings":";;;;AAOA,MAAM,oBAAoB;CAAC;CAAK;CAAK;CAAK;CAAK;AAAG;;;AAIlD,IAAa,WAAb,cAA8B,YAAY;CAEjC;CACA;CAFR,YACC,KACA,SAAgC,KAC/B;EACD,MAAM,YAAY,OAAO,GAAG,KAAK;EAH1B,KAAA,MAAA;EACA,KAAA,SAAA;EAGP,KAAK,OAAO;CACb;AACD;;;;;;;;;;;;;;;;;AAoBA,MAAa,WAlBH,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,CAkBR,CAAA,CAAE,GACzB,iBACA,EACC,OAAO;CACN,KAAK,EAAE,OAAO;CACd,QAAQ,EAAE,OAAO;EAChB,MAAM;EACN,SAAS;CACV,CAAC;AACF,EACD,IACC,MAAa;CACb,MAAM,EAAE,KAAK,WAAW,EAAE;CAC1B,IAAI,WAAW,EAAE;CACjB,IAAI,CAAC,UAAU;EACd,WAAW,EAAE,SAAS,IAAI,QAAQ,EAAE;EACpC,EAAE,MAAM;CACT;CACA,SAAS,SAAS;CAClB,SAAS,QAAQ,IAAI,YAAY,GAAG;CACpC,MAAM,IAAI,SAAS,KAAK,MAAwB;AACjD,CACD;;;;;AAMA,MAAa,iBACZ,UACA,eACkB;CAClB,SAAS,SAAS,WAAW;CAC7B,SAAS,QAAQ,IAAI,YAAY,WAAW,GAAG;CAC/C,OAAO;AACR;;;;;AAMA,MAAa,cACZ,QACA,aACc;CACd,IAAI,EAAE,kBAAkB,WAAW,MAAM;CACzC,MAAM,UAAU,YAAY,EAAE,SAAS,IAAI,QAAQ,EAAE;CACrD,cAAc,SAAS,MAAM;CAC7B,OAAO,WAAW,SAAS,IAAI;AAChC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const require_index = require("../../index.cjs");
|
|
2
|
+
const require_response = require("./response.cjs");
|
|
3
|
+
//#region src/plugins/http/request.ts
|
|
4
|
+
const parseQuery = (url) => {
|
|
5
|
+
const q = {};
|
|
6
|
+
for (const [key, value] of url.searchParams) {
|
|
7
|
+
const current = q[key];
|
|
8
|
+
q[key] = current === void 0 ? value : Array.isArray(current) ? [...current, value] : [current, value];
|
|
9
|
+
}
|
|
10
|
+
return q;
|
|
11
|
+
};
|
|
12
|
+
const parseCookies = (header) => {
|
|
13
|
+
const jar = {};
|
|
14
|
+
for (const part of (header ?? "").split(";")) {
|
|
15
|
+
const [name, ...rest] = part.trim().split("=");
|
|
16
|
+
if (name) jar[name] = decodeURIComponent(rest.join("="));
|
|
17
|
+
}
|
|
18
|
+
return jar;
|
|
19
|
+
};
|
|
20
|
+
/** Build the `req` value from a fetch Request. The body cannot be read
|
|
21
|
+
* synchronously, so it comes in from whoever already awaited it -
|
|
22
|
+
* `fromRequest` does that for you. */
|
|
23
|
+
const toHttpRequest = (raw, body) => {
|
|
24
|
+
const url = new URL(raw.url);
|
|
25
|
+
return {
|
|
26
|
+
raw,
|
|
27
|
+
method: raw.method.toUpperCase(),
|
|
28
|
+
path: url.pathname,
|
|
29
|
+
headers: raw.headers,
|
|
30
|
+
query: parseQuery(url),
|
|
31
|
+
cookies: parseCookies(raw.headers.get("cookie")),
|
|
32
|
+
body
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
const req = require_index.v.var("req", { default: null });
|
|
36
|
+
const fromRequest = require_index.v.fn({ use: [{
|
|
37
|
+
req,
|
|
38
|
+
res: require_response.res
|
|
39
|
+
}] }).fn("http.from_request", {
|
|
40
|
+
input: { request: require_index.v.any() },
|
|
41
|
+
provides: ["req"]
|
|
42
|
+
}, async (c) => {
|
|
43
|
+
const raw = c.input.request;
|
|
44
|
+
let body;
|
|
45
|
+
if (raw.method !== "GET" && raw.method !== "HEAD") {
|
|
46
|
+
const contentType = raw.headers.get("content-type") ?? "";
|
|
47
|
+
if (contentType.includes("json")) body = await raw.clone().json().catch(() => void 0);
|
|
48
|
+
else if (contentType.includes("text")) body = await raw.clone().text().catch(() => void 0);
|
|
49
|
+
}
|
|
50
|
+
const value = toHttpRequest(raw, body);
|
|
51
|
+
c.req = value;
|
|
52
|
+
c.res = { headers: new Headers() };
|
|
53
|
+
return {
|
|
54
|
+
method: value.method,
|
|
55
|
+
path: value.path
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
//#endregion
|
|
59
|
+
exports.fromRequest = fromRequest;
|
|
60
|
+
exports.req = req;
|
|
61
|
+
exports.toHttpRequest = toHttpRequest;
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=request.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.cjs","names":["v"],"sources":["../../../src/plugins/http/request.ts"],"sourcesContent":["import { v } from \"../../index\";\nimport { res } from \"./response\";\n\nconst parseQuery = (url: URL) => {\n\tconst q: Record<string, string | string[]> = {};\n\tfor (const [key, value] of url.searchParams) {\n\t\tconst current = q[key];\n\t\tq[key] =\n\t\t\tcurrent === undefined\n\t\t\t\t? value\n\t\t\t\t: Array.isArray(current)\n\t\t\t\t\t? [...current, value]\n\t\t\t\t\t: [current, value];\n\t}\n\treturn q;\n};\n\nconst parseCookies = (header: string | null) => {\n\tconst jar: Record<string, string> = {};\n\tfor (const part of (header ?? \"\").split(\";\")) {\n\t\tconst [name, ...rest] = part.trim().split(\"=\");\n\t\tif (name) jar[name] = decodeURIComponent(rest.join(\"=\"));\n\t}\n\treturn jar;\n};\n\n/** The whole request-side state, as ONE value: `c.req` and\n * everything is there - no per-piece vars to require one by one. */\nexport type HttpRequest = {\n\t/** The fetch Request itself, untouched. */\n\traw: Request;\n\tmethod: string;\n\tpath: string;\n\theaders: Headers;\n\tquery: Record<string, string | string[]>;\n\tcookies: Record<string, string>;\n\t/** Parsed by `fromRequest` when the content type says json/text -\n\t * anything else stays on `raw`. */\n\tbody: unknown;\n};\n\n/** Build the `req` value from a fetch Request. The body cannot be read\n * synchronously, so it comes in from whoever already awaited it -\n * `fromRequest` does that for you. */\nexport const toHttpRequest = (raw: Request, body?: unknown): HttpRequest => {\n\tconst url = new URL(raw.url);\n\treturn {\n\t\traw,\n\t\tmethod: raw.method.toUpperCase(),\n\t\tpath: url.pathname,\n\t\theaders: raw.headers,\n\t\tquery: parseQuery(url),\n\t\tcookies: parseCookies(raw.headers.get(\"cookie\")),\n\t\tbody,\n\t};\n};\n\nexport const req = v.var(\"req\", { default: null as HttpRequest | null });\n\nconst h = v.fn({ use: [{ req, res }] });\n\nexport const fromRequest = h.fn(\n\t\"http.from_request\",\n\t{ input: { request: v.any<Request>() }, provides: [\"req\"] },\n\tasync (c) => {\n\t\tconst raw = c.input.request;\n\t\tlet body: unknown;\n\t\tif (raw.method !== \"GET\" && raw.method !== \"HEAD\") {\n\t\t\tconst contentType = raw.headers.get(\"content-type\") ?? \"\";\n\t\t\tif (contentType.includes(\"json\")) {\n\t\t\t\tbody = await raw\n\t\t\t\t\t.clone()\n\t\t\t\t\t.json()\n\t\t\t\t\t.catch(() => undefined);\n\t\t\t} else if (contentType.includes(\"text\")) {\n\t\t\t\tbody = await raw\n\t\t\t\t\t.clone()\n\t\t\t\t\t.text()\n\t\t\t\t\t.catch(() => undefined);\n\t\t\t}\n\t\t}\n\t\tconst value = toHttpRequest(raw, body);\n\t\tc.req = value;\n\t\tc.res = { headers: new Headers() };\n\t\treturn { method: value.method, path: value.path };\n\t},\n);\n"],"mappings":";;;AAGA,MAAM,cAAc,QAAa;CAChC,MAAM,IAAuC,CAAC;CAC9C,KAAK,MAAM,CAAC,KAAK,UAAU,IAAI,cAAc;EAC5C,MAAM,UAAU,EAAE;EAClB,EAAE,OACD,YAAY,KAAA,IACT,QACA,MAAM,QAAQ,OAAO,IACpB,CAAC,GAAG,SAAS,KAAK,IAClB,CAAC,SAAS,KAAK;CACrB;CACA,OAAO;AACR;AAEA,MAAM,gBAAgB,WAA0B;CAC/C,MAAM,MAA8B,CAAC;CACrC,KAAK,MAAM,SAAS,UAAU,GAAA,CAAI,MAAM,GAAG,GAAG;EAC7C,MAAM,CAAC,MAAM,GAAG,QAAQ,KAAK,KAAK,CAAC,CAAC,MAAM,GAAG;EAC7C,IAAI,MAAM,IAAI,QAAQ,mBAAmB,KAAK,KAAK,GAAG,CAAC;CACxD;CACA,OAAO;AACR;;;;AAoBA,MAAa,iBAAiB,KAAc,SAAgC;CAC3E,MAAM,MAAM,IAAI,IAAI,IAAI,GAAG;CAC3B,OAAO;EACN;EACA,QAAQ,IAAI,OAAO,YAAY;EAC/B,MAAM,IAAI;EACV,SAAS,IAAI;EACb,OAAO,WAAW,GAAG;EACrB,SAAS,aAAa,IAAI,QAAQ,IAAI,QAAQ,CAAC;EAC/C;CACD;AACD;AAEA,MAAa,MAAMA,cAAAA,EAAE,IAAI,OAAO,EAAE,SAAS,KAA2B,CAAC;AAIvE,MAAa,cAFHA,cAAAA,EAAE,GAAG,EAAE,KAAK,CAAC;CAAE;CAAK,KAAA,iBAAA;AAAI,CAAC,EAAE,CAEV,CAAA,CAAE,GAC5B,qBACA;CAAE,OAAO,EAAE,SAASA,cAAAA,EAAE,IAAa,EAAE;CAAG,UAAU,CAAC,KAAK;AAAE,GAC1D,OAAO,MAAM;CACZ,MAAM,MAAM,EAAE,MAAM;CACpB,IAAI;CACJ,IAAI,IAAI,WAAW,SAAS,IAAI,WAAW,QAAQ;EAClD,MAAM,cAAc,IAAI,QAAQ,IAAI,cAAc,KAAK;EACvD,IAAI,YAAY,SAAS,MAAM,GAC9B,OAAO,MAAM,IACX,MAAM,CAAC,CACP,KAAK,CAAC,CACN,YAAY,KAAA,CAAS;OACjB,IAAI,YAAY,SAAS,MAAM,GACrC,OAAO,MAAM,IACX,MAAM,CAAC,CACP,KAAK,CAAC,CACN,YAAY,KAAA,CAAS;CAEzB;CACA,MAAM,QAAQ,cAAc,KAAK,IAAI;CACrC,EAAE,MAAM;CACR,EAAE,MAAM,EAAE,SAAS,IAAI,QAAQ,EAAE;CACjC,OAAO;EAAE,QAAQ,MAAM;EAAQ,MAAM,MAAM;CAAK;AACjD,CACD"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { TypeDefination } from "../../schema.cjs";
|
|
2
|
+
import { FnDefination } from "../../fn.cjs";
|
|
3
|
+
import { VarDefination } from "../../var.cjs";
|
|
4
|
+
import { HttpResponse } from "./response.cjs";
|
|
5
|
+
//#region src/plugins/http/request.d.ts
|
|
6
|
+
/** The whole request-side state, as ONE value: `c.req` and
|
|
7
|
+
* everything is there - no per-piece vars to require one by one. */
|
|
8
|
+
type HttpRequest = {
|
|
9
|
+
/** The fetch Request itself, untouched. */
|
|
10
|
+
raw: Request;
|
|
11
|
+
method: string;
|
|
12
|
+
path: string;
|
|
13
|
+
headers: Headers;
|
|
14
|
+
query: Record<string, string | string[]>;
|
|
15
|
+
cookies: Record<string, string>;
|
|
16
|
+
/** Parsed by `fromRequest` when the content type says json/text -
|
|
17
|
+
* anything else stays on `raw`. */
|
|
18
|
+
body: unknown;
|
|
19
|
+
};
|
|
20
|
+
/** Build the `req` value from a fetch Request. The body cannot be read
|
|
21
|
+
* synchronously, so it comes in from whoever already awaited it -
|
|
22
|
+
* `fromRequest` does that for you. */
|
|
23
|
+
declare const toHttpRequest: (raw: Request, body?: unknown) => HttpRequest;
|
|
24
|
+
declare const req: VarDefination<"req", HttpRequest | null, undefined, never>;
|
|
25
|
+
declare const fromRequest: FnDefination<{
|
|
26
|
+
readonly request: Request;
|
|
27
|
+
}, Promise<{
|
|
28
|
+
method: string;
|
|
29
|
+
path: string;
|
|
30
|
+
}>, "http.from_request", {
|
|
31
|
+
readonly request: TypeDefination<Request, Request, never>;
|
|
32
|
+
}, readonly ["req"], {}, {
|
|
33
|
+
res?: ({
|
|
34
|
+
headers: {
|
|
35
|
+
append: (name: string, value: string) => void;
|
|
36
|
+
delete: (name: string) => void;
|
|
37
|
+
get: (name: string) => string | null;
|
|
38
|
+
getSetCookie: () => string[];
|
|
39
|
+
has: (name: string) => boolean;
|
|
40
|
+
set: (name: string, value: string) => void;
|
|
41
|
+
forEach: (callbackfn: (value: string, key: string, parent: Headers) => void, thisArg?: any) => void;
|
|
42
|
+
entries: () => HeadersIterator<[string, string]>;
|
|
43
|
+
keys: () => HeadersIterator<string>;
|
|
44
|
+
values: () => HeadersIterator<string>;
|
|
45
|
+
[Symbol.iterator]: () => HeadersIterator<[string, string]>;
|
|
46
|
+
};
|
|
47
|
+
status?: number | undefined;
|
|
48
|
+
statusText?: string | undefined;
|
|
49
|
+
} & HttpResponse) | null | undefined;
|
|
50
|
+
req?: ({
|
|
51
|
+
raw: {
|
|
52
|
+
readonly cache: RequestCache;
|
|
53
|
+
readonly credentials: RequestCredentials;
|
|
54
|
+
readonly destination: RequestDestination;
|
|
55
|
+
readonly headers: {
|
|
56
|
+
append: (name: string, value: string) => void;
|
|
57
|
+
delete: (name: string) => void;
|
|
58
|
+
get: (name: string) => string | null;
|
|
59
|
+
getSetCookie: () => string[];
|
|
60
|
+
has: (name: string) => boolean;
|
|
61
|
+
set: (name: string, value: string) => void;
|
|
62
|
+
forEach: (callbackfn: (value: string, key: string, parent: Headers) => void, thisArg?: any) => void;
|
|
63
|
+
entries: () => HeadersIterator<[string, string]>;
|
|
64
|
+
keys: () => HeadersIterator<string>;
|
|
65
|
+
values: () => HeadersIterator<string>;
|
|
66
|
+
[Symbol.iterator]: () => HeadersIterator<[string, string]>;
|
|
67
|
+
};
|
|
68
|
+
readonly integrity: string;
|
|
69
|
+
readonly keepalive: boolean;
|
|
70
|
+
readonly method: string;
|
|
71
|
+
readonly mode: RequestMode;
|
|
72
|
+
readonly redirect: RequestRedirect;
|
|
73
|
+
readonly referrer: string;
|
|
74
|
+
readonly referrerPolicy: ReferrerPolicy;
|
|
75
|
+
readonly signal: {
|
|
76
|
+
readonly aborted: boolean;
|
|
77
|
+
onabort: ((this: AbortSignal, ev: Event) => any) | null;
|
|
78
|
+
readonly reason: any;
|
|
79
|
+
throwIfAborted: () => void;
|
|
80
|
+
addEventListener: {
|
|
81
|
+
<K extends keyof AbortSignalEventMap>(type: K, listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
|
82
|
+
(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
|
83
|
+
};
|
|
84
|
+
removeEventListener: {
|
|
85
|
+
<K extends keyof AbortSignalEventMap>(type: K, listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
|
86
|
+
(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
|
87
|
+
};
|
|
88
|
+
dispatchEvent: (event: Event) => boolean;
|
|
89
|
+
};
|
|
90
|
+
readonly url: string;
|
|
91
|
+
clone: () => Request;
|
|
92
|
+
readonly body: {
|
|
93
|
+
readonly locked: boolean;
|
|
94
|
+
cancel: (reason?: any) => Promise<void>;
|
|
95
|
+
getReader: {
|
|
96
|
+
(options: {
|
|
97
|
+
mode: "byob";
|
|
98
|
+
}): ReadableStreamBYOBReader;
|
|
99
|
+
(): ReadableStreamDefaultReader<Uint8Array<ArrayBuffer>>;
|
|
100
|
+
(options?: ReadableStreamGetReaderOptions): ReadableStreamReader<Uint8Array<ArrayBuffer>>;
|
|
101
|
+
};
|
|
102
|
+
pipeThrough: <T>(transform: ReadableWritablePair<T, Uint8Array<ArrayBuffer>>, options?: StreamPipeOptions) => ReadableStream<T>;
|
|
103
|
+
pipeTo: (destination: WritableStream<Uint8Array<ArrayBuffer>>, options?: StreamPipeOptions) => Promise<void>;
|
|
104
|
+
tee: () => [ReadableStream<Uint8Array<ArrayBuffer>>, ReadableStream<Uint8Array<ArrayBuffer>>];
|
|
105
|
+
values: (options?: ReadableStreamIteratorOptions) => ReadableStreamAsyncIterator<Uint8Array<ArrayBuffer>>;
|
|
106
|
+
[Symbol.asyncIterator]: (options?: ReadableStreamIteratorOptions) => ReadableStreamAsyncIterator<Uint8Array<ArrayBuffer>>;
|
|
107
|
+
} | null;
|
|
108
|
+
readonly bodyUsed: boolean;
|
|
109
|
+
arrayBuffer: () => Promise<ArrayBuffer>;
|
|
110
|
+
blob: () => Promise<Blob>;
|
|
111
|
+
bytes: () => Promise<Uint8Array<ArrayBuffer>>;
|
|
112
|
+
formData: () => Promise<FormData>;
|
|
113
|
+
json: () => Promise<any>;
|
|
114
|
+
text: () => Promise<string>;
|
|
115
|
+
};
|
|
116
|
+
method: string;
|
|
117
|
+
path: string;
|
|
118
|
+
headers: {
|
|
119
|
+
append: (name: string, value: string) => void;
|
|
120
|
+
delete: (name: string) => void;
|
|
121
|
+
get: (name: string) => string | null;
|
|
122
|
+
getSetCookie: () => string[];
|
|
123
|
+
has: (name: string) => boolean;
|
|
124
|
+
set: (name: string, value: string) => void;
|
|
125
|
+
forEach: (callbackfn: (value: string, key: string, parent: Headers) => void, thisArg?: any) => void;
|
|
126
|
+
entries: () => HeadersIterator<[string, string]>;
|
|
127
|
+
keys: () => HeadersIterator<string>;
|
|
128
|
+
values: () => HeadersIterator<string>;
|
|
129
|
+
[Symbol.iterator]: () => HeadersIterator<[string, string]>;
|
|
130
|
+
};
|
|
131
|
+
query: {
|
|
132
|
+
[x: string]: string | string[];
|
|
133
|
+
};
|
|
134
|
+
cookies: {
|
|
135
|
+
[x: string]: string;
|
|
136
|
+
};
|
|
137
|
+
body: unknown;
|
|
138
|
+
} & HttpRequest) | null | undefined;
|
|
139
|
+
}, unknown>;
|
|
140
|
+
//#endregion
|
|
141
|
+
export { HttpRequest, fromRequest, req, toHttpRequest };
|
|
142
|
+
//# sourceMappingURL=request.d.cts.map
|