@taicode/common-server 4.0.0-beta.2 → 4.0.0-beta.4

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 (276) 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/core/boot/context.js +106 -0
  13. package/output/core/boot/lifecycle.d.ts +94 -0
  14. package/output/core/boot/lifecycle.d.ts.map +1 -0
  15. package/output/{app → core/boot}/lifecycle.js +45 -14
  16. package/output/core/boot/shutdown.d.ts +30 -0
  17. package/output/core/boot/shutdown.d.ts.map +1 -0
  18. package/output/core/boot/shutdown.js +45 -0
  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/core/types.d.ts +338 -0
  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} +12 -7
  124. package/output/redis/index.d.ts.map +1 -0
  125. package/output/{app/redis.js → redis/index.js} +15 -5
  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 +16 -15
  135. package/LICENSE +0 -21
  136. package/output/app/auth.test.d.ts +0 -2
  137. package/output/app/auth.test.d.ts.map +0 -1
  138. package/output/app/auth.test.js +0 -148
  139. package/output/app/boot.d.ts +0 -39
  140. package/output/app/boot.d.ts.map +0 -1
  141. package/output/app/boot.js +0 -140
  142. package/output/app/config.test.d.ts +0 -2
  143. package/output/app/config.test.d.ts.map +0 -1
  144. package/output/app/config.test.js +0 -132
  145. package/output/app/context.d.ts +0 -70
  146. package/output/app/context.d.ts.map +0 -1
  147. package/output/app/context.js +0 -73
  148. package/output/app/core/cookie.d.ts +0 -25
  149. package/output/app/core/cookie.d.ts.map +0 -1
  150. package/output/app/core/identity.d.ts +0 -12
  151. package/output/app/core/identity.d.ts.map +0 -1
  152. package/output/app/core/index.d.ts +0 -44
  153. package/output/app/core/index.d.ts.map +0 -1
  154. package/output/app/core/index.js +0 -57
  155. package/output/app/core/logging.d.ts +0 -13
  156. package/output/app/core/logging.d.ts.map +0 -1
  157. package/output/app/core/openapi.d.ts +0 -17
  158. package/output/app/core/openapi.d.ts.map +0 -1
  159. package/output/app/core/request-id.d.ts.map +0 -1
  160. package/output/app/core/response.d.ts +0 -41
  161. package/output/app/core/response.d.ts.map +0 -1
  162. package/output/app/define-server.negative-cases.d.ts +0 -40
  163. package/output/app/define-server.negative-cases.d.ts.map +0 -1
  164. package/output/app/define-server.negative-cases.js +0 -268
  165. package/output/app/define-server.test.d.ts +0 -2
  166. package/output/app/define-server.test.d.ts.map +0 -1
  167. package/output/app/define-server.test.js +0 -97
  168. package/output/app/entries.d.ts +0 -29
  169. package/output/app/entries.d.ts.map +0 -1
  170. package/output/app/entries.js +0 -64
  171. package/output/app/env.d.ts +0 -59
  172. package/output/app/env.d.ts.map +0 -1
  173. package/output/app/env.js +0 -66
  174. package/output/app/env.test.js +0 -124
  175. package/output/app/error-contract.test.d.ts +0 -2
  176. package/output/app/error-contract.test.d.ts.map +0 -1
  177. package/output/app/error-contract.test.js +0 -227
  178. package/output/app/errors.d.ts +0 -20
  179. package/output/app/errors.d.ts.map +0 -1
  180. package/output/app/errors.js +0 -51
  181. package/output/app/generate-openapi.test.d.ts +0 -2
  182. package/output/app/generate-openapi.test.d.ts.map +0 -1
  183. package/output/app/generate-openapi.test.js +0 -123
  184. package/output/app/lifecycle-logging.test.d.ts +0 -2
  185. package/output/app/lifecycle-logging.test.d.ts.map +0 -1
  186. package/output/app/lifecycle-logging.test.js +0 -155
  187. package/output/app/lifecycle.d.ts +0 -70
  188. package/output/app/lifecycle.d.ts.map +0 -1
  189. package/output/app/lifecycle.test.d.ts +0 -2
  190. package/output/app/lifecycle.test.d.ts.map +0 -1
  191. package/output/app/lifecycle.test.js +0 -152
  192. package/output/app/middleware/auth.d.ts +0 -71
  193. package/output/app/middleware/auth.d.ts.map +0 -1
  194. package/output/app/middleware/auth.js +0 -190
  195. package/output/app/middleware/context.d.ts +0 -13
  196. package/output/app/middleware/context.d.ts.map +0 -1
  197. package/output/app/middleware/context.js +0 -15
  198. package/output/app/middleware/cors.d.ts +0 -14
  199. package/output/app/middleware/cors.d.ts.map +0 -1
  200. package/output/app/middleware/cors.js +0 -30
  201. package/output/app/middleware/index.d.ts +0 -17
  202. package/output/app/middleware/index.d.ts.map +0 -1
  203. package/output/app/middleware/index.js +0 -16
  204. package/output/app/middleware/rate-limit.d.ts +0 -24
  205. package/output/app/middleware/rate-limit.d.ts.map +0 -1
  206. package/output/app/middleware/rate-limit.js +0 -46
  207. package/output/app/middleware-order.test.d.ts +0 -2
  208. package/output/app/middleware-order.test.d.ts.map +0 -1
  209. package/output/app/middleware-order.test.js +0 -148
  210. package/output/app/permission-operations.d.ts +0 -48
  211. package/output/app/permission-operations.d.ts.map +0 -1
  212. package/output/app/permission-operations.js +0 -77
  213. package/output/app/permission-operations.test.d.ts +0 -2
  214. package/output/app/permission-operations.test.d.ts.map +0 -1
  215. package/output/app/permission-operations.test.js +0 -72
  216. package/output/app/permission-registration.test.d.ts +0 -2
  217. package/output/app/permission-registration.test.d.ts.map +0 -1
  218. package/output/app/permission-registration.test.js +0 -138
  219. package/output/app/redis.d.ts.map +0 -1
  220. package/output/app/registered-operations.test.d.ts +0 -2
  221. package/output/app/registered-operations.test.d.ts.map +0 -1
  222. package/output/app/registered-operations.test.js +0 -57
  223. package/output/app/request-id.test.d.ts +0 -2
  224. package/output/app/request-id.test.d.ts.map +0 -1
  225. package/output/app/request-id.test.js +0 -130
  226. package/output/app/resources.test.d.ts +0 -2
  227. package/output/app/resources.test.d.ts.map +0 -1
  228. package/output/app/resources.test.js +0 -199
  229. package/output/app/shutdown.d.ts +0 -22
  230. package/output/app/shutdown.d.ts.map +0 -1
  231. package/output/app/shutdown.js +0 -30
  232. package/output/app/shutdown.test.d.ts +0 -2
  233. package/output/app/shutdown.test.d.ts.map +0 -1
  234. package/output/app/shutdown.test.js +0 -103
  235. package/output/app/signal.d.ts +0 -12
  236. package/output/app/signal.d.ts.map +0 -1
  237. package/output/app/smoke.test.d.ts +0 -2
  238. package/output/app/smoke.test.d.ts.map +0 -1
  239. package/output/app/smoke.test.js +0 -210
  240. package/output/app/test-support.d.ts +0 -21
  241. package/output/app/test-support.d.ts.map +0 -1
  242. package/output/app/test-support.js +0 -24
  243. package/output/app/type-augment.d.ts.map +0 -1
  244. package/output/app/types.d.ts +0 -228
  245. package/output/app/types.d.ts.map +0 -1
  246. package/output/context/index.d.ts +0 -6
  247. package/output/context/index.d.ts.map +0 -1
  248. package/output/context/index.js +0 -14
  249. package/output/rate-limiter/index.d.ts +0 -5
  250. package/output/rate-limiter/index.d.ts.map +0 -1
  251. package/output/rate-limiter/index.js +0 -4
  252. package/output/rate-limiter/memory-store.d.ts.map +0 -1
  253. package/output/rate-limiter/rate-limiter.d.ts.map +0 -1
  254. package/output/rate-limiter/redis-store.d.ts.map +0 -1
  255. package/output/rate-limiter/redis-store.test.d.ts.map +0 -1
  256. package/output/rate-limiter/types.d.ts.map +0 -1
  257. package/output/redis-cache/index.d.ts +0 -4
  258. package/output/redis-cache/index.d.ts.map +0 -1
  259. package/output/redis-cache/index.js +0 -1
  260. package/output/redis-cache/redis-cache.d.ts.map +0 -1
  261. package/output/redis-cache/redis-cache.test.d.ts +0 -2
  262. package/output/redis-cache/redis-cache.test.d.ts.map +0 -1
  263. package/output/schema/index.d.ts.map +0 -1
  264. /package/output/{app → core}/env.test.d.ts +0 -0
  265. /package/output/{rate-limiter → core/modules/auth-provider}/types.js +0 -0
  266. /package/output/{context → core/modules/context}/index.test.d.ts +0 -0
  267. /package/output/{context → core/modules/context}/index.test.js +0 -0
  268. /package/output/{app → core}/type-augment.js +0 -0
  269. /package/output/{app → core}/types.js +0 -0
  270. /package/output/{rate-limiter/rate-limiter.js → rate-limit/limiter.js} +0 -0
  271. /package/output/{rate-limiter → rate-limit}/memory-store.d.ts +0 -0
  272. /package/output/{rate-limiter → rate-limit}/memory-store.js +0 -0
  273. /package/output/{rate-limiter → rate-limit}/redis-store.d.ts +0 -0
  274. /package/output/{rate-limiter → rate-limit}/redis-store.js +0 -0
  275. /package/output/{rate-limiter → rate-limit}/redis-store.test.d.ts +0 -0
  276. /package/output/{redis-cache/redis-cache.js → redis/cache.js} +0 -0
