@lark-apaas/nestjs-common 0.1.6 → 0.1.8
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.cjs +12 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -28,6 +28,7 @@ __export(index_exports, {
|
|
|
28
28
|
OBSERVABLE_SERVICE: () => OBSERVABLE_SERVICE,
|
|
29
29
|
PLATFORM_HTTP_CLIENT: () => PLATFORM_HTTP_CLIENT,
|
|
30
30
|
RequestContextService: () => RequestContextService,
|
|
31
|
+
createTimer: () => createTimer,
|
|
31
32
|
stripBasePath: () => stripBasePath
|
|
32
33
|
});
|
|
33
34
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -128,6 +129,16 @@ function stripBasePath(fullPath, basePath) {
|
|
|
128
129
|
return fullPath;
|
|
129
130
|
}
|
|
130
131
|
__name(stripBasePath, "stripBasePath");
|
|
132
|
+
|
|
133
|
+
// src/utils/create-timer.ts
|
|
134
|
+
function createTimer() {
|
|
135
|
+
const start = process.hrtime();
|
|
136
|
+
return () => {
|
|
137
|
+
const diff = process.hrtime(start);
|
|
138
|
+
return Math.round((diff[0] * 1e3 + diff[1] / 1e6) * 100) / 100;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
__name(createTimer, "createTimer");
|
|
131
142
|
// Annotate the CommonJS export names for ESM import in node:
|
|
132
143
|
0 && (module.exports = {
|
|
133
144
|
AUTO_TRACE,
|
|
@@ -137,6 +148,7 @@ __name(stripBasePath, "stripBasePath");
|
|
|
137
148
|
OBSERVABLE_SERVICE,
|
|
138
149
|
PLATFORM_HTTP_CLIENT,
|
|
139
150
|
RequestContextService,
|
|
151
|
+
createTimer,
|
|
140
152
|
stripBasePath
|
|
141
153
|
});
|
|
142
154
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/services/request-context.service.ts","../src/decorators/auto-trace.decorator.ts","../src/tokens.ts","../src/module.ts","../src/utils/strip-base-path.ts"],"sourcesContent":["export { RequestContextService, type RequestContextState } from './services/request-context.service';\nexport { AutoTrace } from './decorators/auto-trace.decorator';\nexport { CommonModule } from './module';\nexport { stripBasePath } from './utils/strip-base-path';\nexport * from './tokens';\nexport * from './type';\n","import { Injectable } from '@nestjs/common';\nimport { AsyncLocalStorage } from 'async_hooks';\n\nexport interface RequestContextState {\n requestId?: string;\n path?: string;\n method?: string;\n userId?: string;\n appId?: string;\n tenantId?: string;\n ip?: string;\n requestRootSpan?: unknown;\n /** x-tt-env header,用于环境标识透传(如灰度/测试环境) */\n ttEnv?: string;\n /** 请求来源页面路由 (X-Page-Route header) */\n pageRoute?: string;\n /** 是否为系统账号 */\n isSystemAccount?: boolean;\n [key: string]: unknown;\n}\n\n@Injectable()\nexport class RequestContextService {\n private readonly storage = new AsyncLocalStorage<RequestContextState>();\n\n run<T>(context: RequestContextState, callback: () => T): T {\n const store = { ...context };\n return this.storage.run(store, callback);\n }\n\n setContext(partial: Partial<RequestContextState>): void {\n const store = this.storage.getStore();\n if (!store) {\n return;\n }\n Object.assign(store, partial);\n }\n\n getContext(): RequestContextState | undefined {\n return this.storage.getStore();\n }\n\n get<K extends keyof RequestContextState>(key: K): RequestContextState[K] | undefined {\n return this.storage.getStore()?.[key];\n }\n}\n","import { SetMetadata } from '@nestjs/common';\nimport { AUTO_TRACE } from '../tokens';\n\nexport const AutoTrace = (options: string) => {\n return SetMetadata(AUTO_TRACE, options);\n};","/**\n * DI token for ObservableService\n *\n * 注入此 token 获得 ObservableService 实例\n */\nexport const OBSERVABLE_SERVICE = Symbol('OBSERVABLE_SERVICE');\n\n/**\n * DI Token for Platform HttpClient\n *\n * 这些 token 供 PlatformModule 和内部依赖(如 AuthNPaasModule)共享使用,通过创建独立的 nestjs-common 包,避免循环依赖\n *\n * @example\n * ```typescript\n * // nestjs-core 中注册 provider\n * import { PLATFORM_HTTP_CLIENT } from '@lark-apaas/nestjs-common';\n *\n * {\n * provide: PLATFORM_HTTP_CLIENT,\n * useFactory: (svc: PlatformHttpClientService) => svc.instance,\n * inject: [PlatformHttpClientService],\n * }\n * ```\n *\n * @example\n * ```typescript\n * // nestjs-authnpaas 中注入使用\n * import { Injectable, Inject } from '@nestjs/common';\n * import { PLATFORM_HTTP_CLIENT, type SafeHttpClient } from '@lark-apaas/nestjs-common';\n *\n * @Injectable()\n * export class AuthNService {\n * constructor(\n * @Inject(PLATFORM_HTTP_CLIENT) private http: SafeHttpClient\n * ) {}\n * }\n * ```\n */\n\n/**\n * DI token for PlatformHttpClient instance\n *\n * 注入此 token 获得 SafeHttpClient 实例(不暴露 interceptors)\n */\nexport const PLATFORM_HTTP_CLIENT = Symbol('PLATFORM_HTTP_CLIENT');\n\n/**\n * DI token for AutoTraceInterceptor\n *\n * 此 token 用于元数据存取 AUTO_TRACE 装饰器的参数\n */\nexport const AUTO_TRACE = Symbol('AUTO_TRACE');\n\n/**\n * DI token for HttpClientFactory\n *\n * 用于创建独立的 HttpClient 实例,支持自定义拦截器\n *\n * @example\n * ```typescript\n * // 注入并使用\n * @Injectable()\n * export class PluginService {\n * constructor(\n * @Inject(HTTP_CLIENT_FACTORY) private factory: HttpClientFactory\n * ) {}\n *\n * createClientForPlugin(pluginKey: string) {\n * const client = this.factory.create();\n * client.interceptors.request.use((config) => {\n * config.headers['x-plugin-key'] = pluginKey;\n * return config;\n * });\n * return client;\n * }\n * }\n * ```\n */\nexport const HTTP_CLIENT_FACTORY = Symbol('HTTP_CLIENT_FACTORY');\n","import { Global, Module } from '@nestjs/common';\nimport { RequestContextService } from './services/request-context.service';\n\n@Global()\n@Module({\n providers: [RequestContextService],\n exports: [RequestContextService],\n})\nexport class CommonModule {}\n","/**\n * 从完整路径中去除 basePath 前缀,获取相对页面路由\n *\n * @param fullPath - 完整路径,如 \"/af/p/app_xxx/dashboard\"\n * @param basePath - 基础路径前缀,如 \"/af/p/app_xxx\",通常来自 CLIENT_BASE_PATH 环境变量\n * @returns 去除前缀后的相对路径,如 \"/dashboard\";如果无法处理则返回原值\n *\n * @example\n * stripBasePath('/af/p/app_xxx/dashboard', '/af/p/app_xxx') // => '/dashboard'\n * stripBasePath('/af/p/app_xxx', '/af/p/app_xxx') // => '/'\n * stripBasePath('/other/path', '/af/p/app_xxx') // => '/other/path'\n * stripBasePath(undefined, '/af/p/app_xxx') // => undefined\n * stripBasePath('/dashboard', '') // => '/dashboard'\n */\nexport function stripBasePath(\n fullPath: string | undefined | null,\n basePath: string | undefined | null,\n): string | undefined | null {\n // 如果 fullPath 为空,直接返回\n if (!fullPath) {\n return fullPath;\n }\n\n // 如果 basePath 为空,直接返回原路径\n if (!basePath) {\n return fullPath;\n }\n\n // 如果 fullPath 以 basePath 开头,去除前缀\n // 需要确保是完整的路径段匹配,避免部分匹配(如 /app_xxx 匹配到 /app_xxx_extended)\n if (fullPath.startsWith(basePath)) {\n const stripped = fullPath.slice(basePath.length);\n // 确保 stripped 为空(完全匹配)或以 '/' 开头(路径段边界)\n if (stripped === '' || stripped.startsWith('/')) {\n return stripped || '/';\n }\n }\n\n // 不匹配则返回原路径\n return fullPath;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/services/request-context.service.ts","../src/decorators/auto-trace.decorator.ts","../src/tokens.ts","../src/module.ts","../src/utils/strip-base-path.ts","../src/utils/create-timer.ts"],"sourcesContent":["export { RequestContextService, type RequestContextState } from './services/request-context.service';\nexport { AutoTrace } from './decorators/auto-trace.decorator';\nexport { CommonModule } from './module';\nexport { stripBasePath } from './utils/strip-base-path';\nexport { createTimer } from './utils/create-timer';\nexport * from './tokens';\nexport * from './type';\n","import { Injectable } from '@nestjs/common';\nimport { AsyncLocalStorage } from 'async_hooks';\n\nexport interface RequestContextState {\n requestId?: string;\n path?: string;\n method?: string;\n userId?: string;\n appId?: string;\n tenantId?: string;\n ip?: string;\n requestRootSpan?: unknown;\n /** x-tt-env header,用于环境标识透传(如灰度/测试环境) */\n ttEnv?: string;\n /** 请求来源页面路由 (X-Page-Route header) */\n pageRoute?: string;\n /** 前端参数化页面路由 (Rpc-Persist-Apaas-Observability-Referer-Path) */\n refererPath?: string;\n /** 前端参数化 API 标识 (Rpc-Persist-Apaas-Observability-Api) */\n observabilityApi?: string;\n /** 是否为系统账号 */\n isSystemAccount?: boolean;\n [key: string]: unknown;\n}\n\n@Injectable()\nexport class RequestContextService {\n private readonly storage = new AsyncLocalStorage<RequestContextState>();\n\n run<T>(context: RequestContextState, callback: () => T): T {\n const store = { ...context };\n return this.storage.run(store, callback);\n }\n\n setContext(partial: Partial<RequestContextState>): void {\n const store = this.storage.getStore();\n if (!store) {\n return;\n }\n Object.assign(store, partial);\n }\n\n getContext(): RequestContextState | undefined {\n return this.storage.getStore();\n }\n\n get<K extends keyof RequestContextState>(key: K): RequestContextState[K] | undefined {\n return this.storage.getStore()?.[key];\n }\n}\n","import { SetMetadata } from '@nestjs/common';\nimport { AUTO_TRACE } from '../tokens';\n\nexport const AutoTrace = (options: string) => {\n return SetMetadata(AUTO_TRACE, options);\n};","/**\n * DI token for ObservableService\n *\n * 注入此 token 获得 ObservableService 实例\n */\nexport const OBSERVABLE_SERVICE = Symbol('OBSERVABLE_SERVICE');\n\n/**\n * DI Token for Platform HttpClient\n *\n * 这些 token 供 PlatformModule 和内部依赖(如 AuthNPaasModule)共享使用,通过创建独立的 nestjs-common 包,避免循环依赖\n *\n * @example\n * ```typescript\n * // nestjs-core 中注册 provider\n * import { PLATFORM_HTTP_CLIENT } from '@lark-apaas/nestjs-common';\n *\n * {\n * provide: PLATFORM_HTTP_CLIENT,\n * useFactory: (svc: PlatformHttpClientService) => svc.instance,\n * inject: [PlatformHttpClientService],\n * }\n * ```\n *\n * @example\n * ```typescript\n * // nestjs-authnpaas 中注入使用\n * import { Injectable, Inject } from '@nestjs/common';\n * import { PLATFORM_HTTP_CLIENT, type SafeHttpClient } from '@lark-apaas/nestjs-common';\n *\n * @Injectable()\n * export class AuthNService {\n * constructor(\n * @Inject(PLATFORM_HTTP_CLIENT) private http: SafeHttpClient\n * ) {}\n * }\n * ```\n */\n\n/**\n * DI token for PlatformHttpClient instance\n *\n * 注入此 token 获得 SafeHttpClient 实例(不暴露 interceptors)\n */\nexport const PLATFORM_HTTP_CLIENT = Symbol('PLATFORM_HTTP_CLIENT');\n\n/**\n * DI token for AutoTraceInterceptor\n *\n * 此 token 用于元数据存取 AUTO_TRACE 装饰器的参数\n */\nexport const AUTO_TRACE = Symbol('AUTO_TRACE');\n\n/**\n * DI token for HttpClientFactory\n *\n * 用于创建独立的 HttpClient 实例,支持自定义拦截器\n *\n * @example\n * ```typescript\n * // 注入并使用\n * @Injectable()\n * export class PluginService {\n * constructor(\n * @Inject(HTTP_CLIENT_FACTORY) private factory: HttpClientFactory\n * ) {}\n *\n * createClientForPlugin(pluginKey: string) {\n * const client = this.factory.create();\n * client.interceptors.request.use((config) => {\n * config.headers['x-plugin-key'] = pluginKey;\n * return config;\n * });\n * return client;\n * }\n * }\n * ```\n */\nexport const HTTP_CLIENT_FACTORY = Symbol('HTTP_CLIENT_FACTORY');\n","import { Global, Module } from '@nestjs/common';\nimport { RequestContextService } from './services/request-context.service';\n\n@Global()\n@Module({\n providers: [RequestContextService],\n exports: [RequestContextService],\n})\nexport class CommonModule {}\n","/**\n * 从完整路径中去除 basePath 前缀,获取相对页面路由\n *\n * @param fullPath - 完整路径,如 \"/af/p/app_xxx/dashboard\"\n * @param basePath - 基础路径前缀,如 \"/af/p/app_xxx\",通常来自 CLIENT_BASE_PATH 环境变量\n * @returns 去除前缀后的相对路径,如 \"/dashboard\";如果无法处理则返回原值\n *\n * @example\n * stripBasePath('/af/p/app_xxx/dashboard', '/af/p/app_xxx') // => '/dashboard'\n * stripBasePath('/af/p/app_xxx', '/af/p/app_xxx') // => '/'\n * stripBasePath('/other/path', '/af/p/app_xxx') // => '/other/path'\n * stripBasePath(undefined, '/af/p/app_xxx') // => undefined\n * stripBasePath('/dashboard', '') // => '/dashboard'\n */\nexport function stripBasePath(\n fullPath: string | undefined | null,\n basePath: string | undefined | null,\n): string | undefined | null {\n // 如果 fullPath 为空,直接返回\n if (!fullPath) {\n return fullPath;\n }\n\n // 如果 basePath 为空,直接返回原路径\n if (!basePath) {\n return fullPath;\n }\n\n // 如果 fullPath 以 basePath 开头,去除前缀\n // 需要确保是完整的路径段匹配,避免部分匹配(如 /app_xxx 匹配到 /app_xxx_extended)\n if (fullPath.startsWith(basePath)) {\n const stripped = fullPath.slice(basePath.length);\n // 确保 stripped 为空(完全匹配)或以 '/' 开头(路径段边界)\n if (stripped === '' || stripped.startsWith('/')) {\n return stripped || '/';\n }\n }\n\n // 不匹配则返回原路径\n return fullPath;\n}\n","/**\n * 创建高精度计时器\n * 使用 process.hrtime 正确计算秒 + 纳秒,支持亚毫秒测量\n * 返回一个函数,调用后返回经过的毫秒数(保留两位小数)\n */\nexport function createTimer(): () => number {\n const start = process.hrtime();\n return () => {\n const diff = process.hrtime(start);\n return Math.round((diff[0] * 1000 + diff[1] / 1e6) * 100) / 100;\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;ACAA,oBAA2B;AAC3B,yBAAkC;;;;;;;;AAyB3B,IAAMA,wBAAN,MAAMA;SAAAA;;;EACMC,UAAU,IAAIC,qCAAAA;EAE/BC,IAAOC,SAA8BC,UAAsB;AACzD,UAAMC,QAAQ;MAAE,GAAGF;IAAQ;AAC3B,WAAO,KAAKH,QAAQE,IAAIG,OAAOD,QAAAA;EACjC;EAEAE,WAAWC,SAA6C;AACtD,UAAMF,QAAQ,KAAKL,QAAQQ,SAAQ;AACnC,QAAI,CAACH,OAAO;AACV;IACF;AACAI,WAAOC,OAAOL,OAAOE,OAAAA;EACvB;EAEAI,aAA8C;AAC5C,WAAO,KAAKX,QAAQQ,SAAQ;EAC9B;EAEAI,IAAyCC,KAA4C;AACnF,WAAO,KAAKb,QAAQQ,SAAQ,IAAKK,GAAAA;EACnC;AACF;;;;;;ACjDA,IAAAC,iBAA4B;;;ACKrB,IAAMC,qBAAqBC,uBAAO,oBAAA;AAuClC,IAAMC,uBAAuBD,uBAAO,sBAAA;AAOpC,IAAME,aAAaF,uBAAO,YAAA;AA2B1B,IAAMG,sBAAsBH,uBAAO,qBAAA;;;AD3EnC,IAAMI,YAAY,wBAACC,YAAAA;AACxB,aAAOC,4BAAYC,YAAYF,OAAAA;AACjC,GAFyB;;;AEHzB,IAAAG,iBAA+B;;;;;;;;AAQxB,IAAMC,eAAN,MAAMA;SAAAA;;;AAAc;;;;IAHzBC,WAAW;MAACC;;IACZC,SAAS;MAACD;;;;;;ACQL,SAASE,cACdC,UACAC,UAAmC;AAGnC,MAAI,CAACD,UAAU;AACb,WAAOA;EACT;AAGA,MAAI,CAACC,UAAU;AACb,WAAOD;EACT;AAIA,MAAIA,SAASE,WAAWD,QAAAA,GAAW;AACjC,UAAME,WAAWH,SAASI,MAAMH,SAASI,MAAM;AAE/C,QAAIF,aAAa,MAAMA,SAASD,WAAW,GAAA,GAAM;AAC/C,aAAOC,YAAY;IACrB;EACF;AAGA,SAAOH;AACT;AA1BgBD;;;ACTT,SAASO,cAAAA;AACd,QAAMC,QAAQC,QAAQC,OAAM;AAC5B,SAAO,MAAA;AACL,UAAMC,OAAOF,QAAQC,OAAOF,KAAAA;AAC5B,WAAOI,KAAKC,OAAOF,KAAK,CAAA,IAAK,MAAOA,KAAK,CAAA,IAAK,OAAO,GAAA,IAAO;EAC9D;AACF;AANgBJ;","names":["RequestContextService","storage","AsyncLocalStorage","run","context","callback","store","setContext","partial","getStore","Object","assign","getContext","get","key","import_common","OBSERVABLE_SERVICE","Symbol","PLATFORM_HTTP_CLIENT","AUTO_TRACE","HTTP_CLIENT_FACTORY","AutoTrace","options","SetMetadata","AUTO_TRACE","import_common","CommonModule","providers","RequestContextService","exports","stripBasePath","fullPath","basePath","startsWith","stripped","slice","length","createTimer","start","process","hrtime","diff","Math","round"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -13,6 +13,10 @@ interface RequestContextState {
|
|
|
13
13
|
ttEnv?: string;
|
|
14
14
|
/** 请求来源页面路由 (X-Page-Route header) */
|
|
15
15
|
pageRoute?: string;
|
|
16
|
+
/** 前端参数化页面路由 (Rpc-Persist-Apaas-Observability-Referer-Path) */
|
|
17
|
+
refererPath?: string;
|
|
18
|
+
/** 前端参数化 API 标识 (Rpc-Persist-Apaas-Observability-Api) */
|
|
19
|
+
observabilityApi?: string;
|
|
16
20
|
/** 是否为系统账号 */
|
|
17
21
|
isSystemAccount?: boolean;
|
|
18
22
|
[key: string]: unknown;
|
|
@@ -122,6 +126,13 @@ declare class CommonModule {
|
|
|
122
126
|
*/
|
|
123
127
|
declare function stripBasePath(fullPath: string | undefined | null, basePath: string | undefined | null): string | undefined | null;
|
|
124
128
|
|
|
129
|
+
/**
|
|
130
|
+
* 创建高精度计时器
|
|
131
|
+
* 使用 process.hrtime 正确计算秒 + 纳秒,支持亚毫秒测量
|
|
132
|
+
* 返回一个函数,调用后返回经过的毫秒数(保留两位小数)
|
|
133
|
+
*/
|
|
134
|
+
declare function createTimer(): () => number;
|
|
135
|
+
|
|
125
136
|
interface ObservableService {
|
|
126
137
|
log(level: string, message: string, attributes: Record<string, unknown>, parentSpan?: {
|
|
127
138
|
traceId: string;
|
|
@@ -246,4 +257,4 @@ interface HttpClientFactory {
|
|
|
246
257
|
create(options?: unknown): HttpClientWithInterceptors;
|
|
247
258
|
}
|
|
248
259
|
|
|
249
|
-
export { AUTO_TRACE, AutoTrace, CommonModule, HTTP_CLIENT_FACTORY, type HttpClientFactory, type HttpClientWithInterceptors, OBSERVABLE_SERVICE, type ObservableService, PLATFORM_HTTP_CLIENT, type PlatformHttpClient, RequestContextService, type RequestContextState, stripBasePath };
|
|
260
|
+
export { AUTO_TRACE, AutoTrace, CommonModule, HTTP_CLIENT_FACTORY, type HttpClientFactory, type HttpClientWithInterceptors, OBSERVABLE_SERVICE, type ObservableService, PLATFORM_HTTP_CLIENT, type PlatformHttpClient, RequestContextService, type RequestContextState, createTimer, stripBasePath };
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,10 @@ interface RequestContextState {
|
|
|
13
13
|
ttEnv?: string;
|
|
14
14
|
/** 请求来源页面路由 (X-Page-Route header) */
|
|
15
15
|
pageRoute?: string;
|
|
16
|
+
/** 前端参数化页面路由 (Rpc-Persist-Apaas-Observability-Referer-Path) */
|
|
17
|
+
refererPath?: string;
|
|
18
|
+
/** 前端参数化 API 标识 (Rpc-Persist-Apaas-Observability-Api) */
|
|
19
|
+
observabilityApi?: string;
|
|
16
20
|
/** 是否为系统账号 */
|
|
17
21
|
isSystemAccount?: boolean;
|
|
18
22
|
[key: string]: unknown;
|
|
@@ -122,6 +126,13 @@ declare class CommonModule {
|
|
|
122
126
|
*/
|
|
123
127
|
declare function stripBasePath(fullPath: string | undefined | null, basePath: string | undefined | null): string | undefined | null;
|
|
124
128
|
|
|
129
|
+
/**
|
|
130
|
+
* 创建高精度计时器
|
|
131
|
+
* 使用 process.hrtime 正确计算秒 + 纳秒,支持亚毫秒测量
|
|
132
|
+
* 返回一个函数,调用后返回经过的毫秒数(保留两位小数)
|
|
133
|
+
*/
|
|
134
|
+
declare function createTimer(): () => number;
|
|
135
|
+
|
|
125
136
|
interface ObservableService {
|
|
126
137
|
log(level: string, message: string, attributes: Record<string, unknown>, parentSpan?: {
|
|
127
138
|
traceId: string;
|
|
@@ -246,4 +257,4 @@ interface HttpClientFactory {
|
|
|
246
257
|
create(options?: unknown): HttpClientWithInterceptors;
|
|
247
258
|
}
|
|
248
259
|
|
|
249
|
-
export { AUTO_TRACE, AutoTrace, CommonModule, HTTP_CLIENT_FACTORY, type HttpClientFactory, type HttpClientWithInterceptors, OBSERVABLE_SERVICE, type ObservableService, PLATFORM_HTTP_CLIENT, type PlatformHttpClient, RequestContextService, type RequestContextState, stripBasePath };
|
|
260
|
+
export { AUTO_TRACE, AutoTrace, CommonModule, HTTP_CLIENT_FACTORY, type HttpClientFactory, type HttpClientWithInterceptors, OBSERVABLE_SERVICE, type ObservableService, PLATFORM_HTTP_CLIENT, type PlatformHttpClient, RequestContextService, type RequestContextState, createTimer, stripBasePath };
|
package/dist/index.js
CHANGED
|
@@ -97,6 +97,16 @@ function stripBasePath(fullPath, basePath) {
|
|
|
97
97
|
return fullPath;
|
|
98
98
|
}
|
|
99
99
|
__name(stripBasePath, "stripBasePath");
|
|
100
|
+
|
|
101
|
+
// src/utils/create-timer.ts
|
|
102
|
+
function createTimer() {
|
|
103
|
+
const start = process.hrtime();
|
|
104
|
+
return () => {
|
|
105
|
+
const diff = process.hrtime(start);
|
|
106
|
+
return Math.round((diff[0] * 1e3 + diff[1] / 1e6) * 100) / 100;
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
__name(createTimer, "createTimer");
|
|
100
110
|
export {
|
|
101
111
|
AUTO_TRACE,
|
|
102
112
|
AutoTrace,
|
|
@@ -105,6 +115,7 @@ export {
|
|
|
105
115
|
OBSERVABLE_SERVICE,
|
|
106
116
|
PLATFORM_HTTP_CLIENT,
|
|
107
117
|
RequestContextService,
|
|
118
|
+
createTimer,
|
|
108
119
|
stripBasePath
|
|
109
120
|
};
|
|
110
121
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/services/request-context.service.ts","../src/decorators/auto-trace.decorator.ts","../src/tokens.ts","../src/module.ts","../src/utils/strip-base-path.ts"],"sourcesContent":["import { Injectable } from '@nestjs/common';\nimport { AsyncLocalStorage } from 'async_hooks';\n\nexport interface RequestContextState {\n requestId?: string;\n path?: string;\n method?: string;\n userId?: string;\n appId?: string;\n tenantId?: string;\n ip?: string;\n requestRootSpan?: unknown;\n /** x-tt-env header,用于环境标识透传(如灰度/测试环境) */\n ttEnv?: string;\n /** 请求来源页面路由 (X-Page-Route header) */\n pageRoute?: string;\n /** 是否为系统账号 */\n isSystemAccount?: boolean;\n [key: string]: unknown;\n}\n\n@Injectable()\nexport class RequestContextService {\n private readonly storage = new AsyncLocalStorage<RequestContextState>();\n\n run<T>(context: RequestContextState, callback: () => T): T {\n const store = { ...context };\n return this.storage.run(store, callback);\n }\n\n setContext(partial: Partial<RequestContextState>): void {\n const store = this.storage.getStore();\n if (!store) {\n return;\n }\n Object.assign(store, partial);\n }\n\n getContext(): RequestContextState | undefined {\n return this.storage.getStore();\n }\n\n get<K extends keyof RequestContextState>(key: K): RequestContextState[K] | undefined {\n return this.storage.getStore()?.[key];\n }\n}\n","import { SetMetadata } from '@nestjs/common';\nimport { AUTO_TRACE } from '../tokens';\n\nexport const AutoTrace = (options: string) => {\n return SetMetadata(AUTO_TRACE, options);\n};","/**\n * DI token for ObservableService\n *\n * 注入此 token 获得 ObservableService 实例\n */\nexport const OBSERVABLE_SERVICE = Symbol('OBSERVABLE_SERVICE');\n\n/**\n * DI Token for Platform HttpClient\n *\n * 这些 token 供 PlatformModule 和内部依赖(如 AuthNPaasModule)共享使用,通过创建独立的 nestjs-common 包,避免循环依赖\n *\n * @example\n * ```typescript\n * // nestjs-core 中注册 provider\n * import { PLATFORM_HTTP_CLIENT } from '@lark-apaas/nestjs-common';\n *\n * {\n * provide: PLATFORM_HTTP_CLIENT,\n * useFactory: (svc: PlatformHttpClientService) => svc.instance,\n * inject: [PlatformHttpClientService],\n * }\n * ```\n *\n * @example\n * ```typescript\n * // nestjs-authnpaas 中注入使用\n * import { Injectable, Inject } from '@nestjs/common';\n * import { PLATFORM_HTTP_CLIENT, type SafeHttpClient } from '@lark-apaas/nestjs-common';\n *\n * @Injectable()\n * export class AuthNService {\n * constructor(\n * @Inject(PLATFORM_HTTP_CLIENT) private http: SafeHttpClient\n * ) {}\n * }\n * ```\n */\n\n/**\n * DI token for PlatformHttpClient instance\n *\n * 注入此 token 获得 SafeHttpClient 实例(不暴露 interceptors)\n */\nexport const PLATFORM_HTTP_CLIENT = Symbol('PLATFORM_HTTP_CLIENT');\n\n/**\n * DI token for AutoTraceInterceptor\n *\n * 此 token 用于元数据存取 AUTO_TRACE 装饰器的参数\n */\nexport const AUTO_TRACE = Symbol('AUTO_TRACE');\n\n/**\n * DI token for HttpClientFactory\n *\n * 用于创建独立的 HttpClient 实例,支持自定义拦截器\n *\n * @example\n * ```typescript\n * // 注入并使用\n * @Injectable()\n * export class PluginService {\n * constructor(\n * @Inject(HTTP_CLIENT_FACTORY) private factory: HttpClientFactory\n * ) {}\n *\n * createClientForPlugin(pluginKey: string) {\n * const client = this.factory.create();\n * client.interceptors.request.use((config) => {\n * config.headers['x-plugin-key'] = pluginKey;\n * return config;\n * });\n * return client;\n * }\n * }\n * ```\n */\nexport const HTTP_CLIENT_FACTORY = Symbol('HTTP_CLIENT_FACTORY');\n","import { Global, Module } from '@nestjs/common';\nimport { RequestContextService } from './services/request-context.service';\n\n@Global()\n@Module({\n providers: [RequestContextService],\n exports: [RequestContextService],\n})\nexport class CommonModule {}\n","/**\n * 从完整路径中去除 basePath 前缀,获取相对页面路由\n *\n * @param fullPath - 完整路径,如 \"/af/p/app_xxx/dashboard\"\n * @param basePath - 基础路径前缀,如 \"/af/p/app_xxx\",通常来自 CLIENT_BASE_PATH 环境变量\n * @returns 去除前缀后的相对路径,如 \"/dashboard\";如果无法处理则返回原值\n *\n * @example\n * stripBasePath('/af/p/app_xxx/dashboard', '/af/p/app_xxx') // => '/dashboard'\n * stripBasePath('/af/p/app_xxx', '/af/p/app_xxx') // => '/'\n * stripBasePath('/other/path', '/af/p/app_xxx') // => '/other/path'\n * stripBasePath(undefined, '/af/p/app_xxx') // => undefined\n * stripBasePath('/dashboard', '') // => '/dashboard'\n */\nexport function stripBasePath(\n fullPath: string | undefined | null,\n basePath: string | undefined | null,\n): string | undefined | null {\n // 如果 fullPath 为空,直接返回\n if (!fullPath) {\n return fullPath;\n }\n\n // 如果 basePath 为空,直接返回原路径\n if (!basePath) {\n return fullPath;\n }\n\n // 如果 fullPath 以 basePath 开头,去除前缀\n // 需要确保是完整的路径段匹配,避免部分匹配(如 /app_xxx 匹配到 /app_xxx_extended)\n if (fullPath.startsWith(basePath)) {\n const stripped = fullPath.slice(basePath.length);\n // 确保 stripped 为空(完全匹配)或以 '/' 开头(路径段边界)\n if (stripped === '' || stripped.startsWith('/')) {\n return stripped || '/';\n }\n }\n\n // 不匹配则返回原路径\n return fullPath;\n}\n"],"mappings":";;;;AAAA,SAASA,kBAAkB;AAC3B,SAASC,yBAAyB;;;;;;;;
|
|
1
|
+
{"version":3,"sources":["../src/services/request-context.service.ts","../src/decorators/auto-trace.decorator.ts","../src/tokens.ts","../src/module.ts","../src/utils/strip-base-path.ts","../src/utils/create-timer.ts"],"sourcesContent":["import { Injectable } from '@nestjs/common';\nimport { AsyncLocalStorage } from 'async_hooks';\n\nexport interface RequestContextState {\n requestId?: string;\n path?: string;\n method?: string;\n userId?: string;\n appId?: string;\n tenantId?: string;\n ip?: string;\n requestRootSpan?: unknown;\n /** x-tt-env header,用于环境标识透传(如灰度/测试环境) */\n ttEnv?: string;\n /** 请求来源页面路由 (X-Page-Route header) */\n pageRoute?: string;\n /** 前端参数化页面路由 (Rpc-Persist-Apaas-Observability-Referer-Path) */\n refererPath?: string;\n /** 前端参数化 API 标识 (Rpc-Persist-Apaas-Observability-Api) */\n observabilityApi?: string;\n /** 是否为系统账号 */\n isSystemAccount?: boolean;\n [key: string]: unknown;\n}\n\n@Injectable()\nexport class RequestContextService {\n private readonly storage = new AsyncLocalStorage<RequestContextState>();\n\n run<T>(context: RequestContextState, callback: () => T): T {\n const store = { ...context };\n return this.storage.run(store, callback);\n }\n\n setContext(partial: Partial<RequestContextState>): void {\n const store = this.storage.getStore();\n if (!store) {\n return;\n }\n Object.assign(store, partial);\n }\n\n getContext(): RequestContextState | undefined {\n return this.storage.getStore();\n }\n\n get<K extends keyof RequestContextState>(key: K): RequestContextState[K] | undefined {\n return this.storage.getStore()?.[key];\n }\n}\n","import { SetMetadata } from '@nestjs/common';\nimport { AUTO_TRACE } from '../tokens';\n\nexport const AutoTrace = (options: string) => {\n return SetMetadata(AUTO_TRACE, options);\n};","/**\n * DI token for ObservableService\n *\n * 注入此 token 获得 ObservableService 实例\n */\nexport const OBSERVABLE_SERVICE = Symbol('OBSERVABLE_SERVICE');\n\n/**\n * DI Token for Platform HttpClient\n *\n * 这些 token 供 PlatformModule 和内部依赖(如 AuthNPaasModule)共享使用,通过创建独立的 nestjs-common 包,避免循环依赖\n *\n * @example\n * ```typescript\n * // nestjs-core 中注册 provider\n * import { PLATFORM_HTTP_CLIENT } from '@lark-apaas/nestjs-common';\n *\n * {\n * provide: PLATFORM_HTTP_CLIENT,\n * useFactory: (svc: PlatformHttpClientService) => svc.instance,\n * inject: [PlatformHttpClientService],\n * }\n * ```\n *\n * @example\n * ```typescript\n * // nestjs-authnpaas 中注入使用\n * import { Injectable, Inject } from '@nestjs/common';\n * import { PLATFORM_HTTP_CLIENT, type SafeHttpClient } from '@lark-apaas/nestjs-common';\n *\n * @Injectable()\n * export class AuthNService {\n * constructor(\n * @Inject(PLATFORM_HTTP_CLIENT) private http: SafeHttpClient\n * ) {}\n * }\n * ```\n */\n\n/**\n * DI token for PlatformHttpClient instance\n *\n * 注入此 token 获得 SafeHttpClient 实例(不暴露 interceptors)\n */\nexport const PLATFORM_HTTP_CLIENT = Symbol('PLATFORM_HTTP_CLIENT');\n\n/**\n * DI token for AutoTraceInterceptor\n *\n * 此 token 用于元数据存取 AUTO_TRACE 装饰器的参数\n */\nexport const AUTO_TRACE = Symbol('AUTO_TRACE');\n\n/**\n * DI token for HttpClientFactory\n *\n * 用于创建独立的 HttpClient 实例,支持自定义拦截器\n *\n * @example\n * ```typescript\n * // 注入并使用\n * @Injectable()\n * export class PluginService {\n * constructor(\n * @Inject(HTTP_CLIENT_FACTORY) private factory: HttpClientFactory\n * ) {}\n *\n * createClientForPlugin(pluginKey: string) {\n * const client = this.factory.create();\n * client.interceptors.request.use((config) => {\n * config.headers['x-plugin-key'] = pluginKey;\n * return config;\n * });\n * return client;\n * }\n * }\n * ```\n */\nexport const HTTP_CLIENT_FACTORY = Symbol('HTTP_CLIENT_FACTORY');\n","import { Global, Module } from '@nestjs/common';\nimport { RequestContextService } from './services/request-context.service';\n\n@Global()\n@Module({\n providers: [RequestContextService],\n exports: [RequestContextService],\n})\nexport class CommonModule {}\n","/**\n * 从完整路径中去除 basePath 前缀,获取相对页面路由\n *\n * @param fullPath - 完整路径,如 \"/af/p/app_xxx/dashboard\"\n * @param basePath - 基础路径前缀,如 \"/af/p/app_xxx\",通常来自 CLIENT_BASE_PATH 环境变量\n * @returns 去除前缀后的相对路径,如 \"/dashboard\";如果无法处理则返回原值\n *\n * @example\n * stripBasePath('/af/p/app_xxx/dashboard', '/af/p/app_xxx') // => '/dashboard'\n * stripBasePath('/af/p/app_xxx', '/af/p/app_xxx') // => '/'\n * stripBasePath('/other/path', '/af/p/app_xxx') // => '/other/path'\n * stripBasePath(undefined, '/af/p/app_xxx') // => undefined\n * stripBasePath('/dashboard', '') // => '/dashboard'\n */\nexport function stripBasePath(\n fullPath: string | undefined | null,\n basePath: string | undefined | null,\n): string | undefined | null {\n // 如果 fullPath 为空,直接返回\n if (!fullPath) {\n return fullPath;\n }\n\n // 如果 basePath 为空,直接返回原路径\n if (!basePath) {\n return fullPath;\n }\n\n // 如果 fullPath 以 basePath 开头,去除前缀\n // 需要确保是完整的路径段匹配,避免部分匹配(如 /app_xxx 匹配到 /app_xxx_extended)\n if (fullPath.startsWith(basePath)) {\n const stripped = fullPath.slice(basePath.length);\n // 确保 stripped 为空(完全匹配)或以 '/' 开头(路径段边界)\n if (stripped === '' || stripped.startsWith('/')) {\n return stripped || '/';\n }\n }\n\n // 不匹配则返回原路径\n return fullPath;\n}\n","/**\n * 创建高精度计时器\n * 使用 process.hrtime 正确计算秒 + 纳秒,支持亚毫秒测量\n * 返回一个函数,调用后返回经过的毫秒数(保留两位小数)\n */\nexport function createTimer(): () => number {\n const start = process.hrtime();\n return () => {\n const diff = process.hrtime(start);\n return Math.round((diff[0] * 1000 + diff[1] / 1e6) * 100) / 100;\n };\n}\n"],"mappings":";;;;AAAA,SAASA,kBAAkB;AAC3B,SAASC,yBAAyB;;;;;;;;AAyB3B,IAAMC,wBAAN,MAAMA;SAAAA;;;EACMC,UAAU,IAAIC,kBAAAA;EAE/BC,IAAOC,SAA8BC,UAAsB;AACzD,UAAMC,QAAQ;MAAE,GAAGF;IAAQ;AAC3B,WAAO,KAAKH,QAAQE,IAAIG,OAAOD,QAAAA;EACjC;EAEAE,WAAWC,SAA6C;AACtD,UAAMF,QAAQ,KAAKL,QAAQQ,SAAQ;AACnC,QAAI,CAACH,OAAO;AACV;IACF;AACAI,WAAOC,OAAOL,OAAOE,OAAAA;EACvB;EAEAI,aAA8C;AAC5C,WAAO,KAAKX,QAAQQ,SAAQ;EAC9B;EAEAI,IAAyCC,KAA4C;AACnF,WAAO,KAAKb,QAAQQ,SAAQ,IAAKK,GAAAA;EACnC;AACF;;;;;;ACjDA,SAASC,mBAAmB;;;ACKrB,IAAMC,qBAAqBC,uBAAO,oBAAA;AAuClC,IAAMC,uBAAuBD,uBAAO,sBAAA;AAOpC,IAAME,aAAaF,uBAAO,YAAA;AA2B1B,IAAMG,sBAAsBH,uBAAO,qBAAA;;;AD3EnC,IAAMI,YAAY,wBAACC,YAAAA;AACxB,SAAOC,YAAYC,YAAYF,OAAAA;AACjC,GAFyB;;;AEHzB,SAASG,QAAQC,cAAc;;;;;;;;AAQxB,IAAMC,eAAN,MAAMA;SAAAA;;;AAAc;;;;IAHzBC,WAAW;MAACC;;IACZC,SAAS;MAACD;;;;;;ACQL,SAASE,cACdC,UACAC,UAAmC;AAGnC,MAAI,CAACD,UAAU;AACb,WAAOA;EACT;AAGA,MAAI,CAACC,UAAU;AACb,WAAOD;EACT;AAIA,MAAIA,SAASE,WAAWD,QAAAA,GAAW;AACjC,UAAME,WAAWH,SAASI,MAAMH,SAASI,MAAM;AAE/C,QAAIF,aAAa,MAAMA,SAASD,WAAW,GAAA,GAAM;AAC/C,aAAOC,YAAY;IACrB;EACF;AAGA,SAAOH;AACT;AA1BgBD;;;ACTT,SAASO,cAAAA;AACd,QAAMC,QAAQC,QAAQC,OAAM;AAC5B,SAAO,MAAA;AACL,UAAMC,OAAOF,QAAQC,OAAOF,KAAAA;AAC5B,WAAOI,KAAKC,OAAOF,KAAK,CAAA,IAAK,MAAOA,KAAK,CAAA,IAAK,OAAO,GAAA,IAAO;EAC9D;AACF;AANgBJ;","names":["Injectable","AsyncLocalStorage","RequestContextService","storage","AsyncLocalStorage","run","context","callback","store","setContext","partial","getStore","Object","assign","getContext","get","key","SetMetadata","OBSERVABLE_SERVICE","Symbol","PLATFORM_HTTP_CLIENT","AUTO_TRACE","HTTP_CLIENT_FACTORY","AutoTrace","options","SetMetadata","AUTO_TRACE","Global","Module","CommonModule","providers","RequestContextService","exports","stripBasePath","fullPath","basePath","startsWith","stripped","slice","length","createTimer","start","process","hrtime","diff","Math","round"]}
|