@taicode/common-server 4.0.0-beta.3 → 4.0.0-beta.5

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.
Files changed (270) hide show
  1. package/output/app/index.d.ts +13 -15
  2. package/output/app/index.d.ts.map +1 -1
  3. package/output/app/index.js +256 -18
  4. package/output/auth/index.d.ts +72 -0
  5. package/output/auth/index.d.ts.map +1 -0
  6. package/output/auth/index.js +176 -0
  7. package/output/core/assemble.d.ts +64 -0
  8. package/output/core/assemble.d.ts.map +1 -0
  9. package/output/core/assemble.js +88 -0
  10. package/output/core/boot/context.d.ts +89 -0
  11. package/output/core/boot/context.d.ts.map +1 -0
  12. package/output/{app → core/boot}/context.js +44 -17
  13. package/output/{app → core/boot}/lifecycle.d.ts +13 -15
  14. package/output/core/boot/lifecycle.d.ts.map +1 -0
  15. package/output/{app → core/boot}/lifecycle.js +15 -12
  16. package/output/{app → core/boot}/shutdown.d.ts +9 -6
  17. package/output/core/boot/shutdown.d.ts.map +1 -0
  18. package/output/{app → core/boot}/shutdown.js +7 -4
  19. package/output/core/boot/signal.d.ts +13 -0
  20. package/output/core/boot/signal.d.ts.map +1 -0
  21. package/output/{app → core/boot}/signal.js +3 -2
  22. package/output/core/boot/steps.d.ts +107 -0
  23. package/output/core/boot/steps.d.ts.map +1 -0
  24. package/output/core/boot/steps.js +200 -0
  25. package/output/core/entries.d.ts +123 -0
  26. package/output/core/entries.d.ts.map +1 -0
  27. package/output/core/entries.js +193 -0
  28. package/output/core/entries.test.d.ts +2 -0
  29. package/output/core/entries.test.d.ts.map +1 -0
  30. package/output/core/entries.test.js +217 -0
  31. package/output/core/env.d.ts +62 -0
  32. package/output/core/env.d.ts.map +1 -0
  33. package/output/core/env.js +96 -0
  34. package/output/{app → core}/env.test.d.ts.map +1 -1
  35. package/output/core/env.test.js +105 -0
  36. package/output/core/modules/auth-provider/index.d.ts +10 -0
  37. package/output/core/modules/auth-provider/index.d.ts.map +1 -0
  38. package/output/core/modules/auth-provider/index.js +9 -0
  39. package/output/core/modules/auth-provider/types.d.ts +71 -0
  40. package/output/core/modules/auth-provider/types.d.ts.map +1 -0
  41. package/output/core/modules/context/index.d.ts +18 -0
  42. package/output/core/modules/context/index.d.ts.map +1 -0
  43. package/output/core/modules/context/index.js +23 -0
  44. package/output/core/modules/context/index.test.d.ts.map +1 -0
  45. package/output/core/modules/cookie/index.d.ts +21 -0
  46. package/output/core/modules/cookie/index.d.ts.map +1 -0
  47. package/output/{app/core/cookie.js → core/modules/cookie/index.js} +1 -6
  48. package/output/core/modules/identity/index.d.ts +4 -0
  49. package/output/core/modules/identity/index.d.ts.map +1 -0
  50. package/output/{app/core/identity.js → core/modules/identity/index.js} +1 -1
  51. package/output/core/modules/logging/index.d.ts +5 -0
  52. package/output/core/modules/logging/index.d.ts.map +1 -0
  53. package/output/{app/core/logging.js → core/modules/logging/index.js} +2 -2
  54. package/output/core/modules/openapi/index.d.ts +7 -0
  55. package/output/core/modules/openapi/index.d.ts.map +1 -0
  56. package/output/{app/core/openapi.js → core/modules/openapi/index.js} +11 -12
  57. package/output/core/modules/permission-operations/index.d.ts +26 -0
  58. package/output/core/modules/permission-operations/index.d.ts.map +1 -0
  59. package/output/core/modules/permission-operations/index.js +36 -0
  60. package/output/core/modules/permission-operations/index.test.d.ts +2 -0
  61. package/output/core/modules/permission-operations/index.test.d.ts.map +1 -0
  62. package/output/core/modules/permission-operations/index.test.js +45 -0
  63. package/output/{app/core/request-id.d.ts → core/modules/request-id/index.d.ts} +1 -4
  64. package/output/core/modules/request-id/index.d.ts.map +1 -0
  65. package/output/{app/core/request-id.js → core/modules/request-id/index.js} +2 -2
  66. package/output/core/modules/response/index.d.ts +22 -0
  67. package/output/core/modules/response/index.d.ts.map +1 -0
  68. package/output/{app/core/response.js → core/modules/response/index.js} +22 -11
  69. package/output/{schema/index.d.ts → core/modules/schema/builders.d.ts} +8 -1
  70. package/output/core/modules/schema/builders.d.ts.map +1 -0
  71. package/output/{schema/index.js → core/modules/schema/builders.js} +7 -4
  72. package/output/core/modules/schema/index.d.ts +34 -0
  73. package/output/core/modules/schema/index.d.ts.map +1 -0
  74. package/output/core/modules/schema/index.js +62 -0
  75. package/output/core/modules/schema/index.test.d.ts +2 -0
  76. package/output/core/modules/schema/index.test.d.ts.map +1 -0
  77. package/output/core/modules/schema/index.test.js +55 -0
  78. package/output/core/modules/system-routes/index.d.ts +15 -0
  79. package/output/core/modules/system-routes/index.d.ts.map +1 -0
  80. package/output/core/modules/system-routes/index.js +171 -0
  81. package/output/core/test-support/database.d.ts +96 -0
  82. package/output/core/test-support/database.d.ts.map +1 -0
  83. package/output/core/test-support/database.js +144 -0
  84. package/output/core/test-support/database.test.d.ts +2 -0
  85. package/output/core/test-support/database.test.d.ts.map +1 -0
  86. package/output/core/test-support/database.test.js +110 -0
  87. package/output/core/test-support/environment.d.ts +33 -0
  88. package/output/core/test-support/environment.d.ts.map +1 -0
  89. package/output/core/test-support/environment.js +42 -0
  90. package/output/core/test-support/test-server.d.ts +94 -0
  91. package/output/core/test-support/test-server.d.ts.map +1 -0
  92. package/output/core/test-support/test-server.js +60 -0
  93. package/output/core/test-support/test-server.test.d.ts +2 -0
  94. package/output/core/test-support/test-server.test.d.ts.map +1 -0
  95. package/output/core/test-support/test-server.test.js +162 -0
  96. package/output/{app → core}/type-augment.d.ts +2 -2
  97. package/output/core/type-augment.d.ts.map +1 -0
  98. package/output/{app → core}/types.d.ts +153 -66
  99. package/output/core/types.d.ts.map +1 -0
  100. package/output/cors/index.d.ts +3 -0
  101. package/output/cors/index.d.ts.map +1 -0
  102. package/output/cors/index.js +27 -0
  103. package/output/index.d.ts +8 -4
  104. package/output/index.d.ts.map +1 -1
  105. package/output/index.js +24 -5
  106. package/output/rate-limit/index.d.ts +23 -0
  107. package/output/rate-limit/index.d.ts.map +1 -0
  108. package/output/rate-limit/index.js +42 -0
  109. package/output/{rate-limiter/rate-limiter.d.ts → rate-limit/limiter.d.ts} +1 -1
  110. package/output/rate-limit/limiter.d.ts.map +1 -0
  111. package/output/rate-limit/memory-store.d.ts.map +1 -0
  112. package/output/rate-limit/redis-store.d.ts.map +1 -0
  113. package/output/rate-limit/redis-store.test.d.ts.map +1 -0
  114. package/output/{rate-limiter → rate-limit}/redis-store.test.js +2 -2
  115. package/output/{rate-limiter → rate-limit}/types.d.ts +0 -1
  116. package/output/rate-limit/types.d.ts.map +1 -0
  117. package/output/rate-limit/types.js +1 -0
  118. package/output/{redis-cache/redis-cache.d.ts → redis/cache.d.ts} +1 -1
  119. package/output/redis/cache.d.ts.map +1 -0
  120. package/output/redis/cache.test.d.ts +2 -0
  121. package/output/redis/cache.test.d.ts.map +1 -0
  122. package/output/{redis-cache/redis-cache.test.js → redis/cache.test.js} +1 -1
  123. package/output/{app/redis.d.ts → redis/index.d.ts} +7 -6
  124. package/output/redis/index.d.ts.map +1 -0
  125. package/output/{app/redis.js → redis/index.js} +10 -4
  126. package/output/redis/index.test.d.ts +2 -0
  127. package/output/{context → redis}/index.test.d.ts.map +1 -1
  128. package/output/redis/index.test.js +55 -0
  129. package/output/redis-queue/index.js +1 -1
  130. package/output/redis-queue/test-helpers.d.ts +1 -1
  131. package/output/redis-queue/test-helpers.js +1 -1
  132. package/output/redis-queue/types.d.ts +3 -12
  133. package/output/redis-queue/types.d.ts.map +1 -1
  134. package/package.json +5 -5
  135. package/output/app/auth.test.d.ts +0 -2
  136. package/output/app/auth.test.d.ts.map +0 -1
  137. package/output/app/auth.test.js +0 -148
  138. package/output/app/boot.d.ts +0 -44
  139. package/output/app/boot.d.ts.map +0 -1
  140. package/output/app/boot.js +0 -158
  141. package/output/app/config.test.d.ts +0 -2
  142. package/output/app/config.test.d.ts.map +0 -1
  143. package/output/app/config.test.js +0 -132
  144. package/output/app/context.d.ts +0 -74
  145. package/output/app/context.d.ts.map +0 -1
  146. package/output/app/core/cookie.d.ts +0 -25
  147. package/output/app/core/cookie.d.ts.map +0 -1
  148. package/output/app/core/identity.d.ts +0 -12
  149. package/output/app/core/identity.d.ts.map +0 -1
  150. package/output/app/core/index.d.ts +0 -44
  151. package/output/app/core/index.d.ts.map +0 -1
  152. package/output/app/core/index.js +0 -57
  153. package/output/app/core/logging.d.ts +0 -13
  154. package/output/app/core/logging.d.ts.map +0 -1
  155. package/output/app/core/openapi.d.ts +0 -17
  156. package/output/app/core/openapi.d.ts.map +0 -1
  157. package/output/app/core/request-id.d.ts.map +0 -1
  158. package/output/app/core/response.d.ts +0 -41
  159. package/output/app/core/response.d.ts.map +0 -1
  160. package/output/app/define-server.negative-cases.d.ts +0 -40
  161. package/output/app/define-server.negative-cases.d.ts.map +0 -1
  162. package/output/app/define-server.negative-cases.js +0 -268
  163. package/output/app/define-server.test.d.ts +0 -2
  164. package/output/app/define-server.test.d.ts.map +0 -1
  165. package/output/app/define-server.test.js +0 -97
  166. package/output/app/entries.d.ts +0 -31
  167. package/output/app/entries.d.ts.map +0 -1
  168. package/output/app/entries.js +0 -66
  169. package/output/app/env.d.ts +0 -59
  170. package/output/app/env.d.ts.map +0 -1
  171. package/output/app/env.js +0 -66
  172. package/output/app/env.test.js +0 -124
  173. package/output/app/error-contract.test.d.ts +0 -2
  174. package/output/app/error-contract.test.d.ts.map +0 -1
  175. package/output/app/error-contract.test.js +0 -227
  176. package/output/app/errors.d.ts +0 -20
  177. package/output/app/errors.d.ts.map +0 -1
  178. package/output/app/errors.js +0 -51
  179. package/output/app/generate-openapi.test.d.ts +0 -2
  180. package/output/app/generate-openapi.test.d.ts.map +0 -1
  181. package/output/app/generate-openapi.test.js +0 -123
  182. package/output/app/lifecycle-logging.test.d.ts +0 -2
  183. package/output/app/lifecycle-logging.test.d.ts.map +0 -1
  184. package/output/app/lifecycle-logging.test.js +0 -175
  185. package/output/app/lifecycle.d.ts.map +0 -1
  186. package/output/app/lifecycle.test.d.ts +0 -2
  187. package/output/app/lifecycle.test.d.ts.map +0 -1
  188. package/output/app/lifecycle.test.js +0 -153
  189. package/output/app/middleware/auth.d.ts +0 -71
  190. package/output/app/middleware/auth.d.ts.map +0 -1
  191. package/output/app/middleware/auth.js +0 -190
  192. package/output/app/middleware/context.d.ts +0 -13
  193. package/output/app/middleware/context.d.ts.map +0 -1
  194. package/output/app/middleware/context.js +0 -15
  195. package/output/app/middleware/cors.d.ts +0 -14
  196. package/output/app/middleware/cors.d.ts.map +0 -1
  197. package/output/app/middleware/cors.js +0 -30
  198. package/output/app/middleware/index.d.ts +0 -17
  199. package/output/app/middleware/index.d.ts.map +0 -1
  200. package/output/app/middleware/index.js +0 -16
  201. package/output/app/middleware/rate-limit.d.ts +0 -24
  202. package/output/app/middleware/rate-limit.d.ts.map +0 -1
  203. package/output/app/middleware/rate-limit.js +0 -46
  204. package/output/app/middleware-order.test.d.ts +0 -2
  205. package/output/app/middleware-order.test.d.ts.map +0 -1
  206. package/output/app/middleware-order.test.js +0 -149
  207. package/output/app/permission-operations.d.ts +0 -48
  208. package/output/app/permission-operations.d.ts.map +0 -1
  209. package/output/app/permission-operations.js +0 -77
  210. package/output/app/permission-operations.test.d.ts +0 -2
  211. package/output/app/permission-operations.test.d.ts.map +0 -1
  212. package/output/app/permission-operations.test.js +0 -72
  213. package/output/app/permission-registration.test.d.ts +0 -2
  214. package/output/app/permission-registration.test.d.ts.map +0 -1
  215. package/output/app/permission-registration.test.js +0 -138
  216. package/output/app/redis.d.ts.map +0 -1
  217. package/output/app/registered-operations.test.d.ts +0 -2
  218. package/output/app/registered-operations.test.d.ts.map +0 -1
  219. package/output/app/registered-operations.test.js +0 -57
  220. package/output/app/request-id.test.d.ts +0 -2
  221. package/output/app/request-id.test.d.ts.map +0 -1
  222. package/output/app/request-id.test.js +0 -130
  223. package/output/app/resources.test.d.ts +0 -2
  224. package/output/app/resources.test.d.ts.map +0 -1
  225. package/output/app/resources.test.js +0 -222
  226. package/output/app/shutdown.d.ts.map +0 -1
  227. package/output/app/shutdown.test.d.ts +0 -2
  228. package/output/app/shutdown.test.d.ts.map +0 -1
  229. package/output/app/shutdown.test.js +0 -210
  230. package/output/app/signal.d.ts +0 -12
  231. package/output/app/signal.d.ts.map +0 -1
  232. package/output/app/smoke.test.d.ts +0 -2
  233. package/output/app/smoke.test.d.ts.map +0 -1
  234. package/output/app/smoke.test.js +0 -210
  235. package/output/app/test-support.d.ts +0 -21
  236. package/output/app/test-support.d.ts.map +0 -1
  237. package/output/app/test-support.js +0 -24
  238. package/output/app/type-augment.d.ts.map +0 -1
  239. package/output/app/types.d.ts.map +0 -1
  240. package/output/context/index.d.ts +0 -6
  241. package/output/context/index.d.ts.map +0 -1
  242. package/output/context/index.js +0 -14
  243. package/output/rate-limiter/index.d.ts +0 -5
  244. package/output/rate-limiter/index.d.ts.map +0 -1
  245. package/output/rate-limiter/index.js +0 -4
  246. package/output/rate-limiter/memory-store.d.ts.map +0 -1
  247. package/output/rate-limiter/rate-limiter.d.ts.map +0 -1
  248. package/output/rate-limiter/redis-store.d.ts.map +0 -1
  249. package/output/rate-limiter/redis-store.test.d.ts.map +0 -1
  250. package/output/rate-limiter/types.d.ts.map +0 -1
  251. package/output/redis-cache/index.d.ts +0 -4
  252. package/output/redis-cache/index.d.ts.map +0 -1
  253. package/output/redis-cache/index.js +0 -1
  254. package/output/redis-cache/redis-cache.d.ts.map +0 -1
  255. package/output/redis-cache/redis-cache.test.d.ts +0 -2
  256. package/output/redis-cache/redis-cache.test.d.ts.map +0 -1
  257. package/output/schema/index.d.ts.map +0 -1
  258. /package/output/{app → core}/env.test.d.ts +0 -0
  259. /package/output/{rate-limiter → core/modules/auth-provider}/types.js +0 -0
  260. /package/output/{context → core/modules/context}/index.test.d.ts +0 -0
  261. /package/output/{context → core/modules/context}/index.test.js +0 -0
  262. /package/output/{app → core}/type-augment.js +0 -0
  263. /package/output/{app → core}/types.js +0 -0
  264. /package/output/{rate-limiter/rate-limiter.js → rate-limit/limiter.js} +0 -0
  265. /package/output/{rate-limiter → rate-limit}/memory-store.d.ts +0 -0
  266. /package/output/{rate-limiter → rate-limit}/memory-store.js +0 -0
  267. /package/output/{rate-limiter → rate-limit}/redis-store.d.ts +0 -0
  268. /package/output/{rate-limiter → rate-limit}/redis-store.js +0 -0
  269. /package/output/{rate-limiter → rate-limit}/redis-store.test.d.ts +0 -0
  270. /package/output/{redis-cache/redis-cache.js → redis/cache.js} +0 -0
@@ -1,4 +1,4 @@
1
- import { createRedisClient, RedisCache } from '../redis-cache/index.js';
1
+ import { createRedisClient, RedisCache } from './cache.js';
2
2
  /**
3
3
  * 引导期 Redis / cache helper(N2 §2.13)。
4
4
  *
@@ -18,8 +18,6 @@ import { createRedisClient, RedisCache } from '../redis-cache/index.js';
18
18
  * **惰性包装**:构造时不建连、不 ping,首次真正使用才建连 —— 「出 spec 不连库/Redis」结构性成立。
19
19
  * 释放永远走调用方在 `ctx.disposer` 里的登记,框架不替资源持有句柄。
20
20
  */
21
- /** 一级/二级缓存默认 TTL(秒),与 `RedisCache` 默认一致 */
22
- export const DEFAULT_REDIS_CACHE_TTL_SECONDS = 300;
23
21
  /**
24
22
  * 构造 Redis 句柄(惰性包装:不建连、不 ping)。
25
23
  *
@@ -40,7 +38,13 @@ export function createRedis(env, log) {
40
38
  await client.quit().catch(() => undefined);
41
39
  }
42
40
  else {
43
- client.destroy();
41
+ // 未建连(从未使用过)时 `destroy()` 会抛 "The client is closed";释放必须是幂等的
42
+ try {
43
+ client.destroy();
44
+ }
45
+ catch {
46
+ // 已关闭:无事可做
47
+ }
44
48
  }
45
49
  },
46
50
  };
@@ -63,3 +67,5 @@ export function createCache(params) {
63
67
  params.log?.debug({}, '[redis] REDIS_URL not configured; cache falls back to in-process L1');
64
68
  return new RedisCache({ prefix: params.prefix });
65
69
  }
70
+ // ── 缓存 / 客户端实现(与引导期 helper 同一模块)───────────────
71
+ export { RedisCache, createRedisClient } from './cache.js';
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.test.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../source/context/index.test.ts"],"names":[],"mappings":""}
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/test-helpers'
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/test-helpers'
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,wBAAwB;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,eAAe,CAAA;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,eAAe,CAAA;IAC7B,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;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;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;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,eAAe,CAAA;IAC7B,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,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,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"}
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",
3
+ "version": "4.0.0-beta.5",
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
- "@scalar/fastify-api-reference": "^1",
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.3"
38
+ "@taicode/common-base": "^4.0.0-beta.5"
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.3"
52
+ "@taicode/common-base": "^4.0.0-beta.5"
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,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=auth.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth.test.d.ts","sourceRoot":"","sources":["../../source/app/auth.test.ts"],"names":[],"mappings":""}
@@ -1,148 +0,0 @@
1
- import { afterEach, describe, expect, it, vi } from 'vitest';
2
- import { defineServer, startServer } from './entries.js';
3
- import { createAuthMiddleware } from './middleware/auth.js';
4
- import { createContextMiddleware } from './middleware/context.js';
5
- const listWidgetSchema = { operationId: 'listWidget' };
6
- const widgetDetailSchema = { operationId: 'getWidgetDetail' };
7
- function captureVerify(capture) {
8
- return async (input) => {
9
- capture.push(input);
10
- return { user: { id: 'user-1' }, token: input.token };
11
- };
12
- }
13
- function createServer(configuration, authOptions = {}) {
14
- return defineServer({
15
- app: { service: 'auth', title: 'Auth', version: '1.0.0' },
16
- resources: () => ({}),
17
- config: () => configuration,
18
- services: () => ({}),
19
- middlewares: (ctx) => [
20
- createContextMiddleware(),
21
- createAuthMiddleware(ctx, { registerPermissions: false, ...authOptions }),
22
- ],
23
- routers: (ctx) => {
24
- ctx.app.get('/widget/with-operation', { schema: listWidgetSchema }, () => ({ ok: true }));
25
- ctx.app.get('/widget/no-operation', () => ({ ok: true }));
26
- ctx.app.get('/widget/:id/detail', { schema: widgetDetailSchema }, () => ({ ok: true }));
27
- },
28
- });
29
- }
30
- const bearerToken = ['Bearer', 'token-1'].join(' ');
31
- async function request(app, url, headers = {}) {
32
- const response = await app.inject({
33
- method: 'GET',
34
- url,
35
- headers: { authorization: bearerToken, ...headers },
36
- });
37
- expect(response.statusCode).toBe(200);
38
- }
39
- afterEach(() => {
40
- vi.unstubAllGlobals();
41
- });
42
- describe('auth verify 入参', () => {
43
- it('operation 优先取路由 schema.operationId,未声明时回落 url;service 取身份块', async () => {
44
- const capture = [];
45
- const app = await startServer(createServer({ account: { enabled: true, serviceUrl: 'http://account.local' } }, { verify: captureVerify(capture) }), { listen: false });
46
- try {
47
- await request(app, '/widget/with-operation');
48
- await request(app, '/widget/no-operation');
49
- expect(capture.map((input) => input.operation)).toEqual(['listWidget', '/widget/no-operation']);
50
- expect(capture.map((input) => input.service)).toEqual(['auth', 'auth']);
51
- }
52
- finally {
53
- await app.close();
54
- }
55
- });
56
- });
57
- describe('resource / metadata', () => {
58
- it('resource 取路由参数、metadata 填请求元信息', async () => {
59
- const capture = [];
60
- const app = await startServer(createServer({ account: { enabled: true, serviceUrl: 'http://account.local' } }, { verify: captureVerify(capture) }), { listen: false });
61
- try {
62
- await request(app, '/widget/w-9/detail', { 'user-agent': 'auth-test-agent' });
63
- const input = capture[0];
64
- expect(input.resource).toEqual({ id: 'w-9' });
65
- expect(input.metadata).toMatchObject({
66
- method: 'GET',
67
- url: '/widget/w-9/detail',
68
- userAgent: 'auth-test-agent',
69
- });
70
- expect(typeof input.metadata?.requestId).toBe('string');
71
- expect(typeof input.metadata?.ip).toBe('string');
72
- }
73
- finally {
74
- await app.close();
75
- }
76
- });
77
- it('内置 verify 的 POST body 一并带上 resource 与 metadata', async () => {
78
- const requests = [];
79
- const fetchStub = vi.fn(async (input, init) => {
80
- requests.push({
81
- url: typeof input === 'string' ? input : input.toString(),
82
- body: init?.body ? JSON.parse(String(init.body)) : undefined,
83
- });
84
- return {
85
- ok: true,
86
- status: 200,
87
- json: async () => ({ status: 'SUCCESS', data: { user: { id: 'u' }, token: 'token-1' } }),
88
- };
89
- });
90
- vi.stubGlobal('fetch', fetchStub);
91
- const app = await startServer(createServer({ account: { enabled: true, serviceUrl: 'http://account.local' } }), { listen: false });
92
- try {
93
- await request(app, '/widget/w-9/detail', { 'user-agent': 'auth-test-agent' });
94
- expect(requests).toHaveLength(1);
95
- expect(requests[0].url).toBe('http://account.local/gateway/verify');
96
- expect(requests[0].body?.operation).toBe('getWidgetDetail');
97
- expect(requests[0].body?.resource).toEqual({ id: 'w-9' });
98
- expect(requests[0].body?.metadata).toMatchObject({
99
- method: 'GET',
100
- url: '/widget/w-9/detail',
101
- userAgent: 'auth-test-agent',
102
- });
103
- }
104
- finally {
105
- await app.close();
106
- }
107
- });
108
- });
109
- describe('account serviceUrl 门槛仅作用于内置 verify', () => {
110
- it('自定义 verify + account 无 serviceUrl 时仍然校验', async () => {
111
- const capture = [];
112
- const app = await startServer(createServer({ account: { enabled: false } }, { verify: captureVerify(capture) }), { listen: false });
113
- try {
114
- await request(app, '/widget/with-operation');
115
- expect(capture.map((input) => input.operation)).toEqual(['listWidget']);
116
- }
117
- finally {
118
- await app.close();
119
- }
120
- });
121
- it('内置 verify + account 无 serviceUrl 时放行(不校验、不发请求)', async () => {
122
- const fetchStub = vi.fn(async () => {
123
- throw new Error('should not be called');
124
- });
125
- vi.stubGlobal('fetch', fetchStub);
126
- const app = await startServer(createServer({ account: { enabled: false } }), { listen: false });
127
- try {
128
- // 无凭证也 200:无 serviceUrl 时内置 verify 直接放行
129
- await request(app, '/widget/with-operation', { authorization: '' });
130
- expect(fetchStub).not.toHaveBeenCalled();
131
- }
132
- finally {
133
- await app.close();
134
- }
135
- });
136
- it('跳过 docPath / OPTIONS / NoLoginRequired(默认 skip)', async () => {
137
- const capture = [];
138
- const app = await startServer(createServer({ account: { enabled: true, serviceUrl: 'http://account.local' } }, { verify: captureVerify(capture) }), { listen: false });
139
- try {
140
- const optionsResponse = await app.inject({ method: 'OPTIONS', url: '/widget/with-operation' });
141
- expect(optionsResponse.statusCode).not.toBe(500);
142
- expect(capture).toHaveLength(0);
143
- }
144
- finally {
145
- await app.close();
146
- }
147
- });
148
- });
@@ -1,44 +0,0 @@
1
- import type { ConfigEnv } from './env.js';
2
- import type { ResourcesView, Server, ShutdownContext } from './types.js';
3
- import type { FastifyInstance } from 'fastify';
4
- /** 内部步序(`prepare` → `compose` → `activate`):`startServer` / `generateOpenApi` 共用。 */
5
- export declare const BOOT_PHASE_START = "start";
6
- export declare const BOOT_PHASE_OPENAPI = "openapi";
7
- /** 两个入口的内部步序跳过集 */
8
- export type BootPhase = typeof BOOT_PHASE_START | typeof BOOT_PHASE_OPENAPI;
9
- /** 默认监听地址 */
10
- export declare const DEFAULT_HOST = "0.0.0.0";
11
- export interface BootInput<R, C, S> {
12
- server: Server<R, C, S>;
13
- env: ConfigEnv;
14
- phase: BootPhase;
15
- listen: boolean;
16
- shutdown?: (ctx: ShutdownContext<R, C, S>) => Promise<void>;
17
- }
18
- export interface BootedServer<R, S> {
19
- app: FastifyInstance;
20
- resources: ResourcesView<R>;
21
- services: Awaited<S>;
22
- dispose: () => Promise<void>;
23
- }
24
- /**
25
- * 装配一个服务(`startServer` / `generateOpenApi` 共用)。
26
- *
27
- * 步序(N1 §5):
28
- * ```
29
- * 1. 加载 env(框架固定,调用方已做) → env
30
- * 2. resources(ctx={env,log,disposer}) → R(只构造,不建连)
31
- * 3. config(ctx={env,log,disposer,resources}) → C(仅 start 路径;出 spec 路径不跑)
32
- * 4. services(ctx={log,disposer,resources,config}) → S,随后按声明序 init()(仅 start 路径)
33
- * 5. middlewares(ctx={app,log,disposer,services,config}) → 按数组序 register(app)
34
- * 6. routers(ctx={app,log,disposer,services}) → 注册路由
35
- * 7. ready / listen
36
- * ```
37
- *
38
- * **每个阶段一个独立 `Disposer`**(构造处注册释放);关闭时按阶段**逆序 flush**
39
- * `routers → middlewares → services → config → resources`(services 阶段内部先 flush 自己的
40
- * `disposer`,再逐单元逆序 `dispose`)。资源因此**最后**才断:service 关闭时若还要落库不会
41
- * 撞死连接。出 spec 路径不关闭,也不执行任何 flush。
42
- */
43
- export declare function bootServer<R, C, S>(input: BootInput<R, C, S>): Promise<BootedServer<R, S>>;
44
- //# sourceMappingURL=boot.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"boot.d.ts","sourceRoot":"","sources":["../../source/app/boot.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACzC,OAAO,KAAK,EAAgC,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACtG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAE9C,qFAAqF;AACrF,eAAO,MAAM,gBAAgB,UAAU,CAAA;AACvC,eAAO,MAAM,kBAAkB,YAAY,CAAA;AAC3C,mBAAmB;AACnB,MAAM,MAAM,SAAS,GAAG,OAAO,gBAAgB,GAAG,OAAO,kBAAkB,CAAA;AAC3E,aAAa;AACb,eAAO,MAAM,YAAY,YAAY,CAAA;AAErC,MAAM,WAAW,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IACvB,GAAG,EAAE,SAAS,CAAA;IACd,KAAK,EAAE,SAAS,CAAA;IAChB,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC5D;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,EAAE,CAAC;IAChC,GAAG,EAAE,eAAe,CAAA;IACpB,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;IAC3B,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IACpB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAqCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CA6HhG"}
@@ -1,158 +0,0 @@
1
- import { Disposer } from '@taicode/common-base';
2
- import { createConfigContext, createConfigHolder, createMiddlewareContext, createResourcesContext, createRouterContext, createServiceContext, createShutdownContext, liveResources, readConfigKey, requireConfig, } from './context.js';
3
- import { createFastify, registerCore } from './core/index.js';
4
- import { CONFIG_STAGE, disposeServices, disposeStage, initServiceUnits, MIDDLEWARES_LOG_STAGE, MIDDLEWARES_STAGE, middlewareUnitName, RESOURCES_STAGE, ROUTERS_STAGE, SERVICES_STAGE, } from './lifecycle.js';
5
- import { runShutdown } from './shutdown.js';
6
- import { attachSignalHandlers } from './signal.js';
7
- /** 内部步序(`prepare` → `compose` → `activate`):`startServer` / `generateOpenApi` 共用。 */
8
- export const BOOT_PHASE_START = 'start';
9
- export const BOOT_PHASE_OPENAPI = 'openapi';
10
- /** 默认监听地址 */
11
- export const DEFAULT_HOST = '0.0.0.0';
12
- function resolvePort(env) {
13
- const parsed = Number(env.API_PORT);
14
- if (!Number.isInteger(parsed) || parsed <= 0) {
15
- throw new Error(`[server] API_PORT is required to listen (got "${env.API_PORT}")`);
16
- }
17
- return parsed;
18
- }
19
- /**
20
- * 把各资源通过 `ctx.registerClassifyError` 注册的错误分类器合成单个分类器。
21
- *
22
- * 范式:**一个资源一个分类器,各管各的错误域**(认领不了就返回 `null` 交给下一个)。
23
- *
24
- * - 零个 → `undefined`(响应层落 `UNKNOWN_ERROR` 兜底);
25
- * - 一个 → 原样返回(少一层包装);
26
- * - 多个 → 按**注册顺序**串成链,返回第一个非 `null` 的结果(短路)。
27
- */
28
- function combineClassifiers(classifiers) {
29
- if (classifiers.length === 0) {
30
- return undefined;
31
- }
32
- if (classifiers.length === 1) {
33
- return classifiers[0];
34
- }
35
- return (error) => {
36
- for (const classifier of classifiers) {
37
- const result = classifier(error);
38
- if (result !== null) {
39
- return result;
40
- }
41
- }
42
- return null;
43
- };
44
- }
45
- /**
46
- * 装配一个服务(`startServer` / `generateOpenApi` 共用)。
47
- *
48
- * 步序(N1 §5):
49
- * ```
50
- * 1. 加载 env(框架固定,调用方已做) → env
51
- * 2. resources(ctx={env,log,disposer}) → R(只构造,不建连)
52
- * 3. config(ctx={env,log,disposer,resources}) → C(仅 start 路径;出 spec 路径不跑)
53
- * 4. services(ctx={log,disposer,resources,config}) → S,随后按声明序 init()(仅 start 路径)
54
- * 5. middlewares(ctx={app,log,disposer,services,config}) → 按数组序 register(app)
55
- * 6. routers(ctx={app,log,disposer,services}) → 注册路由
56
- * 7. ready / listen
57
- * ```
58
- *
59
- * **每个阶段一个独立 `Disposer`**(构造处注册释放);关闭时按阶段**逆序 flush**
60
- * `routers → middlewares → services → config → resources`(services 阶段内部先 flush 自己的
61
- * `disposer`,再逐单元逆序 `dispose`)。资源因此**最后**才断:service 关闭时若还要落库不会
62
- * 撞死连接。出 spec 路径不关闭,也不执行任何 flush。
63
- */
64
- export async function bootServer(input) {
65
- const { server, env, phase } = input;
66
- const isStart = phase === BOOT_PHASE_START;
67
- const service = server.app.service;
68
- // ── prepare ──────────────────────────────────────────────────────────────
69
- // ① createFastify(+ 内置 logger / requestId)
70
- const app = createFastify(env);
71
- const instance = app;
72
- const log = app.log;
73
- // 每个阶段一个 Disposer:创建与释放同处一地,关闭时按阶段逆序 flush
74
- const disposers = {
75
- resources: new Disposer(),
76
- config: new Disposer(),
77
- services: new Disposer(),
78
- middlewares: new Disposer(),
79
- routers: new Disposer(),
80
- };
81
- const holder = createConfigHolder();
82
- // ② resources:只构造,不建连(出 spec 路径同样执行)
83
- // 资源错误分类器由各资源通过 `ctx.registerClassifyError` 各自注册:在调 `resources(ctx)` 前建局部收集器,
84
- // 返回后把注册结果按注册顺序合成单个分类器喂给 core。
85
- const classifiers = [];
86
- const resources = (await server.resources(createResourcesContext({
87
- env,
88
- log,
89
- disposer: disposers.resources,
90
- registerClassifyError: (classifier) => {
91
- classifiers.push(classifier);
92
- },
93
- })));
94
- const resourcesView = liveResources(resources);
95
- // ③ core 装配(schema → cookie → response → openapi → 路由注册表)
96
- await registerCore(app, {
97
- identity: server.app,
98
- env,
99
- classifyResourceError: combineClassifiers(classifiers),
100
- readConfig: (key) => readConfigKey(requireConfig(holder), key),
101
- });
102
- // ── compose ──────────────────────────────────────────────────────────────
103
- // ① config(仅 start 路径;出 spec 路径不跑 → `ctx.config` 读到即抛 CONFIG_UNAVAILABLE)
104
- if (isStart) {
105
- holder.current = (await server.config(createConfigContext({ env, log, disposer: disposers.config, resources: resourcesView })));
106
- }
107
- // ② services(两个入口都执行;ctx 无 env、无 services)
108
- const services = server.services(createServiceContext({
109
- log,
110
- disposer: disposers.services,
111
- resources: resourcesView,
112
- holder,
113
- }));
114
- // ③ initLifecycleUnits(仅 start 路径)
115
- if (isStart) {
116
- await initServiceUnits({ service, log, services: services });
117
- }
118
- // ④ middlewares(两个入口都执行:出 spec 也照注册,保证 schema 一致)
119
- const middlewares = server.middlewares(createMiddlewareContext({ app: instance, log, disposer: disposers.middlewares, services, holder }));
120
- for (const [index, unit] of middlewares.entries()) {
121
- await unit.register(instance);
122
- log.debug({ service, unit: middlewareUnitName(service, unit, index), stage: MIDDLEWARES_LOG_STAGE }, '[middleware] registered');
123
- }
124
- // ⑤ routers(两个入口都执行)
125
- await server.routers(createRouterContext({ app: instance, log, disposer: disposers.routers, services }));
126
- // ── activate ─────────────────────────────────────────────────────────────
127
- const runShutdownFlow = async () => {
128
- if (input.shutdown) {
129
- // 整体覆盖:自定义 shutdown 自行负责各阶段 flush(框架不再代劳)
130
- await input.shutdown(createShutdownContext({
131
- app: instance,
132
- log,
133
- disposer: disposers.services,
134
- resources: resourcesView,
135
- holder,
136
- services,
137
- }));
138
- return;
139
- }
140
- await runShutdown({
141
- flushRouters: () => disposeStage({ service, log, stage: ROUTERS_STAGE, disposer: disposers.routers }),
142
- flushMiddlewares: () => disposeStage({ service, log, stage: MIDDLEWARES_STAGE, disposer: disposers.middlewares }),
143
- flushServices: () => disposeStage({ service, log, stage: SERVICES_STAGE, disposer: disposers.services }),
144
- disposeServices: () => disposeServices({ service, log, services: services }),
145
- flushConfig: () => disposeStage({ service, log, stage: CONFIG_STAGE, disposer: disposers.config }),
146
- flushResources: () => disposeStage({ service, log, stage: RESOURCES_STAGE, disposer: disposers.resources }),
147
- }, log);
148
- };
149
- app.addHook('onClose', () => runShutdownFlow());
150
- // ⑥ ready(两个入口都执行)
151
- await app.ready();
152
- // ⑦ listen / signal(仅 start 路径)
153
- if (isStart && input.listen) {
154
- await app.listen({ port: resolvePort(env), host: DEFAULT_HOST });
155
- attachSignalHandlers(app, log);
156
- }
157
- return { app, resources: resourcesView, services, dispose: runShutdownFlow };
158
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=config.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.test.d.ts","sourceRoot":"","sources":["../../source/app/config.test.ts"],"names":[],"mappings":""}