@h-ai/serv 0.1.0-alpha.46 → 0.1.0-alpha.47

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/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import * as _h_ai_core from '@h-ai/core';
2
2
  import { HaiResult, ValidationFormError } from '@h-ai/core';
3
- import { Router, implement } from '@orpc/server';
4
3
  import { AIFunctions, AudioWsStartMessage, AudioFormat } from '@h-ai/ai';
5
4
  import { AnyContractRouter, OpenAPI } from '@orpc/contract';
6
- import { S as ServSession, a as ServContext, b as ServIam, R as RefreshCookieConfig, C as CreateServContext, p as parseRequestContext, c as buildAuthContextFactory } from './serv-context-BUrtWoFC.js';
7
- export { d as CreateServContextInput, N as NativeRefreshTokenTransportConfig, e as RefreshTokenPair } from './serv-context-BUrtWoFC.js';
5
+ import { ProcedureHandler, ErrorMap, Meta, ProcedureHandlerOptions, ORPCErrorConstructorMap, Router, ContractRouter, Context, ContractProcedure, InferSchemaInput, InferSchemaOutput } from '@orpc/server';
6
+ import { S as ServSession, a as ServContext, b as ServIam, R as RefreshCookieConfig, C as CreateServContext, p as parseRequestContext, c as buildAuthContextFactory } from './serv-context-jc3rZxbj.js';
7
+ export { d as CreateServContextInput, N as NativeRefreshTokenTransportConfig, e as RefreshTokenPair } from './serv-context-jc3rZxbj.js';
8
8
  import { MiddlewareHandler } from 'hono';
9
9
  import { z, ZodType } from 'zod';
10
10
  import { CryptoFunctions, TransportKeyStore } from '@h-ai/crypto';
