htmx-router 0.2.0 → 1.0.0-alpha.1

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.
Files changed (55) hide show
  1. package/bin/cli/config.d.ts +10 -0
  2. package/bin/cli/config.js +4 -0
  3. package/bin/cli/index.js +54 -10
  4. package/bin/client/index.d.ts +4 -0
  5. package/bin/client/index.js +100 -0
  6. package/bin/client/mount.d.ts +2 -0
  7. package/bin/client/mount.js +74 -0
  8. package/bin/client/watch.d.ts +1 -0
  9. package/bin/client/watch.js +19 -0
  10. package/bin/helper.d.ts +1 -2
  11. package/bin/helper.js +25 -14
  12. package/bin/index.d.ts +8 -6
  13. package/bin/index.js +7 -16
  14. package/bin/request/http.d.ts +10 -0
  15. package/bin/request/http.js +46 -0
  16. package/bin/request/index.d.ts +16 -0
  17. package/bin/request/index.js +6 -0
  18. package/bin/request/native.d.ts +9 -0
  19. package/bin/request/native.js +56 -0
  20. package/bin/router.d.ts +41 -16
  21. package/bin/router.js +176 -236
  22. package/bin/types.d.ts +10 -0
  23. package/bin/types.js +1 -0
  24. package/bin/util/cookies.d.ts +22 -0
  25. package/bin/util/cookies.js +57 -0
  26. package/bin/util/css.d.ts +9 -0
  27. package/bin/util/css.js +47 -0
  28. package/bin/util/dynamic.d.ts +5 -0
  29. package/bin/util/dynamic.js +26 -0
  30. package/bin/util/endpoint.d.ts +9 -0
  31. package/bin/util/endpoint.js +28 -0
  32. package/bin/util/event-source.d.ts +16 -0
  33. package/bin/util/event-source.js +85 -0
  34. package/bin/util/hash.d.ts +1 -0
  35. package/bin/util/hash.js +7 -0
  36. package/bin/util/index.d.ts +1 -0
  37. package/bin/util/index.js +7 -0
  38. package/bin/util/parameters.d.ts +7 -0
  39. package/bin/util/parameters.js +14 -0
  40. package/bin/util/shell.d.ts +32 -0
  41. package/bin/util/shell.js +1 -0
  42. package/package.json +9 -7
  43. package/readme.md +149 -213
  44. package/bin/404-route.d.ts +0 -2
  45. package/bin/404-route.js +0 -8
  46. package/bin/cli/dynamic.d.ts +0 -2
  47. package/bin/cli/dynamic.js +0 -47
  48. package/bin/cli/static.d.ts +0 -2
  49. package/bin/cli/static.js +0 -49
  50. package/bin/components.d.ts +0 -8
  51. package/bin/components.js +0 -11
  52. package/bin/render-args.d.ts +0 -35
  53. package/bin/render-args.js +0 -120
  54. package/bin/shared.d.ts +0 -28
  55. package/bin/shared.js +0 -28