@@ -1,21 +1,23 @@
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
  *
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
- client.destroy();
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';
@@ -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":"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"}
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.2",
3
+ "version": "4.0.0-beta.4",
4
4
  "author": "Alain",
5
5
  "license": "ISC",
6
6
  "description": "",
@@ -20,6 +20,15 @@
20
20
  "default": "./output/*/index.js"
21
21
  }
22
22
  },
23
+ "scripts": {
24
+ "test": "vitest run",
25
+ "test:ci": "vitest run",
26
+ "lint": "eslint && tsc --noEmit",
27
+ "typecheck": "tsc --noEmit",
28
+ "build": "rm -rf output && tsc -p tsconfig.json",
29
+ "prepublishOnly": "npm run build",
30
+ "dev": "tsc -p tsconfig.json --watch"
31
+ },
23
32
  "files": [
24
33
  "output"
25
34
  ],
@@ -27,18 +36,19 @@
27
36
  "@fastify/cookie": "^11",
28
37
  "@fastify/cors": "^11",
29
38
  "@fastify/swagger": "^9",
30
- "@scalar/fastify-api-reference": "^1",
39
+ "@taicode/auth-sdk": "^1.0.9",
31
40
  "dotenv": "^17.3.1",
32
41
  "fastify-type-provider-zod": "^6",