@@ -55,8 +55,7 @@ interface AudioWsDeps {
55
55
  /**
56
56
  * @h-ai/serv — Pipeline 共享类型
57
57
  *
58
- * 统一定义 Hono middleware 与 oRPC procedure wrapper 的最小公共类型,
59
- * 供默认实现与使用方自定义实现复用。
58
+ * 统一定义 Hono middleware 与 oRPC procedure handler 类型。
60
59
  * @module pipelines/serv-pipeline-types
61
60
  */
62
61
 
@@ -69,17 +68,13 @@ type ServMiddleware = MiddlewareHandler;
69
68
  * - 带配置 middleware:`ServMiddlewareFactory<MyConfig>`
70
69
  */
71
70
  type ServMiddlewareFactory<TConfig = void> = [TConfig] extends [void] ? () => ServMiddleware : (config: TConfig) => ServMiddleware;
72
- /** oRPC procedure handler 的最小上下文约束。 */
73
- interface ServProcedureOptions<TInput = unknown> {
74
- readonly input: TInput;
75
- readonly context: ServContext;
76
- }
77
- /** oRPC procedure handler。 */
78
- type ServProcedureHandler<TInput, TOutput> = (options: ServProcedureOptions<TInput>) => HaiResult<TOutput> | Promise<HaiResult<TOutput>>;
79
- /** 单参数 procedure 包装器(例如 `mapHaiError`、`requireAuth`)。 */
80
- type ServProcedureWrapper = <TInput, TOutput>(handler: ServProcedureHandler<TInput, TOutput>) => ServProcedureHandler<TInput, TOutput>;
81
- /** 带额外参数的 procedure 包装器(例如 `requirePermission('x', handler)`)。 */
82
- type ServGuardedProcedureWrapper<TRequirement> = <TInput, TOutput>(requirement: TRequirement, handler: ServProcedureHandler<TInput, TOutput>) => ServProcedureHandler<TInput, TOutput>;
71
+ /**
72
+ * 使用 oRPC 公开 `ProcedureHandler` 定义的 HaiResult procedure handler。
73
+ *
74
+ * handler options 完整保留 oRPC 的路径、procedure、signal 与错误构造器信息。
75
+ */
76
+ type ServProcedureOptions<TInput = unknown, TContext extends ServContext = ServContext> = ProcedureHandlerOptions<TContext, TInput, ORPCErrorConstructorMap<ErrorMap>, Meta>;
77
+ type ServProcedureHandler<TInput, TOutput, TContext extends ServContext = ServContext> = ProcedureHandler<TContext, TInput, HaiResult<TOutput>, ErrorMap, Meta>;
83
78
 
84
79
  /**
85
80
  * @h-ai/serv — HTTP 配置
@@ -323,7 +318,7 @@ interface ServHttpApp {
323
318
  * **认证 / 会话填充设计**(遵循最小知识原则):
324
319
  *
325
320
  * - **`iam`**(推荐):单一顶层引用。提供后 serv 自动:
326
- * 1. 使用 `iam.session.verifyToken` 填充 `context.session` → `requireAuth/Permission/Role` 生效
321
+ * 1. 使用 `iam.session.verifyToken` 填充 `context.session` → route guard 生效
327
322
  * 2. 若同时启用 `refreshCookie`,使用 `iam.session.refresh` 实现 refresh token 轮换
328
323
  *
329
324
  * - **`refreshCookie`**(可选):浏览器默认用 httpOnly cookie;受信原生客户端可配置 body 通道。与 `iam` 正交:
@@ -595,99 +590,6 @@ interface ServNodeServer {
595
590
  */
596
591
  declare function listen(app: ServHttpApp, options?: ServListenOptions): ServNodeServer;
597
592
 
598
- /**
599
- * @h-ai/serv — Pipeline 公共 helper
600
- *
601
- * 放置不属于 Hono middleware / oRPC wrapper 默认实现本身、
602
- * 但会被多个 pipeline 复用的公共工具。
603
- * @module pipelines/serv-pipeline-helper
604
- */
605
-
606
- /**
607
- * 捕获未处理异常并转换为 HaiResult。
608
- *
609
- * 虽然它不是 middleware / 鉴权 wrapper,但属于所有 procedure pipeline
610
- * 都可能复用的“公共包装能力”,因此与 `buildHaiErrorBody()` 一起放在 helper 中。
611
- *
612
- * @param handler - 被包装的 procedure handler
613
- * @returns 带异常保护的新 handler
614
- *
615
- * @example
616
- * ```ts
617
- * const safeHandler = serv.mapHaiError(myHandler)
618
- * ```
619
- */
620
- declare function mapHaiError<TInput, TOutput>(handler: ServProcedureHandler<TInput, TOutput>): ServProcedureHandler<TInput, TOutput>;
621
-
622
- /**
623
- * @h-ai/serv — requireAuth 默认实现
624
- * @module pipelines/serv-pipeline-require-auth
625
- */
626
-
627
- /**
628
- * 需要已验证会话的 procedure 包装器。
629
- *
630
- * `context.session` 由 `buildAuthContextFactory(verifyToken)`(或 `serv.createApp({ iam })` 自动启用)填充。
631
- * token 不存在或无效(verifyToken 失败)时 `session` 均为 `undefined`,统一返回 401 UNAUTHORIZED。
632
- * 内置调用 `mapHaiError`,无需外层再次封装。
633
- *
634
- * @param handler - 被包装的 procedure handler
635
- * @returns 带认证检查的新 handler
636
- *
637
- * @example
638
- * ```ts
639
- * const protectedHandler = serv.requireAuth(myHandler)
640
- * ```
641
- */
642
- declare function requireAuth<TInput, TOutput>(handler: ServProcedureHandler<TInput, TOutput>): ServProcedureHandler<TInput, TOutput>;
643
-
644
- /**
645
- * @h-ai/serv — requirePermission 默认实现
646
- * @module pipelines/serv-pipeline-require-permission
647
- */
648
-
649
- /**
650
- * 需要指定权限的 procedure 包装器。
651
- *
652
- * 内置调用 `requireAuth`,在验证 Token 后进一步匹配 `session.permissions`。
653
- * 拥有 {@link WILDCARD_PERMISSION}(`'*'`)的用户自动通过所有权限检查。
654
- *
655
- * @param permission - 所需权限字符串(如 `'iam.users.read'`)
656
- * @param handler - 被包装的 procedure handler
657
- * @returns 带权限检查的新 handler
658
- *
659
- * @example
660
- * ```ts
661
- * const adminHandler = serv.requirePermission('iam.users.write', myHandler)
662
- * ```
663
- */
664
- declare function requirePermission<TInput, TOutput>(permission: string, handler: ServProcedureHandler<TInput, TOutput>): ServProcedureHandler<TInput, TOutput>;
665
-
666
- /**
667
- * @h-ai/serv — requireRole 默认实现
668
- * @module pipelines/serv-pipeline-require-role
669
- */
670
-
671
- /**
672
- * 需要指定角色的 procedure 包装器。
673
- *
674
- * 内置调用 `requireAuth`,在验证 Token 后进一步匹配 `session.roles`。
675
- * 拥有 {@link WILDCARD_ROLE}(`'*'`)的用户自动通过所有角色检查。
676
- *
677
- * **使用建议**:优先使用 {@link requirePermission}(基于行为的细粒度授权);
678
- * `requireRole` 适用于按角色分流的粗粒度路由(如 `'admin'` 专属入口)。
679
- *
680
- * @param role - 所需角色字符串(如 `'admin'`)
681
- * @param handler - 被包装的 procedure handler
682
- * @returns 带角色检查的新 handler
683
- *
684
- * @example
685
- * ```ts
686
- * const adminOnly = serv.requireRole('admin', myHandler)
687
- * ```
688
- */
689
- declare function requireRole<TInput, TOutput>(role: string, handler: ServProcedureHandler<TInput, TOutput>): ServProcedureHandler<TInput, TOutput>;
690
-
691
593
  /**
692
594
  * @h-ai/serv — CORS middleware
693
595
  *
@@ -746,6 +648,86 @@ interface GenerateOpenAPISpecOptions {
746
648
  */
747
649
  declare function generateSpec(contract: AnyContractRouter, options?: GenerateOpenAPISpecOptions): Promise<OpenAPI.Document>;
748
650
 
651
+ /**
652
+ * @h-ai/serv — contract-first 链式 procedure 实现器
653
+ *
654
+ * 在 oRPC `implement()` 之上提供 route 名只出现一次的链式 DSL。
655
+ * 应用只接触 contract 路径、上下文与 guard,不需要组装 oRPC router 对象。
656
+ *
657
+ * @module serv-router
658
+ */
659
+
660
+ type EmptyContext = Record<never, never>;
661
+ type StringKey<T> = Extract<keyof T, string>;
662
+ type ServContract = ContractRouter<Meta>;
663
+ /** contract 中所有 procedure 的点分路径。 */
664
+ type ServRoutePath<TContract extends ServContract> = TContract extends ContractProcedure<infer _TInputSchema, infer _TOutputSchema, infer _TErrorMap, infer _TMeta> ? never : {
665
+ [K in StringKey<TContract>]: TContract[K] extends ContractProcedure<infer _TChildInputSchema, infer _TChildOutputSchema, infer _TChildErrorMap, infer _TChildMeta> ? K : TContract[K] extends ServContract ? ServRoutePath<TContract[K]> extends infer TChild extends string ? `${K}.${TChild}` : never : never;
666
+ }[StringKey<TContract>];
667
+ type ContractAtPath<TContract, TPath extends string> = TPath extends `${infer THead}.${infer TTail}` ? THead extends keyof TContract ? ContractAtPath<TContract[THead], TTail> : never : TPath extends keyof TContract ? TContract[TPath] : never;
668
+ type RouteContract<TContract extends ServContract, TPath extends ServRoutePath<TContract>> = ContractAtPath<TContract, TPath>;
669
+ /** `.auth()`、`.permission()`、`.role()` 后的非空会话上下文。 */
670
+ type AuthenticatedServContext<TContext extends ServContext = ServContext> = TContext & {
671
+ readonly session: NonNullable<TContext['session']>;
672
+ };
673
+ type RouteHandler<TRouteContract, TContext extends Context> = TRouteContract extends ContractProcedure<infer TInputSchema, infer TOutputSchema, infer TErrorMap, infer TMeta> ? InferSchemaInput<TOutputSchema> extends HaiResult<unknown> ? ProcedureHandler<TContext, InferSchemaOutput<TInputSchema>, InferSchemaInput<TOutputSchema>, TErrorMap, TMeta> : never : never;
674
+ /** 从 contract procedure 精确推导当前 route 的 HaiResult handler。 */
675
+ type ServRouteHandler<TContract extends ServContract, TPath extends ServRoutePath<TContract>, TContext extends Context> = RouteHandler<RouteContract<TContract, TPath>, TContext>;
676
+ type ServGuardedRouteHandler<TContract extends ServContract, TPath extends ServRoutePath<TContract>, TContext extends ServContext> = RouteHandler<RouteContract<TContract, TPath>, AuthenticatedServContext<TContext>>;
677
+ type NextBuilder<TContract extends ServContract, TInitialContext extends Context, TCurrentContext extends ServContext, TRemaining extends ServRoutePath<TContract>, TPath extends TRemaining> = ServRouterBuilder<TContract, TInitialContext, TCurrentContext, Exclude<TRemaining, TPath>>;
678
+ /** 尚未声明 guard 的单 route 注册器。 */
679
+ interface ServRouteRegistration<TContract extends ServContract, TInitialContext extends Context, TCurrentContext extends ServContext, TRemaining extends ServRoutePath<TContract>, TPath extends TRemaining> {
680
+ readonly auth: () => ServGuardedRouteRegistration<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
681
+ readonly permission: (permission: string) => ServGuardedRouteRegistration<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
682
+ readonly role: (role: string) => ServGuardedRouteRegistration<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
683
+ }
684
+ /** 已声明认证或授权 guard 的单 route 注册器。 */
685
+ interface ServGuardedRouteRegistration<TContract extends ServContract, TInitialContext extends Context, TCurrentContext extends ServContext, TRemaining extends ServRoutePath<TContract>, TPath extends TRemaining> {
686
+ readonly auth: () => ServGuardedRouteRegistration<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
687
+ readonly permission: (permission: string) => ServGuardedRouteRegistration<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
688
+ readonly role: (role: string) => ServGuardedRouteRegistration<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
689
+ readonly handle: (handler: ServGuardedRouteHandler<TContract, TPath, TCurrentContext>) => NextBuilder<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
690
+ }
691
+ interface ServRouteMethod<TContract extends ServContract, TInitialContext extends Context, TCurrentContext extends ServContext, TRemaining extends ServRoutePath<TContract>> {
692
+ <TPath extends TRemaining>(path: TPath, handler: ServRouteHandler<TContract, TPath, TCurrentContext>): NextBuilder<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
693
+ <TPath extends TRemaining>(path: TPath): ServRouteRegistration<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
694
+ }
695
+ type ServRouterBuilderBuild<TContract extends ServContract, TInitialContext extends Context, TRemaining> = [TRemaining] extends [never] ? {
696
+ /** 所有 contract procedures 均实现后才可调用。 */
697
+ readonly build: () => Router<TContract, TInitialContext>;
698
+ } : {
699
+ /** 仅供 TypeScript/IDE 展示尚未实现的 route;运行时不存在。 */
700
+ readonly missingRoutes: TRemaining;
701
+ };
702
+ /**
703
+ * 链式 router builder。
704
+ *
705
+ * `TRemaining` 会随着 `.route()` 注册逐步收窄;未实现完整 contract 时没有 `.build()`。
706
+ */
707
+ type ServRouterBuilder<TContract extends ServContract, TInitialContext extends Context, TCurrentContext extends ServContext, TRemaining extends ServRoutePath<TContract> = ServRoutePath<TContract>> = {
708
+ readonly route: ServRouteMethod<TContract, TInitialContext, TCurrentContext, TRemaining>;
709
+ } & ServRouterBuilderBuild<TContract, TInitialContext, TRemaining>;
710
+ /** hai-framework 链式 contract 实现器。 */
711
+ interface ServImplementer<TContract extends ServContract> {
712
+ readonly context: <TContext extends ServContext>() => ServRouterBuilder<TContract, TContext & EmptyContext, TContext>;
713
+ }
714
+ /**
715
+ * 创建链式 contract 实现器。
716
+ *
717
+ * @example
718
+ * ```ts
719
+ * serv
720
+ * .implement(contract)
721
+ * .context<ServContext>()
722
+ * .route('info', infoHandler)
723
+ * .route('echo')
724
+ * .auth()
725
+ * .handle(echoHandler)
726
+ * .build()
727
+ * ```
728
+ */
729
+ declare function implement<TContract extends ServContract>(contract: TContract): ServImplementer<TContract>;
730
+
749
731
  /**
750
732
  * @h-ai/serv — 部署环境 HTTP 安全策略
751
733
  *
@@ -877,12 +859,15 @@ declare function resolveRequestLocale(headers: Headers | Record<string, string |
877
859
  *
878
860
  * const Schema = z.object({ name: z.string().min(1) })
879
861
  *
880
- * export const handler = serv.mapHaiError(async ({ input, context }) => {
881
- * const result = serv.validateInputOrFail(Schema, input, context.locale)
882
- * if (!result.success) return result
883
- * const { name } = result.data
884
- * // ...
885
- * })
862
+ * export const procedures = serv
863
+ * .implement(contract)
864
+ * .context<ServContext>()
865
+ * .route('profile.update', ({ input, context }) => {
866
+ * const result = serv.validateInputOrFail(Schema, input, context.locale)
867
+ * if (!result.success) return result
868
+ * return profileService.update(result.data)
869
+ * })
870
+ * .build()
886
871
  * ```
887
872
  *
888
873
  * @param schema - Zod schema
@@ -903,16 +888,11 @@ declare const serv: {
903
888
  storageAssets: typeof storageAssets;
904
889
  createRuntimeSecurityPolicy: typeof createRuntimeSecurityPolicy;
905
890
  generateSpec: typeof generateSpec;
906
- /** 基于 contract 创建可注入 context 的 procedure builder(封装 `@orpc/server` 的 `implement`)。 */
907
891
  implement: typeof implement;
908
- requireAuth: typeof requireAuth;
909
- requirePermission: typeof requirePermission;
910
- requireRole: typeof requireRole;
911
- mapHaiError: typeof mapHaiError;
912
892
  validateInputOrFail: typeof validateInputOrFail;
913
893
  WILDCARD_PERMISSION: string;
914
894
  WILDCARD_ROLE: string;
915
895
  m: (key: "$schema" | "serv_validationFailed" | "serv_validationRequired" | "serv_validationInvalid" | "serv_validationInvalidType" | "serv_validationStringMin" | "serv_validationStringMax" | "serv_validationNumberMin" | "serv_validationNumberMax" | "serv_validationArrayMin" | "serv_validationArrayMax" | "serv_validationTooSmall" | "serv_validationTooBig" | "serv_validationEmail" | "serv_validationUrl" | "serv_validationUuid" | "serv_validationEnum" | "serv_errorUnauthorized" | "serv_errorForbidden" | "serv_errorInternal" | "serv_storageKeyRequired" | "serv_storageKeyTooLong" | "serv_storageKeyIllegalChars" | "serv_storageKeyDotSegments" | "serv_iamCannotDeleteCurrentUser" | "serv_transportInvalidPayload" | "serv_transportUnknownClient" | "serv_transportClientIdRequired" | "serv_transportClientKeyNotFound" | "serv_transportDecryptFailed" | "serv_transportEncryptFailed" | "serv_transportKeyExchangeFailed", options?: _h_ai_core.MessageOptions) => string;
916
896
  };
