@ubean/shared 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +20 -17
- package/dist/logger/hono.d.ts +25 -0
- package/dist/logger/hono.js +104 -0
- package/dist/logger/index.d.ts +34 -0
- package/dist/logger/index.js +2 -0
- package/dist/logger-CG0K8cWb.js +61 -0
- package/dist/types-CFy62PZV.d.ts +40 -0
- package/package.json +10 -1
package/dist/index.d.ts
CHANGED
|
@@ -50,11 +50,9 @@ interface IsrRule {
|
|
|
50
50
|
* - `prerender: true` 该路由加入 SSG 预渲染队列(由 `@ubean/prerender` 自动发现)
|
|
51
51
|
* - `isr: 60` 或 `isr: { ttl: 60, swr: true }` 启用 ISR,以 TTL 秒缓存渲染 HTML
|
|
52
52
|
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* 覆盖全局 `ssr.exclude`;同时该路由加入预渲染队列(等价于 `prerender: true`),
|
|
57
|
-
* 预渲染产物作为静态壳供运行时复用。
|
|
53
|
+
* `ppr: true` 是强制流式 SSR + 预渲染发现的便利别名(等价 `ssr: 'streaming'`
|
|
54
|
+
* 且隐含 `prerender: true`)。**不是** Next.js 的静态壳 / 动态洞 PPR。
|
|
55
|
+
* 流式响应带 `X-SSR-Mode: streaming` 与 `X-PPR: streaming`。
|
|
58
56
|
*
|
|
59
57
|
* 注意:构建时预渲染策略已迁移至 `PrerenderConfig`(由 `ubean.config.ts` 的
|
|
60
58
|
* `prerender` 字段统一管理),`RouteRule.prerender` 仅作为自动发现标记 ——
|
|
@@ -79,8 +77,9 @@ interface RouteRule {
|
|
|
79
77
|
* - `true` 强制 SSR(即使命中全局 exclude)
|
|
80
78
|
* - `false` 强制 CSR(即使全局未排除)
|
|
81
79
|
* - `'streaming'` 强制流式 SSR(等同于 `ssr: true` + 流式输出)
|
|
80
|
+
* - `'data-only'` 跑 loader,返回 CSR shell + 脱水数据(不对页面做 HTML SSR)
|
|
82
81
|
*/
|
|
83
|
-
ssr?: boolean | 'streaming';
|
|
82
|
+
ssr?: boolean | 'streaming' | 'data-only';
|
|
84
83
|
/**
|
|
85
84
|
* 标记该路由加入 SSG 预渲染队列(P9-03)。
|
|
86
85
|
* 由 `collectPrerenderRoutes` 自动从 `routeRules` 中扫描发现。
|
|
@@ -94,17 +93,9 @@ interface RouteRule {
|
|
|
94
93
|
*/
|
|
95
94
|
isr?: number | IsrRule;
|
|
96
95
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* 运行时行为:
|
|
102
|
-
* - 强制流式 SSR(覆盖 `ssr.exclude` / 全局 `streaming`),等价于 `ssr: 'streaming'`
|
|
103
|
-
* - 隐含 `prerender: true`,该路由会被预渲染(产物作为静态壳)
|
|
104
|
-
* - 页面内带 `server:defer` 指令的组件在预渲染时仅渲染 fallback,
|
|
105
|
-
* 在流式 SSR 时通过 Suspense 边界流式输出实际内容
|
|
106
|
-
*
|
|
107
|
-
* 对齐:Next.js 16 PPR(稳定)、Astro 5 `server:defer`。
|
|
96
|
+
* 强制流式 SSR + 加入预渲染队列的便利开关。
|
|
97
|
+
* 等价 `ssr: 'streaming'`,隐含 `prerender: true`。
|
|
98
|
+
* 不是 Next.js Partial Prerendering 静态壳。
|
|
108
99
|
*/
|
|
109
100
|
ppr?: boolean;
|
|
110
101
|
}
|
|
@@ -282,6 +273,18 @@ interface ActionSchema<TOutput = unknown> {
|
|
|
282
273
|
};
|
|
283
274
|
parse?(value: unknown): TOutput;
|
|
284
275
|
_output?: TOutput;
|
|
276
|
+
'~standard'?: {
|
|
277
|
+
version: 1;
|
|
278
|
+
vendor: string;
|
|
279
|
+
validate: (value: unknown) => {
|
|
280
|
+
value: TOutput;
|
|
281
|
+
} | {
|
|
282
|
+
issues: Array<{
|
|
283
|
+
message?: string;
|
|
284
|
+
path?: unknown;
|
|
285
|
+
}>;
|
|
286
|
+
} | Promise<unknown>;
|
|
287
|
+
};
|
|
285
288
|
}
|
|
286
289
|
/**
|
|
287
290
|
* A registered server action — the runtime representation produced by
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { n as RequestLoggerOptions } from "../types-CFy62PZV.js";
|
|
2
|
+
import { MiddlewareHandler } from "hono";
|
|
3
|
+
//#region src/logger/hono.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Hono 请求日志中间件。
|
|
6
|
+
*
|
|
7
|
+
* 记录每个请求:方法、路径、状态码、耗时,以及错误与慢请求(按 `slowThreshold`)。
|
|
8
|
+
* 利用 Hono compose 设置的 `c.error` 识别被 `onError` 收敛的异常(此时 `next()` 不抛出,
|
|
9
|
+
* 而是以 500 Response 正常返回);若中间件链本身向外抛出异常也会被记录后重新抛出。
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { createRequestLoggerMiddleware } from '@ubean/shared/logger/hono';
|
|
14
|
+
* import { createUbeanApp } from 'ubean/runtime/app';
|
|
15
|
+
*
|
|
16
|
+
* const app = createUbeanApp();
|
|
17
|
+
* app.use('*', createRequestLoggerMiddleware({
|
|
18
|
+
* exclude: ['/_health', '/_devtools/**'],
|
|
19
|
+
* slowThreshold: 2000
|
|
20
|
+
* }));
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
declare function createRequestLoggerMiddleware(options?: RequestLoggerOptions): MiddlewareHandler;
|
|
24
|
+
//#endregion
|
|
25
|
+
export { createRequestLoggerMiddleware };
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { n as getLogger } from "../logger-CG0K8cWb.js";
|
|
2
|
+
//#region src/logger/hono.ts
|
|
3
|
+
/**
|
|
4
|
+
* 判断路径是否应被跳过。
|
|
5
|
+
*/
|
|
6
|
+
function shouldSkip(path, exclude) {
|
|
7
|
+
if (!exclude) return false;
|
|
8
|
+
if (typeof exclude === "function") return exclude(path);
|
|
9
|
+
for (const pattern of exclude) if (typeof pattern === "string") {
|
|
10
|
+
if (pattern === path) return true;
|
|
11
|
+
if (pattern === "**" || pattern === "/**") return true;
|
|
12
|
+
if (pattern.endsWith("/**")) {
|
|
13
|
+
const prefix = pattern.slice(0, -3);
|
|
14
|
+
if (path === prefix || path.startsWith(`${prefix}/`)) return true;
|
|
15
|
+
}
|
|
16
|
+
if (path.startsWith(pattern)) return true;
|
|
17
|
+
} else if (pattern instanceof RegExp) {
|
|
18
|
+
if (pattern.test(path)) return true;
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Hono 请求日志中间件。
|
|
24
|
+
*
|
|
25
|
+
* 记录每个请求:方法、路径、状态码、耗时,以及错误与慢请求(按 `slowThreshold`)。
|
|
26
|
+
* 利用 Hono compose 设置的 `c.error` 识别被 `onError` 收敛的异常(此时 `next()` 不抛出,
|
|
27
|
+
* 而是以 500 Response 正常返回);若中间件链本身向外抛出异常也会被记录后重新抛出。
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* import { createRequestLoggerMiddleware } from '@ubean/shared/logger/hono';
|
|
32
|
+
* import { createUbeanApp } from 'ubean/runtime/app';
|
|
33
|
+
*
|
|
34
|
+
* const app = createUbeanApp();
|
|
35
|
+
* app.use('*', createRequestLoggerMiddleware({
|
|
36
|
+
* exclude: ['/_health', '/_devtools/**'],
|
|
37
|
+
* slowThreshold: 2000
|
|
38
|
+
* }));
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
function createRequestLoggerMiddleware(options = {}) {
|
|
42
|
+
const log = options.logger ?? getLogger("http");
|
|
43
|
+
const slowThreshold = options.slowThreshold ?? 1e3;
|
|
44
|
+
return async (c, next) => {
|
|
45
|
+
const { method } = c.req;
|
|
46
|
+
const path = c.req.path;
|
|
47
|
+
const url = options.logQuery ? c.req.url : path;
|
|
48
|
+
if (shouldSkip(path, options.exclude)) return next();
|
|
49
|
+
const requestId = c.get("requestId");
|
|
50
|
+
const start = Date.now();
|
|
51
|
+
log.info({
|
|
52
|
+
method,
|
|
53
|
+
path,
|
|
54
|
+
requestId
|
|
55
|
+
}, `--> ${method} ${url}`);
|
|
56
|
+
try {
|
|
57
|
+
await next();
|
|
58
|
+
const duration = Date.now() - start;
|
|
59
|
+
const status = c.res.status;
|
|
60
|
+
const error = c.error;
|
|
61
|
+
if (error) log.error({
|
|
62
|
+
method,
|
|
63
|
+
path,
|
|
64
|
+
status,
|
|
65
|
+
durationMs: duration,
|
|
66
|
+
requestId,
|
|
67
|
+
error: error.message
|
|
68
|
+
}, `<!- ${method} ${url} ${status} ${duration}ms ERROR`);
|
|
69
|
+
else if (status >= 500) log.error({
|
|
70
|
+
method,
|
|
71
|
+
path,
|
|
72
|
+
status,
|
|
73
|
+
durationMs: duration,
|
|
74
|
+
requestId
|
|
75
|
+
}, `<-- ${method} ${url} ${status} ${duration}ms`);
|
|
76
|
+
else if (status >= 400 || duration >= slowThreshold) log.warn({
|
|
77
|
+
method,
|
|
78
|
+
path,
|
|
79
|
+
status,
|
|
80
|
+
durationMs: duration,
|
|
81
|
+
requestId
|
|
82
|
+
}, `<-- ${method} ${url} ${status} ${duration}ms`);
|
|
83
|
+
else log.info({
|
|
84
|
+
method,
|
|
85
|
+
path,
|
|
86
|
+
status,
|
|
87
|
+
durationMs: duration,
|
|
88
|
+
requestId
|
|
89
|
+
}, `<-- ${method} ${url} ${status} ${duration}ms`);
|
|
90
|
+
} catch (err) {
|
|
91
|
+
const duration = Date.now() - start;
|
|
92
|
+
log.error({
|
|
93
|
+
method,
|
|
94
|
+
path,
|
|
95
|
+
durationMs: duration,
|
|
96
|
+
requestId,
|
|
97
|
+
error: err instanceof Error ? err.message : String(err)
|
|
98
|
+
}, `<!- ${method} ${url} ERROR ${duration}ms`);
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
export { createRequestLoggerMiddleware };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { i as UbeanLoggerOptions, n as RequestLoggerOptions, r as UbeanLogger, t as LogLevelName } from "../types-CFy62PZV.js";
|
|
2
|
+
//#region src/logger/logger.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* 创建一个 ubean 命名的 tslog logger(默认 name 为 `ubean`)。
|
|
5
|
+
*
|
|
6
|
+
* - 未显式提供 `minLevel` 时读取 `LOG_LEVEL`/`TSLOG_LEVEL` 环境变量
|
|
7
|
+
* - 输出格式沿用 tslog 默认:交互式终端彩色 pretty,管道/CI 自动去色;需要结构化 JSON 时显式
|
|
8
|
+
* `{ type: 'json' }` 或设 `TSLOG_TYPE=json`
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const log = createUbeanLogger({ name: 'api' });
|
|
13
|
+
* log.info({ port: 3000 }, 'server started');
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
declare function createUbeanLogger(options?: UbeanLoggerOptions): UbeanLogger;
|
|
17
|
+
/** ubean 全局默认 logger(供应用侧 `import { logger } from 'ubean'` 使用) */
|
|
18
|
+
declare const logger: UbeanLogger;
|
|
19
|
+
/**
|
|
20
|
+
* 获取命名(scope)logger。
|
|
21
|
+
*
|
|
22
|
+
* - 不传 scope 时返回全局默认 `logger`
|
|
23
|
+
* - 传 scope 时返回其子 logger(name 组合为 `ubean:<scope>`,如 `getLogger('cli')` → `ubean:cli`),
|
|
24
|
+
* 继承父 logger 的 settings/minLevel,可通过 `options` 覆盖
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* const cli = getLogger('cli');
|
|
29
|
+
* cli.info('building...');
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
declare function getLogger(scope?: string, options?: UbeanLoggerOptions): UbeanLogger;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { type LogLevelName, type RequestLoggerOptions, type UbeanLogger, type UbeanLoggerOptions, createUbeanLogger, getLogger, logger };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Logger } from "tslog";
|
|
2
|
+
//#region src/logger/logger.ts
|
|
3
|
+
const DEFAULT_NAME = "ubean";
|
|
4
|
+
/**
|
|
5
|
+
* 从环境变量解析日志等级:
|
|
6
|
+
* 1. `LOG_LEVEL`(ubean 约定,友好别名)
|
|
7
|
+
* 2. `TSLOG_LEVEL`(tslog 原生)
|
|
8
|
+
*
|
|
9
|
+
* 返回 undefined 时沿用 tslog 默认 minLevel。
|
|
10
|
+
*/
|
|
11
|
+
function getLogLevelFromEnv() {
|
|
12
|
+
if (typeof process === "undefined" || !process.env) return void 0;
|
|
13
|
+
const value = process.env.LOG_LEVEL ?? process.env.TSLOG_LEVEL;
|
|
14
|
+
if (!value) return void 0;
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 创建一个 ubean 命名的 tslog logger(默认 name 为 `ubean`)。
|
|
19
|
+
*
|
|
20
|
+
* - 未显式提供 `minLevel` 时读取 `LOG_LEVEL`/`TSLOG_LEVEL` 环境变量
|
|
21
|
+
* - 输出格式沿用 tslog 默认:交互式终端彩色 pretty,管道/CI 自动去色;需要结构化 JSON 时显式
|
|
22
|
+
* `{ type: 'json' }` 或设 `TSLOG_TYPE=json`
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const log = createUbeanLogger({ name: 'api' });
|
|
27
|
+
* log.info({ port: 3000 }, 'server started');
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
function createUbeanLogger(options = {}) {
|
|
31
|
+
const minLevel = options.minLevel ?? getLogLevelFromEnv();
|
|
32
|
+
return new Logger({
|
|
33
|
+
name: DEFAULT_NAME,
|
|
34
|
+
...options,
|
|
35
|
+
minLevel
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/** ubean 全局默认 logger(供应用侧 `import { logger } from 'ubean'` 使用) */
|
|
39
|
+
const logger = createUbeanLogger();
|
|
40
|
+
/**
|
|
41
|
+
* 获取命名(scope)logger。
|
|
42
|
+
*
|
|
43
|
+
* - 不传 scope 时返回全局默认 `logger`
|
|
44
|
+
* - 传 scope 时返回其子 logger(name 组合为 `ubean:<scope>`,如 `getLogger('cli')` → `ubean:cli`),
|
|
45
|
+
* 继承父 logger 的 settings/minLevel,可通过 `options` 覆盖
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* const cli = getLogger('cli');
|
|
50
|
+
* cli.info('building...');
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
function getLogger(scope, options = {}) {
|
|
54
|
+
if (!scope) return logger;
|
|
55
|
+
return logger.getSubLogger({
|
|
56
|
+
name: scope,
|
|
57
|
+
...options
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { getLogger as n, logger as r, createUbeanLogger as t };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ILogObj, ISettingsParam, Logger } from "tslog";
|
|
2
|
+
//#region src/logger/types.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* 日志等级名称(与 tslog v5 默认等级表一致)。
|
|
5
|
+
* 仅用于类型标注;`minLevel` 实际接受 number / tslog LogLevel 枚举 / 大小写不敏感的名称。
|
|
6
|
+
*/
|
|
7
|
+
type LogLevelName = 'silly' | 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
8
|
+
/** 由 `@ubean/shared/logger` 创建的 tslog 实例 */
|
|
9
|
+
type UbeanLogger = Logger<ILogObj>;
|
|
10
|
+
/**
|
|
11
|
+
* ubean logger 选项 —— 透传 tslog v5 分组 settings(type/pretty/json/mask/stack/meta/…)。
|
|
12
|
+
* 约定:未显式提供 `minLevel` 时,由 `LOG_LEVEL`/`TSLOG_LEVEL` 环境变量决定(见 {@link createUbeanLogger})。
|
|
13
|
+
*/
|
|
14
|
+
interface UbeanLoggerOptions extends ISettingsParam<ILogObj> {}
|
|
15
|
+
/**
|
|
16
|
+
* `createRequestLoggerMiddleware` 选项。
|
|
17
|
+
*/
|
|
18
|
+
interface RequestLoggerOptions {
|
|
19
|
+
/**
|
|
20
|
+
* 用于输出请求日志的 logger;默认 `getLogger('http')`(name 为 `ubean:http`)。
|
|
21
|
+
*/
|
|
22
|
+
logger?: UbeanLogger;
|
|
23
|
+
/**
|
|
24
|
+
* 跳过的路径:
|
|
25
|
+
* - glob 模式字符串(如 `'/_health'`、`'/api/**'`、`'/favicon.ico'`)
|
|
26
|
+
* - RegExp(如 `/^\/_/`)
|
|
27
|
+
* - 或自定义谓词 `(path) => boolean`
|
|
28
|
+
*/
|
|
29
|
+
exclude?: Array<string | RegExp> | ((path: string) => boolean);
|
|
30
|
+
/**
|
|
31
|
+
* 超过该毫秒数的请求以 `warn` 记录(用于慢请求告警)。默认 `1000`。
|
|
32
|
+
*/
|
|
33
|
+
slowThreshold?: number;
|
|
34
|
+
/**
|
|
35
|
+
* 记录完整 URL(含 query string)而非仅 path。默认 `false`。
|
|
36
|
+
*/
|
|
37
|
+
logQuery?: boolean;
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { UbeanLoggerOptions as i, RequestLoggerOptions as n, UbeanLogger as r, LogLevelName as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ubean/shared",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Shared protocol types, errors, env and universal utilities for ubean",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -17,6 +17,14 @@
|
|
|
17
17
|
"./node": {
|
|
18
18
|
"types": "./dist/node.d.ts",
|
|
19
19
|
"import": "./dist/node.js"
|
|
20
|
+
},
|
|
21
|
+
"./logger": {
|
|
22
|
+
"types": "./dist/logger/index.d.ts",
|
|
23
|
+
"import": "./dist/logger/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./logger/hono": {
|
|
26
|
+
"types": "./dist/logger/hono.d.ts",
|
|
27
|
+
"import": "./dist/logger/hono.js"
|
|
20
28
|
}
|
|
21
29
|
},
|
|
22
30
|
"dependencies": {
|
|
@@ -24,6 +32,7 @@
|
|
|
24
32
|
"hono": "4.13.3",
|
|
25
33
|
"pathe": "^2.0.3",
|
|
26
34
|
"scule": "^1.3.0",
|
|
35
|
+
"tslog": "^5.1.0",
|
|
27
36
|
"ufo": "1.6.4"
|
|
28
37
|
},
|
|
29
38
|
"devDependencies": {
|