@primate/htmx 0.4.0 → 0.5.0
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 +0 -2
- package/eslint.config.js +1 -0
- package/exports.js +1 -1
- package/package.json +6 -12
- package/src/module.js +61 -0
- package/src/handler.js +0 -82
- package/src/index.html +0 -8
package/LICENSE
CHANGED
package/eslint.config.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {default} from "maximin";
|
package/exports.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {default
|
|
1
|
+
export {default} from "./src/module.js";
|
package/package.json
CHANGED
|
@@ -1,23 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primate/htmx",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"author": "Terrablue <terrablue@proton.me>",
|
|
5
|
-
"homepage": "https://primatejs.com/modules/htmx",
|
|
6
|
-
"bugs": "https://github.com/primatejs/primate-htmx/issues",
|
|
7
|
-
"repository": "https://github.com/primatejs/primate-htmx",
|
|
3
|
+
"version": "0.5.0",
|
|
8
4
|
"description": "Primate HTMX module",
|
|
5
|
+
"homepage": "https://primatejs.com/modules/htmx",
|
|
6
|
+
"bugs": "https://github.com/primatejs/htmx/issues",
|
|
9
7
|
"license": "MIT",
|
|
8
|
+
"repository": "https://github.com/primatejs/htmx",
|
|
10
9
|
"dependencies": {
|
|
11
|
-
"htmt": "^0.1.0",
|
|
12
10
|
"htmx.org": "^1.8.6",
|
|
13
|
-
"runtime-compat": "^0.
|
|
11
|
+
"runtime-compat": "^0.14.1"
|
|
14
12
|
},
|
|
15
13
|
"devDependencies": {
|
|
16
|
-
"
|
|
17
|
-
"@babel/eslint-parser": "^7.19.1",
|
|
18
|
-
"@babel/plugin-syntax-import-assertions": "^7.20.0",
|
|
19
|
-
"eslint": "^8.36.0",
|
|
20
|
-
"eslint-plugin-json": "^3.1.0"
|
|
14
|
+
"maximin": "^0.1.2"
|
|
21
15
|
},
|
|
22
16
|
"type": "module",
|
|
23
17
|
"exports": "./exports.js",
|
package/src/module.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import {Path} from "runtime-compat/filesystem";
|
|
2
|
+
import crypto from "runtime-compat/crypto";
|
|
3
|
+
|
|
4
|
+
const fileName = "htmx.min.js";
|
|
5
|
+
const scriptPath = ["node_modules", "htmx.org", "dist", fileName];
|
|
6
|
+
|
|
7
|
+
const hash = async (string, algorithm = "sha-384") => {
|
|
8
|
+
const buffer = new ArrayBuffer(string.length);
|
|
9
|
+
const view = new Uint8Array(buffer);
|
|
10
|
+
for (let i = 0; i < string.length; i++) {
|
|
11
|
+
view[i] = string.charCodeAt(i);
|
|
12
|
+
}
|
|
13
|
+
const bytes = await crypto.subtle.digest(algorithm, buffer);
|
|
14
|
+
return btoa(String.fromCharCode(...new Uint8Array(bytes)));
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const getContent = async (env, name) => {
|
|
18
|
+
try {
|
|
19
|
+
return await env.paths.components.join(`${name}.html`).file.read();
|
|
20
|
+
} catch (error) {
|
|
21
|
+
throw new Error(`cannot load component at ${name}.html`);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const handler = (content, {status = 200, partial = false, adhoc = false} = {}) =>
|
|
26
|
+
async (env, headers) => {
|
|
27
|
+
const src = `/${fileName}`;
|
|
28
|
+
const htmx = env.paths.public.join(fileName);
|
|
29
|
+
const integrity = `sha384-${await hash(await htmx.file.read())}`;
|
|
30
|
+
const head = `<script src="${src}" integrity="${integrity}"></script>`;
|
|
31
|
+
const body = adhoc ? content : await getContent(env, content);
|
|
32
|
+
const scriptSrc = `script-src 'self' '${integrity}';`;
|
|
33
|
+
const styleSrc = "style-src 'unsafe-inline';";
|
|
34
|
+
const csp = `${headers["Content-Security-Policy"]}${scriptSrc}${styleSrc}`;
|
|
35
|
+
const options = {
|
|
36
|
+
status,
|
|
37
|
+
headers: {
|
|
38
|
+
...headers,
|
|
39
|
+
"Content-Type": "text/html",
|
|
40
|
+
"Content-Security-Policy": csp,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return [partial ? body : await env.render({head, body}), options];
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default () => () => {
|
|
48
|
+
return {
|
|
49
|
+
register: async (env, next) => {
|
|
50
|
+
env.register("htmx", handler);
|
|
51
|
+
return next(env);
|
|
52
|
+
},
|
|
53
|
+
bundle: async (env, next) => {
|
|
54
|
+
const htmx = env.paths.public.join(fileName);
|
|
55
|
+
if (!await htmx.exists) {
|
|
56
|
+
await Path.resolve().join(...scriptPath).file.copy(`${htmx}`);
|
|
57
|
+
}
|
|
58
|
+
return next(env);
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
};
|
package/src/handler.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import {Path, File} from "runtime-compat/filesystem";
|
|
2
|
-
import crypto from "runtime-compat/crypto";
|
|
3
|
-
import {fulfill, flatten} from "htmt";
|
|
4
|
-
|
|
5
|
-
const last = -1;
|
|
6
|
-
|
|
7
|
-
const index_html = "index.html";
|
|
8
|
-
const preset = await new Path(import.meta.url).directory.join(index_html).file
|
|
9
|
-
.read();
|
|
10
|
-
|
|
11
|
-
const getIndex = async env => {
|
|
12
|
-
try {
|
|
13
|
-
return await File.read(`${env.paths.static.join(index_html)}`);
|
|
14
|
-
} catch (error) {
|
|
15
|
-
return preset;
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const fileName = "htmx.min.js";
|
|
20
|
-
const scriptPath = ["node_modules", "htmx.org", "dist", fileName];
|
|
21
|
-
|
|
22
|
-
const hash = async (string, algorithm = "sha-384") => {
|
|
23
|
-
const buffer = new ArrayBuffer(string.length);
|
|
24
|
-
const view = new Uint8Array(buffer);
|
|
25
|
-
for (let i = 0; i < string.length; i++) {
|
|
26
|
-
view[i] = string.charCodeAt(i);
|
|
27
|
-
}
|
|
28
|
-
const bytes = await crypto.subtle.digest(algorithm, buffer);
|
|
29
|
-
return btoa(String.fromCharCode(...new Uint8Array(bytes)));
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const render = async (strings, keys, path) => {
|
|
33
|
-
const loadFile = async file => [file.base, (await file.read())
|
|
34
|
-
.replaceAll("\n", "")];
|
|
35
|
-
const components = await path.exists
|
|
36
|
-
? Object.fromEntries(await Promise.all((
|
|
37
|
-
await File.collect(`${path}`, ".html")).map(loadFile)))
|
|
38
|
-
: {};
|
|
39
|
-
const re = strings
|
|
40
|
-
.slice(0, last)
|
|
41
|
-
.map((string, i) => `${string}\${${i}}`)
|
|
42
|
-
.join("") + strings[strings.length + last];
|
|
43
|
-
return flatten(await fulfill(re, components, await Promise.all(keys)));
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export const partial = (strings, ...keys) => async (env, headers) =>
|
|
47
|
-
// -> spread into new Response()
|
|
48
|
-
[await render(strings, keys, env.paths.components), {status: 200, headers}];
|
|
49
|
-
|
|
50
|
-
export default (strings, ...keys) => async (env, headers) => {
|
|
51
|
-
// if doesn't exist, copy htmx file to public
|
|
52
|
-
// if public doesn't exist, create it
|
|
53
|
-
const _public = env.paths.public;
|
|
54
|
-
if (!await _public.exists) {
|
|
55
|
-
await _public.file.create();
|
|
56
|
-
}
|
|
57
|
-
const htmx = _public.join(fileName);
|
|
58
|
-
if (!await htmx.exists) {
|
|
59
|
-
await Path.resolve().join(...scriptPath).file.copy(`${htmx}`);
|
|
60
|
-
}
|
|
61
|
-
const src = `/${fileName}`;
|
|
62
|
-
const integrity = `sha384-${await hash(await htmx.file.read())}`;
|
|
63
|
-
const script = `<script src="${src}" integrity="${integrity}"></script>`;
|
|
64
|
-
const index = (await getIndex(env)).replace("</head>", `${script}</head>`);
|
|
65
|
-
const html = await render(strings, keys, env.paths.components);
|
|
66
|
-
const body = index.replace("<body>", () => `<body>${html}`);
|
|
67
|
-
|
|
68
|
-
const script_src = `script-src 'self' '${integrity}';`;
|
|
69
|
-
const style_src = "style-src 'unsafe-inline';";
|
|
70
|
-
const csp = `${headers["Content-Security-Policy"]}${script_src}${style_src}`;
|
|
71
|
-
const options = {
|
|
72
|
-
status: 200,
|
|
73
|
-
headers: {
|
|
74
|
-
...headers,
|
|
75
|
-
"Content-Type": "text/html",
|
|
76
|
-
"Content-Security-Policy": csp,
|
|
77
|
-
},
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
// -> spread into new Response()
|
|
81
|
-
return [body, options];
|
|
82
|
-
};
|