@void/platform 0.20.0 → 0.20.1

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.
@@ -28,22 +28,22 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  mod
29
29
  ));
30
30
 
31
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/unenv@2.0.0-rc.24/node_modules/unenv/dist/runtime/_internal/utils.mjs
31
+ // ../../home/runner/work/void/void/node_modules/.pnpm/unenv@2.0.0-rc.24/node_modules/unenv/dist/runtime/_internal/utils.mjs
32
32
  // @__NO_SIDE_EFFECTS__
33
33
  function createNotImplementedError(name) {
34
34
  return new Error(`[unenv] ${name} is not implemented yet!`);
35
35
  }
36
36
  var init_utils = __esm({
37
- "../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/unenv@2.0.0-rc.24/node_modules/unenv/dist/runtime/_internal/utils.mjs"() {
37
+ "../../home/runner/work/void/void/node_modules/.pnpm/unenv@2.0.0-rc.24/node_modules/unenv/dist/runtime/_internal/utils.mjs"() {
38
38
  init_performance2();
39
39
  __name(createNotImplementedError, "createNotImplementedError");
40
40
  }
41
41
  });
42
42
 
43
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/unenv@2.0.0-rc.24/node_modules/unenv/dist/runtime/node/internal/perf_hooks/performance.mjs
43
+ // ../../home/runner/work/void/void/node_modules/.pnpm/unenv@2.0.0-rc.24/node_modules/unenv/dist/runtime/node/internal/perf_hooks/performance.mjs
44
44
  var _timeOrigin, _performanceNow, nodeTiming, PerformanceEntry, PerformanceMark, PerformanceMeasure, PerformanceResourceTiming, PerformanceObserverEntryList, Performance, PerformanceObserver, performance;
45
45
  var init_performance = __esm({
46
- "../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/unenv@2.0.0-rc.24/node_modules/unenv/dist/runtime/node/internal/perf_hooks/performance.mjs"() {
46
+ "../../home/runner/work/void/void/node_modules/.pnpm/unenv@2.0.0-rc.24/node_modules/unenv/dist/runtime/node/internal/perf_hooks/performance.mjs"() {
47
47
  init_performance2();
48
48
  init_utils();
49
49
  _timeOrigin = globalThis.performance?.timeOrigin ?? Date.now();
@@ -285,17 +285,17 @@ var init_performance = __esm({
285
285
  }
286
286
  });
287
287
 
288
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/unenv@2.0.0-rc.24/node_modules/unenv/dist/runtime/node/perf_hooks.mjs
288
+ // ../../home/runner/work/void/void/node_modules/.pnpm/unenv@2.0.0-rc.24/node_modules/unenv/dist/runtime/node/perf_hooks.mjs
289
289
  var init_perf_hooks = __esm({
290
- "../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/unenv@2.0.0-rc.24/node_modules/unenv/dist/runtime/node/perf_hooks.mjs"() {
290
+ "../../home/runner/work/void/void/node_modules/.pnpm/unenv@2.0.0-rc.24/node_modules/unenv/dist/runtime/node/perf_hooks.mjs"() {
291
291
  init_performance2();
292
292
  init_performance();
293
293
  }
294
294
  });
295
295
 
296
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/@cloudflare+unenv-preset@2.16.1_unenv@2.0.0-rc.24_workerd@1.20260910.1/node_modules/@cloudflare/unenv-preset/dist/runtime/polyfill/performance.mjs
296
+ // ../../home/runner/work/void/void/node_modules/.pnpm/@cloudflare+unenv-preset@2.16.1_unenv@2.0.0-rc.24_workerd@1.20260910.1/node_modules/@cloudflare/unenv-preset/dist/runtime/polyfill/performance.mjs
297
297
  var init_performance2 = __esm({
298
- "../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/@cloudflare+unenv-preset@2.16.1_unenv@2.0.0-rc.24_workerd@1.20260910.1/node_modules/@cloudflare/unenv-preset/dist/runtime/polyfill/performance.mjs"() {
298
+ "../../home/runner/work/void/void/node_modules/.pnpm/@cloudflare+unenv-preset@2.16.1_unenv@2.0.0-rc.24_workerd@1.20260910.1/node_modules/@cloudflare/unenv-preset/dist/runtime/polyfill/performance.mjs"() {
299
299
  init_perf_hooks();
300
300
  if (!("__unenv__" in performance)) {
301
301
  const proto = Performance.prototype;
@@ -319,9 +319,9 @@ var init_performance2 = __esm({
319
319
  }
320
320
  });
321
321
 
322
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/email-validator@2.0.4/node_modules/email-validator/index.js
322
+ // ../../home/runner/work/void/void/node_modules/.pnpm/email-validator@2.0.4/node_modules/email-validator/index.js
323
323
  var require_email_validator = __commonJS({
324
- "../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/email-validator@2.0.4/node_modules/email-validator/index.js"(exports) {
324
+ "../../home/runner/work/void/void/node_modules/.pnpm/email-validator@2.0.4/node_modules/email-validator/index.js"(exports) {
325
325
  "use strict";
326
326
  init_performance2();
327
327
  var tester = /^[-!#$%&'*+\/0-9=?A-Z^_a-z{|}~](\.?[-!#$%&'*+\/0-9=?A-Z^_a-z`{|}~])*@[a-zA-Z0-9](-*\.?[a-zA-Z0-9])*\.[a-zA-Z](-?[a-zA-Z0-9])+$/;
@@ -346,19 +346,19 @@ var require_email_validator = __commonJS({
346
346
  }
347
347
  });
348
348
 
349
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/index.ts
349
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/index.ts
350
350
  init_performance2();
351
351
 
352
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/index.js
352
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/index.js
353
353
  init_performance2();
354
354
 
355
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/hono.js
355
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/hono.js
356
356
  init_performance2();
357
357
 
358
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/hono-base.js
358
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/hono-base.js
359
359
  init_performance2();
360
360
 
361
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/compose.js
361
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/compose.js
362
362
  init_performance2();
363
363
  var compose = /* @__PURE__ */ __name((middleware, onError, onNotFound) => {
364
364
  return (context, next) => {
@@ -404,29 +404,29 @@ var compose = /* @__PURE__ */ __name((middleware, onError, onNotFound) => {
404
404
  };
405
405
  }, "compose");
406
406
 
407
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/context.js
407
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/context.js
408
408
  init_performance2();
409
409
 
410
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/request.js
410
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/request.js
411
411
  init_performance2();
412
412
 
413
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/http-exception.js
413
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/http-exception.js
414
414
  init_performance2();
415
415
 
416
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/request/constants.js
416
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/request/constants.js
417
417
  init_performance2();
418
418
  var GET_MATCH_RESULT = /* @__PURE__ */ Symbol();
419
419
 
420
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/body.js
420
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/body.js
421
421
  init_performance2();
422
422
 
423
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/buffer.js
423
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/buffer.js
424
424
  init_performance2();
425
425
 
426
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/crypto.js
426
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/crypto.js
427
427
  init_performance2();
428
428
 
429
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/buffer.js
429
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/buffer.js
430
430
  var bufferToFormData = /* @__PURE__ */ __name((arrayBuffer, contentType) => {
431
431
  const response = new Response(arrayBuffer, {
432
432
  headers: {
@@ -437,7 +437,7 @@ var bufferToFormData = /* @__PURE__ */ __name((arrayBuffer, contentType) => {
437
437
  return response.formData();
438
438
  }, "bufferToFormData");
439
439
 
440
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/body.js
440
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/body.js
441
441
  var MAX_NESTING_DEPTH = 32;
442
442
  var MAX_NESTED_OBJECTS = 1e4;
443
443
  var isRawRequest = /* @__PURE__ */ __name((request) => "headers" in request, "isRawRequest");
@@ -537,7 +537,7 @@ var throwNestingLimitExceeded = /* @__PURE__ */ __name(() => {
537
537
  throw new Error("Nesting limit exceeded");
538
538
  }, "throwNestingLimitExceeded");
539
539
 
540
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/url.js
540
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/url.js
541
541
  init_performance2();
542
542
  var splitPath = /* @__PURE__ */ __name((path) => {
543
543
  const paths = path.split("/");
@@ -744,7 +744,7 @@ var getQueryParams = /* @__PURE__ */ __name((url, key) => {
744
744
  }, "getQueryParams");
745
745
  var decodeURIComponent_ = decodeURIComponent;
746
746
 
747
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/request.js
747
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/request.js
748
748
  var HonoRequest = class {
749
749
  static {
750
750
  __name(this, "HonoRequest");
@@ -1028,7 +1028,7 @@ var HonoRequest = class {
1028
1028
  }
1029
1029
  };
1030
1030
 
1031
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/html.js
1031
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/html.js
1032
1032
  init_performance2();
1033
1033
  var HtmlEscapedCallbackPhase = {
1034
1034
  Stringify: 1,
@@ -1071,7 +1071,7 @@ var resolveCallback = /* @__PURE__ */ __name(async (str, phase, preserveCallback
1071
1071
  }
1072
1072
  }, "resolveCallback");
1073
1073
 
1074
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/context.js
1074
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/context.js
1075
1075
  var TEXT_PLAIN = "text/plain; charset=UTF-8";
1076
1076
  var setDefaultContentType = /* @__PURE__ */ __name((contentType, headers) => {
1077
1077
  return {
@@ -1500,7 +1500,7 @@ var Context = class {
1500
1500
  }, "notFound");
1501
1501
  };
1502
1502
 
1503
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router.js
1503
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router.js
1504
1504
  init_performance2();
1505
1505
  var METHOD_NAME_ALL = "ALL";
1506
1506
  var METHOD_NAME_ALL_LOWERCASE = "all";
@@ -1512,11 +1512,11 @@ var UnsupportedPathError = class extends Error {
1512
1512
  }
1513
1513
  };
1514
1514
 
1515
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/constants.js
1515
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/constants.js
1516
1516
  init_performance2();
1517
1517
  var COMPOSED_HANDLER = "__COMPOSED_HANDLER";
1518
1518
 
1519
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/hono-base.js
1519
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/hono-base.js
1520
1520
  var notFoundHandler = /* @__PURE__ */ __name((c) => {
1521
1521
  return c.text("404 Not Found", 404);
1522
1522
  }, "notFoundHandler");
@@ -1627,14 +1627,14 @@ var Hono = class _Hono {
1627
1627
  * app.route("/api", app2) // GET /api/user
1628
1628
  * ```
1629
1629
  */
1630
- route(path, app4) {
1630
+ route(path, app5) {
1631
1631
  const subApp = this.basePath(path);
1632
- app4.routes.map((r) => {
1632
+ app5.routes.map((r) => {
1633
1633
  let handler;
1634
- if (app4.errorHandler === errorHandler) {
1634
+ if (app5.errorHandler === errorHandler) {
1635
1635
  handler = r.handler;
1636
1636
  } else {
1637
- handler = /* @__PURE__ */ __name(async (c, next) => (await compose([], app4.errorHandler)(c, () => r.handler(c, next))).res, "handler");
1637
+ handler = /* @__PURE__ */ __name(async (c, next) => (await compose([], app5.errorHandler)(c, () => r.handler(c, next))).res, "handler");
1638
1638
  handler[COMPOSED_HANDLER] = r.handler;
1639
1639
  }
1640
1640
  subApp.#addRoute(r.method, r.path, handler, r.basePath);
@@ -1897,17 +1897,17 @@ var Hono = class _Hono {
1897
1897
  }, "fire");
1898
1898
  };
1899
1899
 
1900
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/reg-exp-router/index.js
1900
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/reg-exp-router/index.js
1901
1901
  init_performance2();
1902
1902
 
1903
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/reg-exp-router/router.js
1903
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/reg-exp-router/router.js
1904
1904
  init_performance2();
1905
1905
 
1906
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/utils.js
1906
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/utils.js
1907
1907
  init_performance2();
1908
1908
  var createNullObject = /* @__PURE__ */ __name(() => /* @__PURE__ */ Object.create(null), "createNullObject");
1909
1909
 
1910
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/reg-exp-router/matcher.js
1910
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/reg-exp-router/matcher.js
1911
1911
  init_performance2();
1912
1912
  var emptyParam = [];
1913
1913
  function match(method, path) {
@@ -1930,7 +1930,7 @@ function match(method, path) {
1930
1930
  }
1931
1931
  __name(match, "match");
1932
1932
 
1933
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/reg-exp-router/node.js
1933
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/reg-exp-router/node.js
1934
1934
  init_performance2();
1935
1935
  var LABEL_REG_EXP_STR = "[^/]+";
1936
1936
  var ONLY_WILDCARD_REG_EXP_STR = ".*";
@@ -2042,7 +2042,7 @@ var Node = class _Node {
2042
2042
  }
2043
2043
  };
2044
2044
 
2045
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/reg-exp-router/trie.js
2045
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/reg-exp-router/trie.js
2046
2046
  init_performance2();
2047
2047
  var Trie = class {
2048
2048
  static {
@@ -2110,7 +2110,7 @@ var Trie = class {
2110
2110
  }
2111
2111
  };
2112
2112
 
2113
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/reg-exp-router/router.js
2113
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/reg-exp-router/router.js
2114
2114
  var wildcardRegExpCache = createNullObject();
2115
2115
  function buildWildcardRegExp(path) {
2116
2116
  return wildcardRegExpCache[path] ??= new RegExp(
@@ -2236,13 +2236,13 @@ var RegExpRouter = class {
2236
2236
  }
2237
2237
  };
2238
2238
 
2239
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/reg-exp-router/prepared-router.js
2239
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/reg-exp-router/prepared-router.js
2240
2240
  init_performance2();
2241
2241
 
2242
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/smart-router/index.js
2242
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/smart-router/index.js
2243
2243
  init_performance2();
2244
2244
 
2245
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/smart-router/router.js
2245
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/smart-router/router.js
2246
2246
  init_performance2();
2247
2247
  var SmartRouter = class {
2248
2248
  static {
@@ -2301,13 +2301,13 @@ var SmartRouter = class {
2301
2301
  }
2302
2302
  };
2303
2303
 
2304
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/trie-router/index.js
2304
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/trie-router/index.js
2305
2305
  init_performance2();
2306
2306
 
2307
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/trie-router/router.js
2307
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/trie-router/router.js
2308
2308
  init_performance2();
2309
2309
 
2310
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/trie-router/node.js
2310
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/trie-router/node.js
2311
2311
  init_performance2();
2312
2312
  var emptyParams = createNullObject();
2313
2313
  var order = 0;
@@ -2471,7 +2471,7 @@ var Node2 = class _Node2 {
2471
2471
  }
2472
2472
  };
2473
2473
 
2474
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/trie-router/router.js
2474
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/router/trie-router/router.js
2475
2475
  var TrieRouter = class {
2476
2476
  static {
2477
2477
  __name(this, "TrieRouter");
@@ -2488,7 +2488,7 @@ var TrieRouter = class {
2488
2488
  }
2489
2489
  };
2490
2490
 
2491
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/hono.js
2491
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/hono.js
2492
2492
  var Hono2 = class extends Hono {
2493
2493
  static {
2494
2494
  __name(this, "Hono");
@@ -2506,7 +2506,7 @@ var Hono2 = class extends Hono {
2506
2506
  }
2507
2507
  };
2508
2508
 
2509
- // ../../../../../../../Users/cnakazawa/Projects/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/middleware/cors/index.js
2509
+ // ../../home/runner/work/void/void/node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/middleware/cors/index.js
2510
2510
  init_performance2();
2511
2511
  var cors = /* @__PURE__ */ __name((options) => {
2512
2512
  const opts = {
@@ -2593,10 +2593,10 @@ var cors = /* @__PURE__ */ __name((options) => {
2593
2593
  }, "cors2");
2594
2594
  }, "cors");
2595
2595
 
2596
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/ai.ts
2596
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/ai.ts
2597
2597
  init_performance2();
2598
2598
 
2599
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/body.ts
2599
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/body.ts
2600
2600
  init_performance2();
2601
2601
  function isProxyBody(value) {
2602
2602
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -2619,7 +2619,7 @@ function isQueryValue(value) {
2619
2619
  }
2620
2620
  __name(isQueryValue, "isQueryValue");
2621
2621
 
2622
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/ai.ts
2622
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/ai.ts
2623
2623
  var DEFAULT_GATEWAY_ID = "void";
2624
2624
  var PROVIDER_AUTH_DEFAULTS = {
2625
2625
  "google-ai-studio": { header: "x-goog-api-key", prefix: "" }
@@ -2983,7 +2983,7 @@ ai.post("/toMarkdown", async (context) => {
2983
2983
  }
2984
2984
  });
2985
2985
 
2986
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/capabilities.ts
2986
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/capabilities.ts
2987
2987
  init_performance2();
2988
2988
  function proxyCapabilityEnabled(value, capability) {
2989
2989
  if (capability === "sandbox") {
@@ -3001,10 +3001,10 @@ function proxyCapabilityEnabled(value, capability) {
3001
3001
  }
3002
3002
  __name(proxyCapabilityEnabled, "proxyCapabilityEnabled");
3003
3003
 
3004
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/d1.ts
3004
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/d1.ts
3005
3005
  init_performance2();
3006
3006
 
3007
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/dispatch.ts
3007
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/dispatch.ts
3008
3008
  init_performance2();
3009
3009
  async function resolveWorker(api, jwtSecret, projectId) {
3010
3010
  const token = await hmacSign(projectId, jwtSecret);
@@ -3092,7 +3092,7 @@ async function hmacSign(data, secret) {
3092
3092
  }
3093
3093
  __name(hmacSign, "hmacSign");
3094
3094
 
3095
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/resolve.ts
3095
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/resolve.ts
3096
3096
  init_performance2();
3097
3097
  var cache = /* @__PURE__ */ new Map();
3098
3098
  async function resolveResource(api, jwtSecret, projectId, type, bindingName) {
@@ -3179,7 +3179,7 @@ async function hmacSign2(data, secret) {
3179
3179
  }
3180
3180
  __name(hmacSign2, "hmacSign");
3181
3181
 
3182
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/d1.ts
3182
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/d1.ts
3183
3183
  var CF_API = "https://api.cloudflare.com/client/v4";
3184
3184
  var d1 = new Hono2();
3185
3185
  d1.post("/query", async (context) => {
@@ -3252,10 +3252,13 @@ d1.post("/batch", async (context) => {
3252
3252
  return context.json({ error: "atomic D1 batch unavailable for active deployment" }, 503);
3253
3253
  });
3254
3254
 
3255
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/email-router.ts
3255
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/email-relay.ts
3256
3256
  init_performance2();
3257
3257
 
3258
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/api/src/reserved-slugs.ts
3258
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/email-router.ts
3259
+ init_performance2();
3260
+
3261
+ // ../../home/runner/work/void/void/platform/packages/api/src/reserved-slugs.ts
3259
3262
  init_performance2();
3260
3263
  var EMAIL_RESERVED_SLUGS = /* @__PURE__ */ new Set([
3261
3264
  "abuse",
@@ -3269,11 +3272,101 @@ function isReservedEmailSlug(slug) {
3269
3272
  }
3270
3273
  __name(isReservedEmailSlug, "isReservedEmailSlug");
3271
3274
 
3272
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/email-router.ts
3275
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/email-router.ts
3273
3276
  var import_email_validator = __toESM(require_email_validator(), 1);
3274
3277
  import { EmailMessage as EmailMessage2 } from "cloudflare:email";
3275
3278
 
3276
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/email.ts
3279
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/email-lease.ts
3280
+ init_performance2();
3281
+ var LEASE_CACHE_TTL_MS = 45 * 60 * 1e3;
3282
+ var leaseCache = /* @__PURE__ */ new Map();
3283
+ function dropEmailDomainLease(domain) {
3284
+ leaseCache.delete(domain);
3285
+ }
3286
+ __name(dropEmailDomainLease, "dropEmailDomainLease");
3287
+ function leaseBearer(lease) {
3288
+ return lease.kind === "api_token" ? lease.token : lease.accessToken;
3289
+ }
3290
+ __name(leaseBearer, "leaseBearer");
3291
+ async function leaseEmailDomainCredential(env, domain) {
3292
+ const cached = leaseCache.get(domain);
3293
+ if (cached && cached.expiresAt > Date.now()) {
3294
+ return cached.lease;
3295
+ }
3296
+ let res;
3297
+ try {
3298
+ const token = await hmacSign3(domain, env.JWT_SECRET);
3299
+ res = await env.API.fetch("https://api/internal/email/domain-credential", {
3300
+ method: "POST",
3301
+ headers: {
3302
+ "content-type": "application/json",
3303
+ "x-void-internal": token
3304
+ },
3305
+ body: JSON.stringify({ domain })
3306
+ });
3307
+ } catch {
3308
+ return null;
3309
+ }
3310
+ if (!res.ok) {
3311
+ return null;
3312
+ }
3313
+ let data;
3314
+ try {
3315
+ data = await res.json();
3316
+ } catch {
3317
+ return null;
3318
+ }
3319
+ const lease = parseLease(data);
3320
+ if (!lease) {
3321
+ return null;
3322
+ }
3323
+ leaseCache.set(domain, { lease, expiresAt: Date.now() + LEASE_CACHE_TTL_MS });
3324
+ return lease;
3325
+ }
3326
+ __name(leaseEmailDomainCredential, "leaseEmailDomainCredential");
3327
+ function parseLease(data) {
3328
+ if (typeof data !== "object" || data === null) {
3329
+ return null;
3330
+ }
3331
+ const kind = data.kind;
3332
+ if (kind === "api_token") {
3333
+ const token = data.token;
3334
+ return typeof token === "string" && token.length > 0 ? { kind, token } : null;
3335
+ }
3336
+ if (kind === "oauth_grant") {
3337
+ const accessToken = data.accessToken;
3338
+ return typeof accessToken === "string" && accessToken.length > 0 ? { kind, accessToken } : null;
3339
+ }
3340
+ return null;
3341
+ }
3342
+ __name(parseLease, "parseLease");
3343
+ var encoder3 = new TextEncoder();
3344
+ var cachedSignKey3;
3345
+ var cachedKeySecret3;
3346
+ async function getSignKey3(secret) {
3347
+ if (cachedSignKey3 && cachedKeySecret3 === secret) {
3348
+ return cachedSignKey3;
3349
+ }
3350
+ cachedSignKey3 = await crypto.subtle.importKey(
3351
+ "raw",
3352
+ encoder3.encode(secret),
3353
+ { name: "HMAC", hash: "SHA-256" },
3354
+ false,
3355
+ ["sign"]
3356
+ );
3357
+ cachedKeySecret3 = secret;
3358
+ return cachedSignKey3;
3359
+ }
3360
+ __name(getSignKey3, "getSignKey");
3361
+ async function hmacSign3(data, secret) {
3362
+ const key = await getSignKey3(secret);
3363
+ const sig = await crypto.subtle.sign("HMAC", key, encoder3.encode(data));
3364
+ const binary = String.fromCharCode(...new Uint8Array(sig));
3365
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
3366
+ }
3367
+ __name(hmacSign3, "hmacSign");
3368
+
3369
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/email.ts
3277
3370
  init_performance2();
3278
3371
  import { EmailMessage } from "cloudflare:email";
3279
3372
  var app = new Hono2();
@@ -3638,6 +3731,20 @@ app.post("/send", async (context) => {
3638
3731
  413
3639
3732
  );
3640
3733
  }
3734
+ const fromAt = from.indexOf("@");
3735
+ const fromDomain = fromAt === -1 ? "" : from.slice(fromAt + 1).toLowerCase();
3736
+ if (fromDomain !== "" && fromDomain !== senderDomain) {
3737
+ return sendViaCustomDomain(
3738
+ context,
3739
+ projectId,
3740
+ from,
3741
+ fromDomain,
3742
+ senderDomain,
3743
+ recipients,
3744
+ raw2,
3745
+ requestId
3746
+ );
3747
+ }
3641
3748
  const expectedSlug = await context.env.ROUTING.get(`email-slug:${projectId}`);
3642
3749
  if (!expectedSlug) {
3643
3750
  return context.json(
@@ -3858,6 +3965,276 @@ app.post("/send", async (context) => {
3858
3965
  }))
3859
3966
  });
3860
3967
  });
3968
+ function readSendRawAddressList(value) {
3969
+ const out = /* @__PURE__ */ new Set();
3970
+ if (Array.isArray(value)) {
3971
+ for (const entry of value) {
3972
+ if (typeof entry === "string") {
3973
+ out.add(entry.toLowerCase());
3974
+ }
3975
+ }
3976
+ }
3977
+ return out;
3978
+ }
3979
+ __name(readSendRawAddressList, "readSendRawAddressList");
3980
+ async function sendViaCustomDomain(context, projectId, from, fromDomain, senderDomain, recipients, raw2, requestId) {
3981
+ if (!/^[\x21-\x7e]+$/.test(from)) {
3982
+ return context.json(
3983
+ {
3984
+ ok: false,
3985
+ error: { code: "INVALID_FROM", message: "from address must be printable ASCII" }
3986
+ },
3987
+ 403
3988
+ );
3989
+ }
3990
+ const fromLower = from.toLowerCase();
3991
+ const mirror = await readEmailDomainMirror(context.env.ROUTING, fromDomain, { cacheTtl: 60 });
3992
+ if (!mirror || mirror.projectId !== projectId || mirror.status !== "active") {
3993
+ return context.json(
3994
+ {
3995
+ ok: false,
3996
+ error: {
3997
+ code: "INVALID_FROM",
3998
+ message: `from address must be on the configured sender domain (${senderDomain}) or a domain registered to this project`
3999
+ }
4000
+ },
4001
+ 403
4002
+ );
4003
+ }
4004
+ if (!mirror.accountId) {
4005
+ return context.json(
4006
+ {
4007
+ ok: false,
4008
+ error: { code: "UPSTREAM_ERROR", message: "email domain registration is incomplete" }
4009
+ },
4010
+ 502
4011
+ );
4012
+ }
4013
+ const mimeFrom = readMimeFromAddrSpec(raw2);
4014
+ if (!mimeFrom.ok || mimeFrom.addrSpec.toLowerCase() !== fromLower) {
4015
+ const detail = mimeFrom.ok ? "the From header address does not match the envelope sender" : MIME_FROM_REFUSALS[mimeFrom.reason];
4016
+ return context.json(
4017
+ {
4018
+ ok: false,
4019
+ error: {
4020
+ code: "INVALID_FROM",
4021
+ message: `mime From must be the envelope sender ${from}: ${detail}`
4022
+ }
4023
+ },
4024
+ 403
4025
+ );
4026
+ }
4027
+ const slug = await context.env.ROUTING.get(`email-slug:${projectId}`);
4028
+ if (!slug) {
4029
+ return context.json(
4030
+ {
4031
+ ok: false,
4032
+ error: {
4033
+ code: "UPSTREAM_ERROR",
4034
+ message: "project slug unknown \u2014 refusing to send"
4035
+ }
4036
+ },
4037
+ 502
4038
+ );
4039
+ }
4040
+ if (!SLUG_RE.test(slug)) {
4041
+ console.error(
4042
+ `[email-send] project ${projectId} slug malformed in KV: ${sanitizeForLog(slug, 64)}`
4043
+ );
4044
+ return context.json(
4045
+ {
4046
+ ok: false,
4047
+ error: {
4048
+ code: "UPSTREAM_ERROR",
4049
+ message: "project slug malformed in routing"
4050
+ }
4051
+ },
4052
+ 502
4053
+ );
4054
+ }
4055
+ const platformSuspension = await readRoutingSuspension(context.env.ROUTING, slug);
4056
+ if (platformSuspension.kind === "corrupt") {
4057
+ console.error(
4058
+ `[email-send] project ${projectId} routing blob malformed in KV for slug ${sanitizeForLog(slug, 64)}`
4059
+ );
4060
+ return context.json(
4061
+ {
4062
+ ok: false,
4063
+ error: {
4064
+ code: "UPSTREAM_ERROR",
4065
+ message: "project routing entry malformed"
4066
+ }
4067
+ },
4068
+ 502
4069
+ );
4070
+ }
4071
+ if (platformSuspension.kind === "suspended") {
4072
+ return context.json(
4073
+ {
4074
+ ok: false,
4075
+ error: {
4076
+ code: "QUOTA_EXCEEDED",
4077
+ message: `project is suspended (${sanitizeForLog(platformSuspension.reason, 64)})`
4078
+ }
4079
+ },
4080
+ 200
4081
+ );
4082
+ }
4083
+ if (await context.env.ROUTING.get(`email-suspended:${projectId}`)) {
4084
+ return context.json(
4085
+ { ok: false, error: { code: "QUOTA_EXCEEDED", message: "project email is suspended" } },
4086
+ 200
4087
+ );
4088
+ }
4089
+ const now = /* @__PURE__ */ new Date();
4090
+ const burstKey = `email-burst:${projectId}:${minuteBucket(now)}`;
4091
+ const burstCurrent = readCounter(await context.env.ROUTING.get(burstKey));
4092
+ const burstLimit = await getBurstLimit(context.env.ROUTING, projectId);
4093
+ if (burstCurrent + recipients.length > burstLimit) {
4094
+ return context.json(
4095
+ {
4096
+ ok: false,
4097
+ error: {
4098
+ code: "QUOTA_EXCEEDED",
4099
+ message: `outbound burst limit ${burstLimit}/min exceeded`
4100
+ }
4101
+ },
4102
+ 429
4103
+ );
4104
+ }
4105
+ const counterKey = `email-sent:${projectId}:${monthBucket(now)}`;
4106
+ const monthCurrent = readCounter(await context.env.ROUTING.get(counterKey));
4107
+ const monthLimit = await getMonthlyLimit(context.env.ROUTING, projectId);
4108
+ if (monthCurrent + recipients.length > monthLimit) {
4109
+ return context.json(
4110
+ {
4111
+ ok: false,
4112
+ error: {
4113
+ code: "QUOTA_EXCEEDED",
4114
+ message: `monthly outbound limit ${monthLimit} exceeded`
4115
+ }
4116
+ },
4117
+ 429
4118
+ );
4119
+ }
4120
+ let mimeMessage;
4121
+ try {
4122
+ mimeMessage = new TextDecoder("utf-8", { fatal: true, ignoreBOM: false }).decode(raw2);
4123
+ } catch {
4124
+ return context.json(
4125
+ { ok: false, error: { code: "MIME_ERROR", message: "mime must be valid UTF-8" } },
4126
+ 400
4127
+ );
4128
+ }
4129
+ const lease = await leaseEmailDomainCredential(context.env, fromDomain);
4130
+ if (!lease) {
4131
+ return context.json(
4132
+ {
4133
+ ok: false,
4134
+ error: { code: "UPSTREAM_ERROR", message: "could not lease the domain credential" }
4135
+ },
4136
+ 502
4137
+ );
4138
+ }
4139
+ await Promise.all([
4140
+ context.env.ROUTING.put(counterKey, String(monthCurrent + recipients.length), {
4141
+ expirationTtl: monthTtlSeconds(now)
4142
+ }).catch((e) => {
4143
+ console.error(`[email-send] monthly counter put failed for ${projectId}:`, e);
4144
+ }),
4145
+ context.env.ROUTING.put(burstKey, String(burstCurrent + recipients.length), {
4146
+ expirationTtl: 5 * 60
4147
+ }).catch((e) => {
4148
+ console.error(`[email-send] burst counter put failed for ${projectId}:`, e);
4149
+ })
4150
+ ]);
4151
+ let failure = null;
4152
+ let messageId = "";
4153
+ let bounced = /* @__PURE__ */ new Set();
4154
+ let suppressed = /* @__PURE__ */ new Set();
4155
+ let cfRes = null;
4156
+ try {
4157
+ cfRes = await fetch(
4158
+ `https://api.cloudflare.com/client/v4/accounts/${mirror.accountId}/email/sending/send_raw`,
4159
+ {
4160
+ method: "POST",
4161
+ headers: {
4162
+ authorization: `Bearer ${leaseBearer(lease)}`,
4163
+ "content-type": "application/json"
4164
+ },
4165
+ body: JSON.stringify({ from, recipients, mime_message: mimeMessage })
4166
+ }
4167
+ );
4168
+ } catch {
4169
+ failure = { code: "UPSTREAM_ERROR", message: "email sending request failed" };
4170
+ }
4171
+ if (cfRes) {
4172
+ if (!cfRes.ok) {
4173
+ if (cfRes.status === 401 || cfRes.status === 403) {
4174
+ dropEmailDomainLease(fromDomain);
4175
+ }
4176
+ failure = {
4177
+ code: cfRes.status === 429 ? "QUOTA_EXCEEDED" : "UPSTREAM_ERROR",
4178
+ message: `email sending API returned ${cfRes.status}`
4179
+ };
4180
+ } else {
4181
+ let data = null;
4182
+ try {
4183
+ data = await cfRes.json();
4184
+ } catch {
4185
+ data = null;
4186
+ }
4187
+ const success = typeof data === "object" && data !== null && data.success === true;
4188
+ if (!success) {
4189
+ failure = { code: "UPSTREAM_ERROR", message: "email sending API refused the message" };
4190
+ } else {
4191
+ const result = data.result;
4192
+ const id = result?.message_id;
4193
+ messageId = typeof id === "string" ? id : "";
4194
+ bounced = readSendRawAddressList(result?.permanent_bounces);
4195
+ suppressed = readSendRawAddressList(result?.suppressed_recipients);
4196
+ }
4197
+ }
4198
+ }
4199
+ const deliveries = [];
4200
+ for (const r of recipients) {
4201
+ if (failure) {
4202
+ deliveries.push({ recipient: r, ok: false, error: failure });
4203
+ } else if (bounced.has(r)) {
4204
+ deliveries.push({
4205
+ recipient: r,
4206
+ ok: false,
4207
+ error: {
4208
+ code: "UNVERIFIED_DESTINATION",
4209
+ message: `recipient '${r}' permanently bounced`
4210
+ }
4211
+ });
4212
+ } else if (suppressed.has(r)) {
4213
+ deliveries.push({
4214
+ recipient: r,
4215
+ ok: false,
4216
+ error: {
4217
+ code: "UNVERIFIED_DESTINATION",
4218
+ message: `recipient '${r}' is on the suppression list`
4219
+ }
4220
+ });
4221
+ } else {
4222
+ deliveries.push({ recipient: r, ok: true, messageId });
4223
+ }
4224
+ }
4225
+ logSend(projectId, requestId, deliveries);
4226
+ if (deliveries.some((d) => !d.ok)) {
4227
+ return context.json({ ok: false, deliveries }, 200);
4228
+ }
4229
+ return context.json({
4230
+ ok: true,
4231
+ ids: deliveries.map((d) => ({
4232
+ recipient: d.recipient,
4233
+ messageId: d.messageId
4234
+ }))
4235
+ });
4236
+ }
4237
+ __name(sendViaCustomDomain, "sendViaCustomDomain");
3861
4238
  async function recordInboundDelivery(env, projectId, info) {
3862
4239
  const now = /* @__PURE__ */ new Date();
3863
4240
  const counterKey = `email-recv:${projectId}:${monthBucket(now)}`;
@@ -3927,6 +4304,35 @@ async function readAllowlist(kv2, projectId) {
3927
4304
  }
3928
4305
  }
3929
4306
  __name(readAllowlist, "readAllowlist");
4307
+ async function readEmailDomainMirror(kv2, domain, options) {
4308
+ const raw2 = await kv2.get(`email-domain:${domain}`, options);
4309
+ if (!raw2) {
4310
+ return null;
4311
+ }
4312
+ let parsed;
4313
+ try {
4314
+ parsed = JSON.parse(raw2);
4315
+ } catch {
4316
+ return null;
4317
+ }
4318
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
4319
+ return null;
4320
+ }
4321
+ const entry = parsed;
4322
+ if (typeof entry.projectId !== "string" || entry.projectId === "" || typeof entry.status !== "string" || typeof entry.relaySecretSha256 !== "string") {
4323
+ return null;
4324
+ }
4325
+ return {
4326
+ projectId: entry.projectId,
4327
+ status: entry.status,
4328
+ relaySecretSha256: entry.relaySecretSha256,
4329
+ relayWorkerName: typeof entry.relayWorkerName === "string" ? entry.relayWorkerName : null,
4330
+ accountId: typeof entry.accountId === "string" ? entry.accountId : null,
4331
+ zoneId: typeof entry.zoneId === "string" ? entry.zoneId : null,
4332
+ mode: typeof entry.mode === "string" ? entry.mode : null
4333
+ };
4334
+ }
4335
+ __name(readEmailDomainMirror, "readEmailDomainMirror");
3930
4336
  function readCounter(raw2) {
3931
4337
  if (!raw2) {
3932
4338
  return 0;
@@ -4029,7 +4435,7 @@ app.post("/internal/send", async (context) => {
4029
4435
  }
4030
4436
  });
4031
4437
 
4032
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/email-router.ts
4438
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/email-router.ts
4033
4439
  var CONTROL_CHARS_RE2 = new RegExp("[\\u0000-\\u001f\\u007f]+", "g");
4034
4440
  function sanitize(value, maxLen) {
4035
4441
  return value.slice(0, maxLen).replace(CONTROL_CHARS_RE2, " ");
@@ -4129,7 +4535,7 @@ function forwardHeadersWithinBounds(headers) {
4129
4535
  return true;
4130
4536
  }
4131
4537
  __name(forwardHeadersWithinBounds, "forwardHeadersWithinBounds");
4132
- function isPermittedReplySender(from, pin) {
4538
+ async function isPermittedReplySender(from, pin) {
4133
4539
  if (!/^[\x21-\x7e]+$/.test(from)) {
4134
4540
  return false;
4135
4541
  }
@@ -4138,13 +4544,32 @@ function isPermittedReplySender(from, pin) {
4138
4544
  if (at <= 0) {
4139
4545
  return false;
4140
4546
  }
4141
- if (lower.slice(at + 1) !== pin.domain) {
4142
- return false;
4547
+ const fromDomain = lower.slice(at + 1);
4548
+ if (fromDomain === pin.domain) {
4549
+ const localPrefix = lower.slice(0, at).split("+")[0] ?? "";
4550
+ if (localPrefix.length > 0 && localPrefix === pin.slug) {
4551
+ return true;
4552
+ }
4143
4553
  }
4144
- const localPrefix = lower.slice(0, at).split("+")[0] ?? "";
4145
- return localPrefix.length > 0 && localPrefix === pin.slug;
4554
+ return isRegisteredDomainSender(fromDomain, pin);
4146
4555
  }
4147
4556
  __name(isPermittedReplySender, "isPermittedReplySender");
4557
+ async function isRegisteredDomainSender(fromDomain, pin) {
4558
+ if (!pin.projectId) {
4559
+ return false;
4560
+ }
4561
+ const cached = pin.registeredDomains.get(fromDomain);
4562
+ if (cached !== void 0) {
4563
+ return cached;
4564
+ }
4565
+ const mirror = await readEmailDomainMirror(pin.kv, fromDomain, { cacheTtl: 60 }).catch(
4566
+ () => null
4567
+ );
4568
+ const registered = mirror !== null && mirror.projectId === pin.projectId && mirror.status === "active";
4569
+ pin.registeredDomains.set(fromDomain, registered);
4570
+ return registered;
4571
+ }
4572
+ __name(isRegisteredDomainSender, "isRegisteredDomainSender");
4148
4573
  function readCounter2(raw2) {
4149
4574
  if (!raw2) {
4150
4575
  return 0;
@@ -4310,6 +4735,7 @@ async function routeInbound(message, env, ctx) {
4310
4735
  );
4311
4736
  gate = {
4312
4737
  projectId: routing.projectId,
4738
+ skipAllowlist: false,
4313
4739
  allowlist: /* @__PURE__ */ new Set(),
4314
4740
  burstKey: "",
4315
4741
  burstLimit: 0,
@@ -4353,14 +4779,228 @@ async function routeInbound(message, env, ctx) {
4353
4779
  );
4354
4780
  return;
4355
4781
  }
4356
- await enactActions(env, message, actions, gate, { slug, domain: receivedDomain });
4782
+ await enactActions(env, message, actions, gate, {
4783
+ slug,
4784
+ domain: receivedDomain,
4785
+ projectId: routing.projectId,
4786
+ kv: env.ROUTING,
4787
+ registeredDomains: /* @__PURE__ */ new Map()
4788
+ });
4357
4789
  ctx.waitUntil(logRecv(env, routing.projectId, message, actions));
4358
4790
  }
4359
4791
  __name(routeInbound, "routeInbound");
4360
- async function loadOutboundGate(env, projectId) {
4792
+ async function routeRelayed(env, ctx, input) {
4793
+ const { projectId, domain, envelope } = input;
4794
+ const slug = await env.ROUTING.get(`email-slug:${projectId}`);
4795
+ if (!slug) {
4796
+ console.error(`[email-relay] no slug mirror for project ${sanitize(projectId, 64)}`);
4797
+ return { reject: true };
4798
+ }
4799
+ const routingJson = await env.ROUTING.get(slug);
4800
+ if (!routingJson) {
4801
+ console.error(
4802
+ `[email-relay] no routing entry for slug ${sanitize(slug, 64)} (project ${sanitize(projectId, 64)})`
4803
+ );
4804
+ return { reject: true };
4805
+ }
4806
+ let parsedRouting;
4807
+ try {
4808
+ parsedRouting = JSON.parse(routingJson);
4809
+ } catch {
4810
+ console.error(`[email-relay] routing data corrupt for slug ${sanitize(slug, 64)}`);
4811
+ return { reject: true };
4812
+ }
4813
+ if (typeof parsedRouting !== "object" || parsedRouting === null) {
4814
+ console.error(`[email-relay] routing data corrupt for slug ${sanitize(slug, 64)}`);
4815
+ return { reject: true };
4816
+ }
4817
+ const routing = parsedRouting;
4818
+ if (routing.projectId !== projectId) {
4819
+ console.error(
4820
+ `[email-relay] routing blob names another project for slug ${sanitize(slug, 64)}`
4821
+ );
4822
+ return { reject: true };
4823
+ }
4824
+ if (routing.suspended) {
4825
+ console.error(`[email-relay] project ${sanitize(projectId, 64)} is suspended`);
4826
+ return { reject: true };
4827
+ }
4828
+ const workerName = routing.workerName;
4829
+ if (!workerName || typeof workerName !== "string") {
4830
+ console.error(`[email-relay] project ${sanitize(projectId, 64)} has no worker (static deploy)`);
4831
+ return { reject: true };
4832
+ }
4833
+ if (await env.ROUTING.get(`email-suspended:${projectId}`)) {
4834
+ console.error(`[email-relay] project ${sanitize(projectId, 64)} inbound is suspended`);
4835
+ return { reject: true };
4836
+ }
4837
+ let stub;
4838
+ try {
4839
+ stub = routing.limits ? env.DISPATCH.get(workerName, {}, { limits: routing.limits }) : env.DISPATCH.get(workerName);
4840
+ } catch (e) {
4841
+ console.error(`[email-relay] DISPATCH.get(${sanitize(workerName, 320)}) failed:`, e);
4842
+ return { reject: true };
4843
+ }
4844
+ const relayed = createRelayedMessage(env, envelope, { domain, projectId });
4845
+ let gate;
4846
+ try {
4847
+ gate = await loadOutboundGate(env, projectId, { skipAllowlist: true });
4848
+ } catch (e) {
4849
+ console.error(`[email-relay] failed to load outbound gate for ${sanitize(projectId, 64)}:`, e);
4850
+ gate = {
4851
+ projectId,
4852
+ skipAllowlist: true,
4853
+ allowlist: /* @__PURE__ */ new Set(),
4854
+ burstKey: "",
4855
+ burstLimit: 0,
4856
+ burstCurrent: 0,
4857
+ monthKey: "",
4858
+ monthLimit: 0,
4859
+ monthCurrent: 0,
4860
+ quotaExhausted: true
4861
+ };
4862
+ }
4863
+ let actions;
4864
+ try {
4865
+ const result = await stub.email(envelope);
4866
+ if (result === void 0 || result === null) {
4867
+ actions = [];
4868
+ } else if (Array.isArray(result)) {
4869
+ actions = result;
4870
+ } else {
4871
+ console.warn(
4872
+ `[email-relay] ${sanitize(workerName, 320)} email handler returned non-array; treating as no-op`
4873
+ );
4874
+ actions = [];
4875
+ }
4876
+ } catch (e) {
4877
+ const msg = e instanceof Error ? e.message.slice(0, 320) : describeUntrusted(e, 320);
4878
+ if (RPC_METHOD_MISSING.test(msg)) {
4879
+ console.error(
4880
+ `[email-relay] ${sanitize(workerName, 320)} has no .email() (needs redeploy):`,
4881
+ sanitize(msg, 320)
4882
+ );
4883
+ ctx.waitUntil(
4884
+ logRecv(env, projectId, relayed.message, [{ type: "reject", reason: "no-handler" }])
4885
+ );
4886
+ return { reject: true };
4887
+ }
4888
+ console.error(`[email-relay] dispatch to ${sanitize(workerName, 320)} failed:`, msg);
4889
+ ctx.waitUntil(
4890
+ logRecv(env, projectId, relayed.message, [{ type: "reject", reason: "dispatch-error" }])
4891
+ );
4892
+ return { reject: true };
4893
+ }
4894
+ await enactActions(env, relayed.message, actions, gate, {
4895
+ slug: slug.toLowerCase(),
4896
+ domain,
4897
+ projectId,
4898
+ kv: env.ROUTING,
4899
+ registeredDomains: /* @__PURE__ */ new Map()
4900
+ });
4901
+ ctx.waitUntil(logRecv(env, projectId, relayed.message, actions));
4902
+ return { reject: relayed.rejectedReason() !== null };
4903
+ }
4904
+ __name(routeRelayed, "routeRelayed");
4905
+ function createRelayedMessage(env, envelope, relay) {
4906
+ let reason = null;
4907
+ async function sendRaw(from, to, raw2) {
4908
+ const senderDomain = from.slice(from.indexOf("@") + 1).toLowerCase();
4909
+ const mirror = await readEmailDomainMirror(env.ROUTING, senderDomain);
4910
+ if (!mirror || mirror.projectId !== relay.projectId || mirror.status !== "active") {
4911
+ throw new Error("email domain registration is no longer active");
4912
+ }
4913
+ if (!mirror.accountId) {
4914
+ throw new Error("email domain registration is incomplete");
4915
+ }
4916
+ const lease = await leaseEmailDomainCredential(env, senderDomain);
4917
+ if (!lease) {
4918
+ throw new Error("could not lease the domain credential");
4919
+ }
4920
+ const mimeMessage = new TextDecoder("utf-8", { fatal: true, ignoreBOM: false }).decode(raw2);
4921
+ let res;
4922
+ try {
4923
+ res = await fetch(
4924
+ `https://api.cloudflare.com/client/v4/accounts/${mirror.accountId}/email/sending/send_raw`,
4925
+ {
4926
+ method: "POST",
4927
+ headers: {
4928
+ authorization: `Bearer ${leaseBearer(lease)}`,
4929
+ "content-type": "application/json"
4930
+ },
4931
+ body: JSON.stringify({ from, recipients: [to], mime_message: mimeMessage })
4932
+ }
4933
+ );
4934
+ } catch {
4935
+ throw new Error("email sending request failed");
4936
+ }
4937
+ if (res.status === 401 || res.status === 403) {
4938
+ dropEmailDomainLease(senderDomain);
4939
+ }
4940
+ if (!res.ok) {
4941
+ throw new Error(`email sending API returned ${res.status}`);
4942
+ }
4943
+ let data = null;
4944
+ try {
4945
+ data = await res.json();
4946
+ } catch {
4947
+ data = null;
4948
+ }
4949
+ const success = typeof data === "object" && data !== null && data.success === true;
4950
+ if (!success) {
4951
+ throw new Error("email sending API refused the message");
4952
+ }
4953
+ const result = data.result;
4954
+ const target = to.toLowerCase();
4955
+ if (readSendRawAddressList(result?.permanent_bounces).has(target)) {
4956
+ throw new Error("recipient permanently bounced");
4957
+ }
4958
+ if (readSendRawAddressList(result?.suppressed_recipients).has(target)) {
4959
+ throw new Error("recipient is on the suppression list");
4960
+ }
4961
+ }
4962
+ __name(sendRaw, "sendRaw");
4963
+ const message = {
4964
+ from: envelope.from,
4965
+ to: envelope.to,
4966
+ rawSize: envelope.rawSize,
4967
+ headers: new Headers(envelope.headers),
4968
+ raw: envelopeRawStream(envelope.raw),
4969
+ setReject(r) {
4970
+ reason = r;
4971
+ },
4972
+ async forward(to, _headers) {
4973
+ await sendRaw(envelope.to, to, envelope.raw);
4974
+ },
4975
+ // The reply channel `enactSanitized` prefers when present. A native
4976
+ // reply needs both the CF email event this lane never had and a genuine
4977
+ // EmailMessage — whose class exposes no body accessor, so the recorded
4978
+ // reply bytes could not cross it anyway; they arrive on the action.
4979
+ async __voidRelayReply(from, to, raw2) {
4980
+ await sendRaw(from, to, raw2);
4981
+ }
4982
+ };
4983
+ return {
4984
+ message,
4985
+ rejectedReason: /* @__PURE__ */ __name(() => reason, "rejectedReason")
4986
+ };
4987
+ }
4988
+ __name(createRelayedMessage, "createRelayedMessage");
4989
+ function envelopeRawStream(bytes) {
4990
+ return new ReadableStream({
4991
+ start(controller) {
4992
+ controller.enqueue(bytes);
4993
+ controller.close();
4994
+ }
4995
+ });
4996
+ }
4997
+ __name(envelopeRawStream, "envelopeRawStream");
4998
+ async function loadOutboundGate(env, projectId, opts) {
4999
+ const skipAllowlist = opts?.skipAllowlist ?? false;
4361
5000
  if (!projectId) {
4362
5001
  return {
4363
5002
  projectId: void 0,
5003
+ skipAllowlist,
4364
5004
  allowlist: /* @__PURE__ */ new Set(),
4365
5005
  burstKey: "",
4366
5006
  burstLimit: 0,
@@ -4371,7 +5011,7 @@ async function loadOutboundGate(env, projectId) {
4371
5011
  quotaExhausted: true
4372
5012
  };
4373
5013
  }
4374
- const allowlist = await readAllowlist2(env.ROUTING, projectId);
5014
+ const allowlist = skipAllowlist ? /* @__PURE__ */ new Set() : await readAllowlist2(env.ROUTING, projectId);
4375
5015
  const now = /* @__PURE__ */ new Date();
4376
5016
  const burstKey = `email-burst:${projectId}:${minuteBucket2(now)}`;
4377
5017
  const monthKey = `email-sent:${projectId}:${monthBucket2(now)}`;
@@ -4383,6 +5023,7 @@ async function loadOutboundGate(env, projectId) {
4383
5023
  ]);
4384
5024
  return {
4385
5025
  projectId,
5026
+ skipAllowlist,
4386
5027
  allowlist,
4387
5028
  burstKey,
4388
5029
  burstLimit,
@@ -4490,7 +5131,7 @@ async function readStreamToBytes(stream) {
4490
5131
  return out;
4491
5132
  }
4492
5133
  __name(readStreamToBytes, "readStreamToBytes");
4493
- function validateActions(actions, replySender) {
5134
+ async function validateActions(actions, replySender) {
4494
5135
  if (actions.length > MAX_ACTIONS) {
4495
5136
  console.error(
4496
5137
  `[email-router] action list dropped: ${actions.length} actions returned (max ${MAX_ACTIONS})`
@@ -4540,7 +5181,7 @@ function validateActions(actions, replySender) {
4540
5181
  );
4541
5182
  continue;
4542
5183
  }
4543
- if (!isPermittedReplySender(action.from, replySender)) {
5184
+ if (!await isPermittedReplySender(action.from, replySender)) {
4544
5185
  console.error(
4545
5186
  `[email-router] reply dropped: sender not owned by project "${sanitize(replySender.slug, 64)}" (from=${logAddress(action.from)})`
4546
5187
  );
@@ -4584,7 +5225,7 @@ function validateActions(actions, replySender) {
4584
5225
  }
4585
5226
  __name(validateActions, "validateActions");
4586
5227
  async function enactActions(env, message, actions, gate, replySender) {
4587
- const sanitized = validateActions(actions, replySender);
5228
+ const sanitized = await validateActions(actions, replySender);
4588
5229
  if (sanitized === null) {
4589
5230
  return;
4590
5231
  }
@@ -4621,14 +5262,19 @@ async function enactSanitized(env, message, actions, gate) {
4621
5262
  continue;
4622
5263
  }
4623
5264
  try {
4624
- const stream = new ReadableStream({
4625
- start(controller) {
4626
- controller.enqueue(action.raw);
4627
- controller.close();
4628
- }
4629
- });
4630
- const reply = new EmailMessage2(action.from, action.to, stream);
4631
- await message.reply(reply);
5265
+ const relayReply = message.__voidRelayReply;
5266
+ if (relayReply !== void 0) {
5267
+ await relayReply(action.from, action.to, action.raw);
5268
+ } else {
5269
+ const stream = new ReadableStream({
5270
+ start(controller) {
5271
+ controller.enqueue(action.raw);
5272
+ controller.close();
5273
+ }
5274
+ });
5275
+ const reply = new EmailMessage2(action.from, action.to, stream);
5276
+ await message.reply(reply);
5277
+ }
4632
5278
  gate.burstCurrent += 1;
4633
5279
  gate.monthCurrent += 1;
4634
5280
  counterDirty = true;
@@ -4659,7 +5305,7 @@ function checkOutboundGate(gate, target, kind) {
4659
5305
  return false;
4660
5306
  }
4661
5307
  const lowered = target.toLowerCase();
4662
- if (!gate.allowlist.has(lowered)) {
5308
+ if (!gate.skipAllowlist && !gate.allowlist.has(lowered)) {
4663
5309
  console.error(
4664
5310
  `[email-router] ${kind} dropped: recipient not in project allowlist (target=${sanitize(target, 320)})`
4665
5311
  );
@@ -4679,7 +5325,180 @@ function checkOutboundGate(gate, target, kind) {
4679
5325
  }
4680
5326
  __name(checkOutboundGate, "checkOutboundGate");
4681
5327
 
4682
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/kv.ts
5328
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/email-relay.ts
5329
+ var app2 = new Hono2();
5330
+ app2.post("/relay", async (context) => {
5331
+ const projectId = context.get("projectId");
5332
+ const from = context.req.header("X-Void-Email-From") ?? "";
5333
+ const to = context.req.header("X-Void-Email-To") ?? "";
5334
+ const domain = to.slice(to.lastIndexOf("@") + 1).toLowerCase();
5335
+ const body = context.req.raw.body;
5336
+ if (!body) {
5337
+ return context.json({ error: "mime body required" }, 400);
5338
+ }
5339
+ const raw2 = await readMimeBody(body);
5340
+ if (raw2 === null) {
5341
+ return context.json({ error: "mime too large" }, 413);
5342
+ }
5343
+ const headers = parseRelayedHeaders(raw2);
5344
+ if (headers === null) {
5345
+ return context.json({ error: "too many headers" }, 413);
5346
+ }
5347
+ const envelope = {
5348
+ from,
5349
+ to,
5350
+ headers,
5351
+ raw: raw2,
5352
+ rawSize: raw2.byteLength,
5353
+ viaDomain: domain
5354
+ };
5355
+ const pending = [];
5356
+ let ctx = {
5357
+ waitUntil(p) {
5358
+ pending.push(p);
5359
+ },
5360
+ passThroughOnException() {
5361
+ }
5362
+ };
5363
+ try {
5364
+ ctx = context.executionCtx;
5365
+ } catch {
5366
+ }
5367
+ const outcome = await routeRelayed(context.env, ctx, { projectId, domain, envelope });
5368
+ if (pending.length > 0) {
5369
+ await Promise.allSettled(pending);
5370
+ }
5371
+ if (outcome.reject) {
5372
+ return context.json({ error: "message rejected" }, 403);
5373
+ }
5374
+ return context.json({ ok: true });
5375
+ });
5376
+ async function readMimeBody(stream) {
5377
+ const reader = stream.getReader();
5378
+ const chunks = [];
5379
+ let total = 0;
5380
+ for (; ; ) {
5381
+ const { value, done } = await reader.read();
5382
+ if (done) {
5383
+ break;
5384
+ }
5385
+ total += value.byteLength;
5386
+ if (total > MAX_MIME_BYTES) {
5387
+ try {
5388
+ await reader.cancel();
5389
+ } catch {
5390
+ }
5391
+ return null;
5392
+ }
5393
+ chunks.push(value);
5394
+ }
5395
+ const out = new Uint8Array(total);
5396
+ let offset = 0;
5397
+ for (const c of chunks) {
5398
+ out.set(c, offset);
5399
+ offset += c.byteLength;
5400
+ }
5401
+ return out;
5402
+ }
5403
+ __name(readMimeBody, "readMimeBody");
5404
+ var LF2 = 10;
5405
+ var CR2 = 13;
5406
+ var HEADER_NAME_RE = /^[!#$%&'*+\-.^_`|~0-9a-z]+$/;
5407
+ var MAX_INBOUND_HEADER_LINES = 4096;
5408
+ function parseRelayedHeaders(raw2) {
5409
+ const block = new TextDecoder().decode(raw2.subarray(0, headerBlockEnd(raw2)));
5410
+ const folded = /* @__PURE__ */ new Map();
5411
+ let totalPieces = 0;
5412
+ let current = null;
5413
+ let pos = 0;
5414
+ while (pos < block.length) {
5415
+ let nl = block.indexOf("\n", pos);
5416
+ if (nl === -1) {
5417
+ nl = block.length;
5418
+ }
5419
+ let line = block.slice(pos, nl);
5420
+ pos = nl + 1;
5421
+ if (line.endsWith("\r")) {
5422
+ line = line.slice(0, -1);
5423
+ }
5424
+ if (line === "") {
5425
+ break;
5426
+ }
5427
+ if (line.startsWith(" ") || line.startsWith(" ")) {
5428
+ if (current !== null && headerValueSafe(line)) {
5429
+ totalPieces += 1;
5430
+ if (totalPieces > MAX_INBOUND_HEADER_LINES) {
5431
+ return null;
5432
+ }
5433
+ const pieces2 = folded.get(current) ?? [];
5434
+ pieces2.push(` ${line.trim()}`);
5435
+ folded.set(current, pieces2);
5436
+ }
5437
+ continue;
5438
+ }
5439
+ const colon = line.indexOf(":");
5440
+ if (colon === -1) {
5441
+ current = null;
5442
+ continue;
5443
+ }
5444
+ const name = line.slice(0, colon).trim().toLowerCase();
5445
+ const value = line.slice(colon + 1).trim();
5446
+ if (!HEADER_NAME_RE.test(name) || !headerValueSafe(value)) {
5447
+ current = null;
5448
+ continue;
5449
+ }
5450
+ const pieces = folded.get(name);
5451
+ totalPieces += 1;
5452
+ if (totalPieces > MAX_INBOUND_HEADER_LINES) {
5453
+ return null;
5454
+ }
5455
+ if (pieces !== void 0) {
5456
+ pieces.push(`, ${value}`);
5457
+ } else {
5458
+ if (folded.size >= MAX_INBOUND_HEADERS) {
5459
+ return null;
5460
+ }
5461
+ folded.set(name, [value]);
5462
+ }
5463
+ current = name;
5464
+ }
5465
+ return Object.fromEntries(
5466
+ Array.from(folded, ([name, pieces]) => [name, pieces.join("")])
5467
+ );
5468
+ }
5469
+ __name(parseRelayedHeaders, "parseRelayedHeaders");
5470
+ function headerBlockEnd(raw2) {
5471
+ let lineStart = 0;
5472
+ while (lineStart < raw2.length) {
5473
+ const lf = raw2.indexOf(LF2, lineStart);
5474
+ const lineEnd = lf === -1 ? raw2.length : lf;
5475
+ let contentEnd = lineEnd;
5476
+ if (contentEnd > lineStart && raw2[contentEnd - 1] === CR2) {
5477
+ contentEnd--;
5478
+ }
5479
+ if (contentEnd === lineStart) {
5480
+ return lineStart;
5481
+ }
5482
+ lineStart = lf === -1 ? raw2.length : lf + 1;
5483
+ }
5484
+ return raw2.length;
5485
+ }
5486
+ __name(headerBlockEnd, "headerBlockEnd");
5487
+ function headerValueSafe(value) {
5488
+ for (let i = 0; i < value.length; i++) {
5489
+ const code = value.charCodeAt(i);
5490
+ if (code === 9) {
5491
+ continue;
5492
+ }
5493
+ if (code < 32 || code === 127 || code > 255) {
5494
+ return false;
5495
+ }
5496
+ }
5497
+ return true;
5498
+ }
5499
+ __name(headerValueSafe, "headerValueSafe");
5500
+
5501
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/kv.ts
4683
5502
  init_performance2();
4684
5503
  var CF_API2 = "https://api.cloudflare.com/client/v4";
4685
5504
  var kv = new Hono2();
@@ -4861,12 +5680,12 @@ kv.post("/list", async (context) => {
4861
5680
  });
4862
5681
  });
4863
5682
 
4864
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/platform-lifecycle.ts
5683
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/platform-lifecycle.ts
4865
5684
  init_performance2();
4866
5685
  var PLATFORM_DISABLED_KEY = "__void/platform/disabled/v1";
4867
5686
  var PLATFORM_DISABLED_VALUE = "disabled";
4868
5687
 
4869
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/r2.ts
5688
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/r2.ts
4870
5689
  init_performance2();
4871
5690
  var CF_API3 = "https://api.cloudflare.com/client/v4";
4872
5691
  var r2 = new Hono2();
@@ -5128,10 +5947,10 @@ r2.post("/head", async (context) => {
5128
5947
  });
5129
5948
  });
5130
5949
 
5131
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/revalidate.ts
5950
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/revalidate.ts
5132
5951
  init_performance2();
5133
- var app2 = new Hono2();
5134
- app2.post("/", async (context) => {
5952
+ var app3 = new Hono2();
5953
+ app3.post("/", async (context) => {
5135
5954
  const projectId = context.get("projectId");
5136
5955
  const body = context.get("body");
5137
5956
  const response = await context.env.API.fetch(`https://api/internal/revalidate/${projectId}`, {
@@ -5151,9 +5970,9 @@ app2.post("/", async (context) => {
5151
5970
  });
5152
5971
  });
5153
5972
 
5154
- // ../../../../../../../Users/cnakazawa/Projects/void/platform/packages/proxy/src/index.ts
5155
- var app3 = new Hono2();
5156
- app3.use("/*", async (context, next) => {
5973
+ // ../../home/runner/work/void/void/platform/packages/proxy/src/index.ts
5974
+ var app4 = new Hono2();
5975
+ app4.use("/*", async (context, next) => {
5157
5976
  const healthProbeToken = context.env.PLATFORM_HEALTH_PROBE_TOKEN;
5158
5977
  const installerProbe = healthProbeToken !== void 0 && healthProbeToken !== "" && context.req.path === "/health" && context.req.header("X-Void-Platform-Probe") === healthProbeToken;
5159
5978
  if (!installerProbe && (context.env.PLATFORM_TRAFFIC_STATE === "staging" || context.env.PLATFORM_TRAFFIC_STATE === "sandbox-drain" || context.env.PLATFORM_INSTALLATION_ID && await context.env.ROUTING.get(PLATFORM_DISABLED_KEY) === PLATFORM_DISABLED_VALUE)) {
@@ -5161,7 +5980,7 @@ app3.use("/*", async (context, next) => {
5161
5980
  }
5162
5981
  await next();
5163
5982
  });
5164
- app3.use(
5983
+ app4.use(
5165
5984
  "/*",
5166
5985
  cors({
5167
5986
  origin: "*",
@@ -5169,7 +5988,7 @@ app3.use(
5169
5988
  allowHeaders: ["content-type", "authorization"]
5170
5989
  })
5171
5990
  );
5172
- app3.get(
5991
+ app4.get(
5173
5992
  "/health",
5174
5993
  (context) => context.json({
5175
5994
  ok: true,
@@ -5183,7 +6002,7 @@ app3.get(
5183
6002
  }
5184
6003
  })
5185
6004
  );
5186
- app3.all("/*", async (context, next) => {
6005
+ app4.all("/*", async (context, next) => {
5187
6006
  if (context.req.method !== "POST") {
5188
6007
  return context.json({ error: "method not allowed" }, 405);
5189
6008
  }
@@ -5193,7 +6012,53 @@ var PLATFORM_INTERNAL_EMAIL_SENTINEL = "void-platform-internal-email-v1";
5193
6012
  var MAX_PLATFORM_MIME_BASE64_LENGTH = Math.ceil(10 * 1024 * 1024 * 4 / 3) + 4;
5194
6013
  var PLATFORM_TOKEN_MAX_SKEW_SECONDS = 5 * 60;
5195
6014
  var PLATFORM_TOKEN_LENGTH = 43;
5196
- app3.post("/*", async (context, next) => {
6015
+ app4.post("/*", async (context, next) => {
6016
+ const path = new URL(context.req.url).pathname;
6017
+ if (path === "/email/relay") {
6018
+ const relayDomain = context.req.header("X-Void-Email-Domain");
6019
+ const relayFrom = context.req.header("X-Void-Email-From");
6020
+ const relayTo = context.req.header("X-Void-Email-To");
6021
+ const relayAuth = context.req.header("Authorization");
6022
+ if (!relayDomain || !relayFrom || !relayTo || !relayAuth) {
6023
+ return context.json({ error: "relay envelope required" }, 400);
6024
+ }
6025
+ if (relayDomain.length > 256 || relayFrom.length > 256 || relayTo.length > 256 || relayAuth.length > 256) {
6026
+ return context.json({ error: "relay envelope required" }, 400);
6027
+ }
6028
+ const contentLengthRaw = context.req.header("content-length");
6029
+ if (!contentLengthRaw) {
6030
+ return context.json({ error: "content-length required" }, 400);
6031
+ }
6032
+ const contentLength = Number(contentLengthRaw);
6033
+ if (!Number.isInteger(contentLength) || contentLength < 0) {
6034
+ return context.json({ error: "content-length required" }, 400);
6035
+ }
6036
+ if (contentLength > MAX_MIME_BYTES) {
6037
+ return context.json({ error: "mime too large" }, 413);
6038
+ }
6039
+ const relaySecret = relayAuth.startsWith("Bearer ") ? relayAuth.slice(7) : null;
6040
+ if (!relaySecret) {
6041
+ return context.json({ error: "invalid relay credentials" }, 403);
6042
+ }
6043
+ const recipientDomain = relayTo.slice(relayTo.lastIndexOf("@") + 1).toLowerCase();
6044
+ if (recipientDomain.length === 0 || recipientDomain !== relayDomain.toLowerCase()) {
6045
+ return context.json({ error: "relay domain mismatch" }, 403);
6046
+ }
6047
+ const mirror = await readEmailDomainMirror(context.env.ROUTING, recipientDomain);
6048
+ if (!mirror) {
6049
+ return context.json({ error: "invalid relay credentials" }, 403);
6050
+ }
6051
+ const presented = await sha256Hex(relaySecret);
6052
+ if (!constantTimeEqual(presented, mirror.relaySecretSha256)) {
6053
+ return context.json({ error: "invalid relay credentials" }, 403);
6054
+ }
6055
+ if (mirror.status !== "active") {
6056
+ return context.json({ error: "email domain is not active" }, 403);
6057
+ }
6058
+ context.set("projectId", mirror.projectId);
6059
+ await next();
6060
+ return;
6061
+ }
5197
6062
  let body;
5198
6063
  try {
5199
6064
  const json = await context.req.json();
@@ -5205,7 +6070,6 @@ app3.post("/*", async (context, next) => {
5205
6070
  return context.json({ error: "invalid JSON body" }, 400);
5206
6071
  }
5207
6072
  context.set("body", body);
5208
- const path = new URL(context.req.url).pathname;
5209
6073
  if (path.startsWith("/email/internal/")) {
5210
6074
  const platformToken = asString(body.platformToken);
5211
6075
  const platformTimestamp = asNumber(body.platformTimestamp);
@@ -5287,13 +6151,13 @@ app3.post("/*", async (context, next) => {
5287
6151
  }
5288
6152
  await next();
5289
6153
  });
5290
- app3.post("/ai/*", async (context, next) => {
6154
+ app4.post("/ai/*", async (context, next) => {
5291
6155
  if (await context.env.ROUTING.get(`ai-block:${context.get("projectId")}`, { cacheTtl: 60 })) {
5292
6156
  return context.json({ error: "AI usage limit exceeded" }, 429);
5293
6157
  }
5294
6158
  await next();
5295
6159
  });
5296
- app3.post(
6160
+ app4.post(
5297
6161
  "/sandbox/*",
5298
6162
  (context) => context.json(
5299
6163
  {
@@ -5304,7 +6168,7 @@ app3.post(
5304
6168
  501
5305
6169
  )
5306
6170
  );
5307
- app3.post("/email/*", async (context, next) => {
6171
+ app4.post("/email/*", async (context, next) => {
5308
6172
  if (!proxyCapabilityEnabled(context.env.PLATFORM_CAPABILITIES, "email")) {
5309
6173
  return context.json(
5310
6174
  {
@@ -5317,14 +6181,15 @@ app3.post("/email/*", async (context, next) => {
5317
6181
  }
5318
6182
  await next();
5319
6183
  });
5320
- app3.route("/ai", ai);
5321
- app3.route("/d1", d1);
5322
- app3.route("/kv", kv);
5323
- app3.route("/r2", r2);
5324
- app3.route("/revalidate", app2);
5325
- app3.route("/email", app);
6184
+ app4.route("/ai", ai);
6185
+ app4.route("/d1", d1);
6186
+ app4.route("/kv", kv);
6187
+ app4.route("/r2", r2);
6188
+ app4.route("/revalidate", app3);
6189
+ app4.route("/email", app);
6190
+ app4.route("/email", app2);
5326
6191
  var index_default = {
5327
- fetch: app3.fetch,
6192
+ fetch: app4.fetch,
5328
6193
  /**
5329
6194
  * Inbound email entry point — bound as the catch-all CF Email Routing rule
5330
6195
  * on the platform mail zone. See `email-router.ts`.
@@ -5333,27 +6198,27 @@ var index_default = {
5333
6198
  await routeInbound(message, env, ctx);
5334
6199
  }
5335
6200
  };
5336
- var encoder3 = new TextEncoder();
6201
+ var encoder4 = new TextEncoder();
5337
6202
  var decoder = new TextDecoder();
5338
6203
  var cachedVerifyKey;
5339
- var cachedKeySecret3;
6204
+ var cachedKeySecret4;
5340
6205
  async function getVerifyKey(secret) {
5341
- if (cachedVerifyKey && cachedKeySecret3 === secret) {
6206
+ if (cachedVerifyKey && cachedKeySecret4 === secret) {
5342
6207
  return cachedVerifyKey;
5343
6208
  }
5344
6209
  cachedVerifyKey = await crypto.subtle.importKey(
5345
6210
  "raw",
5346
- encoder3.encode(secret),
6211
+ encoder4.encode(secret),
5347
6212
  { name: "HMAC", hash: "SHA-256" },
5348
6213
  false,
5349
6214
  ["verify"]
5350
6215
  );
5351
- cachedKeySecret3 = secret;
6216
+ cachedKeySecret4 = secret;
5352
6217
  return cachedVerifyKey;
5353
6218
  }
5354
6219
  __name(getVerifyKey, "getVerifyKey");
5355
6220
  async function sha256Hex(input) {
5356
- const digest = await crypto.subtle.digest("SHA-256", encoder3.encode(input));
6221
+ const digest = await crypto.subtle.digest("SHA-256", encoder4.encode(input));
5357
6222
  const bytes = new Uint8Array(digest);
5358
6223
  let out = "";
5359
6224
  for (const b of bytes) {
@@ -5362,11 +6227,22 @@ async function sha256Hex(input) {
5362
6227
  return out;
5363
6228
  }
5364
6229
  __name(sha256Hex, "sha256Hex");
6230
+ function constantTimeEqual(a, b) {
6231
+ if (a.length !== b.length) {
6232
+ return false;
6233
+ }
6234
+ let diff = 0;
6235
+ for (let i = 0; i < a.length; i++) {
6236
+ diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
6237
+ }
6238
+ return diff === 0;
6239
+ }
6240
+ __name(constantTimeEqual, "constantTimeEqual");
5365
6241
  async function verifyHmac(data, signature, secret) {
5366
6242
  try {
5367
6243
  const key = await getVerifyKey(secret);
5368
6244
  const sigBytes = base64urlDecode(signature);
5369
- return crypto.subtle.verify("HMAC", key, sigBytes.buffer, encoder3.encode(data));
6245
+ return crypto.subtle.verify("HMAC", key, sigBytes.buffer, encoder4.encode(data));
5370
6246
  } catch {
5371
6247
  return false;
5372
6248
  }
@@ -5391,7 +6267,7 @@ async function verifyJwt(token, secret) {
5391
6267
  "HMAC",
5392
6268
  key,
5393
6269
  sigBytes.buffer,
5394
- encoder3.encode(`${header}.${body}`)
6270
+ encoder4.encode(`${header}.${body}`)
5395
6271
  );
5396
6272
  if (!valid) {
5397
6273
  return null;