htmx-router 2.1.2 → 2.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/dist/cookies.d.ts CHANGED
@@ -26,5 +26,5 @@ export declare class Cookies {
26
26
  private string;
27
27
  unset(name: string, options?: CookieOptions): void;
28
28
  /** Creates the response headers required to make the changes done to these cookies */
29
- export(): string[];
29
+ export(): Array<string>;
30
30
  }
package/dist/cookies.js CHANGED
@@ -58,7 +58,7 @@ export class Cookies {
58
58
  unset(name, options = { maxAge: -1 }) {
59
59
  options.maxAge ||= -1;
60
60
  this.parse();
61
- return this.set(name, "", options);
61
+ this.set(name, "", options);
62
62
  }
63
63
  /** Creates the response headers required to make the changes done to these cookies */
64
64
  export() {
package/dist/css.js CHANGED
@@ -46,9 +46,7 @@ export function GetSheetUrl() {
46
46
  * RouteTree mounting point
47
47
  */
48
48
  export const path = "/_/style/$hash";
49
- export const parameters = {
50
- hash: String
51
- };
49
+ export const parameters = { hash: String };
52
50
  export async function loader(ctx) {
53
51
  const build = GetSheet();
54
52
  if (!ctx.params.hash.startsWith(build.hash))
package/dist/defer.js CHANGED
@@ -53,9 +53,7 @@ export function Deferral(func, params) {
53
53
  * RouteTree mounting point
54
54
  */
55
55
  export const path = "/_/defer/$";
56
- export const parameters = {
57
- "$": String
58
- };
56
+ export const parameters = { "$": String };
59
57
  export async function loader(ctx) {
60
58
  const endpoint = registry.get(ctx.params["$"]);
61
59
  if (!endpoint)
package/dist/endpoint.js CHANGED
@@ -23,9 +23,7 @@ export class Endpoint {
23
23
  * RouteTree mounting point
24
24
  */
25
25
  export const path = "/_/endpoint/$";
26
- export const parameters = {
27
- "$": String
28
- };
26
+ export const parameters = { "$": String };
29
27
  export async function loader(ctx) {
30
28
  const endpoint = registry.get(ctx.params["$"]);
31
29
  if (!endpoint)
@@ -22,15 +22,24 @@ export declare class EventSource<JsxEnabled extends boolean = false> {
22
22
  */
23
23
  _keepAlive(): boolean;
24
24
  dispatch(type: string, data: JsxEnabled extends true ? (JSX.Element | string) : string): boolean;
25
- close(unlink?: boolean): boolean;
25
+ close(): boolean;
26
26
  }
27
27
  export declare class EventSourceSet<JsxEnabled extends boolean = false> extends Set<EventSource<JsxEnabled>> {
28
- /** Send update to all EventSources, auto closing failed dispatches */
29
- dispatch(type: string, data: string): void;
30
- /** Cull all closed connections */
31
- cull(): void;
32
- /** Close all connections */
33
- closeAll(): void;
28
+ /**
29
+ * Send update to all EventSources, auto closing failed dispatches
30
+ * @returns number of successful sends
31
+ */
32
+ dispatch(type: string, data: string): number;
33
+ /**
34
+ * Cull all closed connections
35
+ * @returns number of connections closed
36
+ */
37
+ cull(): number;
38
+ /**
39
+ * Close all connections
40
+ * @returns number of connections closed
41
+ */
42
+ closeAll(): number;
34
43
  }
35
44
  type SharedEventSourceCacheRule = {
36
45
  limit: number;
@@ -97,7 +97,7 @@ export class EventSource {
97
97
  }
98
98
  return this.#sendText(`event: ${type}\ndata: ${html}\n\n`, true);
99
99
  }
100
- close(unlink = true) {
100
+ close() {
101
101
  if (this.#controller) {
102
102
  try {
103
103
  this.#controller.close();
@@ -119,29 +119,46 @@ export class EventSource {
119
119
  }
120
120
  _a = EventSource;
121
121
  export class EventSourceSet extends Set {
122
- /** Send update to all EventSources, auto closing failed dispatches */
122
+ /**
123
+ * Send update to all EventSources, auto closing failed dispatches
124
+ * @returns number of successful sends
125
+ */
123
126
  dispatch(type, data) {
127
+ let count = 0;
124
128
  for (const stream of this) {
125
129
  if (stream.readyState === 0)
126
130
  continue; // skip initializing
127
131
  const success = stream.dispatch(type, data);
128
- if (!success)
132
+ if (success)
133
+ count++;
134
+ else
129
135
  this.delete(stream);
130
136
  }
137
+ return count;
131
138
  }
132
- /** Cull all closed connections */
139
+ /**
140
+ * Cull all closed connections
141
+ * @returns number of connections closed
142
+ */
133
143
  cull() {
144
+ const count = this.size;
134
145
  for (const stream of this) {
135
146
  if (stream.readyState !== 2)
136
147
  continue;
137
148
  this.delete(stream);
138
149
  }
150
+ return count;
139
151
  }
140
- /** Close all connections */
152
+ /**
153
+ * Close all connections
154
+ * @returns number of connections closed
155
+ */
141
156
  closeAll() {
157
+ const count = this.size;
142
158
  for (const stream of this)
143
159
  stream.close();
144
160
  this.clear();
161
+ return count;
145
162
  }
146
163
  }
147
164
  /**
@@ -2,7 +2,7 @@ import { ServerOnlyWarning } from "./util.js";
2
2
  ServerOnlyWarning("client-url");
3
3
  import { readFile } from "fs/promises";
4
4
  export async function GetClientEntryURL() {
5
- if (process.env.NODE_ENV !== "production")
5
+ if (import.meta.env.DEV)
6
6
  return "/app/entry.client.ts";
7
7
  const config = JSON.parse(await readFile("./dist/client/.vite/manifest.json", "utf8"));
8
8
  for (const key in config) {
@@ -3,19 +3,18 @@ import { GetMountUrl } from 'htmx-router/internal/mount';
3
3
  import { GetSheetUrl } from 'htmx-router/css';
4
4
 
5
5
  let cache: JSX.Element | null = null;
6
- const isProduction = process.env.NODE_ENV === "production";
7
6
  const clientEntry = await GetClientEntryURL();
8
7
  export function Scripts() {
9
8
  if (cache) return cache;
10
9
 
11
10
  const res = <>
12
11
  <link href={GetSheetUrl()} rel="stylesheet"></link>
13
- { isProduction ? "" : <script type="module" src="/@vite/client"></script> }
12
+ { import.meta.env.DEV ? <script type="module" src="/@vite/client"></script> : "" }
14
13
  <script type="module" src={clientEntry}></script>
15
14
  <script src={GetMountUrl()}></script>
16
15
  </>;
17
16
 
18
- if (isProduction) cache = res;
17
+ if (import.meta.env.PROD) cache = res;
19
18
  return res;
20
19
  }`;
21
20
  export default {
@@ -1,3 +1,4 @@
1
+ import { ResponseInit } from "./util/types";
1
2
  export declare function text(text: BodyInit, init?: ResponseInit): Response;
2
3
  export declare function html(text: BodyInit, init?: ResponseInit): Response;
3
4
  export type TypedResponse<T> = Omit<Response, "json"> & {
@@ -18,7 +19,7 @@ export declare function refresh(init?: ResponseInit & {
18
19
  * Acts like an assertion that stops execution when the client's ETag matches the current ETag.
19
20
  *
20
21
  * @param {Request} request - The incoming HTTP request object
21
- * @param {Headers} headers - The response headers object to modify
22
+ * @param {Headers} headers - The output response headers object to modify
22
23
  * @param {string} etag - The current ETag value for the resource (do not quote)
23
24
  * @param {Object} [options] - Optional caching configuration
24
25
  * @param {number} [options.revalidate] - client must revalidate their etag at this interval in seconds
package/dist/response.js CHANGED
@@ -58,7 +58,7 @@ export function refresh(init) {
58
58
  * Acts like an assertion that stops execution when the client's ETag matches the current ETag.
59
59
  *
60
60
  * @param {Request} request - The incoming HTTP request object
61
- * @param {Headers} headers - The response headers object to modify
61
+ * @param {Headers} headers - The output response headers object to modify
62
62
  * @param {string} etag - The current ETag value for the resource (do not quote)
63
63
  * @param {Object} [options] - Optional caching configuration
64
64
  * @param {number} [options.revalidate] - client must revalidate their etag at this interval in seconds
@@ -97,6 +97,7 @@ export function refresh(init) {
97
97
  * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/ETag | ETag - MDN Web Docs }
98
98
  */
99
99
  export function AssertETagStale(request, headers, etag, options) {
100
+ headers.delete("Cache-Control"); // clear any defaults
100
101
  if (options) {
101
102
  // default to private, because it's the slightly less worse of the two potential foot guns
102
103
  if (options.public)
@@ -107,7 +108,7 @@ export function AssertETagStale(request, headers, etag, options) {
107
108
  headers.append("Cache-Control", `max-age=${options.revalidate}`);
108
109
  }
109
110
  headers.append("Cache-Control", "must-revalidate");
110
- headers.set("ETag", `"${etag}"`);
111
+ headers.set("ETag", `"${encodeURIComponent(etag.trim())}"`);
111
112
  const client = request.headers.get("if-none-match");
112
113
  if (client !== etag)
113
114
  return;
package/dist/status.d.ts CHANGED
@@ -1,3 +1,9 @@
1
+ import { ResponseInit } from "./util/types";
2
+ type ResponseConfig = ResponseInit & {
3
+ status: number;
4
+ statusText: string;
5
+ };
6
+ export declare function MakeStatus(lookup: StatusCode | StatusText, init?: ResponseInit | Headers): ResponseConfig;
1
7
  declare const dictionary: {
2
8
  100: "Continue";
3
9
  101: "Switching Protocols";
@@ -66,5 +72,4 @@ declare const dictionary: {
66
72
  type Definitions = typeof dictionary;
67
73
  export type StatusCode = keyof Definitions;
68
74
  export type StatusText = Definitions[StatusCode];
69
- export declare function MakeStatus(lookup: StatusCode | StatusText, init?: ResponseInit | Headers): ResponseInit;
70
75
  export {};
package/dist/status.js CHANGED
@@ -1,3 +1,28 @@
1
+ export function MakeStatus(lookup, init) {
2
+ if (init instanceof Headers)
3
+ init = { headers: init };
4
+ if (typeof lookup === "number")
5
+ return lookupCode(lookup, init);
6
+ return lookupStatus(lookup, init);
7
+ }
8
+ function lookupCode(code, init) {
9
+ const text = index.text.get(code);
10
+ if (text === undefined)
11
+ throw new TypeError(`Status ${code} is not a known status code`);
12
+ return SetStatus(init, code, text);
13
+ }
14
+ function lookupStatus(text, init) {
15
+ const code = index.code.get(text.toLowerCase());
16
+ if (code === undefined)
17
+ throw new TypeError(`Status "${text}" is not a known status text`);
18
+ return SetStatus(init, code, text);
19
+ }
20
+ function SetStatus(into = {}, status, statusText) {
21
+ into.statusText = statusText;
22
+ into.status = status;
23
+ return into;
24
+ }
25
+ ;
1
26
  const dictionary = {
2
27
  100: "Continue",
3
28
  101: "Switching Protocols",
@@ -73,28 +98,3 @@ for (const k in dictionary) {
73
98
  index.code.set(text.toLowerCase(), code);
74
99
  index.text.set(code, text);
75
100
  }
76
- export function MakeStatus(lookup, init) {
77
- if (init instanceof Headers)
78
- init = { headers: init };
79
- if (typeof lookup === "number")
80
- return lookupCode(lookup, init);
81
- return lookupStatus(lookup, init);
82
- }
83
- function lookupCode(code, init) {
84
- const text = index.text.get(code);
85
- if (text === undefined)
86
- throw new TypeError(`Status ${code} is not a known status code`);
87
- return SetStatus(init, code, text);
88
- }
89
- function lookupStatus(text, init) {
90
- const code = index.code.get(text.toLowerCase());
91
- if (code === undefined)
92
- throw new TypeError(`Status "${text}" is not a known status text`);
93
- return SetStatus(init, code, text);
94
- }
95
- function SetStatus(into = {}, status, statusText) {
96
- into.statusText = statusText;
97
- into.status = status;
98
- return into;
99
- }
100
- ;
package/dist/timer.d.ts CHANGED
@@ -50,4 +50,5 @@ export declare class RequestTimer {
50
50
  * It will clear all timers for the request, and ensure they aren't included in the response
51
51
  */
52
52
  disable(): void;
53
+ getElapsed(): number;
53
54
  }
package/dist/timer.js CHANGED
@@ -12,7 +12,9 @@
12
12
  */
13
13
  export class RequestTimer {
14
14
  #checkpoints;
15
+ #start;
15
16
  constructor(enabled) {
17
+ this.#start = Date.now();
16
18
  if (!enabled) {
17
19
  this.#checkpoints = null;
18
20
  return;
@@ -77,6 +79,9 @@ export class RequestTimer {
77
79
  * It will clear all timers for the request, and ensure they aren't included in the response
78
80
  */
79
81
  disable() { this.#checkpoints = null; }
82
+ getElapsed() {
83
+ return Date.now() - this.#start;
84
+ }
80
85
  }
81
86
  class Checkpoint {
82
87
  time;
@@ -0,0 +1 @@
1
+ export type ResponseInit = NonNullable<ConstructorParameters<typeof Response>[1]>;
@@ -0,0 +1 @@
1
+ export {};
package/global.d.ts CHANGED
@@ -4,4 +4,23 @@ declare namespace JSX {
4
4
  [elementName: string]: any;
5
5
  }
6
6
  interface Fragment {}
7
+ }
8
+
9
+ interface ImportMeta {
10
+ glob: (
11
+ pattern: string,
12
+ options?: {
13
+ eager?: boolean;
14
+ import?: string;
15
+ as?: string;
16
+ }
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ ) => Record<string, any>;
19
+ env: {
20
+ BASE_URL: string,
21
+ DEV: boolean,
22
+ MODE: string,
23
+ PROD: boolean,
24
+ SSR: true,
25
+ } & Record<`VITE_${string}`, string>
7
26
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "htmx-router",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
4
4
  "description": "A lightweight SSR framework with server+client islands",
5
5
  "keywords": [ "htmx", "router", "client islands", "ssr", "vite" ],
6
6
  "type": "module",