@taicode/common-server 4.0.0-beta.1 → 4.0.0-beta.2
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/output/app/boot.d.ts +0 -9
- package/output/app/boot.d.ts.map +1 -1
- package/output/app/boot.js +32 -15
- package/output/app/context.d.ts +3 -1
- package/output/app/context.d.ts.map +1 -1
- package/output/app/context.js +1 -1
- package/output/app/core/index.d.ts +3 -3
- package/output/app/core/index.d.ts.map +1 -1
- package/output/app/core/index.js +1 -1
- package/output/app/core/response.d.ts +8 -8
- package/output/app/core/response.d.ts.map +1 -1
- package/output/app/core/response.js +6 -6
- package/output/app/define-server.negative-cases.d.ts +8 -0
- package/output/app/define-server.negative-cases.d.ts.map +1 -1
- package/output/app/define-server.negative-cases.js +60 -1
- package/output/app/error-contract.test.js +110 -8
- package/output/app/index.d.ts +1 -1
- package/output/app/index.d.ts.map +1 -1
- package/output/app/resources.test.js +4 -2
- package/output/app/shutdown.test.js +1 -1
- package/output/app/types.d.ts +18 -1
- package/output/app/types.d.ts.map +1 -1
- package/package.json +3 -3
package/output/app/boot.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ErrorClassifier } from './core/response.js';
|
|
2
1
|
import type { ConfigEnv } from './env.js';
|
|
3
2
|
import type { ResourcesView, Server, ShutdownContext } from './types.js';
|
|
4
3
|
import type { FastifyInstance } from 'fastify';
|
|
@@ -22,14 +21,6 @@ export interface BootedServer<R, S> {
|
|
|
22
21
|
services: Awaited<S>;
|
|
23
22
|
dispose: () => Promise<void>;
|
|
24
23
|
}
|
|
25
|
-
/**
|
|
26
|
-
* 资源包里的数据层错误分类器。
|
|
27
|
-
*
|
|
28
|
-
* 约定:`resources(ctx)` 返回的资源包里**任一**提供 `classifyError` 函数的值都会被用上
|
|
29
|
-
* (框架不提供数据层 helper;由服务仓在资源包里自行提供一个带 `classifyError` 的值)。
|
|
30
|
-
* 都没有 → 返回 `undefined`,响应层落 `UNKNOWN_ERROR` 兜底。
|
|
31
|
-
*/
|
|
32
|
-
export declare function resolveErrorClassifier(resources: Record<string, unknown>): ErrorClassifier | undefined;
|
|
33
24
|
/**
|
|
34
25
|
* 装配一个服务(`startServer` / `generateOpenApi` 共用)。
|
|
35
26
|
*
|
package/output/app/boot.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"boot.d.ts","sourceRoot":"","sources":["../../source/app/boot.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"boot.d.ts","sourceRoot":"","sources":["../../source/app/boot.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACzC,OAAO,KAAK,EAAgC,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACtG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAE9C,qFAAqF;AACrF,eAAO,MAAM,gBAAgB,UAAU,CAAA;AACvC,eAAO,MAAM,kBAAkB,YAAY,CAAA;AAC3C,mBAAmB;AACnB,MAAM,MAAM,SAAS,GAAG,OAAO,gBAAgB,GAAG,OAAO,kBAAkB,CAAA;AAC3E,aAAa;AACb,eAAO,MAAM,YAAY,YAAY,CAAA;AAErC,MAAM,WAAW,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IACvB,GAAG,EAAE,SAAS,CAAA;IACd,KAAK,EAAE,SAAS,CAAA;IAChB,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC5D;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,EAAE,CAAC;IAChC,GAAG,EAAE,eAAe,CAAA;IACpB,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;IAC3B,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IACpB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAqCD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CA6GhG"}
|
package/output/app/boot.js
CHANGED
|
@@ -16,23 +16,31 @@ function resolvePort(env) {
|
|
|
16
16
|
}
|
|
17
17
|
return parsed;
|
|
18
18
|
}
|
|
19
|
-
function isRecord(value) {
|
|
20
|
-
return typeof value === 'object' && value !== null;
|
|
21
|
-
}
|
|
22
19
|
/**
|
|
23
|
-
*
|
|
20
|
+
* 把各资源通过 `ctx.registerClassifyError` 注册的错误分类器合成单个分类器。
|
|
21
|
+
*
|
|
22
|
+
* 范式:**一个资源一个分类器,各管各的错误域**(认领不了就返回 `null` 交给下一个)。
|
|
24
23
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
* - 零个 → `undefined`(响应层落 `UNKNOWN_ERROR` 兜底);
|
|
25
|
+
* - 一个 → 原样返回(少一层包装);
|
|
26
|
+
* - 多个 → 按**注册顺序**串成链,返回第一个非 `null` 的结果(短路)。
|
|
28
27
|
*/
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
function combineClassifiers(classifiers) {
|
|
29
|
+
if (classifiers.length === 0) {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
if (classifiers.length === 1) {
|
|
33
|
+
return classifiers[0];
|
|
34
34
|
}
|
|
35
|
-
return
|
|
35
|
+
return (error) => {
|
|
36
|
+
for (const classifier of classifiers) {
|
|
37
|
+
const result = classifier(error);
|
|
38
|
+
if (result !== null) {
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
};
|
|
36
44
|
}
|
|
37
45
|
/**
|
|
38
46
|
* 装配一个服务(`startServer` / `generateOpenApi` 共用)。
|
|
@@ -60,13 +68,22 @@ export async function bootServer(input) {
|
|
|
60
68
|
const disposer = new Disposer();
|
|
61
69
|
const holder = createConfigHolder();
|
|
62
70
|
// ② resources:只构造,不建连(出 spec 路径同样执行)
|
|
63
|
-
|
|
71
|
+
// 资源错误分类器由各资源通过 `ctx.registerClassifyError` 各自注册:在调 `resources(ctx)` 前建局部收集器,
|
|
72
|
+
// 返回后把注册结果按注册顺序合成单个分类器喂给 core。
|
|
73
|
+
const classifiers = [];
|
|
74
|
+
const resources = (await server.resources(createResourcesContext({
|
|
75
|
+
env,
|
|
76
|
+
log,
|
|
77
|
+
registerClassifyError: (classifier) => {
|
|
78
|
+
classifiers.push(classifier);
|
|
79
|
+
},
|
|
80
|
+
})));
|
|
64
81
|
const resourcesView = liveResources(resources);
|
|
65
82
|
// ③ core 装配(schema → cookie → response → openapi → 路由注册表)
|
|
66
83
|
await registerCore(app, {
|
|
67
84
|
identity: server.app,
|
|
68
85
|
env,
|
|
69
|
-
|
|
86
|
+
classifyResourceError: combineClassifiers(classifiers),
|
|
70
87
|
readConfig: (key) => readConfigKey(requireConfig(holder), key),
|
|
71
88
|
});
|
|
72
89
|
// ── compose ──────────────────────────────────────────────────────────────
|
package/output/app/context.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Disposer } from '@taicode/common-base';
|
|
2
2
|
import type { ConfigEnv } from './env.js';
|
|
3
|
-
import type { AppInstance, ConfigContext, LoggerLike, MiddlewareContext, ResourcesContext, ResourcesView, RouterContext, ServiceContext, ShutdownContext } from './types.js';
|
|
3
|
+
import type { AppInstance, ConfigContext, ErrorClassifier, LoggerLike, MiddlewareContext, ResourcesContext, ResourcesView, RouterContext, ServiceContext, ShutdownContext } from './types.js';
|
|
4
4
|
/**
|
|
5
5
|
* 分阶段 ctx 的运行时构造(N1 §2)。
|
|
6
6
|
*
|
|
@@ -23,6 +23,8 @@ export declare function readConfigKey(config: unknown, key: string): unknown;
|
|
|
23
23
|
export interface ResourcesContextParams {
|
|
24
24
|
env: ConfigEnv;
|
|
25
25
|
log: LoggerLike;
|
|
26
|
+
/** 收集器:`bootServer` 注入,把各资源注册的分类器按注册顺序收起来 */
|
|
27
|
+
registerClassifyError: (classifier: ErrorClassifier) => void;
|
|
26
28
|
}
|
|
27
29
|
export declare function createResourcesContext(params: ResourcesContextParams): ResourcesContext;
|
|
28
30
|
/** `config(ctx)` 入参 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../source/app/context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACzC,OAAO,KAAK,EACV,WAAW,EACX,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,cAAc,EACd,eAAe,EAChB,MAAM,YAAY,CAAA;AAEnB;;;;;;GAMG;AAEH,+CAA+C;AAC/C,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQxE;AAED,uDAAuD;AACvD,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,SAAS,CAAA;CAChC;AAED,wBAAgB,kBAAkB,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC,CAAC,CAEvD;AAED,0DAA0D;AAC1D,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CASpE;AAED,+CAA+C;AAC/C,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAEnE;AAED,0BAA0B;AAC1B,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,SAAS,CAAA;IACd,GAAG,EAAE,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../source/app/context.ts"],"names":[],"mappings":"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"}
|
package/output/app/context.js
CHANGED
|
@@ -31,7 +31,7 @@ export function readConfigKey(config, key) {
|
|
|
31
31
|
return config?.[key];
|
|
32
32
|
}
|
|
33
33
|
export function createResourcesContext(params) {
|
|
34
|
-
return { env: params.env, log: params.log };
|
|
34
|
+
return { env: params.env, log: params.log, registerClassifyError: params.registerClassifyError };
|
|
35
35
|
}
|
|
36
36
|
export function createConfigContext(params) {
|
|
37
37
|
return { env: params.env, log: params.log, resources: params.resources };
|
|
@@ -9,7 +9,7 @@ export { registerRequestId, REQUEST_ID_HEADER, REQUEST_ID_LOG_LABEL } from './re
|
|
|
9
9
|
export { createLoggerOptions, LOG_REDACT_PATHS } from './logging.js';
|
|
10
10
|
export { SERVER_IDENTITY, attachServerIdentity, readServerIdentity } from './identity.js';
|
|
11
11
|
export type { AuthCookieOptions, CookieCoreOptions } from './cookie.js';
|
|
12
|
-
export type { ResponseCoreOptions, ResponseEnvelope } from './response.js';
|
|
12
|
+
export type { ResponseCoreOptions, ResponseEnvelope, ErrorClassifier } from './response.js';
|
|
13
13
|
export type { OpenApiCoreOptions } from './openapi.js';
|
|
14
14
|
/**
|
|
15
15
|
* core `schema`(设计 §5.1)——**框架内置、锁定、不可替换/修改**。
|
|
@@ -30,8 +30,8 @@ export interface CoreRegistrationOptions {
|
|
|
30
30
|
/** 身份块(`service` / `title` / `version`):openapi + 内置单元从这里读 */
|
|
31
31
|
identity: AppIdentity;
|
|
32
32
|
env: ConfigEnv;
|
|
33
|
-
/**
|
|
34
|
-
|
|
33
|
+
/** 资源错误分类(各资源经 `ctx.registerClassifyError` 注册;缺省 = 落 `UNKNOWN_ERROR`) */
|
|
34
|
+
classifyResourceError?: ErrorClassifier;
|
|
35
35
|
/** 取**已加载**配置中某个键的访问器(cookie domain 等**惰性**取值;不得在构造期调用) */
|
|
36
36
|
readConfig: (key: string) => unknown;
|
|
37
37
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/app/core/index.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAE9C,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AACrF,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAC5F,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAChF,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAC5F,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AACpE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAEzF,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AACvE,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/app/core/index.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAE9C,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AACrF,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAC5F,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAChF,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAC5F,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AACpE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAEzF,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AACvE,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAC3F,YAAY,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAEtD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI,CAMzD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,SAAS,GAAG,eAAe,CAM7D;AAED,gBAAgB;AAChB,MAAM,WAAW,uBAAuB;IACtC,8DAA8D;IAC9D,QAAQ,EAAE,WAAW,CAAA;IACrB,GAAG,EAAE,SAAS,CAAA;IACd,yEAAyE;IACzE,qBAAqB,CAAC,EAAE,eAAe,CAAA;IACvC,2DAA2D;IAC3D,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;CACrC;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAaxG"}
|
package/output/app/core/index.js
CHANGED
|
@@ -45,7 +45,7 @@ export async function registerCore(app, options) {
|
|
|
45
45
|
attachServerIdentity(app, options.identity);
|
|
46
46
|
registerSchema(app); // schema → zod compiler
|
|
47
47
|
registerCookie(app, { env: options.env, readConfig: options.readConfig });
|
|
48
|
-
registerResponse(app, {
|
|
48
|
+
registerResponse(app, { classifyResourceError: options.classifyResourceError });
|
|
49
49
|
// await:确定性冲刷插件队列,保证 swagger 的 root `onRoute` 钩子在路由注册之前就位
|
|
50
50
|
await registerOpenApi(app, {
|
|
51
51
|
title: options.identity.title,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { SystemError } from '../errors.js';
|
|
2
1
|
import type { FastifyInstance } from 'fastify';
|
|
2
|
+
import type { ErrorClassifier } from '../types.js';
|
|
3
3
|
/**
|
|
4
4
|
* core `response`(设计 §5.1 / §8,错误契约 D7)——**框架内置、锁定、不可替换/修改**。
|
|
5
5
|
*
|
|
6
6
|
* - 成功信封 `{ status: 'SUCCESS', message: 'ok', data }`(由 `preSerialization` 统一包裹)。
|
|
7
7
|
* - 错误信封 `{ status: <错误码字符串>, message, data: null }`。
|
|
8
8
|
* - `setErrorHandler` 固定分支:`UserError`→400(`error.status` 字面量)/ `SystemError`→500 /
|
|
9
|
-
* zod→400 / serde→500 /
|
|
9
|
+
* zod→400 / serde→500 / 资源(各资源 `ctx.registerClassifyError` 注册的分类器)→500 / 未知→500;**禁止按 `error.type` 细分**。
|
|
10
10
|
* - `setNotFoundHandler` → 404 + `NOT_IMPLEMENTED`(落 `warn`,文案对齐 expense/notice)。
|
|
11
11
|
* - 错误日志分级:`UserError` / zod → `warn`,其余 → `error`(带 stack)。
|
|
12
12
|
* - **错误只给稳定码**(`status` 放错误码字符串),文案不归框架(由前端 / i18n 决定,§10-6)。
|
|
@@ -27,15 +27,15 @@ export interface ResponseEnvelope<T> {
|
|
|
27
27
|
export declare function createSuccessResponse<T>(data: T): ResponseEnvelope<T>;
|
|
28
28
|
export declare function createErrorResponse(status: string, message: string): ResponseEnvelope<null>;
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
30
|
+
* 资源错误分类器(单一来源:`types.ts`)。
|
|
31
31
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
32
|
+
* **每个资源注册自己的分类器**(一个资源一个,各管各的错误域);由服务仓在 `resources(ctx)` 里
|
|
33
|
+
* 通过 `ctx.registerClassifyError` 注册;未注册时错误落 `UNKNOWN_ERROR` 兜底。
|
|
34
34
|
*/
|
|
35
|
-
export type ErrorClassifier
|
|
35
|
+
export type { ErrorClassifier };
|
|
36
36
|
export interface ResponseCoreOptions {
|
|
37
|
-
/**
|
|
38
|
-
|
|
37
|
+
/** 资源错误分类(各资源经 `ctx.registerClassifyError` 注册;缺省 = 不做资源错误分类) */
|
|
38
|
+
classifyResourceError?: ErrorClassifier;
|
|
39
39
|
}
|
|
40
40
|
export declare function registerResponse(app: FastifyInstance, options?: ResponseCoreOptions): void;
|
|
41
41
|
//# sourceMappingURL=response.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../../source/app/core/response.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../../source/app/core/response.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElD;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,cAAc,YAAY,CAAA;AACvC,eAAO,MAAM,sBAAsB,oBAAoB,CAAA;AACvD,eAAO,MAAM,oBAAoB,kBAAkB,CAAA;AACnD,eAAO,MAAM,0BAA0B,iCAAiC,CAAA;AACxE,eAAO,MAAM,oBAAoB,kBAAkB,CAAA;AAEnD,uCAAuC;AACvC,eAAO,MAAM,oBAAoB,6BAAS,CAAA;AAC1C,eAAO,MAAM,sBAAsB,6BAAS,CAAA;AAE5C,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,CAAC,CAAA;CACR;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAErE;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAE3F;AAsBD;;;;;GAKG;AACH,YAAY,EAAE,eAAe,EAAE,CAAA;AAE/B,MAAM,WAAW,mBAAmB;IAClC,gEAAgE;IAChE,qBAAqB,CAAC,EAAE,eAAe,CAAA;CACxC;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,GAAE,mBAAwB,GAAG,IAAI,CAyD9F"}
|
|
@@ -6,7 +6,7 @@ import { SystemError, UserError } from '../errors.js';
|
|
|
6
6
|
* - 成功信封 `{ status: 'SUCCESS', message: 'ok', data }`(由 `preSerialization` 统一包裹)。
|
|
7
7
|
* - 错误信封 `{ status: <错误码字符串>, message, data: null }`。
|
|
8
8
|
* - `setErrorHandler` 固定分支:`UserError`→400(`error.status` 字面量)/ `SystemError`→500 /
|
|
9
|
-
* zod→400 / serde→500 /
|
|
9
|
+
* zod→400 / serde→500 / 资源(各资源 `ctx.registerClassifyError` 注册的分类器)→500 / 未知→500;**禁止按 `error.type` 细分**。
|
|
10
10
|
* - `setNotFoundHandler` → 404 + `NOT_IMPLEMENTED`(落 `warn`,文案对齐 expense/notice)。
|
|
11
11
|
* - 错误日志分级:`UserError` / zod → `warn`,其余 → `error`(带 stack)。
|
|
12
12
|
* - **错误只给稳定码**(`status` 放错误码字符串),文案不归框架(由前端 / i18n 决定,§10-6)。
|
|
@@ -72,13 +72,13 @@ export function registerResponse(app, options = {}) {
|
|
|
72
72
|
request.log.error({ err: error }, '[response] response serialization error');
|
|
73
73
|
return reply.code(500).send(createErrorResponse(SERIALIZATION_ERROR_STATUS, error.message));
|
|
74
74
|
}
|
|
75
|
-
// ⑤
|
|
76
|
-
const
|
|
77
|
-
if (
|
|
78
|
-
request.log.error({ err: error }, '[response]
|
|
75
|
+
// ⑤ 资源错误(各资源注册的分类器依次认领)→ 500
|
|
76
|
+
const resourceError = options.classifyResourceError?.(error);
|
|
77
|
+
if (resourceError) {
|
|
78
|
+
request.log.error({ err: error }, '[response] resource error');
|
|
79
79
|
return reply
|
|
80
80
|
.code(500)
|
|
81
|
-
.send(createErrorResponse(
|
|
81
|
+
.send(createErrorResponse(resourceError.type, resolveMessage(resourceError)));
|
|
82
82
|
}
|
|
83
83
|
// ⑥ 未知 → 500
|
|
84
84
|
request.log.error({ err: error }, '[response] unknown error');
|
|
@@ -29,4 +29,12 @@ export declare function middlewaresCannotSeeResources(): void;
|
|
|
29
29
|
export declare function middlewaresCannotSeeEnv(): void;
|
|
30
30
|
/** #15 `services` 看不到 `env`(服务层禁读 env) */
|
|
31
31
|
export declare function servicesCannotSeeEnv(): void;
|
|
32
|
+
/** #16 `config` 看不到 `registerClassifyError`(resources 槽位专属能力) */
|
|
33
|
+
export declare function configCannotRegisterClassifyError(): void;
|
|
34
|
+
/** #17 `services` 看不到 `registerClassifyError`(resources 槽位专属能力) */
|
|
35
|
+
export declare function servicesCannotRegisterClassifyError(): void;
|
|
36
|
+
/** #18 `middlewares` 看不到 `registerClassifyError`(resources 槽位专属能力) */
|
|
37
|
+
export declare function middlewaresCannotRegisterClassifyError(): void;
|
|
38
|
+
/** #19 `routers` 看不到 `registerClassifyError`(resources 槽位专属能力) */
|
|
39
|
+
export declare function routersCannotRegisterClassifyError(): void;
|
|
32
40
|
//# sourceMappingURL=define-server.negative-cases.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-server.negative-cases.d.ts","sourceRoot":"","sources":["../../source/app/define-server.negative-cases.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAgB9C,kCAAkC;AAClC,wBAAgB,wBAAwB,IAAI,IAAI,CAU/C;AAED,oCAAoC;AACpC,wBAAgB,0BAA0B,IAAI,IAAI,CAUjD;AAED,iCAAiC;AACjC,wBAAgB,uBAAuB,IAAI,IAAI,CAa9C;AAED,iDAAiD;AACjD,wBAAgB,yBAAyB,IAAI,IAAI,CAahD;AAED,6CAA6C;AAC7C,wBAAgB,yBAAyB,IAAI,IAAI,CAYhD;AAED,gCAAgC;AAChC,wBAAgB,sBAAsB,IAAI,IAAI,CAY7C;AAED,gDAAgD;AAChD,wBAAgB,kCAAkC,IAAI,IAAI,CAUzD;AAED,8CAA8C;AAC9C,wBAAgB,6BAA6B,IAAI,IAAI,CAUpD;AAED,qDAAqD;AACrD,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,IAAI,CAGhG;AAED,2BAA2B;AAC3B,wBAAgB,oBAAoB,IAAI,IAAI,CAU3C;AAED,kDAAkD;AAClD,wBAAgB,mCAAmC,IAAI,IAAI,CAa1D;AAED,6BAA6B;AAC7B,wBAAgB,kBAAkB,IAAI,IAAI,CAazC;AAED,mDAAmD;AACnD,wBAAgB,6BAA6B,IAAI,IAAI,CAapD;AAED,kCAAkC;AAClC,wBAAgB,uBAAuB,IAAI,IAAI,CAa9C;AAED,0CAA0C;AAC1C,wBAAgB,oBAAoB,IAAI,IAAI,CAa3C"}
|
|
1
|
+
{"version":3,"file":"define-server.negative-cases.d.ts","sourceRoot":"","sources":["../../source/app/define-server.negative-cases.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAgB9C,kCAAkC;AAClC,wBAAgB,wBAAwB,IAAI,IAAI,CAU/C;AAED,oCAAoC;AACpC,wBAAgB,0BAA0B,IAAI,IAAI,CAUjD;AAED,iCAAiC;AACjC,wBAAgB,uBAAuB,IAAI,IAAI,CAa9C;AAED,iDAAiD;AACjD,wBAAgB,yBAAyB,IAAI,IAAI,CAahD;AAED,6CAA6C;AAC7C,wBAAgB,yBAAyB,IAAI,IAAI,CAYhD;AAED,gCAAgC;AAChC,wBAAgB,sBAAsB,IAAI,IAAI,CAY7C;AAED,gDAAgD;AAChD,wBAAgB,kCAAkC,IAAI,IAAI,CAUzD;AAED,8CAA8C;AAC9C,wBAAgB,6BAA6B,IAAI,IAAI,CAUpD;AAED,qDAAqD;AACrD,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,IAAI,CAGhG;AAED,2BAA2B;AAC3B,wBAAgB,oBAAoB,IAAI,IAAI,CAU3C;AAED,kDAAkD;AAClD,wBAAgB,mCAAmC,IAAI,IAAI,CAa1D;AAED,6BAA6B;AAC7B,wBAAgB,kBAAkB,IAAI,IAAI,CAazC;AAED,mDAAmD;AACnD,wBAAgB,6BAA6B,IAAI,IAAI,CAapD;AAED,kCAAkC;AAClC,wBAAgB,uBAAuB,IAAI,IAAI,CAa9C;AAED,0CAA0C;AAC1C,wBAAgB,oBAAoB,IAAI,IAAI,CAa3C;AAED,iEAAiE;AACjE,wBAAgB,iCAAiC,IAAI,IAAI,CAaxD;AAED,mEAAmE;AACnE,wBAAgB,mCAAmC,IAAI,IAAI,CAa1D;AAED,sEAAsE;AACtE,wBAAgB,sCAAsC,IAAI,IAAI,CAa7D;AAED,kEAAkE;AAClE,wBAAgB,kCAAkC,IAAI,IAAI,CAYzD"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineServer, startServer } from './entries.js';
|
|
2
2
|
/**
|
|
3
|
-
* N2 §4 的 **
|
|
3
|
+
* N2 §4 的 **19 条负向用例**:这些写法**必须编译失败**,全部由 `tsc --noEmit` 覆盖
|
|
4
4
|
* (**不进**运行期 vitest 断言)。
|
|
5
5
|
*
|
|
6
6
|
* 文件名刻意**不带** `.test.ts`:它由 `tsc --noEmit` 校验,不被 vitest 当作测试文件执行。
|
|
@@ -207,3 +207,62 @@ export function servicesCannotSeeEnv() {
|
|
|
207
207
|
routers: () => undefined,
|
|
208
208
|
});
|
|
209
209
|
}
|
|
210
|
+
/** #16 `config` 看不到 `registerClassifyError`(resources 槽位专属能力) */
|
|
211
|
+
export function configCannotRegisterClassifyError() {
|
|
212
|
+
defineServer({
|
|
213
|
+
app: identity,
|
|
214
|
+
resources: () => ({}),
|
|
215
|
+
config: (ctx) => {
|
|
216
|
+
// @ts-expect-error `registerClassifyError` 是 resources 槽位专属能力
|
|
217
|
+
void ctx.registerClassifyError;
|
|
218
|
+
return {};
|
|
219
|
+
},
|
|
220
|
+
services: () => ({}),
|
|
221
|
+
middlewares: () => [],
|
|
222
|
+
routers: () => undefined,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
/** #17 `services` 看不到 `registerClassifyError`(resources 槽位专属能力) */
|
|
226
|
+
export function servicesCannotRegisterClassifyError() {
|
|
227
|
+
defineServer({
|
|
228
|
+
app: identity,
|
|
229
|
+
resources: () => ({}),
|
|
230
|
+
config: () => ({}),
|
|
231
|
+
services: (ctx) => {
|
|
232
|
+
// @ts-expect-error `registerClassifyError` 是 resources 槽位专属能力
|
|
233
|
+
void ctx.registerClassifyError;
|
|
234
|
+
return {};
|
|
235
|
+
},
|
|
236
|
+
middlewares: () => [],
|
|
237
|
+
routers: () => undefined,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
/** #18 `middlewares` 看不到 `registerClassifyError`(resources 槽位专属能力) */
|
|
241
|
+
export function middlewaresCannotRegisterClassifyError() {
|
|
242
|
+
defineServer({
|
|
243
|
+
app: identity,
|
|
244
|
+
resources: () => ({}),
|
|
245
|
+
config: () => ({}),
|
|
246
|
+
services: () => ({}),
|
|
247
|
+
middlewares: (ctx) => {
|
|
248
|
+
// @ts-expect-error `registerClassifyError` 是 resources 槽位专属能力
|
|
249
|
+
void ctx.registerClassifyError;
|
|
250
|
+
return [];
|
|
251
|
+
},
|
|
252
|
+
routers: () => undefined,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
/** #19 `routers` 看不到 `registerClassifyError`(resources 槽位专属能力) */
|
|
256
|
+
export function routersCannotRegisterClassifyError() {
|
|
257
|
+
defineServer({
|
|
258
|
+
app: identity,
|
|
259
|
+
resources: () => ({}),
|
|
260
|
+
config: () => ({}),
|
|
261
|
+
services: () => ({}),
|
|
262
|
+
middlewares: () => [],
|
|
263
|
+
routers: (ctx) => {
|
|
264
|
+
// @ts-expect-error `registerClassifyError` 是 resources 槽位专属能力
|
|
265
|
+
void ctx.registerClassifyError;
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
}
|
|
@@ -97,16 +97,15 @@ describe('错误契约', () => {
|
|
|
97
97
|
expect(body.message).toContain('GET /missing');
|
|
98
98
|
await app.close();
|
|
99
99
|
});
|
|
100
|
-
it('
|
|
100
|
+
it('资源注册的 `ctx.registerClassifyError` 分类器生效(→500,错误码 = 分类器返回的 SystemError.type)', async () => {
|
|
101
101
|
const server = defineServer({
|
|
102
102
|
app: { service: 'error-contract-database', title: 'Error Contract Database', version: '1.0.0' },
|
|
103
|
-
resources: () =>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}),
|
|
103
|
+
resources: (ctx) => {
|
|
104
|
+
ctx.registerClassifyError((error) => error instanceof Error && error.message === 'pg down'
|
|
105
|
+
? new SystemError('DATABASE_ERROR', { operation: 'query' }, 'pg down')
|
|
106
|
+
: null);
|
|
107
|
+
return {};
|
|
108
|
+
},
|
|
110
109
|
config: () => ({}),
|
|
111
110
|
services: () => ({}),
|
|
112
111
|
middlewares: () => [],
|
|
@@ -122,4 +121,107 @@ describe('错误契约', () => {
|
|
|
122
121
|
expect(response.json()).toEqual({ status: 'DATABASE_ERROR', message: 'pg down', data: null });
|
|
123
122
|
await app.close();
|
|
124
123
|
});
|
|
124
|
+
it('跨资源注册:每个资源各注册自己的分类器,各自认领域内错误(顺序短路),都不认领则兜底', async () => {
|
|
125
|
+
const calls = [];
|
|
126
|
+
const server = defineServer({
|
|
127
|
+
app: { service: 'error-contract-cross-resource', title: 'Error Contract Cross Resource', version: '1.0.0' },
|
|
128
|
+
resources: (ctx) => {
|
|
129
|
+
// prisma 资源:只认领自己域内的 Prisma 错误(认领不了返回 null)
|
|
130
|
+
ctx.registerClassifyError((error) => {
|
|
131
|
+
calls.push('prisma');
|
|
132
|
+
return error instanceof Error && error.name === 'PrismaError'
|
|
133
|
+
? new SystemError('DATABASE_ERROR', { operation: 'query' }, '数据库错误')
|
|
134
|
+
: null;
|
|
135
|
+
});
|
|
136
|
+
// cache 资源:只认领自己域内的缓存错误
|
|
137
|
+
ctx.registerClassifyError((error) => {
|
|
138
|
+
calls.push('cache');
|
|
139
|
+
return error instanceof Error && error.name === 'CacheError'
|
|
140
|
+
? new SystemError('CACHE_ERROR', undefined, '缓存错误')
|
|
141
|
+
: null;
|
|
142
|
+
});
|
|
143
|
+
return { prisma: {}, cache: {} };
|
|
144
|
+
},
|
|
145
|
+
config: () => ({}),
|
|
146
|
+
services: () => ({}),
|
|
147
|
+
middlewares: () => [],
|
|
148
|
+
routers: (ctx) => {
|
|
149
|
+
ctx.app.get('/prisma-error', () => {
|
|
150
|
+
throw Object.assign(new Error('db down'), { name: 'PrismaError' });
|
|
151
|
+
});
|
|
152
|
+
ctx.app.get('/cache-error', () => {
|
|
153
|
+
throw Object.assign(new Error('cache down'), { name: 'CacheError' });
|
|
154
|
+
});
|
|
155
|
+
ctx.app.get('/unclaimed-error', () => {
|
|
156
|
+
throw new Error('someone else error');
|
|
157
|
+
});
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
const app = await startServer(server, { listen: false });
|
|
161
|
+
// ① prisma 域:prisma 分类器认领,错误码正确;首个命中即短路(不再问 cache)
|
|
162
|
+
calls.length = 0;
|
|
163
|
+
const prisma = await app.inject({ method: 'GET', url: '/prisma-error' });
|
|
164
|
+
expect(prisma.statusCode).toBe(500);
|
|
165
|
+
expect(prisma.json()).toEqual({ status: 'DATABASE_ERROR', message: '数据库错误', data: null });
|
|
166
|
+
expect(calls).toEqual(['prisma']);
|
|
167
|
+
// ② cache 域:prisma 返回 null → 交给 cache 认领,错误码正确
|
|
168
|
+
calls.length = 0;
|
|
169
|
+
const cache = await app.inject({ method: 'GET', url: '/cache-error' });
|
|
170
|
+
expect(cache.statusCode).toBe(500);
|
|
171
|
+
expect(cache.json()).toEqual({ status: 'CACHE_ERROR', message: '缓存错误', data: null });
|
|
172
|
+
expect(calls).toEqual(['prisma', 'cache']);
|
|
173
|
+
// ③ 都不认领 → 落 `UNKNOWN_ERROR` 兜底
|
|
174
|
+
calls.length = 0;
|
|
175
|
+
const unclaimed = await app.inject({ method: 'GET', url: '/unclaimed-error' });
|
|
176
|
+
expect(unclaimed.statusCode).toBe(500);
|
|
177
|
+
expect(unclaimed.json()).toEqual({ status: 'UNKNOWN_ERROR', message: 'someone else error', data: null });
|
|
178
|
+
expect(calls).toEqual(['prisma', 'cache']);
|
|
179
|
+
await app.close();
|
|
180
|
+
});
|
|
181
|
+
it('一个资源都不注册分类器 → 资源错误分支不生效,落 `UNKNOWN_ERROR` 兜底', async () => {
|
|
182
|
+
const server = defineServer({
|
|
183
|
+
app: { service: 'error-contract-none', title: 'Error Contract None', version: '1.0.0' },
|
|
184
|
+
resources: () => ({}),
|
|
185
|
+
config: () => ({}),
|
|
186
|
+
services: () => ({}),
|
|
187
|
+
middlewares: () => [],
|
|
188
|
+
routers: (ctx) => {
|
|
189
|
+
ctx.app.get('/boom', () => {
|
|
190
|
+
throw new Error('boom');
|
|
191
|
+
});
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
const app = await startServer(server, { listen: false });
|
|
195
|
+
const response = await app.inject({ method: 'GET', url: '/boom' });
|
|
196
|
+
expect(response.statusCode).toBe(500);
|
|
197
|
+
expect(response.json()).toEqual({ status: 'UNKNOWN_ERROR', message: 'boom', data: null });
|
|
198
|
+
await app.close();
|
|
199
|
+
});
|
|
200
|
+
it('注册的分类器不影响既有分支:`UserError` 仍走 400(分类器只在资源错误分支求值)', async () => {
|
|
201
|
+
let classified = 0;
|
|
202
|
+
const server = defineServer({
|
|
203
|
+
app: { service: 'error-contract-user', title: 'Error Contract User', version: '1.0.0' },
|
|
204
|
+
resources: (ctx) => {
|
|
205
|
+
ctx.registerClassifyError((error) => {
|
|
206
|
+
classified += 1;
|
|
207
|
+
return error instanceof Error ? new SystemError('SHOULD_NOT_HAPPEN', undefined, 'x') : null;
|
|
208
|
+
});
|
|
209
|
+
return {};
|
|
210
|
+
},
|
|
211
|
+
config: () => ({}),
|
|
212
|
+
services: () => ({}),
|
|
213
|
+
middlewares: () => [],
|
|
214
|
+
routers: (ctx) => {
|
|
215
|
+
ctx.app.get('/user-error-2', () => {
|
|
216
|
+
throw new UserError('INVALID_TOKEN', undefined, 'token 无效');
|
|
217
|
+
});
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
const app = await startServer(server, { listen: false });
|
|
221
|
+
const response = await app.inject({ method: 'GET', url: '/user-error-2' });
|
|
222
|
+
expect(response.statusCode).toBe(400);
|
|
223
|
+
expect(response.json()).toEqual({ status: 'INVALID_TOKEN', message: 'token 无效', data: null });
|
|
224
|
+
expect(classified).toBe(0); // `UserError` 在分支①命中,分类器根本没被求值
|
|
225
|
+
await app.close();
|
|
226
|
+
});
|
|
125
227
|
});
|
package/output/app/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { createCorsMiddleware, createContextMiddleware, createAuthMiddleware, cr
|
|
|
8
8
|
export { REQUEST_ID_HEADER } from './core/request-id.js';
|
|
9
9
|
export { DOC_ROUTE_PREFIX, DOC_SPEC_ROUTE } from './core/openapi.js';
|
|
10
10
|
export { extractPermissionOperations } from './permission-operations.js';
|
|
11
|
-
export type { AppIdentity, AppInstance, LoggerLike, MaybePromise, RedisHandle, Live, ResourcesView, AssertNoDependencies, ServicesShape, ResourcesContext, ResourcesFactory, ConfigContext, ConfigFactory, ServiceUnit, ServiceContext, ServicesFactory, MiddlewareUnit, MiddlewareContext, MiddlewaresFactory, RouterContext, RoutersFactory, ServerConfig, Server, StartServerOptions, ShutdownContext, OpenApiDocument, } from './types.js';
|
|
11
|
+
export type { AppIdentity, AppInstance, LoggerLike, MaybePromise, RedisHandle, Live, ResourcesView, AssertNoDependencies, ServicesShape, ErrorClassifier, ResourcesContext, ResourcesFactory, ConfigContext, ConfigFactory, ServiceUnit, ServiceContext, ServicesFactory, MiddlewareUnit, MiddlewareContext, MiddlewaresFactory, RouterContext, RoutersFactory, ServerConfig, Server, StartServerOptions, ShutdownContext, OpenApiDocument, } from './types.js';
|
|
12
12
|
export type { CacheSetupParams } from './redis.js';
|
|
13
13
|
export type { PermissionOperation } from './permission-operations.js';
|
|
14
14
|
export type { CorsMiddlewareOptions, ContextMiddlewareOptions, AuthMiddlewareOptions, AuthSkip, AuthVerifyInput, AuthVerifyMetadata, AuthVerifyResult, AccountIntegrationConfig, RateLimitMiddlewareOptions } from './middleware/index.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/app/index.ts"],"names":[],"mappings":"AAEA,OAAO,mBAAmB,CAAA;AAG1B,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAGjG,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AACvI,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAGzC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAGpD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,+BAA+B,EAAE,MAAM,YAAY,CAAA;AAGtF,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAG3K,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAGpE,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAA;AAGxE,YAAY,EAEV,WAAW,EACX,WAAW,EACX,UAAU,EACV,YAAY,EACZ,WAAW,EAEX,IAAI,EACJ,aAAa,EACb,oBAAoB,EACpB,aAAa,EAEb,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,WAAW,EACX,cAAc,EACd,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,aAAa,EACb,cAAc,EAEd,YAAY,EACZ,MAAM,EACN,kBAAkB,EAClB,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAClD,YAAY,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AACrE,YAAY,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,QAAQ,EAAE,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAA;AAC1O,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/app/index.ts"],"names":[],"mappings":"AAEA,OAAO,mBAAmB,CAAA;AAG1B,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAGjG,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AACvI,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAGzC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAGpD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,+BAA+B,EAAE,MAAM,YAAY,CAAA;AAGtF,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAG3K,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAGpE,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAA;AAGxE,YAAY,EAEV,WAAW,EACX,WAAW,EACX,UAAU,EACV,YAAY,EACZ,WAAW,EAEX,IAAI,EACJ,aAAa,EACb,oBAAoB,EACpB,aAAa,EAEb,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,WAAW,EACX,cAAc,EACd,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,aAAa,EACb,cAAc,EAEd,YAAY,EACZ,MAAM,EACN,kBAAkB,EAClB,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAClD,YAAY,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AACrE,YAAY,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,QAAQ,EAAE,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAA;AAC1O,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA"}
|
|
@@ -16,7 +16,7 @@ const assertLiveKeysRemovesFalse = () => {
|
|
|
16
16
|
};
|
|
17
17
|
void assertLiveKeysRemovesFalse;
|
|
18
18
|
describe('resources 槽位(N1 §2 / N2 §2.3)', () => {
|
|
19
|
-
it('①
|
|
19
|
+
it('① 入参为 env + log + registerClassifyError,且资源嵌套在 ctx.resources 下(config / services 都能用)', async () => {
|
|
20
20
|
let captured;
|
|
21
21
|
const observed = {};
|
|
22
22
|
const server = defineServer({
|
|
@@ -43,9 +43,11 @@ describe('resources 槽位(N1 §2 / N2 §2.3)', () => {
|
|
|
43
43
|
});
|
|
44
44
|
const app = await startServer(server, { listen: false });
|
|
45
45
|
try {
|
|
46
|
-
expect(Object.keys(captured ?? {}).sort()).toEqual(['env', 'log']);
|
|
46
|
+
expect(Object.keys(captured ?? {}).sort()).toEqual(['env', 'log', 'registerClassifyError']);
|
|
47
47
|
expect(captured?.env.ENV).toBeTypeOf('string');
|
|
48
48
|
expect(typeof captured?.log.info).toBe('function');
|
|
49
|
+
// resources 槽位专属能力:每个资源注册自己的错误分类器(函数)
|
|
50
|
+
expect(typeof captured?.registerClassifyError).toBe('function');
|
|
49
51
|
expect(observed.inConfig).toBe('rows:select 1');
|
|
50
52
|
expect(observed.inServices).toBe('domain:cached');
|
|
51
53
|
const response = await app.inject({ method: 'GET', url: '/resource' });
|
|
@@ -49,7 +49,7 @@ describe('关闭流程集成', () => {
|
|
|
49
49
|
resources: () => ({ database: { dispose: () => calls.push('disposeResource') } }),
|
|
50
50
|
config: () => ({}),
|
|
51
51
|
services: (ctx) => {
|
|
52
|
-
ctx.disposer.
|
|
52
|
+
ctx.disposer.add(() => {
|
|
53
53
|
calls.push('stopProducers');
|
|
54
54
|
});
|
|
55
55
|
return {
|
package/output/app/types.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { FastifyBaseLogger, FastifyInstance, RawServerDefault } from 'fasti
|
|
|
3
3
|
import type { ZodTypeProvider } from 'fastify-type-provider-zod';
|
|
4
4
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
5
5
|
import type { ConfigEnv } from './env.js';
|
|
6
|
+
import type { SystemError } from './errors.js';
|
|
6
7
|
/**
|
|
7
8
|
* `defineServer` 槽位口径与接口类型(N1 / N2,**唯一规格来源**)。
|
|
8
9
|
*
|
|
@@ -82,13 +83,29 @@ export type Live<T> = {
|
|
|
82
83
|
/** 框架在 ctx 上暴露的资源视图(`Awaited<>` 归一 + `false` 键剔除) */
|
|
83
84
|
export type ResourcesView<R> = Live<Awaited<R>>;
|
|
84
85
|
/**
|
|
85
|
-
*
|
|
86
|
+
* 资源错误分类器(响应层用)。
|
|
87
|
+
*
|
|
88
|
+
* **每个资源注册自己的分类器**(一个资源一个):只认领自己错误域内的错误,认领不了返回 `null` 交给
|
|
89
|
+
* 下一个。由服务仓在 `resources(ctx)` 里通过 `ctx.registerClassifyError(...)` 注册;可注册多个,
|
|
90
|
+
* 按注册顺序求值取第一个非 `null` 的结果;全部未命中 / 一个都没注册 → 响应层落 `UNKNOWN_ERROR` 兜底。
|
|
91
|
+
*/
|
|
92
|
+
export type ErrorClassifier = (error: unknown) => SystemError | null;
|
|
93
|
+
/**
|
|
94
|
+
* `resources(ctx)` 的入参:**只有 `env` + `log`**(外加槽位专属的注册能力)。
|
|
86
95
|
*
|
|
87
96
|
* 结构上排除 `config` / `services` / `app` → 「资源依赖配置」这类循环**编译期写不出来**。
|
|
88
97
|
*/
|
|
89
98
|
export interface ResourcesContext {
|
|
90
99
|
readonly env: ConfigEnv;
|
|
91
100
|
readonly log: LoggerLike;
|
|
101
|
+
/**
|
|
102
|
+
* **每个资源注册自己的错误分类器**(响应层用)。
|
|
103
|
+
*
|
|
104
|
+
* 一个资源一个分类器,各管各的错误域:只认领自己域内的错误,认领不了返回 `null` 交给下一个。
|
|
105
|
+
* 可注册多个:按注册顺序求值,取第一个非 `null` 的结果;全部未命中 → 响应层落 `UNKNOWN_ERROR` 兜底。
|
|
106
|
+
* 本方法是 **resources 槽位专属能力**(其他槽位的 ctx 不提供)。
|
|
107
|
+
*/
|
|
108
|
+
registerClassifyError(classifier: ErrorClassifier): void;
|
|
92
109
|
}
|
|
93
110
|
export type ResourcesFactory<R> = (ctx: ResourcesContext) => R;
|
|
94
111
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../source/app/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AACnF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAEhE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../source/app/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taicode/common-server",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.2",
|
|
4
4
|
"author": "Alain",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"description": "",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"fastify": "^5.5.0",
|
|
37
37
|
"redis": "^5.11.0",
|
|
38
|
-
"@taicode/common-base": "^4.0.0-beta.
|
|
38
|
+
"@taicode/common-base": "^4.0.0-beta.2"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@eslint/js": "^9.39.3",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"redis": "^5.11.0",
|
|
50
50
|
"typescript-eslint": "^8.56.1",
|
|
51
51
|
"vitest": "^3.2.4",
|
|
52
|
-
"@taicode/common-base": "^4.0.0-beta.
|
|
52
|
+
"@taicode/common-base": "^4.0.0-beta.2"
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
|
55
55
|
"test": "vitest run",
|