htmx-router 1.0.0-alpha.5 → 1.0.0-pre1
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/example/eventdim-react/package.json +67 -0
- package/example/eventdim-react/server.js +90 -0
- package/example/island-react/global.d.ts +8 -0
- package/example/island-react/package.json +38 -0
- package/example/island-react/server.js +58 -0
- package/global.d.ts +7 -0
- package/package.json +10 -8
- package/readme.md +17 -212
- package/bin/cli/config.d.ts +0 -10
- package/bin/cli/config.js +0 -4
- package/bin/cli/index.d.ts +0 -2
- package/bin/cli/index.js +0 -66
- package/bin/client/entry.d.ts +0 -1
- package/bin/client/entry.js +0 -12
- package/bin/client/index.d.ts +0 -7
- package/bin/client/index.js +0 -132
- package/bin/client/mount.d.ts +0 -2
- package/bin/client/mount.js +0 -116
- package/bin/client/watch.d.ts +0 -1
- package/bin/client/watch.js +0 -11
- package/bin/helper.d.ts +0 -2
- package/bin/helper.js +0 -34
- package/bin/index.d.ts +0 -11
- package/bin/index.js +0 -18
- package/bin/request/http.d.ts +0 -10
- package/bin/request/http.js +0 -41
- package/bin/request/index.d.ts +0 -16
- package/bin/request/index.js +0 -6
- package/bin/request/native.d.ts +0 -9
- package/bin/request/native.js +0 -46
- package/bin/response.d.ts +0 -9
- package/bin/response.js +0 -46
- package/bin/router.d.ts +0 -49
- package/bin/router.js +0 -217
- package/bin/types.d.ts +0 -10
- package/bin/types.js +0 -1
- package/bin/util/cookies.d.ts +0 -25
- package/bin/util/cookies.js +0 -60
- package/bin/util/css.d.ts +0 -13
- package/bin/util/css.js +0 -55
- package/bin/util/dynamic.d.ts +0 -8
- package/bin/util/dynamic.js +0 -40
- package/bin/util/endpoint.d.ts +0 -13
- package/bin/util/endpoint.js +0 -32
- package/bin/util/event-source.d.ts +0 -16
- package/bin/util/event-source.js +0 -85
- package/bin/util/hash.d.ts +0 -4
- package/bin/util/hash.js +0 -10
- package/bin/util/index.d.ts +0 -1
- package/bin/util/index.js +0 -7
- package/bin/util/parameters.d.ts +0 -10
- package/bin/util/parameters.js +0 -17
- package/bin/util/path-builder.d.ts +0 -1
- package/bin/util/path-builder.js +0 -43
- package/bin/util/response.d.ts +0 -11
- package/bin/util/response.js +0 -46
- package/bin/util/shell.d.ts +0 -120
- package/bin/util/shell.js +0 -251
package/bin/client/index.js
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Builds the SSR and client side mounter for client components
|
|
3
|
-
*/
|
|
4
|
-
import { readFile, writeFile } from "fs/promises";
|
|
5
|
-
import { init, parse } from "es-module-lexer";
|
|
6
|
-
import { QuickHash } from "../util/hash.js";
|
|
7
|
-
import { CutString } from "../helper.js";
|
|
8
|
-
const pivot = `\n// DO NOT EDIT BELOW THIS LINE\n`;
|
|
9
|
-
export async function GenerateClient(config, force = false) {
|
|
10
|
-
const file = await readFile(config.source, "utf8");
|
|
11
|
-
const [source, history] = CutString(file, pivot);
|
|
12
|
-
const hash = QuickHash(source);
|
|
13
|
-
if (!force && ExtractHash(history) === hash)
|
|
14
|
-
return;
|
|
15
|
-
await init;
|
|
16
|
-
const imported = ParseImports(source);
|
|
17
|
-
await Promise.all([
|
|
18
|
-
writeFile(config.source, source
|
|
19
|
-
+ pivot
|
|
20
|
-
+ `// hash: ${hash}\n`
|
|
21
|
-
+ BuildClientServer(config.adapter, imported)),
|
|
22
|
-
writeFile(CutString(config.source, ".", -1)[0] + ".manifest.tsx", BuildClientManifest(config.adapter, imported))
|
|
23
|
-
]);
|
|
24
|
-
}
|
|
25
|
-
function ParseImports(source) {
|
|
26
|
-
const parsed = parse(source)[0];
|
|
27
|
-
const out = [];
|
|
28
|
-
for (const imported of parsed) {
|
|
29
|
-
if (imported.a !== -1)
|
|
30
|
-
continue;
|
|
31
|
-
if (imported.t !== 1)
|
|
32
|
-
continue;
|
|
33
|
-
const href = source.slice(imported.s, imported.e);
|
|
34
|
-
const front = source.slice(imported.ss, imported.s);
|
|
35
|
-
const start = front.indexOf("{");
|
|
36
|
-
if (start === -1) {
|
|
37
|
-
const middle = CutString(CutString(front, "import")[1], "from", -1)[0];
|
|
38
|
-
out.push({ mapping: ExtractName(middle), href });
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
const end = front.lastIndexOf("}");
|
|
42
|
-
const segments = front.slice(start + 1, end).split(",");
|
|
43
|
-
out.push({ mapping: segments.map(ExtractName), href });
|
|
44
|
-
}
|
|
45
|
-
return out;
|
|
46
|
-
}
|
|
47
|
-
function SafeScript(type, script) {
|
|
48
|
-
switch (type) {
|
|
49
|
-
case "react": return `<script dangerouslySetInnerHTML={{__html: ${script}}}></script>`;
|
|
50
|
-
default: return `<script>${script}</script>`;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
function BuildClientServer(type, imported) {
|
|
54
|
-
const names = new Array();
|
|
55
|
-
for (const imp of imported) {
|
|
56
|
-
if (Array.isArray(imp.mapping))
|
|
57
|
-
names.push(...imp.mapping.map(x => x.name));
|
|
58
|
-
else
|
|
59
|
-
names.push(imp.mapping.name);
|
|
60
|
-
}
|
|
61
|
-
let out = `import { StyleClass } from "htmx-router";\n`
|
|
62
|
-
+ `const island = new StyleClass("i", ".this{display:contents;}\\n").name;\n\n`
|
|
63
|
-
+ "type FirstArg<T> = T extends (arg: infer U, ...args: any[]) => any ? U : never;\n"
|
|
64
|
-
+ "function mount(name: string, data: string, ssr?: JSX.Element) {\n"
|
|
65
|
-
+ "\treturn (<>\n"
|
|
66
|
-
+ `\t\t<div className={island}>{ssr}</div>\n`
|
|
67
|
-
+ `\t\t${SafeScript(type, "`Router.mountAboveWith('${name}', ${data})`")}\n`
|
|
68
|
-
+ "\t</>);\n"
|
|
69
|
-
+ "}\n"
|
|
70
|
-
+ "\n"
|
|
71
|
-
+ "const Client = {\n";
|
|
72
|
-
for (const name of names) {
|
|
73
|
-
out += `\t${name}: function(props: FirstArg<typeof ${name}> & { children?: JSX.Element }) {\n`
|
|
74
|
-
+ `\t\tconst { children, ...rest } = props;\n`
|
|
75
|
-
+ `\t\treturn mount("${name}", JSON.stringify(rest), children);\n`
|
|
76
|
-
+ `\t},\n`;
|
|
77
|
-
}
|
|
78
|
-
out += "}\nexport default Client;\n\n"
|
|
79
|
-
+ `import { __RebuildClient__ } from "htmx-router/bin/client/watch.js";\n`
|
|
80
|
-
+ `__RebuildClient__();`;
|
|
81
|
-
return out;
|
|
82
|
-
}
|
|
83
|
-
const renderer = {
|
|
84
|
-
react: '\t\tconst r = await import("react-dom/client");\n'
|
|
85
|
-
+ "\t\tr.createRoot(element).render(<C {...props} />);\n"
|
|
86
|
-
};
|
|
87
|
-
function BuildClientManifest(type, imports) {
|
|
88
|
-
let out = "/*------------------------------------------\n"
|
|
89
|
-
+ " * Generated by htmx-router *\n"
|
|
90
|
-
+ " * Warn: Any changes will be overwritten *\n"
|
|
91
|
-
+ "-------------------------------------------*/\n\n"
|
|
92
|
-
+ "/* eslint-disable @typescript-eslint/no-explicit-any */\n"
|
|
93
|
-
+ "const client = {\n";
|
|
94
|
-
const render = renderer[type];
|
|
95
|
-
if (!render) {
|
|
96
|
-
console.error(`Unsupported client adapter ${type}`);
|
|
97
|
-
process.exit(1);
|
|
98
|
-
}
|
|
99
|
-
for (const imported of imports) {
|
|
100
|
-
if (Array.isArray(imported.mapping)) {
|
|
101
|
-
for (const map of imported.mapping) {
|
|
102
|
-
out += `\t${map.name}: async (element: HTMLElement, props: any) => {\n`
|
|
103
|
-
+ `\t\tconst C = (await import("${imported.href}")).${map.original};\n`
|
|
104
|
-
+ render
|
|
105
|
-
+ `\t},\n`;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
out += `\t${imported.mapping.name}: async (element: HTMLElement, props: any) => {\n`
|
|
110
|
-
+ `\t\tconst C = (await import("${imported.href}")).default;\n`
|
|
111
|
-
+ render
|
|
112
|
-
+ `\t},\n`;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
out += "}\nexport default client;\n"
|
|
116
|
-
+ "(window as any).CLIENT = client;";
|
|
117
|
-
return out;
|
|
118
|
-
}
|
|
119
|
-
function ExtractName(str) {
|
|
120
|
-
const parts = CutString(str, "as");
|
|
121
|
-
if (parts[1].length !== 0)
|
|
122
|
-
return { name: parts[1].trim(), original: parts[0].trim() };
|
|
123
|
-
const name = parts[0].trim();
|
|
124
|
-
return { name, original: name };
|
|
125
|
-
}
|
|
126
|
-
function ExtractHash(source) {
|
|
127
|
-
const regex = /\/\/\s+hash\s*:\s*(\w+)/;
|
|
128
|
-
const match = source.match(regex);
|
|
129
|
-
if (match)
|
|
130
|
-
return match[1] || "";
|
|
131
|
-
return "";
|
|
132
|
-
}
|
package/bin/client/mount.d.ts
DELETED
package/bin/client/mount.js
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { QuickHash } from "../util/hash.js";
|
|
2
|
-
import { CutString } from "../helper.js";
|
|
3
|
-
// this function simply exists so it can be stringified and written into the client js bundle
|
|
4
|
-
function ClientMounter() {
|
|
5
|
-
const theme = {
|
|
6
|
-
get: () => {
|
|
7
|
-
return (localStorage.getItem("theme") || theme.infer());
|
|
8
|
-
},
|
|
9
|
-
infer: () => {
|
|
10
|
-
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
11
|
-
const current = prefersDark ? 'dark' : 'light';
|
|
12
|
-
localStorage.setItem("theme", current);
|
|
13
|
-
return current;
|
|
14
|
-
},
|
|
15
|
-
apply: () => {
|
|
16
|
-
document.documentElement.setAttribute('data-theme', theme.get());
|
|
17
|
-
},
|
|
18
|
-
toggle: () => {
|
|
19
|
-
if (theme.get() === "dark")
|
|
20
|
-
localStorage.setItem("theme", "light");
|
|
21
|
-
else
|
|
22
|
-
localStorage.setItem("theme", "dark");
|
|
23
|
-
theme.apply();
|
|
24
|
-
return localStorage.getItem("theme");
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
|
28
|
-
theme.infer();
|
|
29
|
-
theme.apply();
|
|
30
|
-
});
|
|
31
|
-
theme.apply();
|
|
32
|
-
const global = window;
|
|
33
|
-
const mountRequests = new Array();
|
|
34
|
-
function RequestMount(funcName, json) {
|
|
35
|
-
mountRequests.push([funcName, document.currentScript.previousElementSibling, json]);
|
|
36
|
-
}
|
|
37
|
-
function Mount() {
|
|
38
|
-
if (mountRequests.length < 1)
|
|
39
|
-
return;
|
|
40
|
-
if (!global.CLIENT)
|
|
41
|
-
throw new Error("Client manifest missing");
|
|
42
|
-
for (const [funcName, element, json] of mountRequests) {
|
|
43
|
-
console.info("hydrating", funcName, "into", element);
|
|
44
|
-
const func = global.CLIENT[funcName];
|
|
45
|
-
if (!func)
|
|
46
|
-
throw new Error(`Component ${funcName} is missing from client manifest`);
|
|
47
|
-
func(element, json);
|
|
48
|
-
}
|
|
49
|
-
mountRequests.length = 0;
|
|
50
|
-
}
|
|
51
|
-
document.addEventListener("DOMContentLoaded", Mount);
|
|
52
|
-
if (global.htmx)
|
|
53
|
-
global.htmx.onLoad(Mount);
|
|
54
|
-
// Track the number of active requests
|
|
55
|
-
let activeRequests = 0;
|
|
56
|
-
const updateLoadingAttribute = () => {
|
|
57
|
-
if (activeRequests > 0)
|
|
58
|
-
document.body.setAttribute('data-loading', 'true');
|
|
59
|
-
else
|
|
60
|
-
document.body.removeAttribute('data-loading');
|
|
61
|
-
};
|
|
62
|
-
const originalXHROpen = XMLHttpRequest.prototype.open;
|
|
63
|
-
const originalXHRSend = XMLHttpRequest.prototype.send;
|
|
64
|
-
// @ts-ignore
|
|
65
|
-
XMLHttpRequest.prototype.open = function (...args) {
|
|
66
|
-
this.addEventListener('loadstart', () => {
|
|
67
|
-
activeRequests++;
|
|
68
|
-
updateLoadingAttribute();
|
|
69
|
-
});
|
|
70
|
-
this.addEventListener('loadend', () => {
|
|
71
|
-
activeRequests--;
|
|
72
|
-
updateLoadingAttribute();
|
|
73
|
-
});
|
|
74
|
-
originalXHROpen.apply(this, args);
|
|
75
|
-
};
|
|
76
|
-
XMLHttpRequest.prototype.send = function (...args) {
|
|
77
|
-
originalXHRSend.apply(this, args);
|
|
78
|
-
};
|
|
79
|
-
// Override fetch
|
|
80
|
-
const originalFetch = window.fetch;
|
|
81
|
-
window.fetch = async (...args) => {
|
|
82
|
-
activeRequests++;
|
|
83
|
-
updateLoadingAttribute();
|
|
84
|
-
try {
|
|
85
|
-
const response = await originalFetch(...args);
|
|
86
|
-
return response;
|
|
87
|
-
}
|
|
88
|
-
finally {
|
|
89
|
-
activeRequests--;
|
|
90
|
-
updateLoadingAttribute();
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
return {
|
|
94
|
-
mountAboveWith: RequestMount,
|
|
95
|
-
theme
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
;
|
|
99
|
-
const script = "window.Router = (function () {"
|
|
100
|
-
+ CutString(ClientMounter.toString(), "{")[1]
|
|
101
|
-
+ ")();";
|
|
102
|
-
const hash = QuickHash(script);
|
|
103
|
-
export function _resolve(fragments) {
|
|
104
|
-
if (!fragments[2])
|
|
105
|
-
return null;
|
|
106
|
-
// const build = GetSheet();
|
|
107
|
-
if (!fragments[2].startsWith(hash))
|
|
108
|
-
return null;
|
|
109
|
-
const headers = new Headers();
|
|
110
|
-
headers.set("Content-Type", "text/javascript");
|
|
111
|
-
headers.set("Cache-Control", "public, max-age=604800");
|
|
112
|
-
return new Response(script, { headers });
|
|
113
|
-
}
|
|
114
|
-
export function GetMountUrl() {
|
|
115
|
-
return `/_/mount/${hash}.js`;
|
|
116
|
-
}
|
package/bin/client/watch.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function __RebuildClient__(): Promise<void>;
|
package/bin/client/watch.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { GenerateClient } from "../client/index.js";
|
|
2
|
-
import { ReadConfig } from "../cli/config.js";
|
|
3
|
-
export async function __RebuildClient__() {
|
|
4
|
-
if (process.env.NODE_ENV === "production")
|
|
5
|
-
return;
|
|
6
|
-
const config = await ReadConfig();
|
|
7
|
-
const client = config.client;
|
|
8
|
-
if (!client)
|
|
9
|
-
return;
|
|
10
|
-
GenerateClient(client, false).catch(console.error);
|
|
11
|
-
}
|
package/bin/helper.d.ts
DELETED
package/bin/helper.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export function CutString(str, pivot, offset = 1) {
|
|
2
|
-
if (offset > 0) {
|
|
3
|
-
let cursor = 0;
|
|
4
|
-
while (offset !== 0) {
|
|
5
|
-
const i = str.indexOf(pivot, cursor);
|
|
6
|
-
if (i === -1)
|
|
7
|
-
return [str, ""];
|
|
8
|
-
cursor = i + 1;
|
|
9
|
-
offset--;
|
|
10
|
-
}
|
|
11
|
-
cursor--;
|
|
12
|
-
return [str.slice(0, cursor), str.slice(cursor + pivot.length)];
|
|
13
|
-
}
|
|
14
|
-
if (offset < 0) {
|
|
15
|
-
let cursor = str.length;
|
|
16
|
-
while (offset !== 0) {
|
|
17
|
-
const i = str.lastIndexOf(pivot, cursor);
|
|
18
|
-
if (i === -1)
|
|
19
|
-
return [str, ""];
|
|
20
|
-
cursor = i - 1;
|
|
21
|
-
offset++;
|
|
22
|
-
}
|
|
23
|
-
cursor++;
|
|
24
|
-
return [str.slice(0, cursor), str.slice(cursor + pivot.length)];
|
|
25
|
-
}
|
|
26
|
-
return [str, ""];
|
|
27
|
-
}
|
|
28
|
-
export function Singleton(name, cb) {
|
|
29
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
-
const g = globalThis;
|
|
31
|
-
g.__singletons ??= {};
|
|
32
|
-
g.__singletons[name] ??= cb();
|
|
33
|
-
return g.__singletons[name];
|
|
34
|
-
}
|
package/bin/index.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { RouteModule, CatchFunction, RenderFunction } from './types.js';
|
|
2
|
-
import { RouteContext, GenericContext } from "./router.js";
|
|
3
|
-
import { createRequestHandler } from './request/index.js';
|
|
4
|
-
import { MetaDescriptor, RenderMetaDescriptor, ShellOptions, ApplyMetaDescriptorDefaults, LdJsonObject, OpenGraph, OpenGraphImage, OpenGraphVideo, OpenGraphAudio, InferShellOptions } from './util/shell.js';
|
|
5
|
-
import { redirect, refresh, revalidate, text, json } from './util/response.js';
|
|
6
|
-
import { Cookies, CookieOptions } from "./util/cookies.js";
|
|
7
|
-
import { EventSourceConnection } from "./util/event-source.js";
|
|
8
|
-
import { DynamicReference } from './util/dynamic.js';
|
|
9
|
-
import { StyleClass } from './util/css.js';
|
|
10
|
-
import { Endpoint } from './util/endpoint.js';
|
|
11
|
-
export { createRequestHandler, CatchFunction, RenderFunction, RouteContext, RouteModule, GenericContext, Cookies, CookieOptions, Endpoint, DynamicReference, StyleClass, EventSourceConnection, redirect, refresh, revalidate, text, json, MetaDescriptor, RenderMetaDescriptor, ShellOptions, ApplyMetaDescriptorDefaults, LdJsonObject, OpenGraph, OpenGraphImage, OpenGraphVideo, OpenGraphAudio, InferShellOptions };
|
package/bin/index.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { RouteContext, GenericContext } from "./router.js";
|
|
2
|
-
import { createRequestHandler } from './request/index.js';
|
|
3
|
-
import { RenderMetaDescriptor, ApplyMetaDescriptorDefaults } from './util/shell.js';
|
|
4
|
-
import { redirect, refresh, revalidate, text, json } from './util/response.js';
|
|
5
|
-
import { Cookies } from "./util/cookies.js";
|
|
6
|
-
import { EventSourceConnection } from "./util/event-source.js";
|
|
7
|
-
import { DynamicReference } from './util/dynamic.js';
|
|
8
|
-
import { StyleClass } from './util/css.js';
|
|
9
|
-
import { Endpoint } from './util/endpoint.js';
|
|
10
|
-
export { createRequestHandler, RouteContext, GenericContext,
|
|
11
|
-
// Request helpers
|
|
12
|
-
Cookies, Endpoint, DynamicReference,
|
|
13
|
-
// CSS Helper
|
|
14
|
-
StyleClass,
|
|
15
|
-
// SSE helper
|
|
16
|
-
EventSourceConnection,
|
|
17
|
-
// Response helpers
|
|
18
|
-
redirect, refresh, revalidate, text, json, RenderMetaDescriptor, ApplyMetaDescriptorDefaults };
|
package/bin/request/http.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { IncomingMessage, ServerResponse } from "http";
|
|
2
|
-
import type { ViteDevServer } from "vite";
|
|
3
|
-
import { GenericContext } from "../router.js";
|
|
4
|
-
type Config = {
|
|
5
|
-
build: Promise<any> | (() => Promise<Record<string, any>>);
|
|
6
|
-
viteDevServer: ViteDevServer | null;
|
|
7
|
-
render: GenericContext["render"];
|
|
8
|
-
};
|
|
9
|
-
export declare function createRequestHandler(config: Config): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
10
|
-
export {};
|
package/bin/request/http.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { Resolve } from "../request/native.js";
|
|
2
|
-
export function createRequestHandler(config) {
|
|
3
|
-
return async (req, res) => {
|
|
4
|
-
try {
|
|
5
|
-
const mod = typeof config.build === "function" ? await config.build() : await config.build;
|
|
6
|
-
const request = NativeRequest(req);
|
|
7
|
-
let { response, headers } = await Resolve(request, mod.tree, config);
|
|
8
|
-
res.writeHead(response.status, headers);
|
|
9
|
-
let rendered = await response.text();
|
|
10
|
-
res.end(rendered);
|
|
11
|
-
}
|
|
12
|
-
catch (e) {
|
|
13
|
-
res.statusCode = 500;
|
|
14
|
-
if (e instanceof Error) {
|
|
15
|
-
console.error(e.stack);
|
|
16
|
-
config.viteDevServer?.ssrFixStacktrace(e);
|
|
17
|
-
res.end(e.stack);
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
console.error(e);
|
|
21
|
-
res.end(String(e));
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
function NativeRequest(req) {
|
|
27
|
-
const ctrl = new AbortController();
|
|
28
|
-
const headers = new Headers(req.headers);
|
|
29
|
-
const url = new URL(`http://${headers.get('host')}${req.originalUrl || req.url}`);
|
|
30
|
-
req.once('aborted', () => ctrl.abort());
|
|
31
|
-
const bodied = req.method !== "GET" && req.method !== "HEAD";
|
|
32
|
-
return new Request(url, {
|
|
33
|
-
headers,
|
|
34
|
-
method: req.method,
|
|
35
|
-
body: bodied ? req : undefined,
|
|
36
|
-
signal: ctrl.signal,
|
|
37
|
-
referrer: headers.get("referrer") || undefined,
|
|
38
|
-
// @ts-ignore
|
|
39
|
-
duplex: bodied ? 'half' : undefined
|
|
40
|
-
});
|
|
41
|
-
}
|
package/bin/request/index.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { ViteDevServer } from "vite";
|
|
2
|
-
import * as native from "../request/native.js";
|
|
3
|
-
import * as http from "../request/http.js";
|
|
4
|
-
import { GenericContext, RouteTree } from '../router.js';
|
|
5
|
-
export type Config = {
|
|
6
|
-
build: Promise<any> | (() => Promise<Record<string, any>>);
|
|
7
|
-
viteDevServer: ViteDevServer | null;
|
|
8
|
-
render: GenericContext["render"];
|
|
9
|
-
};
|
|
10
|
-
export type RouterModule = {
|
|
11
|
-
tree: RouteTree;
|
|
12
|
-
};
|
|
13
|
-
export declare const createRequestHandler: {
|
|
14
|
-
http: typeof http.createRequestHandler;
|
|
15
|
-
native: typeof native.createRequestHandler;
|
|
16
|
-
};
|
package/bin/request/index.js
DELETED
package/bin/request/native.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { RouteTree } from '../router.js';
|
|
2
|
-
import { Config } from '../request/index.js';
|
|
3
|
-
export declare function createRequestHandler(config: Config): (req: Request) => Promise<Response>;
|
|
4
|
-
export declare function Resolve(request: Request, tree: RouteTree, config: Config): Promise<{
|
|
5
|
-
response: Response;
|
|
6
|
-
headers: {
|
|
7
|
-
[key: string]: string | string[];
|
|
8
|
-
};
|
|
9
|
-
}>;
|
package/bin/request/native.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { GenericContext } from '../router.js';
|
|
2
|
-
export function createRequestHandler(config) {
|
|
3
|
-
return async (req) => {
|
|
4
|
-
try {
|
|
5
|
-
const mod = typeof config.build === "function" ? await config.build() : await config.build;
|
|
6
|
-
let { response } = await Resolve(req, mod.tree, config);
|
|
7
|
-
return response;
|
|
8
|
-
}
|
|
9
|
-
catch (e) {
|
|
10
|
-
if (e instanceof Error) {
|
|
11
|
-
console.error(e.stack);
|
|
12
|
-
config.viteDevServer?.ssrFixStacktrace(e);
|
|
13
|
-
return new Response(e.message + "\n" + e.stack, { status: 500, statusText: "Internal Server Error" });
|
|
14
|
-
}
|
|
15
|
-
else {
|
|
16
|
-
console.error(e);
|
|
17
|
-
return new Response(String(e), { status: 500, statusText: "Internal Server Error" });
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
export async function Resolve(request, tree, config) {
|
|
23
|
-
const url = new URL(request.url);
|
|
24
|
-
const ctx = new GenericContext(request, url, config.render);
|
|
25
|
-
const x = ctx.url.pathname.endsWith("/") ? ctx.url.pathname.slice(0, -1) : ctx.url.pathname;
|
|
26
|
-
const fragments = x.split("/").slice(1);
|
|
27
|
-
let response = await tree.resolve(fragments, ctx);
|
|
28
|
-
if (response === null)
|
|
29
|
-
response = new Response("No Route Found", { status: 404, statusText: "Not Found", headers: ctx.headers });
|
|
30
|
-
// Override with context headers
|
|
31
|
-
if (response.headers !== ctx.headers) {
|
|
32
|
-
for (const [key, value] of ctx.headers) {
|
|
33
|
-
if (ctx.headers.has(key))
|
|
34
|
-
continue;
|
|
35
|
-
response.headers.set(key, value);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
// Merge cookie changes
|
|
39
|
-
const headers = Object.fromEntries(response.headers);
|
|
40
|
-
const cookies = ctx.cookie.export();
|
|
41
|
-
if (cookies.length > 0) {
|
|
42
|
-
headers['set-cookie'] = cookies;
|
|
43
|
-
response.headers.set("Set-Cookie", cookies[0]); // Response object doesn't support multi-header..[]
|
|
44
|
-
}
|
|
45
|
-
return { response, headers };
|
|
46
|
-
}
|
package/bin/response.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export declare function text(text: string, init?: ResponseInit): Response;
|
|
2
|
-
export declare function json(data: unknown, init?: ResponseInit): Response;
|
|
3
|
-
export declare function redirect(url: string, init?: ResponseInit & {
|
|
4
|
-
client?: boolean;
|
|
5
|
-
}): Response;
|
|
6
|
-
export declare function revalidate(init?: ResponseInit): Response;
|
|
7
|
-
export declare function refresh(init?: ResponseInit & {
|
|
8
|
-
client?: boolean;
|
|
9
|
-
}): Response;
|
package/bin/response.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
export function text(text, init) {
|
|
2
|
-
init ||= {};
|
|
3
|
-
init.statusText ||= "ok";
|
|
4
|
-
init.status = 200;
|
|
5
|
-
const res = new Response(text, init);
|
|
6
|
-
res.headers.set("Content-Type", "text/plain");
|
|
7
|
-
res.headers.set("X-Caught", "true");
|
|
8
|
-
return res;
|
|
9
|
-
}
|
|
10
|
-
export function json(data, init) {
|
|
11
|
-
init ||= {};
|
|
12
|
-
init.statusText ||= "ok";
|
|
13
|
-
init.status = 200;
|
|
14
|
-
const res = new Response(JSON.stringify(data), init);
|
|
15
|
-
res.headers.set("Content-Type", "application/json");
|
|
16
|
-
res.headers.set("X-Caught", "true");
|
|
17
|
-
return res;
|
|
18
|
-
}
|
|
19
|
-
export function redirect(url, init) {
|
|
20
|
-
init ||= {};
|
|
21
|
-
init.statusText ||= "Temporary Redirect";
|
|
22
|
-
init.status = 307;
|
|
23
|
-
const res = new Response("", init);
|
|
24
|
-
if (!init?.client)
|
|
25
|
-
res.headers.set("Location", url);
|
|
26
|
-
res.headers.set("HX-Location", url); // use hx-boost if applicable
|
|
27
|
-
return res;
|
|
28
|
-
}
|
|
29
|
-
export function revalidate(init) {
|
|
30
|
-
init ||= {};
|
|
31
|
-
init.statusText ||= "ok";
|
|
32
|
-
init.status = 200;
|
|
33
|
-
const res = new Response("", init);
|
|
34
|
-
res.headers.set("HX-Location", "");
|
|
35
|
-
return res;
|
|
36
|
-
}
|
|
37
|
-
export function refresh(init) {
|
|
38
|
-
init ||= {};
|
|
39
|
-
init.statusText ||= "ok";
|
|
40
|
-
init.status = 200;
|
|
41
|
-
const res = new Response("", init);
|
|
42
|
-
if (!init?.client)
|
|
43
|
-
res.headers.set("Refresh", "0"); // fallback
|
|
44
|
-
res.headers.set("HX-Refresh", "true");
|
|
45
|
-
return res;
|
|
46
|
-
}
|
package/bin/router.d.ts
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { Parameterized, ParameterShaper } from './util/parameters.js';
|
|
2
|
-
import { RouteModule } from "./types.js";
|
|
3
|
-
import { Cookies } from './util/cookies.js';
|
|
4
|
-
export declare class GenericContext {
|
|
5
|
-
request: Request;
|
|
6
|
-
headers: Headers;
|
|
7
|
-
cookie: Cookies;
|
|
8
|
-
params: {
|
|
9
|
-
[key: string]: string;
|
|
10
|
-
};
|
|
11
|
-
url: URL;
|
|
12
|
-
render: (res: JSX.Element) => Response;
|
|
13
|
-
constructor(request: GenericContext["request"], url: GenericContext["url"], renderer: GenericContext["render"]);
|
|
14
|
-
shape<T extends ParameterShaper>(shape: T): RouteContext<T>;
|
|
15
|
-
}
|
|
16
|
-
export declare class RouteContext<T extends ParameterShaper> {
|
|
17
|
-
request: Request;
|
|
18
|
-
headers: Headers;
|
|
19
|
-
cookie: Cookies;
|
|
20
|
-
params: Parameterized<T>;
|
|
21
|
-
url: URL;
|
|
22
|
-
render: (res: JSX.Element) => Response;
|
|
23
|
-
constructor(base: GenericContext, shape: T);
|
|
24
|
-
}
|
|
25
|
-
export declare class RouteLeaf {
|
|
26
|
-
module: RouteModule<any>;
|
|
27
|
-
constructor(module: RouteModule<any>);
|
|
28
|
-
resolve(ctx: GenericContext): Promise<Response | null>;
|
|
29
|
-
error(ctx: GenericContext, e: unknown): Promise<Response>;
|
|
30
|
-
private renderWrapper;
|
|
31
|
-
}
|
|
32
|
-
export declare class RouteTree {
|
|
33
|
-
root: boolean;
|
|
34
|
-
nested: Map<string, RouteTree>;
|
|
35
|
-
index: RouteLeaf | null;
|
|
36
|
-
slug: RouteLeaf | null;
|
|
37
|
-
wild: RouteTree | null;
|
|
38
|
-
wildCard: string;
|
|
39
|
-
constructor(root?: boolean);
|
|
40
|
-
ingest(path: string | string[], module: RouteModule<any>): void;
|
|
41
|
-
resolve(fragments: string[], ctx: GenericContext): Promise<Response | null>;
|
|
42
|
-
private _resolve;
|
|
43
|
-
private resolveIndex;
|
|
44
|
-
private resolveNext;
|
|
45
|
-
private resolveWild;
|
|
46
|
-
private resolveSlug;
|
|
47
|
-
private resolveNative;
|
|
48
|
-
private unwrap;
|
|
49
|
-
}
|