33
42
  "zod": "^4.3.6"
34
43
  },
35
44
  "peerDependencies": {
45
+ "@taicode/common-base": "workspace:^",
36
46
  "fastify": "^5.5.0",
37
- "redis": "^5.11.0",
38
- "@taicode/common-base": "^4.0.0-beta.2"
47
+ "redis": "^5.11.0"
39
48
  },
40
49
  "devDependencies": {
41
50
  "@eslint/js": "^9.39.3",
51
+ "@taicode/common-base": "workspace:^",
42
52
  "@types/node": "^22.19.13",
43
53
  "@yinxulai/eslint-plugin-peculiar": "^1.0.6",
44
54
  "eslint": "^9.39.3",
@@ -48,15 +58,6 @@
48
58
  "globals": "^16.5.0",
49
59
  "redis": "^5.11.0",
50
60
  "typescript-eslint": "^8.56.1",
51
- "vitest": "^3.2.4",
52
- "@taicode/common-base": "^4.0.0-beta.2"
53
- },
54
- "scripts": {
55
- "test": "vitest run",
56
- "test:ci": "vitest run",
57
- "lint": "eslint && tsc --noEmit",
58
- "typecheck": "tsc --noEmit",
59
- "build": "tsc -p tsconfig.json",
60
- "dev": "tsc -p tsconfig.json --watch"
61
+ "vitest": "^3.2.4"
61
62
  }
