@hyperspan/framework 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build.ts +9 -22
- package/dist/assets.js +32 -148
- package/dist/server.js +12 -6
- package/package.json +4 -3
- package/src/actions.test.ts +13 -14
- package/src/actions.ts +16 -13
- package/src/assets.ts +41 -13
- package/src/clientjs/hyperspan-client.ts +23 -8
- package/src/clientjs/preact.ts +2 -1
- package/src/server.ts +7 -14
- package/dist/assets.d.ts +0 -46
- package/dist/server.d.ts +0 -88
package/build.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {build} from 'bun';
|
|
2
|
-
import dts from 'bun-plugin-dts';
|
|
1
|
+
import { build } from 'bun';
|
|
3
2
|
|
|
4
3
|
const entrypoints = ['./src/server.ts', './src/assets.ts'];
|
|
5
4
|
const external = ['@hyperspan/html'];
|
|
@@ -7,23 +6,11 @@ const outdir = './dist';
|
|
|
7
6
|
const target = 'node';
|
|
8
7
|
const splitting = true;
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}),
|
|
19
|
-
|
|
20
|
-
// Build type files for TypeScript
|
|
21
|
-
build({
|
|
22
|
-
entrypoints,
|
|
23
|
-
external,
|
|
24
|
-
outdir,
|
|
25
|
-
target,
|
|
26
|
-
splitting,
|
|
27
|
-
plugins: [dts()],
|
|
28
|
-
}),
|
|
29
|
-
]);
|
|
9
|
+
// Build JS
|
|
10
|
+
await build({
|
|
11
|
+
entrypoints,
|
|
12
|
+
external,
|
|
13
|
+
outdir,
|
|
14
|
+
target,
|
|
15
|
+
splitting,
|
|
16
|
+
});
|
package/dist/assets.js
CHANGED
|
@@ -1,145 +1,11 @@
|
|
|
1
1
|
// src/assets.ts
|
|
2
2
|
import { html } from "@hyperspan/html";
|
|
3
|
-
|
|
4
|
-
// src/clientjs/md5.js
|
|
5
|
-
function md5cycle(x, k) {
|
|
6
|
-
var a = x[0], b = x[1], c = x[2], d = x[3];
|
|
7
|
-
a = ff(a, b, c, d, k[0], 7, -680876936);
|
|
8
|
-
d = ff(d, a, b, c, k[1], 12, -389564586);
|
|
9
|
-
c = ff(c, d, a, b, k[2], 17, 606105819);
|
|
10
|
-
b = ff(b, c, d, a, k[3], 22, -1044525330);
|
|
11
|
-
a = ff(a, b, c, d, k[4], 7, -176418897);
|
|
12
|
-
d = ff(d, a, b, c, k[5], 12, 1200080426);
|
|
13
|
-
c = ff(c, d, a, b, k[6], 17, -1473231341);
|
|
14
|
-
b = ff(b, c, d, a, k[7], 22, -45705983);
|
|
15
|
-
a = ff(a, b, c, d, k[8], 7, 1770035416);
|
|
16
|
-
d = ff(d, a, b, c, k[9], 12, -1958414417);
|
|
17
|
-
c = ff(c, d, a, b, k[10], 17, -42063);
|
|
18
|
-
b = ff(b, c, d, a, k[11], 22, -1990404162);
|
|
19
|
-
a = ff(a, b, c, d, k[12], 7, 1804603682);
|
|
20
|
-
d = ff(d, a, b, c, k[13], 12, -40341101);
|
|
21
|
-
c = ff(c, d, a, b, k[14], 17, -1502002290);
|
|
22
|
-
b = ff(b, c, d, a, k[15], 22, 1236535329);
|
|
23
|
-
a = gg(a, b, c, d, k[1], 5, -165796510);
|
|
24
|
-
d = gg(d, a, b, c, k[6], 9, -1069501632);
|
|
25
|
-
c = gg(c, d, a, b, k[11], 14, 643717713);
|
|
26
|
-
b = gg(b, c, d, a, k[0], 20, -373897302);
|
|
27
|
-
a = gg(a, b, c, d, k[5], 5, -701558691);
|
|
28
|
-
d = gg(d, a, b, c, k[10], 9, 38016083);
|
|
29
|
-
c = gg(c, d, a, b, k[15], 14, -660478335);
|
|
30
|
-
b = gg(b, c, d, a, k[4], 20, -405537848);
|
|
31
|
-
a = gg(a, b, c, d, k[9], 5, 568446438);
|
|
32
|
-
d = gg(d, a, b, c, k[14], 9, -1019803690);
|
|
33
|
-
c = gg(c, d, a, b, k[3], 14, -187363961);
|
|
34
|
-
b = gg(b, c, d, a, k[8], 20, 1163531501);
|
|
35
|
-
a = gg(a, b, c, d, k[13], 5, -1444681467);
|
|
36
|
-
d = gg(d, a, b, c, k[2], 9, -51403784);
|
|
37
|
-
c = gg(c, d, a, b, k[7], 14, 1735328473);
|
|
38
|
-
b = gg(b, c, d, a, k[12], 20, -1926607734);
|
|
39
|
-
a = hh(a, b, c, d, k[5], 4, -378558);
|
|
40
|
-
d = hh(d, a, b, c, k[8], 11, -2022574463);
|
|
41
|
-
c = hh(c, d, a, b, k[11], 16, 1839030562);
|
|
42
|
-
b = hh(b, c, d, a, k[14], 23, -35309556);
|
|
43
|
-
a = hh(a, b, c, d, k[1], 4, -1530992060);
|
|
44
|
-
d = hh(d, a, b, c, k[4], 11, 1272893353);
|
|
45
|
-
c = hh(c, d, a, b, k[7], 16, -155497632);
|
|
46
|
-
b = hh(b, c, d, a, k[10], 23, -1094730640);
|
|
47
|
-
a = hh(a, b, c, d, k[13], 4, 681279174);
|
|
48
|
-
d = hh(d, a, b, c, k[0], 11, -358537222);
|
|
49
|
-
c = hh(c, d, a, b, k[3], 16, -722521979);
|
|
50
|
-
b = hh(b, c, d, a, k[6], 23, 76029189);
|
|
51
|
-
a = hh(a, b, c, d, k[9], 4, -640364487);
|
|
52
|
-
d = hh(d, a, b, c, k[12], 11, -421815835);
|
|
53
|
-
c = hh(c, d, a, b, k[15], 16, 530742520);
|
|
54
|
-
b = hh(b, c, d, a, k[2], 23, -995338651);
|
|
55
|
-
a = ii(a, b, c, d, k[0], 6, -198630844);
|
|
56
|
-
d = ii(d, a, b, c, k[7], 10, 1126891415);
|
|
57
|
-
c = ii(c, d, a, b, k[14], 15, -1416354905);
|
|
58
|
-
b = ii(b, c, d, a, k[5], 21, -57434055);
|
|
59
|
-
a = ii(a, b, c, d, k[12], 6, 1700485571);
|
|
60
|
-
d = ii(d, a, b, c, k[3], 10, -1894986606);
|
|
61
|
-
c = ii(c, d, a, b, k[10], 15, -1051523);
|
|
62
|
-
b = ii(b, c, d, a, k[1], 21, -2054922799);
|
|
63
|
-
a = ii(a, b, c, d, k[8], 6, 1873313359);
|
|
64
|
-
d = ii(d, a, b, c, k[15], 10, -30611744);
|
|
65
|
-
c = ii(c, d, a, b, k[6], 15, -1560198380);
|
|
66
|
-
b = ii(b, c, d, a, k[13], 21, 1309151649);
|
|
67
|
-
a = ii(a, b, c, d, k[4], 6, -145523070);
|
|
68
|
-
d = ii(d, a, b, c, k[11], 10, -1120210379);
|
|
69
|
-
c = ii(c, d, a, b, k[2], 15, 718787259);
|
|
70
|
-
b = ii(b, c, d, a, k[9], 21, -343485551);
|
|
71
|
-
x[0] = add32(a, x[0]);
|
|
72
|
-
x[1] = add32(b, x[1]);
|
|
73
|
-
x[2] = add32(c, x[2]);
|
|
74
|
-
x[3] = add32(d, x[3]);
|
|
75
|
-
}
|
|
76
|
-
function cmn(q, a, b, x, s, t) {
|
|
77
|
-
a = add32(add32(a, q), add32(x, t));
|
|
78
|
-
return add32(a << s | a >>> 32 - s, b);
|
|
79
|
-
}
|
|
80
|
-
function ff(a, b, c, d, x, s, t) {
|
|
81
|
-
return cmn(b & c | ~b & d, a, b, x, s, t);
|
|
82
|
-
}
|
|
83
|
-
function gg(a, b, c, d, x, s, t) {
|
|
84
|
-
return cmn(b & d | c & ~d, a, b, x, s, t);
|
|
85
|
-
}
|
|
86
|
-
function hh(a, b, c, d, x, s, t) {
|
|
87
|
-
return cmn(b ^ c ^ d, a, b, x, s, t);
|
|
88
|
-
}
|
|
89
|
-
function ii(a, b, c, d, x, s, t) {
|
|
90
|
-
return cmn(c ^ (b | ~d), a, b, x, s, t);
|
|
91
|
-
}
|
|
92
|
-
function md51(s) {
|
|
93
|
-
var txt = "";
|
|
94
|
-
var n = s.length, state = [1732584193, -271733879, -1732584194, 271733878], i;
|
|
95
|
-
for (i = 64;i <= s.length; i += 64) {
|
|
96
|
-
md5cycle(state, md5blk(s.substring(i - 64, i)));
|
|
97
|
-
}
|
|
98
|
-
s = s.substring(i - 64);
|
|
99
|
-
var tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
100
|
-
for (i = 0;i < s.length; i++)
|
|
101
|
-
tail[i >> 2] |= s.charCodeAt(i) << (i % 4 << 3);
|
|
102
|
-
tail[i >> 2] |= 128 << (i % 4 << 3);
|
|
103
|
-
if (i > 55) {
|
|
104
|
-
md5cycle(state, tail);
|
|
105
|
-
for (i = 0;i < 16; i++)
|
|
106
|
-
tail[i] = 0;
|
|
107
|
-
}
|
|
108
|
-
tail[14] = n * 8;
|
|
109
|
-
md5cycle(state, tail);
|
|
110
|
-
return state;
|
|
111
|
-
}
|
|
112
|
-
function md5blk(s) {
|
|
113
|
-
var md5blks = [], i;
|
|
114
|
-
for (i = 0;i < 64; i += 4) {
|
|
115
|
-
md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
|
|
116
|
-
}
|
|
117
|
-
return md5blks;
|
|
118
|
-
}
|
|
119
|
-
var hex_chr = "0123456789abcdef".split("");
|
|
120
|
-
function rhex(n) {
|
|
121
|
-
var s = "", j = 0;
|
|
122
|
-
for (;j < 4; j++)
|
|
123
|
-
s += hex_chr[n >> j * 8 + 4 & 15] + hex_chr[n >> j * 8 & 15];
|
|
124
|
-
return s;
|
|
125
|
-
}
|
|
126
|
-
function hex(x) {
|
|
127
|
-
for (var i = 0;i < x.length; i++)
|
|
128
|
-
x[i] = rhex(x[i]);
|
|
129
|
-
return x.join("");
|
|
130
|
-
}
|
|
131
|
-
function add32(a, b) {
|
|
132
|
-
return a + b & 4294967295;
|
|
133
|
-
}
|
|
134
|
-
function md5(s) {
|
|
135
|
-
return hex(md51(s));
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// src/assets.ts
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
139
4
|
import { readdir } from "node:fs/promises";
|
|
140
5
|
import { resolve } from "node:path";
|
|
141
6
|
var IS_PROD = false;
|
|
142
7
|
var PWD = import.meta.dir;
|
|
8
|
+
var clientImportMap = new Map;
|
|
143
9
|
var clientJSFiles = new Map;
|
|
144
10
|
async function buildClientJS() {
|
|
145
11
|
const sourceFile = resolve(PWD, "../", "./src/clientjs/hyperspan-client.ts");
|
|
@@ -180,15 +46,7 @@ function hyperspanScriptTags() {
|
|
|
180
46
|
const jsFiles = Array.from(clientJSFiles.entries());
|
|
181
47
|
return html`
|
|
182
48
|
<script type="importmap">
|
|
183
|
-
{
|
|
184
|
-
"imports": {
|
|
185
|
-
"preact": "https://esm.sh/preact@10.26.4",
|
|
186
|
-
"preact/": "https://esm.sh/preact@10.26.4/",
|
|
187
|
-
"react": "https://esm.sh/preact@10.26.4/compat",
|
|
188
|
-
"react/": "https://esm.sh/preact@10.26.4/compat/",
|
|
189
|
-
"react-dom": "https://esm.sh/preact@10.26.4/compat"
|
|
190
|
-
}
|
|
191
|
-
}
|
|
49
|
+
{"imports": ${Object.fromEntries(clientImportMap)}}
|
|
192
50
|
</script>
|
|
193
51
|
${jsFiles.map(([key, file]) => html`<script
|
|
194
52
|
id="js-${key}"
|
|
@@ -197,21 +55,46 @@ function hyperspanScriptTags() {
|
|
|
197
55
|
></script>`)}
|
|
198
56
|
`;
|
|
199
57
|
}
|
|
58
|
+
var PREACT_PUBLIC_FILE_PATH = "/_hs/js/preact.js";
|
|
59
|
+
function md5(content) {
|
|
60
|
+
return createHash("md5").update(content).digest("hex");
|
|
61
|
+
}
|
|
62
|
+
async function copyPreactToPublicFolder() {
|
|
63
|
+
const sourceFile = resolve(PWD, "../", "./src/clientjs/preact.ts");
|
|
64
|
+
const preactClient = Bun.build({
|
|
65
|
+
entrypoints: [sourceFile],
|
|
66
|
+
outdir: "./public/_hs/js",
|
|
67
|
+
minify: true,
|
|
68
|
+
format: "esm",
|
|
69
|
+
target: "browser"
|
|
70
|
+
});
|
|
71
|
+
}
|
|
200
72
|
async function createPreactIsland(file) {
|
|
201
73
|
let filePath = file.replace("file://", "");
|
|
74
|
+
const jsId = md5(filePath);
|
|
75
|
+
if (!clientImportMap.has("preact")) {
|
|
76
|
+
await copyPreactToPublicFolder();
|
|
77
|
+
clientImportMap.set("preact", "" + PREACT_PUBLIC_FILE_PATH);
|
|
78
|
+
clientImportMap.set("preact/compat", "" + PREACT_PUBLIC_FILE_PATH);
|
|
79
|
+
clientImportMap.set("preact/hooks", "" + PREACT_PUBLIC_FILE_PATH);
|
|
80
|
+
clientImportMap.set("preact/jsx-runtime", "" + PREACT_PUBLIC_FILE_PATH);
|
|
81
|
+
}
|
|
82
|
+
if (!clientImportMap.has("react")) {
|
|
83
|
+
clientImportMap.set("react", "." + PREACT_PUBLIC_FILE_PATH);
|
|
84
|
+
clientImportMap.set("react-dom", "." + PREACT_PUBLIC_FILE_PATH);
|
|
85
|
+
}
|
|
202
86
|
let resultStr = 'import{h,render}from"preact";';
|
|
203
|
-
const
|
|
87
|
+
const buildResult = await Bun.build({
|
|
204
88
|
entrypoints: [filePath],
|
|
205
89
|
minify: true,
|
|
206
90
|
external: ["react", "preact"],
|
|
207
91
|
env: "APP_PUBLIC_*"
|
|
208
92
|
});
|
|
209
|
-
for (const output of
|
|
93
|
+
for (const output of buildResult.outputs) {
|
|
210
94
|
resultStr += await output.text();
|
|
211
95
|
}
|
|
212
96
|
const r = /export\{([a-zA-Z]+) as default\}/g;
|
|
213
97
|
const matchExport = r.exec(resultStr);
|
|
214
|
-
const jsId = md5(resultStr);
|
|
215
98
|
if (!matchExport) {
|
|
216
99
|
throw new Error("File does not have a default export! Ensure a function has export default to use this.");
|
|
217
100
|
}
|
|
@@ -230,6 +113,7 @@ export {
|
|
|
230
113
|
hyperspanScriptTags,
|
|
231
114
|
createPreactIsland,
|
|
232
115
|
clientJSFiles,
|
|
116
|
+
clientImportMap,
|
|
233
117
|
clientCSSFiles,
|
|
234
118
|
buildClientJS,
|
|
235
119
|
buildClientCSS
|
package/dist/server.js
CHANGED
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
// src/server.ts
|
|
7
7
|
import { readdir } from "node:fs/promises";
|
|
8
8
|
import { basename, extname, join } from "node:path";
|
|
9
|
-
import {
|
|
9
|
+
import { html, isHSHtml, renderStream, renderAsync, render } from "@hyperspan/html";
|
|
10
10
|
|
|
11
11
|
// node_modules/isbot/index.mjs
|
|
12
|
-
var fullPattern = " daum[ /]| deusu/| yadirectfetcher|(?:^|[^g])news(?!sapphire)|(?<! (?:channel/|google/))google(?!(app|/google| pixel))|(?<! cu)bots?(?:\\b|_)|(?<!(?:lib))http|(?<![hg]m)score|@[a-z][\\w-]+\\.|\\(\\)|\\.com\\b|\\btime/|\\||^<|^[\\w \\.\\-\\(?:\\):%]+(?:/v?\\d+(?:\\.\\d+)?(?:\\.\\d{1,10})*?)?(?:,|$)|^[^ ]{50,}$|^\\d+\\b|^\\w*search\\b|^\\w+/[\\w\\(\\)]*$|^active|^ad muncher|^amaya|^avsdevicesdk/|^biglotron|^bot|^bw/|^clamav[ /]|^client/|^cobweb/|^custom|^ddg[_-]android|^discourse|^dispatch/\\d|^downcast/|^duckduckgo|^email|^facebook|^getright/|^gozilla/|^hobbit|^hotzonu|^hwcdn/|^igetter/|^jeode/|^jetty/|^jigsaw|^microsoft bits|^movabletype|^mozilla/\\d\\.\\d\\s[\\w\\.-]+$|^mozilla/\\d\\.\\d\\s\\(compatible;?(?:\\s\\w+\\/\\d+\\.\\d+)?\\)$|^navermailapp|^netsurf|^offline|^openai/|^owler|^php|^postman|^python|^rank|^read|^reed|^rest|^rss|^snapchat|^space bison|^svn|^swcd |^taringa|^thumbor/|^track|^w3c|^webbandit/|^webcopier|^wget|^whatsapp|^wordpress|^xenu link sleuth|^yahoo|^yandex|^zdm/\\d|^zoom marketplace/|^{{.*}}$|
|
|
12
|
+
var fullPattern = " daum[ /]| deusu/| yadirectfetcher|(?:^|[^g])news(?!sapphire)|(?<! (?:channel/|google/))google(?!(app|/google| pixel))|(?<! cu)bots?(?:\\b|_)|(?<!(?:lib))http|(?<![hg]m)score|(?<!cam)scan|@[a-z][\\w-]+\\.|\\(\\)|\\.com\\b|\\btime/|\\||^<|^[\\w \\.\\-\\(?:\\):%]+(?:/v?\\d+(?:\\.\\d+)?(?:\\.\\d{1,10})*?)?(?:,|$)|^[^ ]{50,}$|^\\d+\\b|^\\w*search\\b|^\\w+/[\\w\\(\\)]*$|^active|^ad muncher|^amaya|^avsdevicesdk/|^biglotron|^bot|^bw/|^clamav[ /]|^client/|^cobweb/|^custom|^ddg[_-]android|^discourse|^dispatch/\\d|^downcast/|^duckduckgo|^email|^facebook|^getright/|^gozilla/|^hobbit|^hotzonu|^hwcdn/|^igetter/|^jeode/|^jetty/|^jigsaw|^microsoft bits|^movabletype|^mozilla/\\d\\.\\d\\s[\\w\\.-]+$|^mozilla/\\d\\.\\d\\s\\(compatible;?(?:\\s\\w+\\/\\d+\\.\\d+)?\\)$|^navermailapp|^netsurf|^offline|^openai/|^owler|^php|^postman|^python|^rank|^read|^reed|^rest|^rss|^snapchat|^space bison|^svn|^swcd |^taringa|^thumbor/|^track|^w3c|^webbandit/|^webcopier|^wget|^whatsapp|^wordpress|^xenu link sleuth|^yahoo|^yandex|^zdm/\\d|^zoom marketplace/|^{{.*}}$|analyzer|archive|ask jeeves/teoma|audit|bit\\.ly/|bluecoat drtr|browsex|burpcollaborator|capture|catch|check\\b|checker|chrome-lighthouse|chromeframe|classifier|cloudflare|convertify|crawl|cypress/|dareboost|datanyze|dejaclick|detect|dmbrowser|download|evc-batch/|exaleadcloudview|feed|firephp|functionize|gomezagent|grab|headless|httrack|hubspot marketing grader|hydra|ibisbrowser|infrawatch|insight|inspect|iplabel|ips-agent|java(?!;)|library|linkcheck|mail\\.ru/|manager|measure|neustar wpm|node|nutch|offbyone|onetrust|optimize|pageburst|pagespeed|parser|perl|phantomjs|pingdom|powermarks|preview|proxy|ptst[ /]\\d|retriever|rexx;|rigor|rss\\b|scrape|server|sogou|sparkler/|speedcurve|spider|splash|statuscake|supercleaner|synapse|synthetic|tools|torrent|transcoder|url|validator|virtuoso|wappalyzer|webglance|webkit2png|whatcms/";
|
|
13
13
|
var naivePattern = /bot|crawl|http|lighthouse|scan|search|spider/i;
|
|
14
14
|
var pattern;
|
|
15
15
|
function getPattern() {
|
|
@@ -841,7 +841,11 @@ var Hono = class {
|
|
|
841
841
|
optionHandler = options;
|
|
842
842
|
} else {
|
|
843
843
|
optionHandler = options.optionHandler;
|
|
844
|
-
|
|
844
|
+
if (options.replaceRequest === false) {
|
|
845
|
+
replaceRequest = (request) => request;
|
|
846
|
+
} else {
|
|
847
|
+
replaceRequest = options.replaceRequest;
|
|
848
|
+
}
|
|
845
849
|
}
|
|
846
850
|
}
|
|
847
851
|
const getOptions = optionHandler ? (c) => {
|
|
@@ -851,7 +855,8 @@ var Hono = class {
|
|
|
851
855
|
let executionContext = undefined;
|
|
852
856
|
try {
|
|
853
857
|
executionContext = c.executionCtx;
|
|
854
|
-
} catch {
|
|
858
|
+
} catch {
|
|
859
|
+
}
|
|
855
860
|
return [c.env, executionContext];
|
|
856
861
|
};
|
|
857
862
|
replaceRequest ||= (() => {
|
|
@@ -1745,7 +1750,8 @@ var serveStatic2 = (options) => {
|
|
|
1745
1750
|
try {
|
|
1746
1751
|
const stats = await stat(path);
|
|
1747
1752
|
isDir2 = stats.isDirectory();
|
|
1748
|
-
} catch {
|
|
1753
|
+
} catch {
|
|
1754
|
+
}
|
|
1749
1755
|
return isDir2;
|
|
1750
1756
|
};
|
|
1751
1757
|
return serveStatic({
|
|
@@ -1862,7 +1868,7 @@ function createRoute(handler) {
|
|
|
1862
1868
|
const streamOpt = context.req.query("__nostream");
|
|
1863
1869
|
const streamingEnabled = !userIsBot && (streamOpt !== undefined ? streamOpt : true);
|
|
1864
1870
|
const routeKind = typeof routeContent;
|
|
1865
|
-
if (
|
|
1871
|
+
if (isHSHtml(routeContent)) {
|
|
1866
1872
|
if (streamingEnabled) {
|
|
1867
1873
|
return new StreamResponse(renderStream(routeContent));
|
|
1868
1874
|
} else {
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperspan/framework",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Hyperspan Web Framework",
|
|
5
5
|
"main": "dist/server.js",
|
|
6
|
+
"types": "src/server.ts",
|
|
6
7
|
"public": true,
|
|
7
8
|
"publishConfig": {
|
|
8
9
|
"access": "public"
|
|
@@ -63,10 +64,10 @@
|
|
|
63
64
|
"typescript": "^5.0.0"
|
|
64
65
|
},
|
|
65
66
|
"dependencies": {
|
|
66
|
-
"@hyperspan/html": "^0.1.
|
|
67
|
-
"@preact/compat": "^18.3.1",
|
|
67
|
+
"@hyperspan/html": "^0.1.6",
|
|
68
68
|
"hono": "^4.7.4",
|
|
69
69
|
"isbot": "^5.1.25",
|
|
70
|
+
"preact": "^10.26.5",
|
|
70
71
|
"zod": "^4.0.0-beta.20250415T232143"
|
|
71
72
|
}
|
|
72
73
|
}
|
package/src/actions.test.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import z from 'zod';
|
|
2
|
-
import { createAction
|
|
2
|
+
import { createAction } from './actions';
|
|
3
3
|
import { describe, it, expect } from 'bun:test';
|
|
4
|
-
import { html, render, type
|
|
4
|
+
import { html, render, type HSHtml } from '@hyperspan/html';
|
|
5
5
|
import type { Context } from 'hono';
|
|
6
6
|
|
|
7
7
|
describe('createAction', () => {
|
|
8
|
-
const formWithNameOnly = ({ data }:
|
|
8
|
+
const formWithNameOnly = ({ data }: { data?: { name: string } }) => {
|
|
9
9
|
return html`
|
|
10
10
|
<form>
|
|
11
11
|
<p>
|
|
12
12
|
Name:
|
|
13
|
-
<input type="text" name="name" value="${data
|
|
13
|
+
<input type="text" name="name" value="${data?.name || ''}" />
|
|
14
14
|
</p>
|
|
15
15
|
<button type="submit">Submit</button>
|
|
16
16
|
</form>
|
|
@@ -22,9 +22,9 @@ describe('createAction', () => {
|
|
|
22
22
|
const schema = z.object({
|
|
23
23
|
name: z.string(),
|
|
24
24
|
});
|
|
25
|
-
const action = createAction(schema
|
|
25
|
+
const action = createAction(schema, formWithNameOnly);
|
|
26
26
|
|
|
27
|
-
const formResponse = render(action.render({ data: { name: 'John' } }) as
|
|
27
|
+
const formResponse = render(action.render({ data: { name: 'John' } }) as HSHtml);
|
|
28
28
|
expect(formResponse).toContain('value="John"');
|
|
29
29
|
});
|
|
30
30
|
});
|
|
@@ -34,10 +34,9 @@ describe('createAction', () => {
|
|
|
34
34
|
const schema = z.object({
|
|
35
35
|
name: z.string().nonempty(),
|
|
36
36
|
});
|
|
37
|
-
const action = createAction(schema)
|
|
38
|
-
.
|
|
39
|
-
|
|
40
|
-
return html`<div>Thanks for submitting the form, ${data.name}!</div>`;
|
|
37
|
+
const action = createAction(schema, formWithNameOnly)
|
|
38
|
+
.post((c, { data }) => {
|
|
39
|
+
return html`<div>Thanks for submitting the form, ${data?.name}!</div>`;
|
|
41
40
|
})
|
|
42
41
|
.error((c, { error }) => {
|
|
43
42
|
return html`<div>There was an error! ${error?.message}</div>`;
|
|
@@ -56,7 +55,7 @@ describe('createAction', () => {
|
|
|
56
55
|
|
|
57
56
|
const response = await action.run('POST', mockContext);
|
|
58
57
|
|
|
59
|
-
const formResponse = render(response as
|
|
58
|
+
const formResponse = render(response as HSHtml);
|
|
60
59
|
expect(formResponse).toContain('Thanks for submitting the form, John!');
|
|
61
60
|
});
|
|
62
61
|
});
|
|
@@ -68,8 +67,8 @@ describe('createAction', () => {
|
|
|
68
67
|
});
|
|
69
68
|
const action = createAction(schema)
|
|
70
69
|
.form(formWithNameOnly)
|
|
71
|
-
.
|
|
72
|
-
return html`<div>Thanks for submitting the form, ${data
|
|
70
|
+
.post((c, { data }) => {
|
|
71
|
+
return html`<div>Thanks for submitting the form, ${data?.name}!</div>`;
|
|
73
72
|
})
|
|
74
73
|
.error((c, { error }) => {
|
|
75
74
|
return html`<div>There was an error! ${error?.message}</div>`;
|
|
@@ -88,7 +87,7 @@ describe('createAction', () => {
|
|
|
88
87
|
|
|
89
88
|
const response = await action.run('POST', mockContext);
|
|
90
89
|
|
|
91
|
-
const formResponse = render(response as
|
|
90
|
+
const formResponse = render(response as HSHtml);
|
|
92
91
|
expect(formResponse).toContain('There was an error!');
|
|
93
92
|
});
|
|
94
93
|
});
|
package/src/actions.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { html } from '@hyperspan/html';
|
|
1
|
+
import { html, HSHtml } from '@hyperspan/html';
|
|
2
2
|
import * as z from 'zod';
|
|
3
3
|
import { HTTPException } from 'hono/http-exception';
|
|
4
4
|
|
|
@@ -20,21 +20,24 @@ import type { Context } from 'hono';
|
|
|
20
20
|
*/
|
|
21
21
|
export interface HSAction<T extends z.ZodTypeAny> {
|
|
22
22
|
_kind: string;
|
|
23
|
-
form(renderForm: (data: z.infer<T>) =>
|
|
24
|
-
|
|
23
|
+
form(renderForm: ({ data }: { data?: z.infer<T> }) => HSHtml): HSAction<T>;
|
|
24
|
+
post(handler: (c: Context, { data }: { data?: z.infer<T> }) => THSResponseTypes): HSAction<T>;
|
|
25
25
|
error(
|
|
26
26
|
handler: (
|
|
27
27
|
c: Context,
|
|
28
|
-
{ data, error }: { data
|
|
28
|
+
{ data, error }: { data?: z.infer<T>; error?: z.ZodError | Error }
|
|
29
29
|
) => THSResponseTypes
|
|
30
30
|
): HSAction<T>;
|
|
31
|
-
render(props?: { data
|
|
31
|
+
render(props?: { data?: z.infer<T>; error?: z.ZodError | Error }): THSResponseTypes;
|
|
32
32
|
run(method: 'GET' | 'POST', c: Context): Promise<THSResponseTypes>;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export function createAction<T extends z.ZodTypeAny>(
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
export function createAction<T extends z.ZodTypeAny>(
|
|
36
|
+
schema: T | null = null,
|
|
37
|
+
form: Parameters<HSAction<T>['form']>[0] | null = null
|
|
38
|
+
) {
|
|
39
|
+
let _handler: Parameters<HSAction<T>['post']>[0] | null = null,
|
|
40
|
+
_form: Parameters<HSAction<T>['form']>[0] | null = form,
|
|
38
41
|
_errorHandler: Parameters<HSAction<T>['error']>[0] | null = null;
|
|
39
42
|
|
|
40
43
|
const api: HSAction<T> = {
|
|
@@ -50,7 +53,7 @@ export function createAction<T extends z.ZodTypeAny>(schema: T | null = null) {
|
|
|
50
53
|
* Returns result from form processing if successful
|
|
51
54
|
* Re-renders form with data and error information otherwise
|
|
52
55
|
*/
|
|
53
|
-
|
|
56
|
+
post(handler) {
|
|
54
57
|
_handler = handler;
|
|
55
58
|
return api;
|
|
56
59
|
},
|
|
@@ -63,8 +66,8 @@ export function createAction<T extends z.ZodTypeAny>(schema: T | null = null) {
|
|
|
63
66
|
/**
|
|
64
67
|
* Get form renderer method
|
|
65
68
|
*/
|
|
66
|
-
render(data) {
|
|
67
|
-
const form = _form ? _form(
|
|
69
|
+
render(formState?: { data?: z.infer<T>; error?: z.ZodError | Error }) {
|
|
70
|
+
const form = _form ? _form(formState || {}) : null;
|
|
68
71
|
return form ? html`<hs-action>${form}</hs-action>` : null;
|
|
69
72
|
},
|
|
70
73
|
|
|
@@ -86,7 +89,7 @@ export function createAction<T extends z.ZodTypeAny>(schema: T | null = null) {
|
|
|
86
89
|
const formData = await c.req.formData();
|
|
87
90
|
const jsonData = formDataToJSON(formData);
|
|
88
91
|
const schemaData = schema ? schema.safeParse(jsonData) : null;
|
|
89
|
-
const data = schemaData?.success ? (schemaData.data as z.infer<T>) :
|
|
92
|
+
const data = schemaData?.success ? (schemaData.data as z.infer<T>) : undefined;
|
|
90
93
|
let error: z.ZodError | Error | null = null;
|
|
91
94
|
|
|
92
95
|
try {
|
|
@@ -95,7 +98,7 @@ export function createAction<T extends z.ZodTypeAny>(schema: T | null = null) {
|
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
if (!_handler) {
|
|
98
|
-
throw new Error('Action handler not set! Every action must have a handler.');
|
|
101
|
+
throw new Error('Action POST handler not set! Every action must have a POST handler.');
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
return _handler(c, { data });
|
package/src/assets.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { html } from '@hyperspan/html';
|
|
2
|
-
import {
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
3
|
import { readdir } from 'node:fs/promises';
|
|
4
4
|
import { resolve } from 'node:path';
|
|
5
5
|
|
|
6
6
|
const IS_PROD = process.env.NODE_ENV === 'production';
|
|
7
7
|
const PWD = import.meta.dir;
|
|
8
8
|
|
|
9
|
+
export const clientImportMap = new Map<string, string>();
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
12
|
* Build client JS for end users (minimal JS for Hyperspan to work)
|
|
11
13
|
*/
|
|
@@ -74,15 +76,7 @@ export function hyperspanScriptTags() {
|
|
|
74
76
|
|
|
75
77
|
return html`
|
|
76
78
|
<script type="importmap">
|
|
77
|
-
{
|
|
78
|
-
"imports": {
|
|
79
|
-
"preact": "https://esm.sh/preact@10.26.4",
|
|
80
|
-
"preact/": "https://esm.sh/preact@10.26.4/",
|
|
81
|
-
"react": "https://esm.sh/preact@10.26.4/compat",
|
|
82
|
-
"react/": "https://esm.sh/preact@10.26.4/compat/",
|
|
83
|
-
"react-dom": "https://esm.sh/preact@10.26.4/compat"
|
|
84
|
-
}
|
|
85
|
-
}
|
|
79
|
+
{"imports": ${Object.fromEntries(clientImportMap)}}
|
|
86
80
|
</script>
|
|
87
81
|
${jsFiles.map(
|
|
88
82
|
([key, file]) =>
|
|
@@ -95,14 +89,49 @@ export function hyperspanScriptTags() {
|
|
|
95
89
|
`;
|
|
96
90
|
}
|
|
97
91
|
|
|
92
|
+
// External ESM = https://esm.sh/preact@10.26.4/compat
|
|
93
|
+
const PREACT_PUBLIC_FILE_PATH = '/_hs/js/preact.js';
|
|
94
|
+
|
|
95
|
+
function md5(content: string): string {
|
|
96
|
+
return createHash('md5').update(content).digest('hex');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Build Preact client JS and copy to public folder
|
|
101
|
+
*/
|
|
102
|
+
async function copyPreactToPublicFolder() {
|
|
103
|
+
const sourceFile = resolve(PWD, '../', './src/clientjs/preact.ts');
|
|
104
|
+
const preactClient = Bun.build({
|
|
105
|
+
entrypoints: [sourceFile],
|
|
106
|
+
outdir: './public/_hs/js',
|
|
107
|
+
minify: true,
|
|
108
|
+
format: 'esm',
|
|
109
|
+
target: 'browser',
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
98
113
|
/**
|
|
99
114
|
* Return a Preact component, mounted as an island in a <script> tag so it can be embedded into the page response.
|
|
100
115
|
*/
|
|
101
116
|
export async function createPreactIsland(file: string) {
|
|
102
117
|
let filePath = file.replace('file://', '');
|
|
118
|
+
const jsId = md5(filePath);
|
|
119
|
+
|
|
120
|
+
// Add Preact to client import map if not already present
|
|
121
|
+
if (!clientImportMap.has('preact')) {
|
|
122
|
+
await copyPreactToPublicFolder();
|
|
123
|
+
clientImportMap.set('preact', '' + PREACT_PUBLIC_FILE_PATH);
|
|
124
|
+
clientImportMap.set('preact/compat', '' + PREACT_PUBLIC_FILE_PATH);
|
|
125
|
+
clientImportMap.set('preact/hooks', '' + PREACT_PUBLIC_FILE_PATH);
|
|
126
|
+
clientImportMap.set('preact/jsx-runtime', '' + PREACT_PUBLIC_FILE_PATH);
|
|
127
|
+
}
|
|
128
|
+
if (!clientImportMap.has('react')) {
|
|
129
|
+
clientImportMap.set('react', '.' + PREACT_PUBLIC_FILE_PATH);
|
|
130
|
+
clientImportMap.set('react-dom', '.' + PREACT_PUBLIC_FILE_PATH);
|
|
131
|
+
}
|
|
103
132
|
|
|
104
133
|
let resultStr = 'import{h,render}from"preact";';
|
|
105
|
-
const
|
|
134
|
+
const buildResult = await Bun.build({
|
|
106
135
|
entrypoints: [filePath],
|
|
107
136
|
minify: true,
|
|
108
137
|
external: ['react', 'preact'],
|
|
@@ -110,14 +139,13 @@ export async function createPreactIsland(file: string) {
|
|
|
110
139
|
env: 'APP_PUBLIC_*', // Inlines any ENV that starts with 'APP_PUBLIC_'
|
|
111
140
|
});
|
|
112
141
|
|
|
113
|
-
for (const output of
|
|
142
|
+
for (const output of buildResult.outputs) {
|
|
114
143
|
resultStr += await output.text(); // string
|
|
115
144
|
}
|
|
116
145
|
|
|
117
146
|
// Find default export - this is our component
|
|
118
147
|
const r = /export\{([a-zA-Z]+) as default\}/g;
|
|
119
148
|
const matchExport = r.exec(resultStr);
|
|
120
|
-
const jsId = md5(resultStr);
|
|
121
149
|
|
|
122
150
|
if (!matchExport) {
|
|
123
151
|
throw new Error(
|
|
@@ -26,14 +26,10 @@ function htmlAsyncContentObserver() {
|
|
|
26
26
|
const slotEl = document.getElementById(slotId);
|
|
27
27
|
|
|
28
28
|
if (slotEl) {
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
setTimeout(() => {
|
|
34
|
-
Idiomorph.morph(slotEl, el.content.cloneNode(true));
|
|
35
|
-
el.parentNode.removeChild(el);
|
|
36
|
-
}, 100);
|
|
29
|
+
// Only insert the content if it is done streaming in
|
|
30
|
+
waitForEndContent(el.content).then(() => {
|
|
31
|
+
Idiomorph.morph(slotEl, el.content.cloneNode(true));
|
|
32
|
+
el.parentNode.removeChild(el);
|
|
37
33
|
});
|
|
38
34
|
}
|
|
39
35
|
} catch (e) {
|
|
@@ -46,6 +42,25 @@ function htmlAsyncContentObserver() {
|
|
|
46
42
|
}
|
|
47
43
|
htmlAsyncContentObserver();
|
|
48
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Wait until ALL of the content inside an element is present from streaming in.
|
|
47
|
+
* Large chunks of content can sometimes take more than a single tick to write to DOM.
|
|
48
|
+
*/
|
|
49
|
+
async function waitForEndContent(el: HTMLElement) {
|
|
50
|
+
return new Promise((resolve) => {
|
|
51
|
+
const interval = setInterval(() => {
|
|
52
|
+
const endComment = Array.from(el.childNodes).find((node) => {
|
|
53
|
+
return node.nodeType === Node.COMMENT_NODE && node.nodeValue === 'end';
|
|
54
|
+
});
|
|
55
|
+
if (endComment) {
|
|
56
|
+
el.removeChild(endComment);
|
|
57
|
+
clearInterval(interval);
|
|
58
|
+
resolve(true);
|
|
59
|
+
}
|
|
60
|
+
}, 10);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
49
64
|
/**
|
|
50
65
|
* Server action component to handle the client-side form submission and HTML replacement
|
|
51
66
|
*/
|
package/src/clientjs/preact.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export * from '
|
|
1
|
+
export * from 'preact/compat';
|
|
2
|
+
export { h, render } from 'preact';
|
package/src/server.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readdir } from 'node:fs/promises';
|
|
2
2
|
import { basename, extname, join } from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { HSHtml, html, isHSHtml, renderStream, renderAsync, render } from '@hyperspan/html';
|
|
4
4
|
import { isbot } from 'isbot';
|
|
5
5
|
import { buildClientJS, buildClientCSS } from './assets';
|
|
6
6
|
import { Hono, type Context } from 'hono';
|
|
@@ -13,7 +13,7 @@ const CWD = process.cwd();
|
|
|
13
13
|
/**
|
|
14
14
|
* Types
|
|
15
15
|
*/
|
|
16
|
-
export type THSResponseTypes =
|
|
16
|
+
export type THSResponseTypes = HSHtml | Response | string | null;
|
|
17
17
|
export type THSRouteHandler = (context: Context) => THSResponseTypes | Promise<THSResponseTypes>;
|
|
18
18
|
|
|
19
19
|
export type THSRoute = {
|
|
@@ -28,7 +28,7 @@ export type THSRoute = {
|
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* Define a route that can handle a direct HTTP request.
|
|
31
|
-
* Route handlers should return a
|
|
31
|
+
* Route handlers should return a HSHtml or Response object
|
|
32
32
|
*/
|
|
33
33
|
export function createRoute(handler?: THSRouteHandler): THSRoute {
|
|
34
34
|
let _handlers: Record<string, THSRouteHandler> = {};
|
|
@@ -78,19 +78,12 @@ export function createRoute(handler?: THSRouteHandler): THSRoute {
|
|
|
78
78
|
const streamingEnabled = !userIsBot && (streamOpt !== undefined ? streamOpt : true);
|
|
79
79
|
const routeKind = typeof routeContent;
|
|
80
80
|
|
|
81
|
-
// Render
|
|
82
|
-
if (
|
|
83
|
-
routeContent &&
|
|
84
|
-
routeKind === 'object' &&
|
|
85
|
-
(routeContent instanceof TmplHtml ||
|
|
86
|
-
routeContent.constructor.name === 'TmplHtml' ||
|
|
87
|
-
// @ts-ignore
|
|
88
|
-
routeContent?._kind === 'TmplHtml')
|
|
89
|
-
) {
|
|
81
|
+
// Render HSHtml if returned from route handler
|
|
82
|
+
if (isHSHtml(routeContent)) {
|
|
90
83
|
if (streamingEnabled) {
|
|
91
|
-
return new StreamResponse(renderStream(routeContent as
|
|
84
|
+
return new StreamResponse(renderStream(routeContent as HSHtml)) as Response;
|
|
92
85
|
} else {
|
|
93
|
-
const output = await renderAsync(routeContent as
|
|
86
|
+
const output = await renderAsync(routeContent as HSHtml);
|
|
94
87
|
return context.html(output);
|
|
95
88
|
}
|
|
96
89
|
}
|
package/dist/assets.d.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
// Generated by dts-bundle-generator v9.5.1
|
|
2
|
-
|
|
3
|
-
declare class TmplHtml {
|
|
4
|
-
_kind: string;
|
|
5
|
-
content: string;
|
|
6
|
-
asyncContent: Array<{
|
|
7
|
-
id: string;
|
|
8
|
-
promise: Promise<{
|
|
9
|
-
id: string;
|
|
10
|
-
value: unknown;
|
|
11
|
-
}>;
|
|
12
|
-
}>;
|
|
13
|
-
constructor(props: Pick<TmplHtml, "content" | "asyncContent">);
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Build client JS for end users (minimal JS for Hyperspan to work)
|
|
17
|
-
*/
|
|
18
|
-
export declare const clientJSFiles: Map<string, {
|
|
19
|
-
src: string;
|
|
20
|
-
type?: string;
|
|
21
|
-
}>;
|
|
22
|
-
export declare function buildClientJS(): Promise<void>;
|
|
23
|
-
/**
|
|
24
|
-
* Find client CSS file built for end users
|
|
25
|
-
* @TODO: Build this in code here vs. relying on tailwindcss CLI tool from package scripts
|
|
26
|
-
*/
|
|
27
|
-
export declare const clientCSSFiles: Map<string, string>;
|
|
28
|
-
export declare function buildClientCSS(): Promise<string | undefined>;
|
|
29
|
-
/**
|
|
30
|
-
* Output HTML style tag for Hyperspan app
|
|
31
|
-
*/
|
|
32
|
-
export declare function hyperspanStyleTags(): TmplHtml;
|
|
33
|
-
/**
|
|
34
|
-
* Output HTML script tag for Hyperspan app
|
|
35
|
-
* Required for functioning streaming so content can pop into place properly once ready
|
|
36
|
-
*/
|
|
37
|
-
export declare function hyperspanScriptTags(): TmplHtml;
|
|
38
|
-
/**
|
|
39
|
-
* Return a Preact component, mounted as an island in a <script> tag so it can be embedded into the page response.
|
|
40
|
-
*/
|
|
41
|
-
export declare function createPreactIsland(file: string): Promise<(props: any) => {
|
|
42
|
-
_kind: string;
|
|
43
|
-
content: string;
|
|
44
|
-
}>;
|
|
45
|
-
|
|
46
|
-
export {};
|
package/dist/server.d.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
// Generated by dts-bundle-generator v9.5.1
|
|
2
|
-
|
|
3
|
-
import { Context, Hono } from 'hono';
|
|
4
|
-
|
|
5
|
-
declare class TmplHtml {
|
|
6
|
-
_kind: string;
|
|
7
|
-
content: string;
|
|
8
|
-
asyncContent: Array<{
|
|
9
|
-
id: string;
|
|
10
|
-
promise: Promise<{
|
|
11
|
-
id: string;
|
|
12
|
-
value: unknown;
|
|
13
|
-
}>;
|
|
14
|
-
}>;
|
|
15
|
-
constructor(props: Pick<TmplHtml, "content" | "asyncContent">);
|
|
16
|
-
}
|
|
17
|
-
export declare const IS_PROD: boolean;
|
|
18
|
-
/**
|
|
19
|
-
* Types
|
|
20
|
-
*/
|
|
21
|
-
export type THSResponseTypes = TmplHtml | Response | string | null;
|
|
22
|
-
export type THSRouteHandler = (context: Context) => THSResponseTypes | Promise<THSResponseTypes>;
|
|
23
|
-
export type THSRoute = {
|
|
24
|
-
_kind: "hsRoute";
|
|
25
|
-
get: (handler: THSRouteHandler) => THSRoute;
|
|
26
|
-
post: (handler: THSRouteHandler) => THSRoute;
|
|
27
|
-
put: (handler: THSRouteHandler) => THSRoute;
|
|
28
|
-
delete: (handler: THSRouteHandler) => THSRoute;
|
|
29
|
-
patch: (handler: THSRouteHandler) => THSRoute;
|
|
30
|
-
run: (method: string, context: Context) => Promise<Response>;
|
|
31
|
-
};
|
|
32
|
-
/**
|
|
33
|
-
* Define a route that can handle a direct HTTP request.
|
|
34
|
-
* Route handlers should return a TmplHtml or Response object
|
|
35
|
-
*/
|
|
36
|
-
export declare function createRoute(handler?: THSRouteHandler): THSRoute;
|
|
37
|
-
/**
|
|
38
|
-
* Create new API Route
|
|
39
|
-
* API Route handlers should return a JSON object or a Response
|
|
40
|
-
*/
|
|
41
|
-
export declare function createAPIRoute(handler?: THSRouteHandler): THSRoute;
|
|
42
|
-
/**
|
|
43
|
-
* Get a Hyperspan runnable route from a module import
|
|
44
|
-
* @throws Error if no runnable route found
|
|
45
|
-
*/
|
|
46
|
-
export declare function getRunnableRoute(route: unknown): THSRoute;
|
|
47
|
-
export declare function isRunnableRoute(route: unknown): boolean;
|
|
48
|
-
export type THSServerConfig = {
|
|
49
|
-
appDir: string;
|
|
50
|
-
staticFileRoot: string;
|
|
51
|
-
rewrites?: Array<{
|
|
52
|
-
source: string;
|
|
53
|
-
destination: string;
|
|
54
|
-
}>;
|
|
55
|
-
beforeRoutesAdded?: (app: Hono) => void;
|
|
56
|
-
afterRoutesAdded?: (app: Hono) => void;
|
|
57
|
-
};
|
|
58
|
-
export type THSRouteMap = {
|
|
59
|
-
file: string;
|
|
60
|
-
route: string;
|
|
61
|
-
params: string[];
|
|
62
|
-
};
|
|
63
|
-
export declare function buildRoutes(config: THSServerConfig): Promise<THSRouteMap[]>;
|
|
64
|
-
/**
|
|
65
|
-
* Run route from file
|
|
66
|
-
*/
|
|
67
|
-
export declare function createRouteFromModule(RouteModule: any): (context: Context) => Promise<Response>;
|
|
68
|
-
/**
|
|
69
|
-
* Create and start Bun HTTP server
|
|
70
|
-
*/
|
|
71
|
-
export declare function createServer(config: THSServerConfig): Promise<Hono>;
|
|
72
|
-
/**
|
|
73
|
-
* Streaming HTML Response
|
|
74
|
-
*/
|
|
75
|
-
export declare class StreamResponse extends Response {
|
|
76
|
-
constructor(iterator: AsyncIterator<unknown>, options?: {});
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Does what it says on the tin...
|
|
80
|
-
*/
|
|
81
|
-
export declare function createReadableStreamFromAsyncGenerator(output: AsyncGenerator): ReadableStream<any>;
|
|
82
|
-
/**
|
|
83
|
-
* Normalize URL path
|
|
84
|
-
* Removes trailing slash and lowercases path
|
|
85
|
-
*/
|
|
86
|
-
export declare function normalizePath(urlPath: string): string;
|
|
87
|
-
|
|
88
|
-
export {};
|