@hyperspan/framework 0.1.2 → 0.1.4
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 +22 -20
- package/dist/assets.d.ts +1 -1
- package/dist/assets.js +3 -159
- package/dist/server.d.ts +33 -67
- package/dist/server.js +183 -562
- package/package.json +16 -8
- package/src/actions.test.ts +95 -0
- package/src/actions.ts +189 -0
- package/src/assets.ts +11 -10
- package/src/clientjs/hyperspan-client.ts +65 -4
- package/src/server.ts +192 -220
- package/dist/index.d.ts +0 -132
- package/dist/index.js +0 -2477
- package/src/index.ts +0 -1
package/build.ts
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
import {build} from 'bun';
|
|
2
2
|
import dts from 'bun-plugin-dts';
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const entrypoints = ['./src/server.ts', './src/assets.ts'];
|
|
5
|
+
const external = ['@hyperspan/html'];
|
|
5
6
|
const outdir = './dist';
|
|
6
7
|
const target = 'node';
|
|
8
|
+
const splitting = true;
|
|
7
9
|
|
|
8
|
-
await Promise.all(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
await Promise.all([
|
|
11
|
+
// Build JS
|
|
12
|
+
build({
|
|
13
|
+
entrypoints,
|
|
14
|
+
external,
|
|
15
|
+
outdir,
|
|
16
|
+
target,
|
|
17
|
+
splitting,
|
|
18
|
+
}),
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
]
|
|
26
|
-
)
|
|
27
|
-
);
|
|
20
|
+
// Build type files for TypeScript
|
|
21
|
+
build({
|
|
22
|
+
entrypoints,
|
|
23
|
+
external,
|
|
24
|
+
outdir,
|
|
25
|
+
target,
|
|
26
|
+
splitting,
|
|
27
|
+
plugins: [dts()],
|
|
28
|
+
}),
|
|
29
|
+
]);
|
package/dist/assets.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export declare const clientJSFiles: Map<string, {
|
|
|
19
19
|
src: string;
|
|
20
20
|
type?: string;
|
|
21
21
|
}>;
|
|
22
|
-
export declare function buildClientJS(): Promise<
|
|
22
|
+
export declare function buildClientJS(): Promise<void>;
|
|
23
23
|
/**
|
|
24
24
|
* Find client CSS file built for end users
|
|
25
25
|
* @TODO: Build this in code here vs. relying on tailwindcss CLI tool from package scripts
|
package/dist/assets.js
CHANGED
|
@@ -1,161 +1,5 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
* escape-html
|
|
4
|
-
* Copyright(c) 2012-2013 TJ Holowaychuk
|
|
5
|
-
* Copyright(c) 2015 Andreas Lubbe
|
|
6
|
-
* Copyright(c) 2015 Tiancheng "Timothy" Gu
|
|
7
|
-
* MIT Licensed
|
|
8
|
-
*/
|
|
9
|
-
var matchHtmlRegExp = /["'&<>]/;
|
|
10
|
-
function escapeHtml(string) {
|
|
11
|
-
const str = "" + string;
|
|
12
|
-
const match = matchHtmlRegExp.exec(str);
|
|
13
|
-
if (!match) {
|
|
14
|
-
return str;
|
|
15
|
-
}
|
|
16
|
-
let escape;
|
|
17
|
-
let html = "";
|
|
18
|
-
let index = 0;
|
|
19
|
-
let lastIndex = 0;
|
|
20
|
-
for (index = match.index;index < str.length; index++) {
|
|
21
|
-
switch (str.charCodeAt(index)) {
|
|
22
|
-
case 34:
|
|
23
|
-
escape = """;
|
|
24
|
-
break;
|
|
25
|
-
case 38:
|
|
26
|
-
escape = "&";
|
|
27
|
-
break;
|
|
28
|
-
case 39:
|
|
29
|
-
escape = "'";
|
|
30
|
-
break;
|
|
31
|
-
case 60:
|
|
32
|
-
escape = "<";
|
|
33
|
-
break;
|
|
34
|
-
case 62:
|
|
35
|
-
escape = ">";
|
|
36
|
-
break;
|
|
37
|
-
default:
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
if (lastIndex !== index) {
|
|
41
|
-
html += str.substring(lastIndex, index);
|
|
42
|
-
}
|
|
43
|
-
lastIndex = index + 1;
|
|
44
|
-
html += escape;
|
|
45
|
-
}
|
|
46
|
-
return lastIndex !== index ? html + str.substring(lastIndex, index) : html;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
class TmplHtml {
|
|
50
|
-
_kind = "hstmpl";
|
|
51
|
-
content = "";
|
|
52
|
-
asyncContent;
|
|
53
|
-
constructor(props) {
|
|
54
|
-
this.content = props.content;
|
|
55
|
-
this.asyncContent = props.asyncContent;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
var htmlId = 0;
|
|
59
|
-
function html(strings, ...values) {
|
|
60
|
-
const asyncContent = [];
|
|
61
|
-
let content = "";
|
|
62
|
-
for (let i = 0;i < strings.length; i++) {
|
|
63
|
-
const value = values[i];
|
|
64
|
-
const kind = _typeOf(value);
|
|
65
|
-
const renderValue = _renderValue(value, { kind, asyncContent }) || "";
|
|
66
|
-
content += strings[i] + (renderValue ? renderValue : "");
|
|
67
|
-
}
|
|
68
|
-
return new TmplHtml({ content, asyncContent });
|
|
69
|
-
}
|
|
70
|
-
html.raw = (content) => ({ _kind: "html_safe", content });
|
|
71
|
-
function _renderValue(value, opts = {
|
|
72
|
-
kind: undefined,
|
|
73
|
-
id: undefined,
|
|
74
|
-
asyncContent: []
|
|
75
|
-
}) {
|
|
76
|
-
if (value === null || value === undefined || Number.isNaN(value)) {
|
|
77
|
-
return "";
|
|
78
|
-
}
|
|
79
|
-
const kind = opts.kind || _typeOf(value);
|
|
80
|
-
let id = opts.id;
|
|
81
|
-
switch (kind) {
|
|
82
|
-
case "array":
|
|
83
|
-
return value.map((v) => _renderValue(v, { id, asyncContent: opts.asyncContent })).join("");
|
|
84
|
-
case "object":
|
|
85
|
-
id = `async_loading_${htmlId++}`;
|
|
86
|
-
if (value instanceof TmplHtml || value.constructor.name === "TmplHtml" || value?._kind === "hstmpl") {
|
|
87
|
-
opts.asyncContent.push(...value.asyncContent);
|
|
88
|
-
return value.content;
|
|
89
|
-
}
|
|
90
|
-
if (value?._kind === "html_safe") {
|
|
91
|
-
return value?.content || "";
|
|
92
|
-
}
|
|
93
|
-
if (typeof value.renderAsync === "function") {
|
|
94
|
-
opts.asyncContent.push({
|
|
95
|
-
id,
|
|
96
|
-
promise: value.renderAsync().then((result) => ({
|
|
97
|
-
id,
|
|
98
|
-
value: result,
|
|
99
|
-
asyncContent: opts.asyncContent
|
|
100
|
-
}))
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
if (typeof value.render === "function") {
|
|
104
|
-
return render(_htmlPlaceholder(id, value.render()));
|
|
105
|
-
}
|
|
106
|
-
return JSON.stringify(value);
|
|
107
|
-
case "promise":
|
|
108
|
-
id = `async_loading_${htmlId++}`;
|
|
109
|
-
opts.asyncContent.push({
|
|
110
|
-
id,
|
|
111
|
-
promise: value.then((result) => ({
|
|
112
|
-
id,
|
|
113
|
-
value: result,
|
|
114
|
-
asyncContent: opts.asyncContent
|
|
115
|
-
}))
|
|
116
|
-
});
|
|
117
|
-
return render(_htmlPlaceholder(id));
|
|
118
|
-
case "generator":
|
|
119
|
-
throw new Error("Generators are not supported as a template value at this time. Sorry :(");
|
|
120
|
-
default:
|
|
121
|
-
console.log("_renderValue kind =", kind, value);
|
|
122
|
-
}
|
|
123
|
-
return escapeHtml(String(value));
|
|
124
|
-
}
|
|
125
|
-
function _htmlPlaceholder(id, content = "Loading...") {
|
|
126
|
-
return html`<!--hs:loading:${id}--><slot id="${id}">${content}</slot><!--/hs:loading:${id}-->`;
|
|
127
|
-
}
|
|
128
|
-
function render(tmpl) {
|
|
129
|
-
return tmpl.content;
|
|
130
|
-
}
|
|
131
|
-
function _typeOf(obj) {
|
|
132
|
-
if (obj instanceof Promise)
|
|
133
|
-
return "promise";
|
|
134
|
-
if (obj instanceof Date)
|
|
135
|
-
return "date";
|
|
136
|
-
if (obj instanceof String)
|
|
137
|
-
return "string";
|
|
138
|
-
if (obj instanceof Number)
|
|
139
|
-
return "number";
|
|
140
|
-
if (obj instanceof Boolean)
|
|
141
|
-
return "boolean";
|
|
142
|
-
if (obj instanceof Function)
|
|
143
|
-
return "function";
|
|
144
|
-
if (Array.isArray(obj))
|
|
145
|
-
return "array";
|
|
146
|
-
if (Number.isNaN(obj))
|
|
147
|
-
return "NaN";
|
|
148
|
-
if (obj === undefined)
|
|
149
|
-
return "undefined";
|
|
150
|
-
if (obj === null)
|
|
151
|
-
return "null";
|
|
152
|
-
if (isGenerator(obj))
|
|
153
|
-
return "generator";
|
|
154
|
-
return typeof obj;
|
|
155
|
-
}
|
|
156
|
-
function isGenerator(obj) {
|
|
157
|
-
return obj && typeof obj.next == "function" && typeof obj.throw == "function";
|
|
158
|
-
}
|
|
1
|
+
// src/assets.ts
|
|
2
|
+
import { html } from "@hyperspan/html";
|
|
159
3
|
|
|
160
4
|
// src/clientjs/md5.js
|
|
161
5
|
function md5cycle(x, k) {
|
|
@@ -307,7 +151,6 @@ async function buildClientJS() {
|
|
|
307
151
|
});
|
|
308
152
|
const jsFile = output.outputs[0].path.split("/").reverse()[0];
|
|
309
153
|
clientJSFiles.set("_hs", { src: "/_hs/js/" + jsFile });
|
|
310
|
-
return jsFile;
|
|
311
154
|
}
|
|
312
155
|
var clientCSSFiles = new Map;
|
|
313
156
|
async function buildClientCSS() {
|
|
@@ -391,3 +234,4 @@ export {
|
|
|
391
234
|
buildClientJS,
|
|
392
235
|
buildClientCSS
|
|
393
236
|
};
|
|
237
|
+
|
package/dist/server.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Generated by dts-bundle-generator v9.5.1
|
|
2
2
|
|
|
3
|
-
import { Context,
|
|
3
|
+
import { Context, Hono } from 'hono';
|
|
4
4
|
|
|
5
5
|
declare class TmplHtml {
|
|
6
6
|
_kind: string;
|
|
@@ -15,84 +15,46 @@ declare class TmplHtml {
|
|
|
15
15
|
constructor(props: Pick<TmplHtml, "content" | "asyncContent">);
|
|
16
16
|
}
|
|
17
17
|
export declare const IS_PROD: boolean;
|
|
18
|
-
/**
|
|
19
|
-
* Route
|
|
20
|
-
* Define a route that can handle a direct HTTP request
|
|
21
|
-
* Route handlers should return a Response or TmplHtml object
|
|
22
|
-
*/
|
|
23
|
-
export declare function createRoute(handler: Handler): HSRoute;
|
|
24
|
-
/**
|
|
25
|
-
* Component
|
|
26
|
-
* Define a component or partial with an optional loading placeholder
|
|
27
|
-
* These can be rendered anywhere inside other templates - even if async.
|
|
28
|
-
*/
|
|
29
|
-
export declare function createComponent(render: () => THSComponentReturn | Promise<THSComponentReturn>): HSComponent;
|
|
30
|
-
/**
|
|
31
|
-
* Form + route handler
|
|
32
|
-
* Automatically handles and parses form data
|
|
33
|
-
*
|
|
34
|
-
* INITIAL IDEA OF HOW THIS WILL WORK:
|
|
35
|
-
* ---
|
|
36
|
-
* 1. Renders component as initial form markup for GET request
|
|
37
|
-
* 2. Bind form onSubmit function to custom client JS handling
|
|
38
|
-
* 3. Submits form with JavaScript fetch()
|
|
39
|
-
* 4. Replaces form content with content from server
|
|
40
|
-
* 5. All validation and save logic is on the server
|
|
41
|
-
* 6. Handles any Exception thrown on server as error displayed in client
|
|
42
|
-
*/
|
|
43
|
-
export declare function createForm(renderForm: (data?: any) => THSResponseTypes, schema?: z.ZodSchema | null): HSFormRoute;
|
|
44
18
|
/**
|
|
45
19
|
* Types
|
|
46
20
|
*/
|
|
47
|
-
export type THSComponentReturn = TmplHtml | string | number | null;
|
|
48
21
|
export type THSResponseTypes = TmplHtml | Response | string | null;
|
|
49
|
-
export
|
|
50
|
-
/**
|
|
51
|
-
* Route handler helper
|
|
52
|
-
*/
|
|
53
|
-
export declare class HSComponent {
|
|
54
|
-
_kind: string;
|
|
55
|
-
_handlers: Record<string, Handler>;
|
|
56
|
-
_loading?: () => TmplHtml;
|
|
57
|
-
render: () => THSComponentReturn | Promise<THSComponentReturn>;
|
|
58
|
-
constructor(render: () => THSComponentReturn | Promise<THSComponentReturn>);
|
|
59
|
-
loading(fn: () => TmplHtml): this;
|
|
60
|
-
}
|
|
22
|
+
export type THSRouteHandler = (context: Context) => THSResponseTypes | Promise<THSResponseTypes>;
|
|
61
23
|
/**
|
|
62
|
-
* Route
|
|
24
|
+
* Route
|
|
25
|
+
* Define a route that can handle a direct HTTP request
|
|
26
|
+
* Route handlers should return a Response or TmplHtml object
|
|
63
27
|
*/
|
|
64
|
-
export declare
|
|
28
|
+
export declare function createRoute(handler?: THSRouteHandler): {
|
|
65
29
|
_kind: string;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
30
|
+
get(handler: THSRouteHandler): any;
|
|
31
|
+
post(handler: THSRouteHandler): any;
|
|
32
|
+
put(handler: THSRouteHandler): any;
|
|
33
|
+
delete(handler: THSRouteHandler): any;
|
|
34
|
+
patch(handler: THSRouteHandler): any;
|
|
35
|
+
run(method: string, context: Context): Promise<Response>;
|
|
36
|
+
};
|
|
37
|
+
export type THSRoute = ReturnType<typeof createRoute>;
|
|
70
38
|
/**
|
|
71
|
-
*
|
|
39
|
+
* Create new API Route
|
|
40
|
+
* API Route handlers should return a JSON object or a Response
|
|
72
41
|
*/
|
|
73
|
-
export
|
|
74
|
-
export declare class HSFormRoute {
|
|
42
|
+
export declare function createAPIRoute(handler?: THSRouteHandler): {
|
|
75
43
|
_kind: string;
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
*/
|
|
85
|
-
renderForm(data?: any): THSResponseTypes;
|
|
86
|
-
get(handler: Handler): this;
|
|
87
|
-
patch(handler: Handler): this;
|
|
88
|
-
post(handler: Handler): this;
|
|
89
|
-
put(handler: Handler): this;
|
|
90
|
-
delete(handler: Handler): this;
|
|
91
|
-
}
|
|
44
|
+
get(handler: THSRouteHandler): any;
|
|
45
|
+
post(handler: THSRouteHandler): any;
|
|
46
|
+
put(handler: THSRouteHandler): any;
|
|
47
|
+
delete(handler: THSRouteHandler): any;
|
|
48
|
+
patch(handler: THSRouteHandler): any;
|
|
49
|
+
run(method: string, context: Context): Promise<Response>;
|
|
50
|
+
};
|
|
51
|
+
export type THSAPIRoute = ReturnType<typeof createAPIRoute>;
|
|
92
52
|
/**
|
|
93
|
-
*
|
|
53
|
+
* Get a Hyperspan runnable route from a module import
|
|
54
|
+
* @throws Error if no runnable route found
|
|
94
55
|
*/
|
|
95
|
-
export declare function
|
|
56
|
+
export declare function getRunnableRoute(route: unknown): THSRoute;
|
|
57
|
+
export declare function isRouteRunnable(route: unknown): boolean;
|
|
96
58
|
export type THSServerConfig = {
|
|
97
59
|
appDir: string;
|
|
98
60
|
staticFileRoot: string;
|
|
@@ -109,6 +71,10 @@ export type THSRouteMap = {
|
|
|
109
71
|
params: string[];
|
|
110
72
|
};
|
|
111
73
|
export declare function buildRoutes(config: THSServerConfig): Promise<THSRouteMap[]>;
|
|
74
|
+
/**
|
|
75
|
+
* Run route from file
|
|
76
|
+
*/
|
|
77
|
+
export declare function createRouteFromModule(RouteModule: any): (context: Context) => Promise<Response>;
|
|
112
78
|
/**
|
|
113
79
|
* Create and start Bun HTTP server
|
|
114
80
|
*/
|