agentic-canvas 0.1.0 → 0.2.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,2005 @@
1
+ import {
2
+ CanvasService,
3
+ MAX_LIVE_BYTES
4
+ } from "./chunk-W7NRP3EX.js";
5
+ import {
6
+ CanvasError,
7
+ principalSchema
8
+ } from "./chunk-GGQPE65T.js";
9
+
10
+ // src/worker.ts
11
+ import { parseRegion } from "agentic-identity";
12
+ import { createD1Store, createR2Blobs, D1_SCHEMA } from "agentic-identity/cloudflare";
13
+
14
+ // node_modules/hono/dist/request/constants.js
15
+ var GET_MATCH_RESULT = /* @__PURE__ */ Symbol();
16
+
17
+ // node_modules/hono/dist/utils/buffer.js
18
+ var bufferToFormData = (arrayBuffer, contentType) => {
19
+ return new Response(arrayBuffer, { headers: { "Content-Type": contentType.replace(/^[^;]+/, (mediaType) => mediaType.toLowerCase()) } }).formData();
20
+ };
21
+
22
+ // node_modules/hono/dist/utils/body.js
23
+ var MAX_NESTED_OBJECTS = 1e4;
24
+ var isRawRequest = (request) => "headers" in request;
25
+ var parseBody = async (request, options = /* @__PURE__ */ Object.create(null)) => {
26
+ const { all = false, dot = false } = options;
27
+ const mediaType = (isRawRequest(request) ? request.headers : request.raw.headers).get("Content-Type")?.split(";")[0].trim().toLowerCase();
28
+ if (mediaType === "multipart/form-data" || mediaType === "application/x-www-form-urlencoded") return parseFormData(request, {
29
+ all,
30
+ dot
31
+ });
32
+ return {};
33
+ };
34
+ async function parseFormData(request, options) {
35
+ if (!isRawRequest(request) && request.bodyCache.formData) return convertFormDataToBodyData(await request.bodyCache.formData, options);
36
+ const headers = isRawRequest(request) ? request.headers : request.raw.headers;
37
+ const arrayBuffer = await request.arrayBuffer();
38
+ const formDataPromise = bufferToFormData(arrayBuffer, headers.get("Content-Type") || "");
39
+ if (!isRawRequest(request)) request.bodyCache.formData = formDataPromise;
40
+ const formData = await formDataPromise;
41
+ if (formData) return convertFormDataToBodyData(formData, options);
42
+ return {};
43
+ }
44
+ function convertFormDataToBodyData(formData, options) {
45
+ const form = /* @__PURE__ */ Object.create(null);
46
+ const nestingState = { count: 0 };
47
+ formData.forEach((value, key) => {
48
+ if (!(options.all || key.endsWith("[]"))) form[key] = value;
49
+ else handleParsingAllValues(form, key, value);
50
+ });
51
+ if (options.dot) Object.entries(form).forEach(([key, value]) => {
52
+ if (key.includes(".")) {
53
+ handleParsingNestedValues(form, key, value, nestingState);
54
+ delete form[key];
55
+ }
56
+ });
57
+ return form;
58
+ }
59
+ var handleParsingAllValues = (form, key, value) => {
60
+ if (form[key] !== void 0) {
61
+ if (Array.isArray(form[key])) form[key].push(value);
62
+ else form[key] = [form[key], value];
63
+ } else if (!key.endsWith("[]")) form[key] = value;
64
+ else form[key] = [value];
65
+ };
66
+ var handleParsingNestedValues = (form, key, value, state) => {
67
+ if (/(?:^|\.)__proto__\./.test(key)) return;
68
+ let nestedForm = form;
69
+ const keys = key.split(".", 34);
70
+ if (keys.length > 33) throwNestingLimitExceeded();
71
+ keys.forEach((key2, index) => {
72
+ if (index === keys.length - 1) nestedForm[key2] = value;
73
+ else {
74
+ if (!nestedForm[key2] || typeof nestedForm[key2] !== "object" || Array.isArray(nestedForm[key2]) || nestedForm[key2] instanceof File) {
75
+ if (state.count++ >= MAX_NESTED_OBJECTS) throwNestingLimitExceeded();
76
+ nestedForm[key2] = /* @__PURE__ */ Object.create(null);
77
+ }
78
+ nestedForm = nestedForm[key2];
79
+ }
80
+ });
81
+ };
82
+ var throwNestingLimitExceeded = () => {
83
+ throw new Error("Nesting limit exceeded");
84
+ };
85
+
86
+ // node_modules/hono/dist/utils/url.js
87
+ var splitPath = (path) => {
88
+ const paths = path.split("/");
89
+ if (paths[0] === "") paths.shift();
90
+ return paths;
91
+ };
92
+ var splitRoutingPath = (routePath) => {
93
+ const { groups, path } = extractGroupsFromPath(routePath);
94
+ const paths = splitPath(path);
95
+ return replaceGroupMarks(paths, groups);
96
+ };
97
+ var extractGroupsFromPath = (path) => {
98
+ const groups = [];
99
+ path = path.replace(/\{[^}]+\}/g, (match2, index) => {
100
+ const mark = `@${index}`;
101
+ groups.push([mark, match2]);
102
+ return mark;
103
+ });
104
+ return {
105
+ groups,
106
+ path
107
+ };
108
+ };
109
+ var replaceGroupMarks = (paths, groups) => {
110
+ for (let i = groups.length - 1; i >= 0; i--) {
111
+ const [mark] = groups[i];
112
+ for (let j = paths.length - 1; j >= 0; j--) if (paths[j].includes(mark)) {
113
+ paths[j] = paths[j].replace(mark, groups[i][1]);
114
+ break;
115
+ }
116
+ }
117
+ return paths;
118
+ };
119
+ var patternCache = {};
120
+ var getPattern = (label, next) => {
121
+ if (label === "*") return "*";
122
+ const match2 = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
123
+ if (match2) {
124
+ const cacheKey = `${label}#${next}`;
125
+ if (!patternCache[cacheKey]) {
126
+ if (match2[2]) patternCache[cacheKey] = next && next[0] !== ":" && next[0] !== "*" ? [
127
+ cacheKey,
128
+ match2[1],
129
+ new RegExp(`^${match2[2]}(?=/${next})`)
130
+ ] : [
131
+ label,
132
+ match2[1],
133
+ new RegExp(`^${match2[2]}$`)
134
+ ];
135
+ else patternCache[cacheKey] = [
136
+ label,
137
+ match2[1],
138
+ true
139
+ ];
140
+ }
141
+ return patternCache[cacheKey];
142
+ }
143
+ return null;
144
+ };
145
+ var tryDecode = (str, decoder) => {
146
+ try {
147
+ return decoder(str);
148
+ } catch {
149
+ return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match2) => {
150
+ try {
151
+ return decoder(match2);
152
+ } catch {
153
+ return match2;
154
+ }
155
+ });
156
+ }
157
+ };
158
+ var tryDecodeURI = (str) => tryDecode(str, decodeURI);
159
+ var getPath = (request) => {
160
+ const url = request.url;
161
+ const start = url.indexOf("/", url.indexOf(":") + 4);
162
+ let i = start;
163
+ for (; i < url.length; i++) {
164
+ const charCode = url.charCodeAt(i);
165
+ if (charCode === 37) {
166
+ const queryIndex = url.indexOf("?", i);
167
+ const hashIndex = url.indexOf("#", i);
168
+ const end = queryIndex === -1 ? hashIndex === -1 ? void 0 : hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex);
169
+ const path = url.slice(start, end);
170
+ return tryDecodeURI(path.includes("%25") ? path.replace(/%25/g, "%2525") : path);
171
+ } else if (charCode === 63 || charCode === 35) break;
172
+ }
173
+ return url.slice(start, i);
174
+ };
175
+ var getPathNoStrict = (request) => {
176
+ const result = getPath(request);
177
+ return result.length > 1 && result.at(-1) === "/" ? result.slice(0, -1) : result;
178
+ };
179
+ var mergePath = (base, sub, ...rest) => {
180
+ if (rest.length) sub = mergePath(sub, ...rest);
181
+ return `${base?.[0] === "/" ? "" : "/"}${base}${sub === "/" ? "" : `${base?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`;
182
+ };
183
+ var checkOptionalParameter = (path) => {
184
+ if (path.charCodeAt(path.length - 1) !== 63 || !path.includes(":")) return null;
185
+ const segments = path.split("/");
186
+ const results = [];
187
+ let basePath = "";
188
+ segments.forEach((segment) => {
189
+ if (segment !== "" && !/\:/.test(segment)) basePath += "/" + segment;
190
+ else if (/\:/.test(segment)) {
191
+ if (segment.charCodeAt(segment.length - 1) === 63) {
192
+ if (results.length === 0 && basePath === "") results.push("/");
193
+ else results.push(basePath);
194
+ const optionalSegment = segment.slice(0, -1);
195
+ basePath += "/" + optionalSegment;
196
+ results.push(basePath);
197
+ } else basePath += "/" + segment;
198
+ }
199
+ });
200
+ return results.filter((v, i, a) => a.indexOf(v) === i);
201
+ };
202
+ var tryDecodeURIComponent = (str) => str.indexOf("%") !== -1 ? tryDecode(str, decodeURIComponent_) : str;
203
+ var _decodeURI = (value) => {
204
+ if (value.indexOf("+") !== -1) value = value.replace(/\+/g, " ");
205
+ return tryDecodeURIComponent(value);
206
+ };
207
+ var _getQueryParam = (url, key, multiple) => {
208
+ const hashIndex = url.indexOf("#", 8);
209
+ if (hashIndex !== -1) url = url.slice(0, hashIndex);
210
+ let encoded;
211
+ if (!multiple && key && key.indexOf("%") === -1 && key.indexOf("+") === -1) {
212
+ const queryIndex = url.indexOf("?", 8);
213
+ let keyIndex2 = queryIndex;
214
+ if (keyIndex2 === -1) return;
215
+ if (!url.startsWith(key, keyIndex2 + 1)) keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
216
+ while (keyIndex2 !== -1) {
217
+ const trailingKeyCode = url.charCodeAt(keyIndex2 + key.length + 1);
218
+ if (trailingKeyCode === 61 || trailingKeyCode === 38 || isNaN(trailingKeyCode)) {
219
+ if (keyIndex2 > queryIndex && /(?:^|&)[^=&]*[%+]/.test(url.slice(queryIndex + 1, keyIndex2))) break;
220
+ if (trailingKeyCode === 61) {
221
+ const valueIndex = keyIndex2 + key.length + 2;
222
+ const endIndex = url.indexOf("&", valueIndex);
223
+ return _decodeURI(url.slice(valueIndex, endIndex === -1 ? void 0 : endIndex));
224
+ }
225
+ return "";
226
+ }
227
+ keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
228
+ }
229
+ encoded = /[%+]/.test(url);
230
+ if (!encoded) return;
231
+ }
232
+ const results = /* @__PURE__ */ Object.create(null);
233
+ encoded ??= /[%+]/.test(url);
234
+ let keyIndex = url.indexOf("?", 8);
235
+ while (keyIndex !== -1) {
236
+ const nextKeyIndex = url.indexOf("&", keyIndex + 1);
237
+ let valueIndex = url.indexOf("=", keyIndex);
238
+ if (valueIndex > nextKeyIndex && nextKeyIndex !== -1) valueIndex = -1;
239
+ let name = url.slice(keyIndex + 1, valueIndex === -1 ? nextKeyIndex === -1 ? void 0 : nextKeyIndex : valueIndex);
240
+ if (encoded) name = _decodeURI(name);
241
+ keyIndex = nextKeyIndex;
242
+ if (name === "") continue;
243
+ let value;
244
+ if (valueIndex === -1) value = "";
245
+ else {
246
+ value = url.slice(valueIndex + 1, nextKeyIndex === -1 ? void 0 : nextKeyIndex);
247
+ if (encoded) value = _decodeURI(value);
248
+ }
249
+ if (multiple) {
250
+ if (!(results[name] && Array.isArray(results[name]))) results[name] = [];
251
+ results[name].push(value);
252
+ } else results[name] ??= value;
253
+ }
254
+ return key ? results[key] : results;
255
+ };
256
+ var getQueryParam = _getQueryParam;
257
+ var getQueryParams = (url, key) => {
258
+ return _getQueryParam(url, key, true);
259
+ };
260
+ var decodeURIComponent_ = decodeURIComponent;
261
+
262
+ // node_modules/hono/dist/request.js
263
+ var HonoRequest = class {
264
+ /**
265
+ * `.raw` can get the raw Request object.
266
+ *
267
+ * @see {@link https://hono.dev/docs/api/request#raw}
268
+ *
269
+ * @example
270
+ * ```ts
271
+ * // For Cloudflare Workers
272
+ * app.post('/', async (c) => {
273
+ * const metadata = c.req.raw.cf?.hostMetadata?
274
+ * ...
275
+ * })
276
+ * ```
277
+ */
278
+ raw;
279
+ #validatedData;
280
+ #matchResult;
281
+ routeIndex = 0;
282
+ /**
283
+ * `.path` can get the pathname of the request.
284
+ *
285
+ * @see {@link https://hono.dev/docs/api/request#path}
286
+ *
287
+ * @example
288
+ * ```ts
289
+ * app.get('/about/me', (c) => {
290
+ * const pathname = c.req.path // `/about/me`
291
+ * })
292
+ * ```
293
+ */
294
+ path;
295
+ bodyCache = {};
296
+ constructor(request, path = "/", matchResult = [[]]) {
297
+ this.raw = request;
298
+ this.path = path;
299
+ this.#matchResult = matchResult;
300
+ }
301
+ param(key) {
302
+ return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams();
303
+ }
304
+ #getDecodedParam(key) {
305
+ const paramKey = this.#matchResult[0][this.routeIndex]?.[1][key];
306
+ const param = this.#getParamValue(paramKey);
307
+ return param && tryDecodeURIComponent(param);
308
+ }
309
+ #getAllDecodedParams() {
310
+ const decoded = {};
311
+ const keys = Object.keys(this.#matchResult[0][this.routeIndex]?.[1] ?? {});
312
+ for (const key of keys) {
313
+ const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]);
314
+ if (value !== void 0) decoded[key] = tryDecodeURIComponent(value);
315
+ }
316
+ return decoded;
317
+ }
318
+ #getParamValue(paramKey) {
319
+ return this.#matchResult[1] ? this.#matchResult[1][paramKey] : paramKey;
320
+ }
321
+ query(key) {
322
+ return getQueryParam(this.url, key);
323
+ }
324
+ queries(key) {
325
+ return getQueryParams(this.url, key);
326
+ }
327
+ header(name) {
328
+ if (name) return this.raw.headers.get(name) ?? void 0;
329
+ const headerData = /* @__PURE__ */ Object.create(null);
330
+ this.raw.headers.forEach((value, key) => {
331
+ headerData[key] = value;
332
+ });
333
+ return headerData;
334
+ }
335
+ async parseBody(options) {
336
+ return parseBody(this, options);
337
+ }
338
+ #cachedBody = (key) => {
339
+ const { bodyCache, raw: raw2 } = this;
340
+ const cachedBody = bodyCache[key];
341
+ if (cachedBody) return cachedBody;
342
+ for (const anyCachedKey in bodyCache) return bodyCache[anyCachedKey].then((body) => {
343
+ if (anyCachedKey === "json") body = JSON.stringify(body);
344
+ const contentType = anyCachedKey === "formData" ? void 0 : raw2.headers.get("content-type");
345
+ return new Response(body, { headers: contentType ? { "Content-Type": contentType } : void 0 })[key]();
346
+ });
347
+ return bodyCache[key] = raw2[key]();
348
+ };
349
+ /**
350
+ * `.json()` can parse Request body of type `application/json`
351
+ *
352
+ * @see {@link https://hono.dev/docs/api/request#json}
353
+ *
354
+ * @example
355
+ * ```ts
356
+ * app.post('/entry', async (c) => {
357
+ * const body = await c.req.json()
358
+ * })
359
+ * ```
360
+ */
361
+ json() {
362
+ return this.#cachedBody("text").then((text2) => JSON.parse(text2));
363
+ }
364
+ /**
365
+ * `.text()` can parse Request body of type `text/plain`
366
+ *
367
+ * @see {@link https://hono.dev/docs/api/request#text}
368
+ *
369
+ * @example
370
+ * ```ts
371
+ * app.post('/entry', async (c) => {
372
+ * const body = await c.req.text()
373
+ * })
374
+ * ```
375
+ */
376
+ text() {
377
+ return this.#cachedBody("text");
378
+ }
379
+ /**
380
+ * `.arrayBuffer()` parse Request body as an `ArrayBuffer`
381
+ *
382
+ * @see {@link https://hono.dev/docs/api/request#arraybuffer}
383
+ *
384
+ * @example
385
+ * ```ts
386
+ * app.post('/entry', async (c) => {
387
+ * const body = await c.req.arrayBuffer()
388
+ * })
389
+ * ```
390
+ */
391
+ arrayBuffer() {
392
+ return this.#cachedBody("arrayBuffer");
393
+ }
394
+ /**
395
+ * `.bytes()` parses the request body as a `Uint8Array`.
396
+ *
397
+ * @see {@link https://hono.dev/docs/api/request#bytes}
398
+ *
399
+ * @example
400
+ * ```ts
401
+ * app.post('/entry', async (c) => {
402
+ * const body = await c.req.bytes()
403
+ * })
404
+ * ```
405
+ */
406
+ bytes() {
407
+ return this.#cachedBody("arrayBuffer").then((buffer) => new Uint8Array(buffer));
408
+ }
409
+ /**
410
+ * Parses the request body as a `Blob`.
411
+ * @example
412
+ * ```ts
413
+ * app.post('/entry', async (c) => {
414
+ * const body = await c.req.blob();
415
+ * });
416
+ * ```
417
+ * @see https://hono.dev/docs/api/request#blob
418
+ */
419
+ blob() {
420
+ return this.#cachedBody("blob");
421
+ }
422
+ /**
423
+ * Parses the request body as `FormData`.
424
+ * @example
425
+ * ```ts
426
+ * app.post('/entry', async (c) => {
427
+ * const body = await c.req.formData();
428
+ * });
429
+ * ```
430
+ * @see https://hono.dev/docs/api/request#formdata
431
+ */
432
+ formData() {
433
+ return this.#cachedBody("formData");
434
+ }
435
+ /**
436
+ * Adds validated data to the request.
437
+ *
438
+ * @param target - The target of the validation.
439
+ * @param data - The validated data to add.
440
+ */
441
+ addValidatedData(target, data) {
442
+ (this.#validatedData ??= {})[target] = data;
443
+ }
444
+ valid(target) {
445
+ return this.#validatedData?.[target];
446
+ }
447
+ /**
448
+ * `.url` can get the request url strings.
449
+ *
450
+ * @see {@link https://hono.dev/docs/api/request#url}
451
+ *
452
+ * @example
453
+ * ```ts
454
+ * app.get('/about/me', (c) => {
455
+ * const url = c.req.url // `http://localhost:8787/about/me`
456
+ * ...
457
+ * })
458
+ * ```
459
+ */
460
+ get url() {
461
+ return this.raw.url;
462
+ }
463
+ /**
464
+ * `.method` can get the method name of the request.
465
+ *
466
+ * @see {@link https://hono.dev/docs/api/request#method}
467
+ *
468
+ * @example
469
+ * ```ts
470
+ * app.get('/about/me', (c) => {
471
+ * const method = c.req.method // `GET`
472
+ * })
473
+ * ```
474
+ */
475
+ get method() {
476
+ return this.raw.method;
477
+ }
478
+ get [GET_MATCH_RESULT]() {
479
+ return this.#matchResult;
480
+ }
481
+ /**
482
+ * `.matchedRoutes` can return a matched route in the handler
483
+ *
484
+ * @deprecated
485
+ *
486
+ * Use matchedRoutes helper defined in "hono/route" instead.
487
+ *
488
+ * @see {@link https://hono.dev/docs/api/request#matchedroutes}
489
+ *
490
+ * @example
491
+ * ```ts
492
+ * app.use('*', async function logger(c, next) {
493
+ * await next()
494
+ * c.req.matchedRoutes.forEach(({ handler, method, path }, i) => {
495
+ * const name = handler.name || (handler.length < 2 ? '[handler]' : '[middleware]')
496
+ * console.log(
497
+ * method,
498
+ * ' ',
499
+ * path,
500
+ * ' '.repeat(Math.max(10 - path.length, 0)),
501
+ * name,
502
+ * i === c.req.routeIndex ? '<- respond from here' : ''
503
+ * )
504
+ * })
505
+ * })
506
+ * ```
507
+ */
508
+ get matchedRoutes() {
509
+ return this.#matchResult[0].map(([[, route]]) => route);
510
+ }
511
+ /**
512
+ * `.routePath` can retrieve the path registered within the handler
513
+ *
514
+ * @deprecated
515
+ *
516
+ * Use routePath helper defined in "hono/route" instead.
517
+ *
518
+ * @see {@link https://hono.dev/docs/api/request#routepath}
519
+ *
520
+ * @example
521
+ * ```ts
522
+ * app.get('/posts/:id', (c) => {
523
+ * return c.json({ path: c.req.routePath })
524
+ * })
525
+ * ```
526
+ */
527
+ get routePath() {
528
+ return this.#matchResult[0].map(([[, route]]) => route)[this.routeIndex].path;
529
+ }
530
+ };
531
+
532
+ // node_modules/hono/dist/utils/html.js
533
+ var HtmlEscapedCallbackPhase = {
534
+ Stringify: 1,
535
+ BeforeStream: 2,
536
+ Stream: 3
537
+ };
538
+ var raw = (value, callbacks) => {
539
+ const escapedString = new String(value);
540
+ escapedString.isEscaped = true;
541
+ escapedString.callbacks = callbacks;
542
+ return escapedString;
543
+ };
544
+ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
545
+ if (typeof str === "object" && !(str instanceof String)) {
546
+ if (!(str instanceof Promise)) str = str.toString();
547
+ if (str instanceof Promise) str = await str;
548
+ }
549
+ const callbacks = str.callbacks;
550
+ if (!callbacks?.length) return Promise.resolve(str);
551
+ if (buffer) buffer[0] += str;
552
+ else buffer = [str];
553
+ const resStr = Promise.all(callbacks.map((c) => c({
554
+ phase,
555
+ buffer,
556
+ context
557
+ }))).then((res) => Promise.all(res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false, context, buffer))).then(() => buffer[0]));
558
+ if (preserveCallbacks) return raw(await resStr, callbacks);
559
+ else return resStr;
560
+ };
561
+
562
+ // node_modules/hono/dist/context.js
563
+ var TEXT_PLAIN = "text/plain; charset=UTF-8";
564
+ var setDefaultContentType = (contentType, headers) => {
565
+ return {
566
+ "Content-Type": contentType,
567
+ ...headers
568
+ };
569
+ };
570
+ var createResponseInstance = (body, init) => new Response(body, init);
571
+ var Context = class {
572
+ #rawRequest;
573
+ #req;
574
+ /**
575
+ * `.env` can get bindings (environment variables, secrets, KV namespaces, D1 database, R2 bucket etc.) in Cloudflare Workers.
576
+ *
577
+ * @see {@link https://hono.dev/docs/api/context#env}
578
+ *
579
+ * @example
580
+ * ```ts
581
+ * // Environment object for Cloudflare Workers
582
+ * app.get('*', async c => {
583
+ * const counter = c.env.COUNTER
584
+ * })
585
+ * ```
586
+ */
587
+ env = {};
588
+ #var;
589
+ finalized = false;
590
+ /**
591
+ * `.error` can get the error object from the middleware if the Handler throws an error.
592
+ *
593
+ * @see {@link https://hono.dev/docs/api/context#error}
594
+ *
595
+ * @example
596
+ * ```ts
597
+ * app.use('*', async (c, next) => {
598
+ * await next()
599
+ * if (c.error) {
600
+ * // do something...
601
+ * }
602
+ * })
603
+ * ```
604
+ */
605
+ error;
606
+ #status;
607
+ #executionCtx;
608
+ #res;
609
+ #layout;
610
+ #renderer;
611
+ #notFoundHandler;
612
+ #preparedHeaders;
613
+ #matchResult;
614
+ #path;
615
+ /**
616
+ * Creates an instance of the Context class.
617
+ *
618
+ * @param req - The Request object.
619
+ * @param options - Optional configuration options for the context.
620
+ */
621
+ constructor(req, options) {
622
+ this.#rawRequest = req;
623
+ if (options) {
624
+ this.#executionCtx = options.executionCtx;
625
+ this.env = options.env;
626
+ this.#notFoundHandler = options.notFoundHandler;
627
+ this.#path = options.path;
628
+ this.#matchResult = options.matchResult;
629
+ }
630
+ }
631
+ /**
632
+ * `.req` is the instance of {@link HonoRequest}.
633
+ */
634
+ get req() {
635
+ this.#req ??= new HonoRequest(this.#rawRequest, this.#path, this.#matchResult);
636
+ return this.#req;
637
+ }
638
+ /**
639
+ * @see {@link https://hono.dev/docs/api/context#event}
640
+ * The FetchEvent associated with the current request.
641
+ *
642
+ * @throws Will throw an error if the context does not have a FetchEvent.
643
+ */
644
+ get event() {
645
+ if (this.#executionCtx && "respondWith" in this.#executionCtx) return this.#executionCtx;
646
+ else throw Error("This context has no FetchEvent");
647
+ }
648
+ /**
649
+ * @see {@link https://hono.dev/docs/api/context#executionctx}
650
+ * The ExecutionContext associated with the current request.
651
+ *
652
+ * @throws Will throw an error if the context does not have an ExecutionContext.
653
+ */
654
+ get executionCtx() {
655
+ if (this.#executionCtx) return this.#executionCtx;
656
+ else throw Error("This context has no ExecutionContext");
657
+ }
658
+ /**
659
+ * @see {@link https://hono.dev/docs/api/context#res}
660
+ * The Response object for the current request.
661
+ */
662
+ get res() {
663
+ return this.#res ||= createResponseInstance(null, { headers: this.#preparedHeaders ??= new Headers() });
664
+ }
665
+ /**
666
+ * Sets the Response object for the current request.
667
+ *
668
+ * @param _res - The Response object to set.
669
+ */
670
+ set res(_res) {
671
+ if (this.#res && _res) {
672
+ _res = createResponseInstance(_res.body, _res);
673
+ for (const [k, v] of this.#res.headers.entries()) {
674
+ if (k === "content-type") continue;
675
+ if (k === "set-cookie") {
676
+ const cookies = this.#res.headers.getSetCookie();
677
+ _res.headers.delete("set-cookie");
678
+ for (const cookie of cookies) _res.headers.append("set-cookie", cookie);
679
+ } else _res.headers.set(k, v);
680
+ }
681
+ }
682
+ this.#res = _res;
683
+ this.finalized = true;
684
+ }
685
+ /**
686
+ * `.render()` can create a response within a layout.
687
+ *
688
+ * @see {@link https://hono.dev/docs/api/context#render-setrenderer}
689
+ *
690
+ * @example
691
+ * ```ts
692
+ * app.get('/', (c) => {
693
+ * return c.render('Hello!')
694
+ * })
695
+ * ```
696
+ */
697
+ render = (...args) => {
698
+ this.#renderer ??= (content) => this.html(content);
699
+ return this.#renderer(...args);
700
+ };
701
+ /**
702
+ * Sets the layout for the response.
703
+ *
704
+ * @param layout - The layout to set.
705
+ * @returns The layout function.
706
+ */
707
+ setLayout = (layout) => this.#layout = layout;
708
+ /**
709
+ * Gets the current layout for the response.
710
+ *
711
+ * @returns The current layout function.
712
+ */
713
+ getLayout = () => this.#layout;
714
+ /**
715
+ * `.setRenderer()` can set the layout in the custom middleware.
716
+ *
717
+ * @see {@link https://hono.dev/docs/api/context#render-setrenderer}
718
+ *
719
+ * @example
720
+ * ```tsx
721
+ * app.use('*', async (c, next) => {
722
+ * c.setRenderer((content) => {
723
+ * return c.html(
724
+ * <html>
725
+ * <body>
726
+ * <p>{content}</p>
727
+ * </body>
728
+ * </html>
729
+ * )
730
+ * })
731
+ * await next()
732
+ * })
733
+ * ```
734
+ */
735
+ setRenderer = (renderer) => {
736
+ this.#renderer = renderer;
737
+ };
738
+ /**
739
+ * `.header()` can set headers.
740
+ *
741
+ * @see {@link https://hono.dev/docs/api/context#header}
742
+ *
743
+ * @example
744
+ * ```ts
745
+ * app.get('/welcome', (c) => {
746
+ * // Set headers
747
+ * c.header('X-Message', 'Hello!')
748
+ * c.header('Content-Type', 'text/plain')
749
+ *
750
+ * // Append multiple headers using the append option (e.g. Vary)
751
+ * c.header('Vary', 'Accept-Encoding', { append: true })
752
+ * c.header('Vary', 'User-Agent', { append: true })
753
+ *
754
+ * return c.body('Thank you for coming')
755
+ * })
756
+ * ```
757
+ */
758
+ header = (name, value, options) => {
759
+ if (this.finalized) this.#res = createResponseInstance(this.#res.body, this.#res);
760
+ const headers = this.#res ? this.#res.headers : this.#preparedHeaders ??= new Headers();
761
+ if (value === void 0) headers.delete(name);
762
+ else if (options?.append) headers.append(name, value);
763
+ else headers.set(name, value);
764
+ };
765
+ status = (status) => {
766
+ this.#status = status;
767
+ };
768
+ /**
769
+ * `.set()` can set the value specified by the key.
770
+ *
771
+ * @see {@link https://hono.dev/docs/api/context#set-get}
772
+ *
773
+ * @example
774
+ * ```ts
775
+ * app.use('*', async (c, next) => {
776
+ * c.set('message', 'Hono is hot!!')
777
+ * await next()
778
+ * })
779
+ * ```
780
+ */
781
+ set = (key, value) => {
782
+ this.#var ??= /* @__PURE__ */ new Map();
783
+ this.#var.set(key, value);
784
+ };
785
+ /**
786
+ * `.get()` can use the value specified by the key.
787
+ *
788
+ * @see {@link https://hono.dev/docs/api/context#set-get}
789
+ *
790
+ * @example
791
+ * ```ts
792
+ * app.get('/', (c) => {
793
+ * const message = c.get('message')
794
+ * return c.text(`The message is "${message}"`)
795
+ * })
796
+ * ```
797
+ */
798
+ get = (key) => {
799
+ return this.#var ? this.#var.get(key) : void 0;
800
+ };
801
+ /**
802
+ * `.var` can access the value of a variable.
803
+ *
804
+ * @see {@link https://hono.dev/docs/api/context#var}
805
+ *
806
+ * @example
807
+ * ```ts
808
+ * const result = c.var.client.oneMethod()
809
+ * ```
810
+ */
811
+ get var() {
812
+ if (!this.#var) return {};
813
+ return Object.fromEntries(this.#var);
814
+ }
815
+ #newResponse(data, arg, headers) {
816
+ let responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders;
817
+ if (typeof arg === "object" && arg.headers) {
818
+ responseHeaders ??= new Headers();
819
+ for (const [key, value] of new Headers(arg.headers)) if (key === "set-cookie") responseHeaders.append(key, value);
820
+ else responseHeaders.set(key, value);
821
+ }
822
+ if (headers) {
823
+ if (!responseHeaders) {
824
+ let count = 0;
825
+ for (const k in headers) if (++count > 1 || typeof headers[k] !== "string") {
826
+ responseHeaders = new Headers();
827
+ break;
828
+ }
829
+ }
830
+ if (responseHeaders) for (const k in headers) {
831
+ const v = headers[k];
832
+ if (typeof v === "string") responseHeaders.set(k, v);
833
+ else {
834
+ responseHeaders.delete(k);
835
+ for (const v2 of v) responseHeaders.append(k, v2);
836
+ }
837
+ }
838
+ }
839
+ const status = typeof arg === "number" ? arg : arg?.status ?? this.#status;
840
+ return createResponseInstance(data, {
841
+ status,
842
+ headers: responseHeaders ?? headers
843
+ });
844
+ }
845
+ newResponse = (...args) => this.#newResponse(...args);
846
+ /**
847
+ * `.body()` can return the HTTP response.
848
+ * You can set headers with `.header()` and set HTTP status code with `.status`.
849
+ * This can also be set in `.text()`, `.json()` and so on.
850
+ *
851
+ * @see {@link https://hono.dev/docs/api/context#body}
852
+ *
853
+ * @example
854
+ * ```ts
855
+ * app.get('/welcome', (c) => {
856
+ * // Set headers
857
+ * c.header('X-Message', 'Hello!')
858
+ * c.header('Content-Type', 'text/plain')
859
+ * // Set HTTP status code
860
+ * c.status(201)
861
+ *
862
+ * // Return the response body
863
+ * return c.body('Thank you for coming')
864
+ * })
865
+ * ```
866
+ */
867
+ body = (data, arg, headers) => this.#newResponse(data, arg, headers);
868
+ /**
869
+ * `.text()` can render text as `Content-Type:text/plain`.
870
+ *
871
+ * @see {@link https://hono.dev/docs/api/context#text}
872
+ *
873
+ * @example
874
+ * ```ts
875
+ * app.get('/say', (c) => {
876
+ * return c.text('Hello!')
877
+ * })
878
+ * ```
879
+ */
880
+ text = (text2, arg, headers) => {
881
+ return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized ? new Response(text2) : this.#newResponse(text2, arg, setDefaultContentType(TEXT_PLAIN, headers));
882
+ };
883
+ /**
884
+ * `.json()` can render JSON as `Content-Type:application/json`.
885
+ *
886
+ * @see {@link https://hono.dev/docs/api/context#json}
887
+ *
888
+ * @example
889
+ * ```ts
890
+ * app.get('/api', (c) => {
891
+ * return c.json({ message: 'Hello!' })
892
+ * })
893
+ * ```
894
+ */
895
+ json = (object, arg, headers) => {
896
+ return this.#newResponse(JSON.stringify(object), arg, setDefaultContentType("application/json", headers));
897
+ };
898
+ html = (html, arg, headers) => {
899
+ const res = (html2) => this.#newResponse(html2, arg, setDefaultContentType("text/html; charset=UTF-8", headers));
900
+ return typeof html === "object" ? resolveCallback(html, HtmlEscapedCallbackPhase.Stringify, false, {}).then(res) : res(html);
901
+ };
902
+ /**
903
+ * `.redirect()` can Redirect, default status code is 302.
904
+ *
905
+ * @see {@link https://hono.dev/docs/api/context#redirect}
906
+ *
907
+ * @example
908
+ * ```ts
909
+ * app.get('/redirect', (c) => {
910
+ * return c.redirect('/')
911
+ * })
912
+ * app.get('/redirect-permanently', (c) => {
913
+ * return c.redirect('/', 301)
914
+ * })
915
+ * ```
916
+ */
917
+ redirect = (location, status) => {
918
+ const locationString = String(location);
919
+ this.header("Location", !/[^\x00-\xFF]/.test(locationString) ? locationString : encodeURI(locationString));
920
+ return this.newResponse(null, status ?? 302);
921
+ };
922
+ /**
923
+ * `.notFound()` can return the Not Found Response.
924
+ *
925
+ * @see {@link https://hono.dev/docs/api/context#notfound}
926
+ *
927
+ * @example
928
+ * ```ts
929
+ * app.get('/notfound', (c) => {
930
+ * return c.notFound()
931
+ * })
932
+ * ```
933
+ */
934
+ notFound = () => {
935
+ this.#notFoundHandler ??= () => createResponseInstance();
936
+ return this.#notFoundHandler(this);
937
+ };
938
+ };
939
+
940
+ // node_modules/hono/dist/compose.js
941
+ var compose = (middleware, onError, onNotFound) => {
942
+ return (context, next) => {
943
+ let index = -1;
944
+ return dispatch(0);
945
+ async function dispatch(i) {
946
+ if (i <= index) throw new Error("next() called multiple times");
947
+ index = i;
948
+ let res;
949
+ let isError = false;
950
+ let handler;
951
+ if (middleware[i]) {
952
+ handler = middleware[i][0][0];
953
+ context.req.routeIndex = i;
954
+ } else handler = i === middleware.length && next || void 0;
955
+ if (handler) try {
956
+ res = await handler(context, () => dispatch(i + 1));
957
+ } catch (err) {
958
+ if (err instanceof Error && onError) {
959
+ context.error = err;
960
+ res = await onError(err, context);
961
+ isError = true;
962
+ } else throw err;
963
+ }
964
+ else if (context.finalized === false && onNotFound) res = await onNotFound(context);
965
+ if (res && (context.finalized === false || isError)) context.res = res;
966
+ return context;
967
+ }
968
+ };
969
+ };
970
+
971
+ // node_modules/hono/dist/router.js
972
+ var METHODS = [
973
+ "get",
974
+ "post",
975
+ "put",
976
+ "delete",
977
+ "options",
978
+ "patch",
979
+ "query"
980
+ ];
981
+ var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built.";
982
+ var UnsupportedPathError = class extends Error {
983
+ };
984
+
985
+ // node_modules/hono/dist/utils/constants.js
986
+ var COMPOSED_HANDLER = "__COMPOSED_HANDLER";
987
+
988
+ // node_modules/hono/dist/hono-base.js
989
+ var notFoundHandler = (c) => {
990
+ return c.text("404 Not Found", 404);
991
+ };
992
+ var errorHandler = (err, c) => {
993
+ if ("getResponse" in err) {
994
+ const res = err.getResponse();
995
+ return c.newResponse(res.body, res);
996
+ }
997
+ console.error(err);
998
+ return c.text("Internal Server Error", 500);
999
+ };
1000
+ var Hono = class Hono2 {
1001
+ get;
1002
+ post;
1003
+ put;
1004
+ delete;
1005
+ options;
1006
+ patch;
1007
+ query;
1008
+ all;
1009
+ on;
1010
+ use;
1011
+ router;
1012
+ getPath;
1013
+ _basePath = "/";
1014
+ #path = "/";
1015
+ routes = [];
1016
+ constructor(options = {}) {
1017
+ [...METHODS, "all"].forEach((method) => {
1018
+ this[method] = (args1, ...args) => {
1019
+ const methodName = method.toUpperCase();
1020
+ if (typeof args1 === "string") this.#path = args1;
1021
+ else this.#addRoute(methodName, this.#path, args1);
1022
+ args.forEach((handler) => {
1023
+ this.#addRoute(methodName, this.#path, handler);
1024
+ });
1025
+ return this;
1026
+ };
1027
+ });
1028
+ this.on = (method, path, ...handlers) => {
1029
+ for (const p of [path].flat()) {
1030
+ this.#path = p;
1031
+ for (const m of [method].flat()) {
1032
+ const methodName = m.toUpperCase();
1033
+ for (const handler of handlers) this.#addRoute(methodName, this.#path, handler);
1034
+ }
1035
+ }
1036
+ return this;
1037
+ };
1038
+ this.use = (arg1, ...handlers) => {
1039
+ if (typeof arg1 === "string") this.#path = arg1;
1040
+ else {
1041
+ this.#path = "*";
1042
+ handlers.unshift(arg1);
1043
+ }
1044
+ handlers.forEach((handler) => {
1045
+ this.#addRoute("ALL", this.#path, handler);
1046
+ });
1047
+ return this;
1048
+ };
1049
+ const { strict, ...optionsWithoutStrict } = options;
1050
+ Object.assign(this, optionsWithoutStrict);
1051
+ this.getPath = strict ?? true ? options.getPath ?? getPath : getPathNoStrict;
1052
+ }
1053
+ #clone() {
1054
+ const clone = new Hono2({
1055
+ router: this.router,
1056
+ getPath: this.getPath
1057
+ });
1058
+ clone.errorHandler = this.errorHandler;
1059
+ clone.#notFoundHandler = this.#notFoundHandler;
1060
+ clone.routes = this.routes;
1061
+ return clone;
1062
+ }
1063
+ #notFoundHandler = notFoundHandler;
1064
+ errorHandler = errorHandler;
1065
+ /**
1066
+ * `.route()` allows grouping other Hono instance in routes.
1067
+ *
1068
+ * @see {@link https://hono.dev/docs/api/routing#grouping}
1069
+ *
1070
+ * @param {string} path - base Path
1071
+ * @param {Hono} app - other Hono instance
1072
+ * @returns {Hono} routed Hono instance
1073
+ *
1074
+ * @example
1075
+ * ```ts
1076
+ * const app = new Hono()
1077
+ * const app2 = new Hono()
1078
+ *
1079
+ * app2.get("/user", (c) => c.text("user"))
1080
+ * app.route("/api", app2) // GET /api/user
1081
+ * ```
1082
+ */
1083
+ route(path, app2) {
1084
+ const subApp = this.basePath(path);
1085
+ app2.routes.map((r) => {
1086
+ let handler;
1087
+ if (app2.errorHandler === errorHandler) handler = r.handler;
1088
+ else {
1089
+ handler = async (c, next) => (await compose([], app2.errorHandler)(c, () => r.handler(c, next))).res;
1090
+ handler[COMPOSED_HANDLER] = r.handler;
1091
+ }
1092
+ subApp.#addRoute(r.method, r.path, handler, r.basePath);
1093
+ });
1094
+ return this;
1095
+ }
1096
+ /**
1097
+ * `.basePath()` allows base paths to be specified.
1098
+ *
1099
+ * @see {@link https://hono.dev/docs/api/routing#base-path}
1100
+ *
1101
+ * @param {string} path - base Path
1102
+ * @returns {Hono} changed Hono instance
1103
+ *
1104
+ * @example
1105
+ * ```ts
1106
+ * const api = new Hono().basePath('/api')
1107
+ * ```
1108
+ */
1109
+ basePath(path) {
1110
+ const subApp = this.#clone();
1111
+ subApp._basePath = mergePath(this._basePath, path);
1112
+ return subApp;
1113
+ }
1114
+ /**
1115
+ * `.onError()` handles an error and returns a customized Response.
1116
+ *
1117
+ * @see {@link https://hono.dev/docs/api/hono#error-handling}
1118
+ *
1119
+ * @param {ErrorHandler} handler - request Handler for error
1120
+ * @returns {Hono} changed Hono instance
1121
+ *
1122
+ * @example
1123
+ * ```ts
1124
+ * app.onError((err, c) => {
1125
+ * console.error(`${err}`)
1126
+ * return c.text('Custom Error Message', 500)
1127
+ * })
1128
+ * ```
1129
+ */
1130
+ onError = (handler) => {
1131
+ this.errorHandler = handler;
1132
+ return this;
1133
+ };
1134
+ /**
1135
+ * `.notFound()` allows you to customize a Not Found Response.
1136
+ *
1137
+ * @see {@link https://hono.dev/docs/api/hono#not-found}
1138
+ *
1139
+ * @param {NotFoundHandler} handler - request handler for not-found
1140
+ * @returns {Hono} changed Hono instance
1141
+ *
1142
+ * @example
1143
+ * ```ts
1144
+ * app.notFound((c) => {
1145
+ * return c.text('Custom 404 Message', 404)
1146
+ * })
1147
+ * ```
1148
+ */
1149
+ notFound = (handler) => {
1150
+ this.#notFoundHandler = handler;
1151
+ return this;
1152
+ };
1153
+ /**
1154
+ * `.mount()` allows you to mount applications built with other frameworks into your Hono application.
1155
+ *
1156
+ * @deprecated Use `mount()` from `hono/mount` instead. `.mount()` will be removed in v5.
1157
+ *
1158
+ * @see {@link https://hono.dev/docs/api/hono#mount}
1159
+ *
1160
+ * @param {string} path - base Path
1161
+ * @param {Function} applicationHandler - other Request Handler
1162
+ * @param {MountOptions} [options] - options of `.mount()`
1163
+ * @returns {Hono} mounted Hono instance
1164
+ *
1165
+ * @example
1166
+ * ```ts
1167
+ * import { Router as IttyRouter } from 'itty-router'
1168
+ * import { Hono } from 'hono'
1169
+ * // Create itty-router application
1170
+ * const ittyRouter = IttyRouter()
1171
+ * // GET /itty-router/hello
1172
+ * ittyRouter.get('/hello', () => new Response('Hello from itty-router'))
1173
+ *
1174
+ * const app = new Hono()
1175
+ * app.mount('/itty-router', ittyRouter.handle)
1176
+ * ```
1177
+ *
1178
+ * @example
1179
+ * ```ts
1180
+ * const app = new Hono()
1181
+ * // Send the request to another application without modification.
1182
+ * app.mount('/app', anotherApp, {
1183
+ * replaceRequest: (req) => req,
1184
+ * })
1185
+ * ```
1186
+ */
1187
+ mount(path, applicationHandler, options) {
1188
+ let replaceRequest;
1189
+ let optionHandler;
1190
+ if (options) {
1191
+ if (typeof options === "function") optionHandler = options;
1192
+ else {
1193
+ optionHandler = options.optionHandler;
1194
+ if (options.replaceRequest === false) replaceRequest = (request) => request;
1195
+ else replaceRequest = options.replaceRequest;
1196
+ }
1197
+ }
1198
+ const getOptions = optionHandler ? (c) => {
1199
+ const options2 = optionHandler(c);
1200
+ return Array.isArray(options2) ? options2 : [options2];
1201
+ } : (c) => {
1202
+ let executionContext = void 0;
1203
+ try {
1204
+ executionContext = c.executionCtx;
1205
+ } catch {
1206
+ }
1207
+ return [c.env, executionContext];
1208
+ };
1209
+ replaceRequest ||= (() => {
1210
+ const mergedPath = mergePath(this._basePath, path);
1211
+ const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length;
1212
+ return (request) => {
1213
+ const url = new URL(request.url);
1214
+ url.pathname = this.getPath(request).slice(pathPrefixLength) || "/";
1215
+ return new Request(url, request);
1216
+ };
1217
+ })();
1218
+ const handler = async (c, next) => {
1219
+ const res = await applicationHandler(replaceRequest(c.req.raw), ...getOptions(c));
1220
+ if (res) return res;
1221
+ await next();
1222
+ };
1223
+ this.#addRoute("ALL", mergePath(path, "*"), handler);
1224
+ return this;
1225
+ }
1226
+ #addRoute(method, path, handler, baseRoutePath) {
1227
+ path = mergePath(this._basePath, path);
1228
+ const r = {
1229
+ basePath: baseRoutePath !== void 0 ? mergePath(this._basePath, baseRoutePath) : this._basePath,
1230
+ path,
1231
+ method,
1232
+ handler
1233
+ };
1234
+ this.router.add(method, path, [handler, r]);
1235
+ this.routes.push(r);
1236
+ }
1237
+ #handleError(err, c) {
1238
+ if (err instanceof Error) return this.errorHandler(err, c);
1239
+ throw err;
1240
+ }
1241
+ #dispatch(request, executionCtx, env, method) {
1242
+ if (method === "HEAD") return (async () => new Response(null, await this.#dispatch(request, executionCtx, env, "GET")))();
1243
+ const path = this.getPath(request, { env });
1244
+ const matchResult = this.router.match(method, path);
1245
+ const c = new Context(request, {
1246
+ path,
1247
+ matchResult,
1248
+ env,
1249
+ executionCtx,
1250
+ notFoundHandler: this.#notFoundHandler
1251
+ });
1252
+ if (matchResult[0].length === 1) {
1253
+ let res;
1254
+ try {
1255
+ res = matchResult[0][0][0][0](c, async () => {
1256
+ c.res = await this.#notFoundHandler(c);
1257
+ });
1258
+ } catch (err) {
1259
+ return this.#handleError(err, c);
1260
+ }
1261
+ 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);
1262
+ }
1263
+ const composed = compose(matchResult[0], this.errorHandler, this.#notFoundHandler);
1264
+ return (async () => {
1265
+ try {
1266
+ const context = await composed(c);
1267
+ if (!context.finalized) throw new Error("Context is not finalized. Did you forget to return a Response object or `await next()`?");
1268
+ return context.res;
1269
+ } catch (err) {
1270
+ return this.#handleError(err, c);
1271
+ }
1272
+ })();
1273
+ }
1274
+ /**
1275
+ * `.fetch()` will be entry point of your app.
1276
+ *
1277
+ * @see {@link https://hono.dev/docs/api/hono#fetch}
1278
+ *
1279
+ * @param {Request} request - request Object of request
1280
+ * @param {Env} env - env Object
1281
+ * @param {ExecutionContext} executionCtx - context of execution
1282
+ * @returns {Response | Promise<Response>} response of request
1283
+ *
1284
+ */
1285
+ fetch = (request, ...rest) => {
1286
+ return this.#dispatch(request, rest[1], rest[0], request.method);
1287
+ };
1288
+ /**
1289
+ * `.request()` is a useful method for testing.
1290
+ * You can pass a URL or pathname to send a GET request.
1291
+ * app will return a Response object.
1292
+ * ```ts
1293
+ * test('GET /hello is ok', async () => {
1294
+ * const res = await app.request('/hello')
1295
+ * expect(res.status).toBe(200)
1296
+ * })
1297
+ * ```
1298
+ * @see https://hono.dev/docs/api/hono#request
1299
+ */
1300
+ request = (input, requestInit, Env, executionCtx) => {
1301
+ if (input instanceof Request) return this.fetch(requestInit ? new Request(input, requestInit) : input, Env, executionCtx);
1302
+ input = input.toString();
1303
+ return this.fetch(new Request(/^https?:\/\//.test(input) ? input : `http://localhost${mergePath("/", input)}`, requestInit), Env, executionCtx);
1304
+ };
1305
+ /**
1306
+ * `.fire()` automatically adds a global fetch event listener.
1307
+ * This can be useful for environments that adhere to the Service Worker API, such as non-ES module Cloudflare Workers.
1308
+ * @deprecated
1309
+ * Use `fire` from `hono/service-worker` instead.
1310
+ * ```ts
1311
+ * import { Hono } from 'hono'
1312
+ * import { fire } from 'hono/service-worker'
1313
+ *
1314
+ * const app = new Hono()
1315
+ * // ...
1316
+ * fire(app)
1317
+ * ```
1318
+ * @see https://hono.dev/docs/api/hono#fire
1319
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API
1320
+ * @see https://developers.cloudflare.com/workers/reference/migrate-to-module-workers/
1321
+ */
1322
+ fire = () => {
1323
+ addEventListener("fetch", (event) => {
1324
+ event.respondWith(this.#dispatch(event.request, event, void 0, event.request.method));
1325
+ });
1326
+ };
1327
+ };
1328
+
1329
+ // node_modules/hono/dist/router/utils.js
1330
+ var createNullObject = () => /* @__PURE__ */ Object.create(null);
1331
+
1332
+ // node_modules/hono/dist/router/reg-exp-router/matcher.js
1333
+ var emptyParam = [];
1334
+ function match(method, path) {
1335
+ const matchers = this.buildAllMatchers();
1336
+ const match2 = ((method2, path2) => {
1337
+ const matcher = matchers[method2] || matchers["ALL"];
1338
+ const staticMatch = matcher[2][path2];
1339
+ if (staticMatch) return staticMatch;
1340
+ const match3 = path2.match(matcher[0]);
1341
+ if (!match3) return [[], emptyParam];
1342
+ const index = match3.indexOf("", 1);
1343
+ return [matcher[1][index], match3];
1344
+ });
1345
+ this.match = match2;
1346
+ return match2(method, path);
1347
+ }
1348
+
1349
+ // node_modules/hono/dist/router/reg-exp-router/node.js
1350
+ var LABEL_REG_EXP_STR = "[^/]+";
1351
+ var TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)";
1352
+ var PATH_ERROR = /* @__PURE__ */ Symbol();
1353
+ var regExpMetaChars = /* @__PURE__ */ new Set(".\\+*[^]$()");
1354
+ function compareKey(a, b) {
1355
+ if (a.length === 1) return b.length === 1 ? a < b ? -1 : 1 : -1;
1356
+ if (b.length === 1) return 1;
1357
+ if (a === ".*" || a === "(?:|/.*)") return b === "(?:|/.*)" ? -1 : 1;
1358
+ else if (b === ".*" || b === "(?:|/.*)") return -1;
1359
+ if (a === "[^/]+") return 1;
1360
+ else if (b === "[^/]+") return -1;
1361
+ return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length;
1362
+ }
1363
+ var Node = class Node2 {
1364
+ #index;
1365
+ #varIndex;
1366
+ #children = createNullObject();
1367
+ insert(tokens, index, paramMap, context, isStatic) {
1368
+ let node = this;
1369
+ for (let i = 0, len = tokens.length; i < len; i++) {
1370
+ const token = tokens[i];
1371
+ const pattern = token.length === 1 ? token === "*" ? i === len - 1 ? [
1372
+ "",
1373
+ "",
1374
+ ".*"
1375
+ ] : [
1376
+ "",
1377
+ "",
1378
+ LABEL_REG_EXP_STR
1379
+ ] : null : token === "/*" ? [
1380
+ "",
1381
+ "",
1382
+ TAIL_WILDCARD_REG_EXP_STR
1383
+ ] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
1384
+ let nextNode;
1385
+ if (pattern) {
1386
+ const name = pattern[1];
1387
+ let regexpStr = pattern[2] || "[^/]+";
1388
+ if (name && pattern[2]) {
1389
+ if (regexpStr === ".*") throw PATH_ERROR;
1390
+ regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
1391
+ if (/\((?!\?:)/.test(regexpStr)) throw PATH_ERROR;
1392
+ if (regexpStr.length === 1 && regExpMetaChars.has(regexpStr)) throw PATH_ERROR;
1393
+ }
1394
+ nextNode = node.#children[regexpStr];
1395
+ if (!nextNode) {
1396
+ if (regexpStr !== ".*" && regexpStr !== "(?:|/.*)") {
1397
+ for (const k in node.#children) if ((regexpStr.length > 1 || k.length > 1) && k !== ".*" && k !== "(?:|/.*)") throw PATH_ERROR;
1398
+ }
1399
+ nextNode = node.#children[regexpStr] = new Node2();
1400
+ }
1401
+ if (name !== "") {
1402
+ nextNode.#varIndex ??= context.varIndex++;
1403
+ paramMap.push([name, nextNode.#varIndex]);
1404
+ }
1405
+ } else {
1406
+ nextNode = node.#children[token];
1407
+ if (!nextNode) {
1408
+ for (const k in node.#children) if (k.length > 1 && k !== ".*" && k !== "(?:|/.*)") throw PATH_ERROR;
1409
+ nextNode = node.#children[token] = new Node2();
1410
+ }
1411
+ }
1412
+ node = nextNode;
1413
+ }
1414
+ if (node.#index !== void 0) throw PATH_ERROR;
1415
+ node.#index = isStatic ? -1 : index;
1416
+ }
1417
+ buildRegExpStr() {
1418
+ const strList = Object.keys(this.#children).sort(compareKey).map((k) => {
1419
+ const c = this.#children[k];
1420
+ const childStr = c.buildRegExpStr();
1421
+ return childStr === "" ? "" : (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + childStr;
1422
+ }).filter(Boolean);
1423
+ if (typeof this.#index === "number" && this.#index !== -1) strList.unshift(`#${this.#index}`);
1424
+ if (strList.length === 0) return "";
1425
+ if (strList.length === 1) return strList[0];
1426
+ return "(?:" + strList.join("|") + ")";
1427
+ }
1428
+ };
1429
+
1430
+ // node_modules/hono/dist/router/reg-exp-router/trie.js
1431
+ var Trie = class {
1432
+ #context = { varIndex: 0 };
1433
+ #root = new Node();
1434
+ #index = 0;
1435
+ paths = createNullObject();
1436
+ insert(path, isStatic) {
1437
+ if (isStatic) {
1438
+ this.#root.insert(path.split(""), 0, [], this.#context, true);
1439
+ return;
1440
+ }
1441
+ const paramAssoc = [];
1442
+ const groups = [];
1443
+ let markedPath = path;
1444
+ for (let i = 0; ; ) {
1445
+ let replaced = false;
1446
+ markedPath = markedPath.replace(/\{[^}]+\}/g, (m) => {
1447
+ const mark = `@\\${i}`;
1448
+ groups[i] = [mark, m];
1449
+ i++;
1450
+ replaced = true;
1451
+ return mark;
1452
+ });
1453
+ if (!replaced) break;
1454
+ }
1455
+ const tokens = markedPath.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
1456
+ for (let i = groups.length - 1; i >= 0; i--) {
1457
+ const [mark] = groups[i];
1458
+ for (let j = tokens.length - 1; j >= 0; j--) if (tokens[j].indexOf(mark) !== -1) {
1459
+ tokens[j] = tokens[j].replace(mark, groups[i][1]);
1460
+ break;
1461
+ }
1462
+ }
1463
+ this.#root.insert(tokens, this.#index, paramAssoc, this.#context, false);
1464
+ this.paths[path] = [this.#index++, paramAssoc];
1465
+ }
1466
+ buildRegExp() {
1467
+ let regexp = this.#root.buildRegExpStr();
1468
+ if (regexp === "") return [
1469
+ /^$/,
1470
+ [],
1471
+ []
1472
+ ];
1473
+ let captureIndex = 0;
1474
+ const indexReplacementMap = [];
1475
+ const paramReplacementMap = [];
1476
+ regexp = regexp.replace(/#(\d+)|@(\d+)|\.\*\$/g, (_, handlerIndex, paramIndex) => {
1477
+ if (handlerIndex !== void 0) {
1478
+ indexReplacementMap[++captureIndex] = Number(handlerIndex);
1479
+ return "$()";
1480
+ }
1481
+ if (paramIndex !== void 0) {
1482
+ paramReplacementMap[Number(paramIndex)] = ++captureIndex;
1483
+ return "";
1484
+ }
1485
+ return "";
1486
+ });
1487
+ return [
1488
+ new RegExp(`^${regexp}`),
1489
+ indexReplacementMap,
1490
+ paramReplacementMap
1491
+ ];
1492
+ }
1493
+ };
1494
+
1495
+ // node_modules/hono/dist/router/reg-exp-router/router.js
1496
+ var wildcardRegExpCache = createNullObject();
1497
+ function buildWildcardRegExp(path) {
1498
+ return wildcardRegExpCache[path] ??= new RegExp(`^${path.replace(/\/:[^/{}]+(?:\{\[\^\/]\+})?(?=[/{]|$)|\/?\*$|([.\\+*[^\]$()?{}|])/g, (match2, metaChar) => metaChar ? `\\${metaChar}` : match2 === "/*" ? TAIL_WILDCARD_REG_EXP_STR : match2 === "*" ? ".*" : `/:${LABEL_REG_EXP_STR}`)}$`);
1499
+ }
1500
+ function findMiddleware(middleware, path) {
1501
+ for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length)) if (buildWildcardRegExp(k).test(path)) return [...middleware[k]];
1502
+ }
1503
+ var RegExpRouter = class {
1504
+ name = "RegExpRouter";
1505
+ #middleware;
1506
+ #routes;
1507
+ #tries;
1508
+ constructor() {
1509
+ this.#middleware = { ["ALL"]: createNullObject() };
1510
+ this.#routes = { ["ALL"]: createNullObject() };
1511
+ this.#tries = { ["ALL"]: new Trie() };
1512
+ }
1513
+ #insertPath(method, path) {
1514
+ try {
1515
+ this.#tries[method].insert(path, !/\*|\/:/.test(path));
1516
+ } catch (e) {
1517
+ throw e === PATH_ERROR ? new UnsupportedPathError(path) : e;
1518
+ }
1519
+ }
1520
+ add(method, path, handler) {
1521
+ const middleware = this.#middleware;
1522
+ const routes = this.#routes;
1523
+ if (!middleware) throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
1524
+ if (!middleware[method]) {
1525
+ this.#tries[method] = new Trie();
1526
+ for (const handlerMap of [middleware, routes]) {
1527
+ handlerMap[method] = createNullObject();
1528
+ for (const p in handlerMap["ALL"]) {
1529
+ handlerMap[method][p] = [...handlerMap["ALL"][p]];
1530
+ this.#insertPath(method, p);
1531
+ }
1532
+ }
1533
+ }
1534
+ if (path === "/*") path = "*";
1535
+ const methods = method === "ALL" ? Object.keys(middleware) : [method];
1536
+ if (/\*$/.test(path)) {
1537
+ const re = buildWildcardRegExp(path);
1538
+ for (const m of methods) if (!middleware[m][path]) {
1539
+ this.#insertPath(m, path);
1540
+ middleware[m][path] = findMiddleware(middleware[m], path) || findMiddleware(middleware["ALL"], path) || [];
1541
+ }
1542
+ for (const handlerMap of [middleware, routes]) for (const m of methods) for (const p in handlerMap[m]) re.test(p) && handlerMap[m][p].push([handler, path]);
1543
+ return;
1544
+ }
1545
+ const paths = checkOptionalParameter(path) || [path];
1546
+ for (const path2 of paths) for (const m of methods) {
1547
+ if (!routes[m][path2]) {
1548
+ this.#insertPath(m, path2);
1549
+ routes[m][path2] = findMiddleware(middleware[m], path2) || findMiddleware(middleware["ALL"], path2) || [];
1550
+ }
1551
+ routes[m][path2].push([handler, path2]);
1552
+ }
1553
+ }
1554
+ match = match;
1555
+ buildAllMatchers() {
1556
+ const matchers = createNullObject();
1557
+ for (const method of Object.keys(this.#routes)) matchers[method] = this.#buildMatcher(method);
1558
+ this.#middleware = this.#routes = this.#tries = void 0;
1559
+ wildcardRegExpCache = createNullObject();
1560
+ return matchers;
1561
+ }
1562
+ #buildMatcher(method) {
1563
+ const middleware = this.#middleware[method];
1564
+ const routes = this.#routes[method];
1565
+ const trie = this.#tries[method];
1566
+ const staticMap = createNullObject();
1567
+ const handlerData = [];
1568
+ const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
1569
+ for (const r of [middleware, routes]) for (const path in r) {
1570
+ const handlers = r[path];
1571
+ const pathData = trie.paths[path];
1572
+ if (!pathData) {
1573
+ staticMap[path] = [handlers.map(([h]) => [h, createNullObject()]), emptyParam];
1574
+ continue;
1575
+ }
1576
+ handlerData[pathData[0]] = handlers.map(([h, handlerPath]) => [h, trie.paths[handlerPath][1].reduceRight((map, [key], i) => {
1577
+ map[key] = paramReplacementMap[pathData[1][i][1]];
1578
+ return map;
1579
+ }, createNullObject())]);
1580
+ }
1581
+ return [
1582
+ regexp,
1583
+ indexReplacementMap.map((i) => handlerData[i]),
1584
+ staticMap
1585
+ ];
1586
+ }
1587
+ };
1588
+
1589
+ // node_modules/hono/dist/router/smart-router/router.js
1590
+ var SmartRouter = class {
1591
+ name = "SmartRouter";
1592
+ #routers = [];
1593
+ #routes = [];
1594
+ constructor(init) {
1595
+ this.#routers = init.routers;
1596
+ }
1597
+ add(method, path, handler) {
1598
+ if (!this.#routes) throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
1599
+ this.#routes.push([
1600
+ method,
1601
+ path,
1602
+ handler
1603
+ ]);
1604
+ }
1605
+ match(method, path) {
1606
+ if (!this.#routes) throw new Error("Fatal error");
1607
+ const routers = this.#routers;
1608
+ const routes = this.#routes;
1609
+ const len = routers.length;
1610
+ let i = 0;
1611
+ let res;
1612
+ for (; i < len; i++) {
1613
+ const router = routers[i];
1614
+ try {
1615
+ for (let i2 = 0, len2 = routes.length; i2 < len2; i2++) router.add(...routes[i2]);
1616
+ res = router.match(method, path);
1617
+ } catch (e) {
1618
+ if (e instanceof UnsupportedPathError) continue;
1619
+ throw e;
1620
+ }
1621
+ this.match = router.match.bind(router);
1622
+ this.#routers = [router];
1623
+ this.#routes = void 0;
1624
+ break;
1625
+ }
1626
+ if (i === len) throw new Error("Fatal error");
1627
+ this.name = `SmartRouter + ${this.activeRouter.name}`;
1628
+ return res;
1629
+ }
1630
+ get activeRouter() {
1631
+ if (this.#routes || this.#routers.length !== 1) throw new Error("No active router has been determined yet.");
1632
+ return this.#routers[0];
1633
+ }
1634
+ };
1635
+
1636
+ // node_modules/hono/dist/router/trie-router/node.js
1637
+ var emptyParams = createNullObject();
1638
+ var order = 0;
1639
+ var Node3 = class Node4 {
1640
+ #methods = [];
1641
+ #children = createNullObject();
1642
+ #patterns = [];
1643
+ #pattern;
1644
+ #params = emptyParams;
1645
+ insert(method, path, handler) {
1646
+ let curNode = this;
1647
+ const parts = splitRoutingPath(path);
1648
+ const possibleKeys = /* @__PURE__ */ new Set();
1649
+ let i = 0;
1650
+ for (const p of parts) {
1651
+ const nextP = parts[++i];
1652
+ const pattern = getPattern(p, nextP) || (nextP === void 0 && p && p.indexOf("*") === p.length - 1 ? p : null);
1653
+ const isParam = Array.isArray(pattern);
1654
+ const key = isParam ? pattern[0] : pattern || p;
1655
+ const child = curNode.#children[key] ||= new Node4();
1656
+ if (pattern && !child.#pattern) {
1657
+ child.#pattern = pattern;
1658
+ curNode.#patterns.push(child);
1659
+ }
1660
+ curNode = child;
1661
+ if (isParam) possibleKeys.add(pattern[1]);
1662
+ }
1663
+ curNode.#methods.push({ [method]: {
1664
+ handler,
1665
+ possibleKeys: [...possibleKeys],
1666
+ score: ++order
1667
+ } });
1668
+ }
1669
+ #pushHandlerSets(handlerSets, node, method, nodeParams, params) {
1670
+ for (let i = 0, len = node.#methods.length; i < len; i++) {
1671
+ const m = node.#methods[i];
1672
+ const handlerSet = m[method] || m["ALL"];
1673
+ if (handlerSet) {
1674
+ handlerSet.params = createNullObject();
1675
+ handlerSets.push(handlerSet);
1676
+ for (let i2 = 0, len2 = handlerSet.possibleKeys.length; i2 < len2; i2++) {
1677
+ const key = handlerSet.possibleKeys[i2];
1678
+ handlerSet.params[key] = params?.[key] && !i2 ? params[key] : nodeParams[key] ?? params?.[key];
1679
+ }
1680
+ }
1681
+ }
1682
+ }
1683
+ search(method, path) {
1684
+ const handlerSets = [];
1685
+ this.#params = emptyParams;
1686
+ let curNodes = [this];
1687
+ const parts = splitPath(path);
1688
+ const curNodesQueue = [];
1689
+ const len = parts.length;
1690
+ let partOffsets = null;
1691
+ for (let i = 0; i < len; i++) {
1692
+ const part = parts[i];
1693
+ const isLast = i === len - 1;
1694
+ const tempNodes = [];
1695
+ for (let j = 0, len2 = curNodes.length; j < len2; j++) {
1696
+ const node = curNodes[j];
1697
+ const nextNode = node.#children[part];
1698
+ if (nextNode) {
1699
+ nextNode.#params = node.#params;
1700
+ if (isLast) {
1701
+ if (nextNode.#children["*"]) this.#pushHandlerSets(handlerSets, nextNode.#children["*"], method, node.#params);
1702
+ this.#pushHandlerSets(handlerSets, nextNode, method, node.#params);
1703
+ } else tempNodes.push(nextNode);
1704
+ }
1705
+ for (const child of node.#patterns) {
1706
+ const pattern = child.#pattern;
1707
+ const params = node.#params === emptyParams ? {} : { ...node.#params };
1708
+ if (typeof pattern === "string") {
1709
+ if (pattern === "*" || part.startsWith(pattern.slice(0, -1))) {
1710
+ this.#pushHandlerSets(handlerSets, child, method, node.#params);
1711
+ if (pattern === "*") {
1712
+ child.#params = params;
1713
+ tempNodes.push(child);
1714
+ }
1715
+ }
1716
+ continue;
1717
+ }
1718
+ const [, name, matcher] = pattern;
1719
+ if (!part && matcher === true) continue;
1720
+ if (matcher !== true) {
1721
+ if (!partOffsets) {
1722
+ partOffsets = [];
1723
+ let offset = path[0] === "/" ? 1 : 0;
1724
+ for (let p = 0; p < len; p++) {
1725
+ partOffsets[p] = offset;
1726
+ offset += parts[p].length + 1;
1727
+ }
1728
+ }
1729
+ const restPathString = path.slice(partOffsets[i]);
1730
+ const m = matcher.exec(restPathString);
1731
+ if (m) {
1732
+ if (!Object.hasOwn(params, name)) params[name] = m[0];
1733
+ this.#pushHandlerSets(handlerSets, child, method, node.#params, params);
1734
+ if (m[0].length === restPathString.length && child.#children["*"]) this.#pushHandlerSets(handlerSets, child.#children["*"], method, node.#params, params);
1735
+ for (const _ in child.#children) {
1736
+ child.#params = params;
1737
+ const componentCount = m[0].match(/\//g)?.length ?? 0;
1738
+ (curNodesQueue[componentCount] ||= []).push(child);
1739
+ break;
1740
+ }
1741
+ continue;
1742
+ }
1743
+ }
1744
+ if (matcher === true || matcher.test(part)) {
1745
+ if (!Object.hasOwn(params, name)) params[name] = part;
1746
+ if (isLast) {
1747
+ this.#pushHandlerSets(handlerSets, child, method, params, node.#params);
1748
+ if (child.#children["*"]) this.#pushHandlerSets(handlerSets, child.#children["*"], method, params, node.#params);
1749
+ } else {
1750
+ child.#params = params;
1751
+ tempNodes.push(child);
1752
+ }
1753
+ }
1754
+ }
1755
+ }
1756
+ const shifted = curNodesQueue.shift();
1757
+ curNodes = shifted ? tempNodes.concat(shifted) : tempNodes;
1758
+ }
1759
+ if (handlerSets[1]) handlerSets.sort((a, b) => {
1760
+ return a.score - b.score;
1761
+ });
1762
+ return [handlerSets.map(({ handler, params }) => [handler, params])];
1763
+ }
1764
+ };
1765
+
1766
+ // node_modules/hono/dist/router/trie-router/router.js
1767
+ var TrieRouter = class {
1768
+ name = "TrieRouter";
1769
+ #node = new Node3();
1770
+ add(method, path, handler) {
1771
+ for (const result of checkOptionalParameter(path) || [path]) this.#node.insert(method, result, handler);
1772
+ }
1773
+ match(method, path) {
1774
+ return this.#node.search(method, path);
1775
+ }
1776
+ };
1777
+
1778
+ // node_modules/hono/dist/hono.js
1779
+ var Hono3 = class extends Hono {
1780
+ /**
1781
+ * Creates an instance of the Hono class.
1782
+ *
1783
+ * @param options - Optional configuration options for the Hono instance.
1784
+ */
1785
+ constructor(options = {}) {
1786
+ super(options);
1787
+ this.router = options.router ?? new SmartRouter({ routers: [new RegExpRouter(), new TrieRouter()] });
1788
+ }
1789
+ };
1790
+
1791
+ // src/worker.ts
1792
+ var MIN_TOKEN_LENGTH = 32;
1793
+ var DEFAULT_MAX_IMAGE_BYTES = 1e6;
1794
+ var MAX_JSON_BYTES = 1e6;
1795
+ var STATUS = {
1796
+ INVALID: 422,
1797
+ DUPLICATE_ID: 409,
1798
+ NOT_FOUND: 404,
1799
+ BAD_REFERENCE: 422,
1800
+ LIMIT: 422,
1801
+ UNAVAILABLE: 503,
1802
+ FORBIDDEN: 403
1803
+ };
1804
+ var fail = (code, message, status) => new Response(JSON.stringify({ error: { code, message } }), { status, headers: { "content-type": "application/json" } });
1805
+ function sameText(a, b) {
1806
+ const x = new TextEncoder().encode(a);
1807
+ const y = new TextEncoder().encode(b);
1808
+ let diff = x.length ^ y.length;
1809
+ for (let i = 0; i < Math.max(x.length, y.length); i++) diff |= (x[i] ?? 0) ^ (y[i] ?? 0);
1810
+ return diff === 0;
1811
+ }
1812
+ function authenticate(request, env) {
1813
+ const token = /^Bearer (.+)$/.exec(request.headers.get("authorization") ?? "")?.[1];
1814
+ if (!token || !env.CANVAS_API_TOKENS) return null;
1815
+ let grants;
1816
+ try {
1817
+ grants = JSON.parse(env.CANVAS_API_TOKENS);
1818
+ } catch {
1819
+ return null;
1820
+ }
1821
+ if (typeof grants !== "object" || grants === null || Array.isArray(grants)) return null;
1822
+ let found;
1823
+ for (const [candidate, grant] of Object.entries(grants)) {
1824
+ if (sameText(candidate, token) && candidate.length >= MIN_TOKEN_LENGTH) found = grant;
1825
+ }
1826
+ if (typeof found !== "object" || found === null) return null;
1827
+ const { actor, kind, role = "editor" } = found;
1828
+ const parsed = principalSchema.safeParse({ kind, id: actor });
1829
+ return parsed.success && (role === "editor" || role === "viewer") ? { actor: parsed.data, role } : null;
1830
+ }
1831
+ function sniffImage(bytes) {
1832
+ const at = (offset, ...sig) => sig.every((b, i) => bytes[offset + i] === b);
1833
+ if (at(0, 137, 80, 78, 71, 13, 10, 26, 10)) return "image/png";
1834
+ if (at(0, 255, 216, 255)) return "image/jpeg";
1835
+ if (at(0, 71, 73, 70, 56) && (bytes[4] === 55 || bytes[4] === 57) && bytes[5] === 97) return "image/gif";
1836
+ if (at(0, 82, 73, 70, 70) && at(8, 87, 69, 66, 80)) return "image/webp";
1837
+ return null;
1838
+ }
1839
+ var hex = (bytes) => [...new Uint8Array(bytes)].map((b) => b.toString(16).padStart(2, "0")).join("");
1840
+ var IMAGE_ID = /^[0-9a-f]{64}$/;
1841
+ var schemas = /* @__PURE__ */ new WeakMap();
1842
+ async function ready(db) {
1843
+ let run = schemas.get(db);
1844
+ if (!run) {
1845
+ run = db.prepare(D1_SCHEMA).run().catch((error) => {
1846
+ schemas.delete(db);
1847
+ throw error;
1848
+ });
1849
+ schemas.set(db, run);
1850
+ }
1851
+ await run;
1852
+ }
1853
+ async function readLimited(request, max) {
1854
+ const chunks = [];
1855
+ let size = 0;
1856
+ const reader = request.body?.getReader();
1857
+ if (!reader) return new Uint8Array(0);
1858
+ for (; ; ) {
1859
+ const { done, value } = await reader.read();
1860
+ if (done) break;
1861
+ size += value.byteLength;
1862
+ if (size > max) {
1863
+ await reader.cancel();
1864
+ return null;
1865
+ }
1866
+ chunks.push(value);
1867
+ }
1868
+ const bytes = new Uint8Array(size);
1869
+ let at = 0;
1870
+ for (const chunk of chunks) bytes.set(chunk, (at += chunk.byteLength) - chunk.byteLength);
1871
+ return bytes;
1872
+ }
1873
+ async function jsonBody(c) {
1874
+ const bytes = await readLimited(c.req.raw, MAX_JSON_BYTES);
1875
+ if (!bytes) throw new CanvasError("INVALID", `the body must be at most ${MAX_JSON_BYTES} bytes`);
1876
+ let body;
1877
+ try {
1878
+ body = bytes.byteLength === 0 ? {} : JSON.parse(new TextDecoder().decode(bytes));
1879
+ } catch {
1880
+ throw new CanvasError("INVALID", "the body must be a JSON object");
1881
+ }
1882
+ if (typeof body !== "object" || body === null || Array.isArray(body)) throw new CanvasError("INVALID", "the body must be a JSON object");
1883
+ return body;
1884
+ }
1885
+ var text = (value, name) => {
1886
+ if (typeof value !== "string") throw new CanvasError("INVALID", `${name} must be a string`);
1887
+ return value;
1888
+ };
1889
+ var num = (value, name) => {
1890
+ if (typeof value !== "number" || !Number.isFinite(value)) throw new CanvasError("INVALID", `${name} must be a number`);
1891
+ return value;
1892
+ };
1893
+ var LOGGABLE = /^(D1_ERROR[^"]{0,150}|transaction kept conflicting)/;
1894
+ var TEMPORARY = /commit token|busy|locked|reset|overloaded|time ?out|timed out|temporar|unspecified error|network/i;
1895
+ var loggable = (error) => error instanceof Error ? LOGGABLE.exec(error.message)?.[0] ?? error.name : "unknown";
1896
+ function createApp(options = {}) {
1897
+ const app2 = new Hono3();
1898
+ app2.get("/health", (c) => c.json({ ok: true }));
1899
+ const api = new Hono3();
1900
+ api.use("*", async (c, next) => {
1901
+ let region;
1902
+ try {
1903
+ region = parseRegion(c.env.CANVAS_REGION ?? "");
1904
+ } catch {
1905
+ return fail("NOT_CONFIGURED", 'set CANVAS_REGION to "eu", "us", or "unknown"', 503);
1906
+ }
1907
+ if (!c.env.DB || !c.env.IMAGES) return fail("NOT_CONFIGURED", "bind DB (D1) and IMAGES (R2)", 503);
1908
+ const who = authenticate(c.req.raw, c.env);
1909
+ if (!who) return fail("UNAUTHORIZED", "send a valid bearer token", 401);
1910
+ if (who.role === "viewer" && c.req.method !== "GET") return fail("FORBIDDEN", "this token is a viewer; it cannot change a board", 403);
1911
+ c.set("actor", who.actor);
1912
+ c.set("role", who.role);
1913
+ await ready(c.env.DB);
1914
+ c.set("service", new CanvasService(createD1Store(c.env.DB, { region })));
1915
+ c.set("blobs", createR2Blobs(c.env.IMAGES, { region, urlBase: new URL(c.req.url).origin, urlSecret: `${crypto.randomUUID()}${crypto.randomUUID()}` }));
1916
+ await next();
1917
+ });
1918
+ api.get("/me", (c) => c.json({ actor: c.var.actor.id, kind: c.var.actor.kind, role: c.var.role }));
1919
+ api.get("/boards/:id/ws", async (c) => {
1920
+ if (!options.live) return fail("NOT_FOUND", "this server hosts no live rooms", 404);
1921
+ if (c.req.header("upgrade") !== "websocket") return fail("UPGRADE_REQUIRED", "open this route as a WebSocket", 426);
1922
+ const id = c.req.param("id");
1923
+ await c.var.service.assertExists(id);
1924
+ const { actor, role } = c.var;
1925
+ return options.live(c.env).connect(id, c.req.raw, { principal: { id: actor.id, kind: actor.kind }, role, name: actor.id });
1926
+ });
1927
+ api.get("/boards/:id/state", async (c) => !options.live ? fail("NOT_FOUND", "this server hosts no live rooms", 404) : c.body(new Uint8Array(await c.var.service.state(c.req.param("id"))), 200, { "content-type": "application/octet-stream" }));
1928
+ api.post("/boards/:id/checkpoint", async (c) => {
1929
+ if (!options.live) return fail("NOT_FOUND", "this server hosts no live rooms", 404);
1930
+ const id = c.req.param("id");
1931
+ await c.var.service.assertExists(id);
1932
+ const update = await readLimited(c.req.raw, MAX_LIVE_BYTES);
1933
+ if (!update) throw new CanvasError("INVALID", `the update must be at most ${MAX_LIVE_BYTES} bytes`);
1934
+ const authors = (await options.live(c.env).meta(id)).contributors.map(({ id: who, kind }) => ({ id: who, kind }));
1935
+ return c.json(await c.var.service.checkpoint(id, update, c.var.actor, authors));
1936
+ });
1937
+ api.post("/boards", async (c) => {
1938
+ const b = await jsonBody(c);
1939
+ const id = b.id === void 0 ? void 0 : text(b.id, "id");
1940
+ const title = b.title === void 0 ? void 0 : text(b.title, "title");
1941
+ return c.json(await c.var.service.create(c.var.actor, { id, title }), 201);
1942
+ });
1943
+ api.get("/boards/:id", async (c) => c.json(await c.var.service.read(c.req.param("id"))));
1944
+ api.get("/boards/:id/svg", async (c) => new Response(await c.var.service.exportSvg(c.req.param("id")), { headers: { "content-type": "image/svg+xml", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'; style-src 'unsafe-inline'; img-src data:" } }));
1945
+ api.post("/boards/:id/shapes", async (c) => c.json(await c.var.service.add(c.req.param("id"), await jsonBody(c), c.var.actor), 201));
1946
+ api.post("/boards/:id/connectors", async (c) => c.json(await c.var.service.connect(c.req.param("id"), await jsonBody(c), c.var.actor), 201));
1947
+ api.post("/boards/:id/flow", async (c) => c.json(await c.var.service.flow(c.req.param("id"), text((await jsonBody(c)).text, "text"), c.var.actor)));
1948
+ api.post("/boards/:id/move", async (c) => {
1949
+ const b = await jsonBody(c);
1950
+ return c.json(await c.var.service.move(c.req.param("id"), text(b.element, "element"), num(b.dx, "dx"), num(b.dy, "dy"), c.var.actor));
1951
+ });
1952
+ api.delete("/boards/:id/elements/:element", async (c) => {
1953
+ const removed = await c.var.service.remove(c.req.param("id"), c.req.param("element"));
1954
+ console.log(JSON.stringify({ level: "info", op: "remove", actorKind: c.var.actor.kind }));
1955
+ return c.json(removed);
1956
+ });
1957
+ api.post("/images", async (c) => {
1958
+ const max = Number(c.env.CANVAS_MAX_IMAGE_BYTES ?? DEFAULT_MAX_IMAGE_BYTES);
1959
+ if (!Number.isFinite(max) || max < 0) return fail("NOT_CONFIGURED", "CANVAS_MAX_IMAGE_BYTES must be a number of 0 or more", 503);
1960
+ const declared = Number(c.req.header("content-length"));
1961
+ if (Number.isFinite(declared) && declared > max) return fail("TOO_LARGE", `the image is over the limit of ${max} bytes`, 413);
1962
+ const bytes = await readLimited(c.req.raw, max);
1963
+ if (!bytes) return fail("TOO_LARGE", `the image is over the limit of ${max} bytes`, 413);
1964
+ const type = sniffImage(bytes);
1965
+ if (!type) return fail("UNSUPPORTED_TYPE", "the image must be PNG, JPEG, GIF, or WebP", 415);
1966
+ const id = hex(await crypto.subtle.digest("SHA-256", bytes));
1967
+ let stored;
1968
+ try {
1969
+ stored = await c.var.blobs.put(id, bytes, { contentType: type, ifNoneMatch: "*" });
1970
+ } catch (error) {
1971
+ console.error(JSON.stringify({ level: "error", message: loggable(error) }));
1972
+ if (error instanceof Error && TEMPORARY.test(error.message)) return fail("UNAVAILABLE", "the image store is busy. Try again", 503);
1973
+ throw error;
1974
+ }
1975
+ return c.json({ id, ref: `blob:${id}`, type, size: bytes.byteLength, created: stored !== null }, stored ? 201 : 200);
1976
+ });
1977
+ api.get("/images/:id", async (c) => {
1978
+ const id = c.req.param("id");
1979
+ const blob = IMAGE_ID.test(id) ? await c.var.blobs.get(id) : null;
1980
+ if (!blob) return fail("NOT_FOUND", "no such image", 404);
1981
+ return new Response(blob.data, { headers: { "content-type": blob.contentType ?? "application/octet-stream", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'; sandbox", "content-disposition": "attachment", "cache-control": "private, no-store" } });
1982
+ });
1983
+ app2.route("/api/v1/canvas", api);
1984
+ app2.notFound(() => fail("NOT_FOUND", "no such route", 404));
1985
+ app2.onError((error) => {
1986
+ if (error instanceof Error && error.message.startsWith("D1_ERROR")) {
1987
+ console.error(JSON.stringify({ level: "error", message: loggable(error) }));
1988
+ if (/too big|too large/i.test(error.message)) return fail("LIMIT", "the board is too big to store", 422);
1989
+ if (TEMPORARY.test(error.message)) return fail("UNAVAILABLE", "the database is busy. Try again", 503);
1990
+ }
1991
+ if (error instanceof CanvasError) return fail(error.code, error.message, STATUS[error.code]);
1992
+ console.error(JSON.stringify({ level: "error", message: loggable(error) }));
1993
+ return fail("INTERNAL", "the server could not finish the request", 500);
1994
+ });
1995
+ return app2;
1996
+ }
1997
+ var app = createApp();
1998
+ var worker_default = { fetch: (request, env, ctx) => app.fetch(request, env, ctx) };
1999
+
2000
+ export {
2001
+ authenticate,
2002
+ sniffImage,
2003
+ createApp,
2004
+ worker_default
2005
+ };