917
897
 
918
- export { type AudioTicketGrant, type AudioTicketVerification, type AuthorizedAudioRequest, type CreateServAppOptions, CreateServContext, type GenerateOpenAPISpecOptions, RefreshCookieConfig, type ServAudioConfig, type ServConfig, type ServConfigInput, ServConfigSchema, ServContext, type ServCorsConfig, type ServCorsRuntimeConfig, type ServCorsRuntimeConfigInput, type ServDocsHttpConfig, type ServFetchHandler, type ServGuardedProcedureWrapper, type ServHealthHttpConfig, type ServHttpApp, type ServHttpConfig, type ServHttpConfigInput, ServIam, type ServListenOptions, type ServMiddleware, type ServMiddlewareFactory, type ServMiddlewareMount, type ServNodeServer, type ServOpenAPIHttpConfig, type ServProcedureHandler, type ServProcedureOptions, type ServProcedureWrapper, type ServRpcHttpConfig, type ServRuntimeSecurityPolicy, type ServRuntimeSecurityPolicyInput, ServSession, type ServStorageAssetsConfig, type ServTransportConfig, type ServTransportRuntimeConfig, type ServTransportRuntimeConfigInput, type ServValidationFailureBody, serv };
898
+ export { type AudioTicketGrant, type AudioTicketVerification, type AuthenticatedServContext, type AuthorizedAudioRequest, type CreateServAppOptions, CreateServContext, type GenerateOpenAPISpecOptions, RefreshCookieConfig, type ServAudioConfig, type ServConfig, type ServConfigInput, ServConfigSchema, ServContext, type ServCorsConfig, type ServCorsRuntimeConfig, type ServCorsRuntimeConfigInput, type ServDocsHttpConfig, type ServFetchHandler, type ServHealthHttpConfig, type ServHttpApp, type ServHttpConfig, type ServHttpConfigInput, ServIam, type ServImplementer, type ServListenOptions, type ServMiddleware, type ServMiddlewareFactory, type ServMiddlewareMount, type ServNodeServer, type ServOpenAPIHttpConfig, type ServProcedureHandler, type ServProcedureOptions, type ServRouteHandler, type ServRoutePath, type ServRouterBuilder, type ServRpcHttpConfig, type ServRuntimeSecurityPolicy, type ServRuntimeSecurityPolicyInput, ServSession, type ServStorageAssetsConfig, type ServTransportConfig, type ServTransportRuntimeConfig, type ServTransportRuntimeConfigInput, type ServValidationFailureBody, serv };
package/dist/index.js CHANGED
@@ -1,6 +1,4 @@
1
- import { WILDCARD_PERMISSION, requirePermission } from './chunk-YQV2OMQK.js';
2
- import { servM, mapHaiError, requireAuth, normalizeServLocale, buildHaiErrorBody } from './chunk-4QBF4PUG.js';
3
- import { implement } from '@orpc/server';
1
+ import { servM, WILDCARD_ROLE, WILDCARD_PERMISSION, implement, normalizeServLocale, buildHaiErrorBody } from './chunk-KIWHKWLD.js';
4
2
  import process2 from 'process';
