@taicode/common-server 4.0.0-beta.1 → 4.0.0-beta.10
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/index.d.ts +18 -15
- package/output/app/index.d.ts.map +1 -1
- package/output/app/index.js +330 -18
- package/output/auth/index.d.ts +73 -0
- package/output/auth/index.d.ts.map +1 -0
- package/output/auth/index.js +196 -0
- package/output/core/assemble.d.ts +64 -0
- package/output/core/assemble.d.ts.map +1 -0
- package/output/core/assemble.js +88 -0
- package/output/core/boot/context.d.ts +109 -0
- package/output/core/boot/context.d.ts.map +1 -0
- package/output/core/boot/context.js +145 -0
- package/output/core/boot/lifecycle.d.ts +206 -0
- package/output/core/boot/lifecycle.d.ts.map +1 -0
- package/output/core/boot/lifecycle.js +255 -0
- package/output/core/boot/shutdown.d.ts +34 -0
- package/output/core/boot/shutdown.d.ts.map +1 -0
- package/output/core/boot/shutdown.js +50 -0
- package/output/core/boot/signal.d.ts +13 -0
- package/output/core/boot/signal.d.ts.map +1 -0
- package/output/{app → core/boot}/signal.js +3 -2
- package/output/core/boot/steps.d.ts +138 -0
- package/output/core/boot/steps.d.ts.map +1 -0
- package/output/core/boot/steps.js +259 -0
- package/output/core/entries.d.ts +151 -0
- package/output/core/entries.d.ts.map +1 -0
- package/output/core/entries.js +242 -0
- package/output/core/entries.test.d.ts +2 -0
- package/output/core/entries.test.d.ts.map +1 -0
- package/output/core/entries.test.js +458 -0
- package/output/core/env.d.ts +83 -0
- package/output/core/env.d.ts.map +1 -0
- package/output/core/env.js +124 -0
- package/output/{app → core}/env.test.d.ts.map +1 -1
- package/output/core/env.test.js +105 -0
- package/output/core/modules/auth-provider/index.d.ts +10 -0
- package/output/core/modules/auth-provider/index.d.ts.map +1 -0
- package/output/core/modules/auth-provider/index.js +9 -0
- package/output/core/modules/auth-provider/types.d.ts +71 -0
- package/output/core/modules/auth-provider/types.d.ts.map +1 -0
- package/output/core/modules/context/index.d.ts +18 -0
- package/output/core/modules/context/index.d.ts.map +1 -0
- package/output/core/modules/context/index.js +23 -0
- package/output/core/modules/context/index.test.d.ts.map +1 -0
- package/output/core/modules/cookie/index.d.ts +21 -0
- package/output/core/modules/cookie/index.d.ts.map +1 -0
- package/output/{app/core/cookie.js → core/modules/cookie/index.js} +1 -6
- package/output/core/modules/identity/index.d.ts +4 -0
- package/output/core/modules/identity/index.d.ts.map +1 -0
- package/output/{app/core/identity.js → core/modules/identity/index.js} +1 -1
- package/output/core/modules/logging/index.d.ts +5 -0
- package/output/core/modules/logging/index.d.ts.map +1 -0
- package/output/{app/core/logging.js → core/modules/logging/index.js} +2 -2
- package/output/core/modules/openapi/index.d.ts +7 -0
- package/output/core/modules/openapi/index.d.ts.map +1 -0
- package/output/{app/core/openapi.js → core/modules/openapi/index.js} +11 -12
- package/output/core/modules/permission-operations/index.d.ts +26 -0
- package/output/core/modules/permission-operations/index.d.ts.map +1 -0
- package/output/core/modules/permission-operations/index.js +36 -0
- package/output/core/modules/permission-operations/index.test.d.ts +2 -0
- package/output/core/modules/permission-operations/index.test.d.ts.map +1 -0
- package/output/core/modules/permission-operations/index.test.js +45 -0
- package/output/{app/core/request-id.d.ts → core/modules/request-id/index.d.ts} +1 -4
- package/output/core/modules/request-id/index.d.ts.map +1 -0
- package/output/{app/core/request-id.js → core/modules/request-id/index.js} +2 -2
- package/output/core/modules/response/index.d.ts +50 -0
- package/output/core/modules/response/index.d.ts.map +1 -0
- package/output/{app/core/response.js → core/modules/response/index.js} +31 -18
- package/output/{schema/index.d.ts → core/modules/schema/builders.d.ts} +8 -1
- package/output/core/modules/schema/builders.d.ts.map +1 -0
- package/output/{schema/index.js → core/modules/schema/builders.js} +7 -4
- package/output/core/modules/schema/index.d.ts +34 -0
- package/output/core/modules/schema/index.d.ts.map +1 -0
- package/output/core/modules/schema/index.js +62 -0
- package/output/core/modules/schema/index.test.d.ts +2 -0
- package/output/core/modules/schema/index.test.d.ts.map +1 -0
- package/output/core/modules/schema/index.test.js +55 -0
- package/output/core/modules/system-routes/index.d.ts +15 -0
- package/output/core/modules/system-routes/index.d.ts.map +1 -0
- package/output/core/modules/system-routes/index.js +205 -0
- package/output/core/resource.d.ts +56 -0
- package/output/core/resource.d.ts.map +1 -0
- package/output/core/resource.js +56 -0
- package/output/core/test-support/database.d.ts +89 -0
- package/output/core/test-support/database.d.ts.map +1 -0
- package/output/core/test-support/database.js +131 -0
- package/output/core/test-support/database.test.d.ts +2 -0
- package/output/core/test-support/database.test.d.ts.map +1 -0
- package/output/core/test-support/database.test.js +111 -0
- package/output/core/test-support/environment.d.ts +38 -0
- package/output/core/test-support/environment.d.ts.map +1 -0
- package/output/core/test-support/environment.js +45 -0
- package/output/core/test-support/service-context.d.ts +64 -0
- package/output/core/test-support/service-context.d.ts.map +1 -0
- package/output/core/test-support/service-context.js +63 -0
- package/output/core/test-support/service-context.test.d.ts +2 -0
- package/output/core/test-support/service-context.test.d.ts.map +1 -0
- package/output/core/test-support/service-context.test.js +55 -0
- package/output/core/test-support/test-server.d.ts +154 -0
- package/output/core/test-support/test-server.d.ts.map +1 -0
- package/output/core/test-support/test-server.js +114 -0
- package/output/core/test-support/test-server.test.d.ts +2 -0
- package/output/core/test-support/test-server.test.d.ts.map +1 -0
- package/output/core/test-support/test-server.test.js +296 -0
- package/output/core/test-support/testdata.d.ts +255 -0
- package/output/core/test-support/testdata.d.ts.map +1 -0
- package/output/core/test-support/testdata.js +271 -0
- package/output/core/test-support/testdata.test.d.ts +2 -0
- package/output/core/test-support/testdata.test.d.ts.map +1 -0
- package/output/core/test-support/testdata.test.js +334 -0
- package/output/{app → core}/type-augment.d.ts +2 -2
- package/output/core/type-augment.d.ts.map +1 -0
- package/output/core/types.d.ts +582 -0
- package/output/core/types.d.ts.map +1 -0
- package/output/cors/index.d.ts +3 -0
- package/output/cors/index.d.ts.map +1 -0
- package/output/cors/index.js +28 -0
- package/output/index.d.ts +10 -4
- package/output/index.d.ts.map +1 -1
- package/output/index.js +25 -5
- package/output/rate-limit/index.d.ts +23 -0
- package/output/rate-limit/index.d.ts.map +1 -0
- package/output/rate-limit/index.js +43 -0
- package/output/{rate-limiter/rate-limiter.d.ts → rate-limit/limiter.d.ts} +1 -1
- package/output/rate-limit/limiter.d.ts.map +1 -0
- package/output/{rate-limiter → rate-limit}/memory-store.d.ts +6 -0
- package/output/rate-limit/memory-store.d.ts.map +1 -0
- package/output/{rate-limiter → rate-limit}/memory-store.js +8 -0
- package/output/{rate-limiter → rate-limit}/redis-store.d.ts +18 -0
- package/output/rate-limit/redis-store.d.ts.map +1 -0
- package/output/{rate-limiter → rate-limit}/redis-store.js +35 -0
- package/output/rate-limit/redis-store.test.d.ts.map +1 -0
- package/output/{rate-limiter → rate-limit}/redis-store.test.js +2 -2
- package/output/rate-limit/types.d.ts +45 -0
- package/output/rate-limit/types.d.ts.map +1 -0
- package/output/rate-limit/types.js +1 -0
- package/output/{redis-cache/redis-cache.d.ts → redis/cache.d.ts} +1 -1
- package/output/redis/cache.d.ts.map +1 -0
- package/output/redis/cache.test.d.ts +2 -0
- package/output/redis/cache.test.d.ts.map +1 -0
- package/output/{redis-cache/redis-cache.test.js → redis/cache.test.js} +1 -1
- package/output/{app/redis.d.ts → redis/index.d.ts} +12 -7
- package/output/redis/index.d.ts.map +1 -0
- package/output/{app/redis.js → redis/index.js} +15 -5
- package/output/redis/index.test.d.ts +2 -0
- package/output/{context → redis}/index.test.d.ts.map +1 -1
- package/output/redis/index.test.js +55 -0
- package/output/redis-queue/index.js +1 -1
- package/output/redis-queue/test-helpers.d.ts +1 -1
- package/output/redis-queue/test-helpers.js +1 -1
- package/output/redis-queue/types.d.ts +3 -12
- package/output/redis-queue/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/output/app/auth.test.d.ts +0 -2
- package/output/app/auth.test.d.ts.map +0 -1
- package/output/app/auth.test.js +0 -148
- package/output/app/boot.d.ts +0 -48
- package/output/app/boot.d.ts.map +0 -1
- package/output/app/boot.js +0 -123
- package/output/app/config.test.d.ts +0 -2
- package/output/app/config.test.d.ts.map +0 -1
- package/output/app/config.test.js +0 -132
- package/output/app/context.d.ts +0 -68
- package/output/app/context.d.ts.map +0 -1
- package/output/app/context.js +0 -73
- package/output/app/core/cookie.d.ts +0 -25
- package/output/app/core/cookie.d.ts.map +0 -1
- package/output/app/core/identity.d.ts +0 -12
- package/output/app/core/identity.d.ts.map +0 -1
- package/output/app/core/index.d.ts +0 -44
- package/output/app/core/index.d.ts.map +0 -1
- package/output/app/core/index.js +0 -57
- package/output/app/core/logging.d.ts +0 -13
- package/output/app/core/logging.d.ts.map +0 -1
- package/output/app/core/openapi.d.ts +0 -17
- package/output/app/core/openapi.d.ts.map +0 -1
- package/output/app/core/request-id.d.ts.map +0 -1
- package/output/app/core/response.d.ts +0 -41
- package/output/app/core/response.d.ts.map +0 -1
- package/output/app/define-server.negative-cases.d.ts +0 -32
- package/output/app/define-server.negative-cases.d.ts.map +0 -1
- package/output/app/define-server.negative-cases.js +0 -209
- package/output/app/define-server.test.d.ts +0 -2
- package/output/app/define-server.test.d.ts.map +0 -1
- package/output/app/define-server.test.js +0 -97
- package/output/app/entries.d.ts +0 -29
- package/output/app/entries.d.ts.map +0 -1
- package/output/app/entries.js +0 -64
- package/output/app/env.d.ts +0 -59
- package/output/app/env.d.ts.map +0 -1
- package/output/app/env.js +0 -66
- package/output/app/env.test.js +0 -124
- package/output/app/error-contract.test.d.ts +0 -2
- package/output/app/error-contract.test.d.ts.map +0 -1
- package/output/app/error-contract.test.js +0 -125
- package/output/app/errors.d.ts +0 -20
- package/output/app/errors.d.ts.map +0 -1
- package/output/app/errors.js +0 -51
- package/output/app/generate-openapi.test.d.ts +0 -2
- package/output/app/generate-openapi.test.d.ts.map +0 -1
- package/output/app/generate-openapi.test.js +0 -123
- package/output/app/lifecycle-logging.test.d.ts +0 -2
- package/output/app/lifecycle-logging.test.d.ts.map +0 -1
- package/output/app/lifecycle-logging.test.js +0 -155
- package/output/app/lifecycle.d.ts +0 -70
- package/output/app/lifecycle.d.ts.map +0 -1
- package/output/app/lifecycle.js +0 -99
- package/output/app/lifecycle.test.d.ts +0 -2
- package/output/app/lifecycle.test.d.ts.map +0 -1
- package/output/app/lifecycle.test.js +0 -152
- package/output/app/middleware/auth.d.ts +0 -71
- package/output/app/middleware/auth.d.ts.map +0 -1
- package/output/app/middleware/auth.js +0 -190
- package/output/app/middleware/context.d.ts +0 -13
- package/output/app/middleware/context.d.ts.map +0 -1
- package/output/app/middleware/context.js +0 -15
- package/output/app/middleware/cors.d.ts +0 -14
- package/output/app/middleware/cors.d.ts.map +0 -1
- package/output/app/middleware/cors.js +0 -30
- package/output/app/middleware/index.d.ts +0 -17
- package/output/app/middleware/index.d.ts.map +0 -1
- package/output/app/middleware/index.js +0 -16
- package/output/app/middleware/rate-limit.d.ts +0 -24
- package/output/app/middleware/rate-limit.d.ts.map +0 -1
- package/output/app/middleware/rate-limit.js +0 -46
- package/output/app/middleware-order.test.d.ts +0 -2
- package/output/app/middleware-order.test.d.ts.map +0 -1
- package/output/app/middleware-order.test.js +0 -148
- package/output/app/permission-operations.d.ts +0 -48
- package/output/app/permission-operations.d.ts.map +0 -1
- package/output/app/permission-operations.js +0 -77
- package/output/app/permission-operations.test.d.ts +0 -2
- package/output/app/permission-operations.test.d.ts.map +0 -1
- package/output/app/permission-operations.test.js +0 -72
- package/output/app/permission-registration.test.d.ts +0 -2
- package/output/app/permission-registration.test.d.ts.map +0 -1
- package/output/app/permission-registration.test.js +0 -138
- package/output/app/redis.d.ts.map +0 -1
- package/output/app/registered-operations.test.d.ts +0 -2
- package/output/app/registered-operations.test.d.ts.map +0 -1
- package/output/app/registered-operations.test.js +0 -57
- package/output/app/request-id.test.d.ts +0 -2
- package/output/app/request-id.test.d.ts.map +0 -1
- package/output/app/request-id.test.js +0 -130
- package/output/app/resources.test.d.ts +0 -2
- package/output/app/resources.test.d.ts.map +0 -1
- package/output/app/resources.test.js +0 -197
- package/output/app/shutdown.d.ts +0 -22
- package/output/app/shutdown.d.ts.map +0 -1
- package/output/app/shutdown.js +0 -30
- package/output/app/shutdown.test.d.ts +0 -2
- package/output/app/shutdown.test.d.ts.map +0 -1
- package/output/app/shutdown.test.js +0 -103
- package/output/app/signal.d.ts +0 -12
- package/output/app/signal.d.ts.map +0 -1
- package/output/app/smoke.test.d.ts +0 -2
- package/output/app/smoke.test.d.ts.map +0 -1
- package/output/app/smoke.test.js +0 -210
- package/output/app/test-support.d.ts +0 -21
- package/output/app/test-support.d.ts.map +0 -1
- package/output/app/test-support.js +0 -24
- package/output/app/type-augment.d.ts.map +0 -1
- package/output/app/types.d.ts +0 -211
- package/output/app/types.d.ts.map +0 -1
- package/output/context/index.d.ts +0 -6
- package/output/context/index.d.ts.map +0 -1
- package/output/context/index.js +0 -14
- package/output/rate-limiter/index.d.ts +0 -5
- package/output/rate-limiter/index.d.ts.map +0 -1
- package/output/rate-limiter/index.js +0 -4
- package/output/rate-limiter/memory-store.d.ts.map +0 -1
- package/output/rate-limiter/rate-limiter.d.ts.map +0 -1
- package/output/rate-limiter/redis-store.d.ts.map +0 -1
- package/output/rate-limiter/redis-store.test.d.ts.map +0 -1
- package/output/rate-limiter/types.d.ts +0 -27
- package/output/rate-limiter/types.d.ts.map +0 -1
- package/output/redis-cache/index.d.ts +0 -4
- package/output/redis-cache/index.d.ts.map +0 -1
- package/output/redis-cache/index.js +0 -1
- package/output/redis-cache/redis-cache.d.ts.map +0 -1
- package/output/redis-cache/redis-cache.test.d.ts +0 -2
- package/output/redis-cache/redis-cache.test.d.ts.map +0 -1
- package/output/schema/index.d.ts.map +0 -1
- /package/output/{app → core}/env.test.d.ts +0 -0
- /package/output/{rate-limiter → core/modules/auth-provider}/types.js +0 -0
- /package/output/{context → core/modules/context}/index.test.d.ts +0 -0
- /package/output/{context → core/modules/context}/index.test.js +0 -0
- /package/output/{app → core}/type-augment.js +0 -0
- /package/output/{app → core}/types.js +0 -0
- /package/output/{rate-limiter/rate-limiter.js → rate-limit/limiter.js} +0 -0
- /package/output/{rate-limiter → rate-limit}/redis-store.test.d.ts +0 -0
- /package/output/{redis-cache/redis-cache.js → redis/cache.js} +0 -0
package/output/index.js
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
1
|
+
// 包根出口(`@taicode/common-server`):业务侧直接使用的**构件**——
|
|
2
|
+
// 路由 / 查询 schema 工厂、请求上下文构造、Redis 缓存、限流实现、Redis 队列。
|
|
3
|
+
//
|
|
4
|
+
// 目录布局(见 `common/product/designs/create-server/design.md` §7.1):
|
|
5
|
+
// ```
|
|
6
|
+
// source/
|
|
7
|
+
// ├── core/ 核心设计(锁定:不可替换、不可修改,**不对外导出装配**)
|
|
8
|
+
// ├── app/ 服务入口 barrel(defineServer / startServer / generateOpenApi)
|
|
9
|
+
// ├── auth/ 可选:鉴权中间件
|
|
10
|
+
// ├── cors/ 可选:CORS 中间件
|
|
11
|
+
// ├── rate-limit/ 可选:限流中间件 + 限流实现
|
|
12
|
+
// ├── redis/ 请求期 Redis / 缓存
|
|
13
|
+
// └── redis-queue/ 可选:Redis 队列
|
|
14
|
+
// ```
|
|
15
|
+
//
|
|
16
|
+
// 框架自己装配的一切(`createFastify` / `registerCore` / 各 core 单元 / `request.ctx` 装配 /
|
|
17
|
+
// 默认中间件预设)都不在这里:**固定下来的东西不再交给外面组装**。
|
|
18
|
+
export * from './core/modules/schema/builders.js';
|
|
19
|
+
export { createSuccessResponse, createErrorResponse } from './core/modules/response/index.js';
|
|
20
|
+
export { createContext } from './core/modules/context/index.js';
|
|
21
|
+
export * from './redis/index.js';
|
|
22
|
+
export * from './rate-limit/limiter.js';
|
|
23
|
+
export * from './rate-limit/memory-store.js';
|
|
24
|
+
export * from './rate-limit/redis-store.js';
|
|
25
|
+
export * from './rate-limit/types.js';
|
|
3
26
|
export * from './redis-queue/index.js';
|
|
4
|
-
export * from './redis-cache/index.js';
|
|
5
|
-
export * from './rate-limiter/index.js';
|
|
6
|
-
export * from './context/index.js';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { MiddlewareContext, MiddlewareUnit } from '../core/types.js';
|
|
2
|
+
import type { RateLimitStore } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* 标准中间件单元 `rateLimit`(可替换;**不在默认预设内**)。
|
|
5
|
+
*
|
|
6
|
+
* **规则只有一个来源:路由的 `config.rateLimit`**(与 `auth` 的 `accessControls` 同一取向)。
|
|
7
|
+
* 存储后端由调用方注入(缺省进程内 memory)。`TOO_MANY_REQUESTS` 经 `UserError` 仍映射 **400**。
|
|
8
|
+
* 路由未声明 `config.rateLimit` 时该项空转。
|
|
9
|
+
*
|
|
10
|
+
* 注:中间件的 ctx 看不到 `resources`(中间件不得直连数据层),因此 Redis store 需由调用方
|
|
11
|
+
* 在 `services` 侧构造后注入(`store`),框架不再自行探测 Redis。
|
|
12
|
+
*/
|
|
13
|
+
export interface RateLimitMiddlewareOptions {
|
|
14
|
+
/** 存储后端(缺省进程内 memory) */
|
|
15
|
+
store?: RateLimitStore;
|
|
16
|
+
}
|
|
17
|
+
export declare function createRateLimitMiddleware<C = unknown, S = unknown>(_ctx: MiddlewareContext<C, S>, options?: RateLimitMiddlewareOptions): MiddlewareUnit;
|
|
18
|
+
export { RateLimiter, createRateLimitKey } from './limiter.js';
|
|
19
|
+
export { MemoryRateLimitStore } from './memory-store.js';
|
|
20
|
+
export { RedisRateLimitStore } from './redis-store.js';
|
|
21
|
+
export type { RedisRateLimitStoreOptions } from './redis-store.js';
|
|
22
|
+
export type { RateLimitConfig, RateLimitInfo, RateLimiterOptions, RateLimitResult, RateLimitStore } from './types.js';
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/rate-limit/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAc,iBAAiB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAGhD;;;;;;;;;GASG;AAEH,MAAM,WAAW,0BAA0B;IACzC,yBAAyB;IACzB,KAAK,CAAC,EAAE,cAAc,CAAA;CACvB;AAqBD,wBAAgB,yBAAyB,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,GAAE,0BAA+B,GAAG,cAAc,CAoB3J;AAGD,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,YAAY,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAA;AAClE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,kBAAkB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { UserError } from '@taicode/common-base';
|
|
2
|
+
import { createRateLimitKey, RateLimiter } from './limiter.js';
|
|
3
|
+
import { MemoryRateLimitStore } from './memory-store.js';
|
|
4
|
+
import { readServerIdentity } from '../core/modules/identity/index.js';
|
|
5
|
+
function resolveRule(request) {
|
|
6
|
+
return request.routeOptions?.config?.rateLimit;
|
|
7
|
+
}
|
|
8
|
+
function buildKeys(request, keys) {
|
|
9
|
+
return keys.map((key) => {
|
|
10
|
+
if (key === 'ip') {
|
|
11
|
+
return `ip:${request.ip}`;
|
|
12
|
+
}
|
|
13
|
+
if (key === 'user') {
|
|
14
|
+
return `user:${String(request.user?.id ?? 'anonymous')}`;
|
|
15
|
+
}
|
|
16
|
+
if (key === 'path') {
|
|
17
|
+
return `path:${request.routeOptions?.url ?? request.url}`;
|
|
18
|
+
}
|
|
19
|
+
return `${key}:${String(request[key] ?? '')}`;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export function createRateLimitMiddleware(_ctx, options = {}) {
|
|
23
|
+
const register = (app) => {
|
|
24
|
+
const limiter = new RateLimiter({ store: options.store ?? new MemoryRateLimitStore() });
|
|
25
|
+
const prefix = `${readServerIdentity(app)?.service ?? ''}:`;
|
|
26
|
+
app.addHook('preValidation', async (request) => {
|
|
27
|
+
const rule = resolveRule(request);
|
|
28
|
+
if (!rule) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const keys = buildKeys(request, rule.keys ?? ['ip']).map((key) => createRateLimitKey(prefix, key));
|
|
32
|
+
const result = await limiter.checkMultiLimit(keys, { limit: rule.limit, window: rule.window });
|
|
33
|
+
if (!result.allowed) {
|
|
34
|
+
throw new UserError('TOO_MANY_REQUESTS', undefined, '请求过于频繁');
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
return { name: 'rateLimit', register };
|
|
39
|
+
}
|
|
40
|
+
// ── 限流实现(与中间件同一模块)─────────────────────────────────
|
|
41
|
+
export { RateLimiter, createRateLimitKey } from './limiter.js';
|
|
42
|
+
export { MemoryRateLimitStore } from './memory-store.js';
|
|
43
|
+
export { RedisRateLimitStore } from './redis-store.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limiter.d.ts","sourceRoot":"","sources":["../../source/rate-limit/limiter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,kBAAkB,EAAE,eAAe,EAAkB,MAAM,YAAY,CAAA;AAErH,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAgB;gBAEjB,OAAO,GAAE,kBAAuB;IAItC,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;IAoC1E,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAItC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAI9D;;OAEG;IACG,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;CAezF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAE7E"}
|
|
@@ -7,6 +7,12 @@ export declare class MemoryRateLimitStore implements RateLimitStore {
|
|
|
7
7
|
set(key: string, info: RateLimitInfo): Promise<void>;
|
|
8
8
|
delete(key: string): Promise<void>;
|
|
9
9
|
cleanup(): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* 清空全部计数,**保留定时清理器**(它只是 GC,不属于「数据」)。
|
|
12
|
+
*
|
|
13
|
+
* 只影响本实例:进程内 store 的键本来就只在本进程可见。
|
|
14
|
+
*/
|
|
15
|
+
clear(): Promise<void>;
|
|
10
16
|
destroy(): void;
|
|
11
17
|
}
|
|
12
18
|
//# sourceMappingURL=memory-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-store.d.ts","sourceRoot":"","sources":["../../source/rate-limit/memory-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAO/D,qBAAa,oBAAqB,YAAW,cAAc;IACzD,OAAO,CAAC,KAAK,CAAsC;IACnD,OAAO,CAAC,eAAe,CAA8B;gBAEzC,iBAAiB,SAAQ;IAY/B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAY/C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,OAAO,IAAI,IAAI;CAOhB"}
|
|
@@ -36,6 +36,14 @@ export class MemoryRateLimitStore {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* 清空全部计数,**保留定时清理器**(它只是 GC,不属于「数据」)。
|
|
41
|
+
*
|
|
42
|
+
* 只影响本实例:进程内 store 的键本来就只在本进程可见。
|
|
43
|
+
*/
|
|
44
|
+
async clear() {
|
|
45
|
+
this.store.clear();
|
|
46
|
+
}
|
|
39
47
|
destroy() {
|
|
40
48
|
if (this.cleanupInterval) {
|
|
41
49
|
clearInterval(this.cleanupInterval);
|
|
@@ -39,6 +39,24 @@ export declare class RedisRateLimitStore implements RateLimitStore {
|
|
|
39
39
|
delete(key: string): Promise<void>;
|
|
40
40
|
/** Redis 的键自带过期时间,无需额外清理 */
|
|
41
41
|
cleanup(): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* 清空**本前缀下**的全部计数(`SCAN` + `DEL`,不用 `KEYS`——后者在大库上会阻塞)。
|
|
44
|
+
*
|
|
45
|
+
* `fallback` 一并清掉:降级期间写入的计数也是计数,漏清就会留下「只有降级那段没重置」
|
|
46
|
+
* 的诡异状态。
|
|
47
|
+
*
|
|
48
|
+
* 前缀是构造参数,所以它只会删自己这批键,不会碰同一 Redis 上其它用途的数据。
|
|
49
|
+
*
|
|
50
|
+
* ## 已知不足:扫描中途失败只记日志、不抛
|
|
51
|
+
*
|
|
52
|
+
* 与 `get` / `set` 的降级策略保持一致(Redis 抖动不该让业务抛错),但 `clear()` 的
|
|
53
|
+
* 唯一用途是「让下一条用例从零配额开始」:静默失败 = 旧桶保留 = 又变成「顺序相关的
|
|
54
|
+
* 偶发红」,正是本方法要消灭的形态。
|
|
55
|
+
*
|
|
56
|
+
* TODO(需单独评审,行为变更):测试路径上让失败冒泡(或返回 `boolean` 交由
|
|
57
|
+
* `cleanServiceUnits()` 判错),生产路径继续降级。当前 Redis 侧无对应单测。
|
|
58
|
+
*/
|
|
59
|
+
clear(): Promise<void>;
|
|
42
60
|
private buildKey;
|
|
43
61
|
private logError;
|
|
44
62
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-store.d.ts","sourceRoot":"","sources":["../../source/rate-limit/redis-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,eAAe,EAAE,MAAM,OAAO,CAAA;AAG1D,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE/D,MAAM,WAAW,0BAA0B;IACzC,wBAAwB;IACxB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,kCAAkC;IAClC,WAAW,CAAC,EAAE,eAAe,CAAA;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,cAAc,CAAA;CAC1B;AAED;;;;;;;;;;GAUG;AACH,qBAAa,mBAAoB,YAAW,cAAc;IACxD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+B;IACrD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAiB;IACjD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IAEzC,OAAO,CAAC,gBAAgB,CAAI;gBAEhB,OAAO,GAAE,0BAA+B;IAyBvC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B,UAAU,IAAI,IAAI;IAKZ,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAqB/C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBpD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY/C,4BAA4B;IACf,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrC;;;;;;;;;;;;;;;;OAgBG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBnC,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,QAAQ;CAOjB"}
|
|
@@ -101,6 +101,41 @@ export class RedisRateLimitStore {
|
|
|
101
101
|
async cleanup() {
|
|
102
102
|
await this.fallback.cleanup?.();
|
|
103
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* 清空**本前缀下**的全部计数(`SCAN` + `DEL`,不用 `KEYS`——后者在大库上会阻塞)。
|
|
106
|
+
*
|
|
107
|
+
* `fallback` 一并清掉:降级期间写入的计数也是计数,漏清就会留下「只有降级那段没重置」
|
|
108
|
+
* 的诡异状态。
|
|
109
|
+
*
|
|
110
|
+
* 前缀是构造参数,所以它只会删自己这批键,不会碰同一 Redis 上其它用途的数据。
|
|
111
|
+
*
|
|
112
|
+
* ## 已知不足:扫描中途失败只记日志、不抛
|
|
113
|
+
*
|
|
114
|
+
* 与 `get` / `set` 的降级策略保持一致(Redis 抖动不该让业务抛错),但 `clear()` 的
|
|
115
|
+
* 唯一用途是「让下一条用例从零配额开始」:静默失败 = 旧桶保留 = 又变成「顺序相关的
|
|
116
|
+
* 偶发红」,正是本方法要消灭的形态。
|
|
117
|
+
*
|
|
118
|
+
* TODO(需单独评审,行为变更):测试路径上让失败冒泡(或返回 `boolean` 交由
|
|
119
|
+
* `cleanServiceUnits()` 判错),生产路径继续降级。当前 Redis 侧无对应单测。
|
|
120
|
+
*/
|
|
121
|
+
async clear() {
|
|
122
|
+
await this.fallback.clear?.();
|
|
123
|
+
if (!this.redis?.isReady)
|
|
124
|
+
return;
|
|
125
|
+
try {
|
|
126
|
+
let cursor = '0';
|
|
127
|
+
do {
|
|
128
|
+
const reply = await this.redis.scan(cursor, { MATCH: `${this.prefix}*`, COUNT: 200 });
|
|
129
|
+
cursor = reply.cursor;
|
|
130
|
+
if (reply.keys.length > 0) {
|
|
131
|
+
await this.redis.del(reply.keys);
|
|
132
|
+
}
|
|
133
|
+
} while (cursor !== '0');
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
this.logError('clear', error);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
104
139
|
buildKey(key) {
|
|
105
140
|
return `${this.prefix}${key}`;
|
|
106
141
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-store.test.d.ts","sourceRoot":"","sources":["../../source/rate-limit/redis-store.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
-
import { createRedisClient } from '../redis
|
|
3
|
-
import { RateLimiter } from './
|
|
2
|
+
import { createRedisClient } from '../redis/cache.js';
|
|
3
|
+
import { RateLimiter } from './limiter.js';
|
|
4
4
|
import { RedisRateLimitStore } from './redis-store.js';
|
|
5
5
|
const REDIS_URL = process.env.REDIS_URL || 'redis://localhost:6379';
|
|
6
6
|
describe('RedisRateLimitStore', () => {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export interface RateLimitInfo {
|
|
2
|
+
count: number;
|
|
3
|
+
windowStart: Date;
|
|
4
|
+
windowEnd: Date;
|
|
5
|
+
}
|
|
6
|
+
export interface RateLimitResult {
|
|
7
|
+
allowed: boolean;
|
|
8
|
+
remaining: number;
|
|
9
|
+
resetAt: Date;
|
|
10
|
+
limit: number;
|
|
11
|
+
window: number;
|
|
12
|
+
}
|
|
13
|
+
export interface RateLimitStore {
|
|
14
|
+
get(key: string): Promise<RateLimitInfo | null>;
|
|
15
|
+
set(key: string, info: RateLimitInfo): Promise<void>;
|
|
16
|
+
delete(key: string): Promise<void>;
|
|
17
|
+
cleanup?(): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* **清空全部计数**(不是「删一个键」——那是 `delete`)。
|
|
20
|
+
*
|
|
21
|
+
* ## 为什么这是存储层的职责,而不是「测试自己换个 key」
|
|
22
|
+
*
|
|
23
|
+
* 限流的键是 `ip:` / `user:` / `path:` —— 由请求本身的属性拼成,测试**改不了**(除非
|
|
24
|
+
* 伪造 `remoteAddress`)。没有 `clear()` 的时候,想「从干净配额开始」只能给每次请求换一个
|
|
25
|
+
* 假 IP:一个测试文件里铺一串 `ipSeq` 计数器,注释里还得解释「为什么不能回退序号」。
|
|
26
|
+
*
|
|
27
|
+
* 这完全是**测试在迁就实现细节**:用例真正想表达的是「这条用例从零计数开始」,而它被
|
|
28
|
+
* 迫描述成「这次请用 10.31.0.7 访问」。有了 `clear()`,`beforeEach` 一行搞定,而且
|
|
29
|
+
* 不再需要任何假 IP——测试与真实请求的差别越小,证明力越强。
|
|
30
|
+
*
|
|
31
|
+
* ## 可选,但不是可忽略
|
|
32
|
+
*
|
|
33
|
+
* 声明为可选只为了让**第三方自定义 store** 不必立刻实现它;框架自带的两个实现都有。
|
|
34
|
+
* 测试里用 `store.clear?.()` 而不是硬调。
|
|
35
|
+
*/
|
|
36
|
+
clear?(): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
export interface RateLimitConfig {
|
|
39
|
+
limit: number;
|
|
40
|
+
window: number;
|
|
41
|
+
}
|
|
42
|
+
export interface RateLimiterOptions {
|
|
43
|
+
store?: RateLimitStore;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../source/rate-limit/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,IAAI,CAAA;IACjB,SAAS,EAAE,IAAI,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,IAAI,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAA;IAC/C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACpD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAClC,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB;;;;;;;;;;;;;;;;;OAiBG;IACH,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,cAAc,CAAA;CACvB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -136,4 +136,4 @@ export interface CreateRedisClientOptions {
|
|
|
136
136
|
connectTimeoutMs?: number;
|
|
137
137
|
}
|
|
138
138
|
export declare function createRedisClient(options: CreateRedisClientOptions): RedisClientType;
|
|
139
|
-
//# sourceMappingURL=
|
|
139
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../source/redis/cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,eAAe,EAAE,MAAM,OAAO,CAAA;AAE1D;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,kDAAkD;IAClD,WAAW,CAAC,EAAE,eAAe,CAAA;IAC7B,uBAAuB;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,kCAAkC;IAClC,EAAE,CAAC,EAAE,mBAAmB,GAAG,KAAK,CAAA;CACjC;AAaD;;;;;;;;;;GAUG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+B;IACrD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAiB;IACjD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAQ;IAC1C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;IAEvC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAA0B;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAEhC,gDAAgD;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsC;IAE/D,OAAO,CAAC,gBAAgB,CAAI;gBAEhB,OAAO,EAAE,iBAAiB;IA6BtC,uBAAuB;IACvB,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,sBAAsB;IACtB,IAAW,QAAQ,IAAI,MAAM,CAE5B;IAED,wCAAwC;IACxC,IAAW,WAAW,IAAI,OAAO,CAEhC;IAED;;;OAGG;IACU,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAOrC,0BAA0B;IACnB,UAAU,IAAI,IAAI;IAOzB;;;;;OAKG;IACU,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAMrC;;;OAGG;IACI,KAAK,IAAI,IAAI;IAQP,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAItC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAa/C;;;;;;OAMG;IACU,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAwB5D;;;;;;OAMG;IACU,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IA6BhG;;;;OAIG;IACH,OAAO,CAAC,QAAQ;IAIhB,8CAA8C;YAChC,aAAa;YAmBb,aAAa;IAY3B,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,QAAQ;IAUhB,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,QAAQ;CAOjB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,wBAAwB;IACvC,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,eAAe,CAkBpF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.test.d.ts","sourceRoot":"","sources":["../../source/redis/cache.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { RedisCache, createRedisClient } from './
|
|
2
|
+
import { RedisCache, createRedisClient } from './cache.js';
|
|
3
3
|
const REDIS_URL = process.env.REDIS_URL || 'redis://localhost:6379';
|
|
4
4
|
describe('RedisCache', () => {
|
|
5
5
|
describe('纯一级缓存(未配置 Redis)', () => {
|
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
import { RedisCache } from '
|
|
2
|
-
import type { ConfigEnv } from '
|
|
3
|
-
import type { LoggerLike, RedisHandle } from '
|
|
1
|
+
import { RedisCache } from './cache.js';
|
|
2
|
+
import type { ConfigEnv } from '../core/env.js';
|
|
3
|
+
import type { LoggerLike, RedisHandle } from '../core/types.js';
|
|
4
4
|
/**
|
|
5
5
|
* 引导期 Redis / cache helper(N2 §2.13)。
|
|
6
6
|
*
|
|
7
|
-
* 在 `resources(ctx)` 槽位里按需调用(框架自己**不**创建 Redis
|
|
7
|
+
* 在 `resources(ctx)` 槽位里按需调用(框架自己**不**创建 Redis);释放**在创建处**登记:
|
|
8
8
|
*
|
|
9
9
|
* ```ts
|
|
10
10
|
* resources: (ctx) => {
|
|
11
11
|
* const redis = createRedis(ctx.env, ctx.log) // 无 REDIS_URL → undefined
|
|
12
|
+
* if (redis) {
|
|
13
|
+
* ctx.disposer.add(() => redis.dispose()) // 关闭时 resources 阶段最后 flush
|
|
14
|
+
* }
|
|
12
15
|
* return { redis, cache: createCache({ env: ctx.env, prefix: 'account', redis }) }
|
|
13
16
|
* }
|
|
14
17
|
* ```
|
|
15
18
|
*
|
|
16
19
|
* `REDIS_URL` 由 helper 直接读 `env`(固定约定),**不**取自 `config`;`redis` / `cache` 一律是
|
|
17
20
|
* **惰性包装**:构造时不建连、不 ping,首次真正使用才建连 —— 「出 spec 不连库/Redis」结构性成立。
|
|
21
|
+
* 释放永远走调用方在 `ctx.disposer` 里的登记,框架不替资源持有句柄。
|
|
18
22
|
*/
|
|
19
|
-
/** 一级/二级缓存默认 TTL(秒),与 `RedisCache` 默认一致 */
|
|
20
|
-
export declare const DEFAULT_REDIS_CACHE_TTL_SECONDS = 300;
|
|
21
23
|
/**
|
|
22
24
|
* 构造 Redis 句柄(惰性包装:不建连、不 ping)。
|
|
23
25
|
*
|
|
@@ -42,4 +44,7 @@ export interface CacheSetupParams {
|
|
|
42
44
|
* - 都没有 → 纯进程内一级缓存(不建连)。
|
|
43
45
|
*/
|
|
44
46
|
export declare function createCache(params: CacheSetupParams): RedisCache;
|
|
45
|
-
|
|
47
|
+
export { RedisCache, createRedisClient } from './cache.js';
|
|
48
|
+
export type { CreateRedisClientOptions, RedisCacheL1Options, RedisCacheOptions } from './cache.js';
|
|
49
|
+
export type { RedisClientType } from 'redis';
|
|
50
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/redis/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,UAAU,EAAE,MAAM,YAAY,CAAA;AAE1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE/D;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,WAAW,GAAG,SAAS,CAwBrF;AAED,uBAAuB;AACvB,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,SAAS,CAAA;IACd,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAA;IACd,iDAAiD;IACjD,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,GAAG,CAAC,EAAE,UAAU,CAAA;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CAYhE;AAGD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC1D,YAAY,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAClG,YAAY,EAAE,eAAe,EAAE,MAAM,OAAO,CAAA"}
|
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
import { createRedisClient, RedisCache } from '
|
|
1
|
+
import { createRedisClient, RedisCache } from './cache.js';
|
|
2
2
|
/**
|
|
3
3
|
* 引导期 Redis / cache helper(N2 §2.13)。
|
|
4
4
|
*
|
|
5
|
-
* 在 `resources(ctx)` 槽位里按需调用(框架自己**不**创建 Redis
|
|
5
|
+
* 在 `resources(ctx)` 槽位里按需调用(框架自己**不**创建 Redis);释放**在创建处**登记:
|
|
6
6
|
*
|
|
7
7
|
* ```ts
|
|
8
8
|
* resources: (ctx) => {
|
|
9
9
|
* const redis = createRedis(ctx.env, ctx.log) // 无 REDIS_URL → undefined
|
|
10
|
+
* if (redis) {
|
|
11
|
+
* ctx.disposer.add(() => redis.dispose()) // 关闭时 resources 阶段最后 flush
|
|
12
|
+
* }
|
|
10
13
|
* return { redis, cache: createCache({ env: ctx.env, prefix: 'account', redis }) }
|
|
11
14
|
* }
|
|
12
15
|
* ```
|
|
13
16
|
*
|
|
14
17
|
* `REDIS_URL` 由 helper 直接读 `env`(固定约定),**不**取自 `config`;`redis` / `cache` 一律是
|
|
15
18
|
* **惰性包装**:构造时不建连、不 ping,首次真正使用才建连 —— 「出 spec 不连库/Redis」结构性成立。
|
|
19
|
+
* 释放永远走调用方在 `ctx.disposer` 里的登记,框架不替资源持有句柄。
|
|
16
20
|
*/
|
|
17
|
-
/** 一级/二级缓存默认 TTL(秒),与 `RedisCache` 默认一致 */
|
|
18
|
-
export const DEFAULT_REDIS_CACHE_TTL_SECONDS = 300;
|
|
19
21
|
/**
|
|
20
22
|
* 构造 Redis 句柄(惰性包装:不建连、不 ping)。
|
|
21
23
|
*
|
|
@@ -36,7 +38,13 @@ export function createRedis(env, log) {
|
|
|
36
38
|
await client.quit().catch(() => undefined);
|
|
37
39
|
}
|
|
38
40
|
else {
|
|
39
|
-
|
|
41
|
+
// 未建连(从未使用过)时 `destroy()` 会抛 "The client is closed";释放必须是幂等的
|
|
42
|
+
try {
|
|
43
|
+
client.destroy();
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// 已关闭:无事可做
|
|
47
|
+
}
|
|
40
48
|
}
|
|
41
49
|
},
|
|
42
50
|
};
|
|
@@ -59,3 +67,5 @@ export function createCache(params) {
|
|
|
59
67
|
params.log?.debug({}, '[redis] REDIS_URL not configured; cache falls back to in-process L1');
|
|
60
68
|
return new RedisCache({ prefix: params.prefix });
|
|
61
69
|
}
|
|
70
|
+
// ── 缓存 / 客户端实现(与引导期 helper 同一模块)───────────────
|
|
71
|
+
export { RedisCache, createRedisClient } from './cache.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../source/
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../source/redis/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { RedisCache } from './cache.js';
|
|
3
|
+
import { createCache, createRedis } from './index.js';
|
|
4
|
+
function createRecordingLogger() {
|
|
5
|
+
const entries = [];
|
|
6
|
+
const record = (level) => (obj, msg) => {
|
|
7
|
+
entries.push({ level, obj, msg });
|
|
8
|
+
};
|
|
9
|
+
return { entries, debug: record('debug'), info: record('info'), warn: record('warn'), error: record('error') };
|
|
10
|
+
}
|
|
11
|
+
/** 测试用 `ConfigEnv`(固定读取约定:`ENV` / `API_PORT` / `LOG_LEVEL` / `DATABASE_URL` / `REDIS_URL`) */
|
|
12
|
+
function createTestConfigEnv(overrides = {}) {
|
|
13
|
+
return { ENV: 'test', API_PORT: '', LOG_LEVEL: 'info', DATABASE_URL: '', REDIS_URL: undefined, ...overrides };
|
|
14
|
+
}
|
|
15
|
+
describe('createRedis', () => {
|
|
16
|
+
it('无 REDIS_URL → undefined,并留一条 debug 线索', () => {
|
|
17
|
+
const log = createRecordingLogger();
|
|
18
|
+
const handle = createRedis(createTestConfigEnv({ REDIS_URL: undefined }), log);
|
|
19
|
+
expect(handle).toBeUndefined();
|
|
20
|
+
expect(log.entries.filter((entry) => entry.level === 'debug')).toHaveLength(1);
|
|
21
|
+
});
|
|
22
|
+
it('有 REDIS_URL → 句柄(client + dispose),构造期不建连', () => {
|
|
23
|
+
const handle = createRedis(createTestConfigEnv({ REDIS_URL: 'redis://127.0.0.1:6379/0' }));
|
|
24
|
+
expect(handle).toBeDefined();
|
|
25
|
+
expect(handle?.client).toBeDefined();
|
|
26
|
+
expect(typeof handle?.dispose).toBe('function');
|
|
27
|
+
// 惰性:尚未 connect,客户端未打开
|
|
28
|
+
expect((handle?.client).isOpen).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
it('dispose:未建连时直接销毁客户端,不抛错、可重复调用', async () => {
|
|
31
|
+
const handle = createRedis(createTestConfigEnv({ REDIS_URL: 'redis://127.0.0.1:6379/0' }));
|
|
32
|
+
await expect(handle?.dispose()).resolves.toBeUndefined();
|
|
33
|
+
await expect(handle?.dispose()).resolves.toBeUndefined();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe('createCache', () => {
|
|
37
|
+
it('无 redis 句柄、无 REDIS_URL → 纯进程内 L1(不建连)', () => {
|
|
38
|
+
const log = createRecordingLogger();
|
|
39
|
+
const cache = createCache({ env: createTestConfigEnv({ REDIS_URL: undefined }), prefix: 'test:', log });
|
|
40
|
+
expect(cache).toBeInstanceOf(RedisCache);
|
|
41
|
+
expect(log.entries.filter((entry) => entry.level === 'debug')).toHaveLength(1);
|
|
42
|
+
});
|
|
43
|
+
it('复用传入的 redis 句柄(一条连接同时给 cache 与其它消费者)', () => {
|
|
44
|
+
const handle = createRedis(createTestConfigEnv({ REDIS_URL: 'redis://127.0.0.1:6379/0' }));
|
|
45
|
+
const cache = createCache({ env: createTestConfigEnv(), prefix: 'test:', redis: handle });
|
|
46
|
+
expect(cache).toBeInstanceOf(RedisCache);
|
|
47
|
+
});
|
|
48
|
+
it('无句柄但有 REDIS_URL → 自建客户端(由 RedisCache 自己持有)', () => {
|
|
49
|
+
const cache = createCache({
|
|
50
|
+
env: createTestConfigEnv({ REDIS_URL: 'redis://127.0.0.1:6379/0' }),
|
|
51
|
+
prefix: 'test:',
|
|
52
|
+
});
|
|
53
|
+
expect(cache).toBeInstanceOf(RedisCache);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
export { RedisQueueProvider } from './redis-queue-provider.js';
|
|
3
3
|
export { RedisQueueConsumer } from './redis-queue-consumer.js';
|
|
4
4
|
export { RedisQueueBatchConsumer } from './redis-queue-batch-consumer.js';
|
|
5
|
-
//
|
|
5
|
+
// 测试辅助函数导出(与队列实现同一出口:谁提供的功能,谁提供配套的测试工具)
|
|
6
6
|
export * as test from './test-helpers.js';
|
|
@@ -14,7 +14,7 @@ import type { AnyRegistry, QueueStats, RedisQueueRegistry, Task } from './types.
|
|
|
14
14
|
*
|
|
15
15
|
* @example
|
|
16
16
|
* ```ts
|
|
17
|
-
* import { dispatchQueueTask } from '@taicode/common-server/redis-queue
|
|
17
|
+
* import { dispatchQueueTask } from '@taicode/common-server/redis-queue'
|
|
18
18
|
* import { RedisQueueProvider, RedisQueueConsumer } from '@taicode/common-server/redis-queue'
|
|
19
19
|
*
|
|
20
20
|
* describe('My Queue Tests', () => {
|
|
@@ -11,7 +11,7 @@ import { RedisQueueConsumer } from './redis-queue-consumer.js';
|
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
13
13
|
* ```ts
|
|
14
|
-
* import { dispatchQueueTask } from '@taicode/common-server/redis-queue
|
|
14
|
+
* import { dispatchQueueTask } from '@taicode/common-server/redis-queue'
|
|
15
15
|
* import { RedisQueueProvider, RedisQueueConsumer } from '@taicode/common-server/redis-queue'
|
|
16
16
|
*
|
|
17
17
|
* describe('My Queue Tests', () => {
|
|
@@ -109,24 +109,18 @@ export interface RedisQueueCommonConfig {
|
|
|
109
109
|
/**
|
|
110
110
|
* 队列生产者配置
|
|
111
111
|
*/
|
|
112
|
-
export interface RedisQueueProviderConfig {
|
|
113
|
-
redisUrl?: string;
|
|
114
|
-
redisClient?: RedisClientType;
|
|
115
|
-
cleanupDelay?: number;
|
|
112
|
+
export interface RedisQueueProviderConfig extends RedisQueueCommonConfig {
|
|
116
113
|
processingDelay?: number;
|
|
117
114
|
}
|
|
118
115
|
/**
|
|
119
116
|
* 队列消费者配置
|
|
120
117
|
*/
|
|
121
|
-
export interface RedisQueueConsumerConfig<T extends TaskData = TaskData> {
|
|
122
|
-
redisUrl?: string;
|
|
123
|
-
redisClient?: RedisClientType;
|
|
118
|
+
export interface RedisQueueConsumerConfig<T extends TaskData = TaskData> extends RedisQueueCommonConfig {
|
|
124
119
|
handler: TaskHandler<T>;
|
|
125
120
|
maxRetries?: number;
|
|
126
121
|
concurrency?: number;
|
|
127
122
|
consumerInterval?: number;
|
|
128
123
|
processingTimeout?: number;
|
|
129
|
-
cleanupDelay?: number;
|
|
130
124
|
}
|
|
131
125
|
/**
|
|
132
126
|
* 任务处理器函数
|
|
@@ -135,14 +129,11 @@ export type TaskHandler<T extends TaskData = TaskData> = (data: T) => Promise<Ca
|
|
|
135
129
|
/**
|
|
136
130
|
* 批量消费者配置
|
|
137
131
|
*/
|
|
138
|
-
export interface BatchConsumerConfig<T extends TaskData = TaskData> {
|
|
139
|
-
redisUrl?: string;
|
|
140
|
-
redisClient?: RedisClientType;
|
|
132
|
+
export interface BatchConsumerConfig<T extends TaskData = TaskData> extends RedisQueueCommonConfig {
|
|
141
133
|
handler: BatchTaskHandler<T>;
|
|
142
134
|
batchSize?: number;
|
|
143
135
|
maxRetries?: number;
|
|
144
136
|
concurrency?: number;
|
|
145
|
-
cleanupDelay?: number;
|
|
146
137
|
consumerInterval?: number;
|
|
147
138
|
processingTimeout?: number;
|
|
148
139
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../source/redis-queue/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAA;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAEH,MAAM,WAAW,kBAAkB;CAElC;AAED;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAA;AAEtE;;;;;GAKG;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AAE7C;;GAEG;AAEH,MAAM,MAAM,QAAQ,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,CAAA;AAE1D;;GAEG;AACH,MAAM,WAAW,IAAI,CAAC,CAAC,GAAG,QAAQ;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,CAAC,CAAA;IACP,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,eAAe,CAAA;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../source/redis-queue/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAA;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAEH,MAAM,WAAW,kBAAkB;CAElC;AAED;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAA;AAEtE;;;;;GAKG;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AAE7C;;GAEG;AAEH,MAAM,MAAM,QAAQ,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,CAAA;AAE1D;;GAEG;AACH,MAAM,WAAW,IAAI,CAAC,CAAC,GAAG,QAAQ;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,CAAC,CAAA;IACP,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,eAAe,CAAA;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAyB,SAAQ,sBAAsB;IACtE,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,CAAE,SAAQ,sBAAsB;IACrG,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA;AAE3G;;GAEG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,CAAE,SAAQ,sBAAsB;IAChG,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAA;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,KAAK,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA"}
|
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.10",
|
|
4
4
|
"author": "Alain",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"description": "",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"@fastify/cookie": "^11",
|
|
28
28
|
"@fastify/cors": "^11",
|
|
29
29
|
"@fastify/swagger": "^9",
|
|
30
|
-
"@
|
|
30
|
+
"@taicode/auth-sdk": "^1.0.9",
|
|
31
31
|
"dotenv": "^17.3.1",
|
|
32
32
|
"fastify-type-provider-zod": "^6",
|
|
33
33
|
"zod": "^4.3.6"
|
|
@@ -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.10"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@eslint/js": "^9.39.3",
|
|
@@ -49,14 +49,14 @@
|
|
|
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.10"
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
|
55
55
|
"test": "vitest run",
|
|
56
56
|
"test:ci": "vitest run",
|
|
57
57
|
"lint": "eslint && tsc --noEmit",
|
|
58
58
|
"typecheck": "tsc --noEmit",
|
|
59
|
-
"build": "tsc -p tsconfig.json",
|
|
59
|
+
"build": "rm -rf output && tsc -p tsconfig.json",
|
|
60
60
|
"dev": "tsc -p tsconfig.json --watch"
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auth.test.d.ts","sourceRoot":"","sources":["../../source/app/auth.test.ts"],"names":[],"mappings":""}
|