htmx-router 0.0.5 → 0.0.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.
@@ -0,0 +1,2 @@
1
+ import { RenderArgs } from "./render-args";
2
+ export declare function Render(rn: string, { req }: RenderArgs): Promise<string>;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Render = void 0;
4
+ const shared_1 = require("./shared");
5
+ async function Render(rn, { req }) {
6
+ throw new shared_1.ErrorResponse(404, "Resource Not Found", req.url || "/");
7
+ }
8
+ exports.Render = Render;
@@ -39,7 +39,7 @@ function readDirRecursively(dir: string) {
39
39
  script += "\tconst ext = extname(file);\n";
40
40
  script += "\tif (!IsAllowedExt(ext)) continue;\n";
41
41
  script += "\tconst url = relative(ctx, file.slice(0, file.lastIndexOf(\".\")).replace(/\\\\/g, \"/\"));\n";
42
- script += `\timport(file).then((mod) => Router.ingest(url, mod, []));\n`;
42
+ script += `\timport(file).then((mod) => Router.ingest(url, mod, [false]));\n`;
43
43
  script += "}\n";
44
44
  (0, fs_1.writeFileSync)(`${cwd}/router.ts`, script);
45
45
  console.log(`Finished Building`);
package/bin/cli/static.js CHANGED
@@ -40,7 +40,7 @@ function BuildStatic(cwd) {
40
40
  script += `\nexport const Router = new RouteTree();\n`;
41
41
  for (let i = 0; i < files.length; i++) {
42
42
  const file = files[i];
43
- script += `Router.ingest("${file.slice(DIR.length - 1)}", Route${i}, []);\n`;
43
+ script += `Router.ingest("${file.slice(DIR.length - 1)}", Route${i}, [false]);\n`;
44
44
  }
45
45
  script += `Router.assignRoot(RootRoute);\n`;
46
46
  (0, fs_1.writeFileSync)(`${cwd}/router.ts`, script);
@@ -0,0 +1,5 @@
1
+ export declare function Link(props: {
2
+ to: string;
3
+ target?: string;
4
+ style?: string;
5
+ }, contents: string[]): string;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.Link = void 0;
27
+ const elements = __importStar(require("typed-html"));
28
+ function Link(props, contents) {
29
+ return elements.createElement("a", { target: props.target || "", style: props.style || "", href: props.to, "hx-get": props.to, "hx-headers": '{"hx-headless": "true"}' }, contents);
30
+ }
31
+ exports.Link = Link;
package/bin/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
+ import { ErrorResponse, Redirect, Outlet, Override } from "./shared";
1
2
  import { RouteTree, IsAllowedExt } from "./router";
2
- import { ErrorResponse, Redirect, Outlet, Override, RenderArgs } from "./shared";
3
+ import { RenderArgs } from "./render-args";
4
+ import { Link } from "./components";
3
5
  import { StyleCSS } from "./helper";
4
- export { IsAllowedExt, RouteTree, ErrorResponse, Redirect, Override, RenderArgs, Outlet, StyleCSS };
6
+ export { IsAllowedExt, RouteTree, ErrorResponse, Redirect, Override, RenderArgs, Outlet, StyleCSS, Link };
package/bin/index.js CHANGED
@@ -1,13 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.StyleCSS = exports.RenderArgs = exports.Override = exports.Redirect = exports.ErrorResponse = exports.RouteTree = exports.IsAllowedExt = void 0;
4
- const router_1 = require("./router");
5
- Object.defineProperty(exports, "RouteTree", { enumerable: true, get: function () { return router_1.RouteTree; } });
6
- Object.defineProperty(exports, "IsAllowedExt", { enumerable: true, get: function () { return router_1.IsAllowedExt; } });
3
+ exports.Link = exports.StyleCSS = exports.RenderArgs = exports.Override = exports.Redirect = exports.ErrorResponse = exports.RouteTree = exports.IsAllowedExt = void 0;
7
4
  const shared_1 = require("./shared");
8
5
  Object.defineProperty(exports, "ErrorResponse", { enumerable: true, get: function () { return shared_1.ErrorResponse; } });
9
6
  Object.defineProperty(exports, "Redirect", { enumerable: true, get: function () { return shared_1.Redirect; } });
10
7
  Object.defineProperty(exports, "Override", { enumerable: true, get: function () { return shared_1.Override; } });
11
- Object.defineProperty(exports, "RenderArgs", { enumerable: true, get: function () { return shared_1.RenderArgs; } });
8
+ const router_1 = require("./router");
9
+ Object.defineProperty(exports, "RouteTree", { enumerable: true, get: function () { return router_1.RouteTree; } });
10
+ Object.defineProperty(exports, "IsAllowedExt", { enumerable: true, get: function () { return router_1.IsAllowedExt; } });
11
+ const render_args_1 = require("./render-args");
12
+ Object.defineProperty(exports, "RenderArgs", { enumerable: true, get: function () { return render_args_1.RenderArgs; } });
13
+ const components_1 = require("./components");
14
+ Object.defineProperty(exports, "Link", { enumerable: true, get: function () { return components_1.Link; } });
12
15
  const helper_1 = require("./helper");
13
16
  Object.defineProperty(exports, "StyleCSS", { enumerable: true, get: function () { return helper_1.StyleCSS; } });
@@ -0,0 +1,33 @@
1
+ /// <reference types="node" />
2
+ import type http from "node:http";
3
+ import { RouteLeaf } from "./router";
4
+ type MetaHTML = {
5
+ [key: string]: string;
6
+ };
7
+ export declare enum MaskType {
8
+ show = 0,
9
+ headless = 1,
10
+ hide = 2
11
+ }
12
+ export declare class RenderArgs {
13
+ req: http.IncomingMessage;
14
+ res: http.ServerResponse;
15
+ params: MetaHTML;
16
+ url: URL;
17
+ shared: {
18
+ [key: string]: any;
19
+ };
20
+ links: MetaHTML[];
21
+ meta: MetaHTML[];
22
+ _outletChain: RouteLeaf[];
23
+ _maskChain: MaskType[];
24
+ _maxChain: number;
25
+ constructor(req: http.IncomingMessage, res: http.ServerResponse, url: URL);
26
+ addLinks: (links: MetaHTML[], override?: boolean) => void;
27
+ addMeta: (links: MetaHTML[], override?: boolean) => void;
28
+ Outlet: () => Promise<string>;
29
+ _addOutlet(route: RouteLeaf): void;
30
+ _applyMask(mask: boolean[], depth: number): void;
31
+ renderHeadHTML: () => string;
32
+ }
33
+ export {};
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RenderArgs = exports.MaskType = void 0;
4
+ const attrRegex = /^[A-z][A-z\-0-9]+$/;
5
+ function ValidateMetaHTML(val) {
6
+ for (const key in val) {
7
+ if (!attrRegex.test(key))
8
+ return false;
9
+ }
10
+ return true;
11
+ }
12
+ function ValidateMetaHTMLs(val) {
13
+ for (const meta of val) {
14
+ if (!ValidateMetaHTML(meta))
15
+ return false;
16
+ }
17
+ return true;
18
+ }
19
+ var MaskType;
20
+ (function (MaskType) {
21
+ MaskType[MaskType["show"] = 0] = "show";
22
+ MaskType[MaskType["headless"] = 1] = "headless";
23
+ MaskType[MaskType["hide"] = 2] = "hide";
24
+ })(MaskType || (exports.MaskType = MaskType = {}));
25
+ class RenderArgs {
26
+ constructor(req, res, url) {
27
+ this.addLinks = (links, override = false) => {
28
+ if (!ValidateMetaHTMLs(links))
29
+ throw new Error(`Provided links have invalid attribute`);
30
+ if (override) {
31
+ this.links = links;
32
+ }
33
+ else {
34
+ this.links.push(...links);
35
+ }
36
+ };
37
+ this.addMeta = (links, override = false) => {
38
+ if (!ValidateMetaHTMLs(links))
39
+ throw new Error(`Provided links have invalid attribute`);
40
+ if (override) {
41
+ this.meta = links;
42
+ }
43
+ else {
44
+ this.meta.push(...links);
45
+ }
46
+ };
47
+ // unpacking Outlet caused this to be undefined
48
+ // hence the weird def
49
+ this.Outlet = () => {
50
+ const depth = this._maxChain - this._outletChain.length;
51
+ const route = this._outletChain.pop();
52
+ let mask = this._maskChain.pop();
53
+ if (mask === undefined) {
54
+ mask = MaskType.show;
55
+ }
56
+ if (!route)
57
+ return new Promise((res) => res(""));
58
+ const routeName = `hx-route-${depth.toString(16)}`;
59
+ return route.render(this, mask, routeName);
60
+ };
61
+ this.renderHeadHTML = () => {
62
+ let out = "";
63
+ for (const elm of this.links) {
64
+ out += "<link";
65
+ for (const attr in elm) {
66
+ out += ` ${attr}="${elm[attr].replace(/"/g, "\\\"")}"`;
67
+ }
68
+ out += "></link>";
69
+ }
70
+ for (const elm of this.meta) {
71
+ out += "<meta";
72
+ for (const attr in elm) {
73
+ out += ` ${attr}="${elm[attr].replace(/"/g, "\\\"")}"`;
74
+ }
75
+ out += "></meta>";
76
+ }
77
+ return out;
78
+ };
79
+ this.req = req;
80
+ this.res = res;
81
+ this.url = url;
82
+ this.params = {};
83
+ this.shared = {};
84
+ this.links = [];
85
+ this.meta = [];
86
+ this._outletChain = [];
87
+ this._maskChain = [];
88
+ this._maxChain = 0;
89
+ }
90
+ _addOutlet(route) {
91
+ this._outletChain.push(route);
92
+ }
93
+ _applyMask(mask, depth) {
94
+ const padded = new Array(this._outletChain.length - mask.length).fill(false);
95
+ for (let i = mask.length - 1; i >= 0; i--) {
96
+ padded.push(mask[i]);
97
+ }
98
+ this._maskChain = padded
99
+ .map((x, i) => x === true ?
100
+ MaskType.hide :
101
+ padded.length - i > depth ?
102
+ MaskType.show :
103
+ MaskType.headless);
104
+ this._maxChain = this._maskChain.length;
105
+ }
106
+ }
107
+ exports.RenderArgs = RenderArgs;
package/bin/router.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  /// <reference types="node" />
2
2
  import type http from "node:http";
3
- import { Outlet, Override, Redirect, RenderArgs, RouteModule } from "./shared";
3
+ import { Override, Redirect, RouteModule } from "./shared";
4
+ import { MaskType, RenderArgs } from "./render-args";
4
5
  export declare function IsAllowedExt(ext: string): boolean;
5
- declare class RouteLeaf {
6
+ export declare class RouteLeaf {
6
7
  module: RouteModule;
7
8
  mask: boolean[];
8
9
  constructor(module: RouteModule, mask: boolean[]);
9
- makeOutlet(args: RenderArgs, outlet: Outlet, depth: number): Outlet;
10
+ render(args: RenderArgs, mask: MaskType, routeName: string): Promise<string>;
10
11
  }
11
12
  export declare class RouteTree {
12
13
  nested: Map<string, RouteTree>;
@@ -17,7 +18,6 @@ export declare class RouteTree {
17
18
  constructor();
18
19
  assignRoot(module: RouteModule): void;
19
20
  ingest(path: string | string[], module: RouteModule, override: boolean[]): void;
21
+ calculateDepth(from: string[], to: string[]): number;
20
22
  render(req: http.IncomingMessage, res: http.ServerResponse, url: URL): Promise<string | Redirect | Override>;
21
- private _recursiveRender;
22
23
  }
23
- export {};
package/bin/router.js CHANGED
@@ -1,7 +1,32 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RouteTree = exports.IsAllowedExt = void 0;
26
+ exports.RouteTree = exports.RouteLeaf = exports.IsAllowedExt = void 0;
4
27
  const shared_1 = require("./shared");
28
+ const render_args_1 = require("./render-args");
29
+ const BlankRoute = __importStar(require("./404-route"));
5
30
  function IsAllowedExt(ext) {
6
31
  if (ext[0] !== ".")
7
32
  return false;
@@ -19,36 +44,37 @@ function IsAllowedExt(ext) {
19
44
  return true;
20
45
  }
21
46
  exports.IsAllowedExt = IsAllowedExt;
22
- async function blankOutlet() {
23
- return "";
24
- }
25
47
  class RouteLeaf {
26
48
  constructor(module, mask) {
27
49
  this.module = module;
28
50
  this.mask = mask;
29
51
  }
30
- makeOutlet(args, outlet, depth) {
31
- const renderer = this.module.Render || blankOutlet;
32
- const catcher = this.module.CatchError;
33
- return async () => {
34
- try {
35
- args.depth = depth;
36
- return await renderer(args, outlet);
52
+ async render(args, mask, routeName) {
53
+ try {
54
+ if (this.module.Auth)
55
+ return await this.module.Auth(args);
56
+ if (mask === render_args_1.MaskType.show) {
57
+ if (this.module.Render)
58
+ return await this.module.Render(routeName, args);
37
59
  }
38
- catch (e) {
39
- if (e instanceof shared_1.Redirect || e instanceof shared_1.Override)
40
- throw e;
41
- const err = (e instanceof shared_1.ErrorResponse) ? e :
42
- new shared_1.ErrorResponse(500, "Runtime Error", e);
43
- if (catcher) {
44
- args.depth = depth;
45
- return await catcher(args, err);
46
- }
47
- throw err;
60
+ else {
61
+ return await args.Outlet();
48
62
  }
49
- };
63
+ }
64
+ catch (e) {
65
+ if (e instanceof shared_1.Redirect || e instanceof shared_1.Override)
66
+ throw e;
67
+ const err = (e instanceof shared_1.ErrorResponse) ? e :
68
+ new shared_1.ErrorResponse(500, "Runtime Error", e);
69
+ if (this.module.CatchError)
70
+ return await this.module.CatchError(routeName, args, err);
71
+ throw err;
72
+ }
73
+ return "";
50
74
  }
51
75
  }
76
+ exports.RouteLeaf = RouteLeaf;
77
+ const blankLeaf = new RouteLeaf(BlankRoute, []);
52
78
  class RouteTree {
53
79
  constructor() {
54
80
  this.nested = new Map();
@@ -69,10 +95,12 @@ class RouteTree {
69
95
  path = path.split(/[\./\\]/g);
70
96
  }
71
97
  if (path.length === 0) {
98
+ override.push(false);
72
99
  this.route = new RouteLeaf(module, override);
73
100
  return;
74
101
  }
75
102
  if (path.length === 1 && path[0] === "_index") {
103
+ override.push(false);
76
104
  this.default = new RouteLeaf(module, override);
77
105
  return;
78
106
  }
@@ -105,67 +133,132 @@ class RouteTree {
105
133
  path.splice(0, 1);
106
134
  next.ingest(path, module, override);
107
135
  }
108
- async render(req, res, url) {
109
- const args = new shared_1.RenderArgs(req, res, url);
110
- if (!this.default || !this.default.module.Render) {
111
- return "";
136
+ calculateDepth(from, to) {
137
+ let depth = 0;
138
+ if (from.length == 0 || to.length == 0) {
139
+ depth = 1;
112
140
  }
113
- const frags = url.pathname.split('/').slice(1);
114
- if (frags.length === 1 && frags[0] === "") {
115
- frags.splice(0, 1);
141
+ else {
142
+ const segmentA = from.splice(0, 1)[0];
143
+ const segmentB = to.splice(0, 1)[0];
144
+ const subRoute = this.nested.get(segmentA);
145
+ if (subRoute && segmentA === segmentB) {
146
+ depth = subRoute.calculateDepth(from, to);
147
+ }
148
+ else if (this.wild) {
149
+ depth = this.wild.calculateDepth(from, to);
150
+ }
151
+ else {
152
+ return 1;
153
+ }
116
154
  }
155
+ depth++;
156
+ return depth;
157
+ }
158
+ async render(req, res, url) {
159
+ var _a;
160
+ if (url.pathname.length != 1 && url.pathname.endsWith("/")) {
161
+ return new shared_1.Redirect(url.pathname.slice(0, -1) + url.search);
162
+ }
163
+ const args = new render_args_1.RenderArgs(req, res, url);
164
+ const from = req.headers['hx-headless'] ?
165
+ new URL(((_a = req.headers['hx-current-url']) === null || _a === void 0 ? void 0 : _a.toString()) || "/").pathname :
166
+ "";
117
167
  try {
118
- const out = await this._recursiveRender(args, frags).outlet();
119
- return out;
168
+ const depth = BuildOutlet(this, args, from);
169
+ if (from) {
170
+ res.setHeader('HX-Replace-Url', req.url || "/");
171
+ if (depth > 0) {
172
+ res.setHeader('HX-Retarget', `#hx-route-${depth.toString(16)}`);
173
+ }
174
+ res.setHeader('HX-Reswap', "outerHTML");
175
+ }
176
+ return await args.Outlet();
120
177
  }
121
178
  catch (e) {
122
179
  if (e instanceof shared_1.Redirect)
123
180
  return e;
124
181
  if (e instanceof shared_1.Override)
125
182
  return e;
183
+ console.error(e);
126
184
  throw new Error(`Unhandled boil up type ${typeof (e)}: ${e}`);
127
185
  }
128
186
  ;
129
187
  }
130
- _recursiveRender(args, frags) {
131
- var _a;
132
- let out = {
133
- outlet: blankOutlet,
134
- mask: [],
135
- };
136
- if (frags.length == 0) {
137
- if (!this.default) {
138
- out.outlet = () => {
139
- throw new shared_1.ErrorResponse(404, "Resource Not Found", `Unable to find ${args.url.pathname}`);
140
- };
188
+ }
189
+ exports.RouteTree = RouteTree;
190
+ function BuildOutlet(start, args, fromPath) {
191
+ const frags = args.url.pathname.split('/').slice(1);
192
+ if (frags.length === 1 && frags[0] === "") {
193
+ frags.splice(0, 1);
194
+ }
195
+ const from = fromPath.split('/').slice(1);
196
+ if (from.length === 1 && from[0] === "") {
197
+ from.splice(0, 1);
198
+ }
199
+ let matching = fromPath.length > 0;
200
+ let depth = -1;
201
+ const stack = [start];
202
+ let mask = null;
203
+ while (stack.length > 0) {
204
+ const cursor = stack.pop();
205
+ if (!mask) {
206
+ stack.push(cursor);
207
+ if (frags.length === 0) {
208
+ if (matching && from.length !== 0) {
209
+ depth = args._outletChain.length + stack.length;
210
+ matching = false;
211
+ }
212
+ ;
213
+ if (cursor.default) {
214
+ args._addOutlet(cursor.default);
215
+ mask = cursor.default.mask;
216
+ }
217
+ else {
218
+ args._addOutlet(blankLeaf);
219
+ mask = [];
220
+ }
141
221
  }
142
- else if ((_a = this.default) === null || _a === void 0 ? void 0 : _a.module.Render) {
143
- out.mask = [...this.default.mask];
144
- out.outlet = this.default.makeOutlet(args, out.outlet, out.mask.length);
222
+ else {
223
+ if (matching && from.length === 0) {
224
+ depth = args._outletChain.length + stack.length;
225
+ matching = false;
226
+ }
227
+ const segment = frags.splice(0, 1)[0];
228
+ const other = from.splice(0, 1)[0];
229
+ const subRoute = cursor.nested.get(segment);
230
+ if (subRoute) {
231
+ if (matching && segment !== other) {
232
+ depth = args._outletChain.length + stack.length;
233
+ matching = false;
234
+ }
235
+ ;
236
+ stack.push(subRoute);
237
+ }
238
+ else if (cursor.wild) {
239
+ if (matching && cursor.nested.has(other)) {
240
+ depth = args._outletChain.length + stack.length;
241
+ matching = false;
242
+ }
243
+ ;
244
+ args.params[cursor.wildCard] = segment;
245
+ stack.push(cursor.wild);
246
+ }
247
+ else {
248
+ args._addOutlet(blankLeaf);
249
+ mask = [];
250
+ }
145
251
  }
146
252
  }
147
253
  else {
148
- const segment = frags.splice(0, 1)[0];
149
- const subRoute = this.nested.get(segment);
150
- if (subRoute) {
151
- out = subRoute._recursiveRender(args, frags);
152
- }
153
- else if (this.wild) {
154
- args.params[this.wildCard] = segment;
155
- out = this.wild._recursiveRender(args, frags);
254
+ if (cursor.route) {
255
+ args._addOutlet(cursor.route);
156
256
  }
157
- else {
158
- out.outlet = () => {
159
- throw new shared_1.ErrorResponse(404, "Resource Not Found", `Unable to find ${args.url.pathname}`);
160
- };
161
- }
162
- }
163
- // Is this route masked out?
164
- const ignored = out.mask.splice(0, 1)[0] === true;
165
- if (!ignored && this.route) {
166
- out.outlet = this.route.makeOutlet(args, out.outlet, out.mask.length);
167
257
  }
168
- return out;
169
258
  }
259
+ if (matching) {
260
+ depth = args._outletChain.length - 1;
261
+ }
262
+ args._applyMask(mask, depth);
263
+ return depth;
170
264
  }
171
- exports.RouteTree = RouteTree;
package/bin/shared.d.ts CHANGED
@@ -1,12 +1,15 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
3
  import type http from "node:http";
4
+ import { RenderArgs } from "./render-args";
4
5
  export type Outlet = () => Promise<string>;
5
- export type RenderFunction = (args: RenderArgs, Outlet: Outlet) => Promise<string>;
6
- export type CatchFunction = (args: RenderArgs, err: ErrorResponse) => Promise<string>;
6
+ export type CatchFunction = (routeName: string, args: RenderArgs, err: ErrorResponse) => Promise<string>;
7
+ export type RenderFunction = (routeName: string, args: RenderArgs) => Promise<string>;
8
+ export type AuthFunction = (args: RenderArgs) => Promise<string>;
7
9
  export type RouteModule = {
8
10
  Render?: RenderFunction;
9
11
  CatchError?: CatchFunction;
12
+ Auth?: AuthFunction;
10
13
  };
11
14
  export declare class ErrorResponse {
12
15
  code: number;
@@ -23,20 +26,3 @@ export declare class Override {
23
26
  data: string | Buffer | Uint8Array;
24
27
  constructor(data: string | Buffer | Uint8Array);
25
28
  }
26
- type MetaHTML = {
27
- [key: string]: string;
28
- };
29
- export declare class RenderArgs {
30
- req: http.IncomingMessage;
31
- res: http.ServerResponse;
32
- params: MetaHTML;
33
- depth: number;
34
- url: URL;
35
- links: MetaHTML[];
36
- meta: MetaHTML[];
37
- constructor(req: http.IncomingMessage, res: http.ServerResponse, url: URL);
38
- addLinks(links: MetaHTML[], override?: boolean): void;
39
- addMeta(links: MetaHTML[], override?: boolean): void;
40
- renderHeadHTML(): string;
41
- }
42
- export {};
package/bin/shared.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RenderArgs = exports.Override = exports.Redirect = exports.ErrorResponse = void 0;
3
+ exports.Override = exports.Redirect = exports.ErrorResponse = void 0;
4
4
  class ErrorResponse {
5
5
  constructor(statusCode, statusMessage, data) {
6
6
  this.code = statusCode;
@@ -26,68 +26,3 @@ class Override {
26
26
  }
27
27
  }
28
28
  exports.Override = Override;
29
- const attrRegex = /^[A-z][A-z\-0-9]+$/;
30
- function ValidateMetaHTML(val) {
31
- for (const key in val) {
32
- if (!attrRegex.test(key))
33
- return false;
34
- }
35
- return true;
36
- }
37
- function ValidateMetaHTMLs(val) {
38
- for (const meta of val) {
39
- if (!ValidateMetaHTML(meta))
40
- return false;
41
- }
42
- return true;
43
- }
44
- class RenderArgs {
45
- constructor(req, res, url) {
46
- this.req = req;
47
- this.res = res;
48
- this.url = url;
49
- this.params = {};
50
- this.depth = -1;
51
- this.links = [];
52
- this.meta = [];
53
- }
54
- addLinks(links, override = false) {
55
- if (!ValidateMetaHTMLs(links))
56
- throw new Error(`Provided links have invalid attribute`);
57
- if (override) {
58
- this.links = links;
59
- }
60
- else {
61
- this.links.push(...links);
62
- }
63
- }
64
- addMeta(links, override = false) {
65
- if (!ValidateMetaHTMLs(links))
66
- throw new Error(`Provided links have invalid attribute`);
67
- if (override) {
68
- this.meta = links;
69
- }
70
- else {
71
- this.meta.push(...links);
72
- }
73
- }
74
- renderHeadHTML() {
75
- let out = "";
76
- for (const elm of this.links) {
77
- out += "<link";
78
- for (const attr in elm) {
79
- out += ` ${attr}="${elm[attr].replace(/"/g, "\\\"")}"`;
80
- }
81
- out += "></link>";
82
- }
83
- for (const elm of this.meta) {
84
- out += "<meta";
85
- for (const attr in elm) {
86
- out += ` ${attr}="${elm[attr].replace(/"/g, "\\\"")}"`;
87
- }
88
- out += "></meta>";
89
- }
90
- return out;
91
- }
92
- }
93
- exports.RenderArgs = RenderArgs;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "htmx-router",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "A remix.js style file path router for htmX websites",
5
5
  "main": "./bin/index.js",
6
6
  "scripts": {
@@ -25,6 +25,7 @@
25
25
  "typescript": "^5.1.6"
26
26
  },
27
27
  "dependencies": {
28
- "csstype": "^3.1.2"
28
+ "csstype": "^3.1.2",
29
+ "typed-html": "^3.0.1"
29
30
  }
30
31
  }