@h-ai/serv 0.1.0-alpha.66 → 0.1.0-alpha.68
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 +75 -37
- package/README.ja.md +76 -38
- package/README.md +77 -39
- package/dist/chunk-BGWE4S6Z.js +37 -0
- package/dist/chunk-BGWE4S6Z.js.map +1 -0
- package/dist/{chunk-R354OMWL.js → chunk-TWHCU6HT.js} +48 -6
- package/dist/chunk-TWHCU6HT.js.map +1 -0
- package/dist/{chunk-27PCPE37.js → chunk-XKCLD42I.js} +2 -2
- package/dist/chunk-XKCLD42I.js.map +1 -0
- package/dist/features/ai.d.ts +139 -57
- package/dist/features/ai.js +57 -46
- package/dist/features/ai.js.map +1 -1
- package/dist/features/iam.d.ts +29 -4
- package/dist/features/iam.js +3 -3
- package/dist/features/iam.js.map +1 -1
- package/dist/features/storage.d.ts +94 -9
- package/dist/features/storage.js +48 -12
- package/dist/features/storage.js.map +1 -1
- package/dist/index.d.ts +587 -187
- package/dist/index.js +89 -111
- package/dist/index.js.map +1 -1
- package/dist/{serv-context-CWzyrsdq.d.ts → serv-context-C48WdBcd.d.ts} +127 -7
- package/dist/serv-router-BX8hgYxo.d.ts +322 -0
- package/package.json +14 -10
- package/dist/chunk-27PCPE37.js.map +0 -1
- package/dist/chunk-R354OMWL.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -2,14 +2,16 @@ import * as _h_ai_core from '@h-ai/core';
|
|
|
2
2
|
import { HaiResult, ValidationFormError } from '@h-ai/core';
|
|
3
3
|
import { AIFunctions, AudioWsStartMessage, AudioFormat } from '@h-ai/ai';
|
|
4
4
|
import { AnyContractRouter, OpenAPI } from '@orpc/contract';
|
|
5
|
-
import { ProcedureHandler, ErrorMap, Meta, ProcedureHandlerOptions, ORPCErrorConstructorMap, Router
|
|
6
|
-
import { a as ServSession, S as ServContext, b as ServIam, R as RefreshCookieConfig, C as CreateServContext, c as ServRequestMetadata, p as parseRequestContext, d as buildAuthContextFactory } from './serv-context-
|
|
7
|
-
export { e as CreateServContextInput, N as NativeRefreshTokenTransportConfig, f as RefreshTokenPair } from './serv-context-
|
|
5
|
+
import { ProcedureHandler, ErrorMap, Meta, ProcedureHandlerOptions, ORPCErrorConstructorMap, Router } from '@orpc/server';
|
|
6
|
+
import { a as ServSession, S as ServContext, b as ServIam, R as RefreshCookieConfig, C as CreateServContext, c as ServRequestMetadata, p as parseRequestContext, d as buildAuthContextFactory } from './serv-context-C48WdBcd.js';
|
|
7
|
+
export { e as CreateServContextInput, N as NativeRefreshTokenTransportConfig, f as RefreshTokenPair } from './serv-context-C48WdBcd.js';
|
|
8
8
|
import { MiddlewareHandler } from 'hono';
|
|
9
9
|
import { z, ZodType } from 'zod';
|
|
10
|
-
import { CryptoFunctions, TransportKeyStore } from '@h-ai/crypto';
|
|
10
|
+
import { TransportServerKeyRing, CryptoFunctions, TransportKeyStore } from '@h-ai/crypto';
|
|
11
11
|
import { ServerType } from '@hono/node-server';
|
|
12
12
|
import { AddressInfo } from 'node:net';
|
|
13
|
+
import { i as implement } from './serv-router-BX8hgYxo.js';
|
|
14
|
+
export { A as AuthenticatedServContext, S as ServImplementer, a as ServRouteHandler, b as ServRoutePath, c as ServRouterBuilder } from './serv-router-BX8hgYxo.js';
|
|
13
15
|
import { StorageFunctions } from '@h-ai/storage';
|
|
14
16
|
|
|
15
17
|
/**
|
|
@@ -26,7 +28,18 @@ import { StorageFunctions } from '@h-ai/storage';
|
|
|
26
28
|
* @module features/serv-feature-audio
|
|
27
29
|
*/
|
|
28
30
|
|
|
29
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* 语音 WebSocket 接入依赖。
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* // 模块内部上下文:示例复用当前声明所在模块的实际绑定。
|
|
37
|
+
* function withAudioLimits(deps: AudioWsDeps): AudioWsDeps {
|
|
38
|
+
* return { ...deps, maxSessionMs: 60000, maxBufferedBytes: 1024 * 1024 }
|
|
39
|
+
* }
|
|
40
|
+
* // verifyTicket 必须原子消费共享的一次性票据,不能仅解析客户端身份。
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
30
43
|
interface AudioWsDeps {
|
|
31
44
|
/** AI 服务对象的语音能力(`ai.audio`)。 */
|
|
32
45
|
readonly ai: Pick<AIFunctions, 'audio'>;
|
|
@@ -59,21 +72,67 @@ interface AudioWsDeps {
|
|
|
59
72
|
* @module pipelines/serv-pipeline-types
|
|
60
73
|
*/
|
|
61
74
|
|
|
62
|
-
/**
|
|
75
|
+
/**
|
|
76
|
+
* Serv 层 Hono middleware。
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* import type { ServMiddleware } from '@h-ai/serv'
|
|
81
|
+
* import { serv } from '@h-ai/serv'
|
|
82
|
+
*
|
|
83
|
+
* const middleware: ServMiddleware = async (context, next) => {
|
|
84
|
+
* context.header('X-App-Version', '1')
|
|
85
|
+
* await next()
|
|
86
|
+
* }
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
63
89
|
type ServMiddleware = MiddlewareHandler;
|
|
64
90
|
/**
|
|
65
91
|
* Hono middleware 工厂类型。
|
|
66
92
|
*
|
|
67
93
|
* - 无配置 middleware:`ServMiddlewareFactory<void>`
|
|
68
94
|
* - 带配置 middleware:`ServMiddlewareFactory<MyConfig>`
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* import type { ServMiddlewareFactory } from '@h-ai/serv'
|
|
99
|
+
* import { serv } from '@h-ai/serv'
|
|
100
|
+
*
|
|
101
|
+
* const createTrace: ServMiddlewareFactory<{ header: string }> = config => async (context, next) => {
|
|
102
|
+
* context.header(config.header, 'enabled')
|
|
103
|
+
* await next()
|
|
104
|
+
* }
|
|
105
|
+
* const middleware = createTrace({ header: 'X-Trace-Enabled' })
|
|
106
|
+
* ```
|
|
69
107
|
*/
|
|
70
108
|
type ServMiddlewareFactory<TConfig = void> = [TConfig] extends [void] ? () => ServMiddleware : (config: TConfig) => ServMiddleware;
|
|
71
109
|
/**
|
|
72
110
|
* 使用 oRPC 公开 `ProcedureHandler` 定义的 HaiResult procedure handler。
|
|
73
111
|
*
|
|
74
112
|
* handler options 完整保留 oRPC 的路径、procedure、signal 与错误构造器信息。
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* import type { ServProcedureOptions } from '@h-ai/serv'
|
|
117
|
+
* import { serv } from '@h-ai/serv'
|
|
118
|
+
*
|
|
119
|
+
* function requestId(options: ServProcedureOptions<{ id: string }>) {
|
|
120
|
+
* return { id: options.input.id, requestId: options.context.requestId }
|
|
121
|
+
* }
|
|
122
|
+
* ```
|
|
75
123
|
*/
|
|
76
124
|
type ServProcedureOptions<TInput = unknown, TContext extends ServContext = ServContext> = ProcedureHandlerOptions<TContext, TInput, ORPCErrorConstructorMap<ErrorMap>, Meta>;
|
|
125
|
+
/**
|
|
126
|
+
* 基于 oRPC 真实 options 的 HaiResult handler;领域失败返回错误分支,异常由 route 包装收口。
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* import type { ServProcedureHandler } from '@h-ai/serv'
|
|
131
|
+
* import { serv } from '@h-ai/serv'
|
|
132
|
+
*
|
|
133
|
+
* const handler: ServProcedureHandler<{ id: string }, { id: string }> = async ({ input }) => ({ success: true, data: { id: input.id } })
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
77
136
|
type ServProcedureHandler<TInput, TOutput, TContext extends ServContext = ServContext> = ProcedureHandler<TContext, TInput, HaiResult<TOutput>, ErrorMap, Meta>;
|
|
78
137
|
|
|
79
138
|
/**
|
|
@@ -84,41 +143,125 @@ type ServProcedureHandler<TInput, TOutput, TContext extends ServContext = ServCo
|
|
|
84
143
|
* @module serv-config
|
|
85
144
|
*/
|
|
86
145
|
|
|
87
|
-
/**
|
|
146
|
+
/**
|
|
147
|
+
* 服务器监听配置(对应 `config/_serv.yml` 的 `server`)。
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```ts
|
|
151
|
+
* import type { ServServerConfig } from '@h-ai/serv'
|
|
152
|
+
* import { serv } from '@h-ai/serv'
|
|
153
|
+
*
|
|
154
|
+
* const config: ServServerConfig = { host: '127.0.0.1', port: 3000 }
|
|
155
|
+
* const bindAddress = config.host
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
88
158
|
interface ServServerConfig {
|
|
89
159
|
readonly host: string;
|
|
90
160
|
readonly port: number;
|
|
91
161
|
}
|
|
92
|
-
/**
|
|
162
|
+
/**
|
|
163
|
+
* `config/_serv.yml` 中的服务器监听输入类型。
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```ts
|
|
167
|
+
* import type { ServServerConfigInput } from '@h-ai/serv'
|
|
168
|
+
* import { serv } from '@h-ai/serv'
|
|
169
|
+
*
|
|
170
|
+
* const input: ServServerConfigInput = { port: 3000 }
|
|
171
|
+
* // HOST/PORT 的环境覆盖由配置解析完成后传给 listen。
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
93
174
|
type ServServerConfigInput = Partial<ServServerConfig>;
|
|
94
|
-
/**
|
|
175
|
+
/**
|
|
176
|
+
* OpenAPI JSON endpoint 配置。
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```ts
|
|
180
|
+
* import type { ServOpenAPIHttpConfig } from '@h-ai/serv'
|
|
181
|
+
* import { serv } from '@h-ai/serv'
|
|
182
|
+
*
|
|
183
|
+
* const openapi: ServOpenAPIHttpConfig = { path: '/openapi.json' }
|
|
184
|
+
* // 文档仅在 createApp.http 显式启用时挂载。
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
95
187
|
interface ServOpenAPIHttpConfig {
|
|
96
188
|
readonly path: `/${string}`;
|
|
97
189
|
}
|
|
98
|
-
/**
|
|
190
|
+
/**
|
|
191
|
+
* 文档页面 endpoint 配置。
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* import type { ServDocsHttpConfig } from '@h-ai/serv'
|
|
196
|
+
* import { serv } from '@h-ai/serv'
|
|
197
|
+
*
|
|
198
|
+
* const docs: ServDocsHttpConfig = { path: '/docs', requireAuth: true }
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
99
201
|
interface ServDocsHttpConfig {
|
|
100
202
|
readonly path: `/${string}`;
|
|
101
203
|
readonly requireAuth?: boolean;
|
|
102
204
|
}
|
|
103
|
-
/**
|
|
205
|
+
/**
|
|
206
|
+
* 健康检查 endpoint 配置。
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```ts
|
|
210
|
+
* import type { ServHealthHttpConfig } from '@h-ai/serv'
|
|
211
|
+
* import { serv } from '@h-ai/serv'
|
|
212
|
+
*
|
|
213
|
+
* const health: ServHealthHttpConfig = { path: '/health', readyPath: '/ready' }
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
104
216
|
interface ServHealthHttpConfig {
|
|
105
217
|
readonly path: `/${string}`;
|
|
106
218
|
readonly readyPath?: `/${string}`;
|
|
107
219
|
}
|
|
108
|
-
/**
|
|
220
|
+
/**
|
|
221
|
+
* 内部 RPC endpoint 配置。
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```ts
|
|
225
|
+
* import type { ServRpcHttpConfig } from '@h-ai/serv'
|
|
226
|
+
* import { serv } from '@h-ai/serv'
|
|
227
|
+
*
|
|
228
|
+
* const rpc: ServRpcHttpConfig = { prefix: '/rpc', access: 'loopback' }
|
|
229
|
+
* // 缺少可信连接信息时拒绝;跨节点来源通过明确网关/网络策略控制。
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
109
232
|
interface ServRpcHttpConfig {
|
|
110
233
|
readonly prefix: `/${string}`;
|
|
111
234
|
readonly access: 'loopback' | 'private-network' | 'gateway-only';
|
|
112
235
|
readonly gatewayHeader?: string;
|
|
113
236
|
readonly gatewaySecret?: string;
|
|
114
237
|
}
|
|
115
|
-
/**
|
|
238
|
+
/**
|
|
239
|
+
* 传输加密运行时配置(对应 `config/_serv.yml`)。
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```ts
|
|
243
|
+
* import type { ServTransportRuntimeConfig } from '@h-ai/serv'
|
|
244
|
+
* import { serv } from '@h-ai/serv'
|
|
245
|
+
*
|
|
246
|
+
* const transport: ServTransportRuntimeConfig = { keyExchangePath: '/_hai/key-exchange', excludePaths: ['/health'] }
|
|
247
|
+
* // 仅路径配置;真正启用还需私有 keyring 与共享 keyStore。
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
116
250
|
interface ServTransportRuntimeConfig {
|
|
117
251
|
readonly keyExchangePath: `/${string}`;
|
|
118
252
|
readonly excludePaths: readonly `/${string}`[];
|
|
119
|
-
readonly maxClients: number;
|
|
120
253
|
}
|
|
121
|
-
/**
|
|
254
|
+
/**
|
|
255
|
+
* `config/_serv.yml` 中可序列化的跨端 CORS 配置。
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* ```ts
|
|
259
|
+
* import type { ServCorsRuntimeConfig } from '@h-ai/serv'
|
|
260
|
+
* import { serv } from '@h-ai/serv'
|
|
261
|
+
*
|
|
262
|
+
* const cors: ServCorsRuntimeConfig = { origin: 'https://app.example.com', allowedHeaders: ['Authorization', 'Content-Type'], exposedHeaders: [], credentials: true }
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
122
265
|
interface ServCorsRuntimeConfig {
|
|
123
266
|
readonly origin?: string;
|
|
124
267
|
readonly nativeOrigins?: string;
|
|
@@ -126,7 +269,17 @@ interface ServCorsRuntimeConfig {
|
|
|
126
269
|
readonly exposedHeaders: readonly string[];
|
|
127
270
|
readonly credentials: boolean;
|
|
128
271
|
}
|
|
129
|
-
/**
|
|
272
|
+
/**
|
|
273
|
+
* ServHttpApp 的 HTTP 挂载配置。
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```ts
|
|
277
|
+
* import type { ServHttpConfig } from '@h-ai/serv'
|
|
278
|
+
* import { serv } from '@h-ai/serv'
|
|
279
|
+
*
|
|
280
|
+
* const http: ServHttpConfig = { trustedProxies: [], apiPrefix: '/api/v1', openapi: false, docs: false, health: { path: '/health' }, rpc: false }
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
130
283
|
interface ServHttpConfig {
|
|
131
284
|
/** 可信任的连接代理 IP/CIDR;默认空数组,不采纳转发头。 */
|
|
132
285
|
readonly trustedProxies: readonly string[];
|
|
@@ -136,22 +289,65 @@ interface ServHttpConfig {
|
|
|
136
289
|
readonly health: false | ServHealthHttpConfig;
|
|
137
290
|
readonly rpc: false | ServRpcHttpConfig;
|
|
138
291
|
}
|
|
139
|
-
/**
|
|
292
|
+
/**
|
|
293
|
+
* `config/_serv.yml` 的顶层配置结构。
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* ```ts
|
|
297
|
+
* import type { ServConfig } from '@h-ai/serv'
|
|
298
|
+
* import { serv } from '@h-ai/serv'
|
|
299
|
+
*
|
|
300
|
+
* import { ServConfigSchema } from '@h-ai/serv'
|
|
301
|
+
*
|
|
302
|
+
* const config: ServConfig = ServConfigSchema.parse({ server: { host: '127.0.0.1', port: 3000 } })
|
|
303
|
+
* const port = config.server.port
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
140
306
|
interface ServConfig {
|
|
141
307
|
readonly server: ServServerConfig;
|
|
142
308
|
readonly http: ServHttpConfig;
|
|
143
309
|
readonly cors: ServCorsRuntimeConfig;
|
|
144
310
|
readonly transport: false | ServTransportRuntimeConfig;
|
|
145
311
|
}
|
|
146
|
-
/**
|
|
312
|
+
/**
|
|
313
|
+
* `config/_serv.yml` 中的 CORS 输入类型。
|
|
314
|
+
*
|
|
315
|
+
* @example
|
|
316
|
+
* ```ts
|
|
317
|
+
* import type { ServCorsRuntimeConfigInput } from '@h-ai/serv'
|
|
318
|
+
* import { serv } from '@h-ai/serv'
|
|
319
|
+
*
|
|
320
|
+
* const input: ServCorsRuntimeConfigInput = { origin: 'https://app.example.com', credentials: true }
|
|
321
|
+
* ```
|
|
322
|
+
*/
|
|
147
323
|
type ServCorsRuntimeConfigInput = Partial<ServCorsRuntimeConfig>;
|
|
148
|
-
/**
|
|
324
|
+
/**
|
|
325
|
+
* `config/_serv.yml` 中的传输加密输入类型。
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```ts
|
|
329
|
+
* import type { ServTransportRuntimeConfigInput } from '@h-ai/serv'
|
|
330
|
+
* import { serv } from '@h-ai/serv'
|
|
331
|
+
*
|
|
332
|
+
* const input: ServTransportRuntimeConfigInput = { keyExchangePath: '/_hai/key-exchange' }
|
|
333
|
+
* // 此输入不包含私钥;私有 Secret 仅在服务端运行时装配。
|
|
334
|
+
* ```
|
|
335
|
+
*/
|
|
149
336
|
type ServTransportRuntimeConfigInput = Partial<{
|
|
150
337
|
readonly keyExchangePath: `/${string}`;
|
|
151
338
|
readonly excludePaths: readonly `/${string}`[];
|
|
152
|
-
readonly maxClients: number;
|
|
153
339
|
}>;
|
|
154
|
-
/**
|
|
340
|
+
/**
|
|
341
|
+
* `serv.createApp` 接受的 HTTP 配置入参类型。
|
|
342
|
+
*
|
|
343
|
+
* @example
|
|
344
|
+
* ```ts
|
|
345
|
+
* import type { ServHttpConfigInput } from '@h-ai/serv'
|
|
346
|
+
* import { serv } from '@h-ai/serv'
|
|
347
|
+
*
|
|
348
|
+
* const http: ServHttpConfigInput = { apiPrefix: '/api/v2', trustedProxies: ['192.0.2.0/24'], docs: false }
|
|
349
|
+
* ```
|
|
350
|
+
*/
|
|
155
351
|
type ServHttpConfigInput = Partial<{
|
|
156
352
|
readonly trustedProxies: readonly string[];
|
|
157
353
|
readonly apiPrefix: `/api/${string}`;
|
|
@@ -160,14 +356,40 @@ type ServHttpConfigInput = Partial<{
|
|
|
160
356
|
readonly health: false | Partial<ServHealthHttpConfig>;
|
|
161
357
|
readonly rpc: false | Partial<ServRpcHttpConfig>;
|
|
162
358
|
}>;
|
|
163
|
-
/**
|
|
359
|
+
/**
|
|
360
|
+
* `config/_serv.yml` 的顶层输入类型。
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```ts
|
|
364
|
+
* import type { ServConfigInput } from '@h-ai/serv'
|
|
365
|
+
* import { serv } from '@h-ai/serv'
|
|
366
|
+
*
|
|
367
|
+
* import { ServConfigSchema } from '@h-ai/serv'
|
|
368
|
+
*
|
|
369
|
+
* const input: ServConfigInput = { http: { apiPrefix: '/api/v2' }, transport: false }
|
|
370
|
+
* const parsed = ServConfigSchema.safeParse(input)
|
|
371
|
+
* if (!parsed.success) throw new Error('Invalid service configuration')
|
|
372
|
+
* ```
|
|
373
|
+
*/
|
|
164
374
|
interface ServConfigInput {
|
|
165
375
|
readonly server?: ServServerConfigInput;
|
|
166
376
|
readonly http?: ServHttpConfigInput;
|
|
167
377
|
readonly cors?: ServCorsRuntimeConfigInput;
|
|
168
378
|
readonly transport?: false | ServTransportRuntimeConfigInput;
|
|
169
379
|
}
|
|
170
|
-
/**
|
|
380
|
+
/**
|
|
381
|
+
* `config/_serv.yml` 对应的配置 Schema。
|
|
382
|
+
*
|
|
383
|
+
* @example
|
|
384
|
+
* ```ts
|
|
385
|
+
* import { ServConfigSchema } from '@h-ai/serv'
|
|
386
|
+
*
|
|
387
|
+
* const parsed = ServConfigSchema.safeParse({ http: { apiPrefix: '/api/v1', docs: false } })
|
|
388
|
+
* if (parsed.success) {
|
|
389
|
+
* const host = parsed.data.server.host
|
|
390
|
+
* }
|
|
391
|
+
* ```
|
|
392
|
+
*/
|
|
171
393
|
declare const ServConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
172
394
|
server: z.ZodOptional<z.ZodObject<{
|
|
173
395
|
host: z.ZodDefault<z.ZodString>;
|
|
@@ -208,7 +430,6 @@ declare const ServConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
208
430
|
transport: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<false>, z.ZodObject<{
|
|
209
431
|
keyExchangePath: z.ZodDefault<z.ZodCustom<`/${string}`, `/${string}`>>;
|
|
210
432
|
excludePaths: z.ZodDefault<z.ZodArray<z.ZodCustom<`/${string}`, `/${string}`>>>;
|
|
211
|
-
maxClients: z.ZodDefault<z.ZodNumber>;
|
|
212
433
|
}, z.core.$strip>]>>;
|
|
213
434
|
}, z.core.$strip>, z.ZodTransform<{
|
|
214
435
|
server: ServServerConfig;
|
|
@@ -251,7 +472,6 @@ declare const ServConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
251
472
|
transport?: false | {
|
|
252
473
|
keyExchangePath: `/${string}`;
|
|
253
474
|
excludePaths: `/${string}`[];
|
|
254
|
-
maxClients: number;
|
|
255
475
|
} | undefined;
|
|
256
476
|
}>>;
|
|
257
477
|
|
|
@@ -273,8 +493,25 @@ declare const ServConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
273
493
|
* @module serv-transport
|
|
274
494
|
*/
|
|
275
495
|
|
|
276
|
-
/**
|
|
496
|
+
/**
|
|
497
|
+
* {@link createApp} 的 `transport` 配置项。
|
|
498
|
+
*
|
|
499
|
+
* @example
|
|
500
|
+
* ```ts
|
|
501
|
+
* import type { ServTransportConfig } from '@h-ai/serv'
|
|
502
|
+
* import { serv } from '@h-ai/serv'
|
|
503
|
+
*
|
|
504
|
+
* import { crypto } from '@h-ai/crypto'
|
|
505
|
+
*
|
|
506
|
+
* function configure(serverKeyRing: ServTransportConfig['serverKeyRing'], keyStore: ServTransportConfig['keyStore']): ServTransportConfig {
|
|
507
|
+
* return { crypto, serverKeyRing, keyStore }
|
|
508
|
+
* }
|
|
509
|
+
* // 私有 keyring 跨节点共享并支持轮换;生产 keyStore 原子消费重放标识,不能用进程 Map。
|
|
510
|
+
* ```
|
|
511
|
+
*/
|
|
277
512
|
interface ServTransportConfig {
|
|
513
|
+
/** 受管服务端密钥环,仅运行时从私有 Secret 注入。 */
|
|
514
|
+
readonly serverKeyRing: TransportServerKeyRing;
|
|
278
515
|
/**
|
|
279
516
|
* crypto 服务实例。serv 通过 `crypto.transport.createServer()` 创建
|
|
280
517
|
* 传输加密管理器,并使用 `crypto.transport.protocol` 中的协议常量。
|
|
@@ -290,9 +527,7 @@ interface ServTransportConfig {
|
|
|
290
527
|
*/
|
|
291
528
|
readonly excludePaths?: readonly string[];
|
|
292
529
|
/** 共享客户端公钥存储;适用于多节点部署。 */
|
|
293
|
-
readonly keyStore
|
|
294
|
-
/** 服务端可缓存的客户端公钥数量上限。默认 10000。 */
|
|
295
|
-
readonly maxClients?: number;
|
|
530
|
+
readonly keyStore: TransportKeyStore;
|
|
296
531
|
}
|
|
297
532
|
|
|
298
533
|
/**
|
|
@@ -319,6 +554,15 @@ interface ServTransportConfig {
|
|
|
319
554
|
* - `path` 省略时默认挂到 `'*'`
|
|
320
555
|
* - 按数组顺序注册
|
|
321
556
|
* - 注册位置固定在内置 `securityHeaders` 之后、`transport` / 业务路由之前
|
|
557
|
+
*
|
|
558
|
+
* @example
|
|
559
|
+
* ```ts
|
|
560
|
+
* import type { ServMiddlewareMount } from '@h-ai/serv'
|
|
561
|
+
* import { serv } from '@h-ai/serv'
|
|
562
|
+
*
|
|
563
|
+
* const mount: ServMiddlewareMount = { path: '/api/v1/*', middleware: serv.cors({ origin: 'https://app.example.com' }) }
|
|
564
|
+
* // middleware 在 transport 之前运行;短路响应不会经过传输加密。
|
|
565
|
+
* ```
|
|
322
566
|
*/
|
|
323
567
|
interface ServMiddlewareMount {
|
|
324
568
|
readonly path?: string;
|
|
@@ -330,6 +574,17 @@ interface ServMiddlewareMount {
|
|
|
330
574
|
* Hono 是当前内部实现细节,应用代码只应依赖此最小接口:
|
|
331
575
|
* - `fetch`:部署到 Fetch-first 运行时或交给 `serv.listen()`。
|
|
332
576
|
* - `request`:测试 / 本地直连时发起 in-process 请求,避免消费方 import Hono。
|
|
577
|
+
*
|
|
578
|
+
* @example
|
|
579
|
+
* ```ts
|
|
580
|
+
* import type { ServHttpApp } from '@h-ai/serv'
|
|
581
|
+
* import { serv } from '@h-ai/serv'
|
|
582
|
+
*
|
|
583
|
+
* async function health(app: ServHttpApp): Promise<boolean> {
|
|
584
|
+
* const response = await app.request('/health')
|
|
585
|
+
* return response.ok
|
|
586
|
+
* }
|
|
587
|
+
* ```
|
|
333
588
|
*/
|
|
334
589
|
interface ServHttpApp {
|
|
335
590
|
readonly fetch: (request: Request, metadata?: ServRequestMetadata) => Response | Promise<Response>;
|
|
@@ -347,10 +602,20 @@ interface ServHttpApp {
|
|
|
347
602
|
* - **`refreshCookie`**(可选):浏览器默认用 httpOnly cookie;受信原生客户端可配置 body 通道。与 `iam` 正交:
|
|
348
603
|
* `iam` 决定 *谁* 验证 token,`refreshCookie` 决定 refresh token *怎么* 传输。
|
|
349
604
|
*
|
|
350
|
-
* - **`verifyToken`**(高级):不使用 IAM
|
|
605
|
+
* - **`verifyToken`**(高级):不使用 IAM 模块的覆盖入口。优先于 `iam.auth.verifyToken`。
|
|
351
606
|
*
|
|
352
607
|
* - **`createContext`**(高级):完全接管上下文构造,设置后 serv **不再**自动填充 session,
|
|
353
608
|
* 由调用方负责。
|
|
609
|
+
*
|
|
610
|
+
* @example
|
|
611
|
+
* ```ts
|
|
612
|
+
* import type { CreateServAppOptions } from '@h-ai/serv'
|
|
613
|
+
* import { serv } from '@h-ai/serv'
|
|
614
|
+
*
|
|
615
|
+
* function mount<TContract extends Parameters<typeof serv.createApp>[0]['contract'], TProcedures extends Parameters<typeof serv.createApp>[0]['procedures']>(options: CreateServAppOptions<TContract, TProcedures>) {
|
|
616
|
+
* return serv.createApp(options)
|
|
617
|
+
* }
|
|
618
|
+
* ```
|
|
354
619
|
*/
|
|
355
620
|
interface CreateServAppOptions<TContract extends AnyContractRouter, TProcedures extends Router<AnyContractRouter, ServContext>> {
|
|
356
621
|
readonly contract: TContract;
|
|
@@ -389,14 +654,10 @@ interface CreateServAppOptions<TContract extends AnyContractRouter, TProcedures
|
|
|
389
654
|
readonly createContext?: CreateServContext;
|
|
390
655
|
/**
|
|
391
656
|
* 启用传输加密(opt-in)。提供后 serv 自动:
|
|
392
|
-
* 1.
|
|
657
|
+
* 1. 使用显式 serverKeyRing / keyStore 创建受管传输管理器
|
|
393
658
|
* 2. 在 oRPC 路由之前挂载中间件,自动解密请求 / 加密响应
|
|
394
659
|
* 3. 在 `${apiPrefix}${keyExchangePath}` 暴露 POST 密钥协商端点
|
|
395
660
|
*
|
|
396
|
-
* @example
|
|
397
|
-
* ```ts
|
|
398
|
-
* serv.createApp({ contract, procedures, transport: { crypto } })
|
|
399
|
-
* ```
|
|
400
661
|
*/
|
|
401
662
|
readonly transport?: ServTransportConfig;
|
|
402
663
|
/**
|
|
@@ -407,14 +668,25 @@ interface CreateServAppOptions<TContract extends AnyContractRouter, TProcedures
|
|
|
407
668
|
*
|
|
408
669
|
* 需配合 `serv.listen()`(Node 适配器会自动完成 WebSocket 升级注入)。
|
|
409
670
|
*
|
|
410
|
-
* @example
|
|
411
|
-
* ```ts
|
|
412
|
-
* serv.createApp({ contract, procedures, iam, audio: { ai, verifyTicket, authorize } })
|
|
413
|
-
* ```
|
|
414
671
|
*/
|
|
415
672
|
readonly audio?: ServAudioConfig;
|
|
416
673
|
}
|
|
417
|
-
/**
|
|
674
|
+
/**
|
|
675
|
+
* `serv.createApp()` 的语音 WebSocket 接入配置。
|
|
676
|
+
*
|
|
677
|
+
* @example
|
|
678
|
+
* ```ts
|
|
679
|
+
* import type { ServAudioConfig } from '@h-ai/serv'
|
|
680
|
+
* import { serv } from '@h-ai/serv'
|
|
681
|
+
*
|
|
682
|
+
* import { ai } from '@h-ai/ai'
|
|
683
|
+
*
|
|
684
|
+
* function configureAudio(verifyTicket: ServAudioConfig['verifyTicket']): ServAudioConfig {
|
|
685
|
+
* return { ai, verifyTicket, preAuthTimeoutMs: 3000, maxSessionMs: 60000 }
|
|
686
|
+
* }
|
|
687
|
+
* // 应用实现 verifyTicket:原子消费共享票据并返回可信 session/grant。
|
|
688
|
+
* ```
|
|
689
|
+
*/
|
|
418
690
|
interface ServAudioConfig {
|
|
419
691
|
/** AI 服务对象(提供 `ai.audio` 领域能力)。 */
|
|
420
692
|
readonly ai: AudioWsDeps['ai'];
|
|
@@ -453,7 +725,18 @@ interface ServAudioConfig {
|
|
|
453
725
|
/** 发送缓冲高水位(字节,默认 8 MiB):`ws.bufferedAmount` 超过即以领域错误关闭慢客户端。 */
|
|
454
726
|
readonly maxSendBufferBytes?: number;
|
|
455
727
|
}
|
|
456
|
-
/**
|
|
728
|
+
/**
|
|
729
|
+
* Audio ticket 绑定的能力授权(消费时原样返回,供服务端交叉校验 start 帧)。
|
|
730
|
+
*
|
|
731
|
+
* @example
|
|
732
|
+
* ```ts
|
|
733
|
+
* import type { AudioTicketGrant } from '@h-ai/serv'
|
|
734
|
+
* import { serv } from '@h-ai/serv'
|
|
735
|
+
*
|
|
736
|
+
* const grant: AudioTicketGrant = { operation: 'synthesize', model: 'speech-model', sessionId: 'session-1' }
|
|
737
|
+
* // 签发时绑定;start 帧不能覆盖服务端核准的模型与操作。
|
|
738
|
+
* ```
|
|
739
|
+
*/
|
|
457
740
|
interface AudioTicketGrant {
|
|
458
741
|
/** 允许的操作 */
|
|
459
742
|
readonly operation?: 'transcribe' | 'synthesize';
|
|
@@ -464,14 +747,38 @@ interface AudioTicketGrant {
|
|
|
464
747
|
/** 应用自定义绑定字段 */
|
|
465
748
|
readonly [key: string]: unknown;
|
|
466
749
|
}
|
|
467
|
-
/**
|
|
750
|
+
/**
|
|
751
|
+
* Audio ticket 验证结果:IAM 会话 + 可选能力授权。
|
|
752
|
+
*
|
|
753
|
+
* @example
|
|
754
|
+
* ```ts
|
|
755
|
+
* import type { AudioTicketVerification } from '@h-ai/serv'
|
|
756
|
+
* import { serv } from '@h-ai/serv'
|
|
757
|
+
*
|
|
758
|
+
* function verified(session: AudioTicketVerification['session']): AudioTicketVerification {
|
|
759
|
+
* return { session, grant: { operation: 'transcribe' } }
|
|
760
|
+
* }
|
|
761
|
+
* // session 必须来自成功消费的可信票据,不能从客户端 JSON 直接构造。
|
|
762
|
+
* ```
|
|
763
|
+
*/
|
|
468
764
|
interface AudioTicketVerification {
|
|
469
765
|
/** IAM 会话摘要 */
|
|
470
766
|
readonly session: ServSession;
|
|
471
767
|
/** 票据绑定的能力授权(如有) */
|
|
472
768
|
readonly grant?: AudioTicketGrant;
|
|
473
769
|
}
|
|
474
|
-
/**
|
|
770
|
+
/**
|
|
771
|
+
* Audio WebSocket 经应用授权后允许生效的服务端参数。
|
|
772
|
+
*
|
|
773
|
+
* @example
|
|
774
|
+
* ```ts
|
|
775
|
+
* import type { AuthorizedAudioRequest } from '@h-ai/serv'
|
|
776
|
+
* import { serv } from '@h-ai/serv'
|
|
777
|
+
*
|
|
778
|
+
* const request: AuthorizedAudioRequest = { operation: 'synthesize', format: 'mp3' }
|
|
779
|
+
* // model/voice/instruction 只有经应用 authorize 确认后才生效。
|
|
780
|
+
* ```
|
|
781
|
+
*/
|
|
475
782
|
interface AuthorizedAudioRequest {
|
|
476
783
|
readonly operation: 'transcribe' | 'synthesize';
|
|
477
784
|
/** 服务端允许的模型 ID;不传时使用 `ai.audio` 对应操作的默认模型。 */
|
|
@@ -482,23 +789,24 @@ interface AuthorizedAudioRequest {
|
|
|
482
789
|
readonly sampleRate?: number;
|
|
483
790
|
}
|
|
484
791
|
/**
|
|
485
|
-
* 创建并装配 HTTP
|
|
792
|
+
* 创建并装配 HTTP app;同步校验配置和依赖,返回可交给 Node 或标准 fetch 适配器的应用。
|
|
486
793
|
*
|
|
487
|
-
* @param options - contract
|
|
488
|
-
* @returns
|
|
794
|
+
* @param options - contract、procedures、HTTP、安全和可选能力依赖
|
|
795
|
+
* @returns 不拥有业务模块生命周期的 ServHttpApp
|
|
796
|
+
* @throws 配置或必需依赖缺失时在装配阶段抛错,宿主须停止启动并清理已初始化资源。
|
|
489
797
|
*
|
|
490
798
|
* @example
|
|
491
799
|
* ```ts
|
|
492
|
-
*
|
|
493
|
-
*
|
|
494
|
-
*
|
|
495
|
-
*
|
|
496
|
-
*
|
|
497
|
-
*
|
|
498
|
-
*
|
|
499
|
-
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
800
|
+
* import type { ServContext } from '@h-ai/serv'
|
|
801
|
+
* import { apiContract } from '@h-ai/api-contract'
|
|
802
|
+
* import { serv } from '@h-ai/serv'
|
|
803
|
+
*
|
|
804
|
+
* const contract = apiContract.create({})
|
|
805
|
+
* const procedures = serv.implement(contract).context<ServContext>().build()
|
|
806
|
+
* const app = serv.createApp({ contract, procedures })
|
|
807
|
+
*
|
|
808
|
+
* const response = await app.request('/health')
|
|
809
|
+
* const healthy = response.ok
|
|
502
810
|
* ```
|
|
503
811
|
*/
|
|
504
812
|
declare function createApp<TContract extends AnyContractRouter, TProcedures extends Router<AnyContractRouter, ServContext>>(options: CreateServAppOptions<TContract, TProcedures>): ServHttpApp;
|
|
@@ -507,35 +815,49 @@ declare function createApp<TContract extends AnyContractRouter, TProcedures exte
|
|
|
507
815
|
* @h-ai/serv — Fetch 适配器
|
|
508
816
|
*
|
|
509
817
|
* 将 ServHttpApp 包装为标准 Web `fetch(Request)` 处理函数,
|
|
510
|
-
*
|
|
818
|
+
* 用于 Node 兼容宿主与客户端测试的标准 fetch 注入;部署仍须满足包的 Node API 依赖。
|
|
511
819
|
* @module adapters/serv-adapter-fetch
|
|
512
820
|
*/
|
|
513
821
|
|
|
514
822
|
/**
|
|
515
|
-
*
|
|
823
|
+
* 标准 fetch 签名类型,供 Node 兼容宿主或客户端 in-process 测试注入。签名兼容不代表包整体不依赖 Node API,也不承诺未经验证的边缘部署。
|
|
516
824
|
*
|
|
517
|
-
*
|
|
518
|
-
*
|
|
519
|
-
*
|
|
825
|
+
* @example
|
|
826
|
+
* ```ts
|
|
827
|
+
* import type { ServFetchHandler } from '@h-ai/serv'
|
|
828
|
+
* import { serv } from '@h-ai/serv'
|
|
829
|
+
*
|
|
830
|
+
* function handle(app: Parameters<typeof serv.toFetch>[0]): ServFetchHandler {
|
|
831
|
+
* return serv.toFetch(app)
|
|
832
|
+
* }
|
|
833
|
+
* // 兼容 fetch 签名;宿主仍须支持此包的 Node 依赖。
|
|
834
|
+
* ```
|
|
520
835
|
*/
|
|
521
836
|
type ServFetchHandler = typeof fetch;
|
|
522
837
|
/**
|
|
523
|
-
*
|
|
838
|
+
* 将应用转换为标准 fetch 签名,供 Node 兼容宿主或客户端测试注入;签名适配不代表整个包可在无 Node API 的边缘运行时加载。
|
|
524
839
|
*
|
|
525
|
-
*
|
|
526
|
-
*
|
|
840
|
+
* RequestInit 的覆盖与正文锁定/消费检查交由标准 Request 构造器处理,不修改原 Request 的字段。
|
|
841
|
+
* 取消会拒绝响应等待并传递给应用,不能撤回 handler 已产生的外部效果;响应交付后的流取消由应用消费 signal。
|
|
842
|
+
*
|
|
843
|
+
* @param app - createApp 返回的应用
|
|
844
|
+
* @returns fetch 兼容处理器
|
|
845
|
+
* @throws 返回的 Promise 可因 Request 构造错误、取消或下游异常而 reject;成功返回 Response。
|
|
527
846
|
*
|
|
528
847
|
* @example
|
|
529
848
|
* ```ts
|
|
530
|
-
*
|
|
531
|
-
*
|
|
849
|
+
* import type { ServContext } from '@h-ai/serv'
|
|
850
|
+
* import { apiContract } from '@h-ai/api-contract'
|
|
851
|
+
* import { serv } from '@h-ai/serv'
|
|
532
852
|
*
|
|
533
|
-
*
|
|
534
|
-
*
|
|
853
|
+
* const contract = apiContract.create({})
|
|
854
|
+
* const procedures = serv.implement(contract).context<ServContext>().build()
|
|
855
|
+
* const app = serv.createApp({ contract, procedures })
|
|
535
856
|
*
|
|
536
|
-
*
|
|
537
|
-
* const
|
|
538
|
-
* await
|
|
857
|
+
* const fetchHandler = serv.toFetch(app)
|
|
858
|
+
* const request = new Request('http://service.test/health')
|
|
859
|
+
* const response = await fetchHandler(request, { headers: { 'x-hai-locale': 'en-US' } })
|
|
860
|
+
* const ready = response.ok
|
|
539
861
|
* ```
|
|
540
862
|
*/
|
|
541
863
|
declare function toFetch(app: ServHttpApp): ServFetchHandler;
|
|
@@ -548,7 +870,18 @@ declare function toFetch(app: ServHttpApp): ServFetchHandler;
|
|
|
548
870
|
* @module adapters/serv-adapter-node
|
|
549
871
|
*/
|
|
550
872
|
|
|
551
|
-
/**
|
|
873
|
+
/**
|
|
874
|
+
* Node 服务器启动配置。
|
|
875
|
+
*
|
|
876
|
+
* @example
|
|
877
|
+
* ```ts
|
|
878
|
+
* import type { ServListenOptions } from '@h-ai/serv'
|
|
879
|
+
* import { serv } from '@h-ai/serv'
|
|
880
|
+
*
|
|
881
|
+
* const options: ServListenOptions = { host: '127.0.0.1', port: 3000 }
|
|
882
|
+
* // HOST/PORT 与配置文件的解析由应用显式完成后传入。
|
|
883
|
+
* ```
|
|
884
|
+
*/
|
|
552
885
|
interface ServListenOptions {
|
|
553
886
|
/**
|
|
554
887
|
* 监听端口。
|
|
@@ -578,7 +911,20 @@ interface ServListenOptions {
|
|
|
578
911
|
*/
|
|
579
912
|
readonly onClose?: () => Promise<void>;
|
|
580
913
|
}
|
|
581
|
-
/**
|
|
914
|
+
/**
|
|
915
|
+
* Node 服务运行句柄。
|
|
916
|
+
*
|
|
917
|
+
* @example
|
|
918
|
+
* ```ts
|
|
919
|
+
* import type { ServNodeServer } from '@h-ai/serv'
|
|
920
|
+
* import { serv } from '@h-ai/serv'
|
|
921
|
+
*
|
|
922
|
+
* async function stop(handle: ServNodeServer) {
|
|
923
|
+
* await handle.close()
|
|
924
|
+
* }
|
|
925
|
+
* // close 只关闭监听句柄;业务资源由宿主生命周期关闭。
|
|
926
|
+
* ```
|
|
927
|
+
*/
|
|
582
928
|
interface ServNodeServer {
|
|
583
929
|
/** 底层 Node.js HTTP Server 实例。 */
|
|
584
930
|
readonly server: ServerType;
|
|
@@ -594,7 +940,7 @@ interface ServNodeServer {
|
|
|
594
940
|
* 在 Node.js 中启动 ServHttpApp。
|
|
595
941
|
*
|
|
596
942
|
* 默认监听 `127.0.0.1:3000`;host/port 建议由应用从 `serv` 配置的 `server`
|
|
597
|
-
|
|
943
|
+
* (支持 `HOST` / `PORT` 环境变量覆盖,环境变量高于配置文件)解析后显式传入。
|
|
598
944
|
* 传入 `onClose` 后自动注册 SIGINT/SIGTERM 优雅关闭,应用层无需手动处理信号。
|
|
599
945
|
*
|
|
600
946
|
* @param app - `serv.createApp()` 返回的 HTTP app
|
|
@@ -603,14 +949,16 @@ interface ServNodeServer {
|
|
|
603
949
|
*
|
|
604
950
|
* @example
|
|
605
951
|
* ```ts
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
* serv
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
612
|
-
*
|
|
613
|
-
*
|
|
952
|
+
* import type { ServContext } from '@h-ai/serv'
|
|
953
|
+
* import { apiContract } from '@h-ai/api-contract'
|
|
954
|
+
* import { serv } from '@h-ai/serv'
|
|
955
|
+
*
|
|
956
|
+
* const contract = apiContract.create({})
|
|
957
|
+
* const procedures = serv.implement(contract).context<ServContext>().build()
|
|
958
|
+
* const app = serv.createApp({ contract, procedures })
|
|
959
|
+
*
|
|
960
|
+
* const server = serv.listen(app, { host: '127.0.0.1', port: 3000 })
|
|
961
|
+
* await server.close()
|
|
614
962
|
* ```
|
|
615
963
|
*/
|
|
616
964
|
declare function listen(app: ServHttpApp, options?: ServListenOptions): ServNodeServer;
|
|
@@ -622,7 +970,18 @@ declare function listen(app: ServHttpApp, options?: ServListenOptions): ServNode
|
|
|
622
970
|
* @module serv-cors
|
|
623
971
|
*/
|
|
624
972
|
|
|
625
|
-
/**
|
|
973
|
+
/**
|
|
974
|
+
* serv CORS 配置。
|
|
975
|
+
*
|
|
976
|
+
* @example
|
|
977
|
+
* ```ts
|
|
978
|
+
* import type { ServCorsConfig } from '@h-ai/serv'
|
|
979
|
+
* import { serv } from '@h-ai/serv'
|
|
980
|
+
*
|
|
981
|
+
* const config: ServCorsConfig = { origin: 'https://app.example.com', credentials: true, exposedHeaders: ['X-Request-Id'] }
|
|
982
|
+
* const middleware = serv.cors(config)
|
|
983
|
+
* ```
|
|
984
|
+
*/
|
|
626
985
|
interface ServCorsConfig {
|
|
627
986
|
/** 允许的 origin:`'*'`、单个字符串、数组或自定义匹配函数。默认 `'*'`。 */
|
|
628
987
|
readonly origin?: '*' | string | readonly string[] | ((origin: string) => boolean);
|
|
@@ -637,7 +996,17 @@ interface ServCorsConfig {
|
|
|
637
996
|
/** 预检缓存秒数。默认 `86400`。 */
|
|
638
997
|
readonly maxAge?: number;
|
|
639
998
|
}
|
|
640
|
-
/**
|
|
999
|
+
/**
|
|
1000
|
+
* 创建可复用的 CORS middleware。
|
|
1001
|
+
*
|
|
1002
|
+
* @example
|
|
1003
|
+
* ```ts
|
|
1004
|
+
* import { serv } from '@h-ai/serv'
|
|
1005
|
+
*
|
|
1006
|
+
* const middleware = serv.cors({ origin: ['https://app.example.com'], credentials: true })
|
|
1007
|
+
* // 生产策略由 createRuntimeSecurityPolicy 先收敛 Origin,避免误用通配符。
|
|
1008
|
+
* ```
|
|
1009
|
+
*/
|
|
641
1010
|
declare function cors(config?: ServCorsConfig): ServMiddleware;
|
|
642
1011
|
|
|
643
1012
|
/**
|
|
@@ -648,7 +1017,17 @@ declare function cors(config?: ServCorsConfig): ServMiddleware;
|
|
|
648
1017
|
* @module serv-openapi
|
|
649
1018
|
*/
|
|
650
1019
|
|
|
651
|
-
/**
|
|
1020
|
+
/**
|
|
1021
|
+
* OpenAPI spec 生成配置。
|
|
1022
|
+
*
|
|
1023
|
+
* @example
|
|
1024
|
+
* ```ts
|
|
1025
|
+
* import type { GenerateOpenAPISpecOptions } from '@h-ai/serv'
|
|
1026
|
+
* import { serv } from '@h-ai/serv'
|
|
1027
|
+
*
|
|
1028
|
+
* const options: GenerateOpenAPISpecOptions = { title: 'Reports API', version: '1.0.0', apiPrefix: '/api/v1' }
|
|
1029
|
+
* ```
|
|
1030
|
+
*/
|
|
652
1031
|
interface GenerateOpenAPISpecOptions {
|
|
653
1032
|
readonly title?: string;
|
|
654
1033
|
readonly version?: string;
|
|
@@ -656,117 +1035,60 @@ interface GenerateOpenAPISpecOptions {
|
|
|
656
1035
|
readonly description?: string;
|
|
657
1036
|
}
|
|
658
1037
|
/**
|
|
659
|
-
*
|
|
1038
|
+
* 由真实应用 contract 生成 OpenAPI 3.1 文档。
|
|
660
1039
|
*
|
|
661
|
-
* @param contract -
|
|
662
|
-
* @param options -
|
|
663
|
-
* @returns OpenAPI
|
|
1040
|
+
* @param contract - 应用 contract
|
|
1041
|
+
* @param options - 标题、版本、描述与服务前缀
|
|
1042
|
+
* @returns OpenAPI 文档
|
|
1043
|
+
* @throws 底层转换器不能处理该 Schema 时 reject,调用方在启动或导出边界处理。
|
|
664
1044
|
*
|
|
665
1045
|
* @example
|
|
666
1046
|
* ```ts
|
|
667
|
-
*
|
|
668
|
-
*
|
|
669
|
-
*
|
|
670
|
-
*
|
|
671
|
-
*
|
|
1047
|
+
* import { apiContract } from '@h-ai/api-contract'
|
|
1048
|
+
* import { serv } from '@h-ai/serv'
|
|
1049
|
+
*
|
|
1050
|
+
* const spec = await serv.generateSpec(apiContract.create({}), { title: 'Reports API', version: '1.0.0', apiPrefix: '/api/v1' })
|
|
1051
|
+
* const title = spec.info.title
|
|
672
1052
|
* ```
|
|
673
1053
|
*/
|
|
674
1054
|
declare function generateSpec(contract: AnyContractRouter, options?: GenerateOpenAPISpecOptions): Promise<OpenAPI.Document>;
|
|
675
1055
|
|
|
676
1056
|
/**
|
|
677
|
-
* @h-ai/serv —
|
|
678
|
-
*
|
|
679
|
-
* 在 oRPC `implement()` 之上提供 route 名只出现一次的链式 DSL。
|
|
680
|
-
* 应用只接触 contract 路径、上下文与 guard,不需要组装 oRPC router 对象。
|
|
681
|
-
*
|
|
682
|
-
* @module serv-router
|
|
683
|
-
*/
|
|
684
|
-
|
|
685
|
-
type EmptyContext = Record<never, never>;
|
|
686
|
-
type StringKey<T> = Extract<keyof T, string>;
|
|
687
|
-
type ServContract = ContractRouter<Meta>;
|
|
688
|
-
/** contract 中所有 procedure 的点分路径。 */
|
|
689
|
-
type ServRoutePath<TContract extends ServContract> = TContract extends ContractProcedure<infer _TInputSchema, infer _TOutputSchema, infer _TErrorMap, infer _TMeta> ? never : {
|
|
690
|
-
[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;
|
|
691
|
-
}[StringKey<TContract>];
|
|
692
|
-
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;
|
|
693
|
-
type RouteContract<TContract extends ServContract, TPath extends ServRoutePath<TContract>> = ContractAtPath<TContract, TPath>;
|
|
694
|
-
/** `.auth()`、`.permission()`、`.role()` 后的非空会话上下文。 */
|
|
695
|
-
type AuthenticatedServContext<TContext extends ServContext = ServContext> = TContext & {
|
|
696
|
-
readonly session: NonNullable<TContext['session']>;
|
|
697
|
-
};
|
|
698
|
-
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;
|
|
699
|
-
/** 从 contract procedure 精确推导当前 route 的 HaiResult handler。 */
|
|
700
|
-
type ServRouteHandler<TContract extends ServContract, TPath extends ServRoutePath<TContract>, TContext extends Context> = RouteHandler<RouteContract<TContract, TPath>, TContext>;
|
|
701
|
-
type ServGuardedRouteHandler<TContract extends ServContract, TPath extends ServRoutePath<TContract>, TContext extends ServContext> = RouteHandler<RouteContract<TContract, TPath>, AuthenticatedServContext<TContext>>;
|
|
702
|
-
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>>;
|
|
703
|
-
/** 尚未声明 guard 的单 route 注册器。 */
|
|
704
|
-
interface ServRouteRegistration<TContract extends ServContract, TInitialContext extends Context, TCurrentContext extends ServContext, TRemaining extends ServRoutePath<TContract>, TPath extends TRemaining> {
|
|
705
|
-
readonly auth: () => ServGuardedRouteRegistration<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
|
|
706
|
-
readonly permission: (permission: string) => ServGuardedRouteRegistration<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
|
|
707
|
-
readonly role: (role: string) => ServGuardedRouteRegistration<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
|
|
708
|
-
}
|
|
709
|
-
/** 已声明认证或授权 guard 的单 route 注册器。 */
|
|
710
|
-
interface ServGuardedRouteRegistration<TContract extends ServContract, TInitialContext extends Context, TCurrentContext extends ServContext, TRemaining extends ServRoutePath<TContract>, TPath extends TRemaining> {
|
|
711
|
-
readonly auth: () => ServGuardedRouteRegistration<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
|
|
712
|
-
readonly permission: (permission: string) => ServGuardedRouteRegistration<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
|
|
713
|
-
readonly role: (role: string) => ServGuardedRouteRegistration<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
|
|
714
|
-
readonly handle: (handler: ServGuardedRouteHandler<TContract, TPath, TCurrentContext>) => NextBuilder<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
|
|
715
|
-
}
|
|
716
|
-
interface ServRouteMethod<TContract extends ServContract, TInitialContext extends Context, TCurrentContext extends ServContext, TRemaining extends ServRoutePath<TContract>> {
|
|
717
|
-
<TPath extends TRemaining>(path: TPath, handler: ServRouteHandler<TContract, TPath, TCurrentContext>): NextBuilder<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
|
|
718
|
-
<TPath extends TRemaining>(path: TPath): ServRouteRegistration<TContract, TInitialContext, TCurrentContext, TRemaining, TPath>;
|
|
719
|
-
}
|
|
720
|
-
type ServRouterBuilderBuild<TContract extends ServContract, TInitialContext extends Context, TRemaining> = [TRemaining] extends [never] ? {
|
|
721
|
-
/** 同步返回完整的普通 router,允许按需选用嵌套的默认 procedures。 */
|
|
722
|
-
readonly build: () => UnlaziedRouter<Router<TContract, TInitialContext>>;
|
|
723
|
-
} : {
|
|
724
|
-
/** 仅供 TypeScript/IDE 展示尚未实现的 route;运行时不存在。 */
|
|
725
|
-
readonly missingRoutes: TRemaining;
|
|
726
|
-
};
|
|
727
|
-
/**
|
|
728
|
-
* 链式 router builder。
|
|
1057
|
+
* @h-ai/serv — 部署环境 HTTP 安全策略
|
|
729
1058
|
*
|
|
730
|
-
*
|
|
1059
|
+
* 将环境与 CORS 配置收敛为 fail-closed 的运行时策略,避免每个业务应用重复实现
|
|
1060
|
+
* Origin 解析、生产通配符保护、Cookie Secure 与 API 文档暴露规则。
|
|
1061
|
+
* @module serv-runtime-security
|
|
731
1062
|
*/
|
|
732
|
-
type ServRouterBuilder<TContract extends ServContract, TInitialContext extends Context, TCurrentContext extends ServContext, TRemaining extends ServRoutePath<TContract> = ServRoutePath<TContract>> = {
|
|
733
|
-
readonly route: ServRouteMethod<TContract, TInitialContext, TCurrentContext, TRemaining>;
|
|
734
|
-
} & ServRouterBuilderBuild<TContract, TInitialContext, TRemaining>;
|
|
735
|
-
/** hai-framework 链式 contract 实现器。 */
|
|
736
|
-
interface ServImplementer<TContract extends ServContract> {
|
|
737
|
-
readonly context: <TContext extends ServContext>() => ServRouterBuilder<TContract, TContext & EmptyContext, TContext>;
|
|
738
|
-
}
|
|
739
1063
|
/**
|
|
740
|
-
*
|
|
1064
|
+
* 运行时安全策略输入;通常来自 `_core.yml.env` 与 `_serv.yml.cors`。
|
|
741
1065
|
*
|
|
742
1066
|
* @example
|
|
743
1067
|
* ```ts
|
|
744
|
-
* serv
|
|
745
|
-
*
|
|
746
|
-
* .context<ServContext>()
|
|
747
|
-
* .route('info', infoHandler)
|
|
748
|
-
* .route('echo')
|
|
749
|
-
* .auth()
|
|
750
|
-
* .handle(echoHandler)
|
|
751
|
-
* .build()
|
|
752
|
-
* ```
|
|
753
|
-
*/
|
|
754
|
-
declare function implement<TContract extends ServContract>(contract: TContract): ServImplementer<TContract>;
|
|
755
|
-
|
|
756
|
-
/**
|
|
757
|
-
* @h-ai/serv — 部署环境 HTTP 安全策略
|
|
1068
|
+
* import type { ServRuntimeSecurityPolicyInput } from '@h-ai/serv'
|
|
1069
|
+
* import { serv } from '@h-ai/serv'
|
|
758
1070
|
*
|
|
759
|
-
*
|
|
760
|
-
*
|
|
761
|
-
*
|
|
1071
|
+
* const input: ServRuntimeSecurityPolicyInput = { environment: 'production', corsOrigin: 'https://app.example.com' }
|
|
1072
|
+
* const policy = serv.createRuntimeSecurityPolicy(input)
|
|
1073
|
+
* ```
|
|
762
1074
|
*/
|
|
763
|
-
/** 运行时安全策略输入;通常来自 `_core.yml.env` 与 `_serv.yml.cors`。 */
|
|
764
1075
|
interface ServRuntimeSecurityPolicyInput {
|
|
765
1076
|
readonly environment?: string;
|
|
766
1077
|
readonly corsOrigin?: string;
|
|
767
1078
|
readonly nativeOrigins?: string;
|
|
768
1079
|
}
|
|
769
|
-
/**
|
|
1080
|
+
/**
|
|
1081
|
+
* 可直接装配到 CORS、refresh cookie 与 HTTP 文档配置的安全策略。
|
|
1082
|
+
*
|
|
1083
|
+
* @example
|
|
1084
|
+
* ```ts
|
|
1085
|
+
* import type { ServRuntimeSecurityPolicy } from '@h-ai/serv'
|
|
1086
|
+
* import { serv } from '@h-ai/serv'
|
|
1087
|
+
*
|
|
1088
|
+
* const policy: ServRuntimeSecurityPolicy = serv.createRuntimeSecurityPolicy({ environment: 'production', corsOrigin: 'https://app.example.com' })
|
|
1089
|
+
* const allowed = policy.allowOrigin('https://app.example.com')
|
|
1090
|
+
* ```
|
|
1091
|
+
*/
|
|
770
1092
|
interface ServRuntimeSecurityPolicy {
|
|
771
1093
|
readonly allowOrigin: (origin: string) => boolean;
|
|
772
1094
|
readonly isNativeOrigin: (origin: string) => boolean;
|
|
@@ -774,9 +1096,19 @@ interface ServRuntimeSecurityPolicy {
|
|
|
774
1096
|
readonly exposeApiDocs: boolean;
|
|
775
1097
|
}
|
|
776
1098
|
/**
|
|
777
|
-
*
|
|
1099
|
+
* 校验部署 Origin 并生成 Cookie、文档与跨端 CORS 安全策略。
|
|
1100
|
+
*
|
|
1101
|
+
* @param input - 部署环境与显式允许的 Web/原生 Origin
|
|
1102
|
+
* @returns 可用于 HTTP 装配的策略
|
|
1103
|
+
* @throws Origin 非法,或 production 缺少明确 Web Origin/使用通配符时抛配置错误。
|
|
778
1104
|
*
|
|
779
|
-
*
|
|
1105
|
+
* @example
|
|
1106
|
+
* ```ts
|
|
1107
|
+
* import { serv } from '@h-ai/serv'
|
|
1108
|
+
*
|
|
1109
|
+
* const policy = serv.createRuntimeSecurityPolicy({ environment: 'production', corsOrigin: 'https://app.example.com' })
|
|
1110
|
+
* const middleware = serv.cors({ origin: policy.allowOrigin, credentials: true })
|
|
1111
|
+
* ```
|
|
780
1112
|
*/
|
|
781
1113
|
declare function createRuntimeSecurityPolicy(input: ServRuntimeSecurityPolicyInput): ServRuntimeSecurityPolicy;
|
|
782
1114
|
|
|
@@ -788,11 +1120,32 @@ declare function createRuntimeSecurityPolicy(input: ServRuntimeSecurityPolicyInp
|
|
|
788
1120
|
* @module serv-storage-assets
|
|
789
1121
|
*/
|
|
790
1122
|
|
|
791
|
-
/**
|
|
1123
|
+
/**
|
|
1124
|
+
* 可由只读资源 middleware 使用的最小 Storage 能力。
|
|
1125
|
+
*
|
|
1126
|
+
* @example
|
|
1127
|
+
* ```ts
|
|
1128
|
+
* // 模块内部上下文:示例复用当前声明所在模块的实际绑定。
|
|
1129
|
+
* function withStorage(source: StorageAssetSource): ServStorageAssetsConfig {
|
|
1130
|
+
* return { storage: source, pathPrefix: '/assets/', keyPattern: new RegExp('^public/[a-z0-9-]+[.]webp$'), allowedContentTypes: ['image/webp'] }
|
|
1131
|
+
* }
|
|
1132
|
+
* ```
|
|
1133
|
+
*/
|
|
792
1134
|
interface StorageAssetSource {
|
|
793
1135
|
readonly file: Pick<StorageFunctions['file'], 'get' | 'head'>;
|
|
794
1136
|
}
|
|
795
|
-
/**
|
|
1137
|
+
/**
|
|
1138
|
+
* Storage 只读资源 middleware 配置。
|
|
1139
|
+
*
|
|
1140
|
+
* @example
|
|
1141
|
+
* ```ts
|
|
1142
|
+
* import { serv } from '@h-ai/serv'
|
|
1143
|
+
* import { storage } from '@h-ai/storage'
|
|
1144
|
+
*
|
|
1145
|
+
* // 仅发布明确公共资源;私有业务资源另执行可信资源授权。
|
|
1146
|
+
* const middleware = serv.storageAssets({ storage, pathPrefix: '/assets/', keyPattern: new RegExp('^public/[a-z0-9-]+[.]webp$'), allowedContentTypes: ['image/webp'], cacheControl: 'public, max-age=3600' })
|
|
1147
|
+
* ```
|
|
1148
|
+
*/
|
|
796
1149
|
interface ServStorageAssetsConfig {
|
|
797
1150
|
/** 已初始化的 Storage 模块或等价文件读取能力。 */
|
|
798
1151
|
readonly storage: StorageAssetSource;
|
|
@@ -818,15 +1171,14 @@ interface ServStorageAssetsConfig {
|
|
|
818
1171
|
*
|
|
819
1172
|
* @param config - Storage、路径、key、MIME 与缓存策略。
|
|
820
1173
|
* @returns 可挂载到 `serv.createApp({ middlewares })` 的 middleware。
|
|
1174
|
+
*
|
|
821
1175
|
* @example
|
|
822
1176
|
* ```ts
|
|
823
|
-
*
|
|
824
|
-
*
|
|
825
|
-
*
|
|
826
|
-
*
|
|
827
|
-
*
|
|
828
|
-
* cacheControl: 'public, max-age=31536000, immutable',
|
|
829
|
-
* })
|
|
1177
|
+
* import { serv } from '@h-ai/serv'
|
|
1178
|
+
* import { storage } from '@h-ai/storage'
|
|
1179
|
+
*
|
|
1180
|
+
* // 仅发布明确公共资源;私有业务资源另执行可信资源授权。
|
|
1181
|
+
* const middleware = serv.storageAssets({ storage, pathPrefix: '/assets/', keyPattern: new RegExp('^public/[a-z0-9-]+[.]webp$'), allowedContentTypes: ['image/webp'], cacheControl: 'public, max-age=3600' })
|
|
830
1182
|
* ```
|
|
831
1183
|
*/
|
|
832
1184
|
declare function storageAssets(config: ServStorageAssetsConfig): ServMiddleware;
|
|
@@ -848,6 +1200,17 @@ declare function storageAssets(config: ServStorageAssetsConfig): ServMiddleware;
|
|
|
848
1200
|
* 复用 `HaiResult` 失败分支结构。字段错误同时在两处出现:
|
|
849
1201
|
* - `error.cause`:与 `validateInputOrFail` 输出对齐,HaiResult 标准位置
|
|
850
1202
|
* - 顶层 `errors`:保留以兼容已有客户端
|
|
1203
|
+
*
|
|
1204
|
+
* @example
|
|
1205
|
+
* ```ts
|
|
1206
|
+
* import type { ServValidationFailureBody } from '@h-ai/serv'
|
|
1207
|
+
* import { serv } from '@h-ai/serv'
|
|
1208
|
+
*
|
|
1209
|
+
* function fields(body: ServValidationFailureBody) {
|
|
1210
|
+
* return body.error.cause ?? body.errors
|
|
1211
|
+
* }
|
|
1212
|
+
* // 业务调用先判断 success,字段错误仅包含安全的本地化文案。
|
|
1213
|
+
* ```
|
|
851
1214
|
*/
|
|
852
1215
|
interface ServValidationFailureBody {
|
|
853
1216
|
readonly success: false;
|
|
@@ -869,6 +1232,14 @@ interface ServValidationFailureBody {
|
|
|
869
1232
|
*
|
|
870
1233
|
* @param headers - 请求头(`Headers` 或与之等价的对象)
|
|
871
1234
|
* @returns 解析得到的 locale
|
|
1235
|
+
*
|
|
1236
|
+
* @example
|
|
1237
|
+
* ```ts
|
|
1238
|
+
* import { serv } from '@h-ai/serv'
|
|
1239
|
+
*
|
|
1240
|
+
* const locale = serv.resolveRequestLocale(new Headers({ 'x-hai-locale': 'en-US' }))
|
|
1241
|
+
* const fallback = serv.resolveRequestLocale(new Headers())
|
|
1242
|
+
* ```
|
|
872
1243
|
*/
|
|
873
1244
|
declare function resolveRequestLocale(headers: Headers | Record<string, string | undefined>): string;
|
|
874
1245
|
/**
|
|
@@ -898,10 +1269,39 @@ declare function resolveRequestLocale(headers: Headers | Record<string, string |
|
|
|
898
1269
|
* @param schema - Zod schema
|
|
899
1270
|
* @param input - 待校验数据
|
|
900
1271
|
* @param locale - 期望 locale(通常来自请求上下文)
|
|
1272
|
+
*
|
|
1273
|
+
* @example
|
|
1274
|
+
* ```ts
|
|
1275
|
+
* import { serv } from '@h-ai/serv'
|
|
1276
|
+
* import { z } from 'zod'
|
|
1277
|
+
*
|
|
1278
|
+
* const result = serv.validateInputOrFail(z.object({ name: z.string().min(1) }), { name: '' }, 'en-US')
|
|
1279
|
+
* if (!result.success) {
|
|
1280
|
+
* const fields = result.error.cause
|
|
1281
|
+
* } else {
|
|
1282
|
+
* const name = result.data.name
|
|
1283
|
+
* }
|
|
1284
|
+
* ```
|
|
901
1285
|
*/
|
|
902
1286
|
declare function validateInputOrFail<TOutput>(schema: ZodType<TOutput>, input: unknown, locale?: string): HaiResult<TOutput>;
|
|
903
1287
|
|
|
904
|
-
/**
|
|
1288
|
+
/**
|
|
1289
|
+
* hai-framework API service runtime 统一入口(扁平 API)。
|
|
1290
|
+
*
|
|
1291
|
+
* @example
|
|
1292
|
+
* ```ts
|
|
1293
|
+
* import type { ServContext } from '@h-ai/serv'
|
|
1294
|
+
* import { apiContract } from '@h-ai/api-contract'
|
|
1295
|
+
* import { serv } from '@h-ai/serv'
|
|
1296
|
+
*
|
|
1297
|
+
* const contract = apiContract.create({})
|
|
1298
|
+
* const procedures = serv.implement(contract).context<ServContext>().build()
|
|
1299
|
+
* const app = serv.createApp({ contract, procedures })
|
|
1300
|
+
*
|
|
1301
|
+
* const response = await app.request('/health')
|
|
1302
|
+
* if (!response.ok) throw new Error('Health request failed')
|
|
1303
|
+
* ```
|
|
1304
|
+
*/
|
|
905
1305
|
declare const serv: {
|
|
906
1306
|
createApp: typeof createApp;
|
|
907
1307
|
parseRequestContext: typeof parseRequestContext;
|
|
@@ -920,4 +1320,4 @@ declare const serv: {
|
|
|
920
1320
|
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;
|
|
921
1321
|
};
|
|
922
1322
|
|
|
923
|
-
export { type AudioTicketGrant, type AudioTicketVerification, type
|
|
1323
|
+
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 ServHealthHttpConfig, type ServHttpApp, type ServHttpConfig, type ServHttpConfigInput, ServIam, type ServListenOptions, type ServMiddleware, type ServMiddlewareFactory, type ServMiddlewareMount, type ServNodeServer, type ServOpenAPIHttpConfig, type ServProcedureHandler, type ServProcedureOptions, ServRequestMetadata, type ServRpcHttpConfig, type ServRuntimeSecurityPolicy, type ServRuntimeSecurityPolicyInput, type ServServerConfig, type ServServerConfigInput, ServSession, type ServStorageAssetsConfig, type ServTransportConfig, type ServTransportRuntimeConfig, type ServTransportRuntimeConfigInput, type ServValidationFailureBody, serv };
|