5
3
  import { serve } from '@hono/node-server';
6
4
  import { apiContract, AUDIO_WS_PATH, AudioWsClientMessageSchema } from '@h-ai/api-contract';
@@ -1329,15 +1327,6 @@ function listen(app, options = {}) {
1329
1327
  }
1330
1328
  return handle;
1331
1329
  }
1332
- var WILDCARD_ROLE = "*";
1333
- function requireRole(role, handler) {
1334
- return requireAuth(async (options) => {
1335
- const roles = options.context.session?.roles ?? [];
1336
- if (!roles.includes(role) && !roles.includes(WILDCARD_ROLE))
1337
- return err(HaiCommonError.FORBIDDEN, servM("serv_errorForbidden", { locale: options.context.locale }));
1338
- return handler(options);
1339
- });
1340
- }
1341
1330
 
1342
1331
  // src/serv-cors.ts
1343
1332
  var DEFAULT_CORS_METHODS = ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE", "OPTIONS"];
@@ -1569,14 +1558,9 @@ var serv = {
1569
1558
  createRuntimeSecurityPolicy,
1570
1559
  // OpenAPI / 导出
1571
1560
  generateSpec,
1572
- // Procedure 装配(contract 路由定义统一使用 `apiContract.route`)。
1573
- /** 基于 contract 创建可注入 context 的 procedure builder(封装 `@orpc/server` 的 `implement`)。 */
1561
+ // Contract procedure 装配。
1574
1562
  implement,
1575
- // oRPC procedure 包装器
1576
- requireAuth,
1577
- requirePermission,
1578
- requireRole,
1579
- mapHaiError,
1563
+ // Procedure 工具;认证与授权统一由 route 链声明。
1580
1564
  validateInputOrFail,
1581
1565
  // 通配符常量
1582
1566
  WILDCARD_PERMISSION,