@dsh-remote/relay 3.1.4 → 3.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,7 +8,7 @@ DSH Remote Control 的**零知识 WebSocket 中继**:在宿主插件与已配
8
8
 
9
9
  ## 自托管
10
10
 
11
- 完整配方(环境变量表、systemd / docker / nginx、排错、升级与回滚)见
11
+ 完整配方(环境变量表、systemd / docker / nginx、排错、升级)见
12
12
  [`docs/SELF-HOSTING.md`](docs/SELF-HOSTING.md)。最速验证:
13
13
 
14
14
  ```sh
@@ -41,67 +41,41 @@
41
41
  # (deploy/docker/README.md 有完整的离线步骤;生产那次就是这么发的)。
42
42
  #
43
43
  # Node 22 与 CI、与 HANDOFF 的工具链口径一致(pnpm 11 要求 >= 22.13)。
44
+ #
45
+ # ## 2026-10-13(3.1.5 起):这份 Dockerfile 回到**单仓形态**
46
+ #
47
+ # 3.1.3/3.1.4 那两次部署用的是**伞仓上下文**(COPY 带 `packages/` 前缀、compose 的
48
+ # `context: ../..` 指到 monorepo 根)——因为那时服务器上摆的是整棵伞仓树。
49
+ # 2026-10-13 用户裁决:服务器改成**单仓部署**(部署源 = 本仓,不再摆伞仓)。
50
+ # 本仓与伞仓共用这份文件路径(`deploy/docker/Dockerfile`),但**两边各有一份内容**:
51
+ # 伞仓那份(`/deploy/docker/`)保持 monorepo 形态给伞仓构建用;本仓这份从现在是
52
+ # 独立仓形态——`COPY package.json pnpm-lock.yaml ./` 拷的是**本包**清单,
53
+ # `@dsh-remote/protocol` 从 **npm** 装(devDependency,发版顺序 protocol 先行),
54
+ # `pnpm-lock.yaml` 由 `scripts/split-repos.mjs` 在暂存时生成并随仓跟踪(CI 的
55
+ # `--frozen-lockfile` 依赖它)。两份 Dockerfile 的差异只有 build 阶段的 COPY 路径,
56
+ # runtime 阶段逐字相同。
44
57
  FROM node:22-alpine AS build
45
58
  WORKDIR /src
46
59
 
47
- # 先只拷锁文件再装:pnpm 的安装缓存按 lockfile 命中,改 src 不必重装依赖树。
60
+ # 先只拷清单与锁再装:安装缓存按 lockfile 命中,改 src 不必重装依赖树。
48
61
  # --frozen-lockfile 是刻意的——镜像里装的必须与提交的 lockfile 逐位一致,
49
62
  # "构建时顺手升了某个传递依赖"这类漂移正是要消掉的。
50
- #
51
- # ## v3 单仓:这里的 COPY 必须带 packages/ 前缀(2026-10-08 修)
52
- #
53
- # v2 时这个仓是**独立仓**,build 上下文(compose 的 `context: ../..`)就是本仓根,
54
- # 所以 `COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./` 拷的是"本包 + 本包锁"。
55
- # v3 变成 monorepo 后,同一行拷的是 **monorepo 根**的三个文件——而根 package.json 里
56
- # 没有 relay 的依赖,于是 pnpm 报的错是「lockfile 里有 ^22.9.0、manifest 要 ^26.6.3」
57
- # 这类**看起来毫不相关**的 mismatch(真实原因:那份 package.json 不是这个包的)。
58
- #
59
- # 症状与判据:`docker compose build` 失败,而 `pnpm install` 在本机完全正常。
60
- # 所以下面显式列出三个路径,让"上下文是单仓根"这件事变成 Dockerfile 自己保证的。
61
- # ⚠️ 下面几行的行尾**不许带注释** —— Dockerfile 会把 `#` 之后的内容也当成拷贝路径
62
- # (报错形态:`"/需要它要解": not found`,看起来像文件不存在,其��是把注释当路径了)。
63
+ # ⚠️ 下面几行的行尾**不许带注释** —— Dockerfile 会把 `#` 之后的内容也当成拷贝路径。
63
64
  # 要说明就写在上一行。
64
- COPY pnpm-workspace.yaml ./
65
- COPY pnpm-lock.yaml ./
66
- # monorepo 根清单:pnpm 需要它来解 workspace(里面没有 relay 的依赖,只负责解析结构)
67
65
  COPY package.json ./
66
+ COPY pnpm-lock.yaml ./
68
67
  #
69
- # ⚠️ **pnpm-workspace.yaml 声明的每一个包都要有 package.json 在场**,少一个都不行。
70
- # 缺的那几个不会报"文件不存在",而是报 `specifiers in the lockfile don't match`,
71
- # 并把**缺的包的依赖名**列出来(第一次栽在这里:漏了 plugin/client/e2e,于是报错说
72
- # 「lockfile 有 ^22.9.0、manifest 要 ^26.6.3」——那是 plugin 的 @types/node,
73
- # 与 relay 一点关系都没有 ⇒ 看起来像 lockfile 坏了,其��是清单没拷全)。
74
- # 镜像只需要 relay + protocol 的源码,但**清单必须全在场**,否则 pnpm 在 install 阶段就退出了。
75
- COPY packages/relay/package.json ./packages/relay/
76
- COPY packages/protocol/package.json ./packages/protocol/
77
- #
78
- # ⚠️ **不需要**把 workspace 里其他包(plugin / client / e2e)的 package.json 也拷进来。
79
- # 我一度以为"声明的包必须清单齐备",为此加了三条 COPY —— 那三条**无效**:
80
- # 删掉之后 `pnpm install --frozen-lockfile` 照样通过(2026-10-08 在服务器上实测过:
81
- # 只放 protocol + relay 两份清单,frozen 检查顺利过,只在下一步因缺 protocol 的
82
- # tsconfig 而失败)。pnpm 只校验**它要解析的那些 importer**。
83
- #
84
- # 那次「lockfile 有 ^22.9.0、manifest 要 ^26.6.3」的 mismatch 真相不是"清单没拷全",
85
- # 而是**根 package.json 被污染**:上传源码时用 `tar xzf`,relay 的 package.json
86
- # 覆盖到了仓库根,于是 pnpm 拿 relay 的依赖去比根的 lock ⇒ 报出 relay 的依赖名。
87
- # ⇒ **报错指错地方时,先怀疑"文件被覆盖",别急着加 COPY。**
88
- #
89
- # protocol 的 src + tsconfig 必须在 install **之前**进来:
90
- # 它的 `prepare: tsc -p tsconfig.json` 是 install 生命周期的一环,
91
- # 顺序写反的报错是 `TS5058: path does not exist`,出现在 install 阶段。
92
- COPY packages/protocol/tsconfig.json ./packages/protocol/
93
- COPY packages/protocol/src ./packages/protocol/src
68
+ # `@dsh-remote/protocol` 是 devDependency、从 **npm** 装(不再是 workspace 软链):
69
+ # 单仓里没有它的源码,也不需要——它对 runtime 是零依赖(bundle 全内联)。
70
+ # 发版顺序因此必须是 **protocol 先发**,本仓构建才能锁到同版本。
71
+ # 锁文件由 `scripts/split-repos.mjs` 暂存时 `pnpm install` 生成并随仓跟踪;
72
+ # 在伞仓里它不存在(伞仓由根锁文件管),这是"两边各有一份内容"的一部分。
94
73
  RUN corepack enable && pnpm install --frozen-lockfile
95
74
 
