@h-ai/serv 0.1.0-alpha.69 → 0.1.0-alpha.71

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.en.md CHANGED
@@ -694,16 +694,6 @@ Browsers keep application-level `setGlobalLocale` / `createLocaleStore`. During
694
694
 
695
695
  Object keys are limited to 1024 UTF-8 bytes and reject absolute paths, backslashes, control characters and dot segments. Each public HTTP batch delete accepts 1–1000 entries. `@h-ai/storage/schemas` exposes the shared browser-safe rules. Presign expiry is an integer from 1 to 604800 seconds (Node default 3600, HTTP default 900). Upload signing accepts only key/contentType/expiresIn; contentLength/maxSize/metadata/checksum are unsupported. Invalid input returns HTTP 400 and the typed client maps it to VALIDATION_FAILED. FileUpload limits guide file selection; applications must validate actual objects on the server. Node streaming/checksum/conditional-write options have no default HTTP endpoints. See the [capability and authorization matrix (Chinese)](../storage/README.md#存储输入约束与跨端能力).
696
696
 
697
- ## Development and testing
698
-
699
- ```bash
700
- pnpm --filter @h-ai/serv test
701
- pnpm --filter @h-ai/serv typecheck
702
- pnpm --filter @h-ai/serv lint
703
- ```
704
-
705
- Declaration JSDoc examples import actual `@h-ai/serv` entries or published feature subpaths. Internal Hono, guard, router and transport examples are marked as internal module context and are not root APIs. Examples distinguish startup configuration exceptions, domain HaiResult, HTTP middleware statuses, and listener shutdown returning Promise<void>; default AI completion still returns non-streaming JSON only. Maintainers can run `node scripts/check-module-jsdoc.mjs --package serv` against actual declarations and internal lexical bindings. Compilation does not replace real HTTP, authorization or distributed replay-protection validation.
706
-
707
697
  ## Optional feedback service and trusted scope
708
698
 
709
699
  Mount `apiContract.feedback` with `createFeedbackProcedures` from `@h-ai/serv/features/feedback`. The runtime root does not load the feedback service. Initialize reldb/storage/reach/feedback in the host, then map verified sessions and deployment policy to feedback scope. A null resolver result or mismatched user is denied; the domain module also checks scope and permissions.
@@ -734,6 +724,22 @@ const app = serv.createApp({
734
724
  })
735
725
  ```
736
726
 
727
+ ## Error messages and correlated logs
728
+
729
+ HTTP errors expose localized safe messages followed by `(traceId: …)`, with the same ID in `error.traceId` and `X-Trace-Id`. The framework reuses the request ID to correlate browser and server logs. Sanitized exceptions, stacks and operation context remain in logs; internal cause/ext are not exposed. Field validation returns localized field names and messages only.
730
+
731
+ Use `core.error.toPublic(error, traceId?)` at HTTP/UI boundaries and `core.error.formatMessage(error)` after translating messages; formatting is idempotent. Pass complete Error objects to logs instead of discarding their context. Database failures log driver codes, sanitized messages/stacks and table/column context; SQL text, bound values and connection credentials are excluded.
732
+
733
+ ## Development and testing
734
+
735
+ ```bash
736
+ pnpm --filter @h-ai/serv test
737
+ pnpm --filter @h-ai/serv typecheck
738
+ pnpm --filter @h-ai/serv lint
739
+ ```
740
+
741
+ Declaration JSDoc examples import actual `@h-ai/serv` entries or published feature subpaths. Internal Hono, guard, router and transport examples are marked as internal module context and are not root APIs. Examples distinguish startup configuration exceptions, domain HaiResult, HTTP middleware statuses, and listener shutdown returning Promise<void>; default AI completion still returns non-streaming JSON only. Maintainers can run `node scripts/check-module-jsdoc.mjs --package serv` against actual declarations and internal lexical bindings. Compilation does not replace real HTTP, authorization or distributed replay-protection validation.
742
+
737
743
  ## License
738
744
 
739
745
  Apache-2.0
package/README.ja.md CHANGED
@@ -694,16 +694,6 @@ Node リクエストと SSR は `core.i18n.runWithLocale(locale, () => handleReq
694
694
 
695
695
  キーは UTF-8 で最大 1024 バイトで、絶対パス、バックスラッシュ、制御文字、ドットセグメントを拒否します。公開 HTTP 一括削除は一度に 1–1000 件です。共通規則はブラウザー対応の `@h-ai/storage/schemas` から参照できます。署名有効期限は整数 1–604800 秒(Node 既定 3600、HTTP 既定 900)。アップロード署名の入力は key/contentType/expiresIn のみで、contentLength/maxSize/metadata/checksum は未対応です。不正入力は HTTP 400、typed client では VALIDATION_FAILED です。FileUpload の制限は選択時の補助であり、実際のオブジェクトはサーバーで検証してください。Node のストリーム/checksum/条件付き書き込みには既定の HTTP エンドポイントがありません。[機能と認可の対応表(中国語)](../storage/README.md#存储输入约束与跨端能力)を参照してください。
696
696
 
697
- ## 開発とテスト
698
-
699
- ```bash
700
- pnpm --filter @h-ai/serv test
701
- pnpm --filter @h-ai/serv typecheck
702
- pnpm --filter @h-ai/serv lint
703
- ```
704
-
705
- 宣言の JSDoc 例は実在する `@h-ai/serv` または公開 features サブパスから import します。内部 Hono・guard・router・transport は「模块内部上下文」と明記し、ルート API として扱いません。起動設定の例外、業務 HaiResult、HTTP middleware の status、listener の Promise<void> 終了を区別し、既定の AI completion は非ストリーミング JSON のままです。保守時は `node scripts/check-module-jsdoc.mjs --package serv` で実際の宣言と内部スコープに対して例をコンパイルします。実 HTTP、認可、共有リプレイ防止の検証を代替しません。
706
-
707
697
  ## オプションのフィードバックサービスと信頼範囲
708
698
 
709
699
  `@h-ai/serv/features/feedback` の `createFeedbackProcedures` で `apiContract.feedback` を接続します。通常のランタイム入口は feedback サービスを読み込みません。ホストで reldb/storage/reach/feedback を初期化し、検証済みセッションと配置ポリシーから範囲を作ります。null またはユーザー不一致は拒否し、ドメイン側も範囲と権限を検証します。
@@ -734,6 +724,22 @@ const app = serv.createApp({
734
724
  })
735
725
  ```
736
726
 
727
+ ## エラー表示とログの関連付け
728
+
729
+ HTTP エラーはローカライズ済みの安全な表示に `(traceId: …)` を付け、同じ ID を error.traceId と X-Trace-Id に返します。requestId を traceId として共有し、ブラウザーとサーバーのログを関連付けます。脱機密化した例外・スタック・操作情報はログに残し、内部 cause/ext は公開しません。項目検証は翻訳済みの項目名とメッセージだけを返します。
730
+
731
+ HTTP/UI 境界には core.error.toPublic(error, traceId?)、再翻訳後の表示には core.error.formatMessage(error) を使い、ID を重複追加しません。ログには完全な Error を渡してください。DB ログにはドライバーコード、脱機密化したメッセージ・スタック、表・列を残し、SQL 本文、バインド値と接続認証情報を記録しません。
732
+
733
+ ## 開発とテスト
734
+
735
+ ```bash
736
+ pnpm --filter @h-ai/serv test
737
+ pnpm --filter @h-ai/serv typecheck
738
+ pnpm --filter @h-ai/serv lint
739
+ ```
740
+
741
+ 宣言の JSDoc 例は実在する `@h-ai/serv` または公開 features サブパスから import します。内部 Hono・guard・router・transport は「模块内部上下文」と明記し、ルート API として扱いません。起動設定の例外、業務 HaiResult、HTTP middleware の status、listener の Promise<void> 終了を区別し、既定の AI completion は非ストリーミング JSON のままです。保守時は `node scripts/check-module-jsdoc.mjs --package serv` で実際の宣言と内部スコープに対して例をコンパイルします。実 HTTP、認可、共有リプレイ防止の検証を代替しません。
742
+
737
743
  ## ライセンス
738
744
 
739
745
  Apache-2.0
package/README.md CHANGED
@@ -694,16 +694,6 @@ Node 请求与 SSR 使用 `core.i18n.runWithLocale(locale, () => handleRequest()
694
694
 
695
695
  存储 key 按 UTF-8 最多 1024 字节,并拒绝绝对路径、反斜线、控制字符及点路径段;公开 HTTP 批量删除每次 1–1000 项。`@h-ai/storage/schemas` 提供浏览器安全的共同规则。预签名有效期为整数 1–604800 秒(Node 默认 3600,HTTP 默认 900);HTTP 上传仅接受 key/contentType/expiresIn,不支持 contentLength/maxSize/metadata/checksum。无效输入返回 HTTP 400,typed client 映射 VALIDATION_FAILED。FileUpload 的大小/类型限制仅为前端体验,实际对象须由应用服务端复核。Node 流式读写/checksum/条件写等没有默认 HTTP 端点。完整映射与授权边界见 [存储 API 能力](../storage/README.md#存储输入约束与跨端能力)。
696
696
 
697
- ## 开发测试
698
-
699
- ```bash
700
- pnpm --filter @h-ai/serv test
701
- pnpm --filter @h-ai/serv typecheck
702
- pnpm --filter @h-ai/serv lint
703
- ```
704
-
705
- 声明旁的 JSDoc 示例从实际 `@h-ai/serv` 或已公开的 features 子路径导入;内部 Hono/guard/router/transport 示例明确标注“模块内部上下文”,不代表根 API。示例区分工厂的启动配置异常、领域 HaiResult、HTTP middleware 状态码和监听句柄的 Promise<void> 关闭;默认 AI completion 仍只返回非流式 JSON。框架维护运行 `node scripts/check-module-jsdoc.mjs --package serv` 对实际声明和内部词法绑定编译示例,编译不代替真实 HTTP、授权与分布式防重放验收。
706
-
707
697
  ## 可选的反馈服务与可信范围
708
698
 
709
699
  通过 `@h-ai/serv/features/feedback` 的 `createFeedbackProcedures` 挂载 `apiContract.feedback`;只导入运行时根入口不会加载反馈服务。宿主先初始化 reldb/storage/reach/feedback,再从已验证的会话与部署策略映射反馈范围。resolveContext 返回 null 或用户不匹配时拒绝访问;领域模块再次校验范围与权限。
@@ -734,6 +724,22 @@ const app = serv.createApp({
734
724
  })
735
725
  ```
736
726
 
727
+ ## 错误提示与关联日志
728
+
729
+ HTTP 错误只向用户返回本地化的安全提示,末尾显示 `(traceId: …)`;响应同时包含 `error.traceId` 和 `X-Trace-Id`。框架复用本次 requestId 作为 traceId,前后端日志自动关联。底层异常、堆栈和操作上下文经凭据脱敏后写入日志,不通过 cause/ext 向用户公开。字段校验只返回本地化的字段名和错误。
730
+
731
+ `core.error.toPublic(error, traceId?)` 用于接口/UI 边界;`core.error.formatMessage(error)` 用于重新翻译后的提示,重复调用不会重复追加标识。日志传入完整 Error 对象,不能只记录通用标题或提前 String(error) 丢失上下文。数据库失败记录驱动错误码、消息、堆栈及表/列;SQL 原文、绑定值和连接凭据不进入日志。
732
+
733
+ ## 开发测试
734
+
735
+ ```bash
736
+ pnpm --filter @h-ai/serv test
737
+ pnpm --filter @h-ai/serv typecheck
738
+ pnpm --filter @h-ai/serv lint
739
+ ```
740
+
741
+ 声明旁的 JSDoc 示例从实际 `@h-ai/serv` 或已公开的 features 子路径导入;内部 Hono/guard/router/transport 示例明确标注“模块内部上下文”,不代表根 API。示例区分工厂的启动配置异常、领域 HaiResult、HTTP middleware 状态码和监听句柄的 Promise<void> 关闭;默认 AI completion 仍只返回非流式 JSON。框架维护运行 `node scripts/check-module-jsdoc.mjs --package serv` 对实际声明和内部词法绑定编译示例,编译不代替真实 HTTP、授权与分布式防重放验收。
742
+
737
743
  ## 许可证
738
744
 
739
745
  Apache-2.0
@@ -190,7 +190,8 @@ function buildHaiErrorBody(def, message) {
190
190
  success: false,
191
191
  error: {
192
192
  code: def.code,
193
- message,
193
+ message: core.error.formatMessage({ message, traceId: core.context.get().traceId ?? core.context.get().requestId }),
194
+ traceId: core.context.get().traceId ?? core.context.get().requestId,
194
195
  httpStatus: def.httpStatus,
195
196
  system: def.system,
196
197
  module: def.module
@@ -200,9 +201,16 @@ function buildHaiErrorBody(def, message) {
200
201
  function mapHaiError(handler) {
201
202
  return async (options) => {
202
203
  try {
203
- return await handler(options);
204
+ const result = await handler(options);
205
+ if (result.success)
206
+ return result;
207
+ const error = core.error.toPublic(result.error, options.context.requestId, options.context.locale);
208
+ options.context.logger.error("Procedure failed", { traceId: error.traceId, error: result.error });
209
+ return { success: false, error };
204
210
  } catch (error) {
205
- return err(HaiCommonError.INTERNAL_ERROR, servM("serv_errorInternal", { locale: options.context.locale }), error);
211
+ const safe = core.error.toPublic({ ...HaiCommonError.INTERNAL_ERROR, message: servM("serv_errorInternal", { locale: options.context.locale }) }, options.context.requestId, options.context.locale);
212
+ options.context.logger.error("Procedure threw an exception", { traceId: safe.traceId, error });
213
+ return err(safe);
206
214
  }
207
215
  };
208
216
  }
@@ -246,7 +254,8 @@ var ServRouterBuilderRuntime = class {
246
254
  const implementHandler = getHandlerMethod(procedureImplementer);
247
255
  if (!implementHandler)
248
256
  throw new TypeError(`Contract path is not implementable: ${path}`);
249
- const safeHandler = hasGuards(guards) ? applyServGuards(guards, handler) : mapHaiError(handler);
257
+ const guardedHandler = hasGuards(guards) ? applyServGuards(guards, handler) : handler;
258
+ const safeHandler = mapHaiError(guardedHandler);
250
259
  const implemented = Reflect.apply(
251
260
  implementHandler,
252
261
  procedureImplementer,
@@ -358,5 +367,5 @@ function getHandlerMethod(value) {
358
367
  }
359
368
 
360
369
  export { WILDCARD_PERMISSION, WILDCARD_ROLE, buildHaiErrorBody, implement, normalizeServLocale, servM };
361
- //# sourceMappingURL=chunk-TWHCU6HT.js.map
362
- //# sourceMappingURL=chunk-TWHCU6HT.js.map
370
+ //# sourceMappingURL=chunk-KR4H56KP.js.map
371
+ //# sourceMappingURL=chunk-KR4H56KP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../messages/en-US.json","../messages/ja-JP.json","../messages/zh-CN.json","../src/serv-i18n.ts","../src/pipelines/serv-pipeline-guard.ts","../src/pipelines/serv-pipeline-helper.ts","../src/serv-router.ts"],"names":["core","HaiCommonError","err","orpcImplement"],"mappings":";;;;;;AAAA,IAAA,aAAA,GAAA;AAAA,EACE,OAAA,EAAW,iDAAA;AAAA,EACX,qBAAA,EAAyB,mBAAA;AAAA,EACzB,uBAAA,EAA2B,wBAAA;AAAA,EAC3B,sBAAA,EAA0B,sBAAA;AAAA,EAC1B,0BAAA,EAA8B,oBAAA;AAAA,EAC9B,wBAAA,EAA4B,iCAAA;AAAA,EAC5B,wBAAA,EAA4B,iCAAA;AAAA,EAC5B,wBAAA,EAA4B,8BAAA;AAAA,EAC5B,wBAAA,EAA4B,6BAAA;AAAA,EAC5B,uBAAA,EAA2B,+BAAA;AAAA,EAC3B,uBAAA,EAA2B,8BAAA;AAAA,EAC3B,uBAAA,EAA2B,8BAAA;AAAA,EAC3B,qBAAA,EAAyB,6BAAA;AAAA,EACzB,oBAAA,EAAwB,6BAAA;AAAA,EACxB,kBAAA,EAAsB,mBAAA;AAAA,EACtB,mBAAA,EAAuB,oBAAA;AAAA,EACvB,mBAAA,EAAuB,uBAAA;AAAA,EACvB,sBAAA,EAA0B,cAAA;AAAA,EAC1B,mBAAA,EAAuB,WAAA;AAAA,EACvB,kBAAA,EAAsB,uBAAA;AAAA,EACtB,uBAAA,EAA2B,+BAAA;AAAA,EAC3B,sBAAA,EAA0B,8CAAA;AAAA,EAC1B,2BAAA,EAA+B,yCAAA;AAAA,EAC/B,0BAAA,EAA8B,oDAAA;AAAA,EAC9B,+BAAA,EAAmC,0CAAA;AAAA,EACnC,4BAAA,EAAgC,qCAAA;AAAA,EAChC,2BAAA,EAA+B,kDAAA;AAAA,EAC/B,8BAAA,EAAkC,mDAAA;AAAA,EAClC,+BAAA,EAAmC,uEAAA;AAAA,EACnC,2BAAA,EAA+B,2BAAA;AAAA,EAC/B,2BAAA,EAA+B,4BAAA;AAAA,EAC/B,+BAAA,EAAmC;AACrC,CAAA;;;ACjCA,IAAA,aAAA,GAAA;AAAA,EACE,OAAA,EAAW,iDAAA;AAAA,EACX,qBAAA,EAAyB,sFAAA;AAAA,EACzB,uBAAA,EAA2B,wDAAA;AAAA,EAC3B,sBAAA,EAA0B,wDAAA;AAAA,EAC1B,0BAAA,EAA8B,0EAAA;AAAA,EAC9B,wBAAA,EAA4B,qFAAA;AAAA,EAC5B,wBAAA,EAA4B,yGAAA;AAAA,EAC5B,wBAAA,EAA4B,qFAAA;AAAA,EAC5B,wBAAA,EAA4B,qFAAA;AAAA,EAC5B,uBAAA,EAA2B,yEAAA;AAAA,EAC3B,uBAAA,EAA2B,+EAAA;AAAA,EAC3B,uBAAA,EAA2B,qFAAA;AAAA,EAC3B,qBAAA,EAAyB,qFAAA;AAAA,EACzB,oBAAA,EAAwB,oHAAA;AAAA,EACxB,kBAAA,EAAsB,6EAAA;AAAA,EACtB,mBAAA,EAAuB,8EAAA;AAAA,EACvB,mBAAA,EAAuB,sFAAA;AAAA,EACvB,sBAAA,EAA0B,wDAAA;AAAA,EAC1B,mBAAA,EAAuB,0EAAA;AAAA,EACvB,kBAAA,EAAsB,wDAAA;AAAA,EACtB,uBAAA,EAA2B,0HAAA;AAAA,EAC3B,sBAAA,EAA0B,qIAAA;AAAA,EAC1B,2BAAA,EAA+B,gIAAA;AAAA,EAC/B,0BAAA,EAA8B,yLAAA;AAAA,EAC9B,+BAAA,EAAmC,0HAAA;AAAA,EACnC,4BAAA,EAAgC,8GAAA;AAAA,EAChC,2BAAA,EAA+B,4IAAA;AAAA,EAC/B,8BAAA,EAAkC,+HAAA;AAAA,EAClC,+BAAA,EAAmC,oQAAA;AAAA,EACnC,2BAAA,EAA+B,4FAAA;AAAA,EAC/B,2BAAA,EAA+B,kGAAA;AAAA,EAC/B,+BAAA,EAAmC;AACrC,CAAA;;;ACjCA,IAAA,aAAA,GAAA;AAAA,EACE,OAAA,EAAW,iDAAA;AAAA,EACX,qBAAA,EAAyB,sCAAA;AAAA,EACzB,uBAAA,EAA2B,gCAAA;AAAA,EAC3B,sBAAA,EAA0B,sCAAA;AAAA,EAC1B,0BAAA,EAA8B,4CAAA;AAAA,EAC9B,wBAAA,EAA4B,mDAAA;AAAA,EAC5B,wBAAA,EAA4B,0DAAA;AAAA,EAC5B,wBAAA,EAA4B,4CAAA;AAAA,EAC5B,wBAAA,EAA4B,4CAAA;AAAA,EAC5B,uBAAA,EAA2B,uCAAA;AAAA,EAC3B,uBAAA,EAA2B,uCAAA;AAAA,EAC3B,uBAAA,EAA2B,gCAAA;AAAA,EAC3B,qBAAA,EAAyB,gCAAA;AAAA,EACzB,oBAAA,EAAwB,8DAAA;AAAA,EACxB,kBAAA,EAAsB,kDAAA;AAAA,EACtB,mBAAA,EAAuB,2CAAA;AAAA,EACvB,mBAAA,EAAuB,4CAAA;AAAA,EACvB,sBAAA,EAA0B,wDAAA;AAAA,EAC1B,mBAAA,EAAuB,4CAAA;AAAA,EACvB,kBAAA,EAAsB,4CAAA;AAAA,EACtB,uBAAA,EAA2B,2CAAA;AAAA,EAC3B,sBAAA,EAA0B,oEAAA;AAAA,EAC1B,2BAAA,EAA+B,uDAAA;AAAA,EAC/B,0BAAA,EAA8B,0EAAA;AAAA,EAC9B,+BAAA,EAAmC,8DAAA;AAAA,EACnC,4BAAA,EAAgC,oEAAA;AAAA,EAChC,2BAAA,EAA+B,8GAAA;AAAA,EAC/B,8BAAA,EAAkC,mGAAA;AAAA,EAClC,+BAAA,EAAmC,sIAAA;AAAA,EACnC,2BAAA,EAA+B,sCAAA;AAAA,EAC/B,2BAAA,EAA+B,sCAAA;AAAA,EAC/B,+BAAA,EAAmC;AACrC,CAAA;;;ACRA,IAAM,sBAAA,GAAyB,CAAC,OAAA,EAAS,OAAA,EAAS,OAAO,CAAA;AACzD,IAAM,mBAAA,GAAsB,OAAA;AAmBrB,SAAS,oBAAoB,MAAA,EAAoC;AACtE,EAAA,MAAM,YAAY,MAAA,EAAQ,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,GAAG,IAAA,EAAK;AAC9C,EAAA,IAAI,CAAC,SAAA;AACH,IAAA,OAAO,mBAAA;AAET,EAAA,MAAM,KAAA,GAAQ,uBAAuB,IAAA,CAAK,CAAA,IAAA,KAAQ,KAAK,WAAA,EAAY,KAAM,SAAA,CAAU,WAAA,EAAa,CAAA;AAChG,EAAA,IAAI,KAAA;AACF,IAAA,OAAO,KAAA;AAET,EAAA,MAAM,eAAe,SAAA,CAAU,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,GAAG,WAAA,EAAY;AAC1D,EAAA,IAAI,YAAA,KAAiB,IAAA;AACnB,IAAA,OAAO,OAAA;AACT,EAAA,IAAI,YAAA,KAAiB,IAAA;AACnB,IAAA,OAAO,OAAA;AACT,EAAA,IAAI,YAAA,KAAiB,IAAA;AACnB,IAAA,OAAO,OAAA;AAET,EAAA,OAAO,mBAAA;AACT;AAiBO,IAAM,KAAA,GAAQ,IAAA,CAAK,IAAA,CAAK,mBAAA,CAAoC;AAAA,EACjE,OAAA,EAAS,aAAA;AAAA,EACT,OAAA,EAAS,aAAA;AAAA,EACT,OAAA,EAAS;AACX,CAAC;ACzDM,IAAM,mBAAA,GAAsB;AAa5B,IAAM,aAAA,GAAgB;AA+BtB,SAAS,eAAA,CAOd,cACA,OAAA,EAOwE;AACxE,EAAA,OAAO,OAAO,OAAA,KAAY;AACxB,IAAA,IAAI;AACF,MAAA,IAAI,CAAC,uBAAA,CAAwB,OAAA,CAAQ,OAAO,CAAA,EAAG;AAC7C,QAAA,OAAO,GAAA;AAAA,UACL,cAAA,CAAe,YAAA;AAAA,UACf,MAAM,wBAAA,EAA0B,EAAE,QAAQ,OAAA,CAAQ,OAAA,CAAQ,QAAQ;AAAA,SACpE;AAAA,MACF;AAEA,MAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,OAAA,CAAQ,OAAA;AAC5B,MAAA,IAAI,YAAA,CAAa,aAAa,MAAA,EAAQ;AACpC,QAAA,MAAM,UAAU,OAAA,CAAQ,WAAA,CAAY,SAAS,mBAAmB,CAAA,IAC3D,aAAa,WAAA,CAAY,KAAA;AAAA,UAC1B,CAAA,UAAA,KAAc,OAAA,CAAQ,WAAA,CAAY,QAAA,CAAS,UAAU;AAAA,SACvD;AACF,QAAA,IAAI,CAAC,OAAA,EAAS;AACZ,UAAA,OAAO,GAAA;AAAA,YACL,cAAA,CAAe,SAAA;AAAA,YACf,MAAM,qBAAA,EAAuB,EAAE,QAAQ,OAAA,CAAQ,OAAA,CAAQ,QAAQ;AAAA,WACjE;AAAA,QACF;AAAA,MACF;AAEA,MAAA,IAAI,YAAA,CAAa,OAAO,MAAA,EAAQ;AAC9B,QAAA,MAAM,UAAU,OAAA,CAAQ,KAAA,CAAM,SAAS,aAAa,CAAA,IAC/C,aAAa,KAAA,CAAM,KAAA;AAAA,UACpB,CAAA,IAAA,KAAQ,OAAA,CAAQ,KAAA,CAAM,QAAA,CAAS,IAAI;AAAA,SACrC;AACF,QAAA,IAAI,CAAC,OAAA,EAAS;AACZ,UAAA,OAAO,GAAA;AAAA,YACL,cAAA,CAAe,SAAA;AAAA,YACf,MAAM,qBAAA,EAAuB,EAAE,QAAQ,OAAA,CAAQ,OAAA,CAAQ,QAAQ;AAAA,WACjE;AAAA,QACF;AAAA,MACF;AAEA,MAAA,OAAO,MAAM,OAAA,CAAQ;AAAA,QACnB,GAAG,OAAA;AAAA,QACH,SAAS,OAAA,CAAQ;AAAA,OAClB,CAAA;AAAA,IACH,SACO,KAAA,EAAO;AACZ,MAAA,OAAO,GAAA;AAAA,QACL,cAAA,CAAe,cAAA;AAAA,QACf,MAAM,oBAAA,EAAsB,EAAE,QAAQ,OAAA,CAAQ,OAAA,CAAQ,QAAQ,CAAA;AAAA,QAC9D;AAAA,OACF;AAAA,IACF;AAAA,EACF,CAAA;AACF;AAEA,SAAS,wBACP,OAAA,EAC+C;AAC/C,EAAA,OAAO,OAAA,CAAQ,OAAA,KAAY,MAAA,IAAa,OAAA,CAAQ,OAAA,KAAY,IAAA;AAC9D;ACpGO,SAAS,iBAAA,CAAkB,KAAuB,OAAA,EAAiB;AACxE,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,KAAA;AAAA,IACT,KAAA,EAAO;AAAA,MACL,MAAM,GAAA,CAAI,IAAA;AAAA,MACV,SAASA,IAAAA,CAAK,KAAA,CAAM,aAAA,CAAc,EAAE,SAAS,OAAA,EAASA,IAAAA,CAAK,OAAA,CAAQ,GAAA,GAAM,OAAA,IAAWA,IAAAA,CAAK,QAAQ,GAAA,EAAI,CAAE,WAAW,CAAA;AAAA,MAClH,OAAA,EAASA,KAAK,OAAA,CAAQ,GAAA,GAAM,OAAA,IAAWA,IAAAA,CAAK,OAAA,CAAQ,GAAA,EAAI,CAAE,SAAA;AAAA,MAC1D,YAAY,GAAA,CAAI,UAAA;AAAA,MAChB,QAAQ,GAAA,CAAI,MAAA;AAAA,MACZ,QAAQ,GAAA,CAAI;AAAA;AACd,GACF;AACF;AAiBO,SAAS,YAA6B,OAAA,EAAuF;AAClI,EAAA,OAAO,OAAO,OAAA,KAAY;AACxB,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,OAAO,CAAA;AACpC,MAAA,IAAI,MAAA,CAAO,OAAA;AACT,QAAA,OAAO,MAAA;AACT,MAAA,MAAM,KAAA,GAAQA,IAAAA,CAAK,KAAA,CAAM,QAAA,CAAS,MAAA,CAAO,KAAA,EAAO,OAAA,CAAQ,OAAA,CAAQ,SAAA,EAAW,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA;AACjG,MAAA,OAAA,CAAQ,OAAA,CAAQ,MAAA,CAAO,KAAA,CAAM,kBAAA,EAAoB,EAAE,OAAA,EAAS,KAAA,CAAM,OAAA,EAAS,KAAA,EAAO,MAAA,CAAO,KAAA,EAAO,CAAA;AAChG,MAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,KAAA,EAAM;AAAA,IACjC,SACO,KAAA,EAAO;AAEZ,MAAA,MAAM,IAAA,GAAOA,IAAAA,CAAK,KAAA,CAAM,QAAA,CAAS,EAAE,GAAGC,cAAAA,CAAe,cAAA,EAAgB,OAAA,EAAS,KAAA,CAAM,oBAAA,EAAsB,EAAE,QAAQ,OAAA,CAAQ,OAAA,CAAQ,MAAA,EAAQ,CAAA,EAAE,EAAG,QAAQ,OAAA,CAAQ,SAAA,EAAW,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA;AAClM,MAAA,OAAA,CAAQ,OAAA,CAAQ,OAAO,KAAA,CAAM,8BAAA,EAAgC,EAAE,OAAA,EAAS,IAAA,CAAK,OAAA,EAAS,KAAA,EAAO,CAAA;AAC7F,MAAA,OAAOC,IAAI,IAAI,CAAA;AAAA,IACjB;AAAA,EACF,CAAA;AACF;;;AC+ZO,SAAS,UACd,QAAA,EAC4B;AAC5B,EAAA,OAAO;AAAA,IACL,SAAS,MAAoC;AAC3C,MAAA,MAAM,MAAA,GAASC,WAAA,CAAc,QAAQ,CAAA,CAAE,QAAA,EAAmB;AAC1D,MAAA,OAAO,uBAAA,CAAwB,UAAU,MAAM,CAAA;AAAA,IACjD;AAAA,GACF;AACF;AAEA,SAAS,uBAAA,CAKP,UACA,WAAA,EACgE;AAChE,EAAA,MAAM,OAAA,GAAU,IAAI,wBAAA,CAAyB,QAAA,EAAU,WAAW,CAAA;AAIlE,EAAA,OAAO,OAAA;AAKT;AAuCA,IAAM,2BAAN,MAA+B;AAAA,EAK7B,WAAA,CACE,UACiB,WAAA,EACjB;AADiB,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AAEjB,IAAA,IAAA,CAAK,aAAA,GAAgB,IAAI,GAAA,CAAI,qBAAA,CAAsB,QAAQ,CAAC,CAAA;AAC5D,IAAA,IAAA,CAAK,iBAAA,GAAoB,kBAAkB,QAAQ,CAAA;AAAA,EACrD;AAAA,EAJmB,WAAA;AAAA,EANF,aAAA;AAAA,EACA,iBAAA;AAAA,EACA,eAAA,uBAAsB,GAAA,EAAY;AAAA,EAUnD,KAAA,CAAM,MAAc,OAAA,EAA4B;AAC9C,IAAA,IAAI,OAAA,KAAY,MAAA;AACd,MAAA,OAAO,IAAA,CAAK,QAAA,CAAS,IAAA,EAAM,IAAI,OAAO,CAAA;AAExC,IAAA,OAAO,IAAI,4BAAA,CAA6B,IAAA,EAAM,IAAI,CAAA;AAAA,EACpD;AAAA,EAEA,QAAA,CAAS,IAAA,EAAc,MAAA,EAA+B,OAAA,EAAwB;AAC5E,IAAA,IAAI,CAAC,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,IAAI,CAAA;AAC9B,MAAA,MAAM,IAAI,SAAA,CAAU,CAAA,oCAAA,EAAuC,IAAI,CAAA,CAAE,CAAA;AACnE,IAAA,IAAI,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAI,CAAA;AAC/B,MAAA,MAAM,IAAI,SAAA,CAAU,CAAA,oCAAA,EAAuC,IAAI,CAAA,CAAE,CAAA;AACnE,IAAA,IAAI,OAAO,OAAA,KAAY,UAAA;AACrB,MAAA,MAAM,IAAI,SAAA,CAAU,CAAA,sCAAA,EAAyC,IAAI,CAAA,CAAE,CAAA;AAErE,IAAA,MAAM,oBAAA,GAAuB,SAAA,CAAU,IAAA,CAAK,WAAA,EAAa,IAAI,CAAA;AAC7D,IAAA,MAAM,gBAAA,GAAmB,iBAAiB,oBAAoB,CAAA;AAC9D,IAAA,IAAI,CAAC,gBAAA;AACH,MAAA,MAAM,IAAI,SAAA,CAAU,CAAA,oCAAA,EAAuC,IAAI,CAAA,CAAE,CAAA;AAInE,IAAA,MAAM,iBAAiB,SAAA,CAAU,MAAM,IACnC,eAAA,CAAgB,MAAA,EAAQ,OAA+C,CAAA,GACvE,OAAA;AACJ,IAAA,MAAM,WAAA,GAAc,YAAY,cAAc,CAAA;AAC9C,IAAA,MAAM,cAAc,OAAA,CAAQ,KAAA;AAAA,MAC1B,gBAAA;AAAA,MACA,oBAAA;AAAA,MACA,CAAC,WAAW;AAAA,KACd;AAEA,IAAA,SAAA,CAAU,IAAA,CAAK,iBAAA,EAAmB,IAAA,EAAM,WAAW,CAAA;AACnD,IAAA,IAAA,CAAK,eAAA,CAAgB,IAAI,IAAI,CAAA;AAC7B,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,KAAA,GAAiB;AACf,IAAA,MAAM,YAAA,GAAe,CAAC,GAAG,IAAA,CAAK,aAAa,CAAA,CACxC,MAAA,CAAO,CAAA,IAAA,KAAQ,CAAC,KAAK,eAAA,CAAgB,GAAA,CAAI,IAAI,CAAC,EAC9C,IAAA,EAAK;AACR,IAAA,IAAI,YAAA,CAAa,SAAS,CAAA,EAAG;AAC3B,MAAA,MAAM,IAAI,SAAA;AAAA,QACR,CAAA,yCAAA,EAA4C,YAAA,CAAa,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,OACrE;AAAA,IACF;AAEA,IAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,aAAa,QAAQ,CAAA;AAC3D,IAAA,IAAI,OAAO,YAAA,KAAiB,UAAA;AAC1B,MAAA,MAAM,IAAI,UAAU,+CAA+C,CAAA;AAErE,IAAA,OAAO,OAAA,CAAQ,MAAM,YAAA,EAAc,IAAA,CAAK,aAAa,CAAC,IAAA,CAAK,iBAAiB,CAAC,CAAA;AAAA,EAC/E;AACF,CAAA;AAEA,IAAM,+BAAN,MAAmC;AAAA,EAKjC,WAAA,CACmB,QACA,IAAA,EACjB;AAFiB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAAA,EAChB;AAAA,EAFgB,MAAA;AAAA,EACA,IAAA;AAAA,EANX,YAAA,GAAe,KAAA;AAAA,EACN,WAAA,uBAAkB,GAAA,EAAY;AAAA,EAC9B,KAAA,uBAAY,GAAA,EAAY;AAAA,EAOzC,IAAA,GAAa;AACX,IAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AACpB,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,WAAW,UAAA,EAA0B;AACnC,IAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AACpB,IAAA,IAAA,CAAK,WAAA,CAAY,IAAI,UAAU,CAAA;AAC/B,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,KAAK,IAAA,EAAoB;AACvB,IAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AACpB,IAAA,IAAA,CAAK,KAAA,CAAM,IAAI,IAAI,CAAA;AACnB,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,OAAO,OAAA,EAA4C;AACjD,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS,IAAA,CAAK,IAAA,EAAM;AAAA,MACrC,MAAM,IAAA,CAAK,YAAA;AAAA,MACX,WAAA,EAAa,CAAC,GAAG,IAAA,CAAK,WAAW,CAAA;AAAA,MACjC,KAAA,EAAO,CAAC,GAAG,IAAA,CAAK,KAAK;AAAA,OACpB,OAAO,CAAA;AAAA,EACZ;AACF,CAAA;AAEA,SAAS,UAAU,MAAA,EAAwC;AACzD,EAAA,OAAO,MAAA,CAAO,IAAA,KAAS,IAAA,IAAA,CACjB,MAAA,CAAO,WAAA,EAAa,MAAA,IAAU,CAAA,IAAK,CAAA,IAAA,CACnC,MAAA,CAAO,KAAA,EAAO,MAAA,IAAU,CAAA,IAAK,CAAA;AACrC;AAEA,SAAS,qBAAA,CACP,QAAA,EACA,MAAA,GAA4B,EAAC,EACnB;AACV,EAAA,IAAI,oBAAoB,QAAQ,CAAA;AAC9B,IAAA,OAAO,MAAA,CAAO,SAAS,CAAA,GAAI,CAAC,OAAO,IAAA,CAAK,GAAG,CAAC,CAAA,GAAI,EAAC;AAEnD,EAAA,OAAO,OAAO,OAAA,CAAQ,QAAQ,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAC,GAAA,EAAK,KAAK,CAAA,KAClD,sBAAsB,KAAA,EAAO,CAAC,GAAG,MAAA,EAAQ,GAAG,CAAC,CAAC,CAAA;AAClD;AAEA,SAAS,oBAAoB,QAAA,EAAiC;AAC5D,EAAA,OAAO,OAAA,IAAW,QAAA;AACpB;AAEA,SAAS,kBAAkB,QAAA,EAAiD;AAC1E,EAAA,MAAM,KAAA,mBAAiC,MAAA,CAAO,MAAA,CAAO,IAAI,CAAA;AAEzD,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,QAAQ,CAAA,EAAG;AACnD,IAAA,IAAI,CAAC,oBAAoB,KAAK,CAAA;AAC5B,MAAA,KAAA,CAAM,GAAG,CAAA,GAAI,iBAAA,CAAkB,KAAK,CAAA;AAAA,EACxC;AAEA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,SAAA,CAAU,MAAc,IAAA,EAAuB;AACtD,EAAA,IAAI,OAAA,GAAmB,IAAA;AAEvB,EAAA,KAAA,MAAW,OAAA,IAAW,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,EAAG;AACrC,IAAA,IACG,OAAO,OAAA,KAAY,QAAA,IAAY,OAAO,OAAA,KAAY,cAChD,OAAA,KAAY,IAAA,IACZ,EAAE,OAAA,IAAW,OAAA,CAAA,EAChB;AACA,MAAA,OAAO,MAAA;AAAA,IACT;AAEA,IAAA,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAI,OAAA,EAAS,OAAO,CAAA;AAAA,EACxC;AAEA,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,SAAA,CAAU,IAAA,EAA+B,IAAA,EAAc,KAAA,EAAsB;AACpF,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC/B,EAAA,MAAM,IAAA,GAAO,SAAS,GAAA,EAAI;AAC1B,EAAA,IAAI,CAAC,IAAA;AACH,IAAA,MAAM,IAAI,UAAU,gCAAgC,CAAA;AAEtD,EAAA,IAAI,OAAA,GAAU,IAAA;AACd,EAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,IAAA,MAAM,QAAA,GAAW,QAAQ,OAAO,CAAA;AAChC,IAAA,IAAI,aAAa,MAAA,EAAW;AAC1B,MAAA,MAAM,KAAA,mBAAiC,MAAA,CAAO,MAAA,CAAO,IAAI,CAAA;AACzD,MAAA,OAAA,CAAQ,OAAO,CAAA,GAAI,KAAA;AACnB,MAAA,OAAA,GAAU,KAAA;AACV,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,CAAC,QAAA,IAAY,OAAO,QAAA,KAAa,QAAA;AACnC,MAAA,MAAM,IAAI,SAAA,CAAU,CAAA,iDAAA,EAAoD,IAAI,CAAA,CAAE,CAAA;AAEhF,IAAA,OAAA,GAAU,QAAA;AAAA,EACZ;AAEA,EAAA,OAAA,CAAQ,IAAI,CAAA,GAAI,KAAA;AAClB;AAEA,SAAS,iBAAiB,KAAA,EAA6D;AACrF,EAAA,IAAK,OAAO,KAAA,KAAU,QAAA,IAAY,OAAO,KAAA,KAAU,cAAe,KAAA,KAAU,IAAA;AAC1E,IAAA,OAAO,MAAA;AAET,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAI,KAAA,EAAO,SAAS,CAAA;AAC5C,EAAA,OAAO,OAAO,OAAA,KAAY,UAAA,GACtB,OAAA,GACA,MAAA;AACN","file":"chunk-KR4H56KP.js","sourcesContent":["{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"serv_validationFailed\": \"Validation failed\",\n \"serv_validationRequired\": \"This field is required\",\n \"serv_validationInvalid\": \"Invalid input format\",\n \"serv_validationInvalidType\": \"Invalid field type\",\n \"serv_validationStringMin\": \"Enter at least {min} characters\",\n \"serv_validationStringMax\": \"Enter at most {max} UTF-8 bytes\",\n \"serv_validationNumberMin\": \"Value must be at least {min}\",\n \"serv_validationNumberMax\": \"Value must be at most {max}\",\n \"serv_validationArrayMin\": \"Select at least {min} item(s)\",\n \"serv_validationArrayMax\": \"Select at most {max} item(s)\",\n \"serv_validationTooSmall\": \"Value must be at least {min}\",\n \"serv_validationTooBig\": \"Value must be at most {max}\",\n \"serv_validationEmail\": \"Enter a valid email address\",\n \"serv_validationUrl\": \"Enter a valid URL\",\n \"serv_validationUuid\": \"Enter a valid UUID\",\n \"serv_validationEnum\": \"Select a valid option\",\n \"serv_errorUnauthorized\": \"Unauthorized\",\n \"serv_errorForbidden\": \"Forbidden\",\n \"serv_errorInternal\": \"Internal server error\",\n \"serv_storageKeyRequired\": \"Storage key must not be empty\",\n \"serv_storageKeyTooLong\": \"Storage key must not exceed {max} characters\",\n \"serv_storageKeyIllegalChars\": \"Storage key contains illegal characters\",\n \"serv_storageKeyDotSegments\": \"Storage key must not contain . or .. path segments\",\n \"serv_iamCannotDeleteCurrentUser\": \"Cannot delete the current logged-in user\",\n \"serv_transportInvalidPayload\": \"Invalid encrypted transport payload\",\n \"serv_transportUnknownClient\": \"Unknown encryption client; key exchange required\",\n \"serv_transportClientIdRequired\": \"Missing X-Client-Id header; key exchange required\",\n \"serv_transportClientKeyNotFound\": \"Client not registered or session expired; complete key exchange again\",\n \"serv_transportDecryptFailed\": \"Failed to decrypt request\",\n \"serv_transportEncryptFailed\": \"Failed to encrypt response\",\n \"serv_transportKeyExchangeFailed\": \"Key exchange failed\"\n}\n","{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"serv_validationFailed\": \"入力内容の検証に失敗しました\",\n \"serv_validationRequired\": \"この項目は必須です\",\n \"serv_validationInvalid\": \"入力形式が無効です\",\n \"serv_validationInvalidType\": \"フィールドの型が無効です\",\n \"serv_validationStringMin\": \"{min}文字以上で入力してください\",\n \"serv_validationStringMax\": \"UTF-8 で {max} バイト以内で入力してください\",\n \"serv_validationNumberMin\": \"{min}以上の値を入力してください\",\n \"serv_validationNumberMax\": \"{max}以下の値を入力してください\",\n \"serv_validationArrayMin\": \"{min}件以上選択してください\",\n \"serv_validationArrayMax\": \"{max}件以内で選択してください\",\n \"serv_validationTooSmall\": \"{min}以上の値を入力してください\",\n \"serv_validationTooBig\": \"{max}以下の値を入力してください\",\n \"serv_validationEmail\": \"有効なメールアドレスを入力してください\",\n \"serv_validationUrl\": \"有効なURLを入力してください\",\n \"serv_validationUuid\": \"有効なUUIDを入力してください\",\n \"serv_validationEnum\": \"有効な選択肢を選んでください\",\n \"serv_errorUnauthorized\": \"認証されていません\",\n \"serv_errorForbidden\": \"アクセスが拒否されました\",\n \"serv_errorInternal\": \"サーバー内部エラー\",\n \"serv_storageKeyRequired\": \"ストレージキーを空にすることはできません\",\n \"serv_storageKeyTooLong\": \"ストレージキーは{max}文字以内で指定してください\",\n \"serv_storageKeyIllegalChars\": \"ストレージキーに無効な文字が含まれています\",\n \"serv_storageKeyDotSegments\": \"ストレージキーに「.」や「..」のパス要素を含めることはできません\",\n \"serv_iamCannotDeleteCurrentUser\": \"現在ログイン中のユーザーは削除できません\",\n \"serv_transportInvalidPayload\": \"暗号化された通信ペイロードが無効です\",\n \"serv_transportUnknownClient\": \"暗号化クライアントが不明です。鍵交換が必要です\",\n \"serv_transportClientIdRequired\": \"X-Client-Idヘッダーがありません。鍵交換が必要です\",\n \"serv_transportClientKeyNotFound\": \"クライアントが未登録か、セッションの有効期限が切れています。再度鍵交換を行ってください\",\n \"serv_transportDecryptFailed\": \"リクエストの復号に失敗しました\",\n \"serv_transportEncryptFailed\": \"レスポンスの暗号化に失敗しました\",\n \"serv_transportKeyExchangeFailed\": \"鍵交換に失敗しました\"\n}\n","{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"serv_validationFailed\": \"数据验证失败\",\n \"serv_validationRequired\": \"此字段必填\",\n \"serv_validationInvalid\": \"输入格式无效\",\n \"serv_validationInvalidType\": \"字段类型不正确\",\n \"serv_validationStringMin\": \"至少输入 {min} 个字符\",\n \"serv_validationStringMax\": \"最多输入 {max} 个 UTF-8 字节\",\n \"serv_validationNumberMin\": \"数值不能小于 {min}\",\n \"serv_validationNumberMax\": \"数值不能大于 {max}\",\n \"serv_validationArrayMin\": \"至少选择 {min} 项\",\n \"serv_validationArrayMax\": \"最多选择 {max} 项\",\n \"serv_validationTooSmall\": \"不能小于 {min}\",\n \"serv_validationTooBig\": \"不能大于 {max}\",\n \"serv_validationEmail\": \"请输入有效的邮箱地址\",\n \"serv_validationUrl\": \"请输入有效的网址\",\n \"serv_validationUuid\": \"请输入有效的 UUID\",\n \"serv_validationEnum\": \"请选择有效选项\",\n \"serv_errorUnauthorized\": \"未登录或登录已失效\",\n \"serv_errorForbidden\": \"无权执行该操作\",\n \"serv_errorInternal\": \"服务器内部错误\",\n \"serv_storageKeyRequired\": \"存储 key 不能为空\",\n \"serv_storageKeyTooLong\": \"存储 key 不能超过 {max} 个字符\",\n \"serv_storageKeyIllegalChars\": \"存储 key 包含非法字符\",\n \"serv_storageKeyDotSegments\": \"存储 key 不能包含 . 或 .. 路径段\",\n \"serv_iamCannotDeleteCurrentUser\": \"不能删除当前登录用户\",\n \"serv_transportInvalidPayload\": \"传输层加密载荷格式无效\",\n \"serv_transportUnknownClient\": \"未识别的加密客户端,请先完成密钥协商\",\n \"serv_transportClientIdRequired\": \"缺少 X-Client-Id 请求头,请先完成密钥协商\",\n \"serv_transportClientKeyNotFound\": \"客户端未注册或会话已过期,请重新完成密钥协商\",\n \"serv_transportDecryptFailed\": \"请求解密失败\",\n \"serv_transportEncryptFailed\": \"响应加密失败\",\n \"serv_transportKeyExchangeFailed\": \"密钥协商失败\"\n}\n","/**\n * @h-ai/serv — i18n 工具\n *\n * Serv 模块的国际化消息工具,从 @h-ai/core 调用 i18n API。\n * 与 kit-i18n 结构对齐,便于跨包统一维护。\n * @module serv-i18n\n */\n\nimport { core } from '@h-ai/core'\nimport messagesEnUS from '../messages/en-US.json'\nimport messagesJaJP from '../messages/ja-JP.json'\nimport messagesZhCN from '../messages/zh-CN.json'\n\n/**\n * Serv 本地化消息的真实 key 联合。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const key: ServMessageKey = 'serv_errorForbidden'\n * const message = servM(key, { locale: 'en-US' })\n * ```\n */\ntype ServMessageKey = keyof typeof messagesZhCN\n\nconst SUPPORTED_SERV_LOCALES = ['zh-CN', 'en-US', 'ja-JP'] as const\nconst DEFAULT_SERV_LOCALE = 'zh-CN'\n\n/**\n * 规范化 serv 请求 locale。\n *\n * 支持:\n * - 完整 locale:`zh-CN` / `en-US` / `ja-JP`\n * - 简写:`zh` / `en` / `ja`\n * - `Accept-Language` 风格值:`en-US,en;q=0.9`\n *\n * 未识别时回退到默认 `zh-CN`。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const english = normalizeServLocale('en-US,en;q=0.9')\n * const fallback = normalizeServLocale(undefined)\n * ```\n */\nexport function normalizeServLocale(locale: string | undefined): string {\n const candidate = locale?.split(',')[0]?.trim()\n if (!candidate)\n return DEFAULT_SERV_LOCALE\n\n const exact = SUPPORTED_SERV_LOCALES.find(item => item.toLowerCase() === candidate.toLowerCase())\n if (exact)\n return exact\n\n const baseLanguage = candidate.split('-')[0]?.toLowerCase()\n if (baseLanguage === 'en')\n return 'en-US'\n if (baseLanguage === 'ja')\n return 'ja-JP'\n if (baseLanguage === 'zh')\n return 'zh-CN'\n\n return DEFAULT_SERV_LOCALE\n}\n\n/**\n * 获取 Serv 模块的 i18n 消息。\n *\n * 单次调用可通过 `options.locale` 指定该次调用使用的语言,\n * 用于在请求处理过程中根据 `Accept-Language` 头本地化错误消息,\n * 而不污染全局 locale(多并发请求安全)。\n *\n * @example\n * ```ts\n * import { serv } from '@h-ai/serv'\n *\n * const message = serv.m('serv_validationStringMin', { locale: 'en-US', params: { min: 3 } })\n * // 单次 locale 不修改并发请求的全局语言。\n * ```\n */\nexport const servM = core.i18n.createMessageGetter<ServMessageKey>({\n 'zh-CN': messagesZhCN,\n 'en-US': messagesEnUS,\n 'ja-JP': messagesJaJP,\n})\n\nexport type { ServMessageKey }\n","/**\n * @h-ai/serv — procedure 认证与授权 guard\n *\n * 将认证、权限、角色及异常映射合并为单个 handler 包装层,并在类型上把\n * `context.session` 收窄为非空。\n *\n * @module pipelines/serv-pipeline-guard\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ErrorMap, Meta, ProcedureHandler } from '@orpc/server'\nimport type { ServContext } from '../serv-context.js'\nimport type { AuthenticatedServContext } from '../serv-router.js'\nimport { err, HaiCommonError } from '@h-ai/core'\nimport { servM } from '../serv-i18n.js'\n\n/**\n * 通配符权限。仅应授予受信任的超级管理员,可通过任意 permission guard。\n *\n * @example\n * ```ts\n * import { serv } from '@h-ai/serv'\n *\n * const wildcard = serv.WILDCARD_PERMISSION\n * // 仅可信超级管理员可拥有通配符 permissions;普通用户使用明确能力列表。\n * ```\n */\nexport const WILDCARD_PERMISSION = '*'\n\n/**\n * 通配符角色。仅应授予受信任的超级管理员,可通过任意 role guard。\n *\n * @example\n * ```ts\n * import { serv } from '@h-ai/serv'\n *\n * const wildcard = serv.WILDCARD_ROLE\n * // 仅可信超级管理员可拥有通配符 roles;普通用户使用明确能力列表。\n * ```\n */\nexport const WILDCARD_ROLE = '*'\n\n/**\n * 内部 route guard 要求;权限/角色检查以可信非空会话为前提。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const requirements: ServGuardRequirements = { auth: true, permissions: ['reports.read'] }\n * const guarded = applyServGuards(requirements, ({ context }) => ({ success: true, data: { userId: context.session.userId } }))\n * ```\n */\nexport interface ServGuardRequirements {\n readonly auth?: boolean\n readonly permissions?: readonly string[]\n readonly roles?: readonly string[]\n}\n\n/**\n * 将 guard 应用于一个使用 HaiResult 输出的 oRPC handler。\n *\n * 完整保留 oRPC 的 `path`、`procedure`、`signal`、`lastEventId`、`errors` 等\n * options;只在校验成功后把 `context` 收窄为带非空 session 的类型。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const guarded = applyServGuards({ permissions: ['reports.read'] }, ({ context }) => ({ success: true, data: { userId: context.session.userId } }))\n * // 业务 handler 只在可信 session 满足全部权限后执行。\n * ```\n */\nexport function applyServGuards<\n TContext extends ServContext,\n TInput,\n TData,\n TErrorMap extends ErrorMap,\n TMeta extends Meta,\n>(\n requirements: ServGuardRequirements,\n handler: ProcedureHandler<\n AuthenticatedServContext<TContext>,\n TInput,\n HaiResult<TData>,\n TErrorMap,\n TMeta\n >,\n): ProcedureHandler<TContext, TInput, HaiResult<TData>, TErrorMap, TMeta> {\n return async (options) => {\n try {\n if (!hasAuthenticatedSession(options.context)) {\n return err(\n HaiCommonError.UNAUTHORIZED,\n servM('serv_errorUnauthorized', { locale: options.context.locale }),\n )\n }\n\n const { session } = options.context\n if (requirements.permissions?.length) {\n const allowed = session.permissions.includes(WILDCARD_PERMISSION)\n || requirements.permissions.every(\n permission => session.permissions.includes(permission),\n )\n if (!allowed) {\n return err(\n HaiCommonError.FORBIDDEN,\n servM('serv_errorForbidden', { locale: options.context.locale }),\n )\n }\n }\n\n if (requirements.roles?.length) {\n const allowed = session.roles.includes(WILDCARD_ROLE)\n || requirements.roles.every(\n role => session.roles.includes(role),\n )\n if (!allowed) {\n return err(\n HaiCommonError.FORBIDDEN,\n servM('serv_errorForbidden', { locale: options.context.locale }),\n )\n }\n }\n\n return await handler({\n ...options,\n context: options.context,\n })\n }\n catch (error) {\n return err(\n HaiCommonError.INTERNAL_ERROR,\n servM('serv_errorInternal', { locale: options.context.locale }),\n error,\n )\n }\n }\n}\n\nfunction hasAuthenticatedSession<TContext extends ServContext>(\n context: TContext,\n): context is AuthenticatedServContext<TContext> {\n return context.session !== undefined && context.session !== null\n}\n","/**\n * @h-ai/serv — Pipeline 公共 helper\n *\n * 放置不属于 Hono middleware / route guard 默认实现本身、\n * 但会被多个 pipeline 复用的公共工具。\n * @module pipelines/serv-pipeline-helper\n */\n\nimport type { ServProcedureHandler } from './serv-pipeline-types.js'\nimport { core, err, HaiCommonError } from '@h-ai/core'\nimport { servM } from '../serv-i18n.js'\n\n/**\n * 构造 `HaiResult` 失败分支同构的 HTTP 错误定义。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const definition: ServErrorBodyDef = HaiCommonError.UNAUTHORIZED\n * const body = buildHaiErrorBody(definition, servM('serv_errorUnauthorized'))\n * ```\n */\nexport interface ServErrorBodyDef {\n readonly code: string | number\n readonly httpStatus: number\n readonly system: string\n readonly module: string\n}\n\n/**\n * 构造与 `HaiResult` 失败分支同构的 HTTP 响应体。\n *\n * - 字段顺序与 `haiResultSchema()` 输出一致,便于客户端统一解析。\n * - 仅暴露最小信息(code/message/httpStatus),避免泄漏内部细节。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const body = buildHaiErrorBody(HaiCommonError.FORBIDDEN, servM('serv_errorForbidden'))\n * // HTTP middleware 再设置 status;body 只包含安全的领域错误字段。\n * ```\n */\nexport function buildHaiErrorBody(def: ServErrorBodyDef, message: string) {\n return {\n success: false as const,\n error: {\n code: def.code,\n message: core.error.formatMessage({ message, traceId: core.context.get().traceId ?? core.context.get().requestId }),\n traceId: core.context.get().traceId ?? core.context.get().requestId,\n httpStatus: def.httpStatus,\n system: def.system,\n module: def.module,\n },\n }\n}\n\n/**\n * 捕获未处理异常并转换为 HaiResult。\n *\n * 由 contract router 在注册 handler 时统一应用,业务代码无需手动包装。\n *\n * @param handler - 被包装的 procedure handler\n * @returns 带异常保护的新 handler\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const wrapped = mapHaiError<{ id: string }, { id: string }>(async ({ input }) => ({ success: true, data: { id: input.id } }))\n * // oRPC 原始 options 原样传入;未处理异常在此转换为领域错误。\n * ```\n */\nexport function mapHaiError<TInput, TOutput>(handler: ServProcedureHandler<TInput, TOutput>): ServProcedureHandler<TInput, TOutput> {\n return async (options) => {\n try {\n const result = await handler(options)\n if (result.success)\n return result\n const error = core.error.toPublic(result.error, options.context.requestId, options.context.locale)\n options.context.logger.error('Procedure failed', { traceId: error.traceId, error: result.error })\n return { success: false, error }\n }\n catch (error) {\n // 所有未捕获异常统一在这里收口,避免直接把异常冒泡到 HTTP 层。\n const safe = core.error.toPublic({ ...HaiCommonError.INTERNAL_ERROR, message: servM('serv_errorInternal', { locale: options.context.locale }) }, options.context.requestId, options.context.locale)\n options.context.logger.error('Procedure threw an exception', { traceId: safe.traceId, error })\n return err(safe)\n }\n }\n}\n","/**\n * @h-ai/serv — contract-first 链式 procedure 实现器\n *\n * 在 oRPC `implement()` 之上提供 route 名只出现一次的链式 DSL。\n * 应用只接触 contract 路径、上下文与 guard,不需要组装 oRPC router 对象。\n *\n * @module serv-router\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type {\n Context,\n ContractProcedure,\n ContractRouter,\n ErrorMap,\n Implementer,\n InferSchemaInput,\n InferSchemaOutput,\n Meta,\n ProcedureHandler,\n Router,\n UnlaziedRouter,\n} from '@orpc/server'\nimport type { ServGuardRequirements } from './pipelines/serv-pipeline-guard.js'\nimport type { ServContext } from './serv-context.js'\nimport { implement as orpcImplement } from '@orpc/server'\nimport { applyServGuards } from './pipelines/serv-pipeline-guard.js'\nimport { mapHaiError } from './pipelines/serv-pipeline-helper.js'\n\n/**\n * 内部初始 context 空约束,用于保持 oRPC 推导而不伪造运行时字段。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const { serv } = await import('@h-ai/serv')\n * const context: ServContext & EmptyContext = serv.parseRequestContext({ request: new Request('https://example.com/ping') })\n * const requestId = context.requestId\n * ```\n */\ntype EmptyContext = Record<never, never>\n/**\n * 提取 contract 的字符串键,排除 symbol/数字索引。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const { apiContract } = await import('@h-ai/api-contract')\n * const { z } = await import('zod')\n * const { ok } = await import('@h-ai/core')\n * const contract = { ping: apiContract.route({ method: 'GET', path: '/ping' }).output(apiContract.haiResultSchema(z.object({ ready: z.boolean() }))) }\n * const path: StringKey<typeof contract> = 'ping'\n * const procedure = contract[path]\n * ```\n */\ntype StringKey<T> = Extract<keyof T, string>\n/**\n * 内部 contract 泛型边界;真实 procedure 输出须为 HaiResult。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const { apiContract } = await import('@h-ai/api-contract')\n * const { z } = await import('zod')\n * const { ok } = await import('@h-ai/core')\n * const contract = { ping: apiContract.route({ method: 'GET', path: '/ping' }).output(apiContract.haiResultSchema(z.object({ ready: z.boolean() }))) }\n * const checked = contract satisfies ServContract\n * const procedures = implement(checked).context<ServContext>().route('ping', () => ok({ ready: true })).build()\n * ```\n */\ntype ServContract = ContractRouter<Meta>\n\n/**\n * contract 中所有 procedure 的点分路径。\n *\n * @example\n * ```ts\n * import type { ServRoutePath } from '@h-ai/serv'\n * import type { ServContext } from '@h-ai/serv'\n * import { apiContract } from '@h-ai/api-contract'\n * import { ok } from '@h-ai/core'\n * import { serv } from '@h-ai/serv'\n * import { z } from 'zod'\n *\n * const contract = { ping: apiContract.route({ method: 'GET', path: '/ping' }).output(apiContract.haiResultSchema(z.object({ ready: z.boolean() }))) }\n * const path: ServRoutePath<typeof contract> = 'ping'\n * const procedures = serv.implement(contract).context<ServContext>().route(path, () => ok({ ready: true })).build()\n * ```\n */\nexport type ServRoutePath<TContract extends ServContract>\n = TContract extends ContractProcedure<\n infer _TInputSchema,\n infer _TOutputSchema,\n infer _TErrorMap,\n infer _TMeta\n >\n ? never\n : {\n [K in StringKey<TContract>]: TContract[K] extends ContractProcedure<\n infer _TChildInputSchema,\n infer _TChildOutputSchema,\n infer _TChildErrorMap,\n infer _TChildMeta\n >\n ? K\n : TContract[K] extends ServContract\n ? ServRoutePath<TContract[K]> extends infer TChild extends string\n ? `${K}.${TChild}`\n : never\n : never\n }[StringKey<TContract>]\n\n/**\n * 按点分路径查找原始 contract procedure;不存在的路径推导为 never。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const { apiContract } = await import('@h-ai/api-contract')\n * const { z } = await import('zod')\n * const { ok } = await import('@h-ai/core')\n * const contract = { ping: apiContract.route({ method: 'GET', path: '/ping' }).output(apiContract.haiResultSchema(z.object({ ready: z.boolean() }))) }\n * const procedure: ContractAtPath<typeof contract, 'ping'> = contract.ping\n * const scoped = implement({ ping: procedure }).context<ServContext>().route('ping', () => ok({ ready: true })).build()\n * ```\n */\ntype ContractAtPath<TContract, TPath extends string>\n = TPath extends `${infer THead}.${infer TTail}`\n ? THead extends keyof TContract\n ? ContractAtPath<TContract[THead], TTail>\n : never\n : TPath extends keyof TContract\n ? TContract[TPath]\n : never\n\n/**\n * 将合法路由路径映射到对应 contract,供 handler 推导复用。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const { apiContract } = await import('@h-ai/api-contract')\n * const { z } = await import('zod')\n * const { ok } = await import('@h-ai/core')\n * const contract = { ping: apiContract.route({ method: 'GET', path: '/ping' }).output(apiContract.haiResultSchema(z.object({ ready: z.boolean() }))) }\n * const procedure: RouteContract<typeof contract, 'ping'> = contract.ping\n * const scoped = implement({ ping: procedure }).context<ServContext>().route('ping', () => ok({ ready: true })).build()\n * ```\n */\ntype RouteContract<\n TContract extends ServContract,\n TPath extends ServRoutePath<TContract>,\n> = ContractAtPath<TContract, TPath>\n\n/**\n * `.auth()`、`.permission()`、`.role()` 后的非空会话上下文。\n *\n * @example\n * ```ts\n * import type { AuthenticatedServContext } from '@h-ai/serv'\n *\n * function owner(context: AuthenticatedServContext): string {\n * return context.session.userId\n * }\n * // 仅成功 guard 或可信认证结果能建立此上下文,禁止用客户端字段断言。\n * ```\n */\nexport type AuthenticatedServContext<TContext extends ServContext = ServContext>\n = TContext & {\n readonly session: NonNullable<TContext['session']>\n }\n\n/**\n * 内部从具体 procedure 的输入/输出与 context 推导 HaiResult handler。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const { apiContract } = await import('@h-ai/api-contract')\n * const { z } = await import('zod')\n * const { ok } = await import('@h-ai/core')\n * const contract = { ping: apiContract.route({ method: 'GET', path: '/ping' }).output(apiContract.haiResultSchema(z.object({ ready: z.boolean() }))) }\n * const handler: RouteHandler<typeof contract.ping, ServContext> = () => ok({ ready: true })\n * const procedures = implement(contract).context<ServContext>().route('ping', handler).build()\n * ```\n */\ntype RouteHandler<\n TRouteContract,\n TContext extends Context,\n> = TRouteContract extends ContractProcedure<\n infer TInputSchema,\n infer TOutputSchema,\n infer TErrorMap,\n infer TMeta\n>\n ? InferSchemaInput<TOutputSchema> extends HaiResult<unknown>\n ? ProcedureHandler<\n TContext,\n InferSchemaOutput<TInputSchema>,\n InferSchemaInput<TOutputSchema>,\n TErrorMap,\n TMeta\n >\n : never\n : never\n\n/**\n * 从 contract procedure 精确推导当前 route 的 HaiResult handler。\n *\n * @example\n * ```ts\n * import type { ServRouteHandler } from '@h-ai/serv'\n * import type { ServContext } from '@h-ai/serv'\n * import { apiContract } from '@h-ai/api-contract'\n * import { ok } from '@h-ai/core'\n * import { serv } from '@h-ai/serv'\n * import { z } from 'zod'\n *\n * const contract = { ping: apiContract.route({ method: 'GET', path: '/ping' }).output(apiContract.haiResultSchema(z.object({ ready: z.boolean() }))) }\n * const handler: ServRouteHandler<typeof contract, 'ping', ServContext> = () => ok({ ready: true })\n * const procedures = serv.implement(contract).context<ServContext>().route('ping', handler).build()\n * ```\n */\nexport type ServRouteHandler<\n TContract extends ServContract,\n TPath extends ServRoutePath<TContract>,\n TContext extends Context,\n> = RouteHandler<RouteContract<TContract, TPath>, TContext>\n\n/**\n * 内部认证成功 handler 类型;session 在 guard 之后非空。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const { apiContract } = await import('@h-ai/api-contract')\n * const { z } = await import('zod')\n * const { ok } = await import('@h-ai/core')\n * const contract = { ping: apiContract.route({ method: 'GET', path: '/ping' }).output(apiContract.haiResultSchema(z.object({ ready: z.boolean() }))) }\n * const handler: ServGuardedRouteHandler<typeof contract, 'ping', ServContext> = ({ context }) => ok({ ready: context.session.userId.length > 0 })\n * const procedures = implement(contract).context<ServContext>().route('ping').auth().handle(handler).build()\n * ```\n */\ntype ServGuardedRouteHandler<\n TContract extends ServContract,\n TPath extends ServRoutePath<TContract>,\n TContext extends ServContext,\n> = RouteHandler<RouteContract<TContract, TPath>, AuthenticatedServContext<TContext>>\n\n/**\n * 一次注册后移除该路径的 builder;全部路径完成才提供 build。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const { apiContract } = await import('@h-ai/api-contract')\n * const { z } = await import('zod')\n * const { ok } = await import('@h-ai/core')\n * const contract = { ping: apiContract.route({ method: 'GET', path: '/ping' }).output(apiContract.haiResultSchema(z.object({ ready: z.boolean() }))) }\n * const next: NextBuilder<typeof contract, ServContext, ServContext, 'ping', 'ping'> = implement(contract).context<ServContext>().route('ping', () => ok({ ready: true }))\n * const procedures = next.build()\n * ```\n */\ntype NextBuilder<\n TContract extends ServContract,\n TInitialContext extends Context,\n TCurrentContext extends ServContext,\n TRemaining extends ServRoutePath<TContract>,\n TPath extends TRemaining,\n> = ServRouterBuilder<\n TContract,\n TInitialContext,\n TCurrentContext,\n Exclude<TRemaining, TPath>\n>\n\n/**\n * 尚未声明 guard 的单 route 注册器。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const { apiContract } = await import('@h-ai/api-contract')\n * const { z } = await import('zod')\n * const { ok } = await import('@h-ai/core')\n * const contract = { ping: apiContract.route({ method: 'GET', path: '/ping' }).output(apiContract.haiResultSchema(z.object({ ready: z.boolean() }))) }\n * const route: ServRouteRegistration<typeof contract, ServContext, ServContext, 'ping', 'ping'> = implement(contract).context<ServContext>().route('ping')\n * const procedures = route.auth().handle(() => ok({ ready: true })).build()\n * ```\n */\nexport interface ServRouteRegistration<\n TContract extends ServContract,\n TInitialContext extends Context,\n TCurrentContext extends ServContext,\n TRemaining extends ServRoutePath<TContract>,\n TPath extends TRemaining,\n> {\n readonly auth: () => ServGuardedRouteRegistration<\n TContract,\n TInitialContext,\n TCurrentContext,\n TRemaining,\n TPath\n >\n readonly permission: (permission: string) => ServGuardedRouteRegistration<\n TContract,\n TInitialContext,\n TCurrentContext,\n TRemaining,\n TPath\n >\n readonly role: (role: string) => ServGuardedRouteRegistration<\n TContract,\n TInitialContext,\n TCurrentContext,\n TRemaining,\n TPath\n >\n}\n\n/**\n * 已声明认证或授权 guard 的单 route 注册器。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const { apiContract } = await import('@h-ai/api-contract')\n * const { z } = await import('zod')\n * const { ok } = await import('@h-ai/core')\n * const contract = { ping: apiContract.route({ method: 'GET', path: '/ping' }).output(apiContract.haiResultSchema(z.object({ ready: z.boolean() }))) }\n * const guarded: ServGuardedRouteRegistration<typeof contract, ServContext, ServContext, 'ping', 'ping'> = implement(contract).context<ServContext>().route('ping').permission('reports.read')\n * const procedures = guarded.handle(() => ok({ ready: true })).build()\n * ```\n */\nexport interface ServGuardedRouteRegistration<\n TContract extends ServContract,\n TInitialContext extends Context,\n TCurrentContext extends ServContext,\n TRemaining extends ServRoutePath<TContract>,\n TPath extends TRemaining,\n> {\n readonly auth: () => ServGuardedRouteRegistration<\n TContract,\n TInitialContext,\n TCurrentContext,\n TRemaining,\n TPath\n >\n readonly permission: (permission: string) => ServGuardedRouteRegistration<\n TContract,\n TInitialContext,\n TCurrentContext,\n TRemaining,\n TPath\n >\n readonly role: (role: string) => ServGuardedRouteRegistration<\n TContract,\n TInitialContext,\n TCurrentContext,\n TRemaining,\n TPath\n >\n readonly handle: (\n handler: ServGuardedRouteHandler<TContract, TPath, TCurrentContext>,\n ) => NextBuilder<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>\n}\n\n/**\n * 内部 route 重载:直接 handler 或先声明 guard,再收窄剩余路径。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const { apiContract } = await import('@h-ai/api-contract')\n * const { z } = await import('zod')\n * const { ok } = await import('@h-ai/core')\n * const contract = { ping: apiContract.route({ method: 'GET', path: '/ping' }).output(apiContract.haiResultSchema(z.object({ ready: z.boolean() }))) }\n * const route: ServRouteMethod<typeof contract, ServContext, ServContext, 'ping'> = implement(contract).context<ServContext>().route\n * const procedures = route('ping', () => ok({ ready: true })).build()\n * ```\n */\ninterface ServRouteMethod<\n TContract extends ServContract,\n TInitialContext extends Context,\n TCurrentContext extends ServContext,\n TRemaining extends ServRoutePath<TContract>,\n> {\n <TPath extends TRemaining>(\n path: TPath,\n handler: ServRouteHandler<TContract, TPath, TCurrentContext>,\n ): NextBuilder<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>\n <TPath extends TRemaining>(\n path: TPath,\n ): ServRouteRegistration<\n TContract,\n TInitialContext,\n TCurrentContext,\n TRemaining,\n TPath\n >\n}\n\n/**\n * 剩余路径为 never 时才暴露 build,否则仅提供缺失路径类型提示。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const { apiContract } = await import('@h-ai/api-contract')\n * const { z } = await import('zod')\n * const { ok } = await import('@h-ai/core')\n * const contract = { ping: apiContract.route({ method: 'GET', path: '/ping' }).output(apiContract.haiResultSchema(z.object({ ready: z.boolean() }))) }\n * const complete: ServRouterBuilderBuild<typeof contract, ServContext, never> = implement(contract).context<ServContext>().route('ping', () => ok({ ready: true }))\n * const procedures = complete.build()\n * ```\n */\ntype ServRouterBuilderBuild<\n TContract extends ServContract,\n TInitialContext extends Context,\n TRemaining,\n> = [TRemaining] extends [never]\n ? {\n /** 同步返回完整的普通 router,允许按需选用嵌套的默认 procedures。 */\n readonly build: () => UnlaziedRouter<Router<TContract, TInitialContext>>\n }\n : {\n /** 仅供 TypeScript/IDE 展示尚未实现的 route;运行时不存在。 */\n readonly missingRoutes: TRemaining\n }\n\n/**\n * 链式 router builder。\n *\n * `TRemaining` 会随着 `.route()` 注册逐步收窄;未实现完整 contract 时没有 `.build()`。\n *\n * @example\n * ```ts\n * import type { ServRouterBuilder } from '@h-ai/serv'\n * import type { ServContext } from '@h-ai/serv'\n * import { apiContract } from '@h-ai/api-contract'\n * import { ok } from '@h-ai/core'\n * import { serv } from '@h-ai/serv'\n * import { z } from 'zod'\n *\n * const contract = { ping: apiContract.route({ method: 'GET', path: '/ping' }).output(apiContract.haiResultSchema(z.object({ ready: z.boolean() }))) }\n * const builder: ServRouterBuilder<typeof contract, ServContext, ServContext> = serv.implement(contract).context<ServContext>()\n * const procedures = builder.route('ping', () => ok({ ready: true })).build()\n * ```\n */\nexport type ServRouterBuilder<\n TContract extends ServContract,\n TInitialContext extends Context,\n TCurrentContext extends ServContext,\n TRemaining extends ServRoutePath<TContract> = ServRoutePath<TContract>,\n> = {\n readonly route: ServRouteMethod<\n TContract,\n TInitialContext,\n TCurrentContext,\n TRemaining\n >\n} & ServRouterBuilderBuild<TContract, TInitialContext, TRemaining>\n\n/**\n * hai-framework 链式 contract 实现器。\n *\n * @example\n * ```ts\n * import type { ServImplementer } from '@h-ai/serv'\n * import type { ServContext } from '@h-ai/serv'\n * import { apiContract } from '@h-ai/api-contract'\n * import { ok } from '@h-ai/core'\n * import { serv } from '@h-ai/serv'\n * import { z } from 'zod'\n *\n * const contract = { ping: apiContract.route({ method: 'GET', path: '/ping' }).output(apiContract.haiResultSchema(z.object({ ready: z.boolean() }))) }\n * const implementer: ServImplementer<typeof contract> = serv.implement(contract)\n * const procedures = implementer.context<ServContext>().route('ping', () => ok({ ready: true })).build()\n * ```\n */\nexport interface ServImplementer<TContract extends ServContract> {\n readonly context: <TContext extends ServContext>() => ServRouterBuilder<\n TContract,\n TContext & EmptyContext,\n TContext\n >\n}\n\n/**\n * 创建链式 contract 实现器。\n *\n * @example\n * ```ts\n * import type { ServContext } from '@h-ai/serv'\n * import { apiContract } from '@h-ai/api-contract'\n * import { ok } from '@h-ai/core'\n * import { serv } from '@h-ai/serv'\n * import { z } from 'zod'\n *\n * const contract = { ping: apiContract.route({ method: 'GET', path: '/ping' }).output(apiContract.haiResultSchema(z.object({ ready: z.boolean() }))) }\n * const procedures = serv.implement(contract).context<ServContext>().route('ping', () => ok({ ready: true })).build()\n * ```\n */\nexport function implement<TContract extends ServContract>(\n contract: TContract,\n): ServImplementer<TContract> {\n return {\n context: <TContext extends ServContext>() => {\n const native = orpcImplement(contract).$context<TContext>()\n return createServRouterBuilder(contract, native)\n },\n }\n}\n\nfunction createServRouterBuilder<\n TContract extends ServContract,\n TInitialContext extends Context,\n TCurrentContext extends ServContext,\n>(\n contract: TContract,\n implementer: Implementer<TContract, TInitialContext, TCurrentContext>,\n): ServRouterBuilder<TContract, TInitialContext, TCurrentContext> {\n const runtime = new ServRouterBuilderRuntime(contract, implementer)\n\n // oRPC 的 contract 泛型只能在编译期表示;运行时 builder 由同一 contract\n // 创建并逐项校验路径,因此这里将动态实现收敛到唯一的类型边界。\n return runtime as unknown as ServRouterBuilder<\n TContract,\n TInitialContext,\n TCurrentContext\n >\n}\n\n/**\n * 内部运行时 handler 边界;最终输入/输出验证仍由对应 contract 决定。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const { ok } = await import('@h-ai/core')\n * const handler: RuntimeProcedureHandler = ({ input }) => ok(input)\n * // 动态装配边界仍由相同 contract 校验路径与 options,不提升未知输入类型。\n * ```\n */\ntype RuntimeProcedureHandler = ProcedureHandler<\n ServContext,\n unknown,\n HaiResult<unknown>,\n ErrorMap,\n Meta\n>\n/**\n * 内部认证后的运行时 handler,原始 oRPC options 与可信 session 保留。\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const { ok } = await import('@h-ai/core')\n * const handler: AuthenticatedRuntimeProcedureHandler = ({ context }) => ok({ userId: context.session.userId })\n * const guarded = applyServGuards({ auth: true }, handler)\n * ```\n */\ntype AuthenticatedRuntimeProcedureHandler = ProcedureHandler<\n AuthenticatedServContext,\n unknown,\n HaiResult<unknown>,\n ErrorMap,\n Meta\n>\n\nclass ServRouterBuilderRuntime {\n private readonly expectedPaths: ReadonlySet<string>\n private readonly implementedRoutes: Record<string, unknown>\n private readonly registeredPaths = new Set<string>()\n\n constructor(\n contract: ServContract,\n private readonly implementer: object,\n ) {\n this.expectedPaths = new Set(collectProcedurePaths(contract))\n this.implementedRoutes = createRouterShape(contract)\n }\n\n route(path: string, handler?: unknown): unknown {\n if (handler !== undefined)\n return this.register(path, {}, handler)\n\n return new ServRouteRegistrationRuntime(this, path)\n }\n\n register(path: string, guards: ServGuardRequirements, handler: unknown): this {\n if (!this.expectedPaths.has(path))\n throw new TypeError(`Contract path is not implementable: ${path}`)\n if (this.registeredPaths.has(path))\n throw new TypeError(`Duplicate procedure implementation: ${path}`)\n if (typeof handler !== 'function')\n throw new TypeError(`Procedure handler must be a function: ${path}`)\n\n const procedureImplementer = getAtPath(this.implementer, path)\n const implementHandler = getHandlerMethod(procedureImplementer)\n if (!implementHandler)\n throw new TypeError(`Contract path is not implementable: ${path}`)\n\n // 点路径反射会丢失单条 contract 的泛型;路径已由 expectedPaths 校验,\n // handler 的精确 input/output 则由公开的 ServRouteHandler 在调用侧保证。\n const guardedHandler = hasGuards(guards)\n ? applyServGuards(guards, handler as AuthenticatedRuntimeProcedureHandler)\n : handler as RuntimeProcedureHandler\n const safeHandler = mapHaiError(guardedHandler)\n const implemented = Reflect.apply(\n implementHandler,\n procedureImplementer,\n [safeHandler],\n )\n\n setAtPath(this.implementedRoutes, path, implemented)\n this.registeredPaths.add(path)\n return this\n }\n\n build(): unknown {\n const missingPaths = [...this.expectedPaths]\n .filter(path => !this.registeredPaths.has(path))\n .sort()\n if (missingPaths.length > 0) {\n throw new TypeError(\n `Cannot build router. Missing procedures: ${missingPaths.join(', ')}`,\n )\n }\n\n const routerMethod = Reflect.get(this.implementer, 'router')\n if (typeof routerMethod !== 'function')\n throw new TypeError('The oRPC implementer does not expose router()')\n\n return Reflect.apply(routerMethod, this.implementer, [this.implementedRoutes])\n }\n}\n\nclass ServRouteRegistrationRuntime {\n private authRequired = false\n private readonly permissions = new Set<string>()\n private readonly roles = new Set<string>()\n\n constructor(\n private readonly parent: ServRouterBuilderRuntime,\n private readonly path: string,\n ) {}\n\n auth(): this {\n this.authRequired = true\n return this\n }\n\n permission(permission: string): this {\n this.authRequired = true\n this.permissions.add(permission)\n return this\n }\n\n role(role: string): this {\n this.authRequired = true\n this.roles.add(role)\n return this\n }\n\n handle(handler: unknown): ServRouterBuilderRuntime {\n return this.parent.register(this.path, {\n auth: this.authRequired,\n permissions: [...this.permissions],\n roles: [...this.roles],\n }, handler)\n }\n}\n\nfunction hasGuards(guards: ServGuardRequirements): boolean {\n return guards.auth === true\n || (guards.permissions?.length ?? 0) > 0\n || (guards.roles?.length ?? 0) > 0\n}\n\nfunction collectProcedurePaths(\n contract: ServContract,\n prefix: readonly string[] = [],\n): string[] {\n if (isContractProcedure(contract))\n return prefix.length > 0 ? [prefix.join('.')] : []\n\n return Object.entries(contract).flatMap(([key, child]) =>\n collectProcedurePaths(child, [...prefix, key]))\n}\n\nfunction isContractProcedure(contract: ServContract): boolean {\n return '~orpc' in contract\n}\n\nfunction createRouterShape(contract: ServContract): Record<string, unknown> {\n const shape: Record<string, unknown> = Object.create(null)\n\n for (const [key, child] of Object.entries(contract)) {\n if (!isContractProcedure(child))\n shape[key] = createRouterShape(child)\n }\n\n return shape\n}\n\nfunction getAtPath(root: object, path: string): unknown {\n let current: unknown = root\n\n for (const segment of path.split('.')) {\n if (\n (typeof current !== 'object' && typeof current !== 'function')\n || current === null\n || !(segment in current)\n ) {\n return undefined\n }\n\n current = Reflect.get(current, segment)\n }\n\n return current\n}\n\nfunction setAtPath(root: Record<string, unknown>, path: string, value: unknown): void {\n const segments = path.split('.')\n const leaf = segments.pop()\n if (!leaf)\n throw new TypeError('Procedure path cannot be empty')\n\n let current = root\n for (const segment of segments) {\n const existing = current[segment]\n if (existing === undefined) {\n const child: Record<string, unknown> = Object.create(null)\n current[segment] = child\n current = child\n continue\n }\n\n if (!existing || typeof existing !== 'object')\n throw new TypeError(`Procedure path conflicts with an existing route: ${path}`)\n\n current = existing as Record<string, unknown>\n }\n\n current[leaf] = value\n}\n\nfunction getHandlerMethod(value: unknown): ((handler: unknown) => unknown) | undefined {\n if ((typeof value !== 'object' && typeof value !== 'function') || value === null)\n return undefined\n\n const handler = Reflect.get(value, 'handler')\n return typeof handler === 'function'\n ? handler as (handler: unknown) => unknown\n : undefined\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { normalizeServLocale, servM } from './chunk-TWHCU6HT.js';
1
+ import { normalizeServLocale, servM } from './chunk-KR4H56KP.js';
2
2
  import { core, ok, err, HaiCommonError } from '@h-ai/core';
3
3
 
4
4
  var DEFAULT_LOCALE = "zh-CN";
@@ -33,5 +33,5 @@ function validateInputOrFail(schema, input, locale = DEFAULT_LOCALE) {
33
33
  }
34
34
 
35
35
  export { localizeZodError, resolveRequestLocale, validateInputOrFail };
36
- //# sourceMappingURL=chunk-BGWE4S6Z.js.map
37
- //# sourceMappingURL=chunk-BGWE4S6Z.js.map
36
+ //# sourceMappingURL=chunk-WW25756Z.js.map
37
+ //# sourceMappingURL=chunk-WW25756Z.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/serv-validation.ts"],"names":[],"mappings":";;;AAiBA,IAAM,cAAA,GAAiB,OAAA;AAmDhB,SAAS,qBAAqB,OAAA,EAA+D;AAClG,EAAA,MAAM,GAAA,GAAM,CAAC,IAAA,KAAqC;AAChD,IAAA,IAAI,OAAA,YAAmB,OAAA;AACrB,MAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA,IAAK,MAAA;AAC9B,IAAA,OAAO,QAAQ,IAAI,CAAA,IAAK,OAAA,CAAQ,IAAA,CAAK,aAAa,CAAA;AAAA,EACpD,CAAA;AAEA,EAAA,MAAM,QAAA,GAAW,IAAI,cAAc,CAAA;AACnC,EAAA,IAAI,QAAA;AACF,IAAA,OAAO,oBAAoB,QAAQ,CAAA;AAErC,EAAA,OAAO,oBAAoB,GAAA,CAAI,iBAAiB,KAAK,GAAA,CAAI,iBAAiB,KAAK,cAAc,CAAA;AAC/F;AAiBO,SAAS,gBAAA,CAAiB,UAAmB,MAAA,EAAuC;AACzF,EAAA,MAAM,cAAA,GAAiB,oBAAoB,MAAM,CAAA;AACjD,EAAA,OAAO,KAAK,aAAA,CAAc,uBAAA;AAAA,IACxB,QAAA;AAAA,IACA,KAAK,aAAA,CAAc,8BAAA;AAAA,MACjB,MAAA;AAAA,MACA,CAAC,YAAY,MAAA,KAAW,KAAA,CAAM,YAAY,EAAE,MAAA,EAAQ,cAAA,EAAgB,MAAA,EAAQ;AAAA;AAC9E,GACF;AACF;AA2CO,SAAS,mBAAA,CACd,MAAA,EACA,KAAA,EACA,MAAA,GAAiB,cAAA,EACG;AACpB,EAAA,MAAM,cAAA,GAAiB,oBAAoB,MAAM,CAAA;AACjD,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,SAAA,CAAU,KAAK,CAAA;AACrC,EAAA,IAAI,MAAA,CAAO,OAAA;AACT,IAAA,OAAO,EAAA,CAAG,OAAO,IAAI,CAAA;AACvB,EAAA,MAAM,MAAA,GAAS,gBAAA,CAAiB,MAAA,CAAO,KAAA,EAAO,cAAc,CAAA;AAC5D,EAAA,OAAO,GAAA,CAAI,cAAA,CAAe,gBAAA,EAAkB,KAAA,CAAM,uBAAA,EAAyB,EAAE,MAAA,EAAQ,cAAA,EAAgB,CAAA,EAAG,MAAM,CAAA;AAChH","file":"chunk-WW25756Z.js","sourcesContent":["/**\n * @h-ai/serv — 校验工具\n *\n * 为 API service 提供与 kit 对等的校验 i18n 能力:\n * - {@link resolveRequestLocale}:从请求头(`x-hai-locale` / `Accept-Language`)解析语言。\n * - {@link validateInputOrFail}:在 procedure 内显式校验数据,失败返回 `HaiResult` 错误。\n * - oRPC contract 输入校验失败的自动本地化由 `serv-app.ts` 中的 oRPC 响应拦截器处理。\n *\n * @module serv-validation\n */\n\nimport type { HaiResult, ValidationFormError } from '@h-ai/core'\nimport type { ZodType } from 'zod'\nimport type { ServMessageKey } from './serv-i18n.js'\nimport { core, err, HaiCommonError, ok } from '@h-ai/core'\nimport { normalizeServLocale, servM } from './serv-i18n.js'\n\nconst DEFAULT_LOCALE = 'zh-CN'\n\n/**\n * 校验失败响应体(含 i18n 错误列表)。\n *\n * 复用 `HaiResult` 失败分支结构。字段错误同时在两处出现:\n * - `error.cause`:与 `validateInputOrFail` 输出对齐,HaiResult 标准位置\n * - 顶层 `errors`:保留以兼容已有客户端\n *\n * @example\n * ```ts\n * import type { ServValidationFailureBody } from '@h-ai/serv'\n * import { serv } from '@h-ai/serv'\n *\n * function fields(body: ServValidationFailureBody) {\n * return body.error.cause ?? body.errors\n * }\n * // 业务调用先判断 success,字段错误仅包含安全的本地化文案。\n * ```\n */\nexport interface ServValidationFailureBody {\n readonly success: false\n readonly error: {\n readonly code: string | number\n readonly message: string\n readonly traceId?: string\n readonly httpStatus: number\n readonly system: string\n readonly module: string\n readonly cause?: readonly ValidationFormError[]\n }\n readonly errors: readonly ValidationFormError[]\n}\n\n/**\n * 从请求头解析客户端期望 locale。\n *\n * 优先级:`x-hai-locale` > `Accept-Language` 第一个匹配项 > 默认值(`zh-CN`)。\n * 返回值会被规范化为 serv 当前支持的 locale(如 `en` → `en-US`)。\n *\n * @param headers - 请求头(`Headers` 或与之等价的对象)\n * @returns 解析得到的 locale\n *\n * @example\n * ```ts\n * import { serv } from '@h-ai/serv'\n *\n * const locale = serv.resolveRequestLocale(new Headers({ 'x-hai-locale': 'en-US' }))\n * const fallback = serv.resolveRequestLocale(new Headers())\n * ```\n */\nexport function resolveRequestLocale(headers: Headers | Record<string, string | undefined>): string {\n const get = (name: string): string | undefined => {\n if (headers instanceof Headers)\n return headers.get(name) ?? undefined\n return headers[name] ?? headers[name.toLowerCase()]\n }\n\n const explicit = get('x-hai-locale')\n if (explicit)\n return normalizeServLocale(explicit)\n\n return normalizeServLocale(get('accept-language') ?? get('Accept-Language') ?? DEFAULT_LOCALE)\n}\n\n/**\n * 把 Zod 错误转为本地化的扁平错误列表。\n *\n * @param zodError - Zod `SafeParseError` 或 `ZodError`\n * @param locale - 期望 locale\n *\n * @example\n * ```ts\n * // 模块内部上下文:示例复用当前声明所在模块的实际绑定。\n * const { z } = await import('zod')\n * const parsed = z.object({ name: z.string().min(1) }).safeParse({ name: '' })\n * if (parsed.success) return []\n * return localizeZodError(parsed.error, 'en-US')\n * ```\n */\nexport function localizeZodError(zodError: unknown, locale: string): ValidationFormError[] {\n const resolvedLocale = normalizeServLocale(locale)\n return core.zodValidation.mapZodErrorToFormErrors(\n zodError,\n core.zodValidation.createPrefixedZodMessageGetter<ServMessageKey>(\n 'serv',\n (messageKey, params) => servM(messageKey, { locale: resolvedLocale, params }),\n ),\n )\n}\n\n/**\n * 在 procedure handler 内显式校验数据。\n *\n * 与 oRPC contract 自动校验不同,本函数用于业务层二次校验(例如对从数据库读到的对象再校验)。\n * 失败时返回 `HaiResult` 错误分支,错误的 `cause` 字段携带 `ValidationFormError[]`。\n *\n * 推荐使用方式:\n * ```ts\n * import { z } from 'zod'\n * import { serv } from '@h-ai/serv'\n *\n * const Schema = z.object({ name: z.string().min(1) })\n *\n * export const procedures = serv\n * .implement(contract)\n * .context<ServContext>()\n * .route('profile.update', ({ input, context }) => {\n * const result = serv.validateInputOrFail(Schema, input, context.locale)\n * if (!result.success) return result\n * return profileService.update(result.data)\n * })\n * .build()\n * ```\n *\n * @param schema - Zod schema\n * @param input - 待校验数据\n * @param locale - 期望 locale(通常来自请求上下文)\n *\n * @example\n * ```ts\n * import { serv } from '@h-ai/serv'\n * import { z } from 'zod'\n *\n * const result = serv.validateInputOrFail(z.object({ name: z.string().min(1) }), { name: '' }, 'en-US')\n * if (!result.success) {\n * const fields = result.error.cause\n * } else {\n * const name = result.data.name\n * }\n * ```\n */\nexport function validateInputOrFail<TOutput>(\n schema: ZodType<TOutput>,\n input: unknown,\n locale: string = DEFAULT_LOCALE,\n): HaiResult<TOutput> {\n const resolvedLocale = normalizeServLocale(locale)\n const result = schema.safeParse(input)\n if (result.success)\n return ok(result.data)\n const errors = localizeZodError(result.error, resolvedLocale)\n return err(HaiCommonError.VALIDATION_ERROR, servM('serv_validationFailed', { locale: resolvedLocale }), errors)\n}\n"]}
@@ -176,6 +176,7 @@ declare function createAiProcedures(deps: AiProcedureDeps): {
176
176
  error: zod.ZodObject<{
177
177
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
178
178
  message: zod.ZodString;
179
+ traceId: zod.ZodOptional<zod.ZodString>;
179
180
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
180
181
  system: zod.ZodOptional<zod.ZodString>;
181
182
  module: zod.ZodOptional<zod.ZodString>;
@@ -207,6 +208,7 @@ declare function createAiProcedures(deps: AiProcedureDeps): {
207
208
  error: zod.ZodObject<{
208
209
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
209
210
  message: zod.ZodString;
211
+ traceId: zod.ZodOptional<zod.ZodString>;
210
212
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
211
213
  system: zod.ZodOptional<zod.ZodString>;
212
214
  module: zod.ZodOptional<zod.ZodString>;
@@ -306,6 +308,7 @@ declare function createAiProcedures(deps: AiProcedureDeps): {
306
308
  error: zod.ZodObject<{
307
309
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
308
310
  message: zod.ZodString;
311
+ traceId: zod.ZodOptional<zod.ZodString>;
309
312
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
310
313
  system: zod.ZodOptional<zod.ZodString>;
311
314
  module: zod.ZodOptional<zod.ZodString>;
@@ -354,6 +357,7 @@ declare function createAiProcedures(deps: AiProcedureDeps): {
354
357
  error: zod.ZodObject<{
355
358
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
356
359
  message: zod.ZodString;
360
+ traceId: zod.ZodOptional<zod.ZodString>;
357
361
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
358
362
  system: zod.ZodOptional<zod.ZodString>;
359
363
  module: zod.ZodOptional<zod.ZodString>;
@@ -400,6 +404,7 @@ declare function createAiProcedures(deps: AiProcedureDeps): {
400
404
  error: zod.ZodObject<{
401
405
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
402
406
  message: zod.ZodString;
407
+ traceId: zod.ZodOptional<zod.ZodString>;
403
408
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
404
409
  system: zod.ZodOptional<zod.ZodString>;
405
410
  module: zod.ZodOptional<zod.ZodString>;
@@ -428,6 +433,7 @@ declare function createAiProcedures(deps: AiProcedureDeps): {
428
433
  error: zod.ZodObject<{
429
434
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
430
435
  message: zod.ZodString;
436
+ traceId: zod.ZodOptional<zod.ZodString>;
431
437
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
432
438
  system: zod.ZodOptional<zod.ZodString>;
433
439
  module: zod.ZodOptional<zod.ZodString>;
@@ -1,5 +1,5 @@
1
1
  import { wrapItemsResult } from '../chunk-XKCLD42I.js';
2
- import { implement, servM } from '../chunk-TWHCU6HT.js';
2
+ import { implement, servM } from '../chunk-KR4H56KP.js';
3
3
  import { apiContract } from '@h-ai/api-contract';
4
4
  import { ok, err, HaiCommonError } from '@h-ai/core';
5
5
 
@@ -1,6 +1,6 @@
1
1
  import * as _orpc_server from '@orpc/server';
2
- import * as zod_v4_core from 'zod/v4/core';
3
2
  import * as zod from 'zod';
3
+ import * as zod_v4_core from 'zod/v4/core';
4
4
  import { FeedbackFunctions, FeedbackContext } from '@h-ai/feedback';
5
5
  import { S as ServContext } from '../serv-context-B-AxU8hj.js';
6
6
  import { A as AuthenticatedServContext } from '../serv-router-C8dSz2k-.js';
@@ -30,6 +30,31 @@ interface FeedbackProcedureDeps {
30
30
  */
31
31
  declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
32
32
  reports: {
33
+ policy: _orpc_server.Procedure<ServContext & {}, any, zod.ZodObject<{}, zod_v4_core.$strip>, zod.ZodDiscriminatedUnion<[zod.ZodObject<{
34
+ success: zod.ZodLiteral<true>;
35
+ data: zod.ZodObject<{
36
+ maxTotalBytes: zod.ZodNumber;
37
+ maxAttachmentBytes: zod.ZodNumber;
38
+ maxAttachmentsBytes: zod.ZodNumber;
39
+ maxAttachmentCount: zod.ZodNumber;
40
+ maxEvidenceBytes: zod.ZodNumber;
41
+ maxEvidenceCount: zod.ZodNumber;
42
+ maxTransportBytes: zod.ZodNumber;
43
+ }, zod_v4_core.$strip>;
44
+ }, zod_v4_core.$strip>, zod.ZodObject<{
45
+ success: zod.ZodLiteral<false>;
46
+ error: zod.ZodObject<{
47
+ code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
48
+ message: zod.ZodString;
49
+ traceId: zod.ZodOptional<zod.ZodString>;
50
+ httpStatus: zod.ZodOptional<zod.ZodNumber>;
51
+ system: zod.ZodOptional<zod.ZodString>;
52
+ module: zod.ZodOptional<zod.ZodString>;
53
+ cause: zod.ZodOptional<zod.ZodUnknown>;
54
+ suggestion: zod.ZodOptional<zod.ZodString>;
55
+ ext: zod.ZodOptional<zod.ZodRecord<zod.ZodString, zod.ZodUnknown>>;
56
+ }, zod_v4_core.$strip>;
57
+ }, zod_v4_core.$strip>], "success">, Record<never, never>, Record<never, never>>;
33
58
  submit: _orpc_server.Procedure<ServContext & {}, any, zod.ZodObject<{
34
59
  submissionId: zod.ZodString;
35
60
  appId: zod.ZodString;
@@ -97,6 +122,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
97
122
  notificationStatus: zod.ZodEnum<{
98
123
  pending: "pending";
99
124
  failed: "failed";
125
+ disabled: "disabled";
100
126
  sending: "sending";
101
127
  sent: "sent";
102
128
  deferred: "deferred";
@@ -119,6 +145,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
119
145
  error: zod.ZodObject<{
120
146
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
121
147
  message: zod.ZodString;
148
+ traceId: zod.ZodOptional<zod.ZodString>;
122
149
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
123
150
  system: zod.ZodOptional<zod.ZodString>;
124
151
  module: zod.ZodOptional<zod.ZodString>;
@@ -147,6 +174,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
147
174
  notificationStatus: zod.ZodOptional<zod.ZodEnum<{
148
175
  pending: "pending";
149
176
  failed: "failed";
177
+ disabled: "disabled";
150
178
  sending: "sending";
151
179
  sent: "sent";
152
180
  deferred: "deferred";
@@ -178,6 +206,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
178
206
  notificationStatus: zod.ZodEnum<{
179
207
  pending: "pending";
180
208
  failed: "failed";
209
+ disabled: "disabled";
181
210
  sending: "sending";
182
211
  sent: "sent";
183
212
  deferred: "deferred";
@@ -204,6 +233,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
204
233
  error: zod.ZodObject<{
205
234
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
206
235
  message: zod.ZodString;
236
+ traceId: zod.ZodOptional<zod.ZodString>;
207
237
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
208
238
  system: zod.ZodOptional<zod.ZodString>;
209
239
  module: zod.ZodOptional<zod.ZodString>;
@@ -236,6 +266,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
236
266
  notificationStatus: zod.ZodEnum<{
237
267
  pending: "pending";
238
268
  failed: "failed";
269
+ disabled: "disabled";
239
270
  sending: "sending";
240
271
  sent: "sent";
241
272
  deferred: "deferred";
@@ -310,6 +341,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
310
341
  error: zod.ZodObject<{
311
342
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
312
343
  message: zod.ZodString;
344
+ traceId: zod.ZodOptional<zod.ZodString>;
313
345
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
314
346
  system: zod.ZodOptional<zod.ZodString>;
315
347
  module: zod.ZodOptional<zod.ZodString>;
@@ -373,6 +405,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
373
405
  error: zod.ZodObject<{
374
406
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
375
407
  message: zod.ZodString;
408
+ traceId: zod.ZodOptional<zod.ZodString>;
376
409
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
377
410
  system: zod.ZodOptional<zod.ZodString>;
378
411
  module: zod.ZodOptional<zod.ZodString>;
@@ -410,6 +443,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
410
443
  notificationStatus: zod.ZodEnum<{
411
444
  pending: "pending";
412
445
  failed: "failed";
446
+ disabled: "disabled";
413
447
  sending: "sending";
414
448
  sent: "sent";
415
449
  deferred: "deferred";
@@ -432,6 +466,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
432
466
  error: zod.ZodObject<{
433
467
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
434
468
  message: zod.ZodString;
469
+ traceId: zod.ZodOptional<zod.ZodString>;
435
470
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
436
471
  system: zod.ZodOptional<zod.ZodString>;
437
472
  module: zod.ZodOptional<zod.ZodString>;
@@ -457,6 +492,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
457
492
  error: zod.ZodObject<{
458
493
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
459
494
  message: zod.ZodString;
495
+ traceId: zod.ZodOptional<zod.ZodString>;
460
496
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
461
497
  system: zod.ZodOptional<zod.ZodString>;
462
498
  module: zod.ZodOptional<zod.ZodString>;
@@ -497,6 +533,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
497
533
  error: zod.ZodObject<{
498
534
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
499
535
  message: zod.ZodString;
536
+ traceId: zod.ZodOptional<zod.ZodString>;
500
537
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
501
538
  system: zod.ZodOptional<zod.ZodString>;
502
539
  module: zod.ZodOptional<zod.ZodString>;
@@ -539,6 +576,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
539
576
  error: zod.ZodObject<{
540
577
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
541
578
  message: zod.ZodString;
579
+ traceId: zod.ZodOptional<zod.ZodString>;
542
580
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
543
581
  system: zod.ZodOptional<zod.ZodString>;
544
582
  module: zod.ZodOptional<zod.ZodString>;
@@ -562,6 +600,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
562
600
  error: zod.ZodObject<{
563
601
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
564
602
  message: zod.ZodString;
603
+ traceId: zod.ZodOptional<zod.ZodString>;
565
604
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
566
605
  system: zod.ZodOptional<zod.ZodString>;
567
606
  module: zod.ZodOptional<zod.ZodString>;
@@ -594,6 +633,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
594
633
  notificationStatus: zod.ZodEnum<{
595
634
  pending: "pending";
596
635
  failed: "failed";
636
+ disabled: "disabled";
597
637
  sending: "sending";
598
638
  sent: "sent";
599
639
  deferred: "deferred";
@@ -616,6 +656,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
616
656
  error: zod.ZodObject<{
617
657
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
618
658
  message: zod.ZodString;
659
+ traceId: zod.ZodOptional<zod.ZodString>;
619
660
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
620
661
  system: zod.ZodOptional<zod.ZodString>;
621
662
  module: zod.ZodOptional<zod.ZodString>;
@@ -651,6 +692,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
651
692
  error: zod.ZodObject<{
652
693
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
653
694
  message: zod.ZodString;
695
+ traceId: zod.ZodOptional<zod.ZodString>;
654
696
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
655
697
  system: zod.ZodOptional<zod.ZodString>;
656
698
  module: zod.ZodOptional<zod.ZodString>;
@@ -674,6 +716,7 @@ declare function createFeedbackProcedures(deps: FeedbackProcedureDeps): {
674
716
  error: zod.ZodObject<{
675
717
  code: zod.ZodUnion<readonly [zod.ZodString, zod.ZodNumber]>;
676
718
  message: zod.ZodString;
719
+ traceId: zod.ZodOptional<zod.ZodString>;
677
720
  httpStatus: zod.ZodOptional<zod.ZodNumber>;
678
721
  system: zod.ZodOptional<zod.ZodString>;
679
722
  module: zod.ZodOptional<zod.ZodString>;
@@ -1,6 +1,6 @@
1
- import { implement, servM } from '../chunk-TWHCU6HT.js';
1
+ import { implement, servM } from '../chunk-KR4H56KP.js';
2
2
  import { apiContract } from '@h-ai/api-contract';
3
- import { core, err, HaiCommonError } from '@h-ai/core';
3
+ import { ok, core, err, HaiCommonError } from '@h-ai/core';
4
4
 
5
5
  function createFeedbackProcedures(deps) {
6
6
  const contextFor = async (context) => {
@@ -14,7 +14,10 @@ function createFeedbackProcedures(deps) {
14
14
  }
15
15
  };
16
16
  const router = implement(apiContract.feedback).context();
17
- return router.route("reports.submit").auth().handle(async ({ input, context }) => {
17
+ return router.route("reports.policy").auth().handle(async ({ context }) => {
18
+ const actor = await contextFor(context);
19
+ return actor.success ? ok(deps.feedback.budget) : actor;
20
+ }).route("reports.submit").auth().handle(async ({ input, context }) => {
18
21
  const actor = await contextFor(context);
19
22
  if (!actor.success)
20
23
  return actor;