cf-nix-cache 0.1.1 → 0.1.2
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/index.js +1365 -2031
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
- package/release-manifest.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,192 +1,129 @@
|
|
|
1
1
|
import { DurableObject, WorkerEntrypoint, WorkflowEntrypoint } from "cloudflare:workers";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
return dispatch(0);
|
|
6
|
-
async function dispatch(i) {
|
|
7
|
-
if (i <= index) {
|
|
8
|
-
throw new Error("next() called multiple times");
|
|
9
|
-
}
|
|
10
|
-
index = i;
|
|
11
|
-
let res;
|
|
12
|
-
let isError = false;
|
|
13
|
-
let handler;
|
|
14
|
-
if (middleware[i]) {
|
|
15
|
-
handler = middleware[i][0][0];
|
|
16
|
-
context.req.routeIndex = i;
|
|
17
|
-
} else {
|
|
18
|
-
handler = i === middleware.length && next || void 0;
|
|
19
|
-
}
|
|
20
|
-
if (handler) {
|
|
21
|
-
try {
|
|
22
|
-
res = await handler(context, () => dispatch(i + 1));
|
|
23
|
-
} catch (err) {
|
|
24
|
-
if (err instanceof Error && onError) {
|
|
25
|
-
context.error = err;
|
|
26
|
-
res = await onError(err, context);
|
|
27
|
-
isError = true;
|
|
28
|
-
} else {
|
|
29
|
-
throw err;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
} else {
|
|
33
|
-
if (context.finalized === false && onNotFound) {
|
|
34
|
-
res = await onNotFound(context);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
if (res && (context.finalized === false || isError)) {
|
|
38
|
-
context.res = res;
|
|
39
|
-
}
|
|
40
|
-
return context;
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
};
|
|
44
|
-
var GET_MATCH_RESULT = /* @__PURE__ */ Symbol();
|
|
45
|
-
var bufferToFormData = (arrayBuffer, contentType) => {
|
|
46
|
-
const response = new Response(arrayBuffer, {
|
|
47
|
-
headers: {
|
|
48
|
-
// Normalize the media type (case-insensitive) while keeping parameters like the boundary
|
|
49
|
-
"Content-Type": contentType.replace(/^[^;]+/, (mediaType) => mediaType.toLowerCase())
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
return response.formData();
|
|
2
|
+
const GET_MATCH_RESULT = /* @__PURE__ */ Symbol();
|
|
3
|
+
const bufferToFormData = (arrayBuffer, contentType) => {
|
|
4
|
+
return new Response(arrayBuffer, { headers: { "Content-Type": contentType.replace(/^[^;]+/, (mediaType) => mediaType.toLowerCase()) } }).formData();
|
|
53
5
|
};
|
|
54
|
-
|
|
55
|
-
|
|
6
|
+
const MAX_NESTED_OBJECTS = 1e4;
|
|
7
|
+
const isRawRequest = (request) => "headers" in request;
|
|
8
|
+
const parseBody = async (request, options = /* @__PURE__ */ Object.create(null)) => {
|
|
56
9
|
const { all = false, dot = false } = options;
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
10
|
+
const mediaType = (isRawRequest(request) ? request.headers : request.raw.headers).get("Content-Type")?.split(";")[0].trim().toLowerCase();
|
|
11
|
+
if (mediaType === "multipart/form-data" || mediaType === "application/x-www-form-urlencoded") return parseFormData(request, {
|
|
12
|
+
all,
|
|
13
|
+
dot
|
|
14
|
+
});
|
|
63
15
|
return {};
|
|
64
16
|
};
|
|
65
17
|
async function parseFormData(request, options) {
|
|
66
|
-
if (!isRawRequest(request) && request.bodyCache.formData)
|
|
67
|
-
return convertFormDataToBodyData(
|
|
68
|
-
await request.bodyCache.formData,
|
|
69
|
-
options
|
|
70
|
-
);
|
|
71
|
-
}
|
|
18
|
+
if (!isRawRequest(request) && request.bodyCache.formData) return convertFormDataToBodyData(await request.bodyCache.formData, options);
|
|
72
19
|
const headers = isRawRequest(request) ? request.headers : request.raw.headers;
|
|
73
20
|
const arrayBuffer = await request.arrayBuffer();
|
|
74
21
|
const formDataPromise = bufferToFormData(arrayBuffer, headers.get("Content-Type") || "");
|
|
75
|
-
if (!isRawRequest(request))
|
|
76
|
-
request.bodyCache.formData = formDataPromise;
|
|
77
|
-
}
|
|
22
|
+
if (!isRawRequest(request)) request.bodyCache.formData = formDataPromise;
|
|
78
23
|
const formData = await formDataPromise;
|
|
79
|
-
if (formData)
|
|
80
|
-
return convertFormDataToBodyData(formData, options);
|
|
81
|
-
}
|
|
24
|
+
if (formData) return convertFormDataToBodyData(formData, options);
|
|
82
25
|
return {};
|
|
83
26
|
}
|
|
84
27
|
function convertFormDataToBodyData(formData, options) {
|
|
85
28
|
const form = /* @__PURE__ */ Object.create(null);
|
|
29
|
+
const nestingState = { count: 0 };
|
|
86
30
|
formData.forEach((value, key) => {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
31
|
+
if (!(options.all || key.endsWith("[]"))) form[key] = value;
|
|
32
|
+
else handleParsingAllValues(form, key, value);
|
|
33
|
+
});
|
|
34
|
+
if (options.dot) Object.entries(form).forEach(([key, value]) => {
|
|
35
|
+
if (key.includes(".")) {
|
|
36
|
+
handleParsingNestedValues(form, key, value, nestingState);
|
|
37
|
+
delete form[key];
|
|
92
38
|
}
|
|
93
39
|
});
|
|
94
|
-
if (options.dot) {
|
|
95
|
-
Object.entries(form).forEach(([key, value]) => {
|
|
96
|
-
const shouldParseDotValues = key.includes(".");
|
|
97
|
-
if (shouldParseDotValues) {
|
|
98
|
-
handleParsingNestedValues(form, key, value);
|
|
99
|
-
delete form[key];
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
40
|
return form;
|
|
104
41
|
}
|
|
105
|
-
|
|
42
|
+
const handleParsingAllValues = (form, key, value) => {
|
|
106
43
|
if (form[key] !== void 0) {
|
|
107
|
-
if (Array.isArray(form[key]))
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
} else {
|
|
113
|
-
if (!key.endsWith("[]")) {
|
|
114
|
-
form[key] = value;
|
|
115
|
-
} else {
|
|
116
|
-
form[key] = [value];
|
|
117
|
-
}
|
|
118
|
-
}
|
|
44
|
+
if (Array.isArray(form[key])) form[key].push(value);
|
|
45
|
+
else form[key] = [form[key], value];
|
|
46
|
+
} else if (!key.endsWith("[]")) form[key] = value;
|
|
47
|
+
else form[key] = [value];
|
|
119
48
|
};
|
|
120
|
-
|
|
121
|
-
if (/(?:^|\.)__proto__\./.test(key))
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
49
|
+
const handleParsingNestedValues = (form, key, value, state2) => {
|
|
50
|
+
if (/(?:^|\.)__proto__\./.test(key)) return;
|
|
124
51
|
let nestedForm = form;
|
|
125
|
-
const keys = key.split(".");
|
|
52
|
+
const keys = key.split(".", 34);
|
|
53
|
+
if (keys.length > 33) throwNestingLimitExceeded();
|
|
126
54
|
keys.forEach((key2, index) => {
|
|
127
|
-
if (index === keys.length - 1)
|
|
128
|
-
|
|
129
|
-
} else {
|
|
55
|
+
if (index === keys.length - 1) nestedForm[key2] = value;
|
|
56
|
+
else {
|
|
130
57
|
if (!nestedForm[key2] || typeof nestedForm[key2] !== "object" || Array.isArray(nestedForm[key2]) || nestedForm[key2] instanceof File) {
|
|
58
|
+
if (state2.count++ >= MAX_NESTED_OBJECTS) throwNestingLimitExceeded();
|
|
131
59
|
nestedForm[key2] = /* @__PURE__ */ Object.create(null);
|
|
132
60
|
}
|
|
133
61
|
nestedForm = nestedForm[key2];
|
|
134
62
|
}
|
|
135
63
|
});
|
|
136
64
|
};
|
|
137
|
-
|
|
65
|
+
const throwNestingLimitExceeded = () => {
|
|
66
|
+
throw new Error("Nesting limit exceeded");
|
|
67
|
+
};
|
|
68
|
+
const splitPath = (path) => {
|
|
138
69
|
const paths = path.split("/");
|
|
139
|
-
if (paths[0] === "")
|
|
140
|
-
paths.shift();
|
|
141
|
-
}
|
|
70
|
+
if (paths[0] === "") paths.shift();
|
|
142
71
|
return paths;
|
|
143
72
|
};
|
|
144
|
-
|
|
73
|
+
const splitRoutingPath = (routePath) => {
|
|
145
74
|
const { groups, path } = extractGroupsFromPath(routePath);
|
|
146
75
|
const paths = splitPath(path);
|
|
147
76
|
return replaceGroupMarks(paths, groups);
|
|
148
77
|
};
|
|
149
|
-
|
|
78
|
+
const extractGroupsFromPath = (path) => {
|
|
150
79
|
const groups = [];
|
|
151
80
|
path = path.replace(/\{[^}]+\}/g, (match2, index) => {
|
|
152
81
|
const mark = `@${index}`;
|
|
153
82
|
groups.push([mark, match2]);
|
|
154
83
|
return mark;
|
|
155
84
|
});
|
|
156
|
-
return {
|
|
85
|
+
return {
|
|
86
|
+
groups,
|
|
87
|
+
path
|
|
88
|
+
};
|
|
157
89
|
};
|
|
158
|
-
|
|
90
|
+
const replaceGroupMarks = (paths, groups) => {
|
|
159
91
|
for (let i = groups.length - 1; i >= 0; i--) {
|
|
160
92
|
const [mark] = groups[i];
|
|
161
|
-
for (let j = paths.length - 1; j >= 0; j--) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
break;
|
|
165
|
-
}
|
|
93
|
+
for (let j = paths.length - 1; j >= 0; j--) if (paths[j].includes(mark)) {
|
|
94
|
+
paths[j] = paths[j].replace(mark, groups[i][1]);
|
|
95
|
+
break;
|
|
166
96
|
}
|
|
167
97
|
}
|
|
168
98
|
return paths;
|
|
169
99
|
};
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (label === "*")
|
|
173
|
-
return "*";
|
|
174
|
-
}
|
|
100
|
+
const patternCache = {};
|
|
101
|
+
const getPattern = (label, next) => {
|
|
102
|
+
if (label === "*") return "*";
|
|
175
103
|
const match2 = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
|
|
176
104
|
if (match2) {
|
|
177
105
|
const cacheKey = `${label}#${next}`;
|
|
178
106
|
if (!patternCache[cacheKey]) {
|
|
179
|
-
if (match2[2])
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
107
|
+
if (match2[2]) patternCache[cacheKey] = next && next[0] !== ":" && next[0] !== "*" ? [
|
|
108
|
+
cacheKey,
|
|
109
|
+
match2[1],
|
|
110
|
+
new RegExp(`^${match2[2]}(?=/${next})`)
|
|
111
|
+
] : [
|
|
112
|
+
label,
|
|
113
|
+
match2[1],
|
|
114
|
+
new RegExp(`^${match2[2]}$`)
|
|
115
|
+
];
|
|
116
|
+
else patternCache[cacheKey] = [
|
|
117
|
+
label,
|
|
118
|
+
match2[1],
|
|
119
|
+
true
|
|
120
|
+
];
|
|
184
121
|
}
|
|
185
122
|
return patternCache[cacheKey];
|
|
186
123
|
}
|
|
187
124
|
return null;
|
|
188
125
|
};
|
|
189
|
-
|
|
126
|
+
const tryDecode = (str, decoder2) => {
|
|
190
127
|
try {
|
|
191
128
|
return decoder2(str);
|
|
192
129
|
} catch {
|
|
@@ -199,8 +136,8 @@ var tryDecode = (str, decoder2) => {
|
|
|
199
136
|
});
|
|
200
137
|
}
|
|
201
138
|
};
|
|
202
|
-
|
|
203
|
-
|
|
139
|
+
const tryDecodeURI = (str) => tryDecode(str, decodeURI);
|
|
140
|
+
const getPath$1 = (request) => {
|
|
204
141
|
const url = request.url;
|
|
205
142
|
const start = url.indexOf("/", url.indexOf(":") + 4);
|
|
206
143
|
let i = start;
|
|
@@ -212,81 +149,66 @@ var getPath$1 = (request) => {
|
|
|
212
149
|
const end = queryIndex === -1 ? hashIndex === -1 ? void 0 : hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex);
|
|
213
150
|
const path = url.slice(start, end);
|
|
214
151
|
return tryDecodeURI(path.includes("%25") ? path.replace(/%25/g, "%2525") : path);
|
|
215
|
-
} else if (charCode === 63 || charCode === 35)
|
|
216
|
-
break;
|
|
217
|
-
}
|
|
152
|
+
} else if (charCode === 63 || charCode === 35) break;
|
|
218
153
|
}
|
|
219
154
|
return url.slice(start, i);
|
|
220
155
|
};
|
|
221
|
-
|
|
156
|
+
const getPathNoStrict = (request) => {
|
|
222
157
|
const result = getPath$1(request);
|
|
223
158
|
return result.length > 1 && result.at(-1) === "/" ? result.slice(0, -1) : result;
|
|
224
159
|
};
|
|
225
|
-
|
|
226
|
-
if (rest.length)
|
|
227
|
-
sub = mergePath(sub, ...rest);
|
|
228
|
-
}
|
|
160
|
+
const mergePath = (base, sub, ...rest) => {
|
|
161
|
+
if (rest.length) sub = mergePath(sub, ...rest);
|
|
229
162
|
return `${base?.[0] === "/" ? "" : "/"}${base}${sub === "/" ? "" : `${base?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`;
|
|
230
163
|
};
|
|
231
|
-
|
|
232
|
-
if (path.charCodeAt(path.length - 1) !== 63 || !path.includes(":"))
|
|
233
|
-
return null;
|
|
234
|
-
}
|
|
164
|
+
const checkOptionalParameter = (path) => {
|
|
165
|
+
if (path.charCodeAt(path.length - 1) !== 63 || !path.includes(":")) return null;
|
|
235
166
|
const segments = path.split("/");
|
|
236
167
|
const results = [];
|
|
237
168
|
let basePath = "";
|
|
238
169
|
segments.forEach((segment) => {
|
|
239
|
-
if (segment !== "" && !/\:/.test(segment))
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
} else {
|
|
246
|
-
results.push(basePath);
|
|
247
|
-
}
|
|
248
|
-
const optionalSegment = segment.replace("?", "");
|
|
170
|
+
if (segment !== "" && !/\:/.test(segment)) basePath += "/" + segment;
|
|
171
|
+
else if (/\:/.test(segment)) {
|
|
172
|
+
if (segment.charCodeAt(segment.length - 1) === 63) {
|
|
173
|
+
if (results.length === 0 && basePath === "") results.push("/");
|
|
174
|
+
else results.push(basePath);
|
|
175
|
+
const optionalSegment = segment.slice(0, -1);
|
|
249
176
|
basePath += "/" + optionalSegment;
|
|
250
177
|
results.push(basePath);
|
|
251
|
-
} else
|
|
252
|
-
basePath += "/" + segment;
|
|
253
|
-
}
|
|
178
|
+
} else basePath += "/" + segment;
|
|
254
179
|
}
|
|
255
180
|
});
|
|
256
181
|
return results.filter((v, i, a) => a.indexOf(v) === i);
|
|
257
182
|
};
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
if (value.indexOf("+") !== -1)
|
|
261
|
-
value = value.replace(/\+/g, " ");
|
|
262
|
-
}
|
|
183
|
+
const tryDecodeURIComponent = (str) => str.indexOf("%") !== -1 ? tryDecode(str, decodeURIComponent_) : str;
|
|
184
|
+
const _decodeURI = (value) => {
|
|
185
|
+
if (value.indexOf("+") !== -1) value = value.replace(/\+/g, " ");
|
|
263
186
|
return tryDecodeURIComponent(value);
|
|
264
187
|
};
|
|
265
|
-
|
|
188
|
+
const _getQueryParam = (url, key, multiple) => {
|
|
189
|
+
const hashIndex = url.indexOf("#", 8);
|
|
190
|
+
if (hashIndex !== -1) url = url.slice(0, hashIndex);
|
|
266
191
|
let encoded;
|
|
267
192
|
if (!multiple && key && key.indexOf("%") === -1 && key.indexOf("+") === -1) {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
272
|
-
if (!url.startsWith(key, keyIndex2 + 1)) {
|
|
273
|
-
keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
|
|
274
|
-
}
|
|
193
|
+
const queryIndex = url.indexOf("?", 8);
|
|
194
|
+
let keyIndex2 = queryIndex;
|
|
195
|
+
if (keyIndex2 === -1) return;
|
|
196
|
+
if (!url.startsWith(key, keyIndex2 + 1)) keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
|
|
275
197
|
while (keyIndex2 !== -1) {
|
|
276
198
|
const trailingKeyCode = url.charCodeAt(keyIndex2 + key.length + 1);
|
|
277
|
-
if (trailingKeyCode === 61) {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
199
|
+
if (trailingKeyCode === 61 || trailingKeyCode === 38 || isNaN(trailingKeyCode)) {
|
|
200
|
+
if (keyIndex2 > queryIndex && /(?:^|&)[^=&]*[%+]/.test(url.slice(queryIndex + 1, keyIndex2))) break;
|
|
201
|
+
if (trailingKeyCode === 61) {
|
|
202
|
+
const valueIndex = keyIndex2 + key.length + 2;
|
|
203
|
+
const endIndex = url.indexOf("&", valueIndex);
|
|
204
|
+
return _decodeURI(url.slice(valueIndex, endIndex === -1 ? void 0 : endIndex));
|
|
205
|
+
}
|
|
282
206
|
return "";
|
|
283
207
|
}
|
|
284
208
|
keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
|
|
285
209
|
}
|
|
286
210
|
encoded = /[%+]/.test(url);
|
|
287
|
-
if (!encoded)
|
|
288
|
-
return void 0;
|
|
289
|
-
}
|
|
211
|
+
if (!encoded) return;
|
|
290
212
|
}
|
|
291
213
|
const results = /* @__PURE__ */ Object.create(null);
|
|
292
214
|
encoded ??= /[%+]/.test(url);
|
|
@@ -294,77 +216,60 @@ var _getQueryParam = (url, key, multiple) => {
|
|
|
294
216
|
while (keyIndex !== -1) {
|
|
295
217
|
const nextKeyIndex = url.indexOf("&", keyIndex + 1);
|
|
296
218
|
let valueIndex = url.indexOf("=", keyIndex);
|
|
297
|
-
if (valueIndex > nextKeyIndex && nextKeyIndex !== -1)
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
let name = url.slice(
|
|
301
|
-
keyIndex + 1,
|
|
302
|
-
valueIndex === -1 ? nextKeyIndex === -1 ? void 0 : nextKeyIndex : valueIndex
|
|
303
|
-
);
|
|
304
|
-
if (encoded) {
|
|
305
|
-
name = _decodeURI(name);
|
|
306
|
-
}
|
|
219
|
+
if (valueIndex > nextKeyIndex && nextKeyIndex !== -1) valueIndex = -1;
|
|
220
|
+
let name = url.slice(keyIndex + 1, valueIndex === -1 ? nextKeyIndex === -1 ? void 0 : nextKeyIndex : valueIndex);
|
|
221
|
+
if (encoded) name = _decodeURI(name);
|
|
307
222
|
keyIndex = nextKeyIndex;
|
|
308
|
-
if (name === "")
|
|
309
|
-
continue;
|
|
310
|
-
}
|
|
223
|
+
if (name === "") continue;
|
|
311
224
|
let value;
|
|
312
|
-
if (valueIndex === -1)
|
|
313
|
-
|
|
314
|
-
} else {
|
|
225
|
+
if (valueIndex === -1) value = "";
|
|
226
|
+
else {
|
|
315
227
|
value = url.slice(valueIndex + 1, nextKeyIndex === -1 ? void 0 : nextKeyIndex);
|
|
316
|
-
if (encoded)
|
|
317
|
-
value = _decodeURI(value);
|
|
318
|
-
}
|
|
228
|
+
if (encoded) value = _decodeURI(value);
|
|
319
229
|
}
|
|
320
230
|
if (multiple) {
|
|
321
|
-
if (!(results[name] && Array.isArray(results[name])))
|
|
322
|
-
results[name] = [];
|
|
323
|
-
}
|
|
231
|
+
if (!(results[name] && Array.isArray(results[name]))) results[name] = [];
|
|
324
232
|
results[name].push(value);
|
|
325
|
-
} else
|
|
326
|
-
results[name] ??= value;
|
|
327
|
-
}
|
|
233
|
+
} else results[name] ??= value;
|
|
328
234
|
}
|
|
329
235
|
return key ? results[key] : results;
|
|
330
236
|
};
|
|
331
|
-
|
|
332
|
-
|
|
237
|
+
const getQueryParam = _getQueryParam;
|
|
238
|
+
const getQueryParams = (url, key) => {
|
|
333
239
|
return _getQueryParam(url, key, true);
|
|
334
240
|
};
|
|
335
|
-
|
|
241
|
+
const decodeURIComponent_ = decodeURIComponent;
|
|
336
242
|
var HonoRequest = class {
|
|
337
243
|
/**
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
244
|
+
* `.raw` can get the raw Request object.
|
|
245
|
+
*
|
|
246
|
+
* @see {@link https://hono.dev/docs/api/request#raw}
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* ```ts
|
|
250
|
+
* // For Cloudflare Workers
|
|
251
|
+
* app.post('/', async (c) => {
|
|
252
|
+
* const metadata = c.req.raw.cf?.hostMetadata?
|
|
253
|
+
* ...
|
|
254
|
+
* })
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
351
257
|
raw;
|
|
352
258
|
#validatedData;
|
|
353
|
-
// Short name of validatedData
|
|
354
259
|
#matchResult;
|
|
355
260
|
routeIndex = 0;
|
|
356
261
|
/**
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
262
|
+
* `.path` can get the pathname of the request.
|
|
263
|
+
*
|
|
264
|
+
* @see {@link https://hono.dev/docs/api/request#path}
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```ts
|
|
268
|
+
* app.get('/about/me', (c) => {
|
|
269
|
+
* const pathname = c.req.path // `/about/me`
|
|
270
|
+
* })
|
|
271
|
+
* ```
|
|
272
|
+
*/
|
|
368
273
|
path;
|
|
369
274
|
bodyCache = {};
|
|
370
275
|
constructor(request, path = "/", matchResult = [[]]) {
|
|
@@ -376,18 +281,16 @@ var HonoRequest = class {
|
|
|
376
281
|
return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams();
|
|
377
282
|
}
|
|
378
283
|
#getDecodedParam(key) {
|
|
379
|
-
const paramKey = this.#matchResult[0][this.routeIndex][1][key];
|
|
284
|
+
const paramKey = this.#matchResult[0][this.routeIndex]?.[1][key];
|
|
380
285
|
const param = this.#getParamValue(paramKey);
|
|
381
286
|
return param && tryDecodeURIComponent(param);
|
|
382
287
|
}
|
|
383
288
|
#getAllDecodedParams() {
|
|
384
289
|
const decoded = {};
|
|
385
|
-
const keys = Object.keys(this.#matchResult[0][this.routeIndex][1]);
|
|
290
|
+
const keys = Object.keys(this.#matchResult[0][this.routeIndex]?.[1] ?? {});
|
|
386
291
|
for (const key of keys) {
|
|
387
292
|
const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]);
|
|
388
|
-
if (value !== void 0)
|
|
389
|
-
decoded[key] = tryDecodeURIComponent(value);
|
|
390
|
-
}
|
|
293
|
+
if (value !== void 0) decoded[key] = tryDecodeURIComponent(value);
|
|
391
294
|
}
|
|
392
295
|
return decoded;
|
|
393
296
|
}
|
|
@@ -401,9 +304,7 @@ var HonoRequest = class {
|
|
|
401
304
|
return getQueryParams(this.url, key);
|
|
402
305
|
}
|
|
403
306
|
header(name) {
|
|
404
|
-
if (name)
|
|
405
|
-
return this.raw.headers.get(name) ?? void 0;
|
|
406
|
-
}
|
|
307
|
+
if (name) return this.raw.headers.get(name) ?? void 0;
|
|
407
308
|
const headerData = /* @__PURE__ */ Object.create(null);
|
|
408
309
|
this.raw.headers.forEach((value, key) => {
|
|
409
310
|
headerData[key] = value;
|
|
@@ -416,111 +317,106 @@ var HonoRequest = class {
|
|
|
416
317
|
#cachedBody = (key) => {
|
|
417
318
|
const { bodyCache, raw } = this;
|
|
418
319
|
const cachedBody = bodyCache[key];
|
|
419
|
-
if (cachedBody)
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
return
|
|
424
|
-
|
|
425
|
-
body = JSON.stringify(body);
|
|
426
|
-
}
|
|
427
|
-
return new Response(body)[key]();
|
|
428
|
-
});
|
|
429
|
-
}
|
|
320
|
+
if (cachedBody) return cachedBody;
|
|
321
|
+
for (const anyCachedKey in bodyCache) return bodyCache[anyCachedKey].then((body) => {
|
|
322
|
+
if (anyCachedKey === "json") body = JSON.stringify(body);
|
|
323
|
+
const contentType = anyCachedKey === "formData" ? void 0 : raw.headers.get("content-type");
|
|
324
|
+
return new Response(body, { headers: contentType ? { "Content-Type": contentType } : void 0 })[key]();
|
|
325
|
+
});
|
|
430
326
|
return bodyCache[key] = raw[key]();
|
|
431
327
|
};
|
|
432
328
|
/**
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
329
|
+
* `.json()` can parse Request body of type `application/json`
|
|
330
|
+
*
|
|
331
|
+
* @see {@link https://hono.dev/docs/api/request#json}
|
|
332
|
+
*
|
|
333
|
+
* @example
|
|
334
|
+
* ```ts
|
|
335
|
+
* app.post('/entry', async (c) => {
|
|
336
|
+
* const body = await c.req.json()
|
|
337
|
+
* })
|
|
338
|
+
* ```
|
|
339
|
+
*/
|
|
444
340
|
json() {
|
|
445
341
|
return this.#cachedBody("text").then((text) => JSON.parse(text));
|
|
446
342
|
}
|
|
447
343
|
/**
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
344
|
+
* `.text()` can parse Request body of type `text/plain`
|
|
345
|
+
*
|
|
346
|
+
* @see {@link https://hono.dev/docs/api/request#text}
|
|
347
|
+
*
|
|
348
|
+
* @example
|
|
349
|
+
* ```ts
|
|
350
|
+
* app.post('/entry', async (c) => {
|
|
351
|
+
* const body = await c.req.text()
|
|
352
|
+
* })
|
|
353
|
+
* ```
|
|
354
|
+
*/
|
|
459
355
|
text() {
|
|
460
356
|
return this.#cachedBody("text");
|
|
461
357
|
}
|
|
462
358
|
/**
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
359
|
+
* `.arrayBuffer()` parse Request body as an `ArrayBuffer`
|
|
360
|
+
*
|
|
361
|
+
* @see {@link https://hono.dev/docs/api/request#arraybuffer}
|
|
362
|
+
*
|
|
363
|
+
* @example
|
|
364
|
+
* ```ts
|
|
365
|
+
* app.post('/entry', async (c) => {
|
|
366
|
+
* const body = await c.req.arrayBuffer()
|
|
367
|
+
* })
|
|
368
|
+
* ```
|
|
369
|
+
*/
|
|
474
370
|
arrayBuffer() {
|
|
475
371
|
return this.#cachedBody("arrayBuffer");
|
|
476
372
|
}
|
|
477
373
|
/**
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
374
|
+
* `.bytes()` parses the request body as a `Uint8Array`.
|
|
375
|
+
*
|
|
376
|
+
* @see {@link https://hono.dev/docs/api/request#bytes}
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* ```ts
|
|
380
|
+
* app.post('/entry', async (c) => {
|
|
381
|
+
* const body = await c.req.bytes()
|
|
382
|
+
* })
|
|
383
|
+
* ```
|
|
384
|
+
*/
|
|
489
385
|
bytes() {
|
|
490
386
|
return this.#cachedBody("arrayBuffer").then((buffer) => new Uint8Array(buffer));
|
|
491
387
|
}
|
|
492
388
|
/**
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
389
|
+
* Parses the request body as a `Blob`.
|
|
390
|
+
* @example
|
|
391
|
+
* ```ts
|
|
392
|
+
* app.post('/entry', async (c) => {
|
|
393
|
+
* const body = await c.req.blob();
|
|
394
|
+
* });
|
|
395
|
+
* ```
|
|
396
|
+
* @see https://hono.dev/docs/api/request#blob
|
|
397
|
+
*/
|
|
502
398
|
blob() {
|
|
503
399
|
return this.#cachedBody("blob");
|
|
504
400
|
}
|
|
505
401
|
/**
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
402
|
+
* Parses the request body as `FormData`.
|
|
403
|
+
* @example
|
|
404
|
+
* ```ts
|
|
405
|
+
* app.post('/entry', async (c) => {
|
|
406
|
+
* const body = await c.req.formData();
|
|
407
|
+
* });
|
|
408
|
+
* ```
|
|
409
|
+
* @see https://hono.dev/docs/api/request#formdata
|
|
410
|
+
*/
|
|
515
411
|
formData() {
|
|
516
412
|
return this.#cachedBody("formData");
|
|
517
413
|
}
|
|
518
414
|
/**
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
415
|
+
* Adds validated data to the request.
|
|
416
|
+
*
|
|
417
|
+
* @param target - The target of the validation.
|
|
418
|
+
* @param data - The validated data to add.
|
|
419
|
+
*/
|
|
524
420
|
addValidatedData(target, data) {
|
|
525
421
|
(this.#validatedData ??= {})[target] = data;
|
|
526
422
|
}
|
|
@@ -528,33 +424,33 @@ var HonoRequest = class {
|
|
|
528
424
|
return this.#validatedData?.[target];
|
|
529
425
|
}
|
|
530
426
|
/**
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
427
|
+
* `.url` can get the request url strings.
|
|
428
|
+
*
|
|
429
|
+
* @see {@link https://hono.dev/docs/api/request#url}
|
|
430
|
+
*
|
|
431
|
+
* @example
|
|
432
|
+
* ```ts
|
|
433
|
+
* app.get('/about/me', (c) => {
|
|
434
|
+
* const url = c.req.url // `http://localhost:8787/about/me`
|
|
435
|
+
* ...
|
|
436
|
+
* })
|
|
437
|
+
* ```
|
|
438
|
+
*/
|
|
543
439
|
get url() {
|
|
544
440
|
return this.raw.url;
|
|
545
441
|
}
|
|
546
442
|
/**
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
443
|
+
* `.method` can get the method name of the request.
|
|
444
|
+
*
|
|
445
|
+
* @see {@link https://hono.dev/docs/api/request#method}
|
|
446
|
+
*
|
|
447
|
+
* @example
|
|
448
|
+
* ```ts
|
|
449
|
+
* app.get('/about/me', (c) => {
|
|
450
|
+
* const method = c.req.method // `GET`
|
|
451
|
+
* })
|
|
452
|
+
* ```
|
|
453
|
+
*/
|
|
558
454
|
get method() {
|
|
559
455
|
return this.raw.method;
|
|
560
456
|
}
|
|
@@ -562,127 +458,116 @@ var HonoRequest = class {
|
|
|
562
458
|
return this.#matchResult;
|
|
563
459
|
}
|
|
564
460
|
/**
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
461
|
+
* `.matchedRoutes` can return a matched route in the handler
|
|
462
|
+
*
|
|
463
|
+
* @deprecated
|
|
464
|
+
*
|
|
465
|
+
* Use matchedRoutes helper defined in "hono/route" instead.
|
|
466
|
+
*
|
|
467
|
+
* @see {@link https://hono.dev/docs/api/request#matchedroutes}
|
|
468
|
+
*
|
|
469
|
+
* @example
|
|
470
|
+
* ```ts
|
|
471
|
+
* app.use('*', async function logger(c, next) {
|
|
472
|
+
* await next()
|
|
473
|
+
* c.req.matchedRoutes.forEach(({ handler, method, path }, i) => {
|
|
474
|
+
* const name = handler.name || (handler.length < 2 ? '[handler]' : '[middleware]')
|
|
475
|
+
* console.log(
|
|
476
|
+
* method,
|
|
477
|
+
* ' ',
|
|
478
|
+
* path,
|
|
479
|
+
* ' '.repeat(Math.max(10 - path.length, 0)),
|
|
480
|
+
* name,
|
|
481
|
+
* i === c.req.routeIndex ? '<- respond from here' : ''
|
|
482
|
+
* )
|
|
483
|
+
* })
|
|
484
|
+
* })
|
|
485
|
+
* ```
|
|
486
|
+
*/
|
|
591
487
|
get matchedRoutes() {
|
|
592
488
|
return this.#matchResult[0].map(([[, route]]) => route);
|
|
593
489
|
}
|
|
594
490
|
/**
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
491
|
+
* `.routePath` can retrieve the path registered within the handler
|
|
492
|
+
*
|
|
493
|
+
* @deprecated
|
|
494
|
+
*
|
|
495
|
+
* Use routePath helper defined in "hono/route" instead.
|
|
496
|
+
*
|
|
497
|
+
* @see {@link https://hono.dev/docs/api/request#routepath}
|
|
498
|
+
*
|
|
499
|
+
* @example
|
|
500
|
+
* ```ts
|
|
501
|
+
* app.get('/posts/:id', (c) => {
|
|
502
|
+
* return c.json({ path: c.req.routePath })
|
|
503
|
+
* })
|
|
504
|
+
* ```
|
|
505
|
+
*/
|
|
610
506
|
get routePath() {
|
|
611
507
|
return this.#matchResult[0].map(([[, route]]) => route)[this.routeIndex].path;
|
|
612
508
|
}
|
|
613
509
|
};
|
|
614
|
-
|
|
510
|
+
const HtmlEscapedCallbackPhase = {
|
|
615
511
|
Stringify: 1
|
|
616
512
|
};
|
|
617
|
-
|
|
513
|
+
const resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
|
|
618
514
|
if (typeof str === "object" && !(str instanceof String)) {
|
|
619
|
-
if (!(str instanceof Promise))
|
|
620
|
-
|
|
621
|
-
}
|
|
622
|
-
if (str instanceof Promise) {
|
|
623
|
-
str = await str;
|
|
624
|
-
}
|
|
515
|
+
if (!(str instanceof Promise)) str = str.toString();
|
|
516
|
+
if (str instanceof Promise) str = await str;
|
|
625
517
|
}
|
|
626
518
|
const callbacks = str.callbacks;
|
|
627
|
-
if (!callbacks?.length)
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
(res) => Promise.all(
|
|
637
|
-
res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false, context, buffer))
|
|
638
|
-
).then(() => buffer[0])
|
|
639
|
-
);
|
|
640
|
-
{
|
|
641
|
-
return resStr;
|
|
642
|
-
}
|
|
519
|
+
if (!callbacks?.length) return Promise.resolve(str);
|
|
520
|
+
if (buffer) buffer[0] += str;
|
|
521
|
+
else buffer = [str];
|
|
522
|
+
const resStr = Promise.all(callbacks.map((c) => c({
|
|
523
|
+
phase,
|
|
524
|
+
buffer,
|
|
525
|
+
context
|
|
526
|
+
}))).then((res) => Promise.all(res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false, context, buffer))).then(() => buffer[0]));
|
|
527
|
+
return resStr;
|
|
643
528
|
};
|
|
644
|
-
|
|
645
|
-
|
|
529
|
+
const TEXT_PLAIN = "text/plain; charset=UTF-8";
|
|
530
|
+
const setDefaultContentType = (contentType, headers) => {
|
|
646
531
|
return {
|
|
647
532
|
"Content-Type": contentType,
|
|
648
533
|
...headers
|
|
649
534
|
};
|
|
650
535
|
};
|
|
651
|
-
|
|
536
|
+
const createResponseInstance = (body, init) => new Response(body, init);
|
|
652
537
|
var Context = class {
|
|
653
538
|
#rawRequest;
|
|
654
539
|
#req;
|
|
655
540
|
/**
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
541
|
+
* `.env` can get bindings (environment variables, secrets, KV namespaces, D1 database, R2 bucket etc.) in Cloudflare Workers.
|
|
542
|
+
*
|
|
543
|
+
* @see {@link https://hono.dev/docs/api/context#env}
|
|
544
|
+
*
|
|
545
|
+
* @example
|
|
546
|
+
* ```ts
|
|
547
|
+
* // Environment object for Cloudflare Workers
|
|
548
|
+
* app.get('*', async c => {
|
|
549
|
+
* const counter = c.env.COUNTER
|
|
550
|
+
* })
|
|
551
|
+
* ```
|
|
552
|
+
*/
|
|
668
553
|
env = {};
|
|
669
554
|
#var;
|
|
670
555
|
finalized = false;
|
|
671
556
|
/**
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
557
|
+
* `.error` can get the error object from the middleware if the Handler throws an error.
|
|
558
|
+
*
|
|
559
|
+
* @see {@link https://hono.dev/docs/api/context#error}
|
|
560
|
+
*
|
|
561
|
+
* @example
|
|
562
|
+
* ```ts
|
|
563
|
+
* app.use('*', async (c, next) => {
|
|
564
|
+
* await next()
|
|
565
|
+
* if (c.error) {
|
|
566
|
+
* // do something...
|
|
567
|
+
* }
|
|
568
|
+
* })
|
|
569
|
+
* ```
|
|
570
|
+
*/
|
|
686
571
|
error;
|
|
687
572
|
#status;
|
|
688
573
|
#executionCtx;
|
|
@@ -694,11 +579,11 @@ var Context = class {
|
|
|
694
579
|
#matchResult;
|
|
695
580
|
#path;
|
|
696
581
|
/**
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
582
|
+
* Creates an instance of the Context class.
|
|
583
|
+
*
|
|
584
|
+
* @param req - The Request object.
|
|
585
|
+
* @param options - Optional configuration options for the context.
|
|
586
|
+
*/
|
|
702
587
|
constructor(req, options) {
|
|
703
588
|
this.#rawRequest = req;
|
|
704
589
|
if (options) {
|
|
@@ -710,241 +595,210 @@ var Context = class {
|
|
|
710
595
|
}
|
|
711
596
|
}
|
|
712
597
|
/**
|
|
713
|
-
|
|
714
|
-
|
|
598
|
+
* `.req` is the instance of {@link HonoRequest}.
|
|
599
|
+
*/
|
|
715
600
|
get req() {
|
|
716
601
|
this.#req ??= new HonoRequest(this.#rawRequest, this.#path, this.#matchResult);
|
|
717
602
|
return this.#req;
|
|
718
603
|
}
|
|
719
604
|
/**
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
605
|
+
* @see {@link https://hono.dev/docs/api/context#event}
|
|
606
|
+
* The FetchEvent associated with the current request.
|
|
607
|
+
*
|
|
608
|
+
* @throws Will throw an error if the context does not have a FetchEvent.
|
|
609
|
+
*/
|
|
725
610
|
get event() {
|
|
726
|
-
if (this.#executionCtx && "respondWith" in this.#executionCtx)
|
|
727
|
-
|
|
728
|
-
} else {
|
|
729
|
-
throw Error("This context has no FetchEvent");
|
|
730
|
-
}
|
|
611
|
+
if (this.#executionCtx && "respondWith" in this.#executionCtx) return this.#executionCtx;
|
|
612
|
+
else throw Error("This context has no FetchEvent");
|
|
731
613
|
}
|
|
732
614
|
/**
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
615
|
+
* @see {@link https://hono.dev/docs/api/context#executionctx}
|
|
616
|
+
* The ExecutionContext associated with the current request.
|
|
617
|
+
*
|
|
618
|
+
* @throws Will throw an error if the context does not have an ExecutionContext.
|
|
619
|
+
*/
|
|
738
620
|
get executionCtx() {
|
|
739
|
-
if (this.#executionCtx)
|
|
740
|
-
|
|
741
|
-
} else {
|
|
742
|
-
throw Error("This context has no ExecutionContext");
|
|
743
|
-
}
|
|
621
|
+
if (this.#executionCtx) return this.#executionCtx;
|
|
622
|
+
else throw Error("This context has no ExecutionContext");
|
|
744
623
|
}
|
|
745
624
|
/**
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
625
|
+
* @see {@link https://hono.dev/docs/api/context#res}
|
|
626
|
+
* The Response object for the current request.
|
|
627
|
+
*/
|
|
749
628
|
get res() {
|
|
750
|
-
return this.#res ||= createResponseInstance(null, {
|
|
751
|
-
headers: this.#preparedHeaders ??= new Headers()
|
|
752
|
-
});
|
|
629
|
+
return this.#res ||= createResponseInstance(null, { headers: this.#preparedHeaders ??= new Headers() });
|
|
753
630
|
}
|
|
754
631
|
/**
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
632
|
+
* Sets the Response object for the current request.
|
|
633
|
+
*
|
|
634
|
+
* @param _res - The Response object to set.
|
|
635
|
+
*/
|
|
759
636
|
set res(_res) {
|
|
760
637
|
if (this.#res && _res) {
|
|
761
638
|
_res = createResponseInstance(_res.body, _res);
|
|
762
639
|
for (const [k, v] of this.#res.headers.entries()) {
|
|
763
|
-
if (k === "content-type")
|
|
764
|
-
continue;
|
|
765
|
-
}
|
|
640
|
+
if (k === "content-type") continue;
|
|
766
641
|
if (k === "set-cookie") {
|
|
767
642
|
const cookies = this.#res.headers.getSetCookie();
|
|
768
643
|
_res.headers.delete("set-cookie");
|
|
769
|
-
for (const cookie of cookies)
|
|
770
|
-
|
|
771
|
-
}
|
|
772
|
-
} else {
|
|
773
|
-
_res.headers.set(k, v);
|
|
774
|
-
}
|
|
644
|
+
for (const cookie of cookies) _res.headers.append("set-cookie", cookie);
|
|
645
|
+
} else _res.headers.set(k, v);
|
|
775
646
|
}
|
|
776
647
|
}
|
|
777
648
|
this.#res = _res;
|
|
778
649
|
this.finalized = true;
|
|
779
650
|
}
|
|
780
651
|
/**
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
652
|
+
* `.render()` can create a response within a layout.
|
|
653
|
+
*
|
|
654
|
+
* @see {@link https://hono.dev/docs/api/context#render-setrenderer}
|
|
655
|
+
*
|
|
656
|
+
* @example
|
|
657
|
+
* ```ts
|
|
658
|
+
* app.get('/', (c) => {
|
|
659
|
+
* return c.render('Hello!')
|
|
660
|
+
* })
|
|
661
|
+
* ```
|
|
662
|
+
*/
|
|
792
663
|
render = (...args) => {
|
|
793
664
|
this.#renderer ??= (content) => this.html(content);
|
|
794
665
|
return this.#renderer(...args);
|
|
795
666
|
};
|
|
796
667
|
/**
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
668
|
+
* Sets the layout for the response.
|
|
669
|
+
*
|
|
670
|
+
* @param layout - The layout to set.
|
|
671
|
+
* @returns The layout function.
|
|
672
|
+
*/
|
|
802
673
|
setLayout = (layout) => this.#layout = layout;
|
|
803
674
|
/**
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
675
|
+
* Gets the current layout for the response.
|
|
676
|
+
*
|
|
677
|
+
* @returns The current layout function.
|
|
678
|
+
*/
|
|
808
679
|
getLayout = () => this.#layout;
|
|
809
680
|
/**
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
681
|
+
* `.setRenderer()` can set the layout in the custom middleware.
|
|
682
|
+
*
|
|
683
|
+
* @see {@link https://hono.dev/docs/api/context#render-setrenderer}
|
|
684
|
+
*
|
|
685
|
+
* @example
|
|
686
|
+
* ```tsx
|
|
687
|
+
* app.use('*', async (c, next) => {
|
|
688
|
+
* c.setRenderer((content) => {
|
|
689
|
+
* return c.html(
|
|
690
|
+
* <html>
|
|
691
|
+
* <body>
|
|
692
|
+
* <p>{content}</p>
|
|
693
|
+
* </body>
|
|
694
|
+
* </html>
|
|
695
|
+
* )
|
|
696
|
+
* })
|
|
697
|
+
* await next()
|
|
698
|
+
* })
|
|
699
|
+
* ```
|
|
700
|
+
*/
|
|
830
701
|
setRenderer = (renderer) => {
|
|
831
702
|
this.#renderer = renderer;
|
|
832
703
|
};
|
|
833
704
|
/**
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
705
|
+
* `.header()` can set headers.
|
|
706
|
+
*
|
|
707
|
+
* @see {@link https://hono.dev/docs/api/context#header}
|
|
708
|
+
*
|
|
709
|
+
* @example
|
|
710
|
+
* ```ts
|
|
711
|
+
* app.get('/welcome', (c) => {
|
|
712
|
+
* // Set headers
|
|
713
|
+
* c.header('X-Message', 'Hello!')
|
|
714
|
+
* c.header('Content-Type', 'text/plain')
|
|
715
|
+
*
|
|
716
|
+
* // Append multiple headers using the append option (e.g. Vary)
|
|
717
|
+
* c.header('Vary', 'Accept-Encoding', { append: true })
|
|
718
|
+
* c.header('Vary', 'User-Agent', { append: true })
|
|
719
|
+
*
|
|
720
|
+
* return c.body('Thank you for coming')
|
|
721
|
+
* })
|
|
722
|
+
* ```
|
|
723
|
+
*/
|
|
849
724
|
header = (name, value, options) => {
|
|
850
|
-
if (this.finalized)
|
|
851
|
-
this.#res = createResponseInstance(this.#res.body, this.#res);
|
|
852
|
-
}
|
|
725
|
+
if (this.finalized) this.#res = createResponseInstance(this.#res.body, this.#res);
|
|
853
726
|
const headers = this.#res ? this.#res.headers : this.#preparedHeaders ??= new Headers();
|
|
854
|
-
if (value === void 0)
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
headers.append(name, value);
|
|
858
|
-
} else {
|
|
859
|
-
headers.set(name, value);
|
|
860
|
-
}
|
|
727
|
+
if (value === void 0) headers.delete(name);
|
|
728
|
+
else if (options?.append) headers.append(name, value);
|
|
729
|
+
else headers.set(name, value);
|
|
861
730
|
};
|
|
862
731
|
status = (status) => {
|
|
863
732
|
this.#status = status;
|
|
864
733
|
};
|
|
865
734
|
/**
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
735
|
+
* `.set()` can set the value specified by the key.
|
|
736
|
+
*
|
|
737
|
+
* @see {@link https://hono.dev/docs/api/context#set-get}
|
|
738
|
+
*
|
|
739
|
+
* @example
|
|
740
|
+
* ```ts
|
|
741
|
+
* app.use('*', async (c, next) => {
|
|
742
|
+
* c.set('message', 'Hono is hot!!')
|
|
743
|
+
* await next()
|
|
744
|
+
* })
|
|
745
|
+
* ```
|
|
746
|
+
*/
|
|
878
747
|
set = (key, value) => {
|
|
879
748
|
this.#var ??= /* @__PURE__ */ new Map();
|
|
880
749
|
this.#var.set(key, value);
|
|
881
750
|
};
|
|
882
751
|
/**
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
752
|
+
* `.get()` can use the value specified by the key.
|
|
753
|
+
*
|
|
754
|
+
* @see {@link https://hono.dev/docs/api/context#set-get}
|
|
755
|
+
*
|
|
756
|
+
* @example
|
|
757
|
+
* ```ts
|
|
758
|
+
* app.get('/', (c) => {
|
|
759
|
+
* const message = c.get('message')
|
|
760
|
+
* return c.text(`The message is "${message}"`)
|
|
761
|
+
* })
|
|
762
|
+
* ```
|
|
763
|
+
*/
|
|
895
764
|
get = (key) => {
|
|
896
765
|
return this.#var ? this.#var.get(key) : void 0;
|
|
897
766
|
};
|
|
898
767
|
/**
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
// c.var.propName is a read-only
|
|
768
|
+
* `.var` can access the value of a variable.
|
|
769
|
+
*
|
|
770
|
+
* @see {@link https://hono.dev/docs/api/context#var}
|
|
771
|
+
*
|
|
772
|
+
* @example
|
|
773
|
+
* ```ts
|
|
774
|
+
* const result = c.var.client.oneMethod()
|
|
775
|
+
* ```
|
|
776
|
+
*/
|
|
909
777
|
get var() {
|
|
910
|
-
if (!this.#var) {
|
|
911
|
-
return {};
|
|
912
|
-
}
|
|
778
|
+
if (!this.#var) return {};
|
|
913
779
|
return Object.fromEntries(this.#var);
|
|
914
780
|
}
|
|
915
781
|
#newResponse(data, arg, headers) {
|
|
916
782
|
let responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders;
|
|
917
783
|
if (typeof arg === "object" && arg.headers) {
|
|
918
784
|
responseHeaders ??= new Headers();
|
|
919
|
-
for (const [key, value] of new Headers(arg.headers))
|
|
920
|
-
|
|
921
|
-
responseHeaders.append(key, value);
|
|
922
|
-
} else {
|
|
923
|
-
responseHeaders.set(key, value);
|
|
924
|
-
}
|
|
925
|
-
}
|
|
785
|
+
for (const [key, value] of new Headers(arg.headers)) if (key === "set-cookie") responseHeaders.append(key, value);
|
|
786
|
+
else responseHeaders.set(key, value);
|
|
926
787
|
}
|
|
927
788
|
if (headers) {
|
|
928
789
|
if (!responseHeaders) {
|
|
929
790
|
let count = 0;
|
|
930
|
-
for (const k in headers) {
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
break;
|
|
934
|
-
}
|
|
791
|
+
for (const k in headers) if (++count > 1 || typeof headers[k] !== "string") {
|
|
792
|
+
responseHeaders = new Headers();
|
|
793
|
+
break;
|
|
935
794
|
}
|
|
936
795
|
}
|
|
937
|
-
if (responseHeaders) {
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
responseHeaders.delete(k);
|
|
944
|
-
for (const v2 of v) {
|
|
945
|
-
responseHeaders.append(k, v2);
|
|
946
|
-
}
|
|
947
|
-
}
|
|
796
|
+
if (responseHeaders) for (const k in headers) {
|
|
797
|
+
const v = headers[k];
|
|
798
|
+
if (typeof v === "string") responseHeaders.set(k, v);
|
|
799
|
+
else {
|
|
800
|
+
responseHeaders.delete(k);
|
|
801
|
+
for (const v2 of v) responseHeaders.append(k, v2);
|
|
948
802
|
}
|
|
949
803
|
}
|
|
950
804
|
}
|
|
@@ -956,122 +810,144 @@ var Context = class {
|
|
|
956
810
|
}
|
|
957
811
|
newResponse = (...args) => this.#newResponse(...args);
|
|
958
812
|
/**
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
813
|
+
* `.body()` can return the HTTP response.
|
|
814
|
+
* You can set headers with `.header()` and set HTTP status code with `.status`.
|
|
815
|
+
* This can also be set in `.text()`, `.json()` and so on.
|
|
816
|
+
*
|
|
817
|
+
* @see {@link https://hono.dev/docs/api/context#body}
|
|
818
|
+
*
|
|
819
|
+
* @example
|
|
820
|
+
* ```ts
|
|
821
|
+
* app.get('/welcome', (c) => {
|
|
822
|
+
* // Set headers
|
|
823
|
+
* c.header('X-Message', 'Hello!')
|
|
824
|
+
* c.header('Content-Type', 'text/plain')
|
|
825
|
+
* // Set HTTP status code
|
|
826
|
+
* c.status(201)
|
|
827
|
+
*
|
|
828
|
+
* // Return the response body
|
|
829
|
+
* return c.body('Thank you for coming')
|
|
830
|
+
* })
|
|
831
|
+
* ```
|
|
832
|
+
*/
|
|
979
833
|
body = (data, arg, headers) => this.#newResponse(data, arg, headers);
|
|
980
834
|
/**
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
835
|
+
* `.text()` can render text as `Content-Type:text/plain`.
|
|
836
|
+
*
|
|
837
|
+
* @see {@link https://hono.dev/docs/api/context#text}
|
|
838
|
+
*
|
|
839
|
+
* @example
|
|
840
|
+
* ```ts
|
|
841
|
+
* app.get('/say', (c) => {
|
|
842
|
+
* return c.text('Hello!')
|
|
843
|
+
* })
|
|
844
|
+
* ```
|
|
845
|
+
*/
|
|
992
846
|
text = (text, arg, headers) => {
|
|
993
|
-
return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized ? new Response(text) : this.#newResponse(
|
|
994
|
-
text,
|
|
995
|
-
arg,
|
|
996
|
-
setDefaultContentType(TEXT_PLAIN, headers)
|
|
997
|
-
);
|
|
847
|
+
return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized ? new Response(text) : this.#newResponse(text, arg, setDefaultContentType(TEXT_PLAIN, headers));
|
|
998
848
|
};
|
|
999
849
|
/**
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
850
|
+
* `.json()` can render JSON as `Content-Type:application/json`.
|
|
851
|
+
*
|
|
852
|
+
* @see {@link https://hono.dev/docs/api/context#json}
|
|
853
|
+
*
|
|
854
|
+
* @example
|
|
855
|
+
* ```ts
|
|
856
|
+
* app.get('/api', (c) => {
|
|
857
|
+
* return c.json({ message: 'Hello!' })
|
|
858
|
+
* })
|
|
859
|
+
* ```
|
|
860
|
+
*/
|
|
1011
861
|
json = (object, arg, headers) => {
|
|
1012
|
-
return this.#newResponse(
|
|
1013
|
-
JSON.stringify(object),
|
|
1014
|
-
arg,
|
|
1015
|
-
setDefaultContentType("application/json", headers)
|
|
1016
|
-
);
|
|
862
|
+
return this.#newResponse(JSON.stringify(object), arg, setDefaultContentType("application/json", headers));
|
|
1017
863
|
};
|
|
1018
864
|
html = (html, arg, headers) => {
|
|
1019
865
|
const res = (html2) => this.#newResponse(html2, arg, setDefaultContentType("text/html; charset=UTF-8", headers));
|
|
1020
866
|
return typeof html === "object" ? resolveCallback(html, HtmlEscapedCallbackPhase.Stringify, false, {}).then(res) : res(html);
|
|
1021
867
|
};
|
|
1022
868
|
/**
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
869
|
+
* `.redirect()` can Redirect, default status code is 302.
|
|
870
|
+
*
|
|
871
|
+
* @see {@link https://hono.dev/docs/api/context#redirect}
|
|
872
|
+
*
|
|
873
|
+
* @example
|
|
874
|
+
* ```ts
|
|
875
|
+
* app.get('/redirect', (c) => {
|
|
876
|
+
* return c.redirect('/')
|
|
877
|
+
* })
|
|
878
|
+
* app.get('/redirect-permanently', (c) => {
|
|
879
|
+
* return c.redirect('/', 301)
|
|
880
|
+
* })
|
|
881
|
+
* ```
|
|
882
|
+
*/
|
|
1037
883
|
redirect = (location, status) => {
|
|
1038
884
|
const locationString = String(location);
|
|
1039
|
-
this.header(
|
|
1040
|
-
"Location",
|
|
1041
|
-
// Multibyes should be encoded
|
|
1042
|
-
// eslint-disable-next-line no-control-regex
|
|
1043
|
-
!/[^\x00-\xFF]/.test(locationString) ? locationString : encodeURI(locationString)
|
|
1044
|
-
);
|
|
885
|
+
this.header("Location", !/[^\x00-\xFF]/.test(locationString) ? locationString : encodeURI(locationString));
|
|
1045
886
|
return this.newResponse(null, status ?? 302);
|
|
1046
887
|
};
|
|
1047
888
|
/**
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
889
|
+
* `.notFound()` can return the Not Found Response.
|
|
890
|
+
*
|
|
891
|
+
* @see {@link https://hono.dev/docs/api/context#notfound}
|
|
892
|
+
*
|
|
893
|
+
* @example
|
|
894
|
+
* ```ts
|
|
895
|
+
* app.get('/notfound', (c) => {
|
|
896
|
+
* return c.notFound()
|
|
897
|
+
* })
|
|
898
|
+
* ```
|
|
899
|
+
*/
|
|
1059
900
|
notFound = () => {
|
|
1060
901
|
this.#notFoundHandler ??= () => createResponseInstance();
|
|
1061
902
|
return this.#notFoundHandler(this);
|
|
1062
903
|
};
|
|
1063
904
|
};
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
905
|
+
const compose = (middleware, onError, onNotFound) => {
|
|
906
|
+
return (context, next) => {
|
|
907
|
+
let index = -1;
|
|
908
|
+
return dispatch(0);
|
|
909
|
+
async function dispatch(i) {
|
|
910
|
+
if (i <= index) throw new Error("next() called multiple times");
|
|
911
|
+
index = i;
|
|
912
|
+
let res;
|
|
913
|
+
let isError = false;
|
|
914
|
+
let handler;
|
|
915
|
+
if (middleware[i]) {
|
|
916
|
+
handler = middleware[i][0][0];
|
|
917
|
+
context.req.routeIndex = i;
|
|
918
|
+
} else handler = i === middleware.length && next || void 0;
|
|
919
|
+
if (handler) try {
|
|
920
|
+
res = await handler(context, () => dispatch(i + 1));
|
|
921
|
+
} catch (err) {
|
|
922
|
+
if (err instanceof Error && onError) {
|
|
923
|
+
context.error = err;
|
|
924
|
+
res = await onError(err, context);
|
|
925
|
+
isError = true;
|
|
926
|
+
} else throw err;
|
|
927
|
+
}
|
|
928
|
+
else if (context.finalized === false && onNotFound) res = await onNotFound(context);
|
|
929
|
+
if (res && (context.finalized === false || isError)) context.res = res;
|
|
930
|
+
return context;
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
};
|
|
934
|
+
const METHODS = [
|
|
935
|
+
"get",
|
|
936
|
+
"post",
|
|
937
|
+
"put",
|
|
938
|
+
"delete",
|
|
939
|
+
"options",
|
|
940
|
+
"patch",
|
|
941
|
+
"query"
|
|
942
|
+
];
|
|
943
|
+
const MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built.";
|
|
1068
944
|
var UnsupportedPathError = class extends Error {
|
|
1069
945
|
};
|
|
1070
|
-
|
|
1071
|
-
|
|
946
|
+
const COMPOSED_HANDLER = "__COMPOSED_HANDLER";
|
|
947
|
+
const notFoundHandler = (c) => {
|
|
1072
948
|
return c.text("404 Not Found", 404);
|
|
1073
949
|
};
|
|
1074
|
-
|
|
950
|
+
const errorHandler = (err, c) => {
|
|
1075
951
|
if ("getResponse" in err) {
|
|
1076
952
|
const res = err.getResponse();
|
|
1077
953
|
return c.newResponse(res.body, res);
|
|
@@ -1079,7 +955,7 @@ var errorHandler = (err, c) => {
|
|
|
1079
955
|
console.error(err);
|
|
1080
956
|
return c.text("Internal Server Error", 500);
|
|
1081
957
|
};
|
|
1082
|
-
var Hono$1 = class
|
|
958
|
+
var Hono$1 = class Hono {
|
|
1083
959
|
get;
|
|
1084
960
|
post;
|
|
1085
961
|
put;
|
|
@@ -1090,27 +966,19 @@ var Hono$1 = class _Hono {
|
|
|
1090
966
|
all;
|
|
1091
967
|
on;
|
|
1092
968
|
use;
|
|
1093
|
-
/*
|
|
1094
|
-
This class is like an abstract class and does not have a router.
|
|
1095
|
-
To use it, inherit the class and implement router in the constructor.
|
|
1096
|
-
*/
|
|
1097
969
|
router;
|
|
1098
970
|
getPath;
|
|
1099
|
-
// Cannot use `#` because it requires visibility at JavaScript runtime.
|
|
1100
971
|
_basePath = "/";
|
|
1101
972
|
#path = "/";
|
|
1102
973
|
routes = [];
|
|
1103
974
|
constructor(options = {}) {
|
|
1104
|
-
|
|
1105
|
-
allMethods.forEach((method) => {
|
|
975
|
+
[...METHODS, "all"].forEach((method) => {
|
|
1106
976
|
this[method] = (args1, ...args) => {
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
this.#addRoute(method, this.#path, args1);
|
|
1111
|
-
}
|
|
977
|
+
const methodName = method.toUpperCase();
|
|
978
|
+
if (typeof args1 === "string") this.#path = args1;
|
|
979
|
+
else this.#addRoute(methodName, this.#path, args1);
|
|
1112
980
|
args.forEach((handler) => {
|
|
1113
|
-
this.#addRoute(
|
|
981
|
+
this.#addRoute(methodName, this.#path, handler);
|
|
1114
982
|
});
|
|
1115
983
|
return this;
|
|
1116
984
|
};
|
|
@@ -1119,22 +987,20 @@ var Hono$1 = class _Hono {
|
|
|
1119
987
|
for (const p of [path].flat()) {
|
|
1120
988
|
this.#path = p;
|
|
1121
989
|
for (const m of [method].flat()) {
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
});
|
|
990
|
+
const methodName = m.toUpperCase();
|
|
991
|
+
for (const handler of handlers) this.#addRoute(methodName, this.#path, handler);
|
|
1125
992
|
}
|
|
1126
993
|
}
|
|
1127
994
|
return this;
|
|
1128
995
|
};
|
|
1129
996
|
this.use = (arg1, ...handlers) => {
|
|
1130
|
-
if (typeof arg1 === "string")
|
|
1131
|
-
|
|
1132
|
-
} else {
|
|
997
|
+
if (typeof arg1 === "string") this.#path = arg1;
|
|
998
|
+
else {
|
|
1133
999
|
this.#path = "*";
|
|
1134
1000
|
handlers.unshift(arg1);
|
|
1135
1001
|
}
|
|
1136
1002
|
handlers.forEach((handler) => {
|
|
1137
|
-
this.#addRoute(
|
|
1003
|
+
this.#addRoute("ALL", this.#path, handler);
|
|
1138
1004
|
});
|
|
1139
1005
|
return this;
|
|
1140
1006
|
};
|
|
@@ -1143,7 +1009,7 @@ var Hono$1 = class _Hono {
|
|
|
1143
1009
|
this.getPath = strict ?? true ? options.getPath ?? getPath$1 : getPathNoStrict;
|
|
1144
1010
|
}
|
|
1145
1011
|
#clone() {
|
|
1146
|
-
const clone = new
|
|
1012
|
+
const clone = new Hono({
|
|
1147
1013
|
router: this.router,
|
|
1148
1014
|
getPath: this.getPath
|
|
1149
1015
|
});
|
|
@@ -1153,33 +1019,31 @@ var Hono$1 = class _Hono {
|
|
|
1153
1019
|
return clone;
|
|
1154
1020
|
}
|
|
1155
1021
|
#notFoundHandler = notFoundHandler;
|
|
1156
|
-
// Cannot use `#` because it requires visibility at JavaScript runtime.
|
|
1157
1022
|
errorHandler = errorHandler;
|
|
1158
1023
|
/**
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1024
|
+
* `.route()` allows grouping other Hono instance in routes.
|
|
1025
|
+
*
|
|
1026
|
+
* @see {@link https://hono.dev/docs/api/routing#grouping}
|
|
1027
|
+
*
|
|
1028
|
+
* @param {string} path - base Path
|
|
1029
|
+
* @param {Hono} app - other Hono instance
|
|
1030
|
+
* @returns {Hono} routed Hono instance
|
|
1031
|
+
*
|
|
1032
|
+
* @example
|
|
1033
|
+
* ```ts
|
|
1034
|
+
* const app = new Hono()
|
|
1035
|
+
* const app2 = new Hono()
|
|
1036
|
+
*
|
|
1037
|
+
* app2.get("/user", (c) => c.text("user"))
|
|
1038
|
+
* app.route("/api", app2) // GET /api/user
|
|
1039
|
+
* ```
|
|
1040
|
+
*/
|
|
1176
1041
|
route(path, app2) {
|
|
1177
1042
|
const subApp = this.basePath(path);
|
|
1178
1043
|
app2.routes.map((r) => {
|
|
1179
1044
|
let handler;
|
|
1180
|
-
if (app2.errorHandler === errorHandler)
|
|
1181
|
-
|
|
1182
|
-
} else {
|
|
1045
|
+
if (app2.errorHandler === errorHandler) handler = r.handler;
|
|
1046
|
+
else {
|
|
1183
1047
|
handler = async (c, next) => (await compose([], app2.errorHandler)(c, () => r.handler(c, next))).res;
|
|
1184
1048
|
handler[COMPOSED_HANDLER] = r.handler;
|
|
1185
1049
|
}
|
|
@@ -1188,107 +1052,105 @@ var Hono$1 = class _Hono {
|
|
|
1188
1052
|
return this;
|
|
1189
1053
|
}
|
|
1190
1054
|
/**
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1055
|
+
* `.basePath()` allows base paths to be specified.
|
|
1056
|
+
*
|
|
1057
|
+
* @see {@link https://hono.dev/docs/api/routing#base-path}
|
|
1058
|
+
*
|
|
1059
|
+
* @param {string} path - base Path
|
|
1060
|
+
* @returns {Hono} changed Hono instance
|
|
1061
|
+
*
|
|
1062
|
+
* @example
|
|
1063
|
+
* ```ts
|
|
1064
|
+
* const api = new Hono().basePath('/api')
|
|
1065
|
+
* ```
|
|
1066
|
+
*/
|
|
1203
1067
|
basePath(path) {
|
|
1204
1068
|
const subApp = this.#clone();
|
|
1205
1069
|
subApp._basePath = mergePath(this._basePath, path);
|
|
1206
1070
|
return subApp;
|
|
1207
1071
|
}
|
|
1208
1072
|
/**
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1073
|
+
* `.onError()` handles an error and returns a customized Response.
|
|
1074
|
+
*
|
|
1075
|
+
* @see {@link https://hono.dev/docs/api/hono#error-handling}
|
|
1076
|
+
*
|
|
1077
|
+
* @param {ErrorHandler} handler - request Handler for error
|
|
1078
|
+
* @returns {Hono} changed Hono instance
|
|
1079
|
+
*
|
|
1080
|
+
* @example
|
|
1081
|
+
* ```ts
|
|
1082
|
+
* app.onError((err, c) => {
|
|
1083
|
+
* console.error(`${err}`)
|
|
1084
|
+
* return c.text('Custom Error Message', 500)
|
|
1085
|
+
* })
|
|
1086
|
+
* ```
|
|
1087
|
+
*/
|
|
1224
1088
|
onError = (handler) => {
|
|
1225
1089
|
this.errorHandler = handler;
|
|
1226
1090
|
return this;
|
|
1227
1091
|
};
|
|
1228
1092
|
/**
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1093
|
+
* `.notFound()` allows you to customize a Not Found Response.
|
|
1094
|
+
*
|
|
1095
|
+
* @see {@link https://hono.dev/docs/api/hono#not-found}
|
|
1096
|
+
*
|
|
1097
|
+
* @param {NotFoundHandler} handler - request handler for not-found
|
|
1098
|
+
* @returns {Hono} changed Hono instance
|
|
1099
|
+
*
|
|
1100
|
+
* @example
|
|
1101
|
+
* ```ts
|
|
1102
|
+
* app.notFound((c) => {
|
|
1103
|
+
* return c.text('Custom 404 Message', 404)
|
|
1104
|
+
* })
|
|
1105
|
+
* ```
|
|
1106
|
+
*/
|
|
1243
1107
|
notFound = (handler) => {
|
|
1244
1108
|
this.#notFoundHandler = handler;
|
|
1245
1109
|
return this;
|
|
1246
1110
|
};
|
|
1247
1111
|
/**
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1112
|
+
* `.mount()` allows you to mount applications built with other frameworks into your Hono application.
|
|
1113
|
+
*
|
|
1114
|
+
* @deprecated Use `mount()` from `hono/mount` instead. `.mount()` will be removed in v5.
|
|
1115
|
+
*
|
|
1116
|
+
* @see {@link https://hono.dev/docs/api/hono#mount}
|
|
1117
|
+
*
|
|
1118
|
+
* @param {string} path - base Path
|
|
1119
|
+
* @param {Function} applicationHandler - other Request Handler
|
|
1120
|
+
* @param {MountOptions} [options] - options of `.mount()`
|
|
1121
|
+
* @returns {Hono} mounted Hono instance
|
|
1122
|
+
*
|
|
1123
|
+
* @example
|
|
1124
|
+
* ```ts
|
|
1125
|
+
* import { Router as IttyRouter } from 'itty-router'
|
|
1126
|
+
* import { Hono } from 'hono'
|
|
1127
|
+
* // Create itty-router application
|
|
1128
|
+
* const ittyRouter = IttyRouter()
|
|
1129
|
+
* // GET /itty-router/hello
|
|
1130
|
+
* ittyRouter.get('/hello', () => new Response('Hello from itty-router'))
|
|
1131
|
+
*
|
|
1132
|
+
* const app = new Hono()
|
|
1133
|
+
* app.mount('/itty-router', ittyRouter.handle)
|
|
1134
|
+
* ```
|
|
1135
|
+
*
|
|
1136
|
+
* @example
|
|
1137
|
+
* ```ts
|
|
1138
|
+
* const app = new Hono()
|
|
1139
|
+
* // Send the request to another application without modification.
|
|
1140
|
+
* app.mount('/app', anotherApp, {
|
|
1141
|
+
* replaceRequest: (req) => req,
|
|
1142
|
+
* })
|
|
1143
|
+
* ```
|
|
1144
|
+
*/
|
|
1279
1145
|
mount(path, applicationHandler, options) {
|
|
1280
1146
|
let replaceRequest;
|
|
1281
1147
|
let optionHandler;
|
|
1282
1148
|
if (options) {
|
|
1283
|
-
if (typeof options === "function")
|
|
1284
|
-
|
|
1285
|
-
} else {
|
|
1149
|
+
if (typeof options === "function") optionHandler = options;
|
|
1150
|
+
else {
|
|
1286
1151
|
optionHandler = options.optionHandler;
|
|
1287
|
-
if (options.replaceRequest === false)
|
|
1288
|
-
|
|
1289
|
-
} else {
|
|
1290
|
-
replaceRequest = options.replaceRequest;
|
|
1291
|
-
}
|
|
1152
|
+
if (options.replaceRequest === false) replaceRequest = (request) => request;
|
|
1153
|
+
else replaceRequest = options.replaceRequest;
|
|
1292
1154
|
}
|
|
1293
1155
|
}
|
|
1294
1156
|
const getOptions = optionHandler ? (c) => {
|
|
@@ -1313,16 +1175,13 @@ var Hono$1 = class _Hono {
|
|
|
1313
1175
|
})();
|
|
1314
1176
|
const handler = async (c, next) => {
|
|
1315
1177
|
const res = await applicationHandler(replaceRequest(c.req.raw), ...getOptions(c));
|
|
1316
|
-
if (res)
|
|
1317
|
-
return res;
|
|
1318
|
-
}
|
|
1178
|
+
if (res) return res;
|
|
1319
1179
|
await next();
|
|
1320
1180
|
};
|
|
1321
|
-
this.#addRoute(
|
|
1181
|
+
this.#addRoute("ALL", mergePath(path, "*"), handler);
|
|
1322
1182
|
return this;
|
|
1323
1183
|
}
|
|
1324
1184
|
#addRoute(method, path, handler, baseRoutePath) {
|
|
1325
|
-
method = method.toUpperCase();
|
|
1326
1185
|
path = mergePath(this._basePath, path);
|
|
1327
1186
|
const r = {
|
|
1328
1187
|
basePath: baseRoutePath !== void 0 ? mergePath(this._basePath, baseRoutePath) : this._basePath,
|
|
@@ -1334,15 +1193,11 @@ var Hono$1 = class _Hono {
|
|
|
1334
1193
|
this.routes.push(r);
|
|
1335
1194
|
}
|
|
1336
1195
|
#handleError(err, c) {
|
|
1337
|
-
if (err instanceof Error)
|
|
1338
|
-
return this.errorHandler(err, c);
|
|
1339
|
-
}
|
|
1196
|
+
if (err instanceof Error) return this.errorHandler(err, c);
|
|
1340
1197
|
throw err;
|
|
1341
1198
|
}
|
|
1342
1199
|
#dispatch(request, executionCtx, env, method) {
|
|
1343
|
-
if (method === "HEAD")
|
|
1344
|
-
return (async () => new Response(null, await this.#dispatch(request, executionCtx, env, "GET")))();
|
|
1345
|
-
}
|
|
1200
|
+
if (method === "HEAD") return (async () => new Response(null, await this.#dispatch(request, executionCtx, env, "GET")))();
|
|
1346
1201
|
const path = this.getPath(request, { env });
|
|
1347
1202
|
const matchResult = this.router.match(method, path);
|
|
1348
1203
|
const c = new Context(request, {
|
|
@@ -1361,19 +1216,13 @@ var Hono$1 = class _Hono {
|
|
|
1361
1216
|
} catch (err) {
|
|
1362
1217
|
return this.#handleError(err, c);
|
|
1363
1218
|
}
|
|
1364
|
-
return res instanceof Promise ? res.then(
|
|
1365
|
-
(resolved) => resolved || (c.finalized ? c.res : this.#notFoundHandler(c))
|
|
1366
|
-
).catch((err) => this.#handleError(err, c)) : res ?? this.#notFoundHandler(c);
|
|
1219
|
+
return res instanceof Promise ? res.then((resolved) => resolved || (c.finalized ? c.res : this.#notFoundHandler(c))).catch((err) => this.#handleError(err, c)) : res ?? this.#notFoundHandler(c);
|
|
1367
1220
|
}
|
|
1368
1221
|
const composed = compose(matchResult[0], this.errorHandler, this.#notFoundHandler);
|
|
1369
1222
|
return (async () => {
|
|
1370
1223
|
try {
|
|
1371
1224
|
const context = await composed(c);
|
|
1372
|
-
if (!context.finalized)
|
|
1373
|
-
throw new Error(
|
|
1374
|
-
"Context is not finalized. Did you forget to return a Response object or `await next()`?"
|
|
1375
|
-
);
|
|
1376
|
-
}
|
|
1225
|
+
if (!context.finalized) throw new Error("Context is not finalized. Did you forget to return a Response object or `await next()`?");
|
|
1377
1226
|
return context.res;
|
|
1378
1227
|
} catch (err) {
|
|
1379
1228
|
return this.#handleError(err, c);
|
|
@@ -1381,150 +1230,125 @@ var Hono$1 = class _Hono {
|
|
|
1381
1230
|
})();
|
|
1382
1231
|
}
|
|
1383
1232
|
/**
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1233
|
+
* `.fetch()` will be entry point of your app.
|
|
1234
|
+
*
|
|
1235
|
+
* @see {@link https://hono.dev/docs/api/hono#fetch}
|
|
1236
|
+
*
|
|
1237
|
+
* @param {Request} request - request Object of request
|
|
1238
|
+
* @param {Env} env - env Object
|
|
1239
|
+
* @param {ExecutionContext} executionCtx - context of execution
|
|
1240
|
+
* @returns {Response | Promise<Response>} response of request
|
|
1241
|
+
*
|
|
1242
|
+
*/
|
|
1394
1243
|
fetch = (request, ...rest) => {
|
|
1395
1244
|
return this.#dispatch(request, rest[1], rest[0], request.method);
|
|
1396
1245
|
};
|
|
1397
1246
|
/**
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1247
|
+
* `.request()` is a useful method for testing.
|
|
1248
|
+
* You can pass a URL or pathname to send a GET request.
|
|
1249
|
+
* app will return a Response object.
|
|
1250
|
+
* ```ts
|
|
1251
|
+
* test('GET /hello is ok', async () => {
|
|
1252
|
+
* const res = await app.request('/hello')
|
|
1253
|
+
* expect(res.status).toBe(200)
|
|
1254
|
+
* })
|
|
1255
|
+
* ```
|
|
1256
|
+
* @see https://hono.dev/docs/api/hono#request
|
|
1257
|
+
*/
|
|
1409
1258
|
request = (input, requestInit, Env, executionCtx) => {
|
|
1410
|
-
if (input instanceof Request)
|
|
1411
|
-
return this.fetch(requestInit ? new Request(input, requestInit) : input, Env, executionCtx);
|
|
1412
|
-
}
|
|
1259
|
+
if (input instanceof Request) return this.fetch(requestInit ? new Request(input, requestInit) : input, Env, executionCtx);
|
|
1413
1260
|
input = input.toString();
|
|
1414
|
-
return this.fetch(
|
|
1415
|
-
new Request(
|
|
1416
|
-
/^https?:\/\//.test(input) ? input : `http://localhost${mergePath("/", input)}`,
|
|
1417
|
-
requestInit
|
|
1418
|
-
),
|
|
1419
|
-
Env,
|
|
1420
|
-
executionCtx
|
|
1421
|
-
);
|
|
1261
|
+
return this.fetch(new Request(/^https?:\/\//.test(input) ? input : `http://localhost${mergePath("/", input)}`, requestInit), Env, executionCtx);
|
|
1422
1262
|
};
|
|
1423
1263
|
/**
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1264
|
+
* `.fire()` automatically adds a global fetch event listener.
|
|
1265
|
+
* This can be useful for environments that adhere to the Service Worker API, such as non-ES module Cloudflare Workers.
|
|
1266
|
+
* @deprecated
|
|
1267
|
+
* Use `fire` from `hono/service-worker` instead.
|
|
1268
|
+
* ```ts
|
|
1269
|
+
* import { Hono } from 'hono'
|
|
1270
|
+
* import { fire } from 'hono/service-worker'
|
|
1271
|
+
*
|
|
1272
|
+
* const app = new Hono()
|
|
1273
|
+
* // ...
|
|
1274
|
+
* fire(app)
|
|
1275
|
+
* ```
|
|
1276
|
+
* @see https://hono.dev/docs/api/hono#fire
|
|
1277
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API
|
|
1278
|
+
* @see https://developers.cloudflare.com/workers/reference/migrate-to-module-workers/
|
|
1279
|
+
*/
|
|
1440
1280
|
fire = () => {
|
|
1441
1281
|
addEventListener("fetch", (event2) => {
|
|
1442
1282
|
event2.respondWith(this.#dispatch(event2.request, event2, void 0, event2.request.method));
|
|
1443
1283
|
});
|
|
1444
1284
|
};
|
|
1445
1285
|
};
|
|
1446
|
-
|
|
1286
|
+
const createNullObject = () => /* @__PURE__ */ Object.create(null);
|
|
1287
|
+
const emptyParam = [];
|
|
1447
1288
|
function match(method, path) {
|
|
1448
1289
|
const matchers = this.buildAllMatchers();
|
|
1449
1290
|
const match2 = ((method2, path2) => {
|
|
1450
|
-
const matcher = matchers[method2] || matchers[
|
|
1291
|
+
const matcher = matchers[method2] || matchers["ALL"];
|
|
1451
1292
|
const staticMatch = matcher[2][path2];
|
|
1452
|
-
if (staticMatch)
|
|
1453
|
-
return staticMatch;
|
|
1454
|
-
}
|
|
1293
|
+
if (staticMatch) return staticMatch;
|
|
1455
1294
|
const match3 = path2.match(matcher[0]);
|
|
1456
|
-
if (!match3)
|
|
1457
|
-
return [[], emptyParam];
|
|
1458
|
-
}
|
|
1295
|
+
if (!match3) return [[], emptyParam];
|
|
1459
1296
|
const index = match3.indexOf("", 1);
|
|
1460
1297
|
return [matcher[1][index], match3];
|
|
1461
1298
|
});
|
|
1462
1299
|
this.match = match2;
|
|
1463
1300
|
return match2(method, path);
|
|
1464
1301
|
}
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
var regExpMetaChars = new Set(".\\+*[^]$()");
|
|
1302
|
+
const LABEL_REG_EXP_STR = "[^/]+";
|
|
1303
|
+
const TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)";
|
|
1304
|
+
const PATH_ERROR = /* @__PURE__ */ Symbol();
|
|
1305
|
+
const regExpMetaChars = /* @__PURE__ */ new Set(".\\+*[^]$()");
|
|
1470
1306
|
function compareKey(a, b) {
|
|
1471
|
-
if (a.length === 1)
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
if (b
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
if (a === ONLY_WILDCARD_REG_EXP_STR || a === TAIL_WILDCARD_REG_EXP_STR) {
|
|
1478
|
-
return b === TAIL_WILDCARD_REG_EXP_STR ? -1 : 1;
|
|
1479
|
-
} else if (b === ONLY_WILDCARD_REG_EXP_STR || b === TAIL_WILDCARD_REG_EXP_STR) {
|
|
1480
|
-
return -1;
|
|
1481
|
-
}
|
|
1482
|
-
if (a === LABEL_REG_EXP_STR) {
|
|
1483
|
-
return 1;
|
|
1484
|
-
} else if (b === LABEL_REG_EXP_STR) {
|
|
1485
|
-
return -1;
|
|
1486
|
-
}
|
|
1307
|
+
if (a.length === 1) return b.length === 1 ? a < b ? -1 : 1 : -1;
|
|
1308
|
+
if (b.length === 1) return 1;
|
|
1309
|
+
if (a === ".*" || a === "(?:|/.*)") return b === "(?:|/.*)" ? -1 : 1;
|
|
1310
|
+
else if (b === ".*" || b === "(?:|/.*)") return -1;
|
|
1311
|
+
if (a === "[^/]+") return 1;
|
|
1312
|
+
else if (b === "[^/]+") return -1;
|
|
1487
1313
|
return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length;
|
|
1488
1314
|
}
|
|
1489
|
-
var Node$1 = class
|
|
1490
|
-
// handler index of a dynamic path, or -1 for a static path terminal
|
|
1315
|
+
var Node$1 = class Node {
|
|
1491
1316
|
#index;
|
|
1492
1317
|
#varIndex;
|
|
1493
|
-
#children =
|
|
1318
|
+
#children = createNullObject();
|
|
1494
1319
|
insert(tokens, index, paramMap, context, isStatic) {
|
|
1495
1320
|
let node = this;
|
|
1496
1321
|
for (let i = 0, len = tokens.length; i < len; i++) {
|
|
1497
1322
|
const token = tokens[i];
|
|
1498
|
-
const pattern = token.length === 1 ? token === "*" ? i === len - 1 ? [
|
|
1323
|
+
const pattern = token.length === 1 ? token === "*" ? i === len - 1 ? [
|
|
1324
|
+
"",
|
|
1325
|
+
"",
|
|
1326
|
+
".*"
|
|
1327
|
+
] : [
|
|
1328
|
+
"",
|
|
1329
|
+
"",
|
|
1330
|
+
LABEL_REG_EXP_STR
|
|
1331
|
+
] : null : token === "/*" ? [
|
|
1332
|
+
"",
|
|
1333
|
+
"",
|
|
1334
|
+
TAIL_WILDCARD_REG_EXP_STR
|
|
1335
|
+
] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
|
|
1499
1336
|
let nextNode;
|
|
1500
1337
|
if (pattern) {
|
|
1501
1338
|
const name = pattern[1];
|
|
1502
|
-
let regexpStr = pattern[2] ||
|
|
1339
|
+
let regexpStr = pattern[2] || "[^/]+";
|
|
1503
1340
|
if (name && pattern[2]) {
|
|
1504
|
-
if (regexpStr === ".*")
|
|
1505
|
-
throw PATH_ERROR;
|
|
1506
|
-
}
|
|
1341
|
+
if (regexpStr === ".*") throw PATH_ERROR;
|
|
1507
1342
|
regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
|
|
1508
|
-
if (/\((?!\?:)/.test(regexpStr))
|
|
1509
|
-
|
|
1510
|
-
}
|
|
1511
|
-
if (regexpStr.length === 1 && regExpMetaChars.has(regexpStr)) {
|
|
1512
|
-
throw PATH_ERROR;
|
|
1513
|
-
}
|
|
1343
|
+
if (/\((?!\?:)/.test(regexpStr)) throw PATH_ERROR;
|
|
1344
|
+
if (regexpStr.length === 1 && regExpMetaChars.has(regexpStr)) throw PATH_ERROR;
|
|
1514
1345
|
}
|
|
1515
1346
|
nextNode = node.#children[regexpStr];
|
|
1516
1347
|
if (!nextNode) {
|
|
1517
|
-
if (regexpStr !==
|
|
1518
|
-
for (const k in node.#children)
|
|
1519
|
-
if (
|
|
1520
|
-
// a single-char pattern coexists with single-char literals as a literal does
|
|
1521
|
-
(regexpStr.length > 1 || k.length > 1) && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
|
|
1522
|
-
) {
|
|
1523
|
-
throw PATH_ERROR;
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1348
|
+
if (regexpStr !== ".*" && regexpStr !== "(?:|/.*)") {
|
|
1349
|
+
for (const k in node.#children) if ((regexpStr.length > 1 || k.length > 1) && k !== ".*" && k !== "(?:|/.*)") throw PATH_ERROR;
|
|
1526
1350
|
}
|
|
1527
|
-
nextNode = node.#children[regexpStr] = new
|
|
1351
|
+
nextNode = node.#children[regexpStr] = new Node();
|
|
1528
1352
|
}
|
|
1529
1353
|
if (name !== "") {
|
|
1530
1354
|
nextNode.#varIndex ??= context.varIndex++;
|
|
@@ -1533,37 +1357,24 @@ var Node$1 = class _Node {
|
|
|
1533
1357
|
} else {
|
|
1534
1358
|
nextNode = node.#children[token];
|
|
1535
1359
|
if (!nextNode) {
|
|
1536
|
-
for (const k in node.#children)
|
|
1537
|
-
|
|
1538
|
-
throw PATH_ERROR;
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
|
-
nextNode = node.#children[token] = new _Node();
|
|
1360
|
+
for (const k in node.#children) if (k.length > 1 && k !== ".*" && k !== "(?:|/.*)") throw PATH_ERROR;
|
|
1361
|
+
nextNode = node.#children[token] = new Node();
|
|
1542
1362
|
}
|
|
1543
1363
|
}
|
|
1544
1364
|
node = nextNode;
|
|
1545
1365
|
}
|
|
1546
|
-
if (node.#index !== void 0)
|
|
1547
|
-
throw PATH_ERROR;
|
|
1548
|
-
}
|
|
1366
|
+
if (node.#index !== void 0) throw PATH_ERROR;
|
|
1549
1367
|
node.#index = isStatic ? -1 : index;
|
|
1550
1368
|
}
|
|
1551
1369
|
buildRegExpStr() {
|
|
1552
|
-
const
|
|
1553
|
-
const strList = childKeys.map((k) => {
|
|
1370
|
+
const strList = Object.keys(this.#children).sort(compareKey).map((k) => {
|
|
1554
1371
|
const c = this.#children[k];
|
|
1555
1372
|
const childStr = c.buildRegExpStr();
|
|
1556
1373
|
return childStr === "" ? "" : (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + childStr;
|
|
1557
1374
|
}).filter(Boolean);
|
|
1558
|
-
if (typeof this.#index === "number" && this.#index !== -1) {
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
if (strList.length === 0) {
|
|
1562
|
-
return "";
|
|
1563
|
-
}
|
|
1564
|
-
if (strList.length === 1) {
|
|
1565
|
-
return strList[0];
|
|
1566
|
-
}
|
|
1375
|
+
if (typeof this.#index === "number" && this.#index !== -1) strList.unshift(`#${this.#index}`);
|
|
1376
|
+
if (strList.length === 0) return "";
|
|
1377
|
+
if (strList.length === 1) return strList[0];
|
|
1567
1378
|
return "(?:" + strList.join("|") + ")";
|
|
1568
1379
|
}
|
|
1569
1380
|
};
|
|
@@ -1571,8 +1382,7 @@ var Trie = class {
|
|
|
1571
1382
|
#context = { varIndex: 0 };
|
|
1572
1383
|
#root = new Node$1();
|
|
1573
1384
|
#index = 0;
|
|
1574
|
-
|
|
1575
|
-
paths = /* @__PURE__ */ Object.create(null);
|
|
1385
|
+
paths = createNullObject();
|
|
1576
1386
|
insert(path, isStatic) {
|
|
1577
1387
|
if (isStatic) {
|
|
1578
1388
|
this.#root.insert(path.split(""), 0, [], this.#context, true);
|
|
@@ -1590,18 +1400,14 @@ var Trie = class {
|
|
|
1590
1400
|
replaced = true;
|
|
1591
1401
|
return mark;
|
|
1592
1402
|
});
|
|
1593
|
-
if (!replaced)
|
|
1594
|
-
break;
|
|
1595
|
-
}
|
|
1403
|
+
if (!replaced) break;
|
|
1596
1404
|
}
|
|
1597
1405
|
const tokens = markedPath.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
|
|
1598
1406
|
for (let i = groups.length - 1; i >= 0; i--) {
|
|
1599
1407
|
const [mark] = groups[i];
|
|
1600
|
-
for (let j = tokens.length - 1; j >= 0; j--) {
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
break;
|
|
1604
|
-
}
|
|
1408
|
+
for (let j = tokens.length - 1; j >= 0; j--) if (tokens[j].indexOf(mark) !== -1) {
|
|
1409
|
+
tokens[j] = tokens[j].replace(mark, groups[i][1]);
|
|
1410
|
+
break;
|
|
1605
1411
|
}
|
|
1606
1412
|
}
|
|
1607
1413
|
this.#root.insert(tokens, this.#index, paramAssoc, this.#context, false);
|
|
@@ -1609,9 +1415,11 @@ var Trie = class {
|
|
|
1609
1415
|
}
|
|
1610
1416
|
buildRegExp() {
|
|
1611
1417
|
let regexp = this.#root.buildRegExpStr();
|
|
1612
|
-
if (regexp === "")
|
|
1613
|
-
|
|
1614
|
-
|
|
1418
|
+
if (regexp === "") return [
|
|
1419
|
+
/^$/,
|
|
1420
|
+
[],
|
|
1421
|
+
[]
|
|
1422
|
+
];
|
|
1615
1423
|
let captureIndex = 0;
|
|
1616
1424
|
const indexReplacementMap = [];
|
|
1617
1425
|
const paramReplacementMap = [];
|
|
@@ -1626,31 +1434,19 @@ var Trie = class {
|
|
|
1626
1434
|
}
|
|
1627
1435
|
return "";
|
|
1628
1436
|
});
|
|
1629
|
-
return [
|
|
1437
|
+
return [
|
|
1438
|
+
new RegExp(`^${regexp}`),
|
|
1439
|
+
indexReplacementMap,
|
|
1440
|
+
paramReplacementMap
|
|
1441
|
+
];
|
|
1630
1442
|
}
|
|
1631
1443
|
};
|
|
1632
|
-
|
|
1444
|
+
let wildcardRegExpCache = createNullObject();
|
|
1633
1445
|
function buildWildcardRegExp(path) {
|
|
1634
|
-
return wildcardRegExpCache[path] ??= new RegExp(
|
|
1635
|
-
path === "*" ? "" : `^${path.replace(
|
|
1636
|
-
/\/\*$|([.\\+*[^\]$()])/g,
|
|
1637
|
-
(_, metaChar) => metaChar ? `\\${metaChar}` : "(?:|/.*)"
|
|
1638
|
-
)}$`
|
|
1639
|
-
);
|
|
1640
|
-
}
|
|
1641
|
-
function clearWildcardRegExpCache() {
|
|
1642
|
-
wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
|
|
1446
|
+
return wildcardRegExpCache[path] ??= new RegExp(`^${path.replace(/\/:[^/{}]+(?:\{\[\^\/]\+})?(?=[/{]|$)|\/?\*$|([.\\+*[^\]$()?{}|])/g, (match2, metaChar) => metaChar ? `\\${metaChar}` : match2 === "/*" ? TAIL_WILDCARD_REG_EXP_STR : match2 === "*" ? ".*" : `/:${LABEL_REG_EXP_STR}`)}$`);
|
|
1643
1447
|
}
|
|
1644
1448
|
function findMiddleware(middleware, path) {
|
|
1645
|
-
|
|
1646
|
-
return void 0;
|
|
1647
|
-
}
|
|
1648
|
-
for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length)) {
|
|
1649
|
-
if (buildWildcardRegExp(k).test(path)) {
|
|
1650
|
-
return [...middleware[k]];
|
|
1651
|
-
}
|
|
1652
|
-
}
|
|
1653
|
-
return void 0;
|
|
1449
|
+
for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length)) if (buildWildcardRegExp(k).test(path)) return [...middleware[k]];
|
|
1654
1450
|
}
|
|
1655
1451
|
var RegExpRouter = class {
|
|
1656
1452
|
name = "RegExpRouter";
|
|
@@ -1658,9 +1454,9 @@ var RegExpRouter = class {
|
|
|
1658
1454
|
#routes;
|
|
1659
1455
|
#tries;
|
|
1660
1456
|
constructor() {
|
|
1661
|
-
this.#middleware = { [
|
|
1662
|
-
this.#routes = { [
|
|
1663
|
-
this.#tries = { [
|
|
1457
|
+
this.#middleware = { ["ALL"]: createNullObject() };
|
|
1458
|
+
this.#routes = { ["ALL"]: createNullObject() };
|
|
1459
|
+
this.#tries = { ["ALL"]: new Trie() };
|
|
1664
1460
|
}
|
|
1665
1461
|
#insertPath(method, path) {
|
|
1666
1462
|
try {
|
|
@@ -1672,117 +1468,69 @@ var RegExpRouter = class {
|
|
|
1672
1468
|
add(method, path, handler) {
|
|
1673
1469
|
const middleware = this.#middleware;
|
|
1674
1470
|
const routes = this.#routes;
|
|
1675
|
-
if (!middleware
|
|
1676
|
-
throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
|
|
1677
|
-
}
|
|
1471
|
+
if (!middleware) throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
|
|
1678
1472
|
if (!middleware[method]) {
|
|
1679
1473
|
this.#tries[method] = new Trie();
|
|
1680
|
-
[middleware, routes]
|
|
1681
|
-
handlerMap[method] =
|
|
1682
|
-
|
|
1683
|
-
handlerMap[method][p] = [...handlerMap[
|
|
1474
|
+
for (const handlerMap of [middleware, routes]) {
|
|
1475
|
+
handlerMap[method] = createNullObject();
|
|
1476
|
+
for (const p in handlerMap["ALL"]) {
|
|
1477
|
+
handlerMap[method][p] = [...handlerMap["ALL"][p]];
|
|
1684
1478
|
this.#insertPath(method, p);
|
|
1685
|
-
}
|
|
1686
|
-
}
|
|
1687
|
-
}
|
|
1688
|
-
if (path === "/*") {
|
|
1689
|
-
path = "*";
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1690
1481
|
}
|
|
1691
|
-
|
|
1482
|
+
if (path === "/*") path = "*";
|
|
1483
|
+
const methods = method === "ALL" ? Object.keys(middleware) : [method];
|
|
1692
1484
|
if (/\*$/.test(path)) {
|
|
1693
1485
|
const re = buildWildcardRegExp(path);
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
});
|
|
1700
|
-
Object.keys(middleware).forEach((m) => {
|
|
1701
|
-
if (method === METHOD_NAME_ALL || method === m) {
|
|
1702
|
-
Object.keys(middleware[m]).forEach((p) => {
|
|
1703
|
-
re.test(p) && middleware[m][p].push([handler, paramCount]);
|
|
1704
|
-
});
|
|
1705
|
-
}
|
|
1706
|
-
});
|
|
1707
|
-
Object.keys(routes).forEach((m) => {
|
|
1708
|
-
if (method === METHOD_NAME_ALL || method === m) {
|
|
1709
|
-
Object.keys(routes[m]).forEach(
|
|
1710
|
-
(p) => re.test(p) && routes[m][p].push([handler, paramCount])
|
|
1711
|
-
);
|
|
1712
|
-
}
|
|
1713
|
-
});
|
|
1486
|
+
for (const m of methods) if (!middleware[m][path]) {
|
|
1487
|
+
this.#insertPath(m, path);
|
|
1488
|
+
middleware[m][path] = findMiddleware(middleware[m], path) || findMiddleware(middleware["ALL"], path) || [];
|
|
1489
|
+
}
|
|
1490
|
+
for (const handlerMap of [middleware, routes]) for (const m of methods) for (const p in handlerMap[m]) re.test(p) && handlerMap[m][p].push([handler, path]);
|
|
1714
1491
|
return;
|
|
1715
1492
|
}
|
|
1716
1493
|
const paths = checkOptionalParameter(path) || [path];
|
|
1717
|
-
for (
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
routes[m][path2] = [
|
|
1724
|
-
...findMiddleware(middleware[m], path2) || findMiddleware(middleware[METHOD_NAME_ALL], path2) || []
|
|
1725
|
-
];
|
|
1726
|
-
}
|
|
1727
|
-
routes[m][path2].push([handler, paramCount - len + i + 1]);
|
|
1728
|
-
}
|
|
1729
|
-
});
|
|
1494
|
+
for (const path2 of paths) for (const m of methods) {
|
|
1495
|
+
if (!routes[m][path2]) {
|
|
1496
|
+
this.#insertPath(m, path2);
|
|
1497
|
+
routes[m][path2] = findMiddleware(middleware[m], path2) || findMiddleware(middleware["ALL"], path2) || [];
|
|
1498
|
+
}
|
|
1499
|
+
routes[m][path2].push([handler, path2]);
|
|
1730
1500
|
}
|
|
1731
1501
|
}
|
|
1732
1502
|
match = match;
|
|
1733
1503
|
buildAllMatchers() {
|
|
1734
|
-
const matchers =
|
|
1735
|
-
Object.keys(this.#routes)
|
|
1736
|
-
matchers[method] ||= this.#buildMatcher(method);
|
|
1737
|
-
});
|
|
1504
|
+
const matchers = createNullObject();
|
|
1505
|
+
for (const method of Object.keys(this.#routes)) matchers[method] = this.#buildMatcher(method);
|
|
1738
1506
|
this.#middleware = this.#routes = this.#tries = void 0;
|
|
1739
|
-
|
|
1507
|
+
wildcardRegExpCache = createNullObject();
|
|
1740
1508
|
return matchers;
|
|
1741
1509
|
}
|
|
1742
1510
|
#buildMatcher(method) {
|
|
1743
1511
|
const middleware = this.#middleware[method];
|
|
1744
1512
|
const routes = this.#routes[method];
|
|
1745
1513
|
const trie = this.#tries[method];
|
|
1746
|
-
const staticMap =
|
|
1514
|
+
const staticMap = createNullObject();
|
|
1747
1515
|
const handlerData = [];
|
|
1748
|
-
[middleware, routes].forEach((r) => {
|
|
1749
|
-
for (const path in r) {
|
|
1750
|
-
const handlers = r[path];
|
|
1751
|
-
const pathData = trie.paths[path];
|
|
1752
|
-
if (!pathData) {
|
|
1753
|
-
staticMap[path] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
|
|
1754
|
-
continue;
|
|
1755
|
-
}
|
|
1756
|
-
const paramAssoc = pathData[1];
|
|
1757
|
-
handlerData[pathData[0]] = handlers.map(([h, paramCount]) => {
|
|
1758
|
-
const paramIndexMap = /* @__PURE__ */ Object.create(null);
|
|
1759
|
-
paramCount -= 1;
|
|
1760
|
-
for (; paramCount >= 0; paramCount--) {
|
|
1761
|
-
const [key, value] = paramAssoc[paramCount];
|
|
1762
|
-
paramIndexMap[key] = value;
|
|
1763
|
-
}
|
|
1764
|
-
return [h, paramIndexMap];
|
|
1765
|
-
});
|
|
1766
|
-
}
|
|
1767
|
-
});
|
|
1768
1516
|
const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
|
|
1769
|
-
for (
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
const keys = Object.keys(map);
|
|
1776
|
-
for (let k = 0, len3 = keys.length; k < len3; k++) {
|
|
1777
|
-
map[keys[k]] = paramReplacementMap[map[keys[k]]];
|
|
1778
|
-
}
|
|
1517
|
+
for (const r of [middleware, routes]) for (const path in r) {
|
|
1518
|
+
const handlers = r[path];
|
|
1519
|
+
const pathData = trie.paths[path];
|
|
1520
|
+
if (!pathData) {
|
|
1521
|
+
staticMap[path] = [handlers.map(([h]) => [h, createNullObject()]), emptyParam];
|
|
1522
|
+
continue;
|
|
1779
1523
|
}
|
|
1524
|
+
handlerData[pathData[0]] = handlers.map(([h, handlerPath]) => [h, trie.paths[handlerPath][1].reduceRight((map, [key], i) => {
|
|
1525
|
+
map[key] = paramReplacementMap[pathData[1][i][1]];
|
|
1526
|
+
return map;
|
|
1527
|
+
}, createNullObject())]);
|
|
1780
1528
|
}
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1529
|
+
return [
|
|
1530
|
+
regexp,
|
|
1531
|
+
indexReplacementMap.map((i) => handlerData[i]),
|
|
1532
|
+
staticMap
|
|
1533
|
+
];
|
|
1786
1534
|
}
|
|
1787
1535
|
};
|
|
1788
1536
|
var SmartRouter = class {
|
|
@@ -1793,15 +1541,15 @@ var SmartRouter = class {
|
|
|
1793
1541
|
this.#routers = init.routers;
|
|
1794
1542
|
}
|
|
1795
1543
|
add(method, path, handler) {
|
|
1796
|
-
if (!this.#routes)
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1544
|
+
if (!this.#routes) throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
|
|
1545
|
+
this.#routes.push([
|
|
1546
|
+
method,
|
|
1547
|
+
path,
|
|
1548
|
+
handler
|
|
1549
|
+
]);
|
|
1800
1550
|
}
|
|
1801
1551
|
match(method, path) {
|
|
1802
|
-
if (!this.#routes)
|
|
1803
|
-
throw new Error("Fatal error");
|
|
1804
|
-
}
|
|
1552
|
+
if (!this.#routes) throw new Error("Fatal error");
|
|
1805
1553
|
const routers = this.#routers;
|
|
1806
1554
|
const routes = this.#routes;
|
|
1807
1555
|
const len = routers.length;
|
|
@@ -1810,14 +1558,10 @@ var SmartRouter = class {
|
|
|
1810
1558
|
for (; i < len; i++) {
|
|
1811
1559
|
const router = routers[i];
|
|
1812
1560
|
try {
|
|
1813
|
-
for (let i2 = 0, len2 = routes.length; i2 < len2; i2++)
|
|
1814
|
-
router.add(...routes[i2]);
|
|
1815
|
-
}
|
|
1561
|
+
for (let i2 = 0, len2 = routes.length; i2 < len2; i2++) router.add(...routes[i2]);
|
|
1816
1562
|
res = router.match(method, path);
|
|
1817
1563
|
} catch (e) {
|
|
1818
|
-
if (e instanceof UnsupportedPathError)
|
|
1819
|
-
continue;
|
|
1820
|
-
}
|
|
1564
|
+
if (e instanceof UnsupportedPathError) continue;
|
|
1821
1565
|
throw e;
|
|
1822
1566
|
}
|
|
1823
1567
|
this.match = router.match.bind(router);
|
|
@@ -1825,90 +1569,57 @@ var SmartRouter = class {
|
|
|
1825
1569
|
this.#routes = void 0;
|
|
1826
1570
|
break;
|
|
1827
1571
|
}
|
|
1828
|
-
if (i === len)
|
|
1829
|
-
throw new Error("Fatal error");
|
|
1830
|
-
}
|
|
1572
|
+
if (i === len) throw new Error("Fatal error");
|
|
1831
1573
|
this.name = `SmartRouter + ${this.activeRouter.name}`;
|
|
1832
1574
|
return res;
|
|
1833
1575
|
}
|
|
1834
1576
|
get activeRouter() {
|
|
1835
|
-
if (this.#routes || this.#routers.length !== 1)
|
|
1836
|
-
throw new Error("No active router has been determined yet.");
|
|
1837
|
-
}
|
|
1577
|
+
if (this.#routes || this.#routers.length !== 1) throw new Error("No active router has been determined yet.");
|
|
1838
1578
|
return this.#routers[0];
|
|
1839
1579
|
}
|
|
1840
1580
|
};
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
var Node = class _Node2 {
|
|
1849
|
-
#methods;
|
|
1850
|
-
#children;
|
|
1851
|
-
#patterns;
|
|
1852
|
-
#order = 0;
|
|
1581
|
+
const emptyParams = createNullObject();
|
|
1582
|
+
let order = 0;
|
|
1583
|
+
var Node2 = class Node3 {
|
|
1584
|
+
#methods = [];
|
|
1585
|
+
#children = createNullObject();
|
|
1586
|
+
#patterns = [];
|
|
1587
|
+
#pattern;
|
|
1853
1588
|
#params = emptyParams;
|
|
1854
|
-
constructor(method, handler, children) {
|
|
1855
|
-
this.#children = children || /* @__PURE__ */ Object.create(null);
|
|
1856
|
-
this.#methods = [];
|
|
1857
|
-
if (method && handler) {
|
|
1858
|
-
const m = /* @__PURE__ */ Object.create(null);
|
|
1859
|
-
m[method] = { handler, possibleKeys: [], score: 0 };
|
|
1860
|
-
this.#methods = [m];
|
|
1861
|
-
}
|
|
1862
|
-
this.#patterns = [];
|
|
1863
|
-
}
|
|
1864
1589
|
insert(method, path, handler) {
|
|
1865
|
-
this.#order = ++this.#order;
|
|
1866
1590
|
let curNode = this;
|
|
1867
1591
|
const parts = splitRoutingPath(path);
|
|
1868
|
-
const possibleKeys =
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
const nextP = parts[i
|
|
1872
|
-
const pattern = getPattern(p, nextP);
|
|
1873
|
-
const
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
}
|
|
1888
|
-
curNode.#methods.push({
|
|
1889
|
-
[method]: {
|
|
1890
|
-
handler,
|
|
1891
|
-
possibleKeys: possibleKeys.filter((v, i, a) => a.indexOf(v) === i),
|
|
1892
|
-
score: this.#order
|
|
1893
|
-
}
|
|
1894
|
-
});
|
|
1895
|
-
return curNode;
|
|
1592
|
+
const possibleKeys = /* @__PURE__ */ new Set();
|
|
1593
|
+
let i = 0;
|
|
1594
|
+
for (const p of parts) {
|
|
1595
|
+
const nextP = parts[++i];
|
|
1596
|
+
const pattern = getPattern(p, nextP) || (nextP === void 0 && p && p.indexOf("*") === p.length - 1 ? p : null);
|
|
1597
|
+
const isParam = Array.isArray(pattern);
|
|
1598
|
+
const key = isParam ? pattern[0] : pattern || p;
|
|
1599
|
+
const child = curNode.#children[key] ||= new Node3();
|
|
1600
|
+
if (pattern && !child.#pattern) {
|
|
1601
|
+
child.#pattern = pattern;
|
|
1602
|
+
curNode.#patterns.push(child);
|
|
1603
|
+
}
|
|
1604
|
+
curNode = child;
|
|
1605
|
+
if (isParam) possibleKeys.add(pattern[1]);
|
|
1606
|
+
}
|
|
1607
|
+
curNode.#methods.push({ [method]: {
|
|
1608
|
+
handler,
|
|
1609
|
+
possibleKeys: [...possibleKeys],
|
|
1610
|
+
score: ++order
|
|
1611
|
+
} });
|
|
1896
1612
|
}
|
|
1897
1613
|
#pushHandlerSets(handlerSets, node, method, nodeParams, params) {
|
|
1898
1614
|
for (let i = 0, len = node.#methods.length; i < len; i++) {
|
|
1899
1615
|
const m = node.#methods[i];
|
|
1900
|
-
const handlerSet = m[method] || m[
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
handlerSet.params = /* @__PURE__ */ Object.create(null);
|
|
1616
|
+
const handlerSet = m[method] || m["ALL"];
|
|
1617
|
+
if (handlerSet) {
|
|
1618
|
+
handlerSet.params = createNullObject();
|
|
1904
1619
|
handlerSets.push(handlerSet);
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
const processed = processedSet[handlerSet.score];
|
|
1909
|
-
handlerSet.params[key] = params?.[key] && !processed ? params[key] : nodeParams[key] ?? params?.[key];
|
|
1910
|
-
processedSet[handlerSet.score] = true;
|
|
1911
|
-
}
|
|
1620
|
+
for (let i2 = 0, len2 = handlerSet.possibleKeys.length; i2 < len2; i2++) {
|
|
1621
|
+
const key = handlerSet.possibleKeys[i2];
|
|
1622
|
+
handlerSet.params[key] = params?.[key] && !i2 ? params[key] : nodeParams[key] ?? params?.[key];
|
|
1912
1623
|
}
|
|
1913
1624
|
}
|
|
1914
1625
|
}
|
|
@@ -1916,8 +1627,7 @@ var Node = class _Node2 {
|
|
|
1916
1627
|
search(method, path) {
|
|
1917
1628
|
const handlerSets = [];
|
|
1918
1629
|
this.#params = emptyParams;
|
|
1919
|
-
|
|
1920
|
-
let curNodes = [curNode];
|
|
1630
|
+
let curNodes = [this];
|
|
1921
1631
|
const parts = splitPath(path);
|
|
1922
1632
|
const curNodesQueue = [];
|
|
1923
1633
|
const len = parts.length;
|
|
@@ -1932,76 +1642,54 @@ var Node = class _Node2 {
|
|
|
1932
1642
|
if (nextNode) {
|
|
1933
1643
|
nextNode.#params = node.#params;
|
|
1934
1644
|
if (isLast) {
|
|
1935
|
-
if (nextNode.#children["*"])
|
|
1936
|
-
this.#pushHandlerSets(handlerSets, nextNode.#children["*"], method, node.#params);
|
|
1937
|
-
}
|
|
1645
|
+
if (nextNode.#children["*"]) this.#pushHandlerSets(handlerSets, nextNode.#children["*"], method, node.#params);
|
|
1938
1646
|
this.#pushHandlerSets(handlerSets, nextNode, method, node.#params);
|
|
1939
|
-
} else
|
|
1940
|
-
tempNodes.push(nextNode);
|
|
1941
|
-
}
|
|
1647
|
+
} else tempNodes.push(nextNode);
|
|
1942
1648
|
}
|
|
1943
|
-
for (
|
|
1944
|
-
const pattern =
|
|
1649
|
+
for (const child of node.#patterns) {
|
|
1650
|
+
const pattern = child.#pattern;
|
|
1945
1651
|
const params = node.#params === emptyParams ? {} : { ...node.#params };
|
|
1946
|
-
if (pattern === "
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1652
|
+
if (typeof pattern === "string") {
|
|
1653
|
+
if (pattern === "*" || part.startsWith(pattern.slice(0, -1))) {
|
|
1654
|
+
this.#pushHandlerSets(handlerSets, child, method, node.#params);
|
|
1655
|
+
if (pattern === "*") {
|
|
1656
|
+
child.#params = params;
|
|
1657
|
+
tempNodes.push(child);
|
|
1658
|
+
}
|
|
1952
1659
|
}
|
|
1953
1660
|
continue;
|
|
1954
1661
|
}
|
|
1955
|
-
const [
|
|
1956
|
-
if (!part &&
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
if (matcher instanceof RegExp) {
|
|
1961
|
-
if (partOffsets === null) {
|
|
1962
|
-
partOffsets = new Array(len);
|
|
1662
|
+
const [, name, matcher] = pattern;
|
|
1663
|
+
if (!part && matcher === true) continue;
|
|
1664
|
+
if (matcher !== true) {
|
|
1665
|
+
if (!partOffsets) {
|
|
1666
|
+
partOffsets = [];
|
|
1963
1667
|
let offset = path[0] === "/" ? 1 : 0;
|
|
1964
1668
|
for (let p = 0; p < len; p++) {
|
|
1965
1669
|
partOffsets[p] = offset;
|
|
1966
1670
|
offset += parts[p].length + 1;
|
|
1967
1671
|
}
|
|
1968
1672
|
}
|
|
1969
|
-
const restPathString = path.
|
|
1673
|
+
const restPathString = path.slice(partOffsets[i]);
|
|
1970
1674
|
const m = matcher.exec(restPathString);
|
|
1971
1675
|
if (m) {
|
|
1972
|
-
params[name] = m[0];
|
|
1676
|
+
if (!Object.hasOwn(params, name)) params[name] = m[0];
|
|
1973
1677
|
this.#pushHandlerSets(handlerSets, child, method, node.#params, params);
|
|
1974
|
-
if (m[0].length === restPathString.length && child.#children["*"])
|
|
1975
|
-
|
|
1976
|
-
handlerSets,
|
|
1977
|
-
child.#children["*"],
|
|
1978
|
-
method,
|
|
1979
|
-
node.#params,
|
|
1980
|
-
params
|
|
1981
|
-
);
|
|
1982
|
-
}
|
|
1983
|
-
if (hasChildren(child.#children)) {
|
|
1678
|
+
if (m[0].length === restPathString.length && child.#children["*"]) this.#pushHandlerSets(handlerSets, child.#children["*"], method, node.#params, params);
|
|
1679
|
+
for (const _ in child.#children) {
|
|
1984
1680
|
child.#params = params;
|
|
1985
1681
|
const componentCount = m[0].match(/\//g)?.length ?? 0;
|
|
1986
|
-
|
|
1987
|
-
|
|
1682
|
+
(curNodesQueue[componentCount] ||= []).push(child);
|
|
1683
|
+
break;
|
|
1988
1684
|
}
|
|
1989
1685
|
continue;
|
|
1990
1686
|
}
|
|
1991
1687
|
}
|
|
1992
1688
|
if (matcher === true || matcher.test(part)) {
|
|
1993
|
-
params[name] = part;
|
|
1689
|
+
if (!Object.hasOwn(params, name)) params[name] = part;
|
|
1994
1690
|
if (isLast) {
|
|
1995
1691
|
this.#pushHandlerSets(handlerSets, child, method, params, node.#params);
|
|
1996
|
-
if (child.#children["*"])
|
|
1997
|
-
this.#pushHandlerSets(
|
|
1998
|
-
handlerSets,
|
|
1999
|
-
child.#children["*"],
|
|
2000
|
-
method,
|
|
2001
|
-
params,
|
|
2002
|
-
node.#params
|
|
2003
|
-
);
|
|
2004
|
-
}
|
|
1692
|
+
if (child.#children["*"]) this.#pushHandlerSets(handlerSets, child.#children["*"], method, params, node.#params);
|
|
2005
1693
|
} else {
|
|
2006
1694
|
child.#params = params;
|
|
2007
1695
|
tempNodes.push(child);
|
|
@@ -2012,45 +1700,31 @@ var Node = class _Node2 {
|
|
|
2012
1700
|
const shifted = curNodesQueue.shift();
|
|
2013
1701
|
curNodes = shifted ? tempNodes.concat(shifted) : tempNodes;
|
|
2014
1702
|
}
|
|
2015
|
-
if (handlerSets.
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
});
|
|
2019
|
-
}
|
|
1703
|
+
if (handlerSets[1]) handlerSets.sort((a, b) => {
|
|
1704
|
+
return a.score - b.score;
|
|
1705
|
+
});
|
|
2020
1706
|
return [handlerSets.map(({ handler, params }) => [handler, params])];
|
|
2021
1707
|
}
|
|
2022
1708
|
};
|
|
2023
1709
|
var TrieRouter = class {
|
|
2024
1710
|
name = "TrieRouter";
|
|
2025
|
-
#node;
|
|
2026
|
-
constructor() {
|
|
2027
|
-
this.#node = new Node();
|
|
2028
|
-
}
|
|
1711
|
+
#node = new Node2();
|
|
2029
1712
|
add(method, path, handler) {
|
|
2030
|
-
const
|
|
2031
|
-
if (results) {
|
|
2032
|
-
for (let i = 0, len = results.length; i < len; i++) {
|
|
2033
|
-
this.#node.insert(method, results[i], handler);
|
|
2034
|
-
}
|
|
2035
|
-
return;
|
|
2036
|
-
}
|
|
2037
|
-
this.#node.insert(method, path, handler);
|
|
1713
|
+
for (const result of checkOptionalParameter(path) || [path]) this.#node.insert(method, result, handler);
|
|
2038
1714
|
}
|
|
2039
1715
|
match(method, path) {
|
|
2040
1716
|
return this.#node.search(method, path);
|
|
2041
1717
|
}
|
|
2042
1718
|
};
|
|
2043
|
-
var
|
|
1719
|
+
var Hono2 = class extends Hono$1 {
|
|
2044
1720
|
/**
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
1721
|
+
* Creates an instance of the Hono class.
|
|
1722
|
+
*
|
|
1723
|
+
* @param options - Optional configuration options for the Hono instance.
|
|
1724
|
+
*/
|
|
2049
1725
|
constructor(options = {}) {
|
|
2050
1726
|
super(options);
|
|
2051
|
-
this.router = options.router ?? new SmartRouter({
|
|
2052
|
-
routers: [new RegExpRouter(), new TrieRouter()]
|
|
2053
|
-
});
|
|
1727
|
+
this.router = options.router ?? new SmartRouter({ routers: [new RegExpRouter(), new TrieRouter()] });
|
|
2054
1728
|
}
|
|
2055
1729
|
};
|
|
2056
1730
|
class AuthError extends Error {
|
|
@@ -2095,86 +1769,57 @@ class PublicationError extends Error {
|
|
|
2095
1769
|
}
|
|
2096
1770
|
retryable;
|
|
2097
1771
|
}
|
|
2098
|
-
const encoder$2 = new TextEncoder();
|
|
2099
|
-
const decoder$1 = new TextDecoder();
|
|
2100
|
-
const strictDecoder = new TextDecoder("utf-8", { fatal: true });
|
|
1772
|
+
const encoder$2 = new TextEncoder(), decoder$1 = new TextDecoder(), strictDecoder = new TextDecoder("utf-8", { fatal: true });
|
|
2101
1773
|
function concat(...buffers) {
|
|
2102
|
-
const size = buffers.reduce((acc, { length }) => acc + length, 0);
|
|
2103
|
-
const buf = new Uint8Array(size);
|
|
1774
|
+
const size = buffers.reduce((acc, { length }) => acc + length, 0), buf = new Uint8Array(size);
|
|
2104
1775
|
let i = 0;
|
|
2105
|
-
for (const buffer of buffers)
|
|
2106
|
-
buf.set(buffer, i);
|
|
2107
|
-
i += buffer.length;
|
|
2108
|
-
}
|
|
1776
|
+
for (const buffer of buffers)
|
|
1777
|
+
buf.set(buffer, i), i += buffer.length;
|
|
2109
1778
|
return buf;
|
|
2110
1779
|
}
|
|
1780
|
+
const NON_ASCII = /[^\x00-\x7f]/;
|
|
2111
1781
|
function encode$1(string) {
|
|
1782
|
+
if (typeof string == "string" && string.length >= 128) {
|
|
1783
|
+
if (NON_ASCII.test(string))
|
|
1784
|
+
throw new TypeError("non-ASCII string encountered in encode()");
|
|
1785
|
+
return encoder$2.encode(string);
|
|
1786
|
+
}
|
|
2112
1787
|
const bytes = new Uint8Array(string.length);
|
|
2113
1788
|
for (let i = 0; i < string.length; i++) {
|
|
2114
1789
|
const code = string.charCodeAt(i);
|
|
2115
|
-
if (code > 127)
|
|
1790
|
+
if (code > 127)
|
|
2116
1791
|
throw new TypeError("non-ASCII string encountered in encode()");
|
|
2117
|
-
}
|
|
2118
1792
|
bytes[i] = code;
|
|
2119
1793
|
}
|
|
2120
1794
|
return bytes;
|
|
2121
1795
|
}
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
}
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
}
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
throw unusable(expected.namedCurve, "algorithm.namedCurve");
|
|
2144
|
-
}
|
|
2145
|
-
if (expected.length !== void 0 && algorithm.length !== expected.length) {
|
|
2146
|
-
throw unusable(expected.length, "algorithm.length");
|
|
2147
|
-
}
|
|
2148
|
-
checkUsage(key, usage);
|
|
2149
|
-
}
|
|
2150
|
-
function message(msg, actual, ...types) {
|
|
2151
|
-
if (types.length > 2) {
|
|
2152
|
-
const last = types.pop();
|
|
2153
|
-
msg += `one of type ${types.join(", ")}, or ${last}.`;
|
|
2154
|
-
} else if (types.length === 2) {
|
|
2155
|
-
msg += `one of type ${types[0]} or ${types[1]}.`;
|
|
2156
|
-
} else {
|
|
2157
|
-
msg += `of type ${types[0]}.`;
|
|
2158
|
-
}
|
|
2159
|
-
if (actual == null) {
|
|
2160
|
-
msg += ` Received ${actual}`;
|
|
2161
|
-
} else if (typeof actual === "function" && actual.name) {
|
|
2162
|
-
msg += ` Received function ${actual.name}`;
|
|
2163
|
-
} else if (typeof actual === "object" && actual != null) {
|
|
2164
|
-
if (actual.constructor?.name) {
|
|
2165
|
-
msg += ` Received an instance of ${actual.constructor.name}`;
|
|
2166
|
-
}
|
|
2167
|
-
}
|
|
2168
|
-
return msg;
|
|
1796
|
+
function encodeBase64(input, url = false) {
|
|
1797
|
+
if (Uint8Array.prototype.toBase64)
|
|
1798
|
+
return input.toBase64({ alphabet: url ? "base64url" : "base64", omitPadding: url });
|
|
1799
|
+
const CHUNK_SIZE = 32768, arr = [];
|
|
1800
|
+
for (let i = 0; i < input.length; i += CHUNK_SIZE)
|
|
1801
|
+
arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));
|
|
1802
|
+
const encoded = btoa(arr.join(""));
|
|
1803
|
+
return url ? encoded.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_") : encoded;
|
|
1804
|
+
}
|
|
1805
|
+
function decodeBase64(encoded, url = false) {
|
|
1806
|
+
if (Uint8Array.fromBase64)
|
|
1807
|
+
return Uint8Array.fromBase64(encoded, { alphabet: url ? "base64url" : "base64" });
|
|
1808
|
+
if (url) {
|
|
1809
|
+
if (encoded.includes("+") || encoded.includes("/"))
|
|
1810
|
+
throw new TypeError("Invalid base64url");
|
|
1811
|
+
encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
1812
|
+
}
|
|
1813
|
+
const binary = atob(encoded), bytes = new Uint8Array(binary.length);
|
|
1814
|
+
for (let i = 0; i < binary.length; i++)
|
|
1815
|
+
bytes[i] = binary.charCodeAt(i);
|
|
1816
|
+
return bytes;
|
|
2169
1817
|
}
|
|
2170
|
-
const withAlg = (alg, actual, ...types) => message(`Key for the ${alg} algorithm must be `, actual, ...types);
|
|
2171
1818
|
class JOSEError extends Error {
|
|
2172
1819
|
static code = "ERR_JOSE_GENERIC";
|
|
2173
1820
|
code = "ERR_JOSE_GENERIC";
|
|
2174
1821
|
constructor(message2, options) {
|
|
2175
|
-
super(message2, options);
|
|
2176
|
-
this.name = this.constructor.name;
|
|
2177
|
-
Error.captureStackTrace?.(this, this.constructor);
|
|
1822
|
+
super(message2, options), this.name = this.constructor.name, Error.captureStackTrace?.(this, this.constructor);
|
|
2178
1823
|
}
|
|
2179
1824
|
}
|
|
2180
1825
|
class JWTClaimValidationFailed extends JOSEError {
|
|
@@ -2184,10 +1829,7 @@ class JWTClaimValidationFailed extends JOSEError {
|
|
|
2184
1829
|
reason;
|
|
2185
1830
|
payload;
|
|
2186
1831
|
constructor(message2, payload, claim = "unspecified", reason = "unspecified") {
|
|
2187
|
-
super(message2, { cause: { claim, reason, payload } });
|
|
2188
|
-
this.claim = claim;
|
|
2189
|
-
this.reason = reason;
|
|
2190
|
-
this.payload = payload;
|
|
1832
|
+
super(message2, { cause: { claim, reason, payload } }), this.claim = claim, this.reason = reason, this.payload = payload;
|
|
2191
1833
|
}
|
|
2192
1834
|
}
|
|
2193
1835
|
class JWTExpired extends JOSEError {
|
|
@@ -2197,10 +1839,7 @@ class JWTExpired extends JOSEError {
|
|
|
2197
1839
|
reason;
|
|
2198
1840
|
payload;
|
|
2199
1841
|
constructor(message2, payload, claim = "unspecified", reason = "unspecified") {
|
|
2200
|
-
super(message2, { cause: { claim, reason, payload } });
|
|
2201
|
-
this.claim = claim;
|
|
2202
|
-
this.reason = reason;
|
|
2203
|
-
this.payload = payload;
|
|
1842
|
+
super(message2, { cause: { claim, reason, payload } }), this.claim = claim, this.reason = reason, this.payload = payload;
|
|
2204
1843
|
}
|
|
2205
1844
|
}
|
|
2206
1845
|
class JOSEAlgNotAllowed extends JOSEError {
|
|
@@ -2246,207 +1885,168 @@ class JWSSignatureVerificationFailed extends JOSEError {
|
|
|
2246
1885
|
super(message2, options);
|
|
2247
1886
|
}
|
|
2248
1887
|
}
|
|
2249
|
-
const
|
|
2250
|
-
|
|
2251
|
-
return true;
|
|
1888
|
+
const invalid$1 = "The input to be decoded is not correctly encoded.";
|
|
1889
|
+
function decode(input) {
|
|
2252
1890
|
try {
|
|
2253
|
-
return
|
|
2254
|
-
} catch {
|
|
2255
|
-
|
|
2256
|
-
}
|
|
2257
|
-
};
|
|
2258
|
-
const isKeyObject = (key) => key?.[Symbol.toStringTag] === "KeyObject";
|
|
2259
|
-
const isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);
|
|
2260
|
-
function encodeBase64(input) {
|
|
2261
|
-
if (Uint8Array.prototype.toBase64) {
|
|
2262
|
-
return input.toBase64();
|
|
2263
|
-
}
|
|
2264
|
-
const CHUNK_SIZE = 32768;
|
|
2265
|
-
const arr = [];
|
|
2266
|
-
for (let i = 0; i < input.length; i += CHUNK_SIZE) {
|
|
2267
|
-
arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));
|
|
2268
|
-
}
|
|
2269
|
-
return btoa(arr.join(""));
|
|
2270
|
-
}
|
|
2271
|
-
function decodeBase64(encoded) {
|
|
2272
|
-
if (Uint8Array.fromBase64) {
|
|
2273
|
-
return Uint8Array.fromBase64(encoded);
|
|
2274
|
-
}
|
|
2275
|
-
const binary = atob(encoded);
|
|
2276
|
-
const bytes = new Uint8Array(binary.length);
|
|
2277
|
-
for (let i = 0; i < binary.length; i++) {
|
|
2278
|
-
bytes[i] = binary.charCodeAt(i);
|
|
2279
|
-
}
|
|
2280
|
-
return bytes;
|
|
2281
|
-
}
|
|
2282
|
-
const invalid$1 = "The input to be decoded is not correctly encoded.";
|
|
2283
|
-
function decode(input) {
|
|
2284
|
-
if (Uint8Array.fromBase64) {
|
|
2285
|
-
try {
|
|
2286
|
-
return Uint8Array.fromBase64(typeof input === "string" ? input : decoder$1.decode(input), {
|
|
2287
|
-
alphabet: "base64url"
|
|
2288
|
-
});
|
|
2289
|
-
} catch (cause) {
|
|
2290
|
-
throw new TypeError(invalid$1, { cause });
|
|
2291
|
-
}
|
|
2292
|
-
}
|
|
2293
|
-
let encoded = input;
|
|
2294
|
-
if (encoded instanceof Uint8Array) {
|
|
2295
|
-
encoded = decoder$1.decode(encoded);
|
|
2296
|
-
}
|
|
2297
|
-
if (encoded.includes("+") || encoded.includes("/")) {
|
|
2298
|
-
throw new TypeError(invalid$1);
|
|
2299
|
-
}
|
|
2300
|
-
encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
2301
|
-
try {
|
|
2302
|
-
return decodeBase64(encoded);
|
|
2303
|
-
} catch {
|
|
2304
|
-
throw new TypeError(invalid$1);
|
|
1891
|
+
return decodeBase64(typeof input == "string" ? input : decoder$1.decode(input), true);
|
|
1892
|
+
} catch (cause) {
|
|
1893
|
+
throw new TypeError(invalid$1, { cause });
|
|
2305
1894
|
}
|
|
2306
1895
|
}
|
|
2307
1896
|
function encode(input) {
|
|
2308
|
-
|
|
2309
|
-
if (typeof unencoded === "string") {
|
|
2310
|
-
unencoded = encoder$2.encode(unencoded);
|
|
2311
|
-
}
|
|
2312
|
-
if (Uint8Array.prototype.toBase64) {
|
|
2313
|
-
return unencoded.toBase64({ alphabet: "base64url", omitPadding: true });
|
|
2314
|
-
}
|
|
2315
|
-
return encodeBase64(unencoded).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
1897
|
+
return encodeBase64(typeof input == "string" ? encoder$2.encode(input) : input, true);
|
|
2316
1898
|
}
|
|
2317
1899
|
function isObject(input) {
|
|
2318
|
-
if (typeof input
|
|
1900
|
+
if (typeof input != "object" || input === null || Object.prototype.toString.call(input) !== "[object Object]")
|
|
2319
1901
|
return false;
|
|
2320
|
-
}
|
|
2321
1902
|
const prototype = Object.getPrototypeOf(input);
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
while (Object.getPrototypeOf(proto) !== null) {
|
|
2327
|
-
proto = Object.getPrototypeOf(proto);
|
|
2328
|
-
}
|
|
2329
|
-
return prototype === proto;
|
|
1903
|
+
return prototype === null || Object.getPrototypeOf(prototype) === null;
|
|
1904
|
+
}
|
|
1905
|
+
function isJwkSet(input) {
|
|
1906
|
+
return isObject(input) && Array.isArray(input.keys) && Array.from(input.keys).every(isObject);
|
|
2330
1907
|
}
|
|
2331
1908
|
function isDisjoint(...headers) {
|
|
2332
1909
|
const parameters = /* @__PURE__ */ new Set();
|
|
2333
|
-
for (const header of headers)
|
|
2334
|
-
if (
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
1910
|
+
for (const header of headers)
|
|
1911
|
+
if (header)
|
|
1912
|
+
for (const parameter of Object.keys(header)) {
|
|
1913
|
+
if (parameters.has(parameter))
|
|
1914
|
+
return false;
|
|
1915
|
+
parameters.add(parameter);
|
|
2339
1916
|
}
|
|
2340
|
-
parameters.add(parameter);
|
|
2341
|
-
}
|
|
2342
|
-
}
|
|
2343
1917
|
return true;
|
|
2344
1918
|
}
|
|
2345
|
-
const isJWK = (key) => isObject(key) && typeof key.kty === "string";
|
|
2346
|
-
const isPrivateJWK = (key) => key.kty !== "oct" && (key.kty === "AKP" && typeof key.priv === "string" || typeof key.d === "string");
|
|
2347
|
-
const isPublicJWK = (key) => key.kty !== "oct" && key.d === void 0 && key.priv === void 0;
|
|
2348
|
-
const isSecretJWK = (key) => key.kty === "oct" && typeof key.k === "string";
|
|
2349
1919
|
function assertNotSet(value, name) {
|
|
2350
|
-
if (value)
|
|
1920
|
+
if (value !== void 0)
|
|
2351
1921
|
throw new TypeError(`${name} can only be called once`);
|
|
2352
|
-
}
|
|
2353
1922
|
}
|
|
2354
1923
|
function decodeBase64url(value, label, ErrorClass) {
|
|
2355
1924
|
try {
|
|
2356
1925
|
return decode(value);
|
|
2357
|
-
} catch {
|
|
2358
|
-
throw new ErrorClass(`Failed to base64url decode the ${label}
|
|
1926
|
+
} catch (cause) {
|
|
1927
|
+
throw new ErrorClass(`Failed to base64url decode the ${label}`, { cause });
|
|
2359
1928
|
}
|
|
2360
1929
|
}
|
|
2361
|
-
function
|
|
1930
|
+
function encodeAsciiMember(value, label, ErrorClass) {
|
|
2362
1931
|
try {
|
|
2363
1932
|
return encode$1(value);
|
|
2364
|
-
} catch {
|
|
2365
|
-
throw new ErrorClass(`The ${label} is not a valid base64url string
|
|
1933
|
+
} catch (cause) {
|
|
1934
|
+
throw new ErrorClass(`The ${label} is not a valid base64url string`, { cause });
|
|
2366
1935
|
}
|
|
2367
1936
|
}
|
|
2368
|
-
function parseJoseHeader(
|
|
1937
|
+
function parseJoseHeader(encodedProtectedHeader, ErrorClass, message2) {
|
|
2369
1938
|
let parsed;
|
|
2370
1939
|
try {
|
|
2371
|
-
parsed = JSON.parse(strictDecoder.decode(decode(
|
|
2372
|
-
} catch {
|
|
2373
|
-
throw new ErrorClass(message2);
|
|
1940
|
+
parsed = JSON.parse(strictDecoder.decode(decode(encodedProtectedHeader)));
|
|
1941
|
+
} catch (cause) {
|
|
1942
|
+
throw new ErrorClass(message2, { cause });
|
|
2374
1943
|
}
|
|
2375
|
-
if (!isObject(parsed))
|
|
1944
|
+
if (!isObject(parsed))
|
|
2376
1945
|
throw new ErrorClass(message2);
|
|
2377
|
-
}
|
|
2378
1946
|
return parsed;
|
|
2379
1947
|
}
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
1948
|
+
const JWS_RECOGNIZED = { __proto__: null, b64: true };
|
|
1949
|
+
function validateAlgorithms(option, algorithms) {
|
|
1950
|
+
if (algorithms !== void 0 && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s != "string")))
|
|
1951
|
+
throw new TypeError(`"${option}" option must be an array of strings`);
|
|
1952
|
+
return algorithms === void 0 ? void 0 : new Set(algorithms);
|
|
1953
|
+
}
|
|
1954
|
+
function validateCritDuplicates(Err, protectedHeader) {
|
|
1955
|
+
const { crit } = protectedHeader ?? {};
|
|
1956
|
+
if (Array.isArray(crit) && new Set(crit).size !== crit.length)
|
|
1957
|
+
throw new Err('"crit" (Critical) Header Parameter MUST NOT contain duplicate values');
|
|
1958
|
+
}
|
|
1959
|
+
function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
|
|
1960
|
+
if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0)
|
|
1961
|
+
throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
|
|
1962
|
+
if (!protectedHeader || protectedHeader.crit === void 0)
|
|
1963
|
+
return [];
|
|
1964
|
+
if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input != "string" || input.length === 0))
|
|
1965
|
+
throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');
|
|
1966
|
+
const recognized = recognizedOption === void 0 ? recognizedDefault : { __proto__: null, ...recognizedOption, ...recognizedDefault };
|
|
1967
|
+
for (const parameter of protectedHeader.crit) {
|
|
1968
|
+
if (!(parameter in recognized))
|
|
1969
|
+
throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
|
|
1970
|
+
if (!Object.hasOwn(joseHeader, parameter) || joseHeader[parameter] === void 0)
|
|
1971
|
+
throw new Err(`Extension Header Parameter "${parameter}" is missing`);
|
|
1972
|
+
if (recognized[parameter] && (!Object.hasOwn(protectedHeader, parameter) || protectedHeader[parameter] === void 0))
|
|
1973
|
+
throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
|
|
2383
1974
|
}
|
|
2384
|
-
|
|
2385
|
-
|
|
1975
|
+
return protectedHeader.crit;
|
|
1976
|
+
}
|
|
1977
|
+
function validateB64(protectedHeader, extensions) {
|
|
1978
|
+
if (extensions.includes("b64")) {
|
|
1979
|
+
const b64 = protectedHeader.b64;
|
|
1980
|
+
if (typeof b64 != "boolean")
|
|
1981
|
+
throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
|
|
1982
|
+
return b64;
|
|
2386
1983
|
}
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
1984
|
+
return true;
|
|
1985
|
+
}
|
|
1986
|
+
function serializeJoseHeader(Err, header) {
|
|
1987
|
+
let serialized, parsed;
|
|
1988
|
+
try {
|
|
1989
|
+
serialized = JSON.stringify(header), parsed = JSON.parse(serialized);
|
|
1990
|
+
} catch (cause) {
|
|
1991
|
+
throw new Err("JOSE Header is not valid JSON", { cause });
|
|
2392
1992
|
}
|
|
2393
|
-
|
|
2394
|
-
|
|
1993
|
+
if (!isObject(parsed))
|
|
1994
|
+
throw new Err("JOSE Header is not a JSON object");
|
|
1995
|
+
return [parsed, serialized];
|
|
2395
1996
|
}
|
|
2396
|
-
const tag = (key) => key[Symbol.toStringTag]
|
|
2397
|
-
const jwkMatchesOp = (entry, key, usage) => {
|
|
1997
|
+
const tag = (key) => key[Symbol.toStringTag], jwkMatchesOp = (entry, key, usage) => {
|
|
2398
1998
|
const { alg } = entry;
|
|
2399
1999
|
if (key.use !== void 0) {
|
|
2400
2000
|
const expected = usage === "sign" || usage === "verify" ? "sig" : "enc";
|
|
2401
|
-
if (key.use !== expected)
|
|
2001
|
+
if (key.use !== expected)
|
|
2402
2002
|
throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`);
|
|
2403
|
-
}
|
|
2404
2003
|
}
|
|
2405
|
-
if (key.alg !== void 0 && key.alg !== alg)
|
|
2004
|
+
if (key.alg !== void 0 && key.alg !== alg)
|
|
2406
2005
|
throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`);
|
|
2407
|
-
}
|
|
2408
2006
|
if (Array.isArray(key.key_ops)) {
|
|
2409
2007
|
const expectedKeyOp = usage === "encrypt" || usage === "decrypt" ? entry.ops?.[usage === "encrypt" ? 0 : 1] : usage;
|
|
2410
|
-
if (expectedKeyOp && !key.key_ops.includes(expectedKeyOp))
|
|
2008
|
+
if (expectedKeyOp && !key.key_ops.includes(expectedKeyOp))
|
|
2411
2009
|
throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
|
|
2412
|
-
}
|
|
2413
2010
|
}
|
|
2414
2011
|
};
|
|
2415
|
-
function
|
|
2416
|
-
const { alg, secret } = entry;
|
|
2417
|
-
const privateKey = usage === "decrypt" || usage === "sign";
|
|
2012
|
+
async function prepareKey(entry, key, usage) {
|
|
2013
|
+
const { alg, secret } = entry, requiresPrivateKey = usage === "decrypt" || usage === "sign";
|
|
2418
2014
|
if (secret && key instanceof Uint8Array)
|
|
2419
|
-
return
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
if (key.type !== "secret") {
|
|
2432
|
-
throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`);
|
|
2015
|
+
return key;
|
|
2016
|
+
let normalized, keyObject;
|
|
2017
|
+
if (isObject(key)) {
|
|
2018
|
+
if (normalized = normalizeJwk(key), typeof normalized.kty != "string")
|
|
2019
|
+
throw invalidKeyType(alg, key, secret);
|
|
2020
|
+
if (!(secret ? normalized.kty === "oct" && typeof normalized.k == "string" : normalized.kty !== "oct" && (requiresPrivateKey ? normalized.kty === "AKP" && typeof normalized.priv == "string" || typeof normalized.d == "string" : normalized.d === void 0 && normalized.priv === void 0)))
|
|
2021
|
+
throw new TypeError(secret ? 'JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present' : `JSON Web Key for this operation must be a ${requiresPrivateKey ? "private" : "public"} JWK`);
|
|
2022
|
+
if (jwkMatchesOp(entry, normalized, usage), normalized.kty === "oct")
|
|
2023
|
+
return decode(normalized.k);
|
|
2024
|
+
if (!Object.isFrozen(key)) {
|
|
2025
|
+
const { key_ops } = key;
|
|
2026
|
+
Array.isArray(key_ops) && Object.freeze(key_ops), Object.freeze(key);
|
|
2433
2027
|
}
|
|
2434
2028
|
} else {
|
|
2435
|
-
if (key
|
|
2436
|
-
throw
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2029
|
+
if (!isKeyLike(key))
|
|
2030
|
+
throw invalidKeyType(alg, key, secret);
|
|
2031
|
+
const expectedType = secret ? "secret" : requiresPrivateKey ? "private" : "public";
|
|
2032
|
+
if (key.type !== expectedType && (secret || ["secret", "public", "private"].includes(key.type)))
|
|
2033
|
+
throw new TypeError(`${tag(key)} instances must be of type "${expectedType}" for the ${alg} algorithm`);
|
|
2034
|
+
if (isCryptoKey(key))
|
|
2035
|
+
return key;
|
|
2036
|
+
if (keyObject = key, keyObject.type === "secret")
|
|
2037
|
+
return keyObject.export();
|
|
2443
2038
|
}
|
|
2444
|
-
|
|
2039
|
+
cache ||= /* @__PURE__ */ new WeakMap();
|
|
2040
|
+
const cacheKey = key;
|
|
2041
|
+
let cached = cache.get(cacheKey);
|
|
2042
|
+
if (cached?.[alg])
|
|
2043
|
+
return cached[alg];
|
|
2044
|
+
if (cached || cache.set(cacheKey, cached = {}), keyObject && typeof keyObject.toCryptoKey == "function") {
|
|
2045
|
+
const isPublic = keyObject.type === "public", crv = nist[keyObject.asymmetricKeyDetails?.namedCurve], params = entry.resolve?.({ crv, asymmetricKeyType: keyObject.asymmetricKeyType }) ?? entry.subtle;
|
|
2046
|
+
return cached[alg] = keyObject.toCryptoKey(params, isPublic, entry.usages[isPublic ? 0 : 1]);
|
|
2047
|
+
}
|
|
2048
|
+
return normalized ??= keyObject.export({ format: "jwk" }), normalized.alg = alg, cached[alg] = await jwkToKey(entry, normalized);
|
|
2445
2049
|
}
|
|
2446
|
-
const BYTES = 0;
|
|
2447
|
-
const CRYPTO = 1;
|
|
2448
|
-
const KEYOBJECT = 2;
|
|
2449
|
-
const JWK = 3;
|
|
2450
2050
|
let cache;
|
|
2451
2051
|
const nist = {
|
|
2452
2052
|
__proto__: null,
|
|
@@ -2454,93 +2054,104 @@ const nist = {
|
|
|
2454
2054
|
secp384r1: "P-384",
|
|
2455
2055
|
secp521r1: "P-521"
|
|
2456
2056
|
};
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
cache.set(key, { __proto__: null, [alg]: value });
|
|
2465
|
-
}
|
|
2466
|
-
}
|
|
2467
|
-
return value ?? entry?.[alg];
|
|
2468
|
-
}
|
|
2469
|
-
const handleJWK = async (key, jwk, entry) => cached(key, entry.alg) ?? cached(key, entry.alg, await jwkToKey(entry, { ...jwk, alg: entry.alg }));
|
|
2470
|
-
const handleKeyObject = (keyObject, entry) => {
|
|
2471
|
-
const hit = cached(keyObject, entry.alg);
|
|
2472
|
-
if (hit)
|
|
2473
|
-
return hit;
|
|
2474
|
-
const isPublic = keyObject.type === "public";
|
|
2475
|
-
const usages = entry.usages[isPublic ? 0 : 1];
|
|
2476
|
-
const { asymmetricKeyType } = keyObject;
|
|
2477
|
-
const crv = nist[keyObject.asymmetricKeyDetails?.namedCurve];
|
|
2478
|
-
const params = entry.resolve?.({ crv, asymmetricKeyType }) ?? entry.subtle;
|
|
2479
|
-
return cached(keyObject, entry.alg, keyObject.toCryptoKey(params, isPublic, usages));
|
|
2480
|
-
};
|
|
2481
|
-
async function prepareKey(entry, key, usage) {
|
|
2482
|
-
const tagged = checkKeyType(entry, key, usage);
|
|
2483
|
-
switch (tagged[0]) {
|
|
2484
|
-
case BYTES:
|
|
2485
|
-
case CRYPTO:
|
|
2486
|
-
return tagged[1];
|
|
2487
|
-
case JWK: {
|
|
2488
|
-
const key2 = tagged[1];
|
|
2489
|
-
if (key2.k) {
|
|
2490
|
-
return decode(key2.k);
|
|
2491
|
-
}
|
|
2492
|
-
if (!Object.isFrozen(key2)) {
|
|
2493
|
-
const { key_ops } = key2;
|
|
2494
|
-
if (Array.isArray(key_ops))
|
|
2495
|
-
Object.freeze(key_ops);
|
|
2496
|
-
Object.freeze(key2);
|
|
2497
|
-
}
|
|
2498
|
-
return handleJWK(key2, key2, entry);
|
|
2499
|
-
}
|
|
2500
|
-
case KEYOBJECT: {
|
|
2501
|
-
const keyObject = tagged[1];
|
|
2502
|
-
if (keyObject.type === "secret") {
|
|
2503
|
-
return keyObject.export();
|
|
2504
|
-
}
|
|
2505
|
-
if ("toCryptoKey" in keyObject && typeof keyObject.toCryptoKey === "function") {
|
|
2506
|
-
return handleKeyObject(keyObject, entry);
|
|
2507
|
-
}
|
|
2508
|
-
return handleJWK(keyObject, keyObject.export({ format: "jwk" }), entry);
|
|
2509
|
-
}
|
|
2057
|
+
const isCryptoKey = (key) => {
|
|
2058
|
+
if (key?.[Symbol.toStringTag] === "CryptoKey")
|
|
2059
|
+
return true;
|
|
2060
|
+
try {
|
|
2061
|
+
return key instanceof CryptoKey;
|
|
2062
|
+
} catch {
|
|
2063
|
+
return false;
|
|
2510
2064
|
}
|
|
2065
|
+
}, isKeyObject = (key) => key?.[Symbol.toStringTag] === "KeyObject", isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);
|
|
2066
|
+
function message(msg, actual, ...types) {
|
|
2067
|
+
if (types.length > 2) {
|
|
2068
|
+
const last = types.pop();
|
|
2069
|
+
msg += `one of type ${types.join(", ")}, or ${last}.`;
|
|
2070
|
+
} else types.length === 2 ? msg += `one of type ${types[0]} or ${types[1]}.` : msg += `of type ${types[0]}.`;
|
|
2071
|
+
return actual == null ? msg += ` Received ${actual}` : typeof actual == "function" && actual.name ? msg += ` Received function ${actual.name}` : typeof actual == "object" && actual != null && actual.constructor?.name && (msg += ` Received an instance of ${actual.constructor.name}`), msg;
|
|
2072
|
+
}
|
|
2073
|
+
function invalidKeyType(alg, actual, secret) {
|
|
2074
|
+
const types = ["CryptoKey", "KeyObject", "JSON Web Key"];
|
|
2075
|
+
return secret && types.push("Uint8Array"), new TypeError(message(`Key for the ${alg} algorithm must be `, actual, ...types));
|
|
2076
|
+
}
|
|
2077
|
+
const unusable = (name, prop = "algorithm.name") => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
|
|
2078
|
+
function checkUsage(key, usage) {
|
|
2079
|
+
if (usage && !key.usages.includes(usage))
|
|
2080
|
+
throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
|
|
2081
|
+
}
|
|
2082
|
+
function checkModulusLength(alg, key) {
|
|
2083
|
+
const { modulusLength } = key.algorithm;
|
|
2084
|
+
if (typeof modulusLength != "number" || modulusLength < 2048)
|
|
2085
|
+
throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
|
|
2086
|
+
}
|
|
2087
|
+
function checkCryptoKey(key, expected, usage) {
|
|
2088
|
+
const algorithm = key.algorithm;
|
|
2089
|
+
if (algorithm.name !== expected.name)
|
|
2090
|
+
throw unusable(expected.name);
|
|
2091
|
+
if (expected.hash && algorithm.hash?.name !== expected.hash)
|
|
2092
|
+
throw unusable(expected.hash, "algorithm.hash");
|
|
2093
|
+
if (expected.namedCurve && algorithm.namedCurve !== expected.namedCurve)
|
|
2094
|
+
throw unusable(expected.namedCurve, "algorithm.namedCurve");
|
|
2095
|
+
if (expected.length !== void 0 && algorithm.length !== expected.length)
|
|
2096
|
+
throw unusable(expected.length, "algorithm.length");
|
|
2097
|
+
checkUsage(key, usage);
|
|
2098
|
+
}
|
|
2099
|
+
function snapshotJwk(jwk) {
|
|
2100
|
+
return { __proto__: null, ...jwk };
|
|
2101
|
+
}
|
|
2102
|
+
function normalizeJwk(jwk) {
|
|
2103
|
+
const normalized = snapshotJwk(jwk);
|
|
2104
|
+
if (normalized.ext !== void 0 && typeof normalized.ext != "boolean")
|
|
2105
|
+
throw new TypeError('"ext" (Extractable) Parameter must be a boolean');
|
|
2106
|
+
if (normalized.key_ops !== void 0) {
|
|
2107
|
+
const value = normalized.key_ops, keyOps = Array.isArray(value) ? [...value] : void 0;
|
|
2108
|
+
if (!keyOps || keyOps.some((operation) => typeof operation != "string") || new Set(keyOps).size !== keyOps.length)
|
|
2109
|
+
throw new TypeError('"key_ops" (Key Operations) Parameter must be an array of unique strings');
|
|
2110
|
+
normalized.key_ops = keyOps;
|
|
2111
|
+
}
|
|
2112
|
+
return normalized;
|
|
2113
|
+
}
|
|
2114
|
+
function validateExtractableOption(extractable) {
|
|
2115
|
+
return extractable;
|
|
2116
|
+
}
|
|
2117
|
+
async function jwkToKey(entry, jwk, extractable) {
|
|
2118
|
+
if (!entry.kty.includes(jwk.kty))
|
|
2119
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
2120
|
+
const algorithm = entry.resolve?.({ kty: jwk.kty, crv: jwk.crv }) ?? entry.subtle, isPrivate = !!(jwk.d || jwk.priv), keyData = { ...jwk, ext: extractable ?? jwk.ext };
|
|
2121
|
+
return keyData.kty !== "AKP" && delete keyData.alg, delete keyData.use, crypto.subtle.importKey("jwk", keyData, algorithm, keyData.ext ?? !isPrivate, jwk.key_ops ?? entry.usages[isPrivate ? 1 : 0]);
|
|
2122
|
+
}
|
|
2123
|
+
async function rawKey(key, expected, usage, extractable = false) {
|
|
2124
|
+
return key instanceof Uint8Array && (key = await crypto.subtle.importKey("raw", key, expected, extractable, [usage])), checkCryptoKey(key, expected, usage), key;
|
|
2511
2125
|
}
|
|
2512
2126
|
function table(entries) {
|
|
2513
2127
|
const out = { __proto__: null };
|
|
2514
|
-
for (const alg in entries)
|
|
2128
|
+
for (const alg in entries)
|
|
2515
2129
|
out[alg] = { ...entries[alg], alg };
|
|
2516
|
-
}
|
|
2517
2130
|
return out;
|
|
2518
2131
|
}
|
|
2519
2132
|
const wrap = [
|
|
2520
2133
|
["encrypt", "wrapKey"],
|
|
2521
2134
|
["decrypt", "unwrapKey"]
|
|
2522
|
-
];
|
|
2523
|
-
const derive = [[], ["deriveBits"]];
|
|
2524
|
-
const none = [[], []];
|
|
2135
|
+
], derive = [[], ["deriveBits"]], none = [[], []];
|
|
2525
2136
|
function rsaes(bits) {
|
|
2526
2137
|
return {
|
|
2527
2138
|
kty: ["RSA"],
|
|
2139
|
+
mode: "key-encryption",
|
|
2528
2140
|
subtle: { name: "RSA-OAEP", hash: `SHA-${bits}` },
|
|
2529
2141
|
usages: wrap,
|
|
2530
2142
|
ops: ["wrapKey", "unwrapKey"]
|
|
2531
2143
|
};
|
|
2532
2144
|
}
|
|
2533
|
-
function ecdh() {
|
|
2145
|
+
function ecdh(mode) {
|
|
2534
2146
|
return {
|
|
2535
2147
|
kty: ["EC", "OKP"],
|
|
2148
|
+
mode,
|
|
2536
2149
|
subtle: { name: "ECDH" },
|
|
2537
2150
|
resolve: ({ kty, crv, asymmetricKeyType }) => {
|
|
2538
|
-
if (crv === "X25519" || asymmetricKeyType === "x25519")
|
|
2151
|
+
if (crv === "X25519" || asymmetricKeyType === "x25519")
|
|
2539
2152
|
return { name: "X25519" };
|
|
2540
|
-
|
|
2541
|
-
if (kty === "OKP") {
|
|
2153
|
+
if (kty === "OKP")
|
|
2542
2154
|
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
2543
|
-
}
|
|
2544
2155
|
return { name: "ECDH", namedCurve: crv };
|
|
2545
2156
|
},
|
|
2546
2157
|
usages: derive,
|
|
@@ -2550,6 +2161,7 @@ function ecdh() {
|
|
|
2550
2161
|
function aeskw(bits, gcm = false) {
|
|
2551
2162
|
return {
|
|
2552
2163
|
kty: ["oct"],
|
|
2164
|
+
mode: "key-wrapping",
|
|
2553
2165
|
secret: true,
|
|
2554
2166
|
subtle: { name: gcm ? "AES-GCM" : "AES-KW", length: bits },
|
|
2555
2167
|
usages: none,
|
|
@@ -2559,6 +2171,7 @@ function aeskw(bits, gcm = false) {
|
|
|
2559
2171
|
function pbes2() {
|
|
2560
2172
|
return {
|
|
2561
2173
|
kty: ["oct"],
|
|
2174
|
+
mode: "key-wrapping",
|
|
2562
2175
|
secret: true,
|
|
2563
2176
|
subtle: { name: "PBKDF2" },
|
|
2564
2177
|
usages: none,
|
|
@@ -2568,6 +2181,7 @@ function pbes2() {
|
|
|
2568
2181
|
const JWE = table({
|
|
2569
2182
|
dir: {
|
|
2570
2183
|
kty: ["oct"],
|
|
2184
|
+
mode: "direct-encryption",
|
|
2571
2185
|
secret: true,
|
|
2572
2186
|
subtle: { name: "AES-GCM" },
|
|
2573
2187
|
usages: none,
|
|
@@ -2577,10 +2191,10 @@ const JWE = table({
|
|
|
2577
2191
|
"RSA-OAEP-256": rsaes(256),
|
|
2578
2192
|
"RSA-OAEP-384": rsaes(384),
|
|
2579
2193
|
"RSA-OAEP-512": rsaes(512),
|
|
2580
|
-
"ECDH-ES": ecdh(),
|
|
2581
|
-
"ECDH-ES+A128KW": ecdh(),
|
|
2582
|
-
"ECDH-ES+A192KW": ecdh(),
|
|
2583
|
-
"ECDH-ES+A256KW": ecdh(),
|
|
2194
|
+
"ECDH-ES": ecdh("direct-key-agreement"),
|
|
2195
|
+
"ECDH-ES+A128KW": ecdh("key-agreement-with-key-wrapping"),
|
|
2196
|
+
"ECDH-ES+A192KW": ecdh("key-agreement-with-key-wrapping"),
|
|
2197
|
+
"ECDH-ES+A256KW": ecdh("key-agreement-with-key-wrapping"),
|
|
2584
2198
|
A128KW: aeskw(128),
|
|
2585
2199
|
A192KW: aeskw(192),
|
|
2586
2200
|
A256KW: aeskw(256),
|
|
@@ -2590,8 +2204,7 @@ const JWE = table({
|
|
|
2590
2204
|
"PBES2-HS256+A128KW": pbes2(),
|
|
2591
2205
|
"PBES2-HS384+A192KW": pbes2(),
|
|
2592
2206
|
"PBES2-HS512+A256KW": pbes2()
|
|
2593
|
-
});
|
|
2594
|
-
const contentOps = ["encrypt", "decrypt"];
|
|
2207
|
+
}), contentOps = ["encrypt", "decrypt"];
|
|
2595
2208
|
function contentEncryption(bits, cbc = false) {
|
|
2596
2209
|
return {
|
|
2597
2210
|
kty: ["oct"],
|
|
@@ -2612,78 +2225,13 @@ table({
|
|
|
2612
2225
|
"A192CBC-HS384": contentEncryption(384, true),
|
|
2613
2226
|
"A256CBC-HS512": contentEncryption(512, true)
|
|
2614
2227
|
});
|
|
2615
|
-
const JWS_RECOGNIZED = { __proto__: null, b64: true };
|
|
2616
|
-
function validateAlgorithms(option, algorithms) {
|
|
2617
|
-
if (algorithms !== void 0 && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== "string"))) {
|
|
2618
|
-
throw new TypeError(`"${option}" option must be an array of strings`);
|
|
2619
|
-
}
|
|
2620
|
-
if (!algorithms) {
|
|
2621
|
-
return void 0;
|
|
2622
|
-
}
|
|
2623
|
-
return new Set(algorithms);
|
|
2624
|
-
}
|
|
2625
|
-
function validateCritDuplicates(Err, protectedHeader) {
|
|
2626
|
-
const { crit } = protectedHeader ?? {};
|
|
2627
|
-
if (Array.isArray(crit) && new Set(crit).size !== crit.length) {
|
|
2628
|
-
throw new Err('"crit" (Critical) Header Parameter MUST NOT contain duplicate values');
|
|
2629
|
-
}
|
|
2630
|
-
}
|
|
2631
|
-
function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
|
|
2632
|
-
if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0) {
|
|
2633
|
-
throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
|
|
2634
|
-
}
|
|
2635
|
-
if (!protectedHeader || protectedHeader.crit === void 0) {
|
|
2636
|
-
return [];
|
|
2637
|
-
}
|
|
2638
|
-
if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input !== "string" || input.length === 0)) {
|
|
2639
|
-
throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');
|
|
2640
|
-
}
|
|
2641
|
-
const recognized = recognizedOption === void 0 ? recognizedDefault : { __proto__: null, ...recognizedOption, ...recognizedDefault };
|
|
2642
|
-
for (const parameter of protectedHeader.crit) {
|
|
2643
|
-
if (!(parameter in recognized)) {
|
|
2644
|
-
throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
|
|
2645
|
-
}
|
|
2646
|
-
if (!Object.hasOwn(joseHeader, parameter) || joseHeader[parameter] === void 0) {
|
|
2647
|
-
throw new Err(`Extension Header Parameter "${parameter}" is missing`);
|
|
2648
|
-
}
|
|
2649
|
-
if (recognized[parameter] && (!Object.hasOwn(protectedHeader, parameter) || protectedHeader[parameter] === void 0)) {
|
|
2650
|
-
throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
|
|
2651
|
-
}
|
|
2652
|
-
}
|
|
2653
|
-
return protectedHeader.crit;
|
|
2654
|
-
}
|
|
2655
|
-
async function getSigKey(entry, key, usage) {
|
|
2656
|
-
if (key instanceof Uint8Array) {
|
|
2657
|
-
return crypto.subtle.importKey("raw", key, entry.subtle, false, [
|
|
2658
|
-
usage
|
|
2659
|
-
]);
|
|
2660
|
-
}
|
|
2661
|
-
checkCryptoKey(key, entry.subtle, usage);
|
|
2662
|
-
if (entry.minRsaBits)
|
|
2663
|
-
checkModulusLength(entry.alg, key);
|
|
2664
|
-
return key;
|
|
2665
|
-
}
|
|
2666
|
-
async function sign(entry, key, data) {
|
|
2667
|
-
const cryptoKey = await getSigKey(entry, key, "sign");
|
|
2668
|
-
const signature = await crypto.subtle.sign(entry.signing, cryptoKey, data);
|
|
2669
|
-
return new Uint8Array(signature);
|
|
2670
|
-
}
|
|
2671
|
-
async function verify(entry, key, signature, data) {
|
|
2672
|
-
const cryptoKey = await getSigKey(entry, key, "verify");
|
|
2673
|
-
try {
|
|
2674
|
-
return await crypto.subtle.verify(entry.signing, cryptoKey, signature, data);
|
|
2675
|
-
} catch {
|
|
2676
|
-
return false;
|
|
2677
|
-
}
|
|
2678
|
-
}
|
|
2679
2228
|
const sig = [["verify"], ["sign"]];
|
|
2680
2229
|
function hmac(bits) {
|
|
2681
2230
|
const subtle = { name: "HMAC", hash: `SHA-${bits}` };
|
|
2682
2231
|
return { kty: ["oct"], secret: true, subtle, signing: subtle, usages: sig };
|
|
2683
2232
|
}
|
|
2684
2233
|
function rsa(bits, saltLength) {
|
|
2685
|
-
const
|
|
2686
|
-
const subtle = { name, hash: `SHA-${bits}` };
|
|
2234
|
+
const subtle = { name: saltLength ? "RSA-PSS" : "RSASSA-PKCS1-v1_5", hash: `SHA-${bits}` };
|
|
2687
2235
|
return {
|
|
2688
2236
|
kty: ["RSA"],
|
|
2689
2237
|
subtle,
|
|
@@ -2711,9 +2259,8 @@ function eddsa() {
|
|
|
2711
2259
|
usages: sig
|
|
2712
2260
|
};
|
|
2713
2261
|
}
|
|
2714
|
-
function mldsa(
|
|
2715
|
-
const
|
|
2716
|
-
const subtle = { name };
|
|
2262
|
+
function mldsa(parameterSet) {
|
|
2263
|
+
const subtle = { name: `ML-DSA-${parameterSet}` };
|
|
2717
2264
|
return {
|
|
2718
2265
|
kty: ["AKP"],
|
|
2719
2266
|
subtle,
|
|
@@ -2741,547 +2288,334 @@ const JWS = table({
|
|
|
2741
2288
|
"ML-DSA-87": mldsa(87)
|
|
2742
2289
|
});
|
|
2743
2290
|
function jwsAlgorithm(alg) {
|
|
2744
|
-
const entry = typeof alg
|
|
2745
|
-
if (!entry)
|
|
2291
|
+
const entry = typeof alg == "string" ? JWS[alg] : void 0;
|
|
2292
|
+
if (!entry)
|
|
2746
2293
|
throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
2747
|
-
}
|
|
2748
2294
|
return entry;
|
|
2749
2295
|
}
|
|
2750
2296
|
function prepareVerify(options) {
|
|
2751
2297
|
return [options && validateAlgorithms("algorithms", options.algorithms), options?.crit];
|
|
2752
2298
|
}
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
}
|
|
2764
|
-
joseHeader = { ...parsedProt, ...header };
|
|
2765
|
-
} else {
|
|
2766
|
-
joseHeader = parsedProt;
|
|
2767
|
-
}
|
|
2768
|
-
const extensions = validateCrit(JWSInvalid, JWS_RECOGNIZED, shared[1], parsedProt, joseHeader);
|
|
2769
|
-
let b64 = true;
|
|
2770
|
-
if (extensions.includes("b64")) {
|
|
2771
|
-
b64 = parsedProt.b64;
|
|
2772
|
-
if (typeof b64 !== "boolean") {
|
|
2773
|
-
throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
|
|
2774
|
-
}
|
|
2299
|
+
function parseProtectedHeader(encodedProtectedHeader) {
|
|
2300
|
+
return encodedProtectedHeader === void 0 ? {} : parseJoseHeader(encodedProtectedHeader, JWSInvalid, "JWS Protected Header is invalid");
|
|
2301
|
+
}
|
|
2302
|
+
function encodeCompactUnencodedPayload(payload) {
|
|
2303
|
+
try {
|
|
2304
|
+
return encode$1(payload);
|
|
2305
|
+
} catch (cause) {
|
|
2306
|
+
throw new JWSInvalid("JWS Compact Serialization payload must use only ASCII characters", {
|
|
2307
|
+
cause
|
|
2308
|
+
});
|
|
2775
2309
|
}
|
|
2776
|
-
|
|
2777
|
-
|
|
2310
|
+
}
|
|
2311
|
+
async function verifySignature$1(jws, shared, key, encodeUnencodedPayload, parsedProtected) {
|
|
2312
|
+
const { protected: encodedProtectedHeader, header, payload: inputPayload } = jws, protectedHeader = parseProtectedHeader(encodedProtectedHeader);
|
|
2313
|
+
if (!isDisjoint(protectedHeader, header))
|
|
2314
|
+
throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
|
|
2315
|
+
const joseHeader = { ...protectedHeader, ...header }, b64 = validateB64(protectedHeader, validateCrit(JWSInvalid, JWS_RECOGNIZED, shared[1], protectedHeader, joseHeader)), { alg } = joseHeader;
|
|
2316
|
+
if (typeof alg != "string" || !alg)
|
|
2778
2317
|
throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
|
|
2779
|
-
|
|
2780
|
-
if (shared[0] && !shared[0].has(alg)) {
|
|
2318
|
+
if (shared[0] && !shared[0].has(alg))
|
|
2781
2319
|
throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed');
|
|
2782
|
-
}
|
|
2783
2320
|
if (b64) {
|
|
2784
|
-
if (typeof inputPayload
|
|
2321
|
+
if (typeof inputPayload != "string")
|
|
2785
2322
|
throw new JWSInvalid("JWS Payload must be a string");
|
|
2786
|
-
|
|
2787
|
-
} else if (typeof inputPayload !== "string" && !(inputPayload instanceof Uint8Array)) {
|
|
2323
|
+
} else if (typeof inputPayload != "string" && !(inputPayload instanceof Uint8Array))
|
|
2788
2324
|
throw new JWSInvalid("JWS Payload must be a string or an Uint8Array instance");
|
|
2789
|
-
|
|
2325
|
+
const signingPayload = b64 || typeof inputPayload != "string" ? inputPayload : encodeUnencodedPayload(inputPayload);
|
|
2790
2326
|
let resolvedKey = false;
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2327
|
+
typeof key == "function" && (key = await key(protectedHeader, jws), resolvedKey = true);
|
|
2328
|
+
const entry = jwsAlgorithm(alg), signingInput = concat(encodedProtectedHeader !== void 0 ? encode$1(encodedProtectedHeader) : new Uint8Array(), encode$1("."), typeof signingPayload == "string" ? shared[2] ??= encodeAsciiMember(signingPayload, "payload", JWSInvalid) : signingPayload), signature = decodeBase64url(jws.signature, "signature", JWSInvalid), verificationKey = await prepareKey(entry, key, "verify"), cryptoKey = await rawKey(verificationKey, entry.subtle, "verify");
|
|
2329
|
+
entry.minRsaBits && checkModulusLength(entry.alg, cryptoKey);
|
|
2330
|
+
let verified = false;
|
|
2331
|
+
try {
|
|
2332
|
+
verified = await crypto.subtle.verify(entry.signing, cryptoKey, signature, signingInput);
|
|
2333
|
+
} catch (cause) {
|
|
2334
|
+
throw new JWSSignatureVerificationFailed(void 0, { cause });
|
|
2794
2335
|
}
|
|
2795
|
-
|
|
2796
|
-
const data = concat(encodedProtected !== void 0 ? encode$1(encodedProtected) : new Uint8Array(), encode$1("."), typeof inputPayload === "string" ? b64 ? shared[2] ??= encodeBase64url(inputPayload, "payload", JWSInvalid) : encoder$2.encode(inputPayload) : inputPayload);
|
|
2797
|
-
const signature = decodeBase64url(jws.signature, "signature", JWSInvalid);
|
|
2798
|
-
const k = await prepareKey(entry, key, "verify");
|
|
2799
|
-
const verified = await verify(entry, k, signature, data);
|
|
2800
|
-
if (!verified) {
|
|
2336
|
+
if (!verified)
|
|
2801
2337
|
throw new JWSSignatureVerificationFailed();
|
|
2802
|
-
}
|
|
2803
|
-
|
|
2804
|
-
if (b64) {
|
|
2805
|
-
payload = decodeBase64url(inputPayload, "payload", JWSInvalid);
|
|
2806
|
-
} else if (typeof inputPayload === "string") {
|
|
2807
|
-
payload = encoder$2.encode(inputPayload);
|
|
2808
|
-
} else {
|
|
2809
|
-
payload = inputPayload;
|
|
2810
|
-
}
|
|
2811
|
-
return [payload, parsedProt, b64, k, resolvedKey];
|
|
2338
|
+
const result = { payload: typeof signingPayload == "string" ? decodeBase64url(signingPayload, "payload", JWSInvalid) : signingPayload };
|
|
2339
|
+
return encodedProtectedHeader !== void 0 && (result.protectedHeader = protectedHeader), header !== void 0 && (result.unprotectedHeader = header), resolvedKey ? [{ ...result, key: verificationKey }, b64] : [result, b64];
|
|
2812
2340
|
}
|
|
2813
2341
|
async function verifyCompact(jws, shared, key) {
|
|
2814
|
-
if (jws instanceof Uint8Array)
|
|
2815
|
-
jws = decoder$1.decode(jws);
|
|
2816
|
-
}
|
|
2817
|
-
if (typeof jws !== "string") {
|
|
2342
|
+
if (jws instanceof Uint8Array && (jws = decoder$1.decode(jws)), typeof jws != "string")
|
|
2818
2343
|
throw new JWSInvalid("Compact JWS must be a string or Uint8Array");
|
|
2819
|
-
}
|
|
2820
2344
|
const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split(".");
|
|
2821
|
-
if (length !== 3)
|
|
2345
|
+
if (length !== 3)
|
|
2822
2346
|
throw new JWSInvalid("Invalid Compact JWS");
|
|
2823
|
-
}
|
|
2824
|
-
return verifySignature$1({ payload, protected: protectedHeader, signature }, shared, key);
|
|
2347
|
+
return verifySignature$1({ payload, protected: protectedHeader, signature }, shared, key, encodeCompactUnencodedPayload);
|
|
2825
2348
|
}
|
|
2826
|
-
const epoch = (date) => Math.floor(date.getTime() / 1e3)
|
|
2827
|
-
const multipliers = {
|
|
2349
|
+
const epoch = (date) => Math.floor(date.getTime() / 1e3), multipliers = {
|
|
2828
2350
|
s: 1,
|
|
2829
2351
|
m: 60,
|
|
2830
2352
|
h: 3600,
|
|
2831
2353
|
d: 86400,
|
|
2832
2354
|
w: 604800,
|
|
2833
2355
|
y: 31557600
|
|
2834
|
-
};
|
|
2835
|
-
|
|
2836
|
-
|
|
2356
|
+
}, REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i, checkFailed = "check_failed";
|
|
2357
|
+
function invalidDuration() {
|
|
2358
|
+
throw new TypeError("Invalid time period format");
|
|
2359
|
+
}
|
|
2837
2360
|
function secs(str) {
|
|
2361
|
+
typeof str != "string" && invalidDuration();
|
|
2838
2362
|
const matched = REGEX.exec(str);
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
const value = parseFloat(matched[2]);
|
|
2843
|
-
const numericDate2 = Math.round(value * multipliers[matched[3][0].toLowerCase()]);
|
|
2844
|
-
if (matched[1] === "-" || matched[4] === "ago") {
|
|
2845
|
-
return -numericDate2;
|
|
2846
|
-
}
|
|
2847
|
-
return numericDate2;
|
|
2363
|
+
(!matched || matched[4] && matched[1]) && invalidDuration();
|
|
2364
|
+
const value = parseFloat(matched[2]), durationSeconds = Math.round(value * multipliers[matched[3][0].toLowerCase()]);
|
|
2365
|
+
return Number.isFinite(durationSeconds) || invalidDuration(), matched[1] === "-" || matched[4] === "ago" ? -durationSeconds : durationSeconds;
|
|
2848
2366
|
}
|
|
2849
2367
|
function validateInput(label, input) {
|
|
2850
|
-
if (!Number.isFinite(input))
|
|
2368
|
+
if (!Number.isFinite(input))
|
|
2851
2369
|
throw new TypeError(`Invalid ${label} input`);
|
|
2852
|
-
}
|
|
2853
2370
|
return input;
|
|
2854
2371
|
}
|
|
2855
|
-
function
|
|
2856
|
-
if (typeof value
|
|
2857
|
-
|
|
2858
|
-
if (value instanceof Date)
|
|
2859
|
-
return validateInput(label, epoch(value));
|
|
2860
|
-
return epoch(/* @__PURE__ */ new Date()) + secs(value);
|
|
2372
|
+
function validateStringClaim(claim, value) {
|
|
2373
|
+
if (typeof value != "string")
|
|
2374
|
+
throw new TypeError(`"${claim}" claim must be a string`);
|
|
2861
2375
|
}
|
|
2862
|
-
|
|
2863
|
-
if (value.
|
|
2864
|
-
|
|
2865
|
-
}
|
|
2866
|
-
return `application/${value.toLowerCase()}`;
|
|
2867
|
-
};
|
|
2868
|
-
const checkAudiencePresence = (audPayload, audOption) => {
|
|
2869
|
-
if (typeof audPayload === "string") {
|
|
2870
|
-
return audOption.includes(audPayload);
|
|
2871
|
-
}
|
|
2872
|
-
if (Array.isArray(audPayload)) {
|
|
2873
|
-
return audOption.some((aud) => audPayload.includes(aud));
|
|
2874
|
-
}
|
|
2875
|
-
return false;
|
|
2876
|
-
};
|
|
2877
|
-
function validateNumericDate(payload, claim, required = false) {
|
|
2878
|
-
const value = payload[claim];
|
|
2879
|
-
if (value === void 0 && !required)
|
|
2880
|
-
return void 0;
|
|
2881
|
-
if (typeof value !== "number") {
|
|
2882
|
-
throw new JWTClaimValidationFailed(`"${claim}" claim must be a number`, payload, claim, "invalid");
|
|
2883
|
-
}
|
|
2884
|
-
return value;
|
|
2376
|
+
function validateAudienceClaim(value) {
|
|
2377
|
+
if (typeof value != "string" && (!Array.isArray(value) || Array.from(value).some((member) => typeof member != "string")))
|
|
2378
|
+
throw new TypeError('"aud" claim must be a string or an array of strings');
|
|
2885
2379
|
}
|
|
2886
|
-
function
|
|
2887
|
-
|
|
2380
|
+
function numericDate(value, label) {
|
|
2381
|
+
return typeof value == "number" ? validateInput(label, value) : value instanceof Date ? validateInput(label, epoch(value)) : epoch(/* @__PURE__ */ new Date()) + secs(value);
|
|
2888
2382
|
}
|
|
2889
|
-
|
|
2890
|
-
|
|
2383
|
+
const normalizeTyp = (value) => {
|
|
2384
|
+
const normalized = value.toLowerCase();
|
|
2385
|
+
return value.includes("/") ? normalized : `application/${normalized}`;
|
|
2386
|
+
}, checkAudiencePresence = (audPayload, audOption) => typeof audPayload == "string" ? audOption.includes(audPayload) : Array.isArray(audPayload) ? audOption.some((aud) => audPayload.includes(aud)) : false;
|
|
2387
|
+
function validateNumericDate(claimsSet, claim, required = false) {
|
|
2388
|
+
const value = claimsSet[claim];
|
|
2389
|
+
if (!(value === void 0 && !required)) {
|
|
2390
|
+
if (typeof value != "number")
|
|
2391
|
+
throw new JWTClaimValidationFailed(`"${claim}" claim must be a number`, claimsSet, claim, "invalid");
|
|
2392
|
+
return value;
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
function unexpectedClaim(claimsSet, claim) {
|
|
2396
|
+
throw new JWTClaimValidationFailed(`unexpected "${claim}" claim value`, claimsSet, claim, checkFailed);
|
|
2397
|
+
}
|
|
2398
|
+
function validateClaimsSet(protectedHeader, claimsSetBytes, options = {}) {
|
|
2399
|
+
let claimsSet;
|
|
2891
2400
|
try {
|
|
2892
|
-
|
|
2893
|
-
} catch {
|
|
2401
|
+
claimsSet = JSON.parse(strictDecoder.decode(claimsSetBytes));
|
|
2402
|
+
} catch (cause) {
|
|
2403
|
+
throw new JWTInvalid("JWT Claims Set must be a top-level JSON object", { cause });
|
|
2894
2404
|
}
|
|
2895
|
-
if (!isObject(
|
|
2405
|
+
if (!isObject(claimsSet))
|
|
2896
2406
|
throw new JWTInvalid("JWT Claims Set must be a top-level JSON object");
|
|
2897
|
-
}
|
|
2898
2407
|
const { typ } = options;
|
|
2899
|
-
if (typ && (typeof protectedHeader.typ
|
|
2900
|
-
throw new JWTClaimValidationFailed('unexpected "typ" JWT header value',
|
|
2901
|
-
}
|
|
2902
|
-
|
|
2903
|
-
const
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
presenceCheck.push("aud");
|
|
2908
|
-
if (subject !== void 0)
|
|
2909
|
-
presenceCheck.push("sub");
|
|
2910
|
-
if (issuer !== void 0)
|
|
2911
|
-
presenceCheck.push("iss");
|
|
2912
|
-
for (const claim of new Set(presenceCheck.reverse())) {
|
|
2913
|
-
if (!Object.hasOwn(payload, claim)) {
|
|
2914
|
-
throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, payload, claim, "missing");
|
|
2915
|
-
}
|
|
2916
|
-
}
|
|
2917
|
-
if (issuer !== void 0 && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) {
|
|
2918
|
-
unexpectedClaim(payload, "iss");
|
|
2919
|
-
}
|
|
2920
|
-
if (subject !== void 0 && payload.sub !== subject) {
|
|
2921
|
-
unexpectedClaim(payload, "sub");
|
|
2922
|
-
}
|
|
2923
|
-
if (audience !== void 0 && !checkAudiencePresence(payload.aud, typeof audience === "string" ? [audience] : audience)) {
|
|
2924
|
-
unexpectedClaim(payload, "aud");
|
|
2925
|
-
}
|
|
2408
|
+
if (typ !== void 0 && (typeof protectedHeader.typ != "string" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ)))
|
|
2409
|
+
throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', claimsSet, "typ", checkFailed);
|
|
2410
|
+
const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options, presenceCheck = [...requiredClaims];
|
|
2411
|
+
maxTokenAge !== void 0 && presenceCheck.push("iat"), audience !== void 0 && presenceCheck.push("aud"), subject !== void 0 && presenceCheck.push("sub"), issuer !== void 0 && presenceCheck.push("iss");
|
|
2412
|
+
for (const claim of new Set(presenceCheck.reverse()))
|
|
2413
|
+
if (!Object.hasOwn(claimsSet, claim))
|
|
2414
|
+
throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, claimsSet, claim, "missing");
|
|
2415
|
+
issuer !== void 0 && !(Array.isArray(issuer) ? issuer : [issuer]).includes(claimsSet.iss) && unexpectedClaim(claimsSet, "iss"), subject !== void 0 && claimsSet.sub !== subject && unexpectedClaim(claimsSet, "sub"), audience !== void 0 && !checkAudiencePresence(claimsSet.aud, typeof audience == "string" ? [audience] : audience) && unexpectedClaim(claimsSet, "aud");
|
|
2926
2416
|
const { clockTolerance } = options;
|
|
2927
2417
|
let tolerance = 0;
|
|
2928
|
-
if (typeof clockTolerance
|
|
2418
|
+
if (typeof clockTolerance == "string")
|
|
2929
2419
|
tolerance = secs(clockTolerance);
|
|
2930
|
-
|
|
2931
|
-
if (typeof clockTolerance
|
|
2420
|
+
else if (clockTolerance !== void 0) {
|
|
2421
|
+
if (typeof clockTolerance != "number")
|
|
2932
2422
|
throw new TypeError("Invalid clockTolerance option type");
|
|
2933
|
-
}
|
|
2934
2423
|
tolerance = clockTolerance;
|
|
2935
2424
|
}
|
|
2936
2425
|
validateInput("clockTolerance option", tolerance);
|
|
2937
|
-
const { currentDate } = options;
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
const
|
|
2941
|
-
if (
|
|
2942
|
-
|
|
2943
|
-
throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', payload, "nbf", checkFailed);
|
|
2944
|
-
}
|
|
2945
|
-
}
|
|
2946
|
-
const exp = validateNumericDate(payload, "exp");
|
|
2947
|
-
if (exp !== void 0) {
|
|
2948
|
-
if (exp <= now2 - tolerance) {
|
|
2949
|
-
throw new JWTExpired('"exp" claim timestamp check failed', payload, "exp", checkFailed);
|
|
2950
|
-
}
|
|
2951
|
-
}
|
|
2426
|
+
const { currentDate } = options, now2 = validateInput("currentDate option", epoch(currentDate === void 0 ? /* @__PURE__ */ new Date() : currentDate)), iat = validateNumericDate(claimsSet, "iat", maxTokenAge !== void 0), nbf = validateNumericDate(claimsSet, "nbf");
|
|
2427
|
+
if (nbf !== void 0 && nbf > now2 + tolerance)
|
|
2428
|
+
throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', claimsSet, "nbf", checkFailed);
|
|
2429
|
+
const exp = validateNumericDate(claimsSet, "exp");
|
|
2430
|
+
if (exp !== void 0 && exp <= now2 - tolerance)
|
|
2431
|
+
throw new JWTExpired('"exp" claim timestamp check failed', claimsSet, "exp", checkFailed);
|
|
2952
2432
|
if (maxTokenAge !== void 0) {
|
|
2953
|
-
const age = now2 - iat;
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
if (age < 0 - tolerance) {
|
|
2959
|
-
throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', payload, "iat", checkFailed);
|
|
2960
|
-
}
|
|
2433
|
+
const age = now2 - iat, max = validateInput("maxTokenAge option", typeof maxTokenAge == "number" ? maxTokenAge : secs(maxTokenAge));
|
|
2434
|
+
if (age - tolerance > max)
|
|
2435
|
+
throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', claimsSet, "iat", checkFailed);
|
|
2436
|
+
if (age < -tolerance)
|
|
2437
|
+
throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', claimsSet, "iat", checkFailed);
|
|
2961
2438
|
}
|
|
2962
|
-
return
|
|
2439
|
+
return claimsSet;
|
|
2440
|
+
}
|
|
2441
|
+
let producerClaimsSets;
|
|
2442
|
+
function producerClaimsSet(producer) {
|
|
2443
|
+
return producerClaimsSets.get(producer);
|
|
2444
|
+
}
|
|
2445
|
+
function jwtClaimsSetBytes(producer) {
|
|
2446
|
+
const claimsSet = producerClaimsSet(producer);
|
|
2447
|
+
for (const claim of ["iat", "nbf", "exp"]) {
|
|
2448
|
+
const value = claimsSet[claim];
|
|
2449
|
+
if (typeof value == "number" && !Number.isFinite(value))
|
|
2450
|
+
throw new TypeError(`"${claim}" claim must be a finite number`);
|
|
2451
|
+
}
|
|
2452
|
+
return encoder$2.encode(JSON.stringify(claimsSet));
|
|
2963
2453
|
}
|
|
2964
2454
|
class JWTClaimsBuilder {
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
if (!isObject(payload)) {
|
|
2455
|
+
constructor(claimsSet = {}) {
|
|
2456
|
+
if (!isObject(claimsSet))
|
|
2968
2457
|
throw new TypeError("JWT Claims Set MUST be an object");
|
|
2969
|
-
|
|
2970
|
-
this.#payload = structuredClone(payload);
|
|
2971
|
-
}
|
|
2972
|
-
data() {
|
|
2973
|
-
return encoder$2.encode(JSON.stringify(this.#payload));
|
|
2458
|
+
(producerClaimsSets ||= /* @__PURE__ */ new WeakMap()).set(this, structuredClone(claimsSet));
|
|
2974
2459
|
}
|
|
2975
|
-
|
|
2976
|
-
return this
|
|
2460
|
+
setIssuer(value) {
|
|
2461
|
+
return validateStringClaim("iss", value), producerClaimsSet(this).iss = value, this;
|
|
2977
2462
|
}
|
|
2978
|
-
|
|
2979
|
-
this
|
|
2463
|
+
setSubject(value) {
|
|
2464
|
+
return validateStringClaim("sub", value), producerClaimsSet(this).sub = value, this;
|
|
2980
2465
|
}
|
|
2981
|
-
|
|
2982
|
-
return this
|
|
2466
|
+
setAudience(value) {
|
|
2467
|
+
return validateAudienceClaim(value), producerClaimsSet(this).aud = value, this;
|
|
2983
2468
|
}
|
|
2984
|
-
|
|
2985
|
-
this
|
|
2469
|
+
setJti(value) {
|
|
2470
|
+
return validateStringClaim("jti", value), producerClaimsSet(this).jti = value, this;
|
|
2986
2471
|
}
|
|
2987
|
-
|
|
2988
|
-
return this
|
|
2472
|
+
setNotBefore(value) {
|
|
2473
|
+
return producerClaimsSet(this).nbf = numericDate(value, "setNotBefore"), this;
|
|
2989
2474
|
}
|
|
2990
|
-
|
|
2991
|
-
this
|
|
2475
|
+
setExpirationTime(value) {
|
|
2476
|
+
return producerClaimsSet(this).exp = numericDate(value, "setExpirationTime"), this;
|
|
2992
2477
|
}
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
set nbf(value) {
|
|
2997
|
-
this.#payload.nbf = numericDate(value, "setNotBefore");
|
|
2998
|
-
}
|
|
2999
|
-
set exp(value) {
|
|
3000
|
-
this.#payload.exp = numericDate(value, "setExpirationTime");
|
|
3001
|
-
}
|
|
3002
|
-
set iat(value) {
|
|
3003
|
-
if (value === void 0) {
|
|
3004
|
-
this.#payload.iat = epoch(/* @__PURE__ */ new Date());
|
|
3005
|
-
} else if (typeof value === "string") {
|
|
3006
|
-
this.#payload.iat = validateInput("setIssuedAt", epoch(/* @__PURE__ */ new Date()) + secs(value));
|
|
3007
|
-
} else {
|
|
3008
|
-
this.#payload.iat = numericDate(value, "setIssuedAt");
|
|
3009
|
-
}
|
|
2478
|
+
setIssuedAt(value) {
|
|
2479
|
+
const claimsSet = producerClaimsSet(this);
|
|
2480
|
+
return value === void 0 ? claimsSet.iat = epoch(/* @__PURE__ */ new Date()) : typeof value == "string" ? claimsSet.iat = validateInput("setIssuedAt", epoch(/* @__PURE__ */ new Date()) + secs(value)) : claimsSet.iat = numericDate(value, "setIssuedAt"), this;
|
|
3010
2481
|
}
|
|
3011
2482
|
}
|
|
3012
2483
|
async function jwtVerify(jwt, key, options) {
|
|
3013
|
-
const verified = await verifyCompact(jwt, prepareVerify(options), key);
|
|
3014
|
-
if (!
|
|
2484
|
+
const [verified, b64] = await verifyCompact(jwt, prepareVerify(options), key);
|
|
2485
|
+
if (!b64)
|
|
3015
2486
|
throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
const result = { payload, protectedHeader: verified[1] };
|
|
3019
|
-
if (typeof key === "function") {
|
|
3020
|
-
return { ...result, key: verified[3] };
|
|
3021
|
-
}
|
|
3022
|
-
return result;
|
|
3023
|
-
}
|
|
3024
|
-
function unencodedPayload(protectedHeader) {
|
|
3025
|
-
return protectedHeader?.b64 === false && Array.isArray(protectedHeader.crit) && protectedHeader.crit.includes("b64");
|
|
2487
|
+
const payload = validateClaimsSet(verified.protectedHeader, verified.payload, options);
|
|
2488
|
+
return { ...verified, payload };
|
|
3026
2489
|
}
|
|
3027
|
-
async function createSignature(input, key) {
|
|
3028
|
-
|
|
3029
|
-
if (
|
|
3030
|
-
|
|
2490
|
+
async function createSignature(input, key, rejectUnencoded) {
|
|
2491
|
+
let [payload, protectedHeader, unprotectedHeader, crit] = input, encodedProtectedHeader = "";
|
|
2492
|
+
if (protectedHeader !== void 0) {
|
|
2493
|
+
const normalized = serializeJoseHeader(JWSInvalid, protectedHeader);
|
|
2494
|
+
protectedHeader = normalized[0], encodedProtectedHeader = encode(normalized[1]);
|
|
3031
2495
|
}
|
|
3032
|
-
if (
|
|
2496
|
+
if (unprotectedHeader !== void 0 && (unprotectedHeader = serializeJoseHeader(JWSInvalid, unprotectedHeader)[0]), !protectedHeader && !unprotectedHeader)
|
|
2497
|
+
throw new JWSInvalid("either setProtectedHeader or setUnprotectedHeader must be called before #sign()");
|
|
2498
|
+
if (!isDisjoint(protectedHeader, unprotectedHeader))
|
|
3033
2499
|
throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
|
|
3034
|
-
}
|
|
3035
2500
|
const joseHeader = { ...protectedHeader, ...unprotectedHeader };
|
|
3036
2501
|
validateCritDuplicates(JWSInvalid, protectedHeader);
|
|
3037
|
-
const
|
|
3038
|
-
|
|
3039
|
-
if (extensions.includes("b64")) {
|
|
3040
|
-
b64 = protectedHeader.b64;
|
|
3041
|
-
if (typeof b64 !== "boolean") {
|
|
3042
|
-
throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
|
|
3043
|
-
}
|
|
3044
|
-
}
|
|
2502
|
+
const b64 = validateB64(protectedHeader, validateCrit(JWSInvalid, JWS_RECOGNIZED, crit, protectedHeader, joseHeader));
|
|
2503
|
+
b64 || rejectUnencoded?.();
|
|
3045
2504
|
const { alg } = joseHeader;
|
|
3046
|
-
if (typeof alg
|
|
2505
|
+
if (typeof alg != "string" || !alg)
|
|
3047
2506
|
throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
|
|
3048
|
-
}
|
|
3049
2507
|
const entry = jwsAlgorithm(alg);
|
|
3050
|
-
let
|
|
3051
|
-
let payloadB;
|
|
2508
|
+
let encodedPayload = "", signingPayload = payload, signingInput;
|
|
3052
2509
|
if (b64) {
|
|
3053
|
-
const
|
|
3054
|
-
|
|
3055
|
-
encoded[1] ??= encode$1(encoded[0]);
|
|
3056
|
-
payloadS = encoded[0];
|
|
3057
|
-
payloadB = encoded[1];
|
|
3058
|
-
} else {
|
|
3059
|
-
payloadB = input.payload;
|
|
3060
|
-
payloadS = "";
|
|
3061
|
-
}
|
|
3062
|
-
let protectedHeaderString;
|
|
3063
|
-
let protectedHeaderBytes;
|
|
3064
|
-
if (protectedHeader) {
|
|
3065
|
-
protectedHeaderString = encode(JSON.stringify(protectedHeader));
|
|
3066
|
-
protectedHeaderBytes = encode$1(protectedHeaderString);
|
|
3067
|
-
} else {
|
|
3068
|
-
protectedHeaderString = "";
|
|
3069
|
-
protectedHeaderBytes = new Uint8Array();
|
|
2510
|
+
const encodedPayloadCache = input[4];
|
|
2511
|
+
encodedPayloadCache ? (encodedPayload = encodedPayloadCache[0] ??= encode(payload), signingPayload = encodedPayloadCache[1] ??= encode$1(encodedPayload)) : (encodedPayload = encode(payload), signingInput = encoder$2.encode(`${encodedProtectedHeader}.${encodedPayload}`));
|
|
3070
2512
|
}
|
|
3071
|
-
|
|
3072
|
-
const
|
|
3073
|
-
|
|
2513
|
+
signingInput ??= concat(encode$1(encodedProtectedHeader), encode$1("."), signingPayload);
|
|
2514
|
+
const signingKey = await rawKey(await prepareKey(entry, key, "sign"), entry.subtle, "sign");
|
|
2515
|
+
entry.minRsaBits && checkModulusLength(entry.alg, signingKey);
|
|
3074
2516
|
const jws = {
|
|
3075
|
-
signature: encode(
|
|
3076
|
-
payload:
|
|
2517
|
+
signature: encode(new Uint8Array(await crypto.subtle.sign(entry.signing, signingKey, signingInput))),
|
|
2518
|
+
payload: encodedPayload
|
|
3077
2519
|
};
|
|
3078
|
-
|
|
3079
|
-
jws.protected = protectedHeaderString;
|
|
3080
|
-
}
|
|
3081
|
-
if (unprotectedHeader) {
|
|
3082
|
-
jws.header = unprotectedHeader;
|
|
3083
|
-
}
|
|
3084
|
-
return jws;
|
|
2520
|
+
return protectedHeader && (jws.protected = encodedProtectedHeader), unprotectedHeader && (jws.header = unprotectedHeader), [jws, b64];
|
|
3085
2521
|
}
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
#unprotectedHeader;
|
|
3090
|
-
constructor(payload) {
|
|
3091
|
-
if (!(payload instanceof Uint8Array)) {
|
|
3092
|
-
throw new TypeError("payload must be an instance of Uint8Array");
|
|
3093
|
-
}
|
|
3094
|
-
this.#payload = payload;
|
|
3095
|
-
}
|
|
3096
|
-
setProtectedHeader(protectedHeader) {
|
|
3097
|
-
assertNotSet(this.#protectedHeader, "setProtectedHeader");
|
|
3098
|
-
this.#protectedHeader = protectedHeader;
|
|
3099
|
-
return this;
|
|
3100
|
-
}
|
|
3101
|
-
setUnprotectedHeader(unprotectedHeader) {
|
|
3102
|
-
assertNotSet(this.#unprotectedHeader, "setUnprotectedHeader");
|
|
3103
|
-
this.#unprotectedHeader = unprotectedHeader;
|
|
3104
|
-
return this;
|
|
3105
|
-
}
|
|
3106
|
-
async sign(key, options) {
|
|
3107
|
-
return createSignature({
|
|
3108
|
-
payload: this.#payload,
|
|
3109
|
-
protectedHeader: this.#protectedHeader,
|
|
3110
|
-
unprotectedHeader: this.#unprotectedHeader,
|
|
3111
|
-
crit: options?.crit
|
|
3112
|
-
}, key);
|
|
3113
|
-
}
|
|
2522
|
+
async function createCompactSignature(payload, protectedHeader, crit, key, rejectUnencoded) {
|
|
2523
|
+
const [jws] = await createSignature([payload, protectedHeader, void 0, crit], key, rejectUnencoded);
|
|
2524
|
+
return `${jws.protected}.${jws.payload}.${jws.signature}`;
|
|
3114
2525
|
}
|
|
3115
|
-
|
|
3116
|
-
|
|
2526
|
+
const SignJWT_base = JWTClaimsBuilder;
|
|
2527
|
+
class SignJWT extends SignJWT_base {
|
|
3117
2528
|
#protectedHeader;
|
|
3118
|
-
constructor(payload) {
|
|
3119
|
-
this.#flattened = new FlattenedSign(payload);
|
|
3120
|
-
}
|
|
3121
2529
|
setProtectedHeader(protectedHeader) {
|
|
3122
|
-
this.#
|
|
3123
|
-
this.#protectedHeader = protectedHeader;
|
|
3124
|
-
return this;
|
|
2530
|
+
return assertNotSet(this.#protectedHeader, "setProtectedHeader"), this.#protectedHeader = protectedHeader, this;
|
|
3125
2531
|
}
|
|
3126
2532
|
async sign(key, options) {
|
|
3127
|
-
|
|
3128
|
-
throw new TypeError("use the flattened module for creating JWS with b64: false");
|
|
3129
|
-
}
|
|
3130
|
-
const jws = await this.#flattened.sign(key, options);
|
|
3131
|
-
return `${jws.protected}.${jws.payload}.${jws.signature}`;
|
|
3132
|
-
}
|
|
3133
|
-
}
|
|
3134
|
-
class SignJWT {
|
|
3135
|
-
#protectedHeader;
|
|
3136
|
-
#jwt;
|
|
3137
|
-
constructor(payload = {}) {
|
|
3138
|
-
this.#jwt = new JWTClaimsBuilder(payload);
|
|
3139
|
-
}
|
|
3140
|
-
setIssuer(issuer) {
|
|
3141
|
-
this.#jwt.iss = issuer;
|
|
3142
|
-
return this;
|
|
3143
|
-
}
|
|
3144
|
-
setSubject(subject) {
|
|
3145
|
-
this.#jwt.sub = subject;
|
|
3146
|
-
return this;
|
|
3147
|
-
}
|
|
3148
|
-
setAudience(audience) {
|
|
3149
|
-
this.#jwt.aud = audience;
|
|
3150
|
-
return this;
|
|
3151
|
-
}
|
|
3152
|
-
setJti(jwtId) {
|
|
3153
|
-
this.#jwt.jti = jwtId;
|
|
3154
|
-
return this;
|
|
3155
|
-
}
|
|
3156
|
-
setNotBefore(input) {
|
|
3157
|
-
this.#jwt.nbf = input;
|
|
3158
|
-
return this;
|
|
3159
|
-
}
|
|
3160
|
-
setExpirationTime(input) {
|
|
3161
|
-
this.#jwt.exp = input;
|
|
3162
|
-
return this;
|
|
3163
|
-
}
|
|
3164
|
-
setIssuedAt(input) {
|
|
3165
|
-
this.#jwt.iat = input;
|
|
3166
|
-
return this;
|
|
3167
|
-
}
|
|
3168
|
-
setProtectedHeader(protectedHeader) {
|
|
3169
|
-
this.#protectedHeader = protectedHeader;
|
|
3170
|
-
return this;
|
|
3171
|
-
}
|
|
3172
|
-
async sign(key, options) {
|
|
3173
|
-
const sig2 = new CompactSign(this.#jwt.data());
|
|
3174
|
-
sig2.setProtectedHeader(this.#protectedHeader);
|
|
3175
|
-
if (unencodedPayload(this.#protectedHeader)) {
|
|
2533
|
+
return createCompactSignature(jwtClaimsSetBytes(this), this.#protectedHeader, options?.crit, key, () => {
|
|
3176
2534
|
throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
|
|
3177
|
-
}
|
|
3178
|
-
return sig2.sign(key, options);
|
|
2535
|
+
});
|
|
3179
2536
|
}
|
|
3180
2537
|
}
|
|
3181
2538
|
function unsupportedAlg(source = 'JWK "alg" (Algorithm) Parameter') {
|
|
3182
2539
|
throw new JOSENotSupported(`Invalid or unsupported ${source} value`);
|
|
3183
2540
|
}
|
|
3184
2541
|
function keyAlgorithm(alg, source) {
|
|
3185
|
-
return (typeof alg
|
|
2542
|
+
return (typeof alg == "string" ? JWS[alg] ?? JWE[alg] : void 0) ?? unsupportedAlg(source);
|
|
3186
2543
|
}
|
|
3187
|
-
function
|
|
3188
|
-
const
|
|
3189
|
-
|
|
3190
|
-
throw new JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set');
|
|
3191
|
-
}
|
|
3192
|
-
return entry;
|
|
2544
|
+
function isUsableJWK(jwk, entry, alg, kid) {
|
|
2545
|
+
const { kty, key_ops: keyOps, ext, kid: jwkKid, alg: jwkAlg, use, crv } = jwk;
|
|
2546
|
+
return (ext === void 0 || typeof ext == "boolean") && (keyOps === void 0 || Array.isArray(keyOps) && keyOps.every((operation, index) => typeof operation == "string" && keyOps.indexOf(operation) === index) && keyOps.includes("verify")) && entry.kty.includes(kty) && (kid === void 0 || typeof kid == "string" && kid === jwkKid) && (jwkAlg === void 0 ? kty !== "AKP" : alg === jwkAlg) && (use === void 0 || use === "sig") && (!entry.crv || crv === entry.crv);
|
|
3193
2547
|
}
|
|
3194
|
-
function
|
|
3195
|
-
|
|
3196
|
-
|
|
2548
|
+
async function importWithAlgCache(cache2, jwk, entry) {
|
|
2549
|
+
const cached = cache2.get(jwk) || cache2.set(jwk, {}).get(jwk), { alg } = entry;
|
|
2550
|
+
if (cached[alg] === void 0) {
|
|
2551
|
+
const pending = jwkToKey(entry, jwk, true).then((key) => {
|
|
2552
|
+
if (key.type !== "public")
|
|
2553
|
+
throw new JWKSInvalid("JSON Web Key Set members must be public keys");
|
|
2554
|
+
return cached[alg] = key, key;
|
|
2555
|
+
}).catch((error) => {
|
|
2556
|
+
throw cached[alg] === pending && delete cached[alg], error;
|
|
2557
|
+
});
|
|
2558
|
+
cached[alg] = pending;
|
|
3197
2559
|
}
|
|
3198
|
-
|
|
3199
|
-
return Array.isArray(keys) && keys.every(isObject);
|
|
2560
|
+
return cached[alg];
|
|
3200
2561
|
}
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
const entry =
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
2562
|
+
function createLocalJWKSet(jwks) {
|
|
2563
|
+
let snapshot;
|
|
2564
|
+
try {
|
|
2565
|
+
snapshot = structuredClone(jwks);
|
|
2566
|
+
} catch (cause) {
|
|
2567
|
+
throw new JWKSInvalid("JSON Web Key Set malformed", { cause });
|
|
2568
|
+
}
|
|
2569
|
+
if (!isJwkSet(snapshot))
|
|
2570
|
+
throw new JWKSInvalid("JSON Web Key Set malformed");
|
|
2571
|
+
const metadata = snapshot.keys.map((jwk) => {
|
|
2572
|
+
const normalized = snapshotJwk(jwk);
|
|
2573
|
+
return Array.isArray(normalized.key_ops) && (normalized.key_ops = [...normalized.key_ops]), normalized;
|
|
2574
|
+
}), cached = /* @__PURE__ */ new WeakMap();
|
|
2575
|
+
return Object.defineProperty(async (protectedHeader, token) => {
|
|
2576
|
+
const { alg, kid } = { ...protectedHeader, ...token?.header }, entry = typeof alg == "string" ? JWS[alg] : void 0;
|
|
2577
|
+
if (!entry || entry.secret)
|
|
2578
|
+
throw new JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set');
|
|
2579
|
+
const candidates = snapshot.keys.filter((_, index) => isUsableJWK(metadata[index], entry, alg, kid)), { 0: jwk, length } = candidates;
|
|
2580
|
+
if (!length)
|
|
3219
2581
|
throw new JWKSNoMatchingKey();
|
|
3220
|
-
}
|
|
3221
2582
|
if (length !== 1) {
|
|
3222
2583
|
const error = new JWKSMultipleMatchingKeys();
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
for (const jwk2 of candidates) {
|
|
2584
|
+
throw error[Symbol.asyncIterator] = async function* () {
|
|
2585
|
+
for (const jwk2 of candidates)
|
|
3226
2586
|
try {
|
|
3227
|
-
yield await importWithAlgCache(
|
|
2587
|
+
yield await importWithAlgCache(cached, jwk2, entry);
|
|
3228
2588
|
} catch {
|
|
3229
2589
|
}
|
|
3230
|
-
|
|
3231
|
-
};
|
|
3232
|
-
throw error;
|
|
2590
|
+
}, error;
|
|
3233
2591
|
}
|
|
3234
|
-
return importWithAlgCache(
|
|
3235
|
-
}
|
|
3236
|
-
|
|
3237
|
-
async function importWithAlgCache(cache2, jwk, entry) {
|
|
3238
|
-
const cached2 = cache2.get(jwk) || cache2.set(jwk, { __proto__: null }).get(jwk);
|
|
3239
|
-
if (cached2[entry.alg] === void 0) {
|
|
3240
|
-
const key = await jwkToKey(entry, { ...jwk, alg: entry.alg, ext: true });
|
|
3241
|
-
if (key.type !== "public") {
|
|
3242
|
-
throw new JWKSInvalid("JSON Web Key Set members must be public keys");
|
|
3243
|
-
}
|
|
3244
|
-
cached2[entry.alg] = key;
|
|
3245
|
-
}
|
|
3246
|
-
return cached2[entry.alg];
|
|
3247
|
-
}
|
|
3248
|
-
function createLocalJWKSet(jwks) {
|
|
3249
|
-
const set = new LocalJWKSetImpl(jwks);
|
|
3250
|
-
const localJWKSet = async (protectedHeader, token) => set.getKey(protectedHeader, token);
|
|
3251
|
-
Object.defineProperty(localJWKSet, "jwks", {
|
|
3252
|
-
value: () => structuredClone(set.jwks())
|
|
2592
|
+
return importWithAlgCache(cached, jwk, entry);
|
|
2593
|
+
}, "jwks", {
|
|
2594
|
+
value: () => structuredClone(snapshot)
|
|
3253
2595
|
});
|
|
3254
|
-
return localJWKSet;
|
|
3255
2596
|
}
|
|
3256
2597
|
async function importJWK(jwk, alg, options) {
|
|
3257
|
-
if (!isObject(jwk))
|
|
2598
|
+
if (!isObject(jwk))
|
|
3258
2599
|
throw new TypeError("JWK must be an object");
|
|
3259
|
-
}
|
|
3260
|
-
alg ??=
|
|
3261
|
-
const ext = jwk.ext;
|
|
3262
|
-
if (jwk.kty !== "oct" && !alg) {
|
|
2600
|
+
const normalized = normalizeJwk(jwk), extractable = validateExtractableOption(options?.extractable), { alg: jwkAlg } = normalized;
|
|
2601
|
+
if (alg ??= jwkAlg, normalized.kty !== "oct" && !alg)
|
|
3263
2602
|
throw new TypeError('"alg" argument is required when "jwk.alg" is not present');
|
|
3264
|
-
|
|
3265
|
-
switch (jwk.kty) {
|
|
2603
|
+
switch (normalized.kty) {
|
|
3266
2604
|
case "oct":
|
|
3267
|
-
if (typeof
|
|
2605
|
+
if (typeof normalized.k != "string")
|
|
3268
2606
|
throw new TypeError('missing "k" (Key Value) Parameter value');
|
|
3269
|
-
|
|
3270
|
-
return decode(jwk.k);
|
|
3271
|
-
case "RSA":
|
|
3272
|
-
return jwkToKey(keyAlgorithm(alg), { ...jwk, alg, ext });
|
|
2607
|
+
return decode(normalized.k);
|
|
3273
2608
|
case "AKP": {
|
|
3274
|
-
if (typeof
|
|
2609
|
+
if (typeof jwkAlg != "string" || !jwkAlg)
|
|
3275
2610
|
throw new TypeError('missing "alg" (Algorithm) Parameter value');
|
|
3276
|
-
|
|
3277
|
-
if (alg !== void 0 && alg !== jwk.alg) {
|
|
2611
|
+
if (alg !== jwkAlg)
|
|
3278
2612
|
throw new TypeError("JWK alg and alg option value mismatch");
|
|
3279
|
-
|
|
3280
|
-
return jwkToKey(keyAlgorithm(jwk.alg), { ...jwk, ext });
|
|
2613
|
+
return jwkToKey(keyAlgorithm(alg), normalized, extractable);
|
|
3281
2614
|
}
|
|
2615
|
+
case "RSA":
|
|
3282
2616
|
case "EC":
|
|
3283
2617
|
case "OKP":
|
|
3284
|
-
return jwkToKey(keyAlgorithm(alg),
|
|
2618
|
+
return jwkToKey(keyAlgorithm(alg), normalized, extractable);
|
|
3285
2619
|
default:
|
|
3286
2620
|
throw new JOSENotSupported('Unsupported "kty" (Key Type) Parameter value');
|
|
3287
2621
|
}
|
|
@@ -5498,8 +4832,8 @@ async function assertActive$1(env, claims) {
|
|
|
5498
4832
|
`https://token-status.invalid/${encodeURIComponent(claims.iss)}/${encodeURIComponent(claims.jti)}?exp=${claims.exp}`
|
|
5499
4833
|
);
|
|
5500
4834
|
try {
|
|
5501
|
-
const
|
|
5502
|
-
if (
|
|
4835
|
+
const cached = await caches.default.match(key);
|
|
4836
|
+
if (cached) return;
|
|
5503
4837
|
} catch {
|
|
5504
4838
|
}
|
|
5505
4839
|
const result = await namedStub(env.TOKEN_CATALOG, "catalog").check({
|
|
@@ -5603,8 +4937,8 @@ function effectiveLifecycle(catalogue, coordinatorLifecycle) {
|
|
|
5603
4937
|
async function directoryReference(env, name) {
|
|
5604
4938
|
const key = new Request(`https://directory.invalid/cache/${name}`);
|
|
5605
4939
|
try {
|
|
5606
|
-
const
|
|
5607
|
-
if (
|
|
4940
|
+
const cached = await caches.default.match(key);
|
|
4941
|
+
if (cached) return await cached.json();
|
|
5608
4942
|
} catch {
|
|
5609
4943
|
}
|
|
5610
4944
|
const reference2 = unwrapRpc(await system(env).getCache(name));
|
|
@@ -5680,7 +5014,7 @@ function event(id, actor, action, resource, outcome) {
|
|
|
5680
5014
|
metadata: {}
|
|
5681
5015
|
};
|
|
5682
5016
|
}
|
|
5683
|
-
const cacheRoutes = new
|
|
5017
|
+
const cacheRoutes = new Hono2();
|
|
5684
5018
|
cacheRoutes.post("/api/caches", async (c) => {
|
|
5685
5019
|
const operationId = idempotency(c.req.raw);
|
|
5686
5020
|
const admin = await authenticateGlobal(c.req.raw, c.env, "admin");
|
|
@@ -5885,7 +5219,7 @@ function publicationFor(env, cache2, storeHash) {
|
|
|
5885
5219
|
new DurableQuotaLedgerAdapter(quota)
|
|
5886
5220
|
);
|
|
5887
5221
|
}
|
|
5888
|
-
const pathRoutes = new
|
|
5222
|
+
const pathRoutes = new Hono2();
|
|
5889
5223
|
pathRoutes.post("/api/caches/:name/missing", async (c) => {
|
|
5890
5224
|
const name = c.req.param("name");
|
|
5891
5225
|
assertCacheName(name);
|
|
@@ -5950,7 +5284,7 @@ function auditShardNames() {
|
|
|
5950
5284
|
function auditStub(env, eventId) {
|
|
5951
5285
|
return namedStub(env.AUDIT_LOG, auditShardName(eventId));
|
|
5952
5286
|
}
|
|
5953
|
-
const tokenRoutes = new
|
|
5287
|
+
const tokenRoutes = new Hono2();
|
|
5954
5288
|
tokenRoutes.post("/api/bootstrap", async (c) => {
|
|
5955
5289
|
const operationId = idempotency(c.req.raw);
|
|
5956
5290
|
const input = parseJsonSchema(
|
|
@@ -6041,7 +5375,7 @@ tokenRoutes.get("/api/audit", async (c) => {
|
|
|
6041
5375
|
next_cursor: hasMore && last ? encodeCursor({ timestamp: last.timestamp, id: last.id }) : null
|
|
6042
5376
|
});
|
|
6043
5377
|
});
|
|
6044
|
-
const controlRoutes = new
|
|
5378
|
+
const controlRoutes = new Hono2();
|
|
6045
5379
|
controlRoutes.get("/health", (c) => c.json({ status: "ok" }));
|
|
6046
5380
|
controlRoutes.get(
|
|
6047
5381
|
"/api/public-key",
|
|
@@ -6140,7 +5474,7 @@ async function serveNarObject(c, cache2, storeHash, record) {
|
|
|
6140
5474
|
});
|
|
6141
5475
|
return new Response(stream, { status, headers });
|
|
6142
5476
|
}
|
|
6143
|
-
const nixRoutes = new
|
|
5477
|
+
const nixRoutes = new Hono2();
|
|
6144
5478
|
const NARINFO = new RegExp(`^(${STORE_HASH_PATTERN})\\.narinfo$`);
|
|
6145
5479
|
const NAR_OBJECT = new RegExp(`^nar/(${STORE_HASH_PATTERN})\\.nar\\.zst$`);
|
|
6146
5480
|
async function nixHandler(c) {
|
|
@@ -6195,7 +5529,7 @@ async function uploadAccess(c) {
|
|
|
6195
5529
|
function stateResponse(value) {
|
|
6196
5530
|
return Response.json(value, { headers: { "cache-control": "no-store" } });
|
|
6197
5531
|
}
|
|
6198
|
-
const uploadRoutes = new
|
|
5532
|
+
const uploadRoutes = new Hono2();
|
|
6199
5533
|
uploadRoutes.post("/api/uploads", async (c) => {
|
|
6200
5534
|
const key = idempotency(c.req.raw);
|
|
6201
5535
|
const input = parseJsonSchema(
|
|
@@ -6277,7 +5611,7 @@ uploadRoutes.delete("/api/uploads/:id", async (c) => {
|
|
|
6277
5611
|
return stateResponse(unwrapRpc(await job.abort()));
|
|
6278
5612
|
});
|
|
6279
5613
|
function createApp() {
|
|
6280
|
-
const app2 = new
|
|
5614
|
+
const app2 = new Hono2();
|
|
6281
5615
|
app2.use("*", async (c, next) => {
|
|
6282
5616
|
const id = crypto.randomUUID();
|
|
6283
5617
|
c.set("requestId", id);
|