htmx-router 2.0.4 → 2.0.6
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/package.json +1 -1
- package/response.d.ts +46 -0
- package/response.js +76 -5
package/package.json
CHANGED
package/response.d.ts
CHANGED
|
@@ -7,8 +7,54 @@ export type TypedJson<U extends TypedResponse<any>> = U extends TypedResponse<in
|
|
|
7
7
|
export declare function json<T>(data: T, init?: ResponseInit): TypedResponse<T>;
|
|
8
8
|
export declare function redirect(url: string, init?: ResponseInit & {
|
|
9
9
|
clientOnly?: boolean;
|
|
10
|
+
permanent?: boolean;
|
|
10
11
|
}): Response;
|
|
11
12
|
export declare function revalidate(init?: ResponseInit): Response;
|
|
12
13
|
export declare function refresh(init?: ResponseInit & {
|
|
13
14
|
clientOnly?: boolean;
|
|
14
15
|
}): Response;
|
|
16
|
+
/**
|
|
17
|
+
* Handles Entity-Tag based conditional requests by setting cache headers and controlling execution flow.
|
|
18
|
+
* Acts like an assertion that stops execution when the client's ETag matches the current ETag.
|
|
19
|
+
*
|
|
20
|
+
* @param {Request} request - The incoming HTTP request object
|
|
21
|
+
* @param {Headers} headers - The response headers object to modify
|
|
22
|
+
* @param {string} etag - The current ETag value for the resource
|
|
23
|
+
* @param {Object} [options] - Optional caching configuration
|
|
24
|
+
* @param {number} [options.revalidate] - client must revalidate their etag at this interval in seconds
|
|
25
|
+
* @param {boolean} [options.public] - cache visibility scope:
|
|
26
|
+
* - "public": Can be cached by any cache (i.e. Cloudflare)
|
|
27
|
+
* - "private": Can only be cached by private caches (i.e. browser)
|
|
28
|
+
*
|
|
29
|
+
* @throws {Response} `304 Not Modified` Response with the configured headers
|
|
30
|
+
* when the client's If-None-Match header matches the provided ETag
|
|
31
|
+
*
|
|
32
|
+
* @returns {void} if client's etag is stale, allows execution to continue to generate new result
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* // Basic usage - will return early if client has current version
|
|
36
|
+
* GuardEntityTag(request, headers, "v1.2.3");
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* // With caching options
|
|
40
|
+
* GuardEntityTag(request, headers, "v1.2.3", {
|
|
41
|
+
* revalidate: 3600,
|
|
42
|
+
* scope: "public"
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* // Usage in a handler function
|
|
47
|
+
* function handleRequest(request, headers) {
|
|
48
|
+
* const currentEtag = generateEtag(data);
|
|
49
|
+
*
|
|
50
|
+
* // Will throw 304 if client ETag is fresh
|
|
51
|
+
* GuardEntityTag(request, headers, currentEtag);
|
|
52
|
+
*
|
|
53
|
+
* // This code only runs if client needs updated content
|
|
54
|
+
* return new Response(generateContent(), { headers });
|
|
55
|
+
* }
|
|
56
|
+
*/
|
|
57
|
+
export declare function AssertETagStale(request: Request, headers: Headers, etag: string, options?: {
|
|
58
|
+
revalidate?: number;
|
|
59
|
+
public?: boolean;
|
|
60
|
+
}): void;
|
package/response.js
CHANGED
|
@@ -20,8 +20,11 @@ export function json(data, init) {
|
|
|
20
20
|
return res;
|
|
21
21
|
}
|
|
22
22
|
export function redirect(url, init) {
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
if (init?.permanent)
|
|
24
|
+
init = FillResponseInit(308, "Permanent Redirect", init);
|
|
25
|
+
else
|
|
26
|
+
init = FillResponseInit(307, "Temporary Redirect", init);
|
|
27
|
+
const res = new Response(null, init);
|
|
25
28
|
if (!init?.clientOnly)
|
|
26
29
|
res.headers.set("Location", url);
|
|
27
30
|
res.headers.set("HX-Location", url); // use hx-boost if applicable
|
|
@@ -38,13 +41,81 @@ export function revalidate(init) {
|
|
|
38
41
|
}
|
|
39
42
|
export function refresh(init) {
|
|
40
43
|
init = FillResponseInit(200, "Ok", init);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
res.headers.set("Refresh", "
|
|
44
|
+
if (init.clientOnly) {
|
|
45
|
+
const res = new Response(null, init);
|
|
46
|
+
res.headers.set("HX-Refresh", "true");
|
|
47
|
+
res.headers.set("X-Caught", "true");
|
|
48
|
+
return res;
|
|
49
|
+
}
|
|
50
|
+
const res = new Response(`<script>if (document.referrer) location.href = document.referrer;</script>Something went wrong`);
|
|
51
|
+
res.headers.set("Content-Type", "text/html; charset=UTF-8");
|
|
44
52
|
res.headers.set("HX-Refresh", "true");
|
|
45
53
|
res.headers.set("X-Caught", "true");
|
|
46
54
|
return res;
|
|
47
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Handles Entity-Tag based conditional requests by setting cache headers and controlling execution flow.
|
|
58
|
+
* Acts like an assertion that stops execution when the client's ETag matches the current ETag.
|
|
59
|
+
*
|
|
60
|
+
* @param {Request} request - The incoming HTTP request object
|
|
61
|
+
* @param {Headers} headers - The response headers object to modify
|
|
62
|
+
* @param {string} etag - The current ETag value for the resource
|
|
63
|
+
* @param {Object} [options] - Optional caching configuration
|
|
64
|
+
* @param {number} [options.revalidate] - client must revalidate their etag at this interval in seconds
|
|
65
|
+
* @param {boolean} [options.public] - cache visibility scope:
|
|
66
|
+
* - "public": Can be cached by any cache (i.e. Cloudflare)
|
|
67
|
+
* - "private": Can only be cached by private caches (i.e. browser)
|
|
68
|
+
*
|
|
69
|
+
* @throws {Response} `304 Not Modified` Response with the configured headers
|
|
70
|
+
* when the client's If-None-Match header matches the provided ETag
|
|
71
|
+
*
|
|
72
|
+
* @returns {void} if client's etag is stale, allows execution to continue to generate new result
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* // Basic usage - will return early if client has current version
|
|
76
|
+
* GuardEntityTag(request, headers, "v1.2.3");
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* // With caching options
|
|
80
|
+
* GuardEntityTag(request, headers, "v1.2.3", {
|
|
81
|
+
* revalidate: 3600,
|
|
82
|
+
* scope: "public"
|
|
83
|
+
* });
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* // Usage in a handler function
|
|
87
|
+
* function handleRequest(request, headers) {
|
|
88
|
+
* const currentEtag = generateEtag(data);
|
|
89
|
+
*
|
|
90
|
+
* // Will throw 304 if client ETag is fresh
|
|
91
|
+
* GuardEntityTag(request, headers, currentEtag);
|
|
92
|
+
*
|
|
93
|
+
* // This code only runs if client needs updated content
|
|
94
|
+
* return new Response(generateContent(), { headers });
|
|
95
|
+
* }
|
|
96
|
+
*/
|
|
97
|
+
export function AssertETagStale(request, headers, etag, options) {
|
|
98
|
+
if (options) {
|
|
99
|
+
// default to private, because it's the slightly less worse of the two potential foot guns
|
|
100
|
+
if (options.public)
|
|
101
|
+
headers.append("Cache-Control", "public");
|
|
102
|
+
else
|
|
103
|
+
headers.append("Cache-Control", "private");
|
|
104
|
+
if (options.revalidate !== undefined)
|
|
105
|
+
headers.append("Cache-Control", `max-age=${options.revalidate}`);
|
|
106
|
+
}
|
|
107
|
+
headers.append("Cache-Control", "must-revalidate");
|
|
108
|
+
headers.set("ETag", etag);
|
|
109
|
+
const client = request.headers.get("if-none-match");
|
|
110
|
+
if (client !== etag)
|
|
111
|
+
return;
|
|
112
|
+
const res = new Response(null, {
|
|
113
|
+
status: 304, statusText: "Not Modified",
|
|
114
|
+
headers
|
|
115
|
+
});
|
|
116
|
+
res.headers.set("X-Caught", "true");
|
|
117
|
+
throw res;
|
|
118
|
+
}
|
|
48
119
|
/**
|
|
49
120
|
* This is to fix issues with deno
|
|
50
121
|
* When you try and change the statusText on a Response object
|