96
- COPY packages/relay/tsconfig.json ./packages/relay/
97
- COPY packages/relay/src ./packages/relay/src
98
- COPY packages/relay/scripts ./packages/relay/scripts
99
- # protocol 必须**先构建**:它是 workspace 依赖,`pnpm install` 只软链它的 package.json,
100
- # 而 bundle 脚本按 node_modules 解析 ⇒ 拿到的必须是 `dist/src/**`(main 字段指向那里)。
101
- # 少这一步的报错形态是 esbuild 找不到 `@dsh-remote/protocol/dist/src/index.js`。
102
- RUN pnpm --filter @dsh-remote/protocol build
103
- # 在 relay 包目录里构建:它的 tsconfig 与 bundle 脚本都以包根为基准
104
- WORKDIR /src/packages/relay
75
+ COPY tsconfig.json ./
76
+ COPY src ./src
77
+ COPY scripts ./scripts
78
+ # tsconfig/bundle 脚本都以仓根为基准(单仓形态:仓根就是包根)
105
79
  RUN pnpm build
106
80
 
107
81
  # 产物级断言。两条取自 tests/bundle.test.mjs 的同款断言,写在这里是因为
@@ -119,7 +93,7 @@ ARG VCS_REF=unknown
119
93
  LABEL org.opencontainers.image.title="dsh-remote-relay" org.opencontainers.image.description="Zero-knowledge WebSocket relay for DSH Remote Control" org.opencontainers.image.source="https://github.com/providcc/dsh-remote-server" org.opencontainers.image.licenses="MIT" org.opencontainers.image.version="${DRC_VERSION}" org.opencontainers.image.revision="${VCS_REF}"
120
94
 
121
95
  WORKDIR /app
122
- COPY --from=build /src/packages/relay/dist/bundle/main.js /app/relay.mjs
96
+ COPY --from=build /src/dist/bundle/main.js /app/relay.mjs
123
97
 
124
98
  # 只有这两个。**故意不设 DRC_STATE_FILE**:镜像里的默认值要与裸机(systemd 单元)一致——
125
99
  # 不配就是纯内存、配了才落盘。落盘路径属于"部署形态"而不是"程序形态",它与卷是一对,
