@madauth/server 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4462 @@
1
+ import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+
12
+ // src/store/schema.ts
13
+ var madauthSchema;
14
+ var init_schema = __esm({
15
+ "src/store/schema.ts"() {
16
+ "use strict";
17
+ madauthSchema = {
18
+ version: 1,
19
+ models: {
20
+ user: {
21
+ fields: {
22
+ id: { type: "string", primaryKey: true },
23
+ email: { type: "string" },
24
+ emailNormalized: { type: "string", unique: true },
25
+ emailVerified: { type: "boolean" },
26
+ name: { type: "string", nullable: true },
27
+ sessionVersion: { type: "number" },
28
+ lastMailAt: { type: "number" },
29
+ createdAt: { type: "number" }
30
+ }
31
+ },
32
+ /** How a user signs in. `key` is e.g. `password:<userId>`; later `google:<sub>` or `totp:<userId>`. */
33
+ account: {
34
+ fields: {
35
+ id: { type: "string", primaryKey: true },
36
+ userId: { type: "string", index: true },
37
+ key: { type: "string", unique: true },
38
+ secret: { type: "string", nullable: true },
39
+ failedAttempts: { type: "number" },
40
+ lockedUntil: { type: "number" },
41
+ createdAt: { type: "number" }
42
+ }
43
+ },
44
+ /** A pending e-mail verification or password reset. `id` is the SHA-256 of the link token. */
45
+ verification: {
46
+ fields: {
47
+ id: { type: "string", primaryKey: true },
48
+ userId: { type: "string", index: true },
49
+ purpose: { type: "string" },
50
+ codeHash: { type: "string" },
51
+ attempts: { type: "number" },
52
+ expiresAt: { type: "number" }
53
+ }
54
+ }
55
+ }
56
+ };
57
+ }
58
+ });
59
+
60
+ // src/store/sql.ts
61
+ function tableName(model) {
62
+ return `madauth_${model}`;
63
+ }
64
+ function columnName(field) {
65
+ return field.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
66
+ }
67
+ function createTablesSql(dialect, schema = madauthSchema) {
68
+ const statements = [];
69
+ for (const [model, { fields }] of Object.entries(schema.models)) {
70
+ const table2 = tableName(model);
71
+ const columns = Object.entries(fields).map(([field, def]) => {
72
+ const keyed = def.primaryKey || def.unique || def.index;
73
+ const type = dialect === "mysql" && def.type === "string" && keyed ? "VARCHAR(255)" : columnTypes[dialect][def.type];
74
+ const constraints = def.primaryKey ? " PRIMARY KEY" : `${def.nullable ? "" : " NOT NULL"}${def.unique ? " UNIQUE" : ""}`;
75
+ return ` ${columnName(field)} ${type}${constraints}`;
76
+ });
77
+ statements.push(`CREATE TABLE ${table2} (
78
+ ${columns.join(",\n")}
79
+ );`);
80
+ for (const [field, def] of Object.entries(fields)) {
81
+ if (def.index) statements.push(`CREATE INDEX ${table2}_${columnName(field)} ON ${table2} (${columnName(field)});`);
82
+ }
83
+ }
84
+ return statements.join("\n");
85
+ }
86
+ var columnTypes;
87
+ var init_sql = __esm({
88
+ "src/store/sql.ts"() {
89
+ "use strict";
90
+ init_schema();
91
+ columnTypes = {
92
+ sqlite: { string: "TEXT", number: "INTEGER", boolean: "INTEGER" },
93
+ // DOUBLE PRECISION keeps numbers as JavaScript numbers in most Postgres drivers (BIGINT often becomes a string).
94
+ postgres: { string: "TEXT", number: "DOUBLE PRECISION", boolean: "BOOLEAN" },
95
+ mysql: { string: "TEXT", number: "DOUBLE", boolean: "BOOLEAN" }
96
+ };
97
+ }
98
+ });
99
+
100
+ // src/store/sqlite.ts
101
+ var sqlite_exports = {};
102
+ __export(sqlite_exports, {
103
+ createSqliteAdapter: () => createSqliteAdapter
104
+ });
105
+ function createSqliteAdapter(path) {
106
+ const { DatabaseSync } = process.getBuiltinModule("node:sqlite");
107
+ const db = new DatabaseSync(path);
108
+ db.exec("PRAGMA busy_timeout = 5000");
109
+ if (path !== ":memory:") db.exec("PRAGMA journal_mode = WAL");
110
+ migrate(db);
111
+ const fieldsOf = (model) => {
112
+ const fields = madauthSchema.models[model]?.fields;
113
+ if (!fields) throw new Error(`Unknown model "${model}"`);
114
+ return fields;
115
+ };
116
+ const column = (fields, field) => {
117
+ if (!fields[field]) throw new Error(`Unknown field "${field}"`);
118
+ return columnName(field);
119
+ };
120
+ const toSql = (value) => typeof value === "boolean" ? value ? 1 : 0 : value;
121
+ const whereSql = (fields, where) => {
122
+ const parts = [];
123
+ const params = [];
124
+ for (const [field, value] of Object.entries(where)) {
125
+ if (value === null) {
126
+ parts.push(`${column(fields, field)} IS NULL`);
127
+ } else {
128
+ parts.push(`${column(fields, field)} = ?`);
129
+ params.push(toSql(value));
130
+ }
131
+ }
132
+ return { sql: parts.length ? ` WHERE ${parts.join(" AND ")}` : "", params };
133
+ };
134
+ const fromSql = (fields, raw2) => {
135
+ const row = {};
136
+ for (const [field, def] of Object.entries(fields)) {
137
+ const value = raw2[columnName(field)];
138
+ row[field] = def.type === "boolean" && value !== null ? value === 1 : value;
139
+ }
140
+ return row;
141
+ };
142
+ return {
143
+ async create(model, data) {
144
+ const fields = fieldsOf(model);
145
+ const names = Object.keys(data);
146
+ const sql = `INSERT INTO ${tableName(model)} (${names.map((f) => column(fields, f)).join(", ")}) VALUES (${names.map(() => "?").join(", ")}) ON CONFLICT DO NOTHING`;
147
+ return Number(db.prepare(sql).run(...names.map((f) => toSql(data[f]))).changes) === 1;
148
+ },
149
+ async findOne(model, where) {
150
+ const fields = fieldsOf(model);
151
+ const w = whereSql(fields, where);
152
+ const raw2 = db.prepare(`SELECT * FROM ${tableName(model)}${w.sql} LIMIT 1`).get(...w.params);
153
+ return raw2 ? fromSql(fields, raw2) : null;
154
+ },
155
+ async findMany(model, where, opts = {}) {
156
+ const fields = fieldsOf(model);
157
+ const w = whereSql(fields, where);
158
+ const limit = opts.limit === void 0 ? "" : ` LIMIT ${Math.max(0, Math.floor(opts.limit))}`;
159
+ return db.prepare(`SELECT * FROM ${tableName(model)}${w.sql}${limit}`).all(...w.params).map((raw2) => fromSql(fields, raw2));
160
+ },
161
+ async update(model, where, patch) {
162
+ const fields = fieldsOf(model);
163
+ const names = Object.keys(patch);
164
+ if (!names.length) return 0;
165
+ const w = whereSql(fields, where);
166
+ const sql = `UPDATE ${tableName(model)} SET ${names.map((f) => `${column(fields, f)} = ?`).join(", ")}${w.sql}`;
167
+ return Number(db.prepare(sql).run(...names.map((f) => toSql(patch[f])), ...w.params).changes);
168
+ },
169
+ async delete(model, where) {
170
+ const fields = fieldsOf(model);
171
+ const w = whereSql(fields, where);
172
+ return Number(db.prepare(`DELETE FROM ${tableName(model)}${w.sql}`).run(...w.params).changes);
173
+ }
174
+ };
175
+ }
176
+ function migrate(db) {
177
+ const { user_version: version } = db.prepare("PRAGMA user_version").get();
178
+ if (version > madauthSchema.version) {
179
+ throw new Error(
180
+ `The database uses madAuth schema version ${version}, but this madAuth only knows version ${madauthSchema.version}. Update madAuth.`
181
+ );
182
+ }
183
+ if (version === madauthSchema.version) return;
184
+ db.exec("BEGIN");
185
+ try {
186
+ db.exec(createTablesSql("sqlite"));
187
+ db.exec(`PRAGMA user_version = ${madauthSchema.version}`);
188
+ db.exec("COMMIT");
189
+ } catch (e) {
190
+ db.exec("ROLLBACK");
191
+ throw e;
192
+ }
193
+ }
194
+ var init_sqlite = __esm({
195
+ "src/store/sqlite.ts"() {
196
+ "use strict";
197
+ init_schema();
198
+ init_sql();
199
+ }
200
+ });
201
+
202
+ // ../../node_modules/hono/dist/utils/encode.js
203
+ var encodeBase64 = (buf) => {
204
+ let binary = "";
205
+ const bytes = new Uint8Array(buf);
206
+ for (let i = 0, len = bytes.length; i < len; i++) binary += String.fromCharCode(bytes[i]);
207
+ return btoa(binary);
208
+ };
209
+ var decodeBase64 = (str) => {
210
+ const binary = atob(str);
211
+ const bytes = new Uint8Array(new ArrayBuffer(binary.length));
212
+ const half = binary.length / 2;
213
+ for (let i = 0, j = binary.length - 1; i <= half; i++, j--) {
214
+ bytes[i] = binary.charCodeAt(i);
215
+ bytes[j] = binary.charCodeAt(j);
216
+ }
217
+ return bytes;
218
+ };
219
+
220
+ // ../../node_modules/hono/dist/adapter/aws-lambda/handler.js
221
+ import { pipeline } from "stream/promises";
222
+ function sanitizeHeaderValue(value) {
223
+ if (!/[^\x00-\x7F]/.test(value)) return value;
224
+ return encodeURIComponent(value);
225
+ }
226
+ var getRequestContext = (event) => {
227
+ return event.requestContext;
228
+ };
229
+ var handle = (app, { isContentTypeBinary } = { isContentTypeBinary: void 0 }) => {
230
+ return async (event, lambdaContext) => {
231
+ const processor = getProcessor(event);
232
+ let req, requestContext;
233
+ try {
234
+ req = processor.createRequest(event);
235
+ requestContext = getRequestContext(event);
236
+ } catch (error) {
237
+ console.error("Error processing request:", error);
238
+ const errorResponse = error instanceof TypeError ? new Response("Invalid request", { status: 400 }) : new Response("Internal Server Error", { status: 500 });
239
+ return processor.createResult(event, errorResponse, { isContentTypeBinary });
240
+ }
241
+ const res = await app.fetch(req, {
242
+ event,
243
+ requestContext,
244
+ lambdaContext
245
+ });
246
+ return processor.createResult(event, res, { isContentTypeBinary });
247
+ };
248
+ };
249
+ var EventProcessor = class {
250
+ getHeaderValue(headers, key) {
251
+ return headers ? Array.isArray(headers[key]) ? headers[key][0] : headers[key] : void 0;
252
+ }
253
+ getDomainName(event) {
254
+ if (event.requestContext && "domainName" in event.requestContext) return event.requestContext.domainName;
255
+ const hostFromHeaders = this.getHeaderValue(event.headers, "host");
256
+ if (hostFromHeaders) return hostFromHeaders;
257
+ const multiValueHeaders = "multiValueHeaders" in event ? event.multiValueHeaders : {};
258
+ return this.getHeaderValue(multiValueHeaders, "host");
259
+ }
260
+ createRequest(event) {
261
+ const queryString = this.getQueryString(event);
262
+ const urlPath = `https://${this.getDomainName(event)}${this.getPath(event)}`;
263
+ const url = queryString ? `${urlPath}?${queryString}` : urlPath;
264
+ const headers = this.getHeaders(event);
265
+ const requestInit = {
266
+ headers,
267
+ method: this.getMethod(event)
268
+ };
269
+ if (event.body) {
270
+ const body = event.isBase64Encoded ? decodeBase64(event.body) : new TextEncoder().encode(event.body);
271
+ requestInit.body = body;
272
+ headers.set("content-length", body.length.toString());
273
+ }
274
+ return new Request(url, requestInit);
275
+ }
276
+ async createResult(event, res, options) {
277
+ const contentType = res.headers.get("content-type");
278
+ const isContentTypeBinary = options.isContentTypeBinary ?? defaultIsContentTypeBinary;
279
+ let isBase64Encoded = contentType && isContentTypeBinary(contentType) ? true : false;
280
+ if (!isBase64Encoded) {
281
+ const contentEncoding = res.headers.get("content-encoding");
282
+ isBase64Encoded = isContentEncodingBinary(contentEncoding);
283
+ }
284
+ const result = {
285
+ body: isBase64Encoded ? encodeBase64(await res.arrayBuffer()) : await res.text(),
286
+ statusCode: res.status,
287
+ isBase64Encoded,
288
+ ..."multiValueHeaders" in event && event.multiValueHeaders ? { multiValueHeaders: {} } : { headers: {} }
289
+ };
290
+ this.setCookies(event, res, result);
291
+ if (result.multiValueHeaders) res.headers.forEach((value, key) => {
292
+ result.multiValueHeaders[key] = [value];
293
+ });
294
+ else res.headers.forEach((value, key) => {
295
+ result.headers[key] = value;
296
+ });
297
+ return result;
298
+ }
299
+ setCookies(_event, res, result) {
300
+ if (res.headers.has("set-cookie")) {
301
+ const cookies = res.headers.getSetCookie ? res.headers.getSetCookie() : Array.from(res.headers.entries()).filter(([k]) => k === "set-cookie").map(([, v]) => v);
302
+ if (Array.isArray(cookies)) {
303
+ this.setCookiesToResult(result, cookies);
304
+ res.headers.delete("set-cookie");
305
+ }
306
+ }
307
+ }
308
+ };
309
+ var EventV2Processor = class extends EventProcessor {
310
+ getPath(event) {
311
+ return event.rawPath;
312
+ }
313
+ getMethod(event) {
314
+ return event.requestContext.http.method;
315
+ }
316
+ getQueryString(event) {
317
+ return event.rawQueryString;
318
+ }
319
+ getCookies(event, headers) {
320
+ if (Array.isArray(event.cookies)) headers.set("Cookie", event.cookies.join("; "));
321
+ }
322
+ setCookiesToResult(result, cookies) {
323
+ result.cookies = cookies;
324
+ }
325
+ getHeaders(event) {
326
+ const headers = new Headers();
327
+ this.getCookies(event, headers);
328
+ if (event.headers) {
329
+ for (const [k, v] of Object.entries(event.headers)) if (v) headers.set(k, v);
330
+ }
331
+ return headers;
332
+ }
333
+ };
334
+ var v2Processor = new EventV2Processor();
335
+ var EventV1Processor = class extends EventProcessor {
336
+ getPath(event) {
337
+ return event.path;
338
+ }
339
+ getMethod(event) {
340
+ return event.httpMethod;
341
+ }
342
+ getQueryString(event) {
343
+ if (event.multiValueQueryStringParameters) return Object.entries(event.multiValueQueryStringParameters || {}).filter(([, value]) => value).map(([key, values]) => values.map((value) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&")).join("&");
344
+ else return Object.entries(event.queryStringParameters || {}).filter(([, value]) => value !== void 0).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value || "")}`).join("&");
345
+ }
346
+ getCookies(_event, _headers) {
347
+ }
348
+ getHeaders(event) {
349
+ const headers = new Headers();
350
+ this.getCookies(event, headers);
351
+ if (event.multiValueHeaders) {
352
+ for (const [k, values] of Object.entries(event.multiValueHeaders)) if (values) values.forEach((v) => headers.append(k, sanitizeHeaderValue(v)));
353
+ }
354
+ if (event.headers) {
355
+ for (const [k, v] of Object.entries(event.headers)) if (v && !headers.has(k)) headers.set(k, sanitizeHeaderValue(v));
356
+ }
357
+ return headers;
358
+ }
359
+ setCookiesToResult(result, cookies) {
360
+ result.multiValueHeaders = { "set-cookie": cookies };
361
+ }
362
+ };
363
+ var v1Processor = new EventV1Processor();
364
+ var ALBProcessor = class extends EventProcessor {
365
+ getHeaders(event) {
366
+ const headers = new Headers();
367
+ if (event.multiValueHeaders) {
368
+ for (const [key, values] of Object.entries(event.multiValueHeaders)) if (values && Array.isArray(values)) {
369
+ const sanitizedValue = sanitizeHeaderValue(values.join("; "));
370
+ headers.set(key, sanitizedValue);
371
+ }
372
+ } else for (const [key, value] of Object.entries(event.headers ?? {})) if (value) headers.set(key, sanitizeHeaderValue(value));
373
+ return headers;
374
+ }
375
+ getPath(event) {
376
+ return event.path;
377
+ }
378
+ getMethod(event) {
379
+ return event.httpMethod;
380
+ }
381
+ getQueryString(event) {
382
+ if (event.multiValueQueryStringParameters) return Object.entries(event.multiValueQueryStringParameters || {}).filter(([, value]) => value).map(([key, value]) => `${key}=${value.join(`&${key}=`)}`).join("&");
383
+ else return Object.entries(event.queryStringParameters || {}).filter(([, value]) => value !== void 0).map(([key, value]) => `${key}=${value}`).join("&");
384
+ }
385
+ getCookies(event, headers) {
386
+ let cookie;
387
+ if (event.multiValueHeaders) cookie = event.multiValueHeaders["cookie"]?.join("; ");
388
+ else cookie = event.headers ? event.headers["cookie"] : void 0;
389
+ if (cookie) headers.append("Cookie", cookie);
390
+ }
391
+ setCookiesToResult(result, cookies) {
392
+ if (result.multiValueHeaders) result.multiValueHeaders["set-cookie"] = cookies;
393
+ else result.headers["set-cookie"] = cookies[0];
394
+ }
395
+ };
396
+ var albProcessor = new ALBProcessor();
397
+ var LatticeV2Processor = class extends EventProcessor {
398
+ getPath(event) {
399
+ return event.path;
400
+ }
401
+ getMethod(event) {
402
+ return event.method;
403
+ }
404
+ getQueryString() {
405
+ return "";
406
+ }
407
+ getHeaders(event) {
408
+ const headers = new Headers();
409
+ if (event.headers) {
410
+ for (const [k, values] of Object.entries(event.headers)) if (values) values.forEach((v) => headers.append(k, sanitizeHeaderValue(v)));
411
+ }
412
+ return headers;
413
+ }
414
+ getCookies() {
415
+ }
416
+ setCookiesToResult(result, cookies) {
417
+ result.headers = {
418
+ ...result.headers,
419
+ "set-cookie": cookies
420
+ };
421
+ }
422
+ };
423
+ var latticeV2Processor = new LatticeV2Processor();
424
+ var getProcessor = (event) => {
425
+ if (isProxyEventALB(event)) return albProcessor;
426
+ if (isProxyEventV2(event)) return v2Processor;
427
+ if (isLatticeEventV2(event)) return latticeV2Processor;
428
+ return v1Processor;
429
+ };
430
+ var isProxyEventALB = (event) => {
431
+ if (event.requestContext) return Object.hasOwn(event.requestContext, "elb");
432
+ return false;
433
+ };
434
+ var isProxyEventV2 = (event) => {
435
+ return Object.hasOwn(event, "rawPath") && Object.hasOwn(event.requestContext ?? {}, "http");
436
+ };
437
+ var isLatticeEventV2 = (event) => {
438
+ if (event.requestContext) return Object.hasOwn(event.requestContext, "serviceArn");
439
+ return false;
440
+ };
441
+ var defaultIsContentTypeBinary = (contentType) => {
442
+ if (/^application\/vnd\.(?:apple\.installer|mozilla\.xul)\+xml\s*(?:;|$)/i.test(contentType)) return true;
443
+ return !/^text\/(?:plain|html|css|javascript|csv)|(?:\/|\+)(?:json|xml)\s*(?:;|$)/i.test(contentType);
444
+ };
445
+ var isContentEncodingBinary = (contentEncoding) => {
446
+ return !!contentEncoding && !/^identity$/i.test(contentEncoding);
447
+ };
448
+
449
+ // ../../node_modules/hono/dist/request/constants.js
450
+ var GET_MATCH_RESULT = /* @__PURE__ */ Symbol();
451
+
452
+ // ../../node_modules/hono/dist/utils/buffer.js
453
+ var bufferToFormData = (arrayBuffer, contentType) => {
454
+ return new Response(arrayBuffer, { headers: { "Content-Type": contentType.replace(/^[^;]+/, (mediaType) => mediaType.toLowerCase()) } }).formData();
455
+ };
456
+
457
+ // ../../node_modules/hono/dist/utils/body.js
458
+ var MAX_NESTED_OBJECTS = 1e4;
459
+ var isRawRequest = (request) => "headers" in request;
460
+ var parseBody = async (request, options = /* @__PURE__ */ Object.create(null)) => {
461
+ const { all = false, dot = false } = options;
462
+ const mediaType = (isRawRequest(request) ? request.headers : request.raw.headers).get("Content-Type")?.split(";")[0].trim().toLowerCase();
463
+ if (mediaType === "multipart/form-data" || mediaType === "application/x-www-form-urlencoded") return parseFormData(request, {
464
+ all,
465
+ dot
466
+ });
467
+ return {};
468
+ };
469
+ async function parseFormData(request, options) {
470
+ if (!isRawRequest(request) && request.bodyCache.formData) return convertFormDataToBodyData(await request.bodyCache.formData, options);
471
+ const headers = isRawRequest(request) ? request.headers : request.raw.headers;
472
+ const arrayBuffer = await request.arrayBuffer();
473
+ const formDataPromise = bufferToFormData(arrayBuffer, headers.get("Content-Type") || "");
474
+ if (!isRawRequest(request)) request.bodyCache.formData = formDataPromise;
475
+ const formData = await formDataPromise;
476
+ if (formData) return convertFormDataToBodyData(formData, options);
477
+ return {};
478
+ }
479
+ function convertFormDataToBodyData(formData, options) {
480
+ const form = /* @__PURE__ */ Object.create(null);
481
+ const nestingState = { count: 0 };
482
+ formData.forEach((value, key) => {
483
+ if (!(options.all || key.endsWith("[]"))) form[key] = value;
484
+ else handleParsingAllValues(form, key, value);
485
+ });
486
+ if (options.dot) Object.entries(form).forEach(([key, value]) => {
487
+ if (key.includes(".")) {
488
+ handleParsingNestedValues(form, key, value, nestingState);
489
+ delete form[key];
490
+ }
491
+ });
492
+ return form;
493
+ }
494
+ var handleParsingAllValues = (form, key, value) => {
495
+ if (form[key] !== void 0) {
496
+ if (Array.isArray(form[key])) form[key].push(value);
497
+ else form[key] = [form[key], value];
498
+ } else if (!key.endsWith("[]")) form[key] = value;
499
+ else form[key] = [value];
500
+ };
501
+ var handleParsingNestedValues = (form, key, value, state) => {
502
+ if (/(?:^|\.)__proto__\./.test(key)) return;
503
+ let nestedForm = form;
504
+ const keys = key.split(".", 34);
505
+ if (keys.length > 33) throwNestingLimitExceeded();
506
+ keys.forEach((key2, index) => {
507
+ if (index === keys.length - 1) nestedForm[key2] = value;
508
+ else {
509
+ if (!nestedForm[key2] || typeof nestedForm[key2] !== "object" || Array.isArray(nestedForm[key2]) || nestedForm[key2] instanceof File) {
510
+ if (state.count++ >= MAX_NESTED_OBJECTS) throwNestingLimitExceeded();
511
+ nestedForm[key2] = /* @__PURE__ */ Object.create(null);
512
+ }
513
+ nestedForm = nestedForm[key2];
514
+ }
515
+ });
516
+ };
517
+ var throwNestingLimitExceeded = () => {
518
+ throw new Error("Nesting limit exceeded");
519
+ };
520
+
521
+ // ../../node_modules/hono/dist/utils/url.js
522
+ var splitPath = (path) => {
523
+ const paths = path.split("/");
524
+ if (paths[0] === "") paths.shift();
525
+ return paths;
526
+ };
527
+ var splitRoutingPath = (routePath) => {
528
+ const { groups, path } = extractGroupsFromPath(routePath);
529
+ const paths = splitPath(path);
530
+ return replaceGroupMarks(paths, groups);
531
+ };
532
+ var extractGroupsFromPath = (path) => {
533
+ const groups = [];
534
+ path = path.replace(/\{[^}]+\}/g, (match2, index) => {
535
+ const mark = `@${index}`;
536
+ groups.push([mark, match2]);
537
+ return mark;
538
+ });
539
+ return {
540
+ groups,
541
+ path
542
+ };
543
+ };
544
+ var replaceGroupMarks = (paths, groups) => {
545
+ for (let i = groups.length - 1; i >= 0; i--) {
546
+ const [mark] = groups[i];
547
+ for (let j = paths.length - 1; j >= 0; j--) if (paths[j].includes(mark)) {
548
+ paths[j] = paths[j].replace(mark, groups[i][1]);
549
+ break;
550
+ }
551
+ }
552
+ return paths;
553
+ };
554
+ var patternCache = {};
555
+ var getPattern = (label, next) => {
556
+ if (label === "*") return "*";
557
+ const match2 = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
558
+ if (match2) {
559
+ const cacheKey = `${label}#${next}`;
560
+ if (!patternCache[cacheKey]) {
561
+ if (match2[2]) patternCache[cacheKey] = next && next[0] !== ":" && next[0] !== "*" ? [
562
+ cacheKey,
563
+ match2[1],
564
+ new RegExp(`^${match2[2]}(?=/${next})`)
565
+ ] : [
566
+ label,
567
+ match2[1],
568
+ new RegExp(`^${match2[2]}$`)
569
+ ];
570
+ else patternCache[cacheKey] = [
571
+ label,
572
+ match2[1],
573
+ true
574
+ ];
575
+ }
576
+ return patternCache[cacheKey];
577
+ }
578
+ return null;
579
+ };
580
+ var tryDecode = (str, decoder2) => {
581
+ try {
582
+ return decoder2(str);
583
+ } catch {
584
+ return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match2) => {
585
+ try {
586
+ return decoder2(match2);
587
+ } catch {
588
+ return match2;
589
+ }
590
+ });
591
+ }
592
+ };
593
+ var tryDecodeURI = (str) => tryDecode(str, decodeURI);
594
+ var getPath = (request) => {
595
+ const url = request.url;
596
+ const start = url.indexOf("/", url.indexOf(":") + 4);
597
+ let i = start;
598
+ for (; i < url.length; i++) {
599
+ const charCode = url.charCodeAt(i);
600
+ if (charCode === 37) {
601
+ const queryIndex = url.indexOf("?", i);
602
+ const hashIndex = url.indexOf("#", i);
603
+ const end = queryIndex === -1 ? hashIndex === -1 ? void 0 : hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex);
604
+ const path = url.slice(start, end);
605
+ return tryDecodeURI(path.includes("%25") ? path.replace(/%25/g, "%2525") : path);
606
+ } else if (charCode === 63 || charCode === 35) break;
607
+ }
608
+ return url.slice(start, i);
609
+ };
610
+ var getPathNoStrict = (request) => {
611
+ const result = getPath(request);
612
+ return result.length > 1 && result.at(-1) === "/" ? result.slice(0, -1) : result;
613
+ };
614
+ var mergePath = (base, sub, ...rest) => {
615
+ if (rest.length) sub = mergePath(sub, ...rest);
616
+ return `${base?.[0] === "/" ? "" : "/"}${base}${sub === "/" ? "" : `${base?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`;
617
+ };
618
+ var checkOptionalParameter = (path) => {
619
+ if (path.charCodeAt(path.length - 1) !== 63 || !path.includes(":")) return null;
620
+ const segments = path.split("/");
621
+ const results = [];
622
+ let basePath = "";
623
+ segments.forEach((segment) => {
624
+ if (segment !== "" && !/\:/.test(segment)) basePath += "/" + segment;
625
+ else if (/\:/.test(segment)) {
626
+ if (segment.charCodeAt(segment.length - 1) === 63) {
627
+ if (results.length === 0 && basePath === "") results.push("/");
628
+ else results.push(basePath);
629
+ const optionalSegment = segment.slice(0, -1);
630
+ basePath += "/" + optionalSegment;
631
+ results.push(basePath);
632
+ } else basePath += "/" + segment;
633
+ }
634
+ });
635
+ return results.filter((v, i, a) => a.indexOf(v) === i);
636
+ };
637
+ var tryDecodeURIComponent = (str) => str.indexOf("%") !== -1 ? tryDecode(str, decodeURIComponent_) : str;
638
+ var _decodeURI = (value) => {
639
+ if (value.indexOf("+") !== -1) value = value.replace(/\+/g, " ");
640
+ return tryDecodeURIComponent(value);
641
+ };
642
+ var _getQueryParam = (url, key, multiple) => {
643
+ const hashIndex = url.indexOf("#", 8);
644
+ if (hashIndex !== -1) url = url.slice(0, hashIndex);
645
+ let encoded;
646
+ if (!multiple && key && key.indexOf("%") === -1 && key.indexOf("+") === -1) {
647
+ let keyIndex2 = url.indexOf("?", 8);
648
+ if (keyIndex2 === -1) return;
649
+ if (!url.startsWith(key, keyIndex2 + 1)) keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
650
+ while (keyIndex2 !== -1) {
651
+ const trailingKeyCode = url.charCodeAt(keyIndex2 + key.length + 1);
652
+ if (trailingKeyCode === 61) {
653
+ const valueIndex = keyIndex2 + key.length + 2;
654
+ const endIndex = url.indexOf("&", valueIndex);
655
+ return _decodeURI(url.slice(valueIndex, endIndex === -1 ? void 0 : endIndex));
656
+ } else if (trailingKeyCode == 38 || isNaN(trailingKeyCode)) return "";
657
+ keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
658
+ }
659
+ encoded = /[%+]/.test(url);
660
+ if (!encoded) return;
661
+ }
662
+ const results = /* @__PURE__ */ Object.create(null);
663
+ encoded ??= /[%+]/.test(url);
664
+ let keyIndex = url.indexOf("?", 8);
665
+ while (keyIndex !== -1) {
666
+ const nextKeyIndex = url.indexOf("&", keyIndex + 1);
667
+ let valueIndex = url.indexOf("=", keyIndex);
668
+ if (valueIndex > nextKeyIndex && nextKeyIndex !== -1) valueIndex = -1;
669
+ let name = url.slice(keyIndex + 1, valueIndex === -1 ? nextKeyIndex === -1 ? void 0 : nextKeyIndex : valueIndex);
670
+ if (encoded) name = _decodeURI(name);
671
+ keyIndex = nextKeyIndex;
672
+ if (name === "") continue;
673
+ let value;
674
+ if (valueIndex === -1) value = "";
675
+ else {
676
+ value = url.slice(valueIndex + 1, nextKeyIndex === -1 ? void 0 : nextKeyIndex);
677
+ if (encoded) value = _decodeURI(value);
678
+ }
679
+ if (multiple) {
680
+ if (!(results[name] && Array.isArray(results[name]))) results[name] = [];
681
+ results[name].push(value);
682
+ } else results[name] ??= value;
683
+ }
684
+ return key ? results[key] : results;
685
+ };
686
+ var getQueryParam = _getQueryParam;
687
+ var getQueryParams = (url, key) => {
688
+ return _getQueryParam(url, key, true);
689
+ };
690
+ var decodeURIComponent_ = decodeURIComponent;
691
+
692
+ // ../../node_modules/hono/dist/request.js
693
+ var HonoRequest = class {
694
+ /**
695
+ * `.raw` can get the raw Request object.
696
+ *
697
+ * @see {@link https://hono.dev/docs/api/request#raw}
698
+ *
699
+ * @example
700
+ * ```ts
701
+ * // For Cloudflare Workers
702
+ * app.post('/', async (c) => {
703
+ * const metadata = c.req.raw.cf?.hostMetadata?
704
+ * ...
705
+ * })
706
+ * ```
707
+ */
708
+ raw;
709
+ #validatedData;
710
+ #matchResult;
711
+ routeIndex = 0;
712
+ /**
713
+ * `.path` can get the pathname of the request.
714
+ *
715
+ * @see {@link https://hono.dev/docs/api/request#path}
716
+ *
717
+ * @example
718
+ * ```ts
719
+ * app.get('/about/me', (c) => {
720
+ * const pathname = c.req.path // `/about/me`
721
+ * })
722
+ * ```
723
+ */
724
+ path;
725
+ bodyCache = {};
726
+ constructor(request, path = "/", matchResult = [[]]) {
727
+ this.raw = request;
728
+ this.path = path;
729
+ this.#matchResult = matchResult;
730
+ }
731
+ param(key) {
732
+ return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams();
733
+ }
734
+ #getDecodedParam(key) {
735
+ const paramKey = this.#matchResult[0][this.routeIndex]?.[1][key];
736
+ const param = this.#getParamValue(paramKey);
737
+ return param && tryDecodeURIComponent(param);
738
+ }
739
+ #getAllDecodedParams() {
740
+ const decoded = {};
741
+ const keys = Object.keys(this.#matchResult[0][this.routeIndex]?.[1] ?? {});
742
+ for (const key of keys) {
743
+ const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]);
744
+ if (value !== void 0) decoded[key] = tryDecodeURIComponent(value);
745
+ }
746
+ return decoded;
747
+ }
748
+ #getParamValue(paramKey) {
749
+ return this.#matchResult[1] ? this.#matchResult[1][paramKey] : paramKey;
750
+ }
751
+ query(key) {
752
+ return getQueryParam(this.url, key);
753
+ }
754
+ queries(key) {
755
+ return getQueryParams(this.url, key);
756
+ }
757
+ header(name) {
758
+ if (name) return this.raw.headers.get(name) ?? void 0;
759
+ const headerData = /* @__PURE__ */ Object.create(null);
760
+ this.raw.headers.forEach((value, key) => {
761
+ headerData[key] = value;
762
+ });
763
+ return headerData;
764
+ }
765
+ async parseBody(options) {
766
+ return parseBody(this, options);
767
+ }
768
+ #cachedBody = (key) => {
769
+ const { bodyCache, raw: raw2 } = this;
770
+ const cachedBody = bodyCache[key];
771
+ if (cachedBody) return cachedBody;
772
+ for (const anyCachedKey in bodyCache) return bodyCache[anyCachedKey].then((body) => {
773
+ if (anyCachedKey === "json") body = JSON.stringify(body);
774
+ const contentType = anyCachedKey === "formData" ? void 0 : raw2.headers.get("content-type");
775
+ return new Response(body, { headers: contentType ? { "Content-Type": contentType } : void 0 })[key]();
776
+ });
777
+ return bodyCache[key] = raw2[key]();
778
+ };
779
+ /**
780
+ * `.json()` can parse Request body of type `application/json`
781
+ *
782
+ * @see {@link https://hono.dev/docs/api/request#json}
783
+ *
784
+ * @example
785
+ * ```ts
786
+ * app.post('/entry', async (c) => {
787
+ * const body = await c.req.json()
788
+ * })
789
+ * ```
790
+ */
791
+ json() {
792
+ return this.#cachedBody("text").then((text) => JSON.parse(text));
793
+ }
794
+ /**
795
+ * `.text()` can parse Request body of type `text/plain`
796
+ *
797
+ * @see {@link https://hono.dev/docs/api/request#text}
798
+ *
799
+ * @example
800
+ * ```ts
801
+ * app.post('/entry', async (c) => {
802
+ * const body = await c.req.text()
803
+ * })
804
+ * ```
805
+ */
806
+ text() {
807
+ return this.#cachedBody("text");
808
+ }
809
+ /**
810
+ * `.arrayBuffer()` parse Request body as an `ArrayBuffer`
811
+ *
812
+ * @see {@link https://hono.dev/docs/api/request#arraybuffer}
813
+ *
814
+ * @example
815
+ * ```ts
816
+ * app.post('/entry', async (c) => {
817
+ * const body = await c.req.arrayBuffer()
818
+ * })
819
+ * ```
820
+ */
821
+ arrayBuffer() {
822
+ return this.#cachedBody("arrayBuffer");
823
+ }
824
+ /**
825
+ * `.bytes()` parses the request body as a `Uint8Array`.
826
+ *
827
+ * @see {@link https://hono.dev/docs/api/request#bytes}
828
+ *
829
+ * @example
830
+ * ```ts
831
+ * app.post('/entry', async (c) => {
832
+ * const body = await c.req.bytes()
833
+ * })
834
+ * ```
835
+ */
836
+ bytes() {
837
+ return this.#cachedBody("arrayBuffer").then((buffer) => new Uint8Array(buffer));
838
+ }
839
+ /**
840
+ * Parses the request body as a `Blob`.
841
+ * @example
842
+ * ```ts
843
+ * app.post('/entry', async (c) => {
844
+ * const body = await c.req.blob();
845
+ * });
846
+ * ```
847
+ * @see https://hono.dev/docs/api/request#blob
848
+ */
849
+ blob() {
850
+ return this.#cachedBody("blob");
851
+ }
852
+ /**
853
+ * Parses the request body as `FormData`.
854
+ * @example
855
+ * ```ts
856
+ * app.post('/entry', async (c) => {
857
+ * const body = await c.req.formData();
858
+ * });
859
+ * ```
860
+ * @see https://hono.dev/docs/api/request#formdata
861
+ */
862
+ formData() {
863
+ return this.#cachedBody("formData");
864
+ }
865
+ /**
866
+ * Adds validated data to the request.
867
+ *
868
+ * @param target - The target of the validation.
869
+ * @param data - The validated data to add.
870
+ */
871
+ addValidatedData(target, data) {
872
+ (this.#validatedData ??= {})[target] = data;
873
+ }
874
+ valid(target) {
875
+ return this.#validatedData?.[target];
876
+ }
877
+ /**
878
+ * `.url()` can get the request url strings.
879
+ *
880
+ * @see {@link https://hono.dev/docs/api/request#url}
881
+ *
882
+ * @example
883
+ * ```ts
884
+ * app.get('/about/me', (c) => {
885
+ * const url = c.req.url // `http://localhost:8787/about/me`
886
+ * ...
887
+ * })
888
+ * ```
889
+ */
890
+ get url() {
891
+ return this.raw.url;
892
+ }
893
+ /**
894
+ * `.method()` can get the method name of the request.
895
+ *
896
+ * @see {@link https://hono.dev/docs/api/request#method}
897
+ *
898
+ * @example
899
+ * ```ts
900
+ * app.get('/about/me', (c) => {
901
+ * const method = c.req.method // `GET`
902
+ * })
903
+ * ```
904
+ */
905
+ get method() {
906
+ return this.raw.method;
907
+ }
908
+ get [GET_MATCH_RESULT]() {
909
+ return this.#matchResult;
910
+ }
911
+ /**
912
+ * `.matchedRoutes()` can return a matched route in the handler
913
+ *
914
+ * @deprecated
915
+ *
916
+ * Use matchedRoutes helper defined in "hono/route" instead.
917
+ *
918
+ * @see {@link https://hono.dev/docs/api/request#matchedroutes}
919
+ *
920
+ * @example
921
+ * ```ts
922
+ * app.use('*', async function logger(c, next) {
923
+ * await next()
924
+ * c.req.matchedRoutes.forEach(({ handler, method, path }, i) => {
925
+ * const name = handler.name || (handler.length < 2 ? '[handler]' : '[middleware]')
926
+ * console.log(
927
+ * method,
928
+ * ' ',
929
+ * path,
930
+ * ' '.repeat(Math.max(10 - path.length, 0)),
931
+ * name,
932
+ * i === c.req.routeIndex ? '<- respond from here' : ''
933
+ * )
934
+ * })
935
+ * })
936
+ * ```
937
+ */
938
+ get matchedRoutes() {
939
+ return this.#matchResult[0].map(([[, route]]) => route);
940
+ }
941
+ /**
942
+ * `routePath()` can retrieve the path registered within the handler
943
+ *
944
+ * @deprecated
945
+ *
946
+ * Use routePath helper defined in "hono/route" instead.
947
+ *
948
+ * @see {@link https://hono.dev/docs/api/request#routepath}
949
+ *
950
+ * @example
951
+ * ```ts
952
+ * app.get('/posts/:id', (c) => {
953
+ * return c.json({ path: c.req.routePath })
954
+ * })
955
+ * ```
956
+ */
957
+ get routePath() {
958
+ return this.#matchResult[0].map(([[, route]]) => route)[this.routeIndex].path;
959
+ }
960
+ };
961
+
962
+ // ../../node_modules/hono/dist/utils/html.js
963
+ var HtmlEscapedCallbackPhase = {
964
+ Stringify: 1,
965
+ BeforeStream: 2,
966
+ Stream: 3
967
+ };
968
+ var raw = (value, callbacks) => {
969
+ const escapedString = new String(value);
970
+ escapedString.isEscaped = true;
971
+ escapedString.callbacks = callbacks;
972
+ return escapedString;
973
+ };
974
+ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
975
+ if (typeof str === "object" && !(str instanceof String)) {
976
+ if (!(str instanceof Promise)) str = str.toString();
977
+ if (str instanceof Promise) str = await str;
978
+ }
979
+ const callbacks = str.callbacks;
980
+ if (!callbacks?.length) return Promise.resolve(str);
981
+ if (buffer) buffer[0] += str;
982
+ else buffer = [str];
983
+ const resStr = Promise.all(callbacks.map((c) => c({
984
+ phase,
985
+ buffer,
986
+ context
987
+ }))).then((res) => Promise.all(res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false, context, buffer))).then(() => buffer[0]));
988
+ if (preserveCallbacks) return raw(await resStr, callbacks);
989
+ else return resStr;
990
+ };
991
+
992
+ // ../../node_modules/hono/dist/context.js
993
+ var TEXT_PLAIN = "text/plain; charset=UTF-8";
994
+ var setDefaultContentType = (contentType, headers) => {
995
+ return {
996
+ "Content-Type": contentType,
997
+ ...headers
998
+ };
999
+ };
1000
+ var createResponseInstance = (body, init) => new Response(body, init);
1001
+ var Context = class {
1002
+ #rawRequest;
1003
+ #req;
1004
+ /**
1005
+ * `.env` can get bindings (environment variables, secrets, KV namespaces, D1 database, R2 bucket etc.) in Cloudflare Workers.
1006
+ *
1007
+ * @see {@link https://hono.dev/docs/api/context#env}
1008
+ *
1009
+ * @example
1010
+ * ```ts
1011
+ * // Environment object for Cloudflare Workers
1012
+ * app.get('*', async c => {
1013
+ * const counter = c.env.COUNTER
1014
+ * })
1015
+ * ```
1016
+ */
1017
+ env = {};
1018
+ #var;
1019
+ finalized = false;
1020
+ /**
1021
+ * `.error` can get the error object from the middleware if the Handler throws an error.
1022
+ *
1023
+ * @see {@link https://hono.dev/docs/api/context#error}
1024
+ *
1025
+ * @example
1026
+ * ```ts
1027
+ * app.use('*', async (c, next) => {
1028
+ * await next()
1029
+ * if (c.error) {
1030
+ * // do something...
1031
+ * }
1032
+ * })
1033
+ * ```
1034
+ */
1035
+ error;
1036
+ #status;
1037
+ #executionCtx;
1038
+ #res;
1039
+ #layout;
1040
+ #renderer;
1041
+ #notFoundHandler;
1042
+ #preparedHeaders;
1043
+ #matchResult;
1044
+ #path;
1045
+ /**
1046
+ * Creates an instance of the Context class.
1047
+ *
1048
+ * @param req - The Request object.
1049
+ * @param options - Optional configuration options for the context.
1050
+ */
1051
+ constructor(req, options) {
1052
+ this.#rawRequest = req;
1053
+ if (options) {
1054
+ this.#executionCtx = options.executionCtx;
1055
+ this.env = options.env;
1056
+ this.#notFoundHandler = options.notFoundHandler;
1057
+ this.#path = options.path;
1058
+ this.#matchResult = options.matchResult;
1059
+ }
1060
+ }
1061
+ /**
1062
+ * `.req` is the instance of {@link HonoRequest}.
1063
+ */
1064
+ get req() {
1065
+ this.#req ??= new HonoRequest(this.#rawRequest, this.#path, this.#matchResult);
1066
+ return this.#req;
1067
+ }
1068
+ /**
1069
+ * @see {@link https://hono.dev/docs/api/context#event}
1070
+ * The FetchEvent associated with the current request.
1071
+ *
1072
+ * @throws Will throw an error if the context does not have a FetchEvent.
1073
+ */
1074
+ get event() {
1075
+ if (this.#executionCtx && "respondWith" in this.#executionCtx) return this.#executionCtx;
1076
+ else throw Error("This context has no FetchEvent");
1077
+ }
1078
+ /**
1079
+ * @see {@link https://hono.dev/docs/api/context#executionctx}
1080
+ * The ExecutionContext associated with the current request.
1081
+ *
1082
+ * @throws Will throw an error if the context does not have an ExecutionContext.
1083
+ */
1084
+ get executionCtx() {
1085
+ if (this.#executionCtx) return this.#executionCtx;
1086
+ else throw Error("This context has no ExecutionContext");
1087
+ }
1088
+ /**
1089
+ * @see {@link https://hono.dev/docs/api/context#res}
1090
+ * The Response object for the current request.
1091
+ */
1092
+ get res() {
1093
+ return this.#res ||= createResponseInstance(null, { headers: this.#preparedHeaders ??= new Headers() });
1094
+ }
1095
+ /**
1096
+ * Sets the Response object for the current request.
1097
+ *
1098
+ * @param _res - The Response object to set.
1099
+ */
1100
+ set res(_res) {
1101
+ if (this.#res && _res) {
1102
+ _res = createResponseInstance(_res.body, _res);
1103
+ for (const [k, v] of this.#res.headers.entries()) {
1104
+ if (k === "content-type") continue;
1105
+ if (k === "set-cookie") {
1106
+ const cookies = this.#res.headers.getSetCookie();
1107
+ _res.headers.delete("set-cookie");
1108
+ for (const cookie of cookies) _res.headers.append("set-cookie", cookie);
1109
+ } else _res.headers.set(k, v);
1110
+ }
1111
+ }
1112
+ this.#res = _res;
1113
+ this.finalized = true;
1114
+ }
1115
+ /**
1116
+ * `.render()` can create a response within a layout.
1117
+ *
1118
+ * @see {@link https://hono.dev/docs/api/context#render-setrenderer}
1119
+ *
1120
+ * @example
1121
+ * ```ts
1122
+ * app.get('/', (c) => {
1123
+ * return c.render('Hello!')
1124
+ * })
1125
+ * ```
1126
+ */
1127
+ render = (...args) => {
1128
+ this.#renderer ??= (content) => this.html(content);
1129
+ return this.#renderer(...args);
1130
+ };
1131
+ /**
1132
+ * Sets the layout for the response.
1133
+ *
1134
+ * @param layout - The layout to set.
1135
+ * @returns The layout function.
1136
+ */
1137
+ setLayout = (layout) => this.#layout = layout;
1138
+ /**
1139
+ * Gets the current layout for the response.
1140
+ *
1141
+ * @returns The current layout function.
1142
+ */
1143
+ getLayout = () => this.#layout;
1144
+ /**
1145
+ * `.setRenderer()` can set the layout in the custom middleware.
1146
+ *
1147
+ * @see {@link https://hono.dev/docs/api/context#render-setrenderer}
1148
+ *
1149
+ * @example
1150
+ * ```tsx
1151
+ * app.use('*', async (c, next) => {
1152
+ * c.setRenderer((content) => {
1153
+ * return c.html(
1154
+ * <html>
1155
+ * <body>
1156
+ * <p>{content}</p>
1157
+ * </body>
1158
+ * </html>
1159
+ * )
1160
+ * })
1161
+ * await next()
1162
+ * })
1163
+ * ```
1164
+ */
1165
+ setRenderer = (renderer) => {
1166
+ this.#renderer = renderer;
1167
+ };
1168
+ /**
1169
+ * `.header()` can set headers.
1170
+ *
1171
+ * @see {@link https://hono.dev/docs/api/context#header}
1172
+ *
1173
+ * @example
1174
+ * ```ts
1175
+ * app.get('/welcome', (c) => {
1176
+ * // Set headers
1177
+ * c.header('X-Message', 'Hello!')
1178
+ * c.header('Content-Type', 'text/plain')
1179
+ *
1180
+ * // Append multiple headers using the append option (e.g. Vary)
1181
+ * c.header('Vary', 'Accept-Encoding', { append: true })
1182
+ * c.header('Vary', 'User-Agent', { append: true })
1183
+ *
1184
+ * return c.body('Thank you for coming')
1185
+ * })
1186
+ * ```
1187
+ */
1188
+ header = (name, value, options) => {
1189
+ if (this.finalized) this.#res = createResponseInstance(this.#res.body, this.#res);
1190
+ const headers = this.#res ? this.#res.headers : this.#preparedHeaders ??= new Headers();
1191
+ if (value === void 0) headers.delete(name);
1192
+ else if (options?.append) headers.append(name, value);
1193
+ else headers.set(name, value);
1194
+ };
1195
+ status = (status) => {
1196
+ this.#status = status;
1197
+ };
1198
+ /**
1199
+ * `.set()` can set the value specified by the key.
1200
+ *
1201
+ * @see {@link https://hono.dev/docs/api/context#set-get}
1202
+ *
1203
+ * @example
1204
+ * ```ts
1205
+ * app.use('*', async (c, next) => {
1206
+ * c.set('message', 'Hono is hot!!')
1207
+ * await next()
1208
+ * })
1209
+ * ```
1210
+ */
1211
+ set = (key, value) => {
1212
+ this.#var ??= /* @__PURE__ */ new Map();
1213
+ this.#var.set(key, value);
1214
+ };
1215
+ /**
1216
+ * `.get()` can use the value specified by the key.
1217
+ *
1218
+ * @see {@link https://hono.dev/docs/api/context#set-get}
1219
+ *
1220
+ * @example
1221
+ * ```ts
1222
+ * app.get('/', (c) => {
1223
+ * const message = c.get('message')
1224
+ * return c.text(`The message is "${message}"`)
1225
+ * })
1226
+ * ```
1227
+ */
1228
+ get = (key) => {
1229
+ return this.#var ? this.#var.get(key) : void 0;
1230
+ };
1231
+ /**
1232
+ * `.var` can access the value of a variable.
1233
+ *
1234
+ * @see {@link https://hono.dev/docs/api/context#var}
1235
+ *
1236
+ * @example
1237
+ * ```ts
1238
+ * const result = c.var.client.oneMethod()
1239
+ * ```
1240
+ */
1241
+ get var() {
1242
+ if (!this.#var) return {};
1243
+ return Object.fromEntries(this.#var);
1244
+ }
1245
+ #newResponse(data, arg, headers) {
1246
+ let responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders;
1247
+ if (typeof arg === "object" && arg.headers) {
1248
+ responseHeaders ??= new Headers();
1249
+ for (const [key, value] of new Headers(arg.headers)) if (key === "set-cookie") responseHeaders.append(key, value);
1250
+ else responseHeaders.set(key, value);
1251
+ }
1252
+ if (headers) {
1253
+ if (!responseHeaders) {
1254
+ let count = 0;
1255
+ for (const k in headers) if (++count > 1 || typeof headers[k] !== "string") {
1256
+ responseHeaders = new Headers();
1257
+ break;
1258
+ }
1259
+ }
1260
+ if (responseHeaders) for (const k in headers) {
1261
+ const v = headers[k];
1262
+ if (typeof v === "string") responseHeaders.set(k, v);
1263
+ else {
1264
+ responseHeaders.delete(k);
1265
+ for (const v2 of v) responseHeaders.append(k, v2);
1266
+ }
1267
+ }
1268
+ }
1269
+ const status = typeof arg === "number" ? arg : arg?.status ?? this.#status;
1270
+ return createResponseInstance(data, {
1271
+ status,
1272
+ headers: responseHeaders ?? headers
1273
+ });
1274
+ }
1275
+ newResponse = (...args) => this.#newResponse(...args);
1276
+ /**
1277
+ * `.body()` can return the HTTP response.
1278
+ * You can set headers with `.header()` and set HTTP status code with `.status`.
1279
+ * This can also be set in `.text()`, `.json()` and so on.
1280
+ *
1281
+ * @see {@link https://hono.dev/docs/api/context#body}
1282
+ *
1283
+ * @example
1284
+ * ```ts
1285
+ * app.get('/welcome', (c) => {
1286
+ * // Set headers
1287
+ * c.header('X-Message', 'Hello!')
1288
+ * c.header('Content-Type', 'text/plain')
1289
+ * // Set HTTP status code
1290
+ * c.status(201)
1291
+ *
1292
+ * // Return the response body
1293
+ * return c.body('Thank you for coming')
1294
+ * })
1295
+ * ```
1296
+ */
1297
+ body = (data, arg, headers) => this.#newResponse(data, arg, headers);
1298
+ /**
1299
+ * `.text()` can render text as `Content-Type:text/plain`.
1300
+ *
1301
+ * @see {@link https://hono.dev/docs/api/context#text}
1302
+ *
1303
+ * @example
1304
+ * ```ts
1305
+ * app.get('/say', (c) => {
1306
+ * return c.text('Hello!')
1307
+ * })
1308
+ * ```
1309
+ */
1310
+ text = (text, arg, headers) => {
1311
+ return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized ? new Response(text) : this.#newResponse(text, arg, setDefaultContentType(TEXT_PLAIN, headers));
1312
+ };
1313
+ /**
1314
+ * `.json()` can render JSON as `Content-Type:application/json`.
1315
+ *
1316
+ * @see {@link https://hono.dev/docs/api/context#json}
1317
+ *
1318
+ * @example
1319
+ * ```ts
1320
+ * app.get('/api', (c) => {
1321
+ * return c.json({ message: 'Hello!' })
1322
+ * })
1323
+ * ```
1324
+ */
1325
+ json = (object, arg, headers) => {
1326
+ return this.#newResponse(JSON.stringify(object), arg, setDefaultContentType("application/json", headers));
1327
+ };
1328
+ html = (html, arg, headers) => {
1329
+ const res = (html2) => this.#newResponse(html2, arg, setDefaultContentType("text/html; charset=UTF-8", headers));
1330
+ return typeof html === "object" ? resolveCallback(html, HtmlEscapedCallbackPhase.Stringify, false, {}).then(res) : res(html);
1331
+ };
1332
+ /**
1333
+ * `.redirect()` can Redirect, default status code is 302.
1334
+ *
1335
+ * @see {@link https://hono.dev/docs/api/context#redirect}
1336
+ *
1337
+ * @example
1338
+ * ```ts
1339
+ * app.get('/redirect', (c) => {
1340
+ * return c.redirect('/')
1341
+ * })
1342
+ * app.get('/redirect-permanently', (c) => {
1343
+ * return c.redirect('/', 301)
1344
+ * })
1345
+ * ```
1346
+ */
1347
+ redirect = (location, status) => {
1348
+ const locationString = String(location);
1349
+ this.header("Location", !/[^\x00-\xFF]/.test(locationString) ? locationString : encodeURI(locationString));
1350
+ return this.newResponse(null, status ?? 302);
1351
+ };
1352
+ /**
1353
+ * `.notFound()` can return the Not Found Response.
1354
+ *
1355
+ * @see {@link https://hono.dev/docs/api/context#notfound}
1356
+ *
1357
+ * @example
1358
+ * ```ts
1359
+ * app.get('/notfound', (c) => {
1360
+ * return c.notFound()
1361
+ * })
1362
+ * ```
1363
+ */
1364
+ notFound = () => {
1365
+ this.#notFoundHandler ??= () => createResponseInstance();
1366
+ return this.#notFoundHandler(this);
1367
+ };
1368
+ };
1369
+
1370
+ // ../../node_modules/hono/dist/compose.js
1371
+ var compose = (middleware, onError, onNotFound) => {
1372
+ return (context, next) => {
1373
+ let index = -1;
1374
+ return dispatch(0);
1375
+ async function dispatch(i) {
1376
+ if (i <= index) throw new Error("next() called multiple times");
1377
+ index = i;
1378
+ let res;
1379
+ let isError = false;
1380
+ let handler2;
1381
+ if (middleware[i]) {
1382
+ handler2 = middleware[i][0][0];
1383
+ context.req.routeIndex = i;
1384
+ } else handler2 = i === middleware.length && next || void 0;
1385
+ if (handler2) try {
1386
+ res = await handler2(context, () => dispatch(i + 1));
1387
+ } catch (err) {
1388
+ if (err instanceof Error && onError) {
1389
+ context.error = err;
1390
+ res = await onError(err, context);
1391
+ isError = true;
1392
+ } else throw err;
1393
+ }
1394
+ else if (context.finalized === false && onNotFound) res = await onNotFound(context);
1395
+ if (res && (context.finalized === false || isError)) context.res = res;
1396
+ return context;
1397
+ }
1398
+ };
1399
+ };
1400
+
1401
+ // ../../node_modules/hono/dist/router.js
1402
+ var METHODS = [
1403
+ "get",
1404
+ "post",
1405
+ "put",
1406
+ "delete",
1407
+ "options",
1408
+ "patch",
1409
+ "query"
1410
+ ];
1411
+ var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built.";
1412
+ var UnsupportedPathError = class extends Error {
1413
+ };
1414
+
1415
+ // ../../node_modules/hono/dist/utils/constants.js
1416
+ var COMPOSED_HANDLER = "__COMPOSED_HANDLER";
1417
+
1418
+ // ../../node_modules/hono/dist/hono-base.js
1419
+ var notFoundHandler = (c) => {
1420
+ return c.text("404 Not Found", 404);
1421
+ };
1422
+ var errorHandler = (err, c) => {
1423
+ if ("getResponse" in err) {
1424
+ const res = err.getResponse();
1425
+ return c.newResponse(res.body, res);
1426
+ }
1427
+ console.error(err);
1428
+ return c.text("Internal Server Error", 500);
1429
+ };
1430
+ var Hono = class Hono2 {
1431
+ get;
1432
+ post;
1433
+ put;
1434
+ delete;
1435
+ options;
1436
+ patch;
1437
+ query;
1438
+ all;
1439
+ on;
1440
+ use;
1441
+ router;
1442
+ getPath;
1443
+ _basePath = "/";
1444
+ #path = "/";
1445
+ routes = [];
1446
+ constructor(options = {}) {
1447
+ [...METHODS, "all"].forEach((method) => {
1448
+ this[method] = (args1, ...args) => {
1449
+ const methodName = method.toUpperCase();
1450
+ if (typeof args1 === "string") this.#path = args1;
1451
+ else this.#addRoute(methodName, this.#path, args1);
1452
+ args.forEach((handler2) => {
1453
+ this.#addRoute(methodName, this.#path, handler2);
1454
+ });
1455
+ return this;
1456
+ };
1457
+ });
1458
+ this.on = (method, path, ...handlers) => {
1459
+ for (const p of [path].flat()) {
1460
+ this.#path = p;
1461
+ for (const m of [method].flat()) {
1462
+ const methodName = m.toUpperCase();
1463
+ for (const handler2 of handlers) this.#addRoute(methodName, this.#path, handler2);
1464
+ }
1465
+ }
1466
+ return this;
1467
+ };
1468
+ this.use = (arg1, ...handlers) => {
1469
+ if (typeof arg1 === "string") this.#path = arg1;
1470
+ else {
1471
+ this.#path = "*";
1472
+ handlers.unshift(arg1);
1473
+ }
1474
+ handlers.forEach((handler2) => {
1475
+ this.#addRoute("ALL", this.#path, handler2);
1476
+ });
1477
+ return this;
1478
+ };
1479
+ const { strict, ...optionsWithoutStrict } = options;
1480
+ Object.assign(this, optionsWithoutStrict);
1481
+ this.getPath = strict ?? true ? options.getPath ?? getPath : getPathNoStrict;
1482
+ }
1483
+ #clone() {
1484
+ const clone = new Hono2({
1485
+ router: this.router,
1486
+ getPath: this.getPath
1487
+ });
1488
+ clone.errorHandler = this.errorHandler;
1489
+ clone.#notFoundHandler = this.#notFoundHandler;
1490
+ clone.routes = this.routes;
1491
+ return clone;
1492
+ }
1493
+ #notFoundHandler = notFoundHandler;
1494
+ errorHandler = errorHandler;
1495
+ /**
1496
+ * `.route()` allows grouping other Hono instance in routes.
1497
+ *
1498
+ * @see {@link https://hono.dev/docs/api/routing#grouping}
1499
+ *
1500
+ * @param {string} path - base Path
1501
+ * @param {Hono} app - other Hono instance
1502
+ * @returns {Hono} routed Hono instance
1503
+ *
1504
+ * @example
1505
+ * ```ts
1506
+ * const app = new Hono()
1507
+ * const app2 = new Hono()
1508
+ *
1509
+ * app2.get("/user", (c) => c.text("user"))
1510
+ * app.route("/api", app2) // GET /api/user
1511
+ * ```
1512
+ */
1513
+ route(path, app) {
1514
+ const subApp = this.basePath(path);
1515
+ app.routes.map((r) => {
1516
+ let handler2;
1517
+ if (app.errorHandler === errorHandler) handler2 = r.handler;
1518
+ else {
1519
+ handler2 = async (c, next) => (await compose([], app.errorHandler)(c, () => r.handler(c, next))).res;
1520
+ handler2[COMPOSED_HANDLER] = r.handler;
1521
+ }
1522
+ subApp.#addRoute(r.method, r.path, handler2, r.basePath);
1523
+ });
1524
+ return this;
1525
+ }
1526
+ /**
1527
+ * `.basePath()` allows base paths to be specified.
1528
+ *
1529
+ * @see {@link https://hono.dev/docs/api/routing#base-path}
1530
+ *
1531
+ * @param {string} path - base Path
1532
+ * @returns {Hono} changed Hono instance
1533
+ *
1534
+ * @example
1535
+ * ```ts
1536
+ * const api = new Hono().basePath('/api')
1537
+ * ```
1538
+ */
1539
+ basePath(path) {
1540
+ const subApp = this.#clone();
1541
+ subApp._basePath = mergePath(this._basePath, path);
1542
+ return subApp;
1543
+ }
1544
+ /**
1545
+ * `.onError()` handles an error and returns a customized Response.
1546
+ *
1547
+ * @see {@link https://hono.dev/docs/api/hono#error-handling}
1548
+ *
1549
+ * @param {ErrorHandler} handler - request Handler for error
1550
+ * @returns {Hono} changed Hono instance
1551
+ *
1552
+ * @example
1553
+ * ```ts
1554
+ * app.onError((err, c) => {
1555
+ * console.error(`${err}`)
1556
+ * return c.text('Custom Error Message', 500)
1557
+ * })
1558
+ * ```
1559
+ */
1560
+ onError = (handler2) => {
1561
+ this.errorHandler = handler2;
1562
+ return this;
1563
+ };
1564
+ /**
1565
+ * `.notFound()` allows you to customize a Not Found Response.
1566
+ *
1567
+ * @see {@link https://hono.dev/docs/api/hono#not-found}
1568
+ *
1569
+ * @param {NotFoundHandler} handler - request handler for not-found
1570
+ * @returns {Hono} changed Hono instance
1571
+ *
1572
+ * @example
1573
+ * ```ts
1574
+ * app.notFound((c) => {
1575
+ * return c.text('Custom 404 Message', 404)
1576
+ * })
1577
+ * ```
1578
+ */
1579
+ notFound = (handler2) => {
1580
+ this.#notFoundHandler = handler2;
1581
+ return this;
1582
+ };
1583
+ /**
1584
+ * `.mount()` allows you to mount applications built with other frameworks into your Hono application.
1585
+ *
1586
+ * @see {@link https://hono.dev/docs/api/hono#mount}
1587
+ *
1588
+ * @param {string} path - base Path
1589
+ * @param {Function} applicationHandler - other Request Handler
1590
+ * @param {MountOptions} [options] - options of `.mount()`
1591
+ * @returns {Hono} mounted Hono instance
1592
+ *
1593
+ * @example
1594
+ * ```ts
1595
+ * import { Router as IttyRouter } from 'itty-router'
1596
+ * import { Hono } from 'hono'
1597
+ * // Create itty-router application
1598
+ * const ittyRouter = IttyRouter()
1599
+ * // GET /itty-router/hello
1600
+ * ittyRouter.get('/hello', () => new Response('Hello from itty-router'))
1601
+ *
1602
+ * const app = new Hono()
1603
+ * app.mount('/itty-router', ittyRouter.handle)
1604
+ * ```
1605
+ *
1606
+ * @example
1607
+ * ```ts
1608
+ * const app = new Hono()
1609
+ * // Send the request to another application without modification.
1610
+ * app.mount('/app', anotherApp, {
1611
+ * replaceRequest: (req) => req,
1612
+ * })
1613
+ * ```
1614
+ */
1615
+ mount(path, applicationHandler, options) {
1616
+ let replaceRequest;
1617
+ let optionHandler;
1618
+ if (options) {
1619
+ if (typeof options === "function") optionHandler = options;
1620
+ else {
1621
+ optionHandler = options.optionHandler;
1622
+ if (options.replaceRequest === false) replaceRequest = (request) => request;
1623
+ else replaceRequest = options.replaceRequest;
1624
+ }
1625
+ }
1626
+ const getOptions = optionHandler ? (c) => {
1627
+ const options2 = optionHandler(c);
1628
+ return Array.isArray(options2) ? options2 : [options2];
1629
+ } : (c) => {
1630
+ let executionContext = void 0;
1631
+ try {
1632
+ executionContext = c.executionCtx;
1633
+ } catch {
1634
+ }
1635
+ return [c.env, executionContext];
1636
+ };
1637
+ replaceRequest ||= (() => {
1638
+ const mergedPath = mergePath(this._basePath, path);
1639
+ const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length;
1640
+ return (request) => {
1641
+ const url = new URL(request.url);
1642
+ url.pathname = this.getPath(request).slice(pathPrefixLength) || "/";
1643
+ return new Request(url, request);
1644
+ };
1645
+ })();
1646
+ const handler2 = async (c, next) => {
1647
+ const res = await applicationHandler(replaceRequest(c.req.raw), ...getOptions(c));
1648
+ if (res) return res;
1649
+ await next();
1650
+ };
1651
+ this.#addRoute("ALL", mergePath(path, "*"), handler2);
1652
+ return this;
1653
+ }
1654
+ #addRoute(method, path, handler2, baseRoutePath) {
1655
+ path = mergePath(this._basePath, path);
1656
+ const r = {
1657
+ basePath: baseRoutePath !== void 0 ? mergePath(this._basePath, baseRoutePath) : this._basePath,
1658
+ path,
1659
+ method,
1660
+ handler: handler2
1661
+ };
1662
+ this.router.add(method, path, [handler2, r]);
1663
+ this.routes.push(r);
1664
+ }
1665
+ #handleError(err, c) {
1666
+ if (err instanceof Error) return this.errorHandler(err, c);
1667
+ throw err;
1668
+ }
1669
+ #dispatch(request, executionCtx, env, method) {
1670
+ if (method === "HEAD") return (async () => new Response(null, await this.#dispatch(request, executionCtx, env, "GET")))();
1671
+ const path = this.getPath(request, { env });
1672
+ const matchResult = this.router.match(method, path);
1673
+ const c = new Context(request, {
1674
+ path,
1675
+ matchResult,
1676
+ env,
1677
+ executionCtx,
1678
+ notFoundHandler: this.#notFoundHandler
1679
+ });
1680
+ if (matchResult[0].length === 1) {
1681
+ let res;
1682
+ try {
1683
+ res = matchResult[0][0][0][0](c, async () => {
1684
+ c.res = await this.#notFoundHandler(c);
1685
+ });
1686
+ } catch (err) {
1687
+ return this.#handleError(err, c);
1688
+ }
1689
+ 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);
1690
+ }
1691
+ const composed = compose(matchResult[0], this.errorHandler, this.#notFoundHandler);
1692
+ return (async () => {
1693
+ try {
1694
+ const context = await composed(c);
1695
+ if (!context.finalized) throw new Error("Context is not finalized. Did you forget to return a Response object or `await next()`?");
1696
+ return context.res;
1697
+ } catch (err) {
1698
+ return this.#handleError(err, c);
1699
+ }
1700
+ })();
1701
+ }
1702
+ /**
1703
+ * `.fetch()` will be entry point of your app.
1704
+ *
1705
+ * @see {@link https://hono.dev/docs/api/hono#fetch}
1706
+ *
1707
+ * @param {Request} request - request Object of request
1708
+ * @param {Env} env - env Object
1709
+ * @param {ExecutionContext} executionCtx - context of execution
1710
+ * @returns {Response | Promise<Response>} response of request
1711
+ *
1712
+ */
1713
+ fetch = (request, ...rest) => {
1714
+ return this.#dispatch(request, rest[1], rest[0], request.method);
1715
+ };
1716
+ /**
1717
+ * `.request()` is a useful method for testing.
1718
+ * You can pass a URL or pathname to send a GET request.
1719
+ * app will return a Response object.
1720
+ * ```ts
1721
+ * test('GET /hello is ok', async () => {
1722
+ * const res = await app.request('/hello')
1723
+ * expect(res.status).toBe(200)
1724
+ * })
1725
+ * ```
1726
+ * @see https://hono.dev/docs/api/hono#request
1727
+ */
1728
+ request = (input, requestInit, Env, executionCtx) => {
1729
+ if (input instanceof Request) return this.fetch(requestInit ? new Request(input, requestInit) : input, Env, executionCtx);
1730
+ input = input.toString();
1731
+ return this.fetch(new Request(/^https?:\/\//.test(input) ? input : `http://localhost${mergePath("/", input)}`, requestInit), Env, executionCtx);
1732
+ };
1733
+ /**
1734
+ * `.fire()` automatically adds a global fetch event listener.
1735
+ * This can be useful for environments that adhere to the Service Worker API, such as non-ES module Cloudflare Workers.
1736
+ * @deprecated
1737
+ * Use `fire` from `hono/service-worker` instead.
1738
+ * ```ts
1739
+ * import { Hono } from 'hono'
1740
+ * import { fire } from 'hono/service-worker'
1741
+ *
1742
+ * const app = new Hono()
1743
+ * // ...
1744
+ * fire(app)
1745
+ * ```
1746
+ * @see https://hono.dev/docs/api/hono#fire
1747
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API
1748
+ * @see https://developers.cloudflare.com/workers/reference/migrate-to-module-workers/
1749
+ */
1750
+ fire = () => {
1751
+ addEventListener("fetch", (event) => {
1752
+ event.respondWith(this.#dispatch(event.request, event, void 0, event.request.method));
1753
+ });
1754
+ };
1755
+ };
1756
+
1757
+ // ../../node_modules/hono/dist/router/utils.js
1758
+ var createNullObject = () => /* @__PURE__ */ Object.create(null);
1759
+
1760
+ // ../../node_modules/hono/dist/router/reg-exp-router/matcher.js
1761
+ var emptyParam = [];
1762
+ function match(method, path) {
1763
+ const matchers = this.buildAllMatchers();
1764
+ const match2 = ((method2, path2) => {
1765
+ const matcher = matchers[method2] || matchers["ALL"];
1766
+ const staticMatch = matcher[2][path2];
1767
+ if (staticMatch) return staticMatch;
1768
+ const match3 = path2.match(matcher[0]);
1769
+ if (!match3) return [[], emptyParam];
1770
+ const index = match3.indexOf("", 1);
1771
+ return [matcher[1][index], match3];
1772
+ });
1773
+ this.match = match2;
1774
+ return match2(method, path);
1775
+ }
1776
+
1777
+ // ../../node_modules/hono/dist/router/reg-exp-router/node.js
1778
+ var LABEL_REG_EXP_STR = "[^/]+";
1779
+ var TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)";
1780
+ var PATH_ERROR = /* @__PURE__ */ Symbol();
1781
+ var regExpMetaChars = /* @__PURE__ */ new Set(".\\+*[^]$()");
1782
+ function compareKey(a, b) {
1783
+ if (a.length === 1) return b.length === 1 ? a < b ? -1 : 1 : -1;
1784
+ if (b.length === 1) return 1;
1785
+ if (a === ".*" || a === "(?:|/.*)") return b === "(?:|/.*)" ? -1 : 1;
1786
+ else if (b === ".*" || b === "(?:|/.*)") return -1;
1787
+ if (a === "[^/]+") return 1;
1788
+ else if (b === "[^/]+") return -1;
1789
+ return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length;
1790
+ }
1791
+ var Node = class Node2 {
1792
+ #index;
1793
+ #varIndex;
1794
+ #children = createNullObject();
1795
+ insert(tokens, index, paramMap, context, isStatic) {
1796
+ let node = this;
1797
+ for (let i = 0, len = tokens.length; i < len; i++) {
1798
+ const token = tokens[i];
1799
+ const pattern = token.length === 1 ? token === "*" ? i === len - 1 ? [
1800
+ "",
1801
+ "",
1802
+ ".*"
1803
+ ] : [
1804
+ "",
1805
+ "",
1806
+ LABEL_REG_EXP_STR
1807
+ ] : null : token === "/*" ? [
1808
+ "",
1809
+ "",
1810
+ TAIL_WILDCARD_REG_EXP_STR
1811
+ ] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
1812
+ let nextNode;
1813
+ if (pattern) {
1814
+ const name = pattern[1];
1815
+ let regexpStr = pattern[2] || "[^/]+";
1816
+ if (name && pattern[2]) {
1817
+ if (regexpStr === ".*") throw PATH_ERROR;
1818
+ regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
1819
+ if (/\((?!\?:)/.test(regexpStr)) throw PATH_ERROR;
1820
+ if (regexpStr.length === 1 && regExpMetaChars.has(regexpStr)) throw PATH_ERROR;
1821
+ }
1822
+ nextNode = node.#children[regexpStr];
1823
+ if (!nextNode) {
1824
+ if (regexpStr !== ".*" && regexpStr !== "(?:|/.*)") {
1825
+ for (const k in node.#children) if ((regexpStr.length > 1 || k.length > 1) && k !== ".*" && k !== "(?:|/.*)") throw PATH_ERROR;
1826
+ }
1827
+ nextNode = node.#children[regexpStr] = new Node2();
1828
+ }
1829
+ if (name !== "") {
1830
+ nextNode.#varIndex ??= context.varIndex++;
1831
+ paramMap.push([name, nextNode.#varIndex]);
1832
+ }
1833
+ } else {
1834
+ nextNode = node.#children[token];
1835
+ if (!nextNode) {
1836
+ for (const k in node.#children) if (k.length > 1 && k !== ".*" && k !== "(?:|/.*)") throw PATH_ERROR;
1837
+ nextNode = node.#children[token] = new Node2();
1838
+ }
1839
+ }
1840
+ node = nextNode;
1841
+ }
1842
+ if (node.#index !== void 0) throw PATH_ERROR;
1843
+ node.#index = isStatic ? -1 : index;
1844
+ }
1845
+ buildRegExpStr() {
1846
+ const strList = Object.keys(this.#children).sort(compareKey).map((k) => {
1847
+ const c = this.#children[k];
1848
+ const childStr = c.buildRegExpStr();
1849
+ return childStr === "" ? "" : (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + childStr;
1850
+ }).filter(Boolean);
1851
+ if (typeof this.#index === "number" && this.#index !== -1) strList.unshift(`#${this.#index}`);
1852
+ if (strList.length === 0) return "";
1853
+ if (strList.length === 1) return strList[0];
1854
+ return "(?:" + strList.join("|") + ")";
1855
+ }
1856
+ };
1857
+
1858
+ // ../../node_modules/hono/dist/router/reg-exp-router/trie.js
1859
+ var Trie = class {
1860
+ #context = { varIndex: 0 };
1861
+ #root = new Node();
1862
+ #index = 0;
1863
+ paths = createNullObject();
1864
+ insert(path, isStatic) {
1865
+ if (isStatic) {
1866
+ this.#root.insert(path.split(""), 0, [], this.#context, true);
1867
+ return;
1868
+ }
1869
+ const paramAssoc = [];
1870
+ const groups = [];
1871
+ let markedPath = path;
1872
+ for (let i = 0; ; ) {
1873
+ let replaced = false;
1874
+ markedPath = markedPath.replace(/\{[^}]+\}/g, (m) => {
1875
+ const mark = `@\\${i}`;
1876
+ groups[i] = [mark, m];
1877
+ i++;
1878
+ replaced = true;
1879
+ return mark;
1880
+ });
1881
+ if (!replaced) break;
1882
+ }
1883
+ const tokens = markedPath.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
1884
+ for (let i = groups.length - 1; i >= 0; i--) {
1885
+ const [mark] = groups[i];
1886
+ for (let j = tokens.length - 1; j >= 0; j--) if (tokens[j].indexOf(mark) !== -1) {
1887
+ tokens[j] = tokens[j].replace(mark, groups[i][1]);
1888
+ break;
1889
+ }
1890
+ }
1891
+ this.#root.insert(tokens, this.#index, paramAssoc, this.#context, false);
1892
+ this.paths[path] = [this.#index++, paramAssoc];
1893
+ }
1894
+ buildRegExp() {
1895
+ let regexp = this.#root.buildRegExpStr();
1896
+ if (regexp === "") return [
1897
+ /^$/,
1898
+ [],
1899
+ []
1900
+ ];
1901
+ let captureIndex = 0;
1902
+ const indexReplacementMap = [];
1903
+ const paramReplacementMap = [];
1904
+ regexp = regexp.replace(/#(\d+)|@(\d+)|\.\*\$/g, (_, handlerIndex, paramIndex) => {
1905
+ if (handlerIndex !== void 0) {
1906
+ indexReplacementMap[++captureIndex] = Number(handlerIndex);
1907
+ return "$()";
1908
+ }
1909
+ if (paramIndex !== void 0) {
1910
+ paramReplacementMap[Number(paramIndex)] = ++captureIndex;
1911
+ return "";
1912
+ }
1913
+ return "";
1914
+ });
1915
+ return [
1916
+ new RegExp(`^${regexp}`),
1917
+ indexReplacementMap,
1918
+ paramReplacementMap
1919
+ ];
1920
+ }
1921
+ };
1922
+
1923
+ // ../../node_modules/hono/dist/router/reg-exp-router/router.js
1924
+ var wildcardRegExpCache = createNullObject();
1925
+ function buildWildcardRegExp(path) {
1926
+ return wildcardRegExpCache[path] ??= new RegExp(`^${path.replace(/\/:[^/{}]+(?:\{\[\^\/]\+})?(?=[/{]|$)|\/?\*$|([.\\+*[^\]$()?{}|])/g, (match2, metaChar) => metaChar ? `\\${metaChar}` : match2 === "/*" ? TAIL_WILDCARD_REG_EXP_STR : match2 === "*" ? ".*" : `/:${LABEL_REG_EXP_STR}`)}$`);
1927
+ }
1928
+ function findMiddleware(middleware, path) {
1929
+ for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length)) if (buildWildcardRegExp(k).test(path)) return [...middleware[k]];
1930
+ }
1931
+ var RegExpRouter = class {
1932
+ name = "RegExpRouter";
1933
+ #middleware;
1934
+ #routes;
1935
+ #tries;
1936
+ constructor() {
1937
+ this.#middleware = { ["ALL"]: createNullObject() };
1938
+ this.#routes = { ["ALL"]: createNullObject() };
1939
+ this.#tries = { ["ALL"]: new Trie() };
1940
+ }
1941
+ #insertPath(method, path) {
1942
+ try {
1943
+ this.#tries[method].insert(path, !/\*|\/:/.test(path));
1944
+ } catch (e) {
1945
+ throw e === PATH_ERROR ? new UnsupportedPathError(path) : e;
1946
+ }
1947
+ }
1948
+ add(method, path, handler2) {
1949
+ const middleware = this.#middleware;
1950
+ const routes = this.#routes;
1951
+ if (!middleware) throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
1952
+ if (!middleware[method]) {
1953
+ this.#tries[method] = new Trie();
1954
+ for (const handlerMap of [middleware, routes]) {
1955
+ handlerMap[method] = createNullObject();
1956
+ for (const p in handlerMap["ALL"]) {
1957
+ handlerMap[method][p] = [...handlerMap["ALL"][p]];
1958
+ this.#insertPath(method, p);
1959
+ }
1960
+ }
1961
+ }
1962
+ if (path === "/*") path = "*";
1963
+ const methods = method === "ALL" ? Object.keys(middleware) : [method];
1964
+ if (/\*$/.test(path)) {
1965
+ const re = buildWildcardRegExp(path);
1966
+ for (const m of methods) if (!middleware[m][path]) {
1967
+ this.#insertPath(m, path);
1968
+ middleware[m][path] = findMiddleware(middleware[m], path) || findMiddleware(middleware["ALL"], path) || [];
1969
+ }
1970
+ for (const handlerMap of [middleware, routes]) for (const m of methods) for (const p in handlerMap[m]) re.test(p) && handlerMap[m][p].push([handler2, path]);
1971
+ return;
1972
+ }
1973
+ const paths = checkOptionalParameter(path) || [path];
1974
+ for (const path2 of paths) for (const m of methods) {
1975
+ if (!routes[m][path2]) {
1976
+ this.#insertPath(m, path2);
1977
+ routes[m][path2] = findMiddleware(middleware[m], path2) || findMiddleware(middleware["ALL"], path2) || [];
1978
+ }
1979
+ routes[m][path2].push([handler2, path2]);
1980
+ }
1981
+ }
1982
+ match = match;
1983
+ buildAllMatchers() {
1984
+ const matchers = createNullObject();
1985
+ for (const method of Object.keys(this.#routes)) matchers[method] = this.#buildMatcher(method);
1986
+ this.#middleware = this.#routes = this.#tries = void 0;
1987
+ wildcardRegExpCache = createNullObject();
1988
+ return matchers;
1989
+ }
1990
+ #buildMatcher(method) {
1991
+ const middleware = this.#middleware[method];
1992
+ const routes = this.#routes[method];
1993
+ const trie = this.#tries[method];
1994
+ const staticMap = createNullObject();
1995
+ const handlerData = [];
1996
+ const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
1997
+ for (const r of [middleware, routes]) for (const path in r) {
1998
+ const handlers = r[path];
1999
+ const pathData = trie.paths[path];
2000
+ if (!pathData) {
2001
+ staticMap[path] = [handlers.map(([h]) => [h, createNullObject()]), emptyParam];
2002
+ continue;
2003
+ }
2004
+ handlerData[pathData[0]] = handlers.map(([h, handlerPath]) => [h, trie.paths[handlerPath][1].reduceRight((map, [key], i) => {
2005
+ map[key] = paramReplacementMap[pathData[1][i][1]];
2006
+ return map;
2007
+ }, createNullObject())]);
2008
+ }
2009
+ return [
2010
+ regexp,
2011
+ indexReplacementMap.map((i) => handlerData[i]),
2012
+ staticMap
2013
+ ];
2014
+ }
2015
+ };
2016
+
2017
+ // ../../node_modules/hono/dist/router/smart-router/router.js
2018
+ var SmartRouter = class {
2019
+ name = "SmartRouter";
2020
+ #routers = [];
2021
+ #routes = [];
2022
+ constructor(init) {
2023
+ this.#routers = init.routers;
2024
+ }
2025
+ add(method, path, handler2) {
2026
+ if (!this.#routes) throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
2027
+ this.#routes.push([
2028
+ method,
2029
+ path,
2030
+ handler2
2031
+ ]);
2032
+ }
2033
+ match(method, path) {
2034
+ if (!this.#routes) throw new Error("Fatal error");
2035
+ const routers = this.#routers;
2036
+ const routes = this.#routes;
2037
+ const len = routers.length;
2038
+ let i = 0;
2039
+ let res;
2040
+ for (; i < len; i++) {
2041
+ const router = routers[i];
2042
+ try {
2043
+ for (let i2 = 0, len2 = routes.length; i2 < len2; i2++) router.add(...routes[i2]);
2044
+ res = router.match(method, path);
2045
+ } catch (e) {
2046
+ if (e instanceof UnsupportedPathError) continue;
2047
+ throw e;
2048
+ }
2049
+ this.match = router.match.bind(router);
2050
+ this.#routers = [router];
2051
+ this.#routes = void 0;
2052
+ break;
2053
+ }
2054
+ if (i === len) throw new Error("Fatal error");
2055
+ this.name = `SmartRouter + ${this.activeRouter.name}`;
2056
+ return res;
2057
+ }
2058
+ get activeRouter() {
2059
+ if (this.#routes || this.#routers.length !== 1) throw new Error("No active router has been determined yet.");
2060
+ return this.#routers[0];
2061
+ }
2062
+ };
2063
+
2064
+ // ../../node_modules/hono/dist/router/trie-router/node.js
2065
+ var emptyParams = createNullObject();
2066
+ var order = 0;
2067
+ var Node3 = class Node4 {
2068
+ #methods = [];
2069
+ #children = createNullObject();
2070
+ #patterns = [];
2071
+ #pattern;
2072
+ #params = emptyParams;
2073
+ insert(method, path, handler2) {
2074
+ let curNode = this;
2075
+ const parts = splitRoutingPath(path);
2076
+ const possibleKeys = /* @__PURE__ */ new Set();
2077
+ let i = 0;
2078
+ for (const p of parts) {
2079
+ const nextP = parts[++i];
2080
+ const pattern = getPattern(p, nextP) || (nextP === void 0 && p && p.indexOf("*") === p.length - 1 ? p : null);
2081
+ const isParam = Array.isArray(pattern);
2082
+ const key = isParam ? pattern[0] : pattern || p;
2083
+ const child = curNode.#children[key] ||= new Node4();
2084
+ if (pattern && !child.#pattern) {
2085
+ child.#pattern = pattern;
2086
+ curNode.#patterns.push(child);
2087
+ }
2088
+ curNode = child;
2089
+ if (isParam) possibleKeys.add(pattern[1]);
2090
+ }
2091
+ curNode.#methods.push({ [method]: {
2092
+ handler: handler2,
2093
+ possibleKeys: [...possibleKeys],
2094
+ score: ++order
2095
+ } });
2096
+ }
2097
+ #pushHandlerSets(handlerSets, node, method, nodeParams, params) {
2098
+ for (let i = 0, len = node.#methods.length; i < len; i++) {
2099
+ const m = node.#methods[i];
2100
+ const handlerSet = m[method] || m["ALL"];
2101
+ if (handlerSet) {
2102
+ handlerSet.params = createNullObject();
2103
+ handlerSets.push(handlerSet);
2104
+ for (let i2 = 0, len2 = handlerSet.possibleKeys.length; i2 < len2; i2++) {
2105
+ const key = handlerSet.possibleKeys[i2];
2106
+ handlerSet.params[key] = params?.[key] && !i2 ? params[key] : nodeParams[key] ?? params?.[key];
2107
+ }
2108
+ }
2109
+ }
2110
+ }
2111
+ search(method, path) {
2112
+ const handlerSets = [];
2113
+ this.#params = emptyParams;
2114
+ let curNodes = [this];
2115
+ const parts = splitPath(path);
2116
+ const curNodesQueue = [];
2117
+ const len = parts.length;
2118
+ let partOffsets = null;
2119
+ for (let i = 0; i < len; i++) {
2120
+ const part = parts[i];
2121
+ const isLast = i === len - 1;
2122
+ const tempNodes = [];
2123
+ for (let j = 0, len2 = curNodes.length; j < len2; j++) {
2124
+ const node = curNodes[j];
2125
+ const nextNode = node.#children[part];
2126
+ if (nextNode) {
2127
+ nextNode.#params = node.#params;
2128
+ if (isLast) {
2129
+ if (nextNode.#children["*"]) this.#pushHandlerSets(handlerSets, nextNode.#children["*"], method, node.#params);
2130
+ this.#pushHandlerSets(handlerSets, nextNode, method, node.#params);
2131
+ } else tempNodes.push(nextNode);
2132
+ }
2133
+ for (const child of node.#patterns) {
2134
+ const pattern = child.#pattern;
2135
+ const params = node.#params === emptyParams ? {} : { ...node.#params };
2136
+ if (typeof pattern === "string") {
2137
+ if (pattern === "*" || part.startsWith(pattern.slice(0, -1))) {
2138
+ this.#pushHandlerSets(handlerSets, child, method, node.#params);
2139
+ if (pattern === "*") {
2140
+ child.#params = params;
2141
+ tempNodes.push(child);
2142
+ }
2143
+ }
2144
+ continue;
2145
+ }
2146
+ const [, name, matcher] = pattern;
2147
+ if (!part && matcher === true) continue;
2148
+ if (matcher !== true) {
2149
+ if (!partOffsets) {
2150
+ partOffsets = [];
2151
+ let offset = path[0] === "/" ? 1 : 0;
2152
+ for (let p = 0; p < len; p++) {
2153
+ partOffsets[p] = offset;
2154
+ offset += parts[p].length + 1;
2155
+ }
2156
+ }
2157
+ const restPathString = path.slice(partOffsets[i]);
2158
+ const m = matcher.exec(restPathString);
2159
+ if (m) {
2160
+ params[name] = m[0];
2161
+ this.#pushHandlerSets(handlerSets, child, method, node.#params, params);
2162
+ if (m[0].length === restPathString.length && child.#children["*"]) this.#pushHandlerSets(handlerSets, child.#children["*"], method, node.#params, params);
2163
+ for (const _ in child.#children) {
2164
+ child.#params = params;
2165
+ const componentCount = m[0].match(/\//g)?.length ?? 0;
2166
+ (curNodesQueue[componentCount] ||= []).push(child);
2167
+ break;
2168
+ }
2169
+ continue;
2170
+ }
2171
+ }
2172
+ if (matcher === true || matcher.test(part)) {
2173
+ params[name] = part;
2174
+ if (isLast) {
2175
+ this.#pushHandlerSets(handlerSets, child, method, params, node.#params);
2176
+ if (child.#children["*"]) this.#pushHandlerSets(handlerSets, child.#children["*"], method, params, node.#params);
2177
+ } else {
2178
+ child.#params = params;
2179
+ tempNodes.push(child);
2180
+ }
2181
+ }
2182
+ }
2183
+ }
2184
+ const shifted = curNodesQueue.shift();
2185
+ curNodes = shifted ? tempNodes.concat(shifted) : tempNodes;
2186
+ }
2187
+ if (handlerSets[1]) handlerSets.sort((a, b) => {
2188
+ return a.score - b.score;
2189
+ });
2190
+ return [handlerSets.map(({ handler: handler2, params }) => [handler2, params])];
2191
+ }
2192
+ };
2193
+
2194
+ // ../../node_modules/hono/dist/router/trie-router/router.js
2195
+ var TrieRouter = class {
2196
+ name = "TrieRouter";
2197
+ #node = new Node3();
2198
+ add(method, path, handler2) {
2199
+ for (const result of checkOptionalParameter(path) || [path]) this.#node.insert(method, result, handler2);
2200
+ }
2201
+ match(method, path) {
2202
+ return this.#node.search(method, path);
2203
+ }
2204
+ };
2205
+
2206
+ // ../../node_modules/hono/dist/hono.js
2207
+ var Hono3 = class extends Hono {
2208
+ /**
2209
+ * Creates an instance of the Hono class.
2210
+ *
2211
+ * @param options - Optional configuration options for the Hono instance.
2212
+ */
2213
+ constructor(options = {}) {
2214
+ super(options);
2215
+ this.router = options.router ?? new SmartRouter({ routers: [new RegExpRouter(), new TrieRouter()] });
2216
+ }
2217
+ };
2218
+
2219
+ // ../../node_modules/hono/dist/utils/cookie.js
2220
+ var validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/;
2221
+ var relaxedCookieNameRegEx = /^[!#-:<>-[\]-~]+$/;
2222
+ var validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/;
2223
+ var trimCookieWhitespace = (value) => {
2224
+ let start = 0;
2225
+ let end = value.length;
2226
+ while (start < end) {
2227
+ const charCode = value.charCodeAt(start);
2228
+ if (charCode !== 32 && charCode !== 9) break;
2229
+ start++;
2230
+ }
2231
+ while (end > start) {
2232
+ const charCode = value.charCodeAt(end - 1);
2233
+ if (charCode !== 32 && charCode !== 9) break;
2234
+ end--;
2235
+ }
2236
+ return start === 0 && end === value.length ? value : value.slice(start, end);
2237
+ };
2238
+ var parse = (cookie, name) => {
2239
+ if (name && cookie.indexOf(name) === -1) return {};
2240
+ const pairs = cookie.split(";");
2241
+ const parsedCookie = /* @__PURE__ */ Object.create(null);
2242
+ for (const pairStr of pairs) {
2243
+ const valueStartPos = pairStr.indexOf("=");
2244
+ if (valueStartPos === -1) continue;
2245
+ const cookieName = trimCookieWhitespace(pairStr.substring(0, valueStartPos));
2246
+ if (name && name !== cookieName || !relaxedCookieNameRegEx.test(cookieName) || cookieName in parsedCookie) continue;
2247
+ let cookieValue = trimCookieWhitespace(pairStr.substring(valueStartPos + 1));
2248
+ if (cookieValue.startsWith('"') && cookieValue.endsWith('"')) cookieValue = cookieValue.slice(1, -1);
2249
+ if (validCookieValueRegEx.test(cookieValue)) {
2250
+ parsedCookie[cookieName] = tryDecodeURIComponent(cookieValue);
2251
+ if (name) break;
2252
+ }
2253
+ }
2254
+ return parsedCookie;
2255
+ };
2256
+ var _serialize = (name, value, opt = {}) => {
2257
+ if (!validCookieNameRegEx.test(name)) throw new Error("Invalid cookie name");
2258
+ let cookie = `${name}=${value}`;
2259
+ if (name.startsWith("__Secure-") && !opt.secure) throw new Error("__Secure- Cookie must have Secure attributes");
2260
+ if (name.startsWith("__Host-")) {
2261
+ if (!opt.secure) throw new Error("__Host- Cookie must have Secure attributes");
2262
+ if (opt.path !== "/") throw new Error('__Host- Cookie must have Path attributes with "/"');
2263
+ if (opt.domain) throw new Error("__Host- Cookie must not have Domain attributes");
2264
+ }
2265
+ for (const key of [
2266
+ "domain",
2267
+ "path",
2268
+ "sameSite",
2269
+ "priority"
2270
+ ]) if (opt[key] && /[;\r\n]/.test(opt[key])) throw new Error(`${key} must not contain ";", "\\r", or "\\n"`);
2271
+ if (opt && typeof opt.maxAge === "number" && opt.maxAge >= 0) {
2272
+ if (opt.maxAge > 3456e4) throw new Error("Cookies Max-Age SHOULD NOT be greater than 400 days (34560000 seconds) in duration.");
2273
+ cookie += `; Max-Age=${opt.maxAge | 0}`;
2274
+ }
2275
+ if (opt.domain && opt.prefix !== "host") cookie += `; Domain=${opt.domain}`;
2276
+ if (opt.path) cookie += `; Path=${opt.path}`;
2277
+ if (opt.expires) {
2278
+ if (opt.expires.getTime() - Date.now() > 3456e7) throw new Error("Cookies Expires SHOULD NOT be greater than 400 days (34560000 seconds) in the future.");
2279
+ cookie += `; Expires=${opt.expires.toUTCString()}`;
2280
+ }
2281
+ if (opt.httpOnly) cookie += "; HttpOnly";
2282
+ if (opt.secure) cookie += "; Secure";
2283
+ if (opt.sameSite) cookie += `; SameSite=${opt.sameSite.charAt(0).toUpperCase() + opt.sameSite.slice(1)}`;
2284
+ if (opt.priority) cookie += `; Priority=${opt.priority.charAt(0).toUpperCase() + opt.priority.slice(1)}`;
2285
+ if (opt.partitioned) {
2286
+ if (!opt.secure) throw new Error("Partitioned Cookie must have Secure attributes");
2287
+ cookie += "; Partitioned";
2288
+ }
2289
+ return cookie;
2290
+ };
2291
+ var serialize = (name, value, opt) => {
2292
+ value = encodeURIComponent(value);
2293
+ return _serialize(name, value, opt);
2294
+ };
2295
+
2296
+ // ../../node_modules/hono/dist/helper/cookie/index.js
2297
+ var getCookie = (c, key, prefix) => {
2298
+ const cookie = c.req.raw.headers.get("Cookie");
2299
+ if (typeof key === "string") {
2300
+ if (!cookie) return;
2301
+ let finalKey = key;
2302
+ if (prefix === "secure") finalKey = "__Secure-" + key;
2303
+ else if (prefix === "host") finalKey = "__Host-" + key;
2304
+ return parse(cookie, finalKey)[finalKey];
2305
+ }
2306
+ if (!cookie) return {};
2307
+ return parse(cookie);
2308
+ };
2309
+ var generateCookie = (name, value, opt) => {
2310
+ let cookie;
2311
+ if (opt?.prefix === "secure") cookie = serialize("__Secure-" + name, value, {
2312
+ path: "/",
2313
+ ...opt,
2314
+ secure: true
2315
+ });
2316
+ else if (opt?.prefix === "host") cookie = serialize("__Host-" + name, value, {
2317
+ ...opt,
2318
+ path: "/",
2319
+ secure: true,
2320
+ domain: void 0
2321
+ });
2322
+ else cookie = serialize(name, value, {
2323
+ path: "/",
2324
+ ...opt
2325
+ });
2326
+ return cookie;
2327
+ };
2328
+ var setCookie = (c, name, value, opt) => {
2329
+ const cookie = generateCookie(name, value, opt);
2330
+ c.header("Set-Cookie", cookie, { append: true });
2331
+ };
2332
+ var deleteCookie = (c, name, opt) => {
2333
+ const deletedCookie = getCookie(c, name, opt?.prefix);
2334
+ setCookie(c, name, "", {
2335
+ ...opt,
2336
+ maxAge: 0
2337
+ });
2338
+ return deletedCookie;
2339
+ };
2340
+
2341
+ // ../../node_modules/hono/dist/middleware/cors/index.js
2342
+ var cors = (options) => {
2343
+ const opts = {
2344
+ origin: "*",
2345
+ allowMethods: [
2346
+ "GET",
2347
+ "HEAD",
2348
+ "PUT",
2349
+ "POST",
2350
+ "DELETE",
2351
+ "PATCH",
2352
+ "QUERY"
2353
+ ],
2354
+ allowHeaders: [],
2355
+ exposeHeaders: [],
2356
+ ...options
2357
+ };
2358
+ const exposeHeadersStr = opts.exposeHeaders?.length ? opts.exposeHeaders.join(",") : void 0;
2359
+ const allowHeadersStr = opts.allowHeaders?.length ? opts.allowHeaders.join(",") : void 0;
2360
+ const findAllowOrigin = ((optsOrigin) => {
2361
+ if (typeof optsOrigin === "string") {
2362
+ if (optsOrigin === "*") return () => optsOrigin;
2363
+ else return (origin) => optsOrigin === origin ? origin : null;
2364
+ } else if (typeof optsOrigin === "function") return optsOrigin;
2365
+ else return (origin) => optsOrigin.includes(origin) ? origin : null;
2366
+ })(opts.origin);
2367
+ const findAllowMethods = ((optsAllowMethods) => {
2368
+ if (typeof optsAllowMethods === "function") return async (origin, c) => (await optsAllowMethods(origin, c)).join(",");
2369
+ else if (Array.isArray(optsAllowMethods)) {
2370
+ const methodsStr = optsAllowMethods.join(",");
2371
+ return () => methodsStr;
2372
+ } else return () => "";
2373
+ })(opts.allowMethods);
2374
+ return async function cors2(c, next) {
2375
+ function set(key, value) {
2376
+ c.res.headers.set(key, value);
2377
+ }
2378
+ const allowOrigin = await findAllowOrigin(c.req.header("origin") || "", c);
2379
+ if (allowOrigin) set("Access-Control-Allow-Origin", allowOrigin);
2380
+ if (opts.credentials) set("Access-Control-Allow-Credentials", "true");
2381
+ if (exposeHeadersStr) set("Access-Control-Expose-Headers", exposeHeadersStr);
2382
+ if (c.req.method === "OPTIONS") {
2383
+ if (opts.origin !== "*") c.res.headers.append("Vary", "Origin");
2384
+ if (opts.maxAge != null) set("Access-Control-Max-Age", opts.maxAge.toString());
2385
+ const allowMethods = await findAllowMethods(c.req.header("origin") || "", c);
2386
+ if (allowMethods) set("Access-Control-Allow-Methods", allowMethods);
2387
+ let headersStr = allowHeadersStr;
2388
+ if (!headersStr) {
2389
+ const requestHeaders = c.req.header("Access-Control-Request-Headers");
2390
+ if (requestHeaders) headersStr = requestHeaders.split(",").map((h) => h.trim()).join(",");
2391
+ }
2392
+ if (headersStr) {
2393
+ set("Access-Control-Allow-Headers", headersStr);
2394
+ c.res.headers.append("Vary", "Access-Control-Request-Headers");
2395
+ }
2396
+ c.res.headers.delete("Content-Length");
2397
+ c.res.headers.delete("Content-Type");
2398
+ return new Response(null, {
2399
+ headers: c.res.headers,
2400
+ status: 204,
2401
+ statusText: "No Content"
2402
+ });
2403
+ }
2404
+ await next();
2405
+ if (opts.origin !== "*") c.header("Vary", "Origin", { append: true });
2406
+ };
2407
+ };
2408
+
2409
+ // ../../node_modules/jose/dist/webapi/lib/buffer_utils.js
2410
+ var encoder = new TextEncoder();
2411
+ var decoder = new TextDecoder();
2412
+ var strictDecoder = new TextDecoder("utf-8", { fatal: true });
2413
+ var MAX_INT32 = 2 ** 32;
2414
+ function concat(...buffers) {
2415
+ const size = buffers.reduce((acc, { length }) => acc + length, 0), buf = new Uint8Array(size);
2416
+ let i = 0;
2417
+ for (const buffer of buffers)
2418
+ buf.set(buffer, i), i += buffer.length;
2419
+ return buf;
2420
+ }
2421
+ var NON_ASCII = /[^\x00-\x7f]/;
2422
+ function encode(string) {
2423
+ if (typeof string == "string" && string.length >= 128) {
2424
+ if (NON_ASCII.test(string))
2425
+ throw new TypeError("non-ASCII string encountered in encode()");
2426
+ return encoder.encode(string);
2427
+ }
2428
+ const bytes = new Uint8Array(string.length);
2429
+ for (let i = 0; i < string.length; i++) {
2430
+ const code = string.charCodeAt(i);
2431
+ if (code > 127)
2432
+ throw new TypeError("non-ASCII string encountered in encode()");
2433
+ bytes[i] = code;
2434
+ }
2435
+ return bytes;
2436
+ }
2437
+ function encodeBase642(input, url = false) {
2438
+ if (Uint8Array.prototype.toBase64)
2439
+ return input.toBase64({ alphabet: url ? "base64url" : "base64", omitPadding: url });
2440
+ const CHUNK_SIZE = 32768, arr = [];
2441
+ for (let i = 0; i < input.length; i += CHUNK_SIZE)
2442
+ arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));
2443
+ const encoded = btoa(arr.join(""));
2444
+ return url ? encoded.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_") : encoded;
2445
+ }
2446
+ function decodeBase642(encoded, url = false) {
2447
+ if (Uint8Array.fromBase64)
2448
+ return Uint8Array.fromBase64(encoded, { alphabet: url ? "base64url" : "base64" });
2449
+ if (url) {
2450
+ if (encoded.includes("+") || encoded.includes("/"))
2451
+ throw new TypeError("Invalid base64url");
2452
+ encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
2453
+ }
2454
+ const binary = atob(encoded), bytes = new Uint8Array(binary.length);
2455
+ for (let i = 0; i < binary.length; i++)
2456
+ bytes[i] = binary.charCodeAt(i);
2457
+ return bytes;
2458
+ }
2459
+ async function digest(algorithm, data) {
2460
+ const subtleDigest = `SHA-${algorithm.slice(-3)}`;
2461
+ return new Uint8Array(await crypto.subtle.digest(subtleDigest, data));
2462
+ }
2463
+
2464
+ // ../../node_modules/jose/dist/webapi/util/errors.js
2465
+ var JOSEError = class extends Error {
2466
+ static code = "ERR_JOSE_GENERIC";
2467
+ code = "ERR_JOSE_GENERIC";
2468
+ constructor(message2, options) {
2469
+ super(message2, options), this.name = this.constructor.name, Error.captureStackTrace?.(this, this.constructor);
2470
+ }
2471
+ };
2472
+ var JWTClaimValidationFailed = class extends JOSEError {
2473
+ static code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
2474
+ code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
2475
+ claim;
2476
+ reason;
2477
+ payload;
2478
+ constructor(message2, payload, claim = "unspecified", reason = "unspecified") {
2479
+ super(message2, { cause: { claim, reason, payload } }), this.claim = claim, this.reason = reason, this.payload = payload;
2480
+ }
2481
+ };
2482
+ var JWTExpired = class extends JOSEError {
2483
+ static code = "ERR_JWT_EXPIRED";
2484
+ code = "ERR_JWT_EXPIRED";
2485
+ claim;
2486
+ reason;
2487
+ payload;
2488
+ constructor(message2, payload, claim = "unspecified", reason = "unspecified") {
2489
+ super(message2, { cause: { claim, reason, payload } }), this.claim = claim, this.reason = reason, this.payload = payload;
2490
+ }
2491
+ };
2492
+ var JOSEAlgNotAllowed = class extends JOSEError {
2493
+ static code = "ERR_JOSE_ALG_NOT_ALLOWED";
2494
+ code = "ERR_JOSE_ALG_NOT_ALLOWED";
2495
+ };
2496
+ var JOSENotSupported = class extends JOSEError {
2497
+ static code = "ERR_JOSE_NOT_SUPPORTED";
2498
+ code = "ERR_JOSE_NOT_SUPPORTED";
2499
+ };
2500
+ var JWSInvalid = class extends JOSEError {
2501
+ static code = "ERR_JWS_INVALID";
2502
+ code = "ERR_JWS_INVALID";
2503
+ };
2504
+ var JWTInvalid = class extends JOSEError {
2505
+ static code = "ERR_JWT_INVALID";
2506
+ code = "ERR_JWT_INVALID";
2507
+ };
2508
+ var JWKInvalid = class extends JOSEError {
2509
+ static code = "ERR_JWK_INVALID";
2510
+ code = "ERR_JWK_INVALID";
2511
+ };
2512
+ var JWKSInvalid = class extends JOSEError {
2513
+ static code = "ERR_JWKS_INVALID";
2514
+ code = "ERR_JWKS_INVALID";
2515
+ };
2516
+ var JWKSNoMatchingKey = class extends JOSEError {
2517
+ static code = "ERR_JWKS_NO_MATCHING_KEY";
2518
+ code = "ERR_JWKS_NO_MATCHING_KEY";
2519
+ constructor(message2 = "no applicable key found in the JSON Web Key Set", options) {
2520
+ super(message2, options);
2521
+ }
2522
+ };
2523
+ var JWKSMultipleMatchingKeys = class extends JOSEError {
2524
+ [Symbol.asyncIterator] = async function* () {
2525
+ };
2526
+ static code = "ERR_JWKS_MULTIPLE_MATCHING_KEYS";
2527
+ code = "ERR_JWKS_MULTIPLE_MATCHING_KEYS";
2528
+ constructor(message2 = "multiple matching keys found in the JSON Web Key Set", options) {
2529
+ super(message2, options);
2530
+ }
2531
+ };
2532
+ var JWKSTimeout = class extends JOSEError {
2533
+ static code = "ERR_JWKS_TIMEOUT";
2534
+ code = "ERR_JWKS_TIMEOUT";
2535
+ constructor(message2 = "request timed out", options) {
2536
+ super(message2, options);
2537
+ }
2538
+ };
2539
+ var JWSSignatureVerificationFailed = class extends JOSEError {
2540
+ static code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
2541
+ code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
2542
+ constructor(message2 = "signature verification failed", options) {
2543
+ super(message2, options);
2544
+ }
2545
+ };
2546
+
2547
+ // ../../node_modules/jose/dist/webapi/util/base64url.js
2548
+ var base64url_exports = {};
2549
+ __export(base64url_exports, {
2550
+ decode: () => decode,
2551
+ encode: () => encode2
2552
+ });
2553
+ var invalid = "The input to be decoded is not correctly encoded.";
2554
+ function decode(input) {
2555
+ try {
2556
+ return decodeBase642(typeof input == "string" ? input : decoder.decode(input), true);
2557
+ } catch (cause) {
2558
+ throw new TypeError(invalid, { cause });
2559
+ }
2560
+ }
2561
+ function encode2(input) {
2562
+ return encodeBase642(typeof input == "string" ? encoder.encode(input) : input, true);
2563
+ }
2564
+
2565
+ // ../../node_modules/jose/dist/webapi/lib/validate.js
2566
+ function isObject(input) {
2567
+ if (typeof input != "object" || input === null || Object.prototype.toString.call(input) !== "[object Object]")
2568
+ return false;
2569
+ const prototype = Object.getPrototypeOf(input);
2570
+ return prototype === null || Object.getPrototypeOf(prototype) === null;
2571
+ }
2572
+ function isJwkSet(input) {
2573
+ return isObject(input) && Array.isArray(input.keys) && Array.from(input.keys).every(isObject);
2574
+ }
2575
+ function isDisjoint(...headers) {
2576
+ const parameters = /* @__PURE__ */ new Set();
2577
+ for (const header of headers)
2578
+ if (header)
2579
+ for (const parameter of Object.keys(header)) {
2580
+ if (parameters.has(parameter))
2581
+ return false;
2582
+ parameters.add(parameter);
2583
+ }
2584
+ return true;
2585
+ }
2586
+ function assertNotSet(value, name) {
2587
+ if (value !== void 0)
2588
+ throw new TypeError(`${name} can only be called once`);
2589
+ }
2590
+ function decodeBase64url(value, label, ErrorClass) {
2591
+ try {
2592
+ return decode(value);
2593
+ } catch {
2594
+ throw new ErrorClass(`Failed to base64url decode the ${label}`);
2595
+ }
2596
+ }
2597
+ function encodeBase64url(value, label, ErrorClass) {
2598
+ try {
2599
+ return encode(value);
2600
+ } catch {
2601
+ throw new ErrorClass(`The ${label} is not a valid base64url string`);
2602
+ }
2603
+ }
2604
+ function parseJoseHeader(b64, ErrorClass, message2) {
2605
+ let parsed;
2606
+ try {
2607
+ parsed = JSON.parse(strictDecoder.decode(decode(b64)));
2608
+ } catch {
2609
+ throw new ErrorClass(message2);
2610
+ }
2611
+ if (!isObject(parsed))
2612
+ throw new ErrorClass(message2);
2613
+ return parsed;
2614
+ }
2615
+ var 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
+ return algorithms === void 0 ? void 0 : new Set(algorithms);
2620
+ }
2621
+ function validateCritDuplicates(Err, protectedHeader) {
2622
+ const { crit } = protectedHeader ?? {};
2623
+ if (Array.isArray(crit) && new Set(crit).size !== crit.length)
2624
+ throw new Err('"crit" (Critical) Header Parameter MUST NOT contain duplicate values');
2625
+ }
2626
+ function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
2627
+ if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0)
2628
+ throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
2629
+ if (!protectedHeader || protectedHeader.crit === void 0)
2630
+ return [];
2631
+ if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input != "string" || input.length === 0))
2632
+ throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');
2633
+ const recognized = recognizedOption === void 0 ? recognizedDefault : { __proto__: null, ...recognizedOption, ...recognizedDefault };
2634
+ for (const parameter of protectedHeader.crit) {
2635
+ if (!(parameter in recognized))
2636
+ throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
2637
+ if (!Object.hasOwn(joseHeader, parameter) || joseHeader[parameter] === void 0)
2638
+ throw new Err(`Extension Header Parameter "${parameter}" is missing`);
2639
+ if (recognized[parameter] && (!Object.hasOwn(protectedHeader, parameter) || protectedHeader[parameter] === void 0))
2640
+ throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
2641
+ }
2642
+ return protectedHeader.crit;
2643
+ }
2644
+ function validateB64(protectedHeader, extensions) {
2645
+ if (extensions.includes("b64")) {
2646
+ const b64 = protectedHeader.b64;
2647
+ if (typeof b64 != "boolean")
2648
+ throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
2649
+ return b64;
2650
+ }
2651
+ return true;
2652
+ }
2653
+ function serializeJoseHeader(Err, header) {
2654
+ let serialized, parsed;
2655
+ try {
2656
+ serialized = JSON.stringify(header), parsed = JSON.parse(serialized);
2657
+ } catch (cause) {
2658
+ throw new Err("JOSE Header is not valid JSON", { cause });
2659
+ }
2660
+ if (!isObject(parsed))
2661
+ throw new Err("JOSE Header is not a JSON object");
2662
+ return [parsed, serialized];
2663
+ }
2664
+
2665
+ // ../../node_modules/jose/dist/webapi/lib/key.js
2666
+ var tag = (key) => key[Symbol.toStringTag];
2667
+ var jwkMatchesOp = (entry, key, usage) => {
2668
+ const { alg } = entry;
2669
+ if (key.use !== void 0) {
2670
+ const expected = usage === "sign" || usage === "verify" ? "sig" : "enc";
2671
+ if (key.use !== expected)
2672
+ throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`);
2673
+ }
2674
+ if (key.alg !== void 0 && key.alg !== alg)
2675
+ throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`);
2676
+ if (Array.isArray(key.key_ops)) {
2677
+ const expectedKeyOp = usage === "encrypt" || usage === "decrypt" ? entry.ops?.[usage === "encrypt" ? 0 : 1] : usage;
2678
+ if (expectedKeyOp && !key.key_ops.includes(expectedKeyOp))
2679
+ throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
2680
+ }
2681
+ };
2682
+ async function prepareKey(entry, key, usage) {
2683
+ const { alg, secret } = entry, privateKey = usage === "decrypt" || usage === "sign";
2684
+ if (secret && key instanceof Uint8Array)
2685
+ return key;
2686
+ let normalized, keyObject;
2687
+ if (isObject(key)) {
2688
+ if (normalized = normalizeJwk(key), typeof normalized.kty != "string")
2689
+ throw invalidKeyType(alg, key, secret);
2690
+ if (!(secret ? normalized.kty === "oct" && typeof normalized.k == "string" : normalized.kty !== "oct" && (privateKey ? normalized.kty === "AKP" && typeof normalized.priv == "string" || typeof normalized.d == "string" : normalized.d === void 0 && normalized.priv === void 0)))
2691
+ 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 ${privateKey ? "private" : "public"} JWK`);
2692
+ if (jwkMatchesOp(entry, normalized, usage), normalized.kty === "oct")
2693
+ return decode(normalized.k);
2694
+ if (!Object.isFrozen(key)) {
2695
+ const { key_ops } = key;
2696
+ Array.isArray(key_ops) && Object.freeze(key_ops), Object.freeze(key);
2697
+ }
2698
+ } else {
2699
+ if (!isKeyLike(key))
2700
+ throw invalidKeyType(alg, key, secret);
2701
+ const expectedType = secret ? "secret" : privateKey ? "private" : "public";
2702
+ if (key.type !== expectedType && (secret || ["secret", "public", "private"].includes(key.type)))
2703
+ throw new TypeError(`${tag(key)} instances must be of type "${expectedType}" for the ${alg} algorithm`);
2704
+ if (isCryptoKey(key))
2705
+ return key;
2706
+ if (keyObject = key, keyObject.type === "secret")
2707
+ return keyObject.export();
2708
+ }
2709
+ cache ||= /* @__PURE__ */ new WeakMap();
2710
+ const cacheKey = key;
2711
+ let cached = cache.get(cacheKey);
2712
+ if (cached?.[alg])
2713
+ return cached[alg];
2714
+ if (cached || cache.set(cacheKey, cached = {}), keyObject && typeof keyObject.toCryptoKey == "function") {
2715
+ const isPublic = keyObject.type === "public", crv = nist[keyObject.asymmetricKeyDetails?.namedCurve], params = entry.resolve?.({ crv, asymmetricKeyType: keyObject.asymmetricKeyType }) ?? entry.subtle;
2716
+ return cached[alg] = keyObject.toCryptoKey(params, isPublic, entry.usages[isPublic ? 0 : 1]);
2717
+ }
2718
+ return normalized ??= keyObject.export({ format: "jwk" }), normalized.alg = alg, cached[alg] = await jwkToKey(entry, normalized);
2719
+ }
2720
+ var cache;
2721
+ var nist = {
2722
+ __proto__: null,
2723
+ prime256v1: "P-256",
2724
+ secp384r1: "P-384",
2725
+ secp521r1: "P-521"
2726
+ };
2727
+ var isCryptoKey = (key) => {
2728
+ if (key?.[Symbol.toStringTag] === "CryptoKey")
2729
+ return true;
2730
+ try {
2731
+ return key instanceof CryptoKey;
2732
+ } catch {
2733
+ return false;
2734
+ }
2735
+ };
2736
+ var isKeyObject = (key) => key?.[Symbol.toStringTag] === "KeyObject";
2737
+ var isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);
2738
+ function message(msg, actual, ...types) {
2739
+ if (types.length > 2) {
2740
+ const last = types.pop();
2741
+ msg += `one of type ${types.join(", ")}, or ${last}.`;
2742
+ } else types.length === 2 ? msg += `one of type ${types[0]} or ${types[1]}.` : msg += `of type ${types[0]}.`;
2743
+ 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;
2744
+ }
2745
+ var invalidKeyInput = (actual, ...types) => message("Key must be ", actual, ...types);
2746
+ function invalidKeyType(alg, actual, secret) {
2747
+ const types = ["CryptoKey", "KeyObject", "JSON Web Key"];
2748
+ return secret && types.push("Uint8Array"), new TypeError(message(`Key for the ${alg} algorithm must be `, actual, ...types));
2749
+ }
2750
+ var unusable = (name, prop = "algorithm.name") => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
2751
+ function checkUsage(key, usage) {
2752
+ if (usage && !key.usages.includes(usage))
2753
+ throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
2754
+ }
2755
+ function checkModulusLength(alg, key) {
2756
+ const { modulusLength } = key.algorithm;
2757
+ if (typeof modulusLength != "number" || modulusLength < 2048)
2758
+ throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
2759
+ }
2760
+ function checkCryptoKey(key, expected, usage) {
2761
+ const algorithm = key.algorithm;
2762
+ if (algorithm.name !== expected.name)
2763
+ throw unusable(expected.name);
2764
+ if (expected.hash && algorithm.hash?.name !== expected.hash)
2765
+ throw unusable(expected.hash, "algorithm.hash");
2766
+ if (expected.namedCurve && algorithm.namedCurve !== expected.namedCurve)
2767
+ throw unusable(expected.namedCurve, "algorithm.namedCurve");
2768
+ if (expected.length !== void 0 && algorithm.length !== expected.length)
2769
+ throw unusable(expected.length, "algorithm.length");
2770
+ checkUsage(key, usage);
2771
+ }
2772
+ function snapshotJwk(jwk) {
2773
+ return { __proto__: null, ...jwk };
2774
+ }
2775
+ function normalizeJwk(jwk) {
2776
+ const normalized = snapshotJwk(jwk);
2777
+ if (normalized.ext !== void 0 && typeof normalized.ext != "boolean")
2778
+ throw new TypeError('"ext" (Extractable) Parameter must be a boolean');
2779
+ if (normalized.key_ops !== void 0) {
2780
+ const value = normalized.key_ops, keyOps = Array.isArray(value) ? [...value] : void 0;
2781
+ if (!keyOps || keyOps.some((operation) => typeof operation != "string") || new Set(keyOps).size !== keyOps.length)
2782
+ throw new TypeError('"key_ops" (Key Operations) Parameter must be an array of unique strings');
2783
+ normalized.key_ops = keyOps;
2784
+ }
2785
+ return normalized;
2786
+ }
2787
+ function validateExtractableOption(extractable) {
2788
+ if (extractable !== void 0 && typeof extractable != "boolean")
2789
+ throw new TypeError('"extractable" option must be a boolean');
2790
+ return extractable;
2791
+ }
2792
+ async function jwkToKey(entry, jwk, extractable) {
2793
+ if (!entry.kty.includes(jwk.kty))
2794
+ throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
2795
+ const algorithm = entry.resolve?.({ kty: jwk.kty, crv: jwk.crv }) ?? entry.subtle, isPrivate = !!(jwk.d || jwk.priv), keyData = { ...jwk, ext: extractable ?? jwk.ext };
2796
+ 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]);
2797
+ }
2798
+ async function rawKey(key, expected, usage, extractable = false) {
2799
+ return key instanceof Uint8Array && (key = await crypto.subtle.importKey("raw", key, expected, extractable, [usage])), checkCryptoKey(key, expected, usage), key;
2800
+ }
2801
+
2802
+ // ../../node_modules/jose/dist/webapi/lib/key_descriptor.js
2803
+ function table(entries) {
2804
+ const out = { __proto__: null };
2805
+ for (const alg in entries)
2806
+ out[alg] = { ...entries[alg], alg };
2807
+ return out;
2808
+ }
2809
+
2810
+ // ../../node_modules/jose/dist/webapi/lib/jwe_algorithms.js
2811
+ var wrap = [
2812
+ ["encrypt", "wrapKey"],
2813
+ ["decrypt", "unwrapKey"]
2814
+ ];
2815
+ var derive = [[], ["deriveBits"]];
2816
+ var none = [[], []];
2817
+ function rsaes(bits) {
2818
+ return {
2819
+ kty: ["RSA"],
2820
+ mode: "key-encryption",
2821
+ subtle: { name: "RSA-OAEP", hash: `SHA-${bits}` },
2822
+ usages: wrap,
2823
+ ops: ["wrapKey", "unwrapKey"]
2824
+ };
2825
+ }
2826
+ function ecdh(mode) {
2827
+ return {
2828
+ kty: ["EC", "OKP"],
2829
+ mode,
2830
+ subtle: { name: "ECDH" },
2831
+ resolve: ({ kty, crv, asymmetricKeyType }) => {
2832
+ if (crv === "X25519" || asymmetricKeyType === "x25519")
2833
+ return { name: "X25519" };
2834
+ if (kty === "OKP")
2835
+ throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
2836
+ return { name: "ECDH", namedCurve: crv };
2837
+ },
2838
+ usages: derive,
2839
+ ops: [void 0, "deriveBits"]
2840
+ };
2841
+ }
2842
+ function aeskw(bits, gcm = false) {
2843
+ return {
2844
+ kty: ["oct"],
2845
+ mode: "key-wrapping",
2846
+ secret: true,
2847
+ subtle: { name: gcm ? "AES-GCM" : "AES-KW", length: bits },
2848
+ usages: none,
2849
+ ops: gcm ? ["encrypt", "decrypt"] : ["wrapKey", "unwrapKey"]
2850
+ };
2851
+ }
2852
+ function pbes2() {
2853
+ return {
2854
+ kty: ["oct"],
2855
+ mode: "key-wrapping",
2856
+ secret: true,
2857
+ subtle: { name: "PBKDF2" },
2858
+ usages: none,
2859
+ ops: ["deriveBits", "deriveBits"]
2860
+ };
2861
+ }
2862
+ var JWE = table({
2863
+ dir: {
2864
+ kty: ["oct"],
2865
+ mode: "direct-encryption",
2866
+ secret: true,
2867
+ subtle: { name: "AES-GCM" },
2868
+ usages: none,
2869
+ ops: ["encrypt", "decrypt"]
2870
+ },
2871
+ "RSA-OAEP": rsaes(1),
2872
+ "RSA-OAEP-256": rsaes(256),
2873
+ "RSA-OAEP-384": rsaes(384),
2874
+ "RSA-OAEP-512": rsaes(512),
2875
+ "ECDH-ES": ecdh("direct-key-agreement"),
2876
+ "ECDH-ES+A128KW": ecdh("key-agreement-with-key-wrapping"),
2877
+ "ECDH-ES+A192KW": ecdh("key-agreement-with-key-wrapping"),
2878
+ "ECDH-ES+A256KW": ecdh("key-agreement-with-key-wrapping"),
2879
+ A128KW: aeskw(128),
2880
+ A192KW: aeskw(192),
2881
+ A256KW: aeskw(256),
2882
+ A128GCMKW: aeskw(128, true),
2883
+ A192GCMKW: aeskw(192, true),
2884
+ A256GCMKW: aeskw(256, true),
2885
+ "PBES2-HS256+A128KW": pbes2(),
2886
+ "PBES2-HS384+A192KW": pbes2(),
2887
+ "PBES2-HS512+A256KW": pbes2()
2888
+ });
2889
+ var contentOps = ["encrypt", "decrypt"];
2890
+ function contentEncryption(bits, cbc = false) {
2891
+ return {
2892
+ kty: ["oct"],
2893
+ secret: true,
2894
+ subtle: { name: cbc ? "AES-CBC" : "AES-GCM", length: bits },
2895
+ usages: none,
2896
+ ops: contentOps,
2897
+ cekBits: bits,
2898
+ ivBits: cbc ? 128 : 96,
2899
+ cbc
2900
+ };
2901
+ }
2902
+ var ENC = table({
2903
+ A128GCM: contentEncryption(128),
2904
+ A192GCM: contentEncryption(192),
2905
+ A256GCM: contentEncryption(256),
2906
+ "A128CBC-HS256": contentEncryption(256, true),
2907
+ "A192CBC-HS384": contentEncryption(384, true),
2908
+ "A256CBC-HS512": contentEncryption(512, true)
2909
+ });
2910
+
2911
+ // ../../node_modules/jose/dist/webapi/lib/jws_algorithms.js
2912
+ var sig = [["verify"], ["sign"]];
2913
+ function hmac(bits) {
2914
+ const subtle = { name: "HMAC", hash: `SHA-${bits}` };
2915
+ return { kty: ["oct"], secret: true, subtle, signing: subtle, usages: sig };
2916
+ }
2917
+ function rsa(bits, saltLength) {
2918
+ const subtle = { name: saltLength ? "RSA-PSS" : "RSASSA-PKCS1-v1_5", hash: `SHA-${bits}` };
2919
+ return {
2920
+ kty: ["RSA"],
2921
+ subtle,
2922
+ signing: saltLength ? { ...subtle, saltLength } : subtle,
2923
+ usages: sig,
2924
+ minRsaBits: 2048
2925
+ };
2926
+ }
2927
+ function ecdsa(crv, bits) {
2928
+ return {
2929
+ kty: ["EC"],
2930
+ crv,
2931
+ subtle: { name: "ECDSA", namedCurve: crv },
2932
+ signing: { name: "ECDSA", hash: `SHA-${bits}` },
2933
+ usages: sig
2934
+ };
2935
+ }
2936
+ function eddsa() {
2937
+ const subtle = { name: "Ed25519" };
2938
+ return {
2939
+ kty: ["OKP"],
2940
+ crv: "Ed25519",
2941
+ subtle,
2942
+ signing: subtle,
2943
+ usages: sig
2944
+ };
2945
+ }
2946
+ function mldsa(bits) {
2947
+ const subtle = { name: `ML-DSA-${bits}` };
2948
+ return {
2949
+ kty: ["AKP"],
2950
+ subtle,
2951
+ signing: subtle,
2952
+ usages: sig
2953
+ };
2954
+ }
2955
+ var JWS = table({
2956
+ HS256: hmac(256),
2957
+ HS384: hmac(384),
2958
+ HS512: hmac(512),
2959
+ RS256: rsa(256),
2960
+ RS384: rsa(384),
2961
+ RS512: rsa(512),
2962
+ PS256: rsa(256, 32),
2963
+ PS384: rsa(384, 48),
2964
+ PS512: rsa(512, 64),
2965
+ ES256: ecdsa("P-256", 256),
2966
+ ES384: ecdsa("P-384", 384),
2967
+ ES512: ecdsa("P-521", 512),
2968
+ EdDSA: eddsa(),
2969
+ Ed25519: eddsa(),
2970
+ "ML-DSA-44": mldsa(44),
2971
+ "ML-DSA-65": mldsa(65),
2972
+ "ML-DSA-87": mldsa(87)
2973
+ });
2974
+ function jwsAlgorithm(alg) {
2975
+ const entry = typeof alg == "string" ? JWS[alg] : void 0;
2976
+ if (!entry)
2977
+ throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
2978
+ return entry;
2979
+ }
2980
+
2981
+ // ../../node_modules/jose/dist/webapi/lib/jws_verify.js
2982
+ function prepareVerify(options) {
2983
+ return [options && validateAlgorithms("algorithms", options.algorithms), options?.crit];
2984
+ }
2985
+ function parseProtectedHeader(encodedProtected) {
2986
+ return encodedProtected === void 0 ? {} : parseJoseHeader(encodedProtected, JWSInvalid, "JWS Protected Header is invalid");
2987
+ }
2988
+ function encodeCompactUnencodedPayload(payload) {
2989
+ try {
2990
+ return encode(payload);
2991
+ } catch {
2992
+ throw new JWSInvalid("JWS Compact Serialization payload must use only ASCII characters");
2993
+ }
2994
+ }
2995
+ async function verifySignature(jws, shared, key, encodeUnencodedPayload, parsedProtected) {
2996
+ const { protected: encodedProtected, header, payload: inputPayload } = jws, parsedProt = parsedProtected ?? parseProtectedHeader(encodedProtected);
2997
+ if (!isDisjoint(parsedProt, header))
2998
+ throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
2999
+ const joseHeader = { ...parsedProt, ...header }, b64 = validateB64(parsedProt, validateCrit(JWSInvalid, JWS_RECOGNIZED, shared[1], parsedProt, joseHeader)), { alg } = joseHeader;
3000
+ if (typeof alg != "string" || !alg)
3001
+ throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
3002
+ if (shared[0] && !shared[0].has(alg))
3003
+ throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed');
3004
+ if (b64) {
3005
+ if (typeof inputPayload != "string")
3006
+ throw new JWSInvalid("JWS Payload must be a string");
3007
+ } else if (typeof inputPayload != "string" && !(inputPayload instanceof Uint8Array))
3008
+ throw new JWSInvalid("JWS Payload must be a string or an Uint8Array instance");
3009
+ const signingPayload = b64 || typeof inputPayload != "string" ? inputPayload : encodeUnencodedPayload(inputPayload);
3010
+ let resolvedKey = false;
3011
+ typeof key == "function" && (key = await key(parsedProt, jws), resolvedKey = true);
3012
+ const entry = jwsAlgorithm(alg), data = concat(encodedProtected !== void 0 ? encode(encodedProtected) : new Uint8Array(), encode("."), typeof signingPayload == "string" ? shared[2] ??= encodeBase64url(signingPayload, "payload", JWSInvalid) : signingPayload), signature = decodeBase64url(jws.signature, "signature", JWSInvalid), k = await prepareKey(entry, key, "verify"), cryptoKey = await rawKey(k, entry.subtle, "verify");
3013
+ entry.minRsaBits && checkModulusLength(entry.alg, cryptoKey);
3014
+ let verified = false;
3015
+ try {
3016
+ verified = await crypto.subtle.verify(entry.signing, cryptoKey, signature, data);
3017
+ } catch {
3018
+ }
3019
+ if (!verified)
3020
+ throw new JWSSignatureVerificationFailed();
3021
+ const result = { payload: typeof signingPayload == "string" ? decodeBase64url(signingPayload, "payload", JWSInvalid) : signingPayload };
3022
+ return encodedProtected !== void 0 && (result.protectedHeader = parsedProt), header !== void 0 && (result.unprotectedHeader = header), resolvedKey ? [{ ...result, key: k }, b64] : [result, b64];
3023
+ }
3024
+ async function verifyCompact(jws, shared, key) {
3025
+ if (jws instanceof Uint8Array && (jws = decoder.decode(jws)), typeof jws != "string")
3026
+ throw new JWSInvalid("Compact JWS must be a string or Uint8Array");
3027
+ const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split(".");
3028
+ if (length !== 3)
3029
+ throw new JWSInvalid("Invalid Compact JWS");
3030
+ return verifySignature({ payload, protected: protectedHeader, signature }, shared, key, encodeCompactUnencodedPayload);
3031
+ }
3032
+
3033
+ // ../../node_modules/jose/dist/webapi/lib/jwt_claims_set.js
3034
+ var epoch = (date) => Math.floor(date.getTime() / 1e3);
3035
+ var multipliers = {
3036
+ s: 1,
3037
+ m: 60,
3038
+ h: 3600,
3039
+ d: 86400,
3040
+ w: 604800,
3041
+ y: 31557600
3042
+ };
3043
+ var REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;
3044
+ var checkFailed = "check_failed";
3045
+ function invalidDuration() {
3046
+ throw new TypeError("Invalid time period format");
3047
+ }
3048
+ function secs(str) {
3049
+ typeof str != "string" && invalidDuration();
3050
+ const matched = REGEX.exec(str);
3051
+ (!matched || matched[4] && matched[1]) && invalidDuration();
3052
+ const value = parseFloat(matched[2]), numericDate2 = Math.round(value * multipliers[matched[3][0].toLowerCase()]);
3053
+ return Number.isFinite(numericDate2) || invalidDuration(), matched[1] === "-" || matched[4] === "ago" ? -numericDate2 : numericDate2;
3054
+ }
3055
+ function validateInput(label, input) {
3056
+ if (!Number.isFinite(input))
3057
+ throw new TypeError(`Invalid ${label} input`);
3058
+ return input;
3059
+ }
3060
+ function validateStringClaim(claim, value) {
3061
+ if (typeof value != "string")
3062
+ throw new TypeError(`"${claim}" claim must be a string`);
3063
+ }
3064
+ function validateAudienceClaim(value) {
3065
+ if (typeof value != "string" && (!Array.isArray(value) || Array.from(value).some((member) => typeof member != "string")))
3066
+ throw new TypeError('"aud" claim must be a string or an array of strings');
3067
+ }
3068
+ function numericDate(value, label) {
3069
+ return typeof value == "number" ? validateInput(label, value) : value instanceof Date ? validateInput(label, epoch(value)) : epoch(/* @__PURE__ */ new Date()) + secs(value);
3070
+ }
3071
+ var normalizeTyp = (value) => {
3072
+ const normalized = value.toLowerCase();
3073
+ return value.includes("/") ? normalized : `application/${normalized}`;
3074
+ };
3075
+ var checkAudiencePresence = (audPayload, audOption) => typeof audPayload == "string" ? audOption.includes(audPayload) : Array.isArray(audPayload) ? audOption.some((aud) => audPayload.includes(aud)) : false;
3076
+ function validateNumericDate(payload, claim, required = false) {
3077
+ const value = payload[claim];
3078
+ if (!(value === void 0 && !required)) {
3079
+ if (typeof value != "number")
3080
+ throw new JWTClaimValidationFailed(`"${claim}" claim must be a number`, payload, claim, "invalid");
3081
+ return value;
3082
+ }
3083
+ }
3084
+ function unexpectedClaim(payload, claim) {
3085
+ throw new JWTClaimValidationFailed(`unexpected "${claim}" claim value`, payload, claim, checkFailed);
3086
+ }
3087
+ function validateClaimsSet(protectedHeader, encodedPayload, options = {}) {
3088
+ let payload;
3089
+ try {
3090
+ payload = JSON.parse(strictDecoder.decode(encodedPayload));
3091
+ } catch {
3092
+ }
3093
+ if (!isObject(payload))
3094
+ throw new JWTInvalid("JWT Claims Set must be a top-level JSON object");
3095
+ const { typ } = options;
3096
+ if (typ !== void 0 && (typeof protectedHeader.typ != "string" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ)))
3097
+ throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', payload, "typ", checkFailed);
3098
+ const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options, presenceCheck = [...requiredClaims];
3099
+ maxTokenAge !== void 0 && presenceCheck.push("iat"), audience !== void 0 && presenceCheck.push("aud"), subject !== void 0 && presenceCheck.push("sub"), issuer !== void 0 && presenceCheck.push("iss");
3100
+ for (const claim of new Set(presenceCheck.reverse()))
3101
+ if (!Object.hasOwn(payload, claim))
3102
+ throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, payload, claim, "missing");
3103
+ issuer !== void 0 && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss) && unexpectedClaim(payload, "iss"), subject !== void 0 && payload.sub !== subject && unexpectedClaim(payload, "sub"), audience !== void 0 && !checkAudiencePresence(payload.aud, typeof audience == "string" ? [audience] : audience) && unexpectedClaim(payload, "aud");
3104
+ const { clockTolerance } = options;
3105
+ let tolerance = 0;
3106
+ if (typeof clockTolerance == "string")
3107
+ tolerance = secs(clockTolerance);
3108
+ else if (clockTolerance !== void 0) {
3109
+ if (typeof clockTolerance != "number")
3110
+ throw new TypeError("Invalid clockTolerance option type");
3111
+ tolerance = clockTolerance;
3112
+ }
3113
+ validateInput("clockTolerance option", tolerance);
3114
+ const { currentDate } = options, now = validateInput("currentDate option", epoch(currentDate === void 0 ? /* @__PURE__ */ new Date() : currentDate)), iat = validateNumericDate(payload, "iat", maxTokenAge !== void 0), nbf = validateNumericDate(payload, "nbf");
3115
+ if (nbf !== void 0 && nbf > now + tolerance)
3116
+ throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', payload, "nbf", checkFailed);
3117
+ const exp = validateNumericDate(payload, "exp");
3118
+ if (exp !== void 0 && exp <= now - tolerance)
3119
+ throw new JWTExpired('"exp" claim timestamp check failed', payload, "exp", checkFailed);
3120
+ if (maxTokenAge !== void 0) {
3121
+ const age = now - iat, max = validateInput("maxTokenAge option", typeof maxTokenAge == "number" ? maxTokenAge : secs(maxTokenAge));
3122
+ if (age - tolerance > max)
3123
+ throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', payload, "iat", checkFailed);
3124
+ if (age < -tolerance)
3125
+ throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', payload, "iat", checkFailed);
3126
+ }
3127
+ return payload;
3128
+ }
3129
+ var producerPayloads;
3130
+ function producerPayload(producer) {
3131
+ return producerPayloads.get(producer);
3132
+ }
3133
+ function jwtData(producer) {
3134
+ const payload = producerPayload(producer);
3135
+ for (const claim of ["iat", "nbf", "exp"]) {
3136
+ const value = payload[claim];
3137
+ if (typeof value == "number" && !Number.isFinite(value))
3138
+ throw new TypeError(`"${claim}" claim must be a finite number`);
3139
+ }
3140
+ return encoder.encode(JSON.stringify(payload));
3141
+ }
3142
+ var JWTClaimsBuilder = class {
3143
+ constructor(payload = {}) {
3144
+ if (!isObject(payload))
3145
+ throw new TypeError("JWT Claims Set MUST be an object");
3146
+ (producerPayloads ||= /* @__PURE__ */ new WeakMap()).set(this, structuredClone(payload));
3147
+ }
3148
+ setIssuer(value) {
3149
+ return validateStringClaim("iss", value), producerPayload(this).iss = value, this;
3150
+ }
3151
+ setSubject(value) {
3152
+ return validateStringClaim("sub", value), producerPayload(this).sub = value, this;
3153
+ }
3154
+ setAudience(value) {
3155
+ return validateAudienceClaim(value), producerPayload(this).aud = value, this;
3156
+ }
3157
+ setJti(value) {
3158
+ return validateStringClaim("jti", value), producerPayload(this).jti = value, this;
3159
+ }
3160
+ setNotBefore(value) {
3161
+ return producerPayload(this).nbf = numericDate(value, "setNotBefore"), this;
3162
+ }
3163
+ setExpirationTime(value) {
3164
+ return producerPayload(this).exp = numericDate(value, "setExpirationTime"), this;
3165
+ }
3166
+ setIssuedAt(value) {
3167
+ const payload = producerPayload(this);
3168
+ return value === void 0 ? payload.iat = epoch(/* @__PURE__ */ new Date()) : typeof value == "string" ? payload.iat = validateInput("setIssuedAt", epoch(/* @__PURE__ */ new Date()) + secs(value)) : payload.iat = numericDate(value, "setIssuedAt"), this;
3169
+ }
3170
+ };
3171
+
3172
+ // ../../node_modules/jose/dist/webapi/jwt/verify.js
3173
+ async function jwtVerify(jwt, key, options) {
3174
+ const [verified, b64] = await verifyCompact(jwt, prepareVerify(options), key);
3175
+ if (!b64)
3176
+ throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
3177
+ const payload = validateClaimsSet(verified.protectedHeader, verified.payload, options);
3178
+ return { ...verified, payload };
3179
+ }
3180
+
3181
+ // ../../node_modules/jose/dist/webapi/lib/jws_sign.js
3182
+ async function createSignature(input, key, rejectUnencoded) {
3183
+ let [payload, protectedHeader, unprotectedHeader, crit] = input, protectedHeaderString = "";
3184
+ if (protectedHeader !== void 0) {
3185
+ const normalized = serializeJoseHeader(JWSInvalid, protectedHeader);
3186
+ protectedHeader = normalized[0], protectedHeaderString = encode2(normalized[1]);
3187
+ }
3188
+ if (unprotectedHeader !== void 0 && (unprotectedHeader = serializeJoseHeader(JWSInvalid, unprotectedHeader)[0]), !protectedHeader && !unprotectedHeader)
3189
+ throw new JWSInvalid("either setProtectedHeader or setUnprotectedHeader must be called before #sign()");
3190
+ if (!isDisjoint(protectedHeader, unprotectedHeader))
3191
+ throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
3192
+ const joseHeader = { ...protectedHeader, ...unprotectedHeader };
3193
+ validateCritDuplicates(JWSInvalid, protectedHeader);
3194
+ const b64 = validateB64(protectedHeader, validateCrit(JWSInvalid, JWS_RECOGNIZED, crit, protectedHeader, joseHeader));
3195
+ b64 || rejectUnencoded?.();
3196
+ const { alg } = joseHeader;
3197
+ if (typeof alg != "string" || !alg)
3198
+ throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
3199
+ const entry = jwsAlgorithm(alg);
3200
+ let payloadS = "", payloadB = payload, data;
3201
+ if (b64) {
3202
+ const encoded = input[4];
3203
+ encoded ? (payloadS = encoded[0] ??= encode2(payload), payloadB = encoded[1] ??= encode(payloadS)) : (payloadS = encode2(payload), data = encoder.encode(`${protectedHeaderString}.${payloadS}`));
3204
+ }
3205
+ data ??= concat(encode(protectedHeaderString), encode("."), payloadB);
3206
+ const k = await rawKey(await prepareKey(entry, key, "sign"), entry.subtle, "sign");
3207
+ entry.minRsaBits && checkModulusLength(entry.alg, k);
3208
+ const jws = {
3209
+ signature: encode2(new Uint8Array(await crypto.subtle.sign(entry.signing, k, data))),
3210
+ payload: payloadS
3211
+ };
3212
+ return protectedHeader && (jws.protected = protectedHeaderString), unprotectedHeader && (jws.header = unprotectedHeader), [jws, b64];
3213
+ }
3214
+ async function createCompactSignature(payload, protectedHeader, crit, key, rejectUnencoded) {
3215
+ const [jws] = await createSignature([payload, protectedHeader, void 0, crit], key, rejectUnencoded);
3216
+ return `${jws.protected}.${jws.payload}.${jws.signature}`;
3217
+ }
3218
+
3219
+ // ../../node_modules/jose/dist/webapi/jwt/sign.js
3220
+ var SignJWT_base = JWTClaimsBuilder;
3221
+ var SignJWT = class extends SignJWT_base {
3222
+ #protectedHeader;
3223
+ setProtectedHeader(protectedHeader) {
3224
+ return assertNotSet(this.#protectedHeader, "setProtectedHeader"), this.#protectedHeader = protectedHeader, this;
3225
+ }
3226
+ async sign(key, options) {
3227
+ return createCompactSignature(jwtData(this), this.#protectedHeader, options?.crit, key, () => {
3228
+ throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
3229
+ });
3230
+ }
3231
+ };
3232
+
3233
+ // ../../node_modules/jose/dist/webapi/lib/key_algorithm.js
3234
+ var algArgument = '"alg" (Algorithm)';
3235
+ function unsupportedAlg(source = 'JWK "alg" (Algorithm) Parameter') {
3236
+ throw new JOSENotSupported(`Invalid or unsupported ${source} value`);
3237
+ }
3238
+ function keyAlgorithm(alg, source) {
3239
+ return (typeof alg == "string" ? JWS[alg] ?? JWE[alg] : void 0) ?? unsupportedAlg(source);
3240
+ }
3241
+
3242
+ // ../../node_modules/jose/dist/webapi/key/export.js
3243
+ async function exportJWK(key) {
3244
+ if (isKeyObject(key))
3245
+ if (key.type === "secret")
3246
+ key = key.export();
3247
+ else
3248
+ return key.export({ format: "jwk" });
3249
+ if (key instanceof Uint8Array)
3250
+ return {
3251
+ kty: "oct",
3252
+ k: encode2(key)
3253
+ };
3254
+ if (!isCryptoKey(key))
3255
+ throw new TypeError(invalidKeyInput(key, "CryptoKey", "KeyObject", "Uint8Array"));
3256
+ if (!key.extractable)
3257
+ throw new TypeError("non-extractable CryptoKey cannot be exported as a JWK");
3258
+ const jwk = await crypto.subtle.exportKey("jwk", key);
3259
+ delete jwk.ext, delete jwk.key_ops, delete jwk.use, jwk.kty !== "AKP" && delete jwk.alg;
3260
+ for (const parameter of Object.keys(jwk))
3261
+ jwk[parameter] === void 0 && delete jwk[parameter];
3262
+ return jwk;
3263
+ }
3264
+
3265
+ // ../../node_modules/jose/dist/webapi/jwk/thumbprint.js
3266
+ var check = (value, description) => {
3267
+ if (typeof value != "string" || !value)
3268
+ throw new JWKInvalid(`${description} missing or invalid`);
3269
+ };
3270
+ async function calculateJwkThumbprint(key, digestAlgorithm) {
3271
+ let jwk;
3272
+ if (isObject(key)) {
3273
+ if (jwk = snapshotJwk(key), typeof jwk.kty != "string")
3274
+ throw new TypeError(invalidKeyInput(key, "CryptoKey", "KeyObject", "JSON Web Key"));
3275
+ } else if (isKeyLike(key))
3276
+ jwk = snapshotJwk(await exportJWK(key));
3277
+ else
3278
+ throw new TypeError(invalidKeyInput(key, "CryptoKey", "KeyObject", "JSON Web Key"));
3279
+ if (digestAlgorithm ??= "sha256", digestAlgorithm !== "sha256" && digestAlgorithm !== "sha384" && digestAlgorithm !== "sha512")
3280
+ throw new TypeError('digestAlgorithm must one of "sha256", "sha384", or "sha512"');
3281
+ let components;
3282
+ switch (jwk.kty) {
3283
+ case "AKP":
3284
+ check(jwk.alg, '"alg" (Algorithm) Parameter'), check(jwk.pub, '"pub" (Public key) Parameter'), components = { alg: jwk.alg, kty: jwk.kty, pub: jwk.pub };
3285
+ break;
3286
+ case "EC":
3287
+ check(jwk.crv, '"crv" (Curve) Parameter'), check(jwk.x, '"x" (X Coordinate) Parameter'), check(jwk.y, '"y" (Y Coordinate) Parameter'), components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y };
3288
+ break;
3289
+ case "OKP":
3290
+ check(jwk.crv, '"crv" (Subtype of Key Pair) Parameter'), check(jwk.x, '"x" (Public Key) Parameter'), components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x };
3291
+ break;
3292
+ case "RSA":
3293
+ check(jwk.e, '"e" (Exponent) Parameter'), check(jwk.n, '"n" (Modulus) Parameter'), components = { e: jwk.e, kty: jwk.kty, n: jwk.n };
3294
+ break;
3295
+ case "oct":
3296
+ if (typeof jwk.k != "string")
3297
+ throw new JWKInvalid('"k" (Key Value) Parameter missing or invalid');
3298
+ components = { k: jwk.k, kty: jwk.kty };
3299
+ break;
3300
+ default:
3301
+ throw new JOSENotSupported('"kty" (Key Type) Parameter missing or unsupported');
3302
+ }
3303
+ const data = encode(JSON.stringify(components));
3304
+ return encode2(await digest(digestAlgorithm, data));
3305
+ }
3306
+
3307
+ // ../../node_modules/jose/dist/webapi/jwks/local.js
3308
+ function isUsableJWK(jwk, entry, alg, kid) {
3309
+ const { kty, key_ops: keyOps, ext, kid: jwkKid, alg: jwkAlg, use, crv } = jwk;
3310
+ 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);
3311
+ }
3312
+ async function importWithAlgCache(cache2, jwk, entry) {
3313
+ const cached = cache2.get(jwk) || cache2.set(jwk, {}).get(jwk), { alg } = entry;
3314
+ if (cached[alg] === void 0) {
3315
+ const pending = jwkToKey(entry, jwk, true).then((key) => {
3316
+ if (key.type !== "public")
3317
+ throw new JWKSInvalid("JSON Web Key Set members must be public keys");
3318
+ return cached[alg] = key, key;
3319
+ }).catch((error) => {
3320
+ throw cached[alg] === pending && delete cached[alg], error;
3321
+ });
3322
+ cached[alg] = pending;
3323
+ }
3324
+ return cached[alg];
3325
+ }
3326
+ function createLocalJWKSet(jwks) {
3327
+ let snapshot;
3328
+ try {
3329
+ snapshot = structuredClone(jwks);
3330
+ } catch {
3331
+ }
3332
+ if (!isJwkSet(snapshot))
3333
+ throw new JWKSInvalid("JSON Web Key Set malformed");
3334
+ const metadata = snapshot.keys.map((jwk) => {
3335
+ const normalized = snapshotJwk(jwk);
3336
+ return Array.isArray(normalized.key_ops) && (normalized.key_ops = [...normalized.key_ops]), normalized;
3337
+ }), cached = /* @__PURE__ */ new WeakMap();
3338
+ return Object.defineProperty(async (protectedHeader, token) => {
3339
+ const { alg, kid } = { ...protectedHeader, ...token?.header }, entry = typeof alg == "string" ? JWS[alg] : void 0;
3340
+ if (!entry || entry.secret)
3341
+ throw new JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set');
3342
+ const candidates = snapshot.keys.filter((_, index) => isUsableJWK(metadata[index], entry, alg, kid)), { 0: jwk, length } = candidates;
3343
+ if (!length)
3344
+ throw new JWKSNoMatchingKey();
3345
+ if (length !== 1) {
3346
+ const error = new JWKSMultipleMatchingKeys();
3347
+ throw error[Symbol.asyncIterator] = async function* () {
3348
+ for (const jwk2 of candidates)
3349
+ try {
3350
+ yield await importWithAlgCache(cached, jwk2, entry);
3351
+ } catch {
3352
+ }
3353
+ }, error;
3354
+ }
3355
+ return importWithAlgCache(cached, jwk, entry);
3356
+ }, "jwks", {
3357
+ value: () => structuredClone(snapshot)
3358
+ });
3359
+ }
3360
+
3361
+ // ../../node_modules/jose/dist/webapi/jwks/remote.js
3362
+ function isCloudflareWorkers() {
3363
+ return typeof WebSocketPair < "u" || typeof navigator < "u" && navigator.userAgent === "Cloudflare-Workers" || typeof EdgeRuntime < "u" && EdgeRuntime === "vercel";
3364
+ }
3365
+ var USER_AGENT;
3366
+ (typeof navigator > "u" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) && (USER_AGENT = "jose/v6.2.12");
3367
+ var customFetch = /* @__PURE__ */ Symbol();
3368
+ async function fetchJwks(url, headers, signal, fetchImpl = fetch) {
3369
+ const response = await fetchImpl(url, {
3370
+ method: "GET",
3371
+ signal,
3372
+ redirect: "manual",
3373
+ headers
3374
+ }).catch((err) => {
3375
+ throw err.name === "TimeoutError" ? new JWKSTimeout() : err;
3376
+ });
3377
+ if (response.status !== 200)
3378
+ throw new JOSEError("Expected 200 OK from the JSON Web Key Set HTTP response");
3379
+ try {
3380
+ return await response.json();
3381
+ } catch {
3382
+ throw new JOSEError("Failed to parse the JSON Web Key Set HTTP response as JSON");
3383
+ }
3384
+ }
3385
+ var jwksCache = /* @__PURE__ */ Symbol();
3386
+ function isFreshFor(timestamp, duration) {
3387
+ return Number.isFinite(timestamp) && Date.now() < timestamp + duration;
3388
+ }
3389
+ function validateDuration(value, fallback, option) {
3390
+ if (Number.isNaN(value))
3391
+ throw new TypeError(`"${option}" option must not be NaN`);
3392
+ return typeof value == "number" ? value : fallback;
3393
+ }
3394
+ function createRemoteJWKSet(url, options) {
3395
+ if (!(url instanceof URL))
3396
+ throw new TypeError("url must be an instance of URL");
3397
+ const href = new URL(url.href).href, opts = options ?? {}, timeoutOption = opts.timeoutDuration;
3398
+ if (typeof timeoutOption == "number" && (!Number.isInteger(timeoutOption) || timeoutOption < 0))
3399
+ throw new TypeError('"timeoutDuration" option must be a non-negative integer');
3400
+ const timeoutDuration = typeof timeoutOption == "number" ? timeoutOption : 5e3, cooldownDuration = validateDuration(opts.cooldownDuration, 3e4, "cooldownDuration"), cacheMaxAge = validateDuration(opts.cacheMaxAge, 6e5, "cacheMaxAge"), headers = new Headers(opts.headers);
3401
+ USER_AGENT && !headers.has("User-Agent") && headers.set("User-Agent", USER_AGENT), headers.has("accept") || headers.set("accept", "application/json, application/jwk-set+json");
3402
+ const fetchImpl = opts[customFetch], cache2 = opts[jwksCache];
3403
+ let jwksTimestamp, pendingFetch, reloadSequence = 0, appliedSequence = 0, local;
3404
+ if (cache2 && typeof cache2 == "object") {
3405
+ const { uat, jwks } = cache2;
3406
+ isFreshFor(uat, cacheMaxAge) && isJwkSet(jwks) && (jwksTimestamp = uat, local = createLocalJWKSet(jwks));
3407
+ }
3408
+ const reload = async () => {
3409
+ if (pendingFetch && isCloudflareWorkers() && (pendingFetch = void 0), !pendingFetch) {
3410
+ const sequence = ++reloadSequence, current = pendingFetch = fetchJwks(href, headers, AbortSignal.timeout(timeoutDuration), fetchImpl).then((json) => {
3411
+ const next = createLocalJWKSet(json);
3412
+ if (sequence <= appliedSequence)
3413
+ return;
3414
+ local = next;
3415
+ const updatedAt = Date.now();
3416
+ cache2 && (cache2.uat = updatedAt, cache2.jwks = json), jwksTimestamp = updatedAt, appliedSequence = sequence;
3417
+ }).finally(() => {
3418
+ pendingFetch === current && (pendingFetch = void 0);
3419
+ });
3420
+ }
3421
+ await pendingFetch;
3422
+ };
3423
+ return Object.defineProperties(async (protectedHeader, token) => {
3424
+ (!local || !isFreshFor(jwksTimestamp, cacheMaxAge)) && await reload();
3425
+ try {
3426
+ return await local(protectedHeader, token);
3427
+ } catch (err) {
3428
+ if (err instanceof JWKSNoMatchingKey && !isFreshFor(jwksTimestamp, cooldownDuration))
3429
+ return await reload(), local(protectedHeader, token);
3430
+ throw err;
3431
+ }
3432
+ }, {
3433
+ coolingDown: {
3434
+ get: () => isFreshFor(jwksTimestamp, cooldownDuration),
3435
+ enumerable: true
3436
+ },
3437
+ fresh: {
3438
+ get: () => isFreshFor(jwksTimestamp, cacheMaxAge),
3439
+ enumerable: true
3440
+ },
3441
+ reload: {
3442
+ value: reload,
3443
+ enumerable: true
3444
+ },
3445
+ reloading: {
3446
+ get: () => !!pendingFetch,
3447
+ enumerable: true
3448
+ },
3449
+ jwks: {
3450
+ value: () => local?.jwks(),
3451
+ enumerable: true
3452
+ }
3453
+ });
3454
+ }
3455
+
3456
+ // ../../node_modules/jose/dist/webapi/key/import.js
3457
+ async function importJWK(jwk, alg, options) {
3458
+ if (!isObject(jwk))
3459
+ throw new TypeError("JWK must be an object");
3460
+ const normalized = normalizeJwk(jwk), extractable = validateExtractableOption(options?.extractable), { alg: jwkAlg } = normalized;
3461
+ if (alg ??= jwkAlg, normalized.kty !== "oct" && !alg)
3462
+ throw new TypeError('"alg" argument is required when "jwk.alg" is not present');
3463
+ switch (normalized.kty) {
3464
+ case "oct":
3465
+ if (typeof normalized.k != "string")
3466
+ throw new TypeError('missing "k" (Key Value) Parameter value');
3467
+ return decode(normalized.k);
3468
+ case "AKP": {
3469
+ if (typeof jwkAlg != "string" || !jwkAlg)
3470
+ throw new TypeError('missing "alg" (Algorithm) Parameter value');
3471
+ if (alg !== jwkAlg)
3472
+ throw new TypeError("JWK alg and alg option value mismatch");
3473
+ return jwkToKey(keyAlgorithm(alg), normalized, extractable);
3474
+ }
3475
+ case "RSA":
3476
+ case "EC":
3477
+ case "OKP":
3478
+ return jwkToKey(keyAlgorithm(alg), normalized, extractable);
3479
+ default:
3480
+ throw new JOSENotSupported('Unsupported "kty" (Key Type) Parameter value');
3481
+ }
3482
+ }
3483
+
3484
+ // ../../node_modules/jose/dist/webapi/key/generate_key_pair.js
3485
+ function getModulusLengthOption(options) {
3486
+ const modulusLength = options?.modulusLength ?? 2048;
3487
+ if (typeof modulusLength != "number" || !Number.isInteger(modulusLength) || modulusLength < 2048)
3488
+ throw new JOSENotSupported("Invalid or unsupported modulusLength option provided, 2048 bits or larger keys must be used");
3489
+ return modulusLength;
3490
+ }
3491
+ async function generateKeyPair(alg, options) {
3492
+ const extractable = validateExtractableOption(options?.extractable), entry = keyAlgorithm(alg, algArgument);
3493
+ entry.secret && unsupportedAlg(algArgument);
3494
+ let algorithm;
3495
+ if (entry.resolve) {
3496
+ const crv = options?.crv ?? "P-256";
3497
+ if (!["P-256", "P-384", "P-521", "X25519"].includes(crv))
3498
+ throw new JOSENotSupported("Invalid or unsupported crv option provided, supported values are P-256, P-384, P-521, and X25519");
3499
+ algorithm = entry.resolve({ crv });
3500
+ } else {
3501
+ if (entry.crv !== void 0 && options?.crv !== void 0 && options.crv !== entry.crv)
3502
+ throw new JOSENotSupported(`Invalid or unsupported crv option provided, the only supported value for ${alg} is ${entry.crv}`);
3503
+ algorithm = entry.kty[0] === "RSA" ? {
3504
+ ...entry.subtle,
3505
+ publicExponent: Uint8Array.of(1, 0, 1),
3506
+ modulusLength: getModulusLengthOption(options)
3507
+ } : entry.subtle;
3508
+ }
3509
+ return crypto.subtle.generateKey(algorithm, extractable ?? false, [
3510
+ ...entry.usages[1],
3511
+ ...entry.usages[0]
3512
+ ]);
3513
+ }
3514
+
3515
+ // src/keys.ts
3516
+ var SIGNING_ALG = "ES256";
3517
+ async function generateSigningKey() {
3518
+ const { privateKey } = await generateKeyPair(SIGNING_ALG, { extractable: true });
3519
+ const jwk = await exportJWK(privateKey);
3520
+ return { ...jwk, alg: SIGNING_ALG, kid: await calculateJwkThumbprint(jwk) };
3521
+ }
3522
+ function assertPrivateSigningJwk(jwk) {
3523
+ if (jwk.kty !== "EC" || jwk.crv !== "P-256" || !jwk.d || !jwk.x || !jwk.y) {
3524
+ throw new Error('must be a private EC P-256 JWK (kty "EC", crv "P-256", with d, x and y)');
3525
+ }
3526
+ }
3527
+ async function importSigningKeys(jwk) {
3528
+ assertPrivateSigningJwk(jwk);
3529
+ const { d: _d, ...pub } = jwk;
3530
+ const kid = jwk.kid ?? await calculateJwkThumbprint(pub);
3531
+ const publicJwk = { kty: pub.kty, crv: pub.crv, x: pub.x, y: pub.y, alg: SIGNING_ALG, use: "sig", kid };
3532
+ return {
3533
+ privateKey: await importJWK({ ...jwk, alg: SIGNING_ALG }, SIGNING_ALG),
3534
+ publicKey: await importJWK(publicJwk, SIGNING_ALG),
3535
+ publicJwk,
3536
+ kid
3537
+ };
3538
+ }
3539
+
3540
+ // src/password.ts
3541
+ import { createHash, createHmac, hkdfSync, randomBytes, randomInt, scrypt, timingSafeEqual } from "crypto";
3542
+ var HASH_PARAMS = { logN: 15, r: 8, p: 3 };
3543
+ var KEY_LENGTH = 64;
3544
+ var SALT_LENGTH = 16;
3545
+ var MAX_PASSWORD_LENGTH = 256;
3546
+ var MAX_EMAIL_LENGTH = 254;
3547
+ function derive2(password, salt, { logN, r, p }) {
3548
+ const N = 2 ** logN;
3549
+ return new Promise(
3550
+ (resolve, reject) => scrypt(
3551
+ password.normalize("NFC"),
3552
+ salt,
3553
+ KEY_LENGTH,
3554
+ { N, r, p, maxmem: 256 * N * r + 1024 * 1024 },
3555
+ (err, key) => err ? reject(err) : resolve(key)
3556
+ )
3557
+ );
3558
+ }
3559
+ async function hashPassword(password, params = HASH_PARAMS) {
3560
+ const salt = randomBytes(SALT_LENGTH);
3561
+ const key = await derive2(password, salt, params);
3562
+ return ["scrypt", params.logN, params.r, params.p, salt.toString("base64url"), key.toString("base64url")].join("$");
3563
+ }
3564
+ async function verifyPassword(password, stored) {
3565
+ const [scheme, logN, r, p, salt, hash] = stored.split("$");
3566
+ const params = { logN: Number(logN), r: Number(r), p: Number(p) };
3567
+ if (scheme !== "scrypt" || !salt || !hash || !Object.values(params).every((n) => Number.isInteger(n) && n > 0)) {
3568
+ return { ok: false, needsRehash: false };
3569
+ }
3570
+ const expected = Buffer.from(hash, "base64url");
3571
+ const key = await derive2(password, Buffer.from(salt, "base64url"), params);
3572
+ const ok = key.length === expected.length && timingSafeEqual(key, expected);
3573
+ const needsRehash = params.logN !== HASH_PARAMS.logN || params.r !== HASH_PARAMS.r || params.p !== HASH_PARAMS.p;
3574
+ return { ok, needsRehash };
3575
+ }
3576
+ var dummyHash;
3577
+ async function verifyAgainstDummy(password) {
3578
+ dummyHash ??= hashPassword(randomBytes(16).toString("hex"));
3579
+ await verifyPassword(password, await dummyHash);
3580
+ }
3581
+ function checkPasswordPolicy(password, minLength) {
3582
+ if (typeof password !== "string") return "password is missing";
3583
+ const length = [...password].length;
3584
+ if (length < minLength) return `The password must have at least ${minLength} characters.`;
3585
+ if (length > MAX_PASSWORD_LENGTH) return `The password must have at most ${MAX_PASSWORD_LENGTH} characters.`;
3586
+ return null;
3587
+ }
3588
+ function normalizeEmail(email) {
3589
+ return email.trim().toLowerCase();
3590
+ }
3591
+ function isValidEmail(email) {
3592
+ return typeof email === "string" && email.trim().length <= MAX_EMAIL_LENGTH && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.trim());
3593
+ }
3594
+ function generateLinkToken() {
3595
+ return randomBytes(32).toString("base64url");
3596
+ }
3597
+ function hashLinkToken(token) {
3598
+ return createHash("sha256").update(token).digest("base64url");
3599
+ }
3600
+ function generateCode() {
3601
+ return randomInt(0, 1e6).toString().padStart(6, "0");
3602
+ }
3603
+ function deriveCodeKey(signingKeyD) {
3604
+ return Buffer.from(hkdfSync("sha256", Buffer.from(signingKeyD, "base64url"), "", "madauth e-mail code", 32));
3605
+ }
3606
+ function hashCode(key, code) {
3607
+ return createHmac("sha256", key).update(code).digest("base64url");
3608
+ }
3609
+ function safeEqual(a, b) {
3610
+ const x = Buffer.from(a);
3611
+ const y = Buffer.from(b);
3612
+ return x.length === y.length && timingSafeEqual(x, y);
3613
+ }
3614
+
3615
+ // src/google.ts
3616
+ var GOOGLE_ISSUERS = ["https://accounts.google.com", "accounts.google.com"];
3617
+ var googleJwks;
3618
+ function googleKeys() {
3619
+ googleJwks ??= createRemoteJWKSet(new URL("https://www.googleapis.com/oauth2/v3/certs"));
3620
+ return googleJwks;
3621
+ }
3622
+ async function verifyGoogleIdToken(idToken, opts) {
3623
+ let payload;
3624
+ try {
3625
+ ({ payload } = await jwtVerify(idToken, opts.keys ?? googleKeys(), {
3626
+ issuer: GOOGLE_ISSUERS,
3627
+ audience: opts.clientId,
3628
+ algorithms: ["RS256", "ES256"]
3629
+ }));
3630
+ } catch (e) {
3631
+ return { ok: false, error: "verification_failed", reason: e.message };
3632
+ }
3633
+ if (typeof payload.sub !== "string" || !payload.sub) {
3634
+ return { ok: false, error: "verification_failed", reason: "missing sub" };
3635
+ }
3636
+ if (payload.nonce !== opts.nonce) {
3637
+ return { ok: false, error: "verification_failed", reason: "nonce mismatch" };
3638
+ }
3639
+ if (payload.email_verified !== true) {
3640
+ return { ok: false, error: "email_unverified", reason: "e-mail address not verified" };
3641
+ }
3642
+ const user = { id: `google:${payload.sub}` };
3643
+ if (typeof payload.email === "string") user.email = payload.email;
3644
+ if (typeof payload.name === "string") user.name = payload.name;
3645
+ if (typeof payload.picture === "string") user.picture = payload.picture;
3646
+ return { ok: true, user };
3647
+ }
3648
+
3649
+ // src/user.ts
3650
+ var SESSION_COOKIE = "madauth_session";
3651
+ var SESSION_TYP = "madauth-session+jwt";
3652
+
3653
+ // src/tokens.ts
3654
+ function randomString(bytes = 32) {
3655
+ return base64url_exports.encode(crypto.getRandomValues(new Uint8Array(bytes)));
3656
+ }
3657
+ async function signToken(keys, issuer, typ, claims, ttlSeconds) {
3658
+ return new SignJWT(claims).setProtectedHeader({ alg: SIGNING_ALG, kid: keys.kid, typ }).setIssuer(issuer).setIssuedAt().setExpirationTime(`${ttlSeconds}s`).sign(keys.privateKey);
3659
+ }
3660
+ async function readToken(keys, issuer, typ, token) {
3661
+ if (!token) return null;
3662
+ try {
3663
+ const { payload } = await jwtVerify(token, keys.publicKey, { issuer, typ, algorithms: [SIGNING_ALG] });
3664
+ return payload;
3665
+ } catch {
3666
+ return null;
3667
+ }
3668
+ }
3669
+ function signSession(keys, issuer, ttlSeconds, user, amr, extra = {}) {
3670
+ const claims = {
3671
+ ...extra,
3672
+ sub: user.id,
3673
+ email: user.email,
3674
+ email_verified: user.email ? true : void 0,
3675
+ name: user.name,
3676
+ picture: user.picture,
3677
+ amr
3678
+ };
3679
+ return signToken(keys, issuer, SESSION_TYP, claims, ttlSeconds);
3680
+ }
3681
+ function userFromClaims(claims) {
3682
+ const user = { id: claims.sub };
3683
+ if (claims.email) user.email = claims.email;
3684
+ if (claims.name) user.name = claims.name;
3685
+ if (claims.picture) user.picture = claims.picture;
3686
+ return user;
3687
+ }
3688
+
3689
+ // src/routes/google.ts
3690
+ var NONCE_COOKIE = "madauth_nonce";
3691
+ var NONCE_TYP = "madauth-nonce+jwt";
3692
+ var NONCE_TTL = 5 * 60;
3693
+ var OAUTH_COOKIE = "madauth_oauth";
3694
+ var OAUTH_TYP = "madauth-oauth-state+jwt";
3695
+ var OAUTH_TTL = 10 * 60;
3696
+ var GOOGLE_AUTH_ENDPOINT = "https://accounts.google.com/o/oauth2/v2/auth";
3697
+ var GOOGLE_TOKEN_ENDPOINT = "https://oauth2.googleapis.com/token";
3698
+ var REDIRECT_ERROR_PARAM = "madauth_error";
3699
+ async function pkceChallenge(verifier) {
3700
+ const digest2 = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier));
3701
+ return base64url_exports.encode(new Uint8Array(digest2));
3702
+ }
3703
+ function googleRoutes(app, ctx, google) {
3704
+ const { config, keys, secure } = ctx;
3705
+ const { issuer } = config;
3706
+ const callbackUrl = `${issuer}/auth/google/callback`;
3707
+ app.post("/auth/google/nonce", async (c) => {
3708
+ const nonce = randomString();
3709
+ const token = await signToken(await keys, issuer, NONCE_TYP, { nonce }, NONCE_TTL);
3710
+ setCookie(c, NONCE_COOKIE, token, {
3711
+ path: "/auth/google",
3712
+ httpOnly: true,
3713
+ secure,
3714
+ sameSite: "Strict",
3715
+ maxAge: NONCE_TTL
3716
+ });
3717
+ return c.json({ nonce });
3718
+ });
3719
+ app.post("/auth/google/verify", async (c) => {
3720
+ const body = await c.req.json().catch(() => ({}));
3721
+ if (typeof body.credential !== "string" || !body.credential) {
3722
+ return c.json({ error: "verification_failed", message: "credential is missing" }, 400);
3723
+ }
3724
+ const nonceClaims = await readToken(await keys, issuer, NONCE_TYP, getCookie(c, NONCE_COOKIE));
3725
+ if (!nonceClaims) {
3726
+ return c.json({ error: "verification_failed", message: "nonce cookie missing or expired" }, 401);
3727
+ }
3728
+ const result = await verifyGoogleIdToken(body.credential, {
3729
+ clientId: google.clientId,
3730
+ nonce: nonceClaims.nonce,
3731
+ keys: config.jwksResolver
3732
+ });
3733
+ if (!result.ok) {
3734
+ return c.json({ error: result.error, message: result.reason }, result.error === "email_unverified" ? 403 : 401);
3735
+ }
3736
+ deleteCookie(c, NONCE_COOKIE, { path: "/auth/google", secure });
3737
+ await ctx.startSession(c, result.user, ["google"]);
3738
+ await ctx.emit("user.signed_in", { user: result.user, method: "google" });
3739
+ return c.json({ user: result.user });
3740
+ });
3741
+ const requireCodeFlow = async (c, next) => {
3742
+ if (!google.clientSecret) return c.json({ error: "not_found" }, 404);
3743
+ await next();
3744
+ };
3745
+ app.get("/auth/google/start", requireCodeFlow, async (c) => {
3746
+ const returnUrl = ctx.allowedUrl(c.req.query("return_to"));
3747
+ if (!returnUrl) return c.text("return_to must be an absolute URL whose origin is in ALLOWED_ORIGINS", 400);
3748
+ const oauth = {
3749
+ state: randomString(),
3750
+ nonce: randomString(),
3751
+ verifier: randomString(),
3752
+ returnTo: returnUrl.href
3753
+ };
3754
+ const token = await signToken(await keys, issuer, OAUTH_TYP, { ...oauth }, OAUTH_TTL);
3755
+ setCookie(c, OAUTH_COOKIE, token, {
3756
+ path: "/auth/google",
3757
+ httpOnly: true,
3758
+ secure,
3759
+ sameSite: "Lax",
3760
+ maxAge: OAUTH_TTL
3761
+ });
3762
+ const url = new URL(GOOGLE_AUTH_ENDPOINT);
3763
+ url.search = new URLSearchParams({
3764
+ client_id: google.clientId,
3765
+ redirect_uri: callbackUrl,
3766
+ response_type: "code",
3767
+ scope: "openid email profile",
3768
+ state: oauth.state,
3769
+ nonce: oauth.nonce,
3770
+ code_challenge: await pkceChallenge(oauth.verifier),
3771
+ code_challenge_method: "S256"
3772
+ }).toString();
3773
+ return c.redirect(url.href, 302);
3774
+ });
3775
+ app.get("/auth/google/callback", requireCodeFlow, async (c) => {
3776
+ const oauth = await readToken(await keys, issuer, OAUTH_TYP, getCookie(c, OAUTH_COOKIE));
3777
+ if (!oauth) return c.text("Sign-in expired or was started in another browser. Please try again.", 400);
3778
+ deleteCookie(c, OAUTH_COOKIE, { path: "/auth/google", secure });
3779
+ const back = (error) => {
3780
+ const url = new URL(oauth.returnTo);
3781
+ if (error) url.hash = `${REDIRECT_ERROR_PARAM}=${error}`;
3782
+ return c.redirect(url.href, 302);
3783
+ };
3784
+ if (c.req.query("error")) return back(c.req.query("error") === "access_denied" ? "cancelled" : "verification_failed");
3785
+ const code = c.req.query("code");
3786
+ if (!code || c.req.query("state") !== oauth.state) return back("verification_failed");
3787
+ let idToken;
3788
+ try {
3789
+ const res = await fetch(GOOGLE_TOKEN_ENDPOINT, {
3790
+ method: "POST",
3791
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
3792
+ body: new URLSearchParams({
3793
+ code,
3794
+ client_id: google.clientId,
3795
+ client_secret: google.clientSecret,
3796
+ redirect_uri: callbackUrl,
3797
+ grant_type: "authorization_code",
3798
+ code_verifier: oauth.verifier
3799
+ })
3800
+ });
3801
+ if (!res.ok) return back("verification_failed");
3802
+ ({ id_token: idToken } = await res.json());
3803
+ } catch {
3804
+ return back("verification_failed");
3805
+ }
3806
+ if (typeof idToken !== "string") return back("verification_failed");
3807
+ const result = await verifyGoogleIdToken(idToken, {
3808
+ clientId: google.clientId,
3809
+ nonce: oauth.nonce,
3810
+ keys: config.jwksResolver
3811
+ });
3812
+ if (!result.ok) return back(result.error);
3813
+ await ctx.startSession(c, result.user, ["google"]);
3814
+ await ctx.emit("user.signed_in", { user: result.user, method: "google" });
3815
+ return back();
3816
+ });
3817
+ }
3818
+
3819
+ // src/routes/password.ts
3820
+ var FREE_ATTEMPTS = 5;
3821
+ var MAX_LOCK_MS = 15 * 60 * 1e3;
3822
+ var MAIL_INTERVAL_MS = 60 * 1e3;
3823
+ var VERIFY_TTL_MS = 24 * 60 * 60 * 1e3;
3824
+ var RESET_TTL_MS = 30 * 60 * 1e3;
3825
+ var WEBHOOK_TIMEOUT_MS = 1e4;
3826
+ var VERIFY_LINK_PARAM = "madauth_verify";
3827
+ var RESET_LINK_PARAM = "madauth_reset";
3828
+ var MAX_NAME_LENGTH = 100;
3829
+ var MAX_LOCALE_LENGTH = 35;
3830
+ function toMadauthUser(user) {
3831
+ const result = { id: user.id, email: user.email };
3832
+ if (user.name) result.name = user.name;
3833
+ return result;
3834
+ }
3835
+ function passwordRoutes(app, ctx, password, users, webhook) {
3836
+ const { minLength } = password;
3837
+ const body = async (c) => {
3838
+ const data = await c.req.json().catch(() => null);
3839
+ return data && typeof data === "object" ? data : {};
3840
+ };
3841
+ const error = (c, status, code, message2) => c.json({ error: code, message: message2 }, status);
3842
+ const unavailable = (c) => error(c, 503, "temporarily_unavailable", "E-mails can not be sent right now. Please try again later.");
3843
+ const accepted = (c) => c.json({}, 202);
3844
+ const redirectTarget = (c, value) => {
3845
+ const url = ctx.allowedUrl(value);
3846
+ return url ?? error(c, 400, "invalid_options", "redirectTo must be an absolute URL whose origin is in ALLOWED_ORIGINS.");
3847
+ };
3848
+ const sendEmail = async (user, type, data) => {
3849
+ if (Date.now() - user.lastMailAt < MAIL_INTERVAL_MS) return true;
3850
+ const result = await webhook.call(type, { to: user.email, user: { id: user.id, name: user.name ?? void 0 }, ...data }, WEBHOOK_TIMEOUT_MS);
3851
+ if (!result.ok) {
3852
+ console.error(`[madauth] Webhook "${type}" for ${user.email} failed: ${result.reason}`);
3853
+ return false;
3854
+ }
3855
+ await users.updateUser(user.id, { lastMailAt: Date.now() });
3856
+ return true;
3857
+ };
3858
+ const sendLinkEmail = async (user, purpose, target, locale) => {
3859
+ if (Date.now() - user.lastMailAt < MAIL_INTERVAL_MS) return true;
3860
+ const ttl = purpose === "verify" ? VERIFY_TTL_MS : RESET_TTL_MS;
3861
+ const { token, code } = await users.issueVerification(user.id, purpose, ttl);
3862
+ const link = new URL(target);
3863
+ link.hash = `${purpose === "verify" ? VERIFY_LINK_PARAM : RESET_LINK_PARAM}=${token}`;
3864
+ return sendEmail(user, purpose === "verify" ? "email.verify" : "email.reset", {
3865
+ link: link.href,
3866
+ code,
3867
+ expiresAt: Date.now() + ttl,
3868
+ site: target.host,
3869
+ locale
3870
+ });
3871
+ };
3872
+ const localeOf = (data) => typeof data.locale === "string" && data.locale.length <= MAX_LOCALE_LENGTH ? data.locale : void 0;
3873
+ const consume = async (data, purpose) => {
3874
+ if (typeof data.token === "string" && data.token) {
3875
+ return { userId: await users.consumeLinkToken(data.token, purpose), via: "link" };
3876
+ }
3877
+ if (isValidEmail(data.email) && typeof data.code === "string") {
3878
+ const user = await users.findByEmail(normalizeEmail(data.email));
3879
+ const code = data.code.replace(/\s/g, "");
3880
+ return { userId: user ? await users.consumeCode(user.id, purpose, code) : null, via: "code" };
3881
+ }
3882
+ return { userId: null, via: "code" };
3883
+ };
3884
+ const invalidVerification = (c, via) => via === "link" ? error(c, 400, "link_invalid", "The link is invalid, expired or was already used.") : error(c, 400, "code_invalid", "The code is wrong or expired.");
3885
+ app.post("/auth/password/signin", async (c) => {
3886
+ const data = await body(c);
3887
+ const wrong = () => error(c, 401, "invalid_credentials", "E-mail or password is wrong.");
3888
+ const pw = typeof data.password === "string" ? data.password : "";
3889
+ if (!isValidEmail(data.email) || !pw || pw.length > MAX_PASSWORD_LENGTH * 4) return wrong();
3890
+ const user = await users.findByEmail(normalizeEmail(data.email));
3891
+ const account = user ? await users.passwordAccount(user.id) : null;
3892
+ if (!user || !account?.secret) {
3893
+ await verifyAgainstDummy(pw);
3894
+ return wrong();
3895
+ }
3896
+ const now = Date.now();
3897
+ if (account.lockedUntil > now) {
3898
+ const seconds = Math.ceil((account.lockedUntil - now) / 1e3);
3899
+ return error(c, 429, "too_many_attempts", `Too many failed attempts. Try again in ${seconds} seconds.`);
3900
+ }
3901
+ const failed = account.failedAttempts + 1;
3902
+ const lockedUntil = failed >= FREE_ATTEMPTS ? now + Math.min(2 ** (failed - FREE_ATTEMPTS) * 1e3, MAX_LOCK_MS) : 0;
3903
+ if (!await users.countAttempt(account, { failedAttempts: failed, lockedUntil })) {
3904
+ return error(c, 429, "too_many_attempts", "Too many attempts at once. Please try again.");
3905
+ }
3906
+ const { ok, needsRehash } = await verifyPassword(pw, account.secret);
3907
+ if (!ok) return wrong();
3908
+ await users.updateAccount(account.id, {
3909
+ failedAttempts: 0,
3910
+ lockedUntil: 0,
3911
+ ...needsRehash ? { secret: await hashPassword(pw) } : {}
3912
+ });
3913
+ if (!user.emailVerified) {
3914
+ return error(c, 403, "email_unverified", "Please confirm your e-mail address first. We can send the e-mail again.");
3915
+ }
3916
+ const result = toMadauthUser(user);
3917
+ await ctx.startSession(c, result, ["pwd"], { sv: user.sessionVersion });
3918
+ await ctx.emit("user.signed_in", { user: result, method: "password" });
3919
+ return c.json({ user: result });
3920
+ });
3921
+ app.post("/auth/password/signup", async (c) => {
3922
+ const data = await body(c);
3923
+ const target = redirectTarget(c, data.redirectTo);
3924
+ if (target instanceof Response) return target;
3925
+ if (!isValidEmail(data.email)) return error(c, 400, "invalid_email", "This is not a valid e-mail address.");
3926
+ const policy = checkPasswordPolicy(data.password, minLength);
3927
+ if (policy) return error(c, 400, "weak_password", policy);
3928
+ const name = typeof data.name === "string" && data.name.trim() ? data.name.trim().slice(0, MAX_NAME_LENGTH) : null;
3929
+ const email = data.email.trim();
3930
+ const locale = localeOf(data);
3931
+ if (webhook.wants("signup.before")) {
3932
+ const check2 = await webhook.call("signup.before", { email, name: name ?? void 0, locale }, WEBHOOK_TIMEOUT_MS);
3933
+ if (!check2.ok) {
3934
+ console.error(`[madauth] Webhook "signup.before" failed: ${check2.reason}`);
3935
+ return unavailable(c);
3936
+ }
3937
+ const answer = check2.body;
3938
+ if (answer?.allow === false) {
3939
+ const message2 = typeof answer.message === "string" && answer.message ? answer.message : "Sign-up is not possible with this e-mail address.";
3940
+ return error(c, 403, "signup_rejected", message2);
3941
+ }
3942
+ }
3943
+ const passwordHash = await hashPassword(data.password);
3944
+ const existing = await users.findByEmail(normalizeEmail(email));
3945
+ if (existing?.emailVerified) {
3946
+ const sent = await sendEmail(existing, "email.already_registered", { link: target.href, site: target.host, locale });
3947
+ return sent ? accepted(c) : unavailable(c);
3948
+ }
3949
+ if (existing) {
3950
+ if (Date.now() - existing.lastMailAt < MAIL_INTERVAL_MS) return accepted(c);
3951
+ const account = await users.passwordAccount(existing.id);
3952
+ if (account) await users.updateAccount(account.id, { secret: passwordHash, failedAttempts: 0, lockedUntil: 0 });
3953
+ await users.updateUser(existing.id, { name });
3954
+ return await sendLinkEmail({ ...existing, name }, "verify", target, locale) ? accepted(c) : unavailable(c);
3955
+ }
3956
+ const user = await users.createPasswordUser({
3957
+ email,
3958
+ emailNormalized: normalizeEmail(email),
3959
+ name,
3960
+ passwordHash,
3961
+ emailVerified: false
3962
+ });
3963
+ if (!user) return accepted(c);
3964
+ await ctx.emit("user.created", { user: toMadauthUser(user) });
3965
+ return await sendLinkEmail(user, "verify", target, locale) ? accepted(c) : unavailable(c);
3966
+ });
3967
+ app.post("/auth/password/send-verification", async (c) => {
3968
+ const data = await body(c);
3969
+ const target = redirectTarget(c, data.redirectTo);
3970
+ if (target instanceof Response) return target;
3971
+ if (!isValidEmail(data.email)) return error(c, 400, "invalid_email", "This is not a valid e-mail address.");
3972
+ const user = await users.findByEmail(normalizeEmail(data.email));
3973
+ if (user && !user.emailVerified && await users.passwordAccount(user.id)) {
3974
+ if (!await sendLinkEmail(user, "verify", target, localeOf(data))) return unavailable(c);
3975
+ }
3976
+ return accepted(c);
3977
+ });
3978
+ app.post("/auth/password/verify-email", async (c) => {
3979
+ const { userId, via } = await consume(await body(c), "verify");
3980
+ const user = userId ? await users.findById(userId) : null;
3981
+ if (!user) return invalidVerification(c, via);
3982
+ await users.updateUser(user.id, { emailVerified: true });
3983
+ const result = toMadauthUser(user);
3984
+ await ctx.startSession(c, result, ["pwd"], { sv: user.sessionVersion });
3985
+ await ctx.emit("email.verified", { user: result, via });
3986
+ await ctx.emit("user.signed_in", { user: result, method: "password" });
3987
+ return c.json({ user: result });
3988
+ });
3989
+ app.post("/auth/password/send-reset", async (c) => {
3990
+ const data = await body(c);
3991
+ const target = redirectTarget(c, data.redirectTo);
3992
+ if (target instanceof Response) return target;
3993
+ if (!isValidEmail(data.email)) return error(c, 400, "invalid_email", "This is not a valid e-mail address.");
3994
+ const user = await users.findByEmail(normalizeEmail(data.email));
3995
+ if (user && await users.passwordAccount(user.id)) {
3996
+ if (!await sendLinkEmail(user, "reset", target, localeOf(data))) return unavailable(c);
3997
+ }
3998
+ return accepted(c);
3999
+ });
4000
+ app.post("/auth/password/reset", async (c) => {
4001
+ const data = await body(c);
4002
+ const policy = checkPasswordPolicy(data.password, minLength);
4003
+ if (policy) return error(c, 400, "weak_password", policy);
4004
+ const { userId, via } = await consume(data, "reset");
4005
+ const user = userId ? await users.findById(userId) : null;
4006
+ const account = user ? await users.passwordAccount(user.id) : null;
4007
+ if (!user || !account) return invalidVerification(c, via);
4008
+ await users.updateAccount(account.id, { secret: await hashPassword(data.password), failedAttempts: 0, lockedUntil: 0 });
4009
+ const sessionVersion = user.sessionVersion + 1;
4010
+ await users.updateUser(user.id, { emailVerified: true, sessionVersion });
4011
+ await users.clearVerifications(user.id);
4012
+ const result = toMadauthUser(user);
4013
+ await ctx.startSession(c, result, ["pwd"], { sv: sessionVersion });
4014
+ await ctx.emit("password.reset", { user: result });
4015
+ await ctx.emit("user.signed_in", { user: result, method: "password" });
4016
+ return c.json({ user: result });
4017
+ });
4018
+ }
4019
+
4020
+ // src/users.ts
4021
+ import { randomBytes as randomBytes2 } from "crypto";
4022
+ var MAX_CODE_ATTEMPTS = 5;
4023
+ var newId = (prefix) => `${prefix}_${randomBytes2(16).toString("base64url")}`;
4024
+ function passwordAccountKey(userId) {
4025
+ return `password:${userId}`;
4026
+ }
4027
+ var Users = class {
4028
+ /** `codeKey` keys the e-mail codes (see deriveCodeKey); only needed to issue and check them. */
4029
+ constructor(store, codeKey) {
4030
+ this.store = store;
4031
+ this.codeKey = codeKey;
4032
+ }
4033
+ get key() {
4034
+ if (!this.codeKey) throw new Error("Users needs a code key to issue or check e-mail codes.");
4035
+ return this.codeKey;
4036
+ }
4037
+ async findByEmail(emailNormalized) {
4038
+ return await this.store.findOne("user", { emailNormalized });
4039
+ }
4040
+ async findById(id) {
4041
+ return await this.store.findOne("user", { id });
4042
+ }
4043
+ async passwordAccount(userId) {
4044
+ return await this.store.findOne("account", { key: passwordAccountKey(userId) });
4045
+ }
4046
+ /** Creates a user with a password. Resolves to null if the e-mail address is taken. */
4047
+ async createPasswordUser(data) {
4048
+ const now = Date.now();
4049
+ const user = {
4050
+ id: newId("usr"),
4051
+ email: data.email,
4052
+ emailNormalized: data.emailNormalized,
4053
+ emailVerified: data.emailVerified,
4054
+ name: data.name,
4055
+ sessionVersion: 0,
4056
+ lastMailAt: 0,
4057
+ createdAt: now
4058
+ };
4059
+ if (!await this.store.create("user", user)) return null;
4060
+ const account = {
4061
+ id: newId("acc"),
4062
+ userId: user.id,
4063
+ key: passwordAccountKey(user.id),
4064
+ secret: data.passwordHash,
4065
+ failedAttempts: 0,
4066
+ lockedUntil: 0,
4067
+ createdAt: now
4068
+ };
4069
+ if (!await this.store.create("account", account)) {
4070
+ await this.store.delete("user", { id: user.id });
4071
+ return null;
4072
+ }
4073
+ return user;
4074
+ }
4075
+ async updateUser(id, patch) {
4076
+ await this.store.update("user", { id }, patch);
4077
+ }
4078
+ async updateAccount(id, patch) {
4079
+ await this.store.update("account", { id }, patch);
4080
+ }
4081
+ /**
4082
+ * Counts a sign-in attempt: writes `patch` only if the account's `failedAttempts` is still the value that
4083
+ * was read. Resolves to false if another request counted an attempt meanwhile.
4084
+ */
4085
+ async countAttempt(account, patch) {
4086
+ const changed = await this.store.update("account", { id: account.id, failedAttempts: account.failedAttempts }, patch);
4087
+ return changed === 1;
4088
+ }
4089
+ /** Deletes the user's pending verifications and password resets; their links and codes stop working. */
4090
+ async clearVerifications(userId) {
4091
+ await this.store.delete("verification", { userId });
4092
+ }
4093
+ /**
4094
+ * Starts a verification or password reset: replaces the user's earlier one for the same purpose and
4095
+ * returns the link token and the code for the e-mail. Only their hashes are stored.
4096
+ */
4097
+ async issueVerification(userId, purpose, ttlMs) {
4098
+ await this.store.delete("verification", { userId, purpose });
4099
+ const token = generateLinkToken();
4100
+ const code = generateCode();
4101
+ const record = {
4102
+ id: hashLinkToken(token),
4103
+ userId,
4104
+ purpose,
4105
+ codeHash: hashCode(this.key, code),
4106
+ attempts: 0,
4107
+ expiresAt: Date.now() + ttlMs
4108
+ };
4109
+ await this.store.create("verification", record);
4110
+ return { token, code };
4111
+ }
4112
+ /** Uses up the verification a link token belongs to. Resolves to its user ID, or null if invalid, expired or used. */
4113
+ async consumeLinkToken(token, purpose) {
4114
+ const id = hashLinkToken(token);
4115
+ const record = await this.store.findOne("verification", { id, purpose });
4116
+ return record ? this.consume(record) : null;
4117
+ }
4118
+ /** Uses up the user's verification if `code` matches. Too many wrong codes delete it. */
4119
+ async consumeCode(userId, purpose, code) {
4120
+ const record = await this.store.findOne("verification", { userId, purpose });
4121
+ if (!record) return null;
4122
+ const attempts = record.attempts + 1;
4123
+ if (await this.store.update("verification", { id: record.id, attempts: record.attempts }, { attempts }) !== 1) return null;
4124
+ if (!safeEqual(hashCode(this.key, code), record.codeHash)) {
4125
+ if (attempts >= MAX_CODE_ATTEMPTS) await this.store.delete("verification", { id: record.id });
4126
+ return null;
4127
+ }
4128
+ return this.consume(record);
4129
+ }
4130
+ async consume(record) {
4131
+ const deleted = await this.store.delete("verification", { id: record.id });
4132
+ if (deleted !== 1 || record.expiresAt <= Date.now()) return null;
4133
+ return record.userId;
4134
+ }
4135
+ };
4136
+
4137
+ // src/webhooks.ts
4138
+ import { createHmac as createHmac2, randomBytes as randomBytes3, randomUUID, timingSafeEqual as timingSafeEqual2 } from "crypto";
4139
+ var WEBHOOK_TYPES = [
4140
+ "email.verify",
4141
+ "email.reset",
4142
+ "email.already_registered",
4143
+ "signup.before",
4144
+ "user.created",
4145
+ "email.verified",
4146
+ "password.reset",
4147
+ "user.signed_in"
4148
+ ];
4149
+ var isEmailType = (type) => type.startsWith("email.") && type !== "email.verified";
4150
+ var SECRET_PREFIX = "whsec_";
4151
+ var WEBHOOK_TOLERANCE_SECONDS = 5 * 60;
4152
+ function generateWebhookSecret() {
4153
+ return `${SECRET_PREFIX}${randomBytes3(32).toString("base64")}`;
4154
+ }
4155
+ function checkWebhookSecret(secret) {
4156
+ if (!secret.startsWith(SECRET_PREFIX)) return `must start with "${SECRET_PREFIX}"`;
4157
+ const key = Buffer.from(secret.slice(SECRET_PREFIX.length), "base64");
4158
+ if (key.length < 24 || key.length > 64) return "must contain 24 to 64 bytes in base64";
4159
+ return null;
4160
+ }
4161
+ function hmac2(secret, content) {
4162
+ const key = Buffer.from(secret.slice(SECRET_PREFIX.length), "base64");
4163
+ return createHmac2("sha256", key).update(content).digest("base64");
4164
+ }
4165
+ function signWebhook(secret, id, timestamp, body) {
4166
+ return `v1,${hmac2(secret, `${id}.${timestamp}.${body}`)}`;
4167
+ }
4168
+ function createWebhookClient(settings, fetchImpl = fetch) {
4169
+ const wants = (type) => isEmailType(type) || !settings.events || settings.events.has(type);
4170
+ return {
4171
+ wants,
4172
+ async call(type, data, timeoutMs) {
4173
+ if (!wants(type)) return { ok: true, body: void 0 };
4174
+ const id = `msg_${randomUUID()}`;
4175
+ const timestamp = Math.floor(Date.now() / 1e3);
4176
+ const body = JSON.stringify({ type, data });
4177
+ let response;
4178
+ try {
4179
+ response = await fetchImpl(settings.url, {
4180
+ method: "POST",
4181
+ headers: {
4182
+ "Content-Type": "application/json",
4183
+ "webhook-id": id,
4184
+ "webhook-timestamp": String(timestamp),
4185
+ "webhook-signature": signWebhook(settings.secret, id, timestamp, body)
4186
+ },
4187
+ body,
4188
+ signal: AbortSignal.timeout(timeoutMs)
4189
+ });
4190
+ } catch (e) {
4191
+ const reason = e.name === "TimeoutError" ? `no answer within ${timeoutMs} ms` : e.message;
4192
+ return { ok: false, reason };
4193
+ }
4194
+ const text = await response.text().catch(() => "");
4195
+ if (!response.ok) return { ok: false, reason: `HTTP ${response.status}` };
4196
+ let parsed;
4197
+ try {
4198
+ parsed = text ? JSON.parse(text) : void 0;
4199
+ } catch {
4200
+ parsed = void 0;
4201
+ }
4202
+ return { ok: true, body: parsed };
4203
+ }
4204
+ };
4205
+ }
4206
+
4207
+ // src/app.ts
4208
+ var EVENT_TIMEOUT_MS = 5e3;
4209
+ function createApp(config) {
4210
+ const { issuer, allowedOrigins, sessionTtlSeconds, cookieDomain } = config;
4211
+ const keys = importSigningKeys(config.signingKey);
4212
+ const secure = issuer.startsWith("https:");
4213
+ const isAllowedOrigin = (origin) => !!origin && allowedOrigins.includes(origin);
4214
+ const ctx = {
4215
+ config,
4216
+ keys,
4217
+ secure,
4218
+ isAllowedOrigin,
4219
+ allowedUrl(value) {
4220
+ let url;
4221
+ try {
4222
+ url = new URL(typeof value === "string" ? value : "");
4223
+ } catch {
4224
+ return null;
4225
+ }
4226
+ if (!isAllowedOrigin(url.origin)) return null;
4227
+ url.hash = "";
4228
+ return url;
4229
+ },
4230
+ async startSession(c, user, amr, extra) {
4231
+ const token = await signSession(await keys, issuer, sessionTtlSeconds, user, amr, extra);
4232
+ setCookie(c, SESSION_COOKIE, token, {
4233
+ path: "/",
4234
+ domain: cookieDomain,
4235
+ httpOnly: true,
4236
+ secure,
4237
+ sameSite: "Lax",
4238
+ maxAge: sessionTtlSeconds
4239
+ });
4240
+ },
4241
+ users: config.password ? new Users(config.password.store, deriveCodeKey(config.signingKey.d)) : void 0,
4242
+ webhook: config.webhook ? createWebhookClient(config.webhook, config.webhookFetch) : void 0,
4243
+ async emit(type, data) {
4244
+ if (!this.webhook?.wants(type)) return;
4245
+ const result = await this.webhook.call(type, data, EVENT_TIMEOUT_MS);
4246
+ if (!result.ok) console.error(`[madauth] Webhook "${type}" failed: ${result.reason}`);
4247
+ }
4248
+ };
4249
+ const app = new Hono3();
4250
+ app.use(
4251
+ "/auth/*",
4252
+ cors({
4253
+ origin: (origin) => isAllowedOrigin(origin) ? origin : null,
4254
+ credentials: true,
4255
+ allowMethods: ["GET", "POST"],
4256
+ allowHeaders: ["Content-Type"],
4257
+ maxAge: 600
4258
+ })
4259
+ );
4260
+ app.use("/auth/*", async (c, next) => {
4261
+ if (c.req.method === "POST" && !isAllowedOrigin(c.req.header("origin"))) {
4262
+ return c.json({ error: "forbidden_origin" }, 403);
4263
+ }
4264
+ await next();
4265
+ });
4266
+ app.get("/health", (c) => c.text("ok"));
4267
+ app.get("/.well-known/jwks.json", async (c) => {
4268
+ const { publicJwk } = await keys;
4269
+ c.header("Cache-Control", "public, max-age=3600");
4270
+ return c.json({ keys: [publicJwk] });
4271
+ });
4272
+ app.get(
4273
+ "/auth/config",
4274
+ (c) => c.json({
4275
+ google: config.google ? { clientId: config.google.clientId, codeFlow: !!config.google.clientSecret } : null,
4276
+ password: config.password ? { minLength: config.password.minLength } : null
4277
+ })
4278
+ );
4279
+ if (config.google) googleRoutes(app, ctx, config.google);
4280
+ if (config.password && ctx.users && ctx.webhook) passwordRoutes(app, ctx, config.password, ctx.users, ctx.webhook);
4281
+ app.get("/auth/session", async (c) => {
4282
+ const claims = await readToken(await keys, issuer, SESSION_TYP, getCookie(c, SESSION_COOKIE));
4283
+ if (!claims) return c.json({ error: "no_session" }, 401);
4284
+ if (claims.sub.startsWith("usr_")) {
4285
+ const stored = await ctx.users?.findById(claims.sub);
4286
+ if (!stored || stored.sessionVersion !== claims.sv) return c.json({ error: "no_session" }, 401);
4287
+ }
4288
+ const user = userFromClaims(claims);
4289
+ if (Date.now() / 1e3 - claims.iat > sessionTtlSeconds / 2) await ctx.startSession(c, user, claims.amr, { sv: claims.sv });
4290
+ return c.json({ user });
4291
+ });
4292
+ app.post("/auth/logout", (c) => {
4293
+ deleteCookie(c, SESSION_COOKIE, { path: "/", domain: cookieDomain, secure });
4294
+ return c.body(null, 204);
4295
+ });
4296
+ return app;
4297
+ }
4298
+
4299
+ // src/config.ts
4300
+ var DEFAULT_SESSION_TTL = 8 * 60 * 60;
4301
+ var DEFAULT_PASSWORD_MIN_LENGTH = 8;
4302
+ var ConfigError = class extends Error {
4303
+ constructor() {
4304
+ super(...arguments);
4305
+ this.name = "ConfigError";
4306
+ }
4307
+ };
4308
+ function parseOrigin(name, value) {
4309
+ let url;
4310
+ try {
4311
+ url = new URL(value);
4312
+ } catch {
4313
+ throw new ConfigError(`${name}: "${value}" is not a URL.`);
4314
+ }
4315
+ if (url.protocol !== "https:" && url.protocol !== "http:") {
4316
+ throw new ConfigError(`${name}: "${value}" must be an http(s) URL.`);
4317
+ }
4318
+ return url.origin;
4319
+ }
4320
+ function readEnv(env, name) {
4321
+ return env[name]?.trim().replace(/^(['"])(.*)\1$/s, "$2").trim() || void 0;
4322
+ }
4323
+ async function loadConfig(env, overrides = {}) {
4324
+ const read = (name) => readEnv(env, name);
4325
+ const require2 = (name) => {
4326
+ const value = read(name);
4327
+ if (!value) throw new ConfigError(`${name} is not set. See docs/server.md.`);
4328
+ return value;
4329
+ };
4330
+ const issuerValue = require2("MADAUTH_ISSUER");
4331
+ parseOrigin("MADAUTH_ISSUER", issuerValue);
4332
+ const issuer = issuerValue.replace(/\/+$/, "");
4333
+ const keyValue = read("MADAUTH_SIGNING_KEY");
4334
+ if (!keyValue) {
4335
+ const key = await generateSigningKey();
4336
+ throw new ConfigError(
4337
+ `MADAUTH_SIGNING_KEY is not set. Here is a newly generated key you can use (keep it secret and use the same key on every instance):
4338
+
4339
+ MADAUTH_SIGNING_KEY='${JSON.stringify(key)}'
4340
+ `
4341
+ );
4342
+ }
4343
+ let signingKey;
4344
+ try {
4345
+ signingKey = JSON.parse(keyValue);
4346
+ assertPrivateSigningJwk(signingKey);
4347
+ } catch (e) {
4348
+ const reason = e instanceof SyntaxError ? "is not valid JSON" : e.message;
4349
+ throw new ConfigError(`MADAUTH_SIGNING_KEY ${reason}. Generate one with: npx @madauth/server generate-key`);
4350
+ }
4351
+ const allowedOrigins = require2("ALLOWED_ORIGINS").split(",").map((o) => o.trim()).filter(Boolean).map((o) => parseOrigin("ALLOWED_ORIGINS", o));
4352
+ const clientId = read("GOOGLE_CLIENT_ID");
4353
+ if (clientId && !clientId.endsWith(".apps.googleusercontent.com")) {
4354
+ throw new ConfigError(`GOOGLE_CLIENT_ID must end with ".apps.googleusercontent.com" but is "${clientId}".`);
4355
+ }
4356
+ const webhook = webhookFromEnv(read("WEBHOOK_URL"), read("WEBHOOK_SECRET"), read("WEBHOOK_EVENTS"));
4357
+ const store = overrides.store ?? await storeFromDatabaseUrl(read("DATABASE_URL"));
4358
+ let password;
4359
+ if (store) {
4360
+ if (!webhook) {
4361
+ throw new ConfigError(
4362
+ 'WEBHOOK_URL is not set. E-mail & password sign-in sends its e-mails through your webhook. For development, run the example receiver (npm run dev:webhooks) and set WEBHOOK_URL=http://localhost:8790/webhook. See "Webhooks" in docs/server.md.'
4363
+ );
4364
+ }
4365
+ password = { minLength: passwordMinLength(read("PASSWORD_MIN_LENGTH")), store };
4366
+ }
4367
+ if (!clientId && !password) {
4368
+ throw new ConfigError(
4369
+ "No sign-in method is configured. Set GOOGLE_CLIENT_ID for Google sign-in and/or DATABASE_URL (e.g. sqlite:./madauth.db) for e-mail & password sign-in. See docs/server.md."
4370
+ );
4371
+ }
4372
+ const ttlValue = read("SESSION_TTL");
4373
+ const sessionTtlSeconds = ttlValue ? Number(ttlValue) : DEFAULT_SESSION_TTL;
4374
+ if (!Number.isInteger(sessionTtlSeconds) || sessionTtlSeconds < 60) {
4375
+ throw new ConfigError(`SESSION_TTL must be a whole number of seconds (at least 60) but is "${ttlValue}".`);
4376
+ }
4377
+ return {
4378
+ issuer,
4379
+ signingKey,
4380
+ allowedOrigins,
4381
+ sessionTtlSeconds,
4382
+ cookieDomain: read("COOKIE_DOMAIN"),
4383
+ google: clientId ? { clientId, clientSecret: read("GOOGLE_CLIENT_SECRET") } : void 0,
4384
+ password,
4385
+ webhook
4386
+ };
4387
+ }
4388
+ function passwordMinLength(value) {
4389
+ const minLength = value ? Number(value) : DEFAULT_PASSWORD_MIN_LENGTH;
4390
+ if (!Number.isInteger(minLength) || minLength < 1 || minLength > 128) {
4391
+ throw new ConfigError(`PASSWORD_MIN_LENGTH must be a whole number from 1 to 128 but is "${value}".`);
4392
+ }
4393
+ return minLength;
4394
+ }
4395
+ async function storeFromDatabaseUrl(url) {
4396
+ if (!url) return void 0;
4397
+ if (!url.startsWith("sqlite:")) {
4398
+ throw new ConfigError(
4399
+ `DATABASE_URL must start with "sqlite:" (e.g. sqlite:/data/madauth.db) but is "${url}". For other databases, pass your own store adapter (see "Custom store adapter" in docs/server.md).`
4400
+ );
4401
+ }
4402
+ const path = url.slice("sqlite:".length);
4403
+ if (!path) throw new ConfigError("DATABASE_URL needs a file path, e.g. sqlite:/data/madauth.db");
4404
+ const { createSqliteAdapter: createSqliteAdapter2 } = await Promise.resolve().then(() => (init_sqlite(), sqlite_exports));
4405
+ try {
4406
+ return createSqliteAdapter2(path);
4407
+ } catch (e) {
4408
+ throw new ConfigError(`DATABASE_URL: could not open "${path}": ${e.message}`);
4409
+ }
4410
+ }
4411
+ var LOCAL_HOSTS = ["localhost", "127.0.0.1", "[::1]", "host.docker.internal"];
4412
+ function webhookFromEnv(url, secret, events) {
4413
+ if (!url) {
4414
+ if (secret || events) throw new ConfigError("WEBHOOK_SECRET and WEBHOOK_EVENTS need WEBHOOK_URL.");
4415
+ return void 0;
4416
+ }
4417
+ let parsed;
4418
+ try {
4419
+ parsed = new URL(url);
4420
+ } catch {
4421
+ throw new ConfigError(`WEBHOOK_URL: "${url}" is not a URL.`);
4422
+ }
4423
+ if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && LOCAL_HOSTS.includes(parsed.hostname))) {
4424
+ throw new ConfigError(`WEBHOOK_URL must be an https URL (http only for localhost) but is "${url}".`);
4425
+ }
4426
+ if (!secret) {
4427
+ throw new ConfigError(
4428
+ `WEBHOOK_SECRET is not set. Here is a newly generated secret you can use (keep it secret; your webhook receiver needs the same one):
4429
+
4430
+ WEBHOOK_SECRET=${generateWebhookSecret()}
4431
+ `
4432
+ );
4433
+ }
4434
+ const problem = checkWebhookSecret(secret);
4435
+ if (problem) {
4436
+ throw new ConfigError(`WEBHOOK_SECRET ${problem}. Generate one with: npx @madauth/server generate-webhook-secret`);
4437
+ }
4438
+ let selected = null;
4439
+ if (events) {
4440
+ selected = new Set(events.split(",").map((e) => e.trim()).filter(Boolean));
4441
+ const unknown = [...selected].filter((e) => !WEBHOOK_TYPES.includes(e));
4442
+ if (unknown.length) {
4443
+ throw new ConfigError(`WEBHOOK_EVENTS: unknown type ${unknown.join(", ")}. Known types: ${WEBHOOK_TYPES.join(", ")}.`);
4444
+ }
4445
+ }
4446
+ return { url: parsed.href, secret, events: selected };
4447
+ }
4448
+
4449
+ // src/entry/lambda.ts
4450
+ function createHandler(overrides = {}) {
4451
+ let handlerPromise;
4452
+ return async (event, context) => {
4453
+ handlerPromise ??= loadConfig(process.env, overrides).then((config) => handle(createApp(config)));
4454
+ handlerPromise.catch(() => handlerPromise = void 0);
4455
+ return (await handlerPromise)(event, context);
4456
+ };
4457
+ }
4458
+ var handler = createHandler();
4459
+ export {
4460
+ createHandler,
4461
+ handler
4462
+ };