@@ -0,0 +1,28 @@
1
+ import { QuickHash } from "../util/hash.js";
2
+ const registry = new Map();
3
+ export class Endpoint {
4
+ render;
5
+ name;
6
+ url;
7
+ constructor(render, name) {
8
+ this.render = render;
9
+ name ||= render.constructor.name;
10
+ const hash = QuickHash(String(render));
11
+ this.name = name ? `${encodeURIComponent(name)}-${hash}` : hash;
12
+ this.url = `/_/endpoint/${this.name}`;
13
+ registry.set(this.name, this);
14
+ }
15
+ }
16
+ export async function _resolve(fragments, ctx) {
17
+ if (!fragments[2])
18
+ return null;
19
+ const endpoint = registry.get(fragments[2]);
20
+ if (!endpoint)
21
+ return null;
22
+ const res = await endpoint.render(ctx);
23
+ if (res === null)
24
+ return null;
25
+ if (res instanceof Response)
26
+ return res;
27
+ return ctx.render(res);
28
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Create a new SSE handler
3
+ * Includes auto keep-alive, and graceful shutdown
4
+ */
5
+ export declare class EventSourceConnection {
6
+ private controller;
7
+ private stream;
8
+ private timer;
9
+ readonly createdAt: number;
10
+ constructor(request: Request, keepAlive?: number);
11
+ response(): Response;
12
+ private keepAlive;
13
+ send(type: string, data: string, timeStamp: number): boolean;
14
+ isClosed(): boolean;
15
+ close(unlink?: boolean): boolean;
16
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Create a new SSE handler
3
+ * Includes auto keep-alive, and graceful shutdown
4
+ */
5
+ export class EventSourceConnection {
6
+ controller;
7
+ stream;
8
+ timer;
9
+ createdAt; // unix time
10
+ constructor(request, keepAlive = 30_000) {
11
+ this.createdAt = Date.now();
12
+ this.controller = null;
13
+ this.stream = new ReadableStream({
14
+ start: (c) => { this.controller = c; },
15
+ cancel: () => { this.close(); }
16
+ });
17
+ request.signal.addEventListener('abort', () => this.close());
18
+ this.timer = setInterval(() => this.keepAlive(), keepAlive);
19
+ register.push(this);
20
+ }
21
+ response() {
22
+ const headers = new Headers();
23
+ headers.set("Content-Type", "text/event-stream");
24
+ headers.set("Transfer-Encoding", "chunked");
25
+ headers.set("Connection", "keep-alive");
26
+ headers.set("Keep-Alive", `timeout=120`);
27
+ return new Response(this.stream, { headers });
28
+ }
29
+ keepAlive() {
30
+ if (!this.controller)
31
+ return;
32
+ try {
33
+ this.controller.enqueue("\n\n");
34
+ }
35
+ catch (e) {
36
+ console.error(e);
37
+ this.close(); // unbind on failure
38
+ }
39
+ }
40
+ send(type, data, timeStamp) {
41
+ if (!this.controller)
42
+ return false;
43
+ try {
44
+ this.controller.enqueue(`event: ${type}\ndata: [${data},${timeStamp}]\n\n`);
45
+ return true;
46
+ }
47
+ catch (e) {
48
+ console.error(e);
49
+ this.close(); // unbind on failure
50
+ return false;
51
+ }
52
+ }
53
+ isClosed() {
54
+ return this.controller === null;
55
+ }
56
+ close(unlink = true) {
57
+ clearInterval(this.timer);
58
+ if (!this.controller)
59
+ return false;
60
+ if (unlink) {
61
+ const i = register.indexOf(this);
62
+ if (i !== -1)
63
+ register.splice(i, 1);
64
+ }
65
+ try {
66
+ this.controller?.close();
67
+ }
68
+ catch (e) {
69
+ console.error(e);
70
+ this.controller = null;
71
+ return false;
72
+ }
73
+ this.controller = null;
74
+ return true;
75
+ }
76
+ }
77
+ // Auto close all SSE streams when shutdown requested
78
+ // Without this graceful shutdowns will hang indefinitely
79
+ const register = new Array();
80
+ function CloseAll() {
81
+ for (const connection of register)
82
+ connection.close(false); // don't waste time unregistering
83
+ }
84
+ process.on('SIGTERM', CloseAll);
85
+ process.on('SIGHUP', CloseAll);
@@ -0,0 +1 @@
1
+ export declare function QuickHash(input: string): string;
@@ -0,0 +1,7 @@
1
+ export function QuickHash(input) {
2
+ let hash = 0;
3
+ for (let i = 0; i < input.length; i++) {
4
+ hash = (hash * 31 + input.charCodeAt(i)) >>> 0;
5
+ }
6
+ return hash.toString(36).slice(0, 5);
7
+ }
@@ -0,0 +1 @@
1
+ export declare function MergeHeaders(base: Headers, extension: Headers, override: boolean): void;
@@ -0,0 +1,7 @@
1
+ export function MergeHeaders(base, extension, override) {
2
+ extension.forEach((val, key) => {
3
+ if (!override && base.has(key))
4
+ return;
5
+ base.set(key, val);
6
+ });
7
+ }
@@ -0,0 +1,7 @@
1
+ export type Parameterized<T extends ParameterShaper> = {
2
+ [K in keyof T]: ReturnType<T[K]>;
3
+ };
4
+ export type ParameterShaper = Record<string, (val: string) => any>;
5
+ export declare function Parameterize<T extends ParameterShaper>(params: {
6
+ [key: string]: string;
7
+ }, shape: T): Parameterized<T>;
@@ -0,0 +1,14 @@
1
+ export function Parameterize(params, shape) {
2
+ const out = {};
3
+ for (const key in shape) {
4
+ if (!(key in params))
5
+ console.warn(`Parameter ${key} not present in route, but defined in parameters`);
6
+ const func = shape[key];
7
+ const val = func(params[key] || "");
8
+ // NaN moment
9
+ if (func === Number && typeof val === "number" && isNaN(val))
10
+ throw new Error("Invalid Number");
11
+ out[key] = val;
12
+ }
13
+ return out;
14
+ }
@@ -0,0 +1,32 @@
1
+ export type MetaDescriptor = {
2
+ charSet: "utf-8";
3
+ } | {
4
+ title: string;
5
+ } | {
6
+ name: string;
7
+ content: string;
8
+ } | {
9
+ property: string;
10
+ content: string;
11
+ } | {
12
+ httpEquiv: string;
13
+ content: string;
14
+ } | {
15
+ "script:ld+json": LdJsonObject;
16
+ } | {
17
+ tagName: "meta" | "link";
18
+ [name: string]: string;
19
+ } | {
20
+ [name: string]: unknown;
21
+ };
22
+ type LdJsonObject = {
23
+ [Key in string]?: LdJsonValue | undefined;
24
+ };
25
+ type LdJsonArray = LdJsonValue[] | readonly LdJsonValue[];
26
+ type LdJsonPrimitive = string | number | boolean | null;
27
+ type LdJsonValue = LdJsonPrimitive | LdJsonObject | LdJsonArray;
28
+ export type ShellOptions = {
29
+ meta?: Array<MetaDescriptor>;
30
+ } | undefined;
31
+ export type ShellProps<T> = T & ShellOptions;
32
+ export {};
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "htmx-router",
3
- "version": "0.2.0",
4
- "description": "A remix.js style file path router for htmX websites",
3
+ "version": "1.0.0-alpha.1",
4
+ "description": "A simple SSR framework with dynamic+client islands",
5
5
  "main": "./bin/index.js",
6
+ "type": "module",
6
7
  "scripts": {
7
- "build": "tsc"
8
+ "build": "tsc && tsc-alias"
8
9
  },
9
10
  "bin": {
10
11
  "htmx-router": "bin/cli/index.js"
@@ -19,13 +20,14 @@
19
20
  "url": "https://github.com/AjaniBilby/htmx-router/issues"
20
21
  },
21
22
  "homepage": "https://github.com/AjaniBilby/htmx-router#readme",
23
+ "dependencies": {
24
+ "es-module-lexer": "^1.5.4",
25
+ "vite": "^6.0.1"
26
+ },
22
27
  "devDependencies": {
23
28
  "@types/node": "^20.4.5",
24
29
  "ts-node": "^10.9.1",
30
+ "tsc-alias": "^1.8.10",
25
31
  "typescript": "^5.1.6"
26
- },
27
- "dependencies": {
28
- "@kitajs/html": "^1.4.2",
29
- "csstype": "^3.1.2"
30
32
  }
31
33
  }