@@ -3726,7 +3726,7 @@ var require_websocket_server = __commonJS({
3726
3726
  // src/main.ts
3727
3727
  import { readFileSync as readFileSync2 } from "node:fs";
3728
3728
 
3729
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/external.js
3729
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/classic/external.js
3730
3730
  var external_exports = {};
3731
3731
  __export(external_exports, {
3732
3732
  $brand: () => $brand,
@@ -3989,7 +3989,7 @@ __export(external_exports, {
3989
3989
  xor: () => xor
3990
3990
  });
3991
3991
 
3992
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/index.js
3992
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/index.js
3993
3993
  var core_exports2 = {};
3994
3994
  __export(core_exports2, {
3995
3995
  $ZodAny: () => $ZodAny,
@@ -4306,7 +4306,7 @@ __export(core_exports2, {
4306
4306
  withParser: () => withParser
4307
4307
  });
4308
4308
 
4309
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/util.js
4309
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/util.js
4310
4310
  var util_exports = {};
4311
4311
  __export(util_exports, {
4312
4312
  BIGINT_FORMAT_RANGES: () => BIGINT_FORMAT_RANGES,
@@ -4377,6 +4377,7 @@ __export(util_exports, {
4377
4377
  required: () => required,
4378
4378
  safeExtend: () => safeExtend,
4379
4379
  shallowClone: () => shallowClone,
4380
+ sizeCaps: () => sizeCaps,
4380
4381
  slugify: () => slugify,
4381
4382
  stringifyPrimitive: () => stringifyPrimitive,
4382
4383
  toZod: () => toZod,
@@ -4896,6 +4897,18 @@ function prefixIssues(path, issues) {
4896
4897
  function unwrapMessage(message) {
4897
4898
  return typeof message === "string" ? message : message?.message;
4898
4899
  }
4900
+ function sizeCaps(defChecks) {
4901
+ const caps = [];
4902
+ for (const ch of defChecks ?? []) {
4903
+ const d = ch._zod.def;
4904
+ if (!/_(length|size)$|_equals$/.test(d.check))
4905
+ break;
4906
+ const max = d.maximum ?? d.length ?? d.size;
4907
+ if (max >= 0)
4908
+ caps.push([max, ch]);
4909
+ }
4910
+ return caps;
4911
+ }
4899
4912
  function attachSchema(issues, start, inst) {
4900
4913
  var _a3;
4901
4914
  for (let i = start; i < issues.length; i++) {
@@ -5149,7 +5162,7 @@ function constantCatch(value) {
5149
5162
  return fn;
5150
5163
  }
5151
5164
 
5152
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/core.js
5165
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/core.js
5153
5166
  var _a;
5154
5167
  var NEVER = /* @__PURE__ */ Object.freeze({
5155
5168
  status: "aborted"
@@ -5271,7 +5284,7 @@ function config(newConfig) {
5271
5284
  return globalConfig;
5272
5285
  }
5273
5286
 
5274
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/errors.js
5287
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/errors.js
5275
5288
  function _getMessage() {
5276
5289
  const internals = this._zod;
5277
5290
  internals.message ?? (internals.message = JSON.stringify(internals.def, jsonStringifyReplacer, 2));
@@ -5463,7 +5476,7 @@ function prettifyError(error62) {
5463
5476
  return lines.join("\n");
5464
5477
  }
5465
5478
 
5466
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/parse.js
5479
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/parse.js
5467
5480
  function finalizeParams(callee, params) {
5468
5481
  return { callee: params?.callee ?? callee, Err: params?.Err };
5469
5482
  }
@@ -5623,7 +5636,7 @@ var _safeDecodeAsync = (_Err) => async (schema, value, _ctx) => {
5623
5636
  };
5624
5637
  var safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync($ZodRealError);
5625
5638
 
5626
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/regexes.js
5639
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/regexes.js
5627
5640
  var regexes_exports = {};
5628
5641
  __export(regexes_exports, {
5629
5642
  anyString: () => anyString,
@@ -5795,7 +5808,7 @@ var sha512_hex = /^[0-9a-fA-F]{128}$/;
5795
5808
  var sha512_base64 = /* @__PURE__ */ fixedBase64(86, "==");
5796
5809
  var sha512_base64url = /* @__PURE__ */ fixedBase64url(86);
5797
5810
 
5798
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/checks.js
5811
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/checks.js
5799
5812
  var $ZodCheck = /* @__PURE__ */ $constructor("$ZodCheck", (inst, def) => {
5800
5813
  var _a3;
5801
5814
  inst._zod ?? (inst._zod = {});
@@ -6271,7 +6284,7 @@ var $ZodCheckOverwrite = /* @__PURE__ */ $constructor("$ZodCheckOverwrite", (ins
6271
6284
  };
6272
6285
  });
6273
6286
 
6274
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/doc.js
6287
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/doc.js
6275
6288
  var Doc = class {
6276
6289
  constructor(args = [], closed = {}) {
6277
6290
  this.content = [];
@@ -6312,14 +6325,14 @@ ${content.join("\n")}
6312
6325
  }
6313
6326
  };
6314
6327
 
6315
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/versions.js
6328
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/versions.js
6316
6329
  var version = {
6317
6330
  major: 4,
6318
6331
  minor: 6,
6319
- patch: 5
6332
+ patch: 6
6320
6333
  };
6321
6334
 
6322
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/schemas.js
6335
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/schemas.js
6323
6336
  var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
6324
6337
  var _a3;
6325
6338
  inst ?? (inst = {});
@@ -7072,6 +7085,31 @@ var $ZodDate = /* @__PURE__ */ $constructor("$ZodDate", (inst, def) => {
7072
7085
  return payload;
7073
7086
  };
7074
7087
  });
7088
+ function capSize(inst, size) {
7089
+ const caps = sizeCaps(inst._zod.def.checks);
7090
+ if (!caps.length)
7091
+ return;
7092
+ const cap = Math.min(...caps.map((c) => c[0]));
7093
+ const parse3 = inst._zod.parse;
7094
+ inst._zod.parse = (payload, ctx) => {
7095
+ const n = size(payload.value);
7096
+ if (n > cap && !ctx?.skipChecks && ctx?.direction !== "backward") {
7097
+ for (const [max, ch] of sizeCaps(inst._zod.def.checks)) {
7098
+ if (n > max && ch._zod.def.when(payload)) {
7099
+ const start = payload.issues.length;
7100
+ ch._zod.check(payload);
7101
+ payload.issues[start].continue = false;
7102
+ attachSchema(payload.issues, start, inst);
7103
+ return payload;
7104
+ }
7105
+ }
7106
+ }
7107
+ return parse3(payload, ctx);
7108
+ };
7109
+ }
7110
+ var arraySize = (input2) => Array.isArray(input2) ? input2.length : -1;
7111
+ var mapSize = (input2) => input2 instanceof Map ? input2.size : -1;
7112
+ var setSize = (input2) => input2 instanceof Set ? input2.size : -1;
7075
7113
  function handleArrayResult(result, final, index) {
7076
7114
  if (result.issues.length) {
7077
7115
  final.issues.push(...prefixIssues(index, result.issues));
@@ -7115,6 +7153,7 @@ var $ZodArray = /* @__PURE__ */ $constructor("$ZodArray", (inst, def) => {
7115
7153
  }
7116
7154
  return payload;
7117
7155
  };
7156
+ capSize(inst, arraySize);
7118
7157
  });
7119
7158
  function handlePropertyResult(result, final, key, input2, optin, optout) {
7120
7159
  const isPresent = key in input2;
@@ -8071,6 +8110,7 @@ var $ZodMap = /* @__PURE__ */ $constructor("$ZodMap", (inst, def) => {
8071
8110
  return Promise.all(proms).then(() => payload);
8072
8111
  return payload;
8073
8112
  };
8113
+ capSize(inst, mapSize);
8074
8114
  });
8075
8115
  function handleMapResult(keyResult, valueResult, final, key, input2, inst, ctx) {
8076
8116
  if (keyResult.issues.length) {
@@ -8137,6 +8177,7 @@ var $ZodSet = /* @__PURE__ */ $constructor("$ZodSet", (inst, def) => {
8137
8177
  return Promise.all(proms).then(() => payload);
8138
8178
  return payload;
8139
8179
  };
8180
+ capSize(inst, setSize);
8140
8181
  });
8141
8182
  function handleSetResult(result, final) {
8142
8183
  if (result.issues.length) {
@@ -8733,7 +8774,7 @@ function handleRefineResult(result, payload, input2, inst) {
8733
8774
  }
8734
8775
  }
8735
8776
 
8736
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/memoizer.js
8777
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/memoizer.js
8737
8778
  var $ZodCyclicError = class extends Error {
8738
8779
  constructor() {
8739
8780
  super(`Cannot parse a reference cycle that closes through a transform`);
@@ -9010,7 +9051,7 @@ function isBackEdge(ctx, value) {
9010
9051
  return backEdges !== void 0 && isRef(value) && backEdges.has(value);
9011
9052
  }
9012
9053
 
9013
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/index.js
9054
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/index.js
9014
9055
  var locales_exports = {};
9015
9056
  __export(locales_exports, {
9016
9057
  ar: () => ar_default,
@@ -9078,7 +9119,7 @@ __export(locales_exports, {
9078
9119
  zhTW: () => zh_TW_default
9079
9120
  });
9080
9121
 
9081
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ar.js
9122
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/ar.js
9082
9123
  var error = () => {
9083
9124
  const Sizable = {
9084
9125
  string: { unit: "\u062D\u0631\u0641", verb: "\u0623\u0646 \u064A\u062D\u0648\u064A" },
@@ -9190,7 +9231,7 @@ function ar_default() {
9190
9231
  };
9191
9232
  }
9192
9233
 
9193
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/az.js
9234
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/az.js
9194
9235
  var error2 = () => {
9195
9236
  const Sizable = {
9196
9237
  string: { unit: "simvol", verb: "olmal\u0131d\u0131r" },
@@ -9301,7 +9342,7 @@ function az_default() {
9301
9342
  };
9302
9343
  }
9303
9344
 
9304
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/be.js
9345
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/be.js
9305
9346
  function getBelarusianPlural(count, one, few, many) {
9306
9347
  const absCount = Math.abs(count);
9307
9348
  const lastDigit = absCount % 10;
@@ -9470,7 +9511,7 @@ function be_default() {
9470
9511
  };
9471
9512
  }
9472
9513
 
9473
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/bg.js
9514
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/bg.js
9474
9515
  var error4 = () => {
9475
9516
  const Sizable = {
9476
9517
  string: { unit: "\u0441\u0438\u043C\u0432\u043E\u043B\u0430", verb: "\u0434\u0430 \u0441\u044A\u0434\u044A\u0440\u0436\u0430" },
@@ -9596,7 +9637,7 @@ function bg_default() {
9596
9637
  };
9597
9638
  }
9598
9639
 
9599
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/bn.js
9640
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/bn.js
9600
9641
  var error5 = () => {
9601
9642
  const Sizable = {
9602
9643
  string: { unit: "\u0985\u0995\u09CD\u09B7\u09B0", verb: "\u09A5\u09BE\u0995\u09A4\u09C7 \u09B9\u09AC\u09C7" },
@@ -9710,7 +9751,7 @@ function bn_default() {
9710
9751
  };
9711
9752
  }
9712
9753
 
9713
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ca.js
9754
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/ca.js
9714
9755
  var error6 = () => {
9715
9756
  const Sizable = {
9716
9757
  string: { unit: "car\xE0cters", verb: "contenir" },
@@ -9824,7 +9865,7 @@ function ca_default() {
9824
9865
  };
9825
9866
  }
9826
9867
 
9827
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ckb.js
9868
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/ckb.js
9828
9869
  var error7 = () => {
9829
9870
  const Sizable = {
9830
9871
  string: { unit: "\u067E\u06CC\u062A", verb: "\u0628\u06CE\u062A" },
@@ -9957,7 +9998,7 @@ function ckb_default() {
9957
9998
  };
9958
9999
  }
9959
10000
 
9960
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/cs.js
10001
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/cs.js
9961
10002
  var error8 = () => {
9962
10003
  const Sizable = {
9963
10004
  string: { unit: "znak\u016F", verb: "m\xEDt" },
@@ -10074,7 +10115,7 @@ function cs_default() {
10074
10115
  };
10075
10116
  }
10076
10117
 
10077
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/da.js
10118
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/da.js
10078
10119
  var error9 = () => {
10079
10120
  const Sizable = {
10080
10121
  string: { unit: "tegn", verb: "havde" },
@@ -10195,7 +10236,7 @@ function da_default() {
10195
10236
  };
10196
10237
  }
10197
10238
 
10198
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/de.js
10239
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/de.js
10199
10240
  var error10 = () => {
10200
10241
  const Sizable = {
10201
10242
  string: { unit: "Zeichen", verb: "zu haben" },
@@ -10309,7 +10350,7 @@ function de_default() {
10309
10350
  };
10310
10351
  }
10311
10352
 
10312
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/el.js
10353
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/el.js
10313
10354
  var error11 = () => {
10314
10355
  const Sizable = {
10315
10356
  string: { unit: "\u03C7\u03B1\u03C1\u03B1\u03BA\u03C4\u03AE\u03C1\u03B5\u03C2", verb: "\u03BD\u03B1 \u03AD\u03C7\u03B5\u03B9" },
@@ -10422,7 +10463,7 @@ function el_default() {
10422
10463
  };
10423
10464
  }
10424
10465
 
10425
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/en.js
10466
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/en.js
10426
10467
  var error12 = () => {
10427
10468
  const Sizable = {
10428
10469
  string: { unit: "characters", verb: "to have" },
@@ -10547,7 +10588,7 @@ function en_default() {
10547
10588
  };
10548
10589
  }
10549
10590
 
10550
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/eo.js
10591
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/eo.js
10551
10592
  var error13 = () => {
10552
10593
  const Sizable = {
10553
10594
  string: { unit: "karaktrojn", verb: "havi" },
@@ -10662,7 +10703,7 @@ function eo_default() {
10662
10703
  };
10663
10704
  }
10664
10705
 
10665
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/es.js
10706
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/es.js
10666
10707
  var error14 = () => {
10667
10708
  const Sizable = {
10668
10709
  string: { unit: "caracteres", verb: "tener" },
@@ -10799,7 +10840,7 @@ function es_default() {
10799
10840
  };
10800
10841
  }
10801
10842
 
10802
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/fa.js
10843
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/fa.js
10803
10844
  var error15 = () => {
10804
10845
  const Sizable = {
10805
10846
  string: { unit: "\u06A9\u0627\u0631\u0627\u06A9\u062A\u0631", verb: "\u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F" },
@@ -10919,7 +10960,7 @@ function fa_default() {
10919
10960
  };
10920
10961
  }
10921
10962
 
10922
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/fi.js
10963
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/fi.js
10923
10964
  var error16 = () => {
10924
10965
  const Sizable = {
10925
10966
  string: { unit: "merkki\xE4", subject: "merkkijonon" },
@@ -11037,7 +11078,7 @@ function fi_default() {
11037
11078
  };
11038
11079
  }
11039
11080
 
11040
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/fr.js
11081
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/fr.js
11041
11082
  var error17 = () => {
11042
11083
  const Sizable = {
11043
11084
  string: { unit: "caract\xE8res", verb: "avoir" },
@@ -11167,7 +11208,7 @@ function fr_default() {
11167
11208
  };
11168
11209
  }
11169
11210
 
11170
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/fr-CA.js
11211
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/fr-CA.js
11171
11212
  var error18 = () => {
11172
11213
  const Sizable = {
11173
11214
  string: { unit: "caract\xE8res", verb: "avoir" },
@@ -11280,7 +11321,7 @@ function fr_CA_default() {
11280
11321
  };
11281
11322
  }
11282
11323
 
11283
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/gu.js
11324
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/gu.js
11284
11325
  var error19 = () => {
11285
11326
  const Sizable = {
11286
11327
  string: { unit: "\u0A85\u0A95\u0ACD\u0AB7\u0AB0", verb: "\u0AB9\u0ACB\u0AB5\u0ABE \u0A9C\u0ACB\u0A88\u0A8F" },
@@ -11394,7 +11435,7 @@ function gu_default() {
11394
11435
  };
11395
11436
  }
11396
11437
 
11397
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/he.js
11438
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/he.js
11398
11439
  var error20 = () => {
11399
11440
  const TypeNames = {
11400
11441
  string: { label: "\u05DE\u05D7\u05E8\u05D5\u05D6\u05EA", gender: "f" },
@@ -11596,7 +11637,7 @@ function he_default() {
11596
11637
  };
11597
11638
  }
11598
11639
 
11599
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/hi.js
11640
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/hi.js
11600
11641
  var error21 = () => {
11601
11642
  const Sizable = {
11602
11643
  string: { unit: "\u0905\u0915\u094D\u0937\u0930", verb: "\u0930\u0916\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F" },
@@ -11708,7 +11749,7 @@ function hi_default() {
11708
11749
  };
11709
11750
  }
11710
11751
 
11711
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/hr.js
11752
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/hr.js
11712
11753
  var error22 = () => {
11713
11754
  const Sizable = {
11714
11755
  string: { unit: "znakova", verb: "imati" },
@@ -11835,7 +11876,7 @@ function hr_default() {
11835
11876
  };
11836
11877
  }
11837
11878
 
11838
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/hu.js
11879
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/hu.js
11839
11880
  var error23 = () => {
11840
11881
  const Sizable = {
11841
11882
  string: { unit: "karakter", verb: "legyen" },
@@ -11949,7 +11990,7 @@ function hu_default() {
11949
11990
  };
11950
11991
  }
11951
11992
 
11952
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/hy.js
11993
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/hy.js
11953
11994
  function getArmenianPlural(count, one, many) {
11954
11995
  return Math.abs(count) === 1 ? one : many;
11955
11996
  }
@@ -12108,7 +12149,7 @@ function hy_default() {
12108
12149
  };
12109
12150
  }
12110
12151
 
12111
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/id.js
12152
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/id.js
12112
12153
  var error25 = () => {
12113
12154
  const Sizable = {
12114
12155
  string: { unit: "karakter", verb: "memiliki" },
@@ -12220,7 +12261,7 @@ function id_default() {
12220
12261
  };
12221
12262
  }
12222
12263
 
12223
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/is.js
12264
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/is.js
12224
12265
  var error26 = () => {
12225
12266
  const Sizable = {
12226
12267
  string: { unit: "stafi", verb: "a\xF0 hafa" },
@@ -12335,7 +12376,7 @@ function is_default() {
12335
12376
  };
12336
12377
  }
12337
12378
 
12338
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/it.js
12379
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/it.js
12339
12380
  var error27 = () => {
12340
12381
  const Sizable = {
12341
12382
  string: { unit: "caratteri", verb: "avere" },
@@ -12449,7 +12490,7 @@ function it_default() {
12449
12490
  };
12450
12491
  }
12451
12492
 
12452
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ja.js
12493
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/ja.js
12453
12494
  var error28 = () => {
12454
12495
  const Sizable = {
12455
12496
  string: { unit: "\u6587\u5B57", verb: "\u3067\u3042\u308B" },
@@ -12562,7 +12603,7 @@ function ja_default() {
12562
12603
  };
12563
12604
  }
12564
12605
 
12565
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ka.js
12606
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/ka.js
12566
12607
  var error29 = () => {
12567
12608
  const Sizable = {
12568
12609
  string: { unit: "\u10E1\u10D8\u10DB\u10D1\u10DD\u10DA\u10DD", verb: "\u10E3\u10DC\u10D3\u10D0 \u10E8\u10D4\u10D8\u10EA\u10D0\u10D5\u10D3\u10D4\u10E1" },
@@ -12680,7 +12721,7 @@ function ka_default() {
12680
12721
  };
12681
12722
  }
12682
12723
 
12683
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/km.js
12724
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/km.js
12684
12725
  var error30 = () => {
12685
12726
  const Sizable = {
12686
12727
  string: { unit: "\u178F\u17BD\u17A2\u1780\u17D2\u179F\u179A", verb: "\u1782\u17BD\u179A\u1798\u17B6\u1793" },
@@ -12796,12 +12837,12 @@ function km_default() {
12796
12837
  };
12797
12838
  }
12798
12839
 
12799
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/kh.js
12840
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/kh.js
12800
12841
  function kh_default() {
12801
12842
  return km_default();
12802
12843
  }
12803
12844
 
12804
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/kn.js
12845
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/kn.js
12805
12846
  var error31 = () => {
12806
12847
  const Sizable = {
12807
12848
  string: { unit: "\u0C85\u0C95\u0CCD\u0CB7\u0CB0\u0C97\u0CB3\u0CC1", verb: "\u0CB9\u0CCA\u0C82\u0CA6\u0CB2\u0CC1" },
@@ -12917,7 +12958,7 @@ function kn_default() {
12917
12958
  };
12918
12959
  }
12919
12960
 
12920
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ko.js
12961
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/ko.js
12921
12962
  var error32 = () => {
12922
12963
  const Sizable = {
12923
12964
  string: { unit: "\uBB38\uC790", verb: "to have" },
@@ -13034,7 +13075,7 @@ function ko_default() {
13034
13075
  };
13035
13076
  }
13036
13077
 
13037
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/lt.js
13078
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/lt.js
13038
13079
  var capitalizeFirstCharacter = (text) => {
13039
13080
  return text.charAt(0).toUpperCase() + text.slice(1);
13040
13081
  };
@@ -13242,7 +13283,7 @@ function lt_default() {
13242
13283
  };
13243
13284
  }
13244
13285
 
13245
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/mk.js
13286
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/mk.js
13246
13287
  var error34 = () => {
13247
13288
  const Sizable = {
13248
13289
  string: { unit: "\u0437\u043D\u0430\u0446\u0438", verb: "\u0434\u0430 \u0438\u043C\u0430\u0430\u0442" },
@@ -13357,7 +13398,7 @@ function mk_default() {
13357
13398
  };
13358
13399
  }
13359
13400
 
13360
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ms.js
13401
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/ms.js
13361
13402
  var error35 = () => {
13362
13403
  const Sizable = {
13363
13404
  string: { unit: "aksara", verb: "mempunyai" },
@@ -13470,7 +13511,7 @@ function ms_default() {
13470
13511
  };
13471
13512
  }
13472
13513
 
13473
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ne.js
13514
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/ne.js
13474
13515
  var error36 = () => {
13475
13516
  const Sizable = {
13476
13517
  string: { unit: "\u0905\u0915\u094D\u0937\u0930", verb: "\u0939\u0941\u0928\u0941\u092A\u0930\u094D\u091B" },
@@ -13582,7 +13623,7 @@ function ne_default() {
13582
13623
  };
13583
13624
  }
13584
13625
 
13585
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/nl.js
13626
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/nl.js
13586
13627
  var error37 = () => {
13587
13628
  const Sizable = {
13588
13629
  string: { unit: "tekens", verb: "heeft" },
@@ -13698,7 +13739,7 @@ function nl_default() {
13698
13739
  };
13699
13740
  }
13700
13741
 
13701
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/nn.js
13742
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/nn.js
13702
13743
  var error38 = () => {
13703
13744
  const Sizable = {
13704
13745
  string: { unit: "teikn", verb: "\xE5 ha" },
@@ -13812,7 +13853,7 @@ function nn_default() {
13812
13853
  };
13813
13854
  }
13814
13855
 
13815
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/no.js
13856
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/no.js
13816
13857
  var error39 = () => {
13817
13858
  const Sizable = {
13818
13859
  string: { unit: "tegn", verb: "\xE5 ha" },
@@ -13926,7 +13967,7 @@ function no_default() {
13926
13967
  };
13927
13968
  }
13928
13969
 
13929
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ota.js
13970
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/ota.js
13930
13971
  var error40 = () => {
13931
13972
  const Sizable = {
13932
13973
  string: { unit: "harf", verb: "olmal\u0131d\u0131r" },
@@ -14041,7 +14082,7 @@ function ota_default() {
14041
14082
  };
14042
14083
  }
14043
14084
 
14044
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ps.js
14085
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/ps.js
14045
14086
  var error41 = () => {
14046
14087
  const Sizable = {
14047
14088
  string: { unit: "\u062A\u0648\u06A9\u064A", verb: "\u0648\u0644\u0631\u064A" },
@@ -14161,7 +14202,7 @@ function ps_default() {
14161
14202
  };
14162
14203
  }
14163
14204
 
14164
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/pl.js
14205
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/pl.js
14165
14206
  var error42 = () => {
14166
14207
  const Sizable = {
14167
14208
  string: { unit: "znak\xF3w", verb: "mie\u0107" },
@@ -14276,7 +14317,7 @@ function pl_default() {
14276
14317
  };
14277
14318
  }
14278
14319
 
14279
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/pt.js
14320
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/pt.js
14280
14321
  var error43 = () => {
14281
14322
  const Sizable = {
14282
14323
  string: { unit: "caracteres" },
@@ -14420,7 +14461,7 @@ function pt_default() {
14420
14461
  };
14421
14462
  }
14422
14463
 
14423
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/pt-BR.js
14464
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/pt-BR.js
14424
14465
  var error44 = () => {
14425
14466
  const Sizable = {
14426
14467
  string: { unit: "caracteres" },
@@ -14565,7 +14606,7 @@ function pt_BR_default() {
14565
14606
  };
14566
14607
  }
14567
14608
 
14568
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ro.js
14609
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/ro.js
14569
14610
  var error45 = () => {
14570
14611
  const Sizable = {
14571
14612
  string: { unit: "caractere", verb: "s\u0103 aib\u0103" },
@@ -14688,7 +14729,7 @@ function ro_default() {
14688
14729
  };
14689
14730
  }
14690
14731
 
14691
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ru.js
14732
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/ru.js
14692
14733
  function getRussianPlural(count, one, few, many) {
14693
14734
  const absCount = Math.abs(count);
14694
14735
  const lastDigit = absCount % 10;
@@ -14857,7 +14898,7 @@ function ru_default() {
14857
14898
  };
14858
14899
  }
14859
14900
 
14860
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/sk.js
14901
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/sk.js
14861
14902
  var error47 = () => {
14862
14903
  const Sizable = {
14863
14904
  string: { unit: "znakov", verb: "ma\u0165" },
@@ -14974,7 +15015,7 @@ function sk_default() {
14974
15015
  };
14975
15016
  }
14976
15017
 
14977
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/sl.js
15018
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/sl.js
14978
15019
  var error48 = () => {
14979
15020
  const Sizable = {
14980
15021
  string: { unit: "znakov", verb: "imeti" },
@@ -15089,7 +15130,7 @@ function sl_default() {
15089
15130
  };
15090
15131
  }
15091
15132
 
15092
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/sv.js
15133
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/sv.js
15093
15134
  var error49 = () => {
15094
15135
  const Sizable = {
15095
15136
  string: { unit: "tecken", verb: "att ha" },
@@ -15205,7 +15246,7 @@ function sv_default() {
15205
15246
  };
15206
15247
  }
15207
15248
 
15208
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ta.js
15249
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/ta.js
15209
15250
  var error50 = () => {
15210
15251
  const Sizable = {
15211
15252
  string: { unit: "\u0B8E\u0BB4\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1\u0B95\u0BCD\u0B95\u0BB3\u0BCD", verb: "\u0B95\u0BCA\u0BA3\u0BCD\u0B9F\u0BBF\u0BB0\u0BC1\u0B95\u0BCD\u0B95 \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD" },
@@ -15321,7 +15362,7 @@ function ta_default() {
15321
15362
  };
15322
15363
  }
15323
15364
 
15324
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/tg.js
15365
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/tg.js
15325
15366
  var error51 = () => {
15326
15367
  const Sizable = {
15327
15368
  string: { unit: "\u0430\u043B\u043E\u043C\u0430\u0442", verb: "\u0434\u043E\u0448\u0442\u0430 \u0431\u043E\u0448\u0430\u0434" },
@@ -15438,7 +15479,7 @@ function tg_default() {
15438
15479
  };
15439
15480
  }
15440
15481
 
15441
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/th.js
15482
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/th.js
15442
15483
  var error52 = () => {
15443
15484
  const Sizable = {
15444
15485
  string: { unit: "\u0E15\u0E31\u0E27\u0E2D\u0E31\u0E01\u0E29\u0E23", verb: "\u0E04\u0E27\u0E23\u0E21\u0E35" },
@@ -15554,7 +15595,7 @@ function th_default() {
15554
15595
  };
15555
15596
  }
15556
15597
 
15557
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/tk.js
15598
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/tk.js
15558
15599
  var error53 = () => {
15559
15600
  const Sizable = {
15560
15601
  string: { unit: "simwol", verb: "bolmaly" },
@@ -15662,7 +15703,7 @@ function tk_default() {
15662
15703
  };
15663
15704
  }
15664
15705
 
15665
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/tr.js
15706
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/tr.js
15666
15707
  var error54 = () => {
15667
15708
  const Sizable = {
15668
15709
  string: { unit: "karakter", verb: "olmal\u0131" },
@@ -15773,7 +15814,7 @@ function tr_default() {
15773
15814
  };
15774
15815
  }
15775
15816
 
15776
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/uk.js
15817
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/uk.js
15777
15818
  var error55 = () => {
15778
15819
  const Sizable = {
15779
15820
  string: { unit: "\u0441\u0438\u043C\u0432\u043E\u043B\u0456\u0432", verb: "\u043C\u0430\u0442\u0438\u043C\u0435" },
@@ -15887,12 +15928,12 @@ function uk_default() {
15887
15928
  };
15888
15929
  }
15889
15930
 
15890
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ua.js
15931
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/ua.js
15891
15932
  function ua_default() {
15892
15933
  return uk_default();
15893
15934
  }
15894
15935
 
15895
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ur.js
15936
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/ur.js
15896
15937
  var error56 = () => {
15897
15938
  const Sizable = {
15898
15939
  string: { unit: "\u062D\u0631\u0648\u0641", verb: "\u06C1\u0648\u0646\u0627" },
@@ -16008,7 +16049,7 @@ function ur_default() {
16008
16049
  };
16009
16050
  }
16010
16051
 
16011
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/uz.js
16052
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/uz.js
16012
16053
  var error57 = () => {
16013
16054
  const Sizable = {
16014
16055
  string: { unit: "belgi", verb: "bo\u2018lishi kerak" },
@@ -16122,7 +16163,7 @@ function uz_default() {
16122
16163
  };
16123
16164
  }
16124
16165
 
16125
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/vi.js
16166
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/vi.js
16126
16167
  var error58 = () => {
16127
16168
  const Sizable = {
16128
16169
  string: { unit: "k\xFD t\u1EF1", verb: "c\xF3" },
@@ -16236,7 +16277,7 @@ function vi_default() {
16236
16277
  };
16237
16278
  }
16238
16279
 
16239
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/zh-CN.js
16280
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/zh-CN.js
16240
16281
  var error59 = () => {
16241
16282
  const Sizable = {
16242
16283
  string: { unit: "\u5B57\u7B26", verb: "\u5305\u542B" },
@@ -16351,7 +16392,7 @@ function zh_CN_default() {
16351
16392
  };
16352
16393
  }
16353
16394
 
16354
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/zh-TW.js
16395
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/zh-TW.js
16355
16396
  var error60 = () => {
16356
16397
  const Sizable = {
16357
16398
  string: { unit: "\u5B57\u5143", verb: "\u64C1\u6709" },
@@ -16464,7 +16505,7 @@ function zh_TW_default() {
16464
16505
  };
16465
16506
  }
16466
16507
 
16467
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/yo.js
16508
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/locales/yo.js
16468
16509
  var error61 = () => {
16469
16510
  const Sizable = {
16470
16511
  string: { unit: "\xE0mi", verb: "n\xED" },
@@ -16577,7 +16618,7 @@ function yo_default() {
16577
16618
  };
16578
16619
  }
16579
16620
 
16580
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/registries.js
16621
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/registries.js
16581
16622
  var _a2;
16582
16623
  var $output = /* @__PURE__ */ Symbol("ZodOutput");
16583
16624
  var $input = /* @__PURE__ */ Symbol("ZodInput");
@@ -16627,7 +16668,7 @@ function registry() {
16627
16668
  (_a2 = globalThis).__zod_globalRegistry ?? (_a2.__zod_globalRegistry = registry());
16628
16669
  var globalRegistry = globalThis.__zod_globalRegistry;
16629
16670
 
16630
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/compile.js
16671
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/compile.js
16631
16672
  var INVALID = /* @__PURE__ */ Symbol.for("zod.compile.invalid");
16632
16673
  var FALLBACK_FLAG = /* @__PURE__ */ Symbol.for("zod.compile.fallback");
16633
16674
  var ZodCompileAsyncError = class extends Error {
@@ -17667,9 +17708,15 @@ function generateNullableCheck(doc, ctx, schema, accessor, buildsValue = true) {
17667
17708
  doc.write(`}`);
17668
17709
  return outputVar;
17669
17710
  }
17711
+ function generateSizeGate(doc, schema, size) {
17712
+ for (const [max, check2] of sizeCaps(schema._zod.def.checks)) {
17713
+ doc.write(`if (${size} > ${numericOperand(max, check2._zod.def.check)}) return INVALID;`);
17714
+ }
17715
+ }
17670
17716
  function generateArrayCheck(doc, ctx, schema, accessor, buildsValue = true) {
17671
17717
  const def = schema._zod.def;
17672
17718
  doc.write(`if (!Array.isArray(${accessor})) return INVALID;`);
17719
+ generateSizeGate(doc, schema, `${accessor}.length`);
17673
17720
  const outputVar = buildsValue ? newVar(ctx) : null;
17674
17721
  const iVar = newVar(ctx);
17675
17722
  const elemVar = newVar(ctx);
@@ -18069,6 +18116,7 @@ function literalPropertyKey(ctx, key) {
18069
18116
  function generateMapCheck(doc, ctx, schema, accessor) {
18070
18117
  const def = schema._zod.def;
18071
18118
  doc.write(`if (!(${accessor} instanceof Map)) return INVALID;`);
18119
+ generateSizeGate(doc, schema, `${accessor}.size`);
18072
18120
  const outputVar = newVar(ctx);
18073
18121
  const kVar = newVar(ctx);
18074
18122
  const valVar = newVar(ctx);
@@ -18085,6 +18133,7 @@ function generateMapCheck(doc, ctx, schema, accessor) {
18085
18133
  function generateSetCheck(doc, ctx, schema, accessor) {
18086
18134
  const def = schema._zod.def;
18087
18135
  doc.write(`if (!(${accessor} instanceof Set)) return INVALID;`);
18136
+ generateSizeGate(doc, schema, `${accessor}.size`);
18088
18137
  const outputVar = newVar(ctx);
18089
18138
  const valVar = newVar(ctx);
18090
18139
  doc.write(`const ${outputVar} = new Set();`);
@@ -18229,7 +18278,7 @@ function generateTransformCheck(doc, ctx, schema, accessor) {
18229
18278
  return accessor;
18230
18279
  }
18231
18280
 
18232
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/api.js
18281
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/api.js
18233
18282
  function snapshotChecks(def) {
18234
18283
  if (def.checks)
18235
18284
  def.checks = [...def.checks];
@@ -19288,7 +19337,7 @@ function _stringFormat(Class2, format, fnOrRegex, _params = {}) {
19288
19337
  return inst;
19289
19338
  }
19290
19339
 
19291
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/to-json-schema.js
19340
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/to-json-schema.js
19292
19341
  function assignProps(target, ...sources) {
19293
19342
  for (const source of sources) {
19294
19343
  for (const key of Reflect.ownKeys(source)) {
@@ -19818,7 +19867,7 @@ var createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) =
19818
19867
  return finalize(ctx, schema);
19819
19868
  };
19820
19869
 
19821
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/json-schema-processors.js
19870
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/json-schema-processors.js
19822
19871
  var narrowMin = (agg, key, value) => {
19823
19872
  if (agg[key] === void 0 || value > agg[key])
19824
19873
  agg[key] = value;
@@ -20566,7 +20615,7 @@ function toJSONSchema(input2, params) {
20566
20615
  return finalize(ctx, input2);
20567
20616
  }
20568
20617
 
20569
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/json-schema-generator.js
20618
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/json-schema-generator.js
20570
20619
  var JSONSchemaGenerator = class {
20571
20620
  /** @deprecated Access via ctx instead */
20572
20621
  get metadataRegistry() {
@@ -20644,10 +20693,10 @@ var JSONSchemaGenerator = class {
20644
20693
  }
20645
20694
  };
20646
20695
 
20647
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/json-schema.js
20696
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/json-schema.js
20648
20697
  var json_schema_exports = {};
20649
20698
 
20650
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/schemas.js
20699
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/classic/schemas.js
20651
20700
  var schemas_exports2 = {};
20652
20701
  __export(schemas_exports2, {
20653
20702
  ZodAny: () => ZodAny,
@@ -20828,7 +20877,7 @@ __export(schemas_exports2, {
20828
20877
  xor: () => xor
20829
20878
  });
20830
20879
 
20831
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/checks.js
20880
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/classic/checks.js
20832
20881
  var checks_exports2 = {};
20833
20882
  __export(checks_exports2, {
20834
20883
  endsWith: () => _endsWith,
@@ -20863,7 +20912,7 @@ __export(checks_exports2, {
20863
20912
  uppercase: () => _uppercase
20864
20913
  });
20865
20914
 
20866
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/errors.js
20915
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/classic/errors.js
20867
20916
  var _installedErrorProtos = /* @__PURE__ */ new WeakSet([Object.prototype, Error.prototype]);
20868
20917
  function _lazyMethod(proto, key, make) {
20869
20918
  Object.defineProperty(proto, key, {
@@ -20909,7 +20958,7 @@ var ZodRealError = /* @__PURE__ */ $constructor("ZodError", initializer2, void 0
20909
20958
  Parent: Error
20910
20959
  });
20911
20960
 
20912
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/parse.js
20961
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/classic/parse.js
20913
20962
  var parse2 = /* @__PURE__ */ _parse(ZodRealError);
20914
20963
  var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
20915
20964
  var safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
@@ -20923,7 +20972,7 @@ var safeDecode2 = /* @__PURE__ */ _safeDecode(ZodRealError);
20923
20972
  var safeEncodeAsync2 = /* @__PURE__ */ _safeEncodeAsync(ZodRealError);
20924
20973
  var safeDecodeAsync2 = /* @__PURE__ */ _safeDecodeAsync(ZodRealError);
20925
20974
 
20926
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/schemas.js
20975
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/classic/schemas.js
20927
20976
  function _ensureDefaultLocale() {
20928
20977
  if (!globalConfig.localeError)
20929
20978
  config(en_default());
@@ -22388,7 +22437,7 @@ function preprocess(fn, schema) {
22388
22437
  });
22389
22438
  }
22390
22439
 
22391
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/compat.js
22440
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/classic/compat.js
22392
22441
  var ZodIssueCode = {
22393
22442
  invalid_type: "invalid_type",
22394
22443
  too_big: "too_big",
@@ -22414,7 +22463,7 @@ var ZodFirstPartyTypeKind;
22414
22463
  /* @__PURE__ */ (function(ZodFirstPartyTypeKind2) {
22415
22464
  })(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
22416
22465
 
22417
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/iso.js
22466
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/classic/iso.js
22418
22467
  var iso_exports = {};
22419
22468
  __export(iso_exports, {
22420
22469
  ZodISODate: () => ZodISODate,
@@ -22439,7 +22488,7 @@ function duration2(params) {
22439
22488
  return _isoDuration(ZodISODuration, params);
22440
22489
  }
22441
22490
 
22442
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/from-json-schema.js
22491
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/classic/from-json-schema.js
22443
22492
  var z = {
22444
22493
  ...schemas_exports2,
22445
22494
  ...checks_exports2,
@@ -23172,7 +23221,7 @@ function fromJSONSchema(schema, params) {
23172
23221
  return convertSchema(normalized, ctx);
23173
23222
  }
23174
23223
 
23175
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/visit.js
23224
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/core/visit.js
23176
23225
  var RESOLVING = /* @__PURE__ */ Symbol("z.visit/resolving");
23177
23226
  function visit(schema, fnOrHandlers) {
23178
23227
  const fn = typeof fnOrHandlers === "function" ? fnOrHandlers : (node2, rewritten) => {
@@ -23327,7 +23376,7 @@ function visit(schema, fnOrHandlers) {
23327
23376
  return run(schema);
23328
23377
  }
23329
23378
 
23330
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/deep-partial.js
23379
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/classic/deep-partial.js
23331
23380
  function deepPartial(schema) {
23332
23381
  return visit(schema, {
23333
23382
  object: (s) => s.partial(),
@@ -23339,7 +23388,7 @@ function deepPartial(schema) {
23339
23388
  });
23340
23389
  }
23341
23390
 
23342
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/in-out.js
23391
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/classic/in-out.js
23343
23392
  function withChecks(side, checks) {
23344
23393
  if (!checks?.length)
23345
23394
  return side;
@@ -23369,7 +23418,7 @@ function output(schema) {
23369
23418
  });
23370
23419
  }
23371
23420
 
23372
- // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/coerce.js
23421
+ // node_modules/.pnpm/zod@4.6.6/node_modules/zod/v4/classic/coerce.js
23373
23422
  var coerce_exports = {};
23374
23423
  __export(coerce_exports, {
23375
23424
  bigint: () => bigint3,
@@ -23653,11 +23702,14 @@ var Budget = class {
23653
23702
  windowMs;
23654
23703
  windowAt = 0;
23655
23704
  left = 0;
23705
+ /** 有没有真的开过窗口(见 `take` 的第 ② 条)。 */
23706
+ armed = false;
23656
23707
  /** 取一个配额;成功 true,用尽 false。 */
23657
23708
  take(now) {
23658
- if (now - this.windowAt >= this.windowMs || now < this.windowAt) {
23709
+ if (!this.armed || now - this.windowAt >= this.windowMs || now < this.windowAt) {
23659
23710
  this.windowAt = now;
23660
23711
  this.left = this.perWindow;
23712
+ this.armed = true;
23661
23713
  }
23662
23714
  if (this.left <= 0) return false;
23663
23715
  this.left -= 1;
@@ -23811,6 +23863,9 @@ function loadConfig(env, version2) {
23811
23863
  pairStatusBudgetPerSec: integer2(env.DRC_PAIR_STATUS_PER_SEC, 5, "DRC_PAIR_STATUS_PER_SEC", problems),
23812
23864
  maxPendingPairs: integer2(env.DRC_MAX_PENDING_PAIRS, 1e3, "DRC_MAX_PENDING_PAIRS", problems),
23813
23865
  maxHostTokens: integer2(env.DRC_MAX_HOST_TOKENS, 500, "DRC_MAX_HOST_TOKENS", problems),
23866
+ // D6:会话表是唯一曾经没有上界的一张表,而每次认领都要同步写它(成本 ∝ 表大小)。
23867
+ // 默认与依据见 `RelayConfig.maxConversations` 的注释。
23868
+ maxConversations: integer2(env.DRC_MAX_CONVERSATIONS, 5e3, "DRC_MAX_CONVERSATIONS", problems),
23814
23869
  claimMinIntervalMs: claimMinIntervalMs(env, problems),
23815
23870
  conversationIdleTtlMs: integer2(env.DRC_CONV_IDLE_TTL_MS, 7 * 24 * 3600 * 1e3, "DRC_CONV_IDLE_TTL_MS", problems),
23816
23871
  // P2-⑤(2026-10-04 用户拍板 30 分钟):远小于 7 天的空闲 TTL。
@@ -24673,10 +24728,6 @@ function readStateFile(path, log) {
24673
24728
  return void 0;
24674
24729
  }
24675
24730
  const file2 = parsed;
24676
- if (file2.version !== STATE_FILE_VERSION) {
24677
- log.warn("state file version mismatch, starting empty", { path, found: String(file2.version) });
24678
- return void 0;
24679
- }
24680
24731
  const { conversations, dropped } = sanitize(file2.conversations);
24681
24732
  if (dropped > 0) log.warn("state file entries dropped", { path, dropped, kept: conversations.length });
24682
24733
  if (!Array.isArray(file2.hostTokens)) {
@@ -24813,9 +24864,15 @@ var RelayState = class {
24813
24864
  /** 测试可注入固定时钟;默认用真实时间。 */
24814
24865
  clock;
24815
24866
  maxPendingPairsValue;
24867
+ /**
24868
+ * 会话表上界(D6)。见 `RelayConfig.maxConversations` 的注释:这是"每次认领同步整表写"
24869
+ * 那条成本链的**唯一**封口。
24870
+ */
24871
+ maxConversationsValue;
24816
24872
  constructor(options = {}) {
24817
24873
  this.clock = options.now ?? (() => Date.now());
24818
24874
  this.maxPendingPairsValue = options.maxPendingPairs ?? 1e3;
24875
+ this.maxConversationsValue = options.maxConversations ?? 5e3;
24819
24876
  }
24820
24877
  now() {
24821
24878
  return this.clock();
@@ -24880,6 +24937,27 @@ var RelayState = class {
24880
24937
  });
24881
24938
  return { ok: true, replaced: existing !== void 0, full: false };
24882
24939
  }
24940
+ /**
24941
+ * 回收**已空**的会话,从最旧的一条开始,直到表回到上界以下(D6)。
24942
+ *
24943
+ * "最旧"按 `emptySince ?? lastActivityAt` 算——即"它被放弃得有多久",
24944
+ * 而不是"会话建立得有多早":一条建立了很久但直到刚才才被放弃的会话,
24945
+ * 比一条刚建立就被放弃的更该回收。
24946
+ *
24947
+ * 返回回收了几条(调用方拿它写日志/计数——回收这件事必须留痕,
24948
+ * 否则"表为什么突然小了一截"只能靠猜)。
24949
+ */
24950
+ evictAbandonedConversations() {
24951
+ if (this.conversations.size < this.maxConversationsValue) return 0;
24952
+ const abandoned = [...this.conversations.entries()].filter(([, conv]) => conv.clients.size === 0).sort((a, b) => (a[1].emptySince ?? a[1].lastActivityAt) - (b[1].emptySince ?? b[1].lastActivityAt));
24953
+ let dropped = 0;
24954
+ for (const [conversationId] of abandoned) {
24955
+ if (this.conversations.size < this.maxConversationsValue) break;
24956
+ this.conversations.delete(conversationId);
24957
+ dropped += 1;
24958
+ }
24959
+ return dropped;
24960
+ }
24883
24961
  /** 还能被认领的码数(`/api/pair-status` 与主机侧「还有没有码可发」问的都是它)。 */
24884
24962
  countClaimablePairs() {
24885
24963
  let n = 0;
@@ -24894,6 +24972,12 @@ var RelayState = class {
24894
24972
  if (pending.used) return { ok: false, reason: "already_used" };
24895
24973
  const host = this.hosts.get(pending.hostId);
24896
24974
  if (!host || host.ws.readyState !== WS_OPEN) return { ok: false, reason: "host_offline" };
24975
+ if (this.conversations.size >= this.maxConversationsValue) {
24976
+ this.evictAbandonedConversations();
24977
+ if (this.conversations.size >= this.maxConversationsValue) {
24978
+ return { ok: false, reason: "table_full" };
24979
+ }
24980
+ }
24897
24981
  pending.used = true;
24898
24982
  const detached = this.leaveAll(clientId);
24899
24983
  const conversationId = newConversationId();
@@ -25247,11 +25331,16 @@ function tokenMatches(expected, got) {
25247
25331
  return timingSafeEqual(a, b);
25248
25332
  }
25249
25333
  var CLAIM_TRACK_MAX = 1e4;
25334
+ var PERSIST_COALESCE_MS = 200;
25250
25335
  var MAX_HOST_ID_LEN2 = 200;
25251
25336
  var HOST_ID_RE = /^[A-Za-z0-9._:-]+$/;
25252
25337
  function createRelay(config2) {
25253
25338
  const log = new Log(config2.logLevel);
25254
- const state = new RelayState({ maxPendingPairs: config2.maxPendingPairs });
25339
+ const state = new RelayState({
25340
+ maxPendingPairs: config2.maxPendingPairs,
25341
+ // D6:会话表上界(缺了它,每次认领的同步整表写就成了无界的成本放大)。
25342
+ maxConversations: config2.maxConversations
25343
+ });
25255
25344
  const startedAt = Date.now();
25256
25345
  const pairBudget = new Budget(config2.pairGlobalBudgetPerSec);
25257
25346
  const pairStatusBudget = new Budget(config2.pairStatusBudgetPerSec);
@@ -25260,6 +25349,8 @@ function createRelay(config2) {
25260
25349
  const lastClaimAt = /* @__PURE__ */ new Map();
25261
25350
  let sweepTimer;
25262
25351
  let pingTimer;
25352
+ let persistPending = false;
25353
+ let persistTimer;
25263
25354
  let lastPingAt = 0;
25264
25355
  let lastCountersAt = 0;
25265
25356
  function newHostToken() {
@@ -25295,6 +25386,11 @@ function createRelay(config2) {
25295
25386
  }
25296
25387
  }
25297
25388
  function persistNow() {
25389
+ persistPending = false;
25390
+ if (persistTimer !== void 0) {
25391
+ clearTimeout(persistTimer);
25392
+ persistTimer = void 0;
25393
+ }
25298
25394
  if (!persistence.enabled) return false;
25299
25395
  const ok = writeStateFile(config2.stateFile, snapshotState(state, Date.now()), log);
25300
25396
  if (ok) {
@@ -25306,6 +25402,17 @@ function createRelay(config2) {
25306
25402
  return ok;
25307
25403
  }
25308
25404
  function markStateChanged() {
25405
+ if (!persistence.enabled) return;
25406
+ persistPending = true;
25407
+ if (persistTimer !== void 0) return;
25408
+ persistTimer = setTimeout(() => {
25409
+ persistTimer = void 0;
25410
+ flushPendingPersist();
25411
+ }, PERSIST_COALESCE_MS);
25412
+ persistTimer.unref?.();
25413
+ }
25414
+ function flushPendingPersist() {
25415
+ if (!persistPending) return;
25309
25416
  persistNow();
25310
25417
  }
25311
25418
  const MAX_PING_BUCKETS = 1024;
@@ -25475,9 +25582,24 @@ function createRelay(config2) {
25475
25582
  }
25476
25583
  const claimed = state.claim(frame.pairingToken, peer.clientId);
25477
25584
  if (!claimed.ok) {
25585
+ const wireReason = claimed.reason === "table_full" ? "invalid_or_expired" : claimed.reason;
25586
+ if (claimed.reason === "table_full") {
25587
+ counters.rejectedPairs += 1;
25588
+ const now = Date.now();
25589
+ if (now - peer.tableFullWarnedAt >= 1e3) {
25590
+ peer.tableFullWarnedAt = now;
25591
+ log.warn("conversation table full, refusing new pairings (D6)", {
25592
+ clientId: peer.clientId,
25593
+ conversations: state.conversations.size,
25594
+ max: config2.maxConversations
25595
+ });
25596
+ }
25597
+ sendToPeer(peer, pairFail(wireReason, frame.pairingToken));
25598
+ return;
25599
+ }
25478
25600
  peer.pairAttempts += 1;
25479
25601
  counters.rejectedPairs += 1;
25480
- sendToPeer(peer, pairFail(claimed.reason, frame.pairingToken));
25602
+ sendToPeer(peer, pairFail(wireReason, frame.pairingToken));
25481
25603
  log.info("pair failed", {
25482
25604
  clientId: peer.clientId,
25483
25605
  reason: claimed.reason,
@@ -25675,6 +25797,7 @@ function createRelay(config2) {
25675
25797
  notedNonMember: false,
25676
25798
  notedPairTableFull: false,
25677
25799
  pairBudgetWarnedAt: 0,
25800
+ tableFullWarnedAt: 0,
25678
25801
  backpressure: new BackpressureGate(),
25679
25802
  alive: true,
25680
25803
  // 轮转序号取模分配:**均匀是刻意的**。哪怕重启风暴里 10k 条连接在几十秒内
@@ -26141,7 +26264,7 @@ function registerSignalHandlers(shutdown) {
26141
26264
 
26142
26265
  // src/main.ts
26143
26266
  function readVersion() {
26144
- if ("3.1.4") return "3.1.4";
26267
+ if ("3.1.5") return "3.1.5";
26145
26268
  try {
26146
26269
  const pkg = JSON.parse(readFileSync2(new URL("../../package.json", import.meta.url), "utf8"));
26147
26270
  if (typeof pkg.version === "string") return pkg.version;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-remote/relay",
3
- "version": "3.1.4",
3
+ "version": "3.1.5",
4
4
  "description": "DSH Remote Control 的零知识 WebSocket 中继:只做路由,不碰载荷明文。可自托管的单文件产物。",
5
5
  "type": "module",
6
6
  "license": "MIT",