62
- }
63
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2024 TaicodeLabs
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -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,39 +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}) → R(只构造,不建连)
31
- * 3. config(ctx={env,log,resources}) → C(仅 start 路径;出 spec 路径不跑)
32
- * 4. services(ctx={log,disposer,resources,config}) → S,随后按声明序 init()(仅 start 路径)
33
- * 5. middlewares(ctx={app,log,services,config}) → 按数组序 register(app)
34
- * 6. routers(ctx={app,log,services}) → 注册路由
35
- * 7. ready / listen
36
- * ```
37
- */
38
- export declare function bootServer<R, C, S>(input: BootInput<R, C, S>): Promise<BootedServer<R, S>>;
39
- //# sourceMappingURL=boot.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"boot.d.ts","sourceRoot":"","sources":["../../source/app/boot.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACzC,OAAO,KAAK,EAAgC,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACtG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAE9C,qFAAqF;AACrF,eAAO,MAAM,gBAAgB,UAAU,CAAA;AACvC,eAAO,MAAM,kBAAkB,YAAY,CAAA;AAC3C,mBAAmB;AACnB,MAAM,MAAM,SAAS,GAAG,OAAO,gBAAgB,GAAG,OAAO,kBAAkB,CAAA;AAC3E,aAAa;AACb,eAAO,MAAM,YAAY,YAAY,CAAA;AAErC,MAAM,WAAW,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IACvB,GAAG,EAAE,SAAS,CAAA;IACd,KAAK,EAAE,SAAS,CAAA;IAChB,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC5D;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,EAAE,CAAC;IAChC,GAAG,EAAE,eAAe,CAAA;IACpB,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;IAC3B,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IACpB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAqCD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CA6GhG"}
@@ -1,140 +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 { disposeServices, initServiceUnits, MIDDLEWARES_LOG_STAGE, middlewareUnitName } 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}) → R(只构造,不建连)
52
- * 3. config(ctx={env,log,resources}) → C(仅 start 路径;出 spec 路径不跑)
53
- * 4. services(ctx={log,disposer,resources,config}) → S,随后按声明序 init()(仅 start 路径)
54
- * 5. middlewares(ctx={app,log,services,config}) → 按数组序 register(app)
55
- * 6. routers(ctx={app,log,services}) → 注册路由
56
- * 7. ready / listen
57
- * ```
58
- */
59
- export async function bootServer(input) {
60
- const { server, env, phase } = input;
61
- const isStart = phase === BOOT_PHASE_START;
62
- const service = server.app.service;
63
- // ── prepare ──────────────────────────────────────────────────────────────
64
- // ① createFastify(+ 内置 logger / requestId)
65
- const app = createFastify(env);
66
- const instance = app;
67
- const log = app.log;
68
- const disposer = new Disposer();
69
- const holder = createConfigHolder();
70
- // ② resources:只构造,不建连(出 spec 路径同样执行)
71
- // 资源错误分类器由各资源通过 `ctx.registerClassifyError` 各自注册:在调 `resources(ctx)` 前建局部收集器,
72
- // 返回后把注册结果按注册顺序合成单个分类器喂给 core。
73
- const classifiers = [];
74
- const resources = (await server.resources(createResourcesContext({
75
- env,
76
- log,
77
- registerClassifyError: (classifier) => {
78
- classifiers.push(classifier);
79
- },
80
- })));
81
- const resourcesView = liveResources(resources);
82
- // ③ core 装配(schema → cookie → response → openapi → 路由注册表)
83
- await registerCore(app, {
84
- identity: server.app,
85
- env,
86
- classifyResourceError: combineClassifiers(classifiers),
87
- readConfig: (key) => readConfigKey(requireConfig(holder), key),
88
- });
89
- // ── compose ──────────────────────────────────────────────────────────────
90
- // ① config(仅 start 路径;出 spec 路径不跑 → `ctx.config` 读到即抛 CONFIG_UNAVAILABLE)
91
- if (isStart) {
92
- holder.current = (await server.config(createConfigContext({ env, log, resources: resourcesView })));
93
- }
94
- // ② services(两个入口都执行;ctx 无 env、无 services)
95
- const services = server.services(createServiceContext({
96
- log,
97
- disposer,
98
- resources: resourcesView,
99
- holder,
100
- }));
101
- // ③ initLifecycleUnits(仅 start 路径)
102
- if (isStart) {
103
- await initServiceUnits({ service, log, services: services });
104
- }
105
- // ④ middlewares(两个入口都执行:出 spec 也照注册,保证 schema 一致)
106
- const middlewares = server.middlewares(createMiddlewareContext({ app: instance, log, services, holder }));
107
- for (const [index, unit] of middlewares.entries()) {
108
- await unit.register(instance);
109
- log.debug({ service, unit: middlewareUnitName(service, unit, index), stage: MIDDLEWARES_LOG_STAGE }, '[middleware] registered');
110
- }
111
- // ⑤ routers(两个入口都执行)
112
- await server.routers(createRouterContext({ app: instance, log, services }));
113
- // ── activate ─────────────────────────────────────────────────────────────
114
- const runShutdownFlow = async () => {
115
- if (input.shutdown) {
116
- await input.shutdown(createShutdownContext({
117
- app: instance,
118
- log,
119
- disposer,
120
- resources: resourcesView,
121
- holder,
122
- services,
123
- }));
124
- return;
125
- }
126
- await runShutdown({
127
- stopProducers: () => disposer.dispose(),
128
- disposeServices: () => disposeServices({ service, log, services: services }),
129
- }, log);
130
- };
131
- app.addHook('onClose', () => runShutdownFlow());
132
- // ⑥ ready(两个入口都执行)
133
- await app.ready();
134
- // ⑦ listen / signal(仅 start 路径)
135
- if (isStart && input.listen) {
136
- await app.listen({ port: resolvePort(env), host: DEFAULT_HOST });
137
- attachSignalHandlers(app, log);
138
- }
139
- return { app, resources: resourcesView, services, dispose: runShutdownFlow };
140
- }
@@ -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":""}