@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,16 +1,14 @@
1
- import './type-augment.js';
2
- export { defineServer, isServer, SERVER_BRAND, startServer, generateOpenApi } from './entries.js';
3
- export { loadEnvFiles, loadRuntimeEnvFiles, resolveConfigEnv, ENV_FILE_LAYERS, TEST_ENV_FILE_LAYER, DEFAULT_LOG_LEVEL } from './env.js';
4
- export type { ConfigEnv } from './env.js';
5
- export { UserError, SystemError } from './errors.js';
6
- export { createRedis, createCache, DEFAULT_REDIS_CACHE_TTL_SECONDS } from './redis.js';
7
- export { createCorsMiddleware, createContextMiddleware, createAuthMiddleware, createRateLimitMiddleware, defaultMiddlewares, defaultAuthSkip } from './middleware/index.js';
8
- export { REQUEST_ID_HEADER } from './core/request-id.js';
9
- export { DOC_ROUTE_PREFIX, DOC_SPEC_ROUTE } from './core/openapi.js';
10
- export { extractPermissionOperations } from './permission-operations.js';
11
- export type { AppIdentity, AppInstance, LoggerLike, MaybePromise, RedisHandle, Live, ResourcesView, AssertNoDependencies, ServicesShape, ErrorClassifier, ResourcesContext, ResourcesFactory, ConfigContext, ConfigFactory, ServiceUnit, ServiceContext, ServicesFactory, MiddlewareUnit, MiddlewareContext, MiddlewaresFactory, RouterContext, RoutersFactory, ServerConfig, Server, StartServerOptions, ShutdownContext, OpenApiDocument, } from './types.js';
12
- export type { CacheSetupParams } from './redis.js';
13
- export type { PermissionOperation } from './permission-operations.js';
14
- export type { CorsMiddlewareOptions, ContextMiddlewareOptions, AuthMiddlewareOptions, AuthSkip, AuthVerifyInput, AuthVerifyMetadata, AuthVerifyResult, AccountIntegrationConfig, RateLimitMiddlewareOptions } from './middleware/index.js';
15
- export type { AccessControl, RateLimitRule } from './type-augment.js';
1
+ import '../core/type-augment.js';
2
+ export { defineServer, startServer, generateOpenApi } from '../core/entries.js';
3
+ export { createTestServer } from '../core/test-support/test-server.js';
4
+ export { loadRuntimeEnvironment } from '../core/test-support/environment.js';
5
+ export { createCorsMiddleware } from '../cors/index.js';
6
+ export { createAuthMiddleware } from '../auth/index.js';
7
+ export { createRateLimitMiddleware } from '../rate-limit/index.js';
8
+ export { createRedis, createCache } from '../redis/index.js';
9
+ export type { AppInstance, ClientsContext, ClientsFactory, ClientsView, ConfigContext, LoggerLike, Middleware, MiddlewareContext, ResourcesContext, ResourcesView, RouterContext, ServiceContext, } from '../core/types.js';
10
+ export type { AuthVerifyInput, AuthVerifyMetadata, AuthVerifyResult } from '../auth/index.js';
11
+ export type { AuthMiddlewareOptions } from '../auth/index.js';
12
+ export type { AuthClient, AuthVerifyPayload, RegisterPermissionOperationsPayload, } from '../core/modules/auth-provider/index.js';
13
+ export type { RateLimitMiddlewareOptions } from '../rate-limit/index.js';
16
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/app/index.ts"],"names":[],"mappings":"AAEA,OAAO,mBAAmB,CAAA;AAG1B,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAGjG,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AACvI,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAGzC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAGpD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,+BAA+B,EAAE,MAAM,YAAY,CAAA;AAGtF,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAG3K,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAGpE,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAA;AAGxE,YAAY,EAEV,WAAW,EACX,WAAW,EACX,UAAU,EACV,YAAY,EACZ,WAAW,EAEX,IAAI,EACJ,aAAa,EACb,oBAAoB,EACpB,aAAa,EAEb,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,WAAW,EACX,cAAc,EACd,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,aAAa,EACb,cAAc,EAEd,YAAY,EACZ,MAAM,EACN,kBAAkB,EAClB,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAClD,YAAY,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AACrE,YAAY,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,QAAQ,EAAE,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAA;AAC1O,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/app/index.ts"],"names":[],"mappings":"AAsHA,OAAO,yBAAyB,CAAA;AAGhC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAiE/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAA;AAyBtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAA;AA6B5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAA;AAiBlE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAG5D,YAAY,EACV,WAAW,EACX,cAAc,EACd,cAAc,EACd,WAAW,EACX,aAAa,EACb,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,cAAc,GACf,MAAM,kBAAkB,CAAA;AAEzB,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAC7F,YAAY,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AAC7D,YAAY,EACV,UAAU,EACV,iBAAiB,EACjB,mCAAmC,GACpC,MAAM,wCAAwC,CAAA;AAC/C,YAAY,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAA"}
@@ -1,18 +1,256 @@
1
- // 提供 `request.user` / `request.token` / `request.ctx` 与 `routeOptions.config.accessControls`
2
- // 的统一类型增强。
3
- import './type-augment.js';
4
- // ── 入口 API(N1 §1 / N2 §2.8 / §2.10 / §2.11)───────────────────
5
- export { defineServer, isServer, SERVER_BRAND, startServer, generateOpenApi } from './entries.js';
6
- // ── 配置层(env 固定加载)────────────────────────────────────────
7
- export { loadEnvFiles, loadRuntimeEnvFiles, resolveConfigEnv, ENV_FILE_LAYERS, TEST_ENV_FILE_LAYER, DEFAULT_LOG_LEVEL } from './env.js';
8
- // ── 错误类型(N2 §2.12)──────────────────────────────────────────
9
- export { UserError, SystemError } from './errors.js';
10
- // ── 引导期 helper(`resources(ctx)` 里按需调用)─────────────────
11
- export { createRedis, createCache, DEFAULT_REDIS_CACHE_TTL_SECONDS } from './redis.js';
12
- // ── 标准中间件单元 ───────────────────────────────────────────────
13
- export { createCorsMiddleware, createContextMiddleware, createAuthMiddleware, createRateLimitMiddleware, defaultMiddlewares, defaultAuthSkip } from './middleware/index.js';
14
- // ── 公共路由 / header 常量 ───────────────────────────────────────
15
- export { REQUEST_ID_HEADER } from './core/request-id.js';
16
- export { DOC_ROUTE_PREFIX, DOC_SPEC_ROUTE } from './core/openapi.js';
17
- // ── 权限操作目录(框架内置;各仓用它替代自写实现)───────────────
18
- export { extractPermissionOperations } from './permission-operations.js';
1
+ // 服务入口 barrel(`@taicode/common-server/app`):**业务仓唯一需要 import 的路径**。
2
+ //
3
+ // 这里只有两样东西:**入口 API**(定义 / 启动 / 出文档 / 测试)与**可替换的能力工厂**
4
+ // (中间件、Redis)。框架自己决定得了一律不进这里——core 装配、`request.ctx`、系统路由、
5
+ // 响应信封全部在内部固定完成。
6
+ //
7
+ // ─────────────────────────────────────────────────────────────
8
+ // ## 三十秒上手:一个服务写两个文件(出 spec 是构建期的第三个)
9
+ // ─────────────────────────────────────────────────────────────
10
+ //
11
+ // ```ts
12
+ // // source/server.ts —— **只定义,不启动**:不建连、不 listen、不读库
13
+ // import { defineServer } from '@taicode/common-server/app'
14
+ //
15
+ // export const server = defineServer({
16
+ // app: { service: 'release', title: 'Release Service', version: packageJson.version },
17
+ //
18
+ // // 我们拥有的基础设施:**只读 env**,构造时不建连
19
+ // resources: ({ env, disposer }) => ({ database: createDatabase(env.DATABASE_URL) }),
20
+ //
21
+ // // 启动期的配置快照:可以读库,一次读完、进程内不再变
22
+ // config: ({ resources }) => loadConfig(resources),
23
+ //
24
+ // // 我们调用的外部服务:地址 / 凭证来自 config,故排在 config 之后
25
+ // clients: ({ config }) => ({ webhook: createWebhookClient(config.webhook) }),
26
+ //
27
+ // // 业务单元:**服务之间禁止互依**,要共享的东西放 clients
28
+ // services: ({ resources, config, clients }) => ({ user: createUserService({ resources, config, clients }) }),
29
+ //
30
+ // // 中间件:对象 **键即名字、键序即注册序**;`client` 是本仓自己的 `AuthClient` 实现
31
+ // middlewares: (ctx) => ({ cors: createCorsMiddleware(ctx), auth: createAuthMiddleware(ctx, { client }) }),
32
+ //
33
+ // // 业务路由:**只能拿 app / services / clients**(绕不过 service 直连数据层)
34
+ // routers: ({ app, services }) => {
35
+ // app.register(createUserRouter(services.user))
36
+ // },
37
+ // })
38
+ // ```
39
+ //
40
+ // ```ts
41
+ // // source/index.ts —— 启动(listen + 信号处理都在这里面)
42
+ // import { startServer } from '@taicode/common-server/app'
43
+ // import { server } from './server'
44
+ //
45
+ // await startServer(server)
46
+ // ```
47
+ //
48
+ // ```ts
49
+ // // build/openapi-gen.ts —— 出 spec(不连库、不建连、不要求配置有效)
50
+ // import { generateOpenApi } from '@taicode/common-server/app'
51
+ // import { server } from '../source/server'
52
+ //
53
+ // await writeFile('openapi.json', JSON.stringify(await generateOpenApi(server), null, 2))
54
+ // ```
55
+ //
56
+ // ─────────────────────────────────────────────────────────────
57
+ // ## 每个槽位能拿什么(拿不到的就是**故意**拿不到)
58
+ // ─────────────────────────────────────────────────────────────
59
+ //
60
+ // | 槽位 | ctx 里有 | 刻意没有 | 为什么 |
61
+ // |---|---|---|---|
62
+ // | `resources` | `env` / `log` / `disposer` / `registerClassifyError` | `config` / `services` / `app` | 资源只依赖 env,从结构上消灭「资源依赖配置」的循环 |
63
+ // | `config` | `env` / `log` / `disposer` / `resources` | `services` / `app` | 此时服务还没构造 |
64
+ // | `clients` | `log` / `disposer` / `resources` / `config` | `env` / `services` / `app` | 运行期不许回头读 env;客户端地址来自 config |
65
+ // | `services` | `log` / `disposer` / `resources` / `config` / `clients` | `env` / `services` / `app` | 服务层属运行期;禁 service 互依 |
66
+ // | `middlewares` | `app` / `log` / `disposer` / `services` / `config` / `clients` | `resources` / `env` | 中间件碰数据必须穿过 service |
67
+ // | `routers` | `app` / `log` / `disposer` / `services` / `clients` | `resources` / `env` / `config` | 路由只能穿过 service |
68
+ //
69
+ // 资源释放**在创建处登记**:`ctx.disposer.add(() => closeXxx())`,关闭时框架按阶段逆序 flush,
70
+ // 调用方不需要在任何地方再写一遍 close 逻辑。
71
+ //
72
+ // ─────────────────────────────────────────────────────────────
73
+ // ## 路由怎么写(`operationId` 必须有)
74
+ // ─────────────────────────────────────────────────────────────
75
+ //
76
+ // 每个路由都要给 schema,`operationId` / `summary` / `description` / `tags` 缺一即报错。
77
+ // `operationId` 不是文档装饰:**权限目录就是从它采集的**(启动时 `auth` 上报给 account),
78
+ // 没有它这个接口在权限系统里就是「未知操作」。
79
+ //
80
+ // ```ts
81
+ // app.post('/user', {
82
+ // schema: routerSchema({
83
+ // operationId: 'createUser',
84
+ // summary: '创建用户',
85
+ // description: '管理员创建用户,返回创建后的实体',
86
+ // tags: ['user'],
87
+ // body: z.object({ username: z.string() }),
88
+ // response: { 200: userSchema },
89
+ // }),
90
+ // config: {
91
+ // accessControls: ['IgnorePermission'], // 免登录写 'NoLoginRequired'
92
+ // rateLimit: { limit: 100, window: 60 }, // 可选:需装 rateLimit 中间件
93
+ // },
94
+ // }, handler)
95
+ // ```
96
+ //
97
+ // 返回体会被框架包成 `{ status, message, data }`,你只管返回业务数据;错误就
98
+ // `throw new UserError(...)` / `throw new SystemError(...)`(从 `@taicode/common-base` 引,
99
+ // 不是从本包)——状态码映射与信封由框架统一处理,**不要在路由里手拼响应体**。
100
+ //
101
+ // ─────────────────────────────────────────────────────────────
102
+ // ## 目录布局(见 `common/product/designs/create-server/design.md` §7.1)
103
+ // ─────────────────────────────────────────────────────────────
104
+ // ```
105
+ // source/
106
+ // ├── core/ 核心设计(锁定:不可替换、不可修改,**不对外导出装配**)
107
+ // │ └── test-support/ 测试支持(`createTestServer` / `loadRuntimeEnvironment`)
108
+ // ├── app/ 服务入口 barrel(本文件,不含实现)
109
+ // ├── auth/ 可选:鉴权中间件
110
+ // ├── cors/ 可选:CORS 中间件
111
+ // ├── rate-limit/ 可选:限流中间件 + 限流实现
112
+ // ├── redis/ 请求期 Redis / 缓存 helper
113
+ // └── redis-queue/ 可选:Redis 队列(含自己的 `test` 辅助)
114
+ // ```
115
+ //
116
+ // 测试工具**与正式工具同一个导出面**(不多开 `test-support` subpath):入口的测试同构体
117
+ // 就是入口,分两个出口只会让调用方多记一个路径。归属按「谁提供功能,谁提供配套测试工具」:
118
+ // 队列的测试辅助在 `redis-queue` 里,服务装配的测试入口在 `core/test-support/` 里。
119
+ import '../core/type-augment.js';
120
+ // ── 入口 API(定义 / 启动 / 出文档 / 测试)─────────────────────────
121
+ export { defineServer, startServer, generateOpenApi } from '../core/entries.js';
122
+ // 测试对象的**唯一**构造方式:同一份 `defineServer` 定义、同一套装配,不给槽位覆盖入口。
123
+ //
124
+ // env 加载、测试库结算、闸门、`process.env.DATABASE_URL` 改写都是它的**内部步骤**,
125
+ // 不单独导出。导出那一步就等于把「什么时候该跑闸门」交给调用方——顺序本身就是安全前提,
126
+ // 历史上有仓把环境闸门排在 env 加载之前(判的是空的 `ENV`),守卫于是变成装饰。
127
+ //
128
+ // ── 测试怎么写 ──────────────────────────────────────────────
129
+ //
130
+ // ```ts
131
+ // import { createTestServer } from '@taicode/common-server/app'
132
+ // import { server } from '../server'
133
+ //
134
+ // describe('UserRouter', () => {
135
+ // let testServer: Awaited<ReturnType<typeof createTestServer>>
136
+ // let db: PrismaClient
137
+ //
138
+ // beforeAll(async () => {
139
+ // testServer = await createTestServer(server) // 唯一构造方式
140
+ // db = testServer.resources.database // 生产用的那个客户端,不是新建的
141
+ // })
142
+ //
143
+ // afterAll(async () => {
144
+ // await testServer.app.close() // 七步关闭,与生产同一条路径
145
+ // })
146
+ //
147
+ // beforeEach(async () => {
148
+ // await db.user.deleteMany() // 真实数据库,不 mock
149
+ // })
150
+ //
151
+ // it('创建用户', async () => {
152
+ // const res = await testServer.app.inject({
153
+ // method: 'POST',
154
+ // url: '/user',
155
+ // payload: { username: 'alice' },
156
+ // })
157
+ //
158
+ // expect(res.statusCode).toBe(200)
159
+ // expect(await db.user.count()).toBe(1) // 断言落库,不只断言响应
160
+ // })
161
+ //
162
+ // it('service 行为', async () => {
163
+ // // 也可以完全不走 HTTP:直接调装配好的业务单元
164
+ // await testServer.services.user.create({ username: 'bob' })
165
+ // })
166
+ // })
167
+ // ```
168
+ //
169
+ // **三条规矩**:
170
+ // 1. **不要 mock 数据库 / Redis / 外部依赖**。它们由 `resources` / `clients` 真实构造,
171
+ // 测试连的是 `*_test` schema 上的真库。要替换某个外部服务,改组合(见下),不改装配。
172
+ // 2. **不要另造构造器**(`createTestApp` / `createTestDb` / `new PrismaClient()`)。
173
+ // 另造一份就等于测试里有第二套接线,绿了也不能说明生产是对的。
174
+ // 3. **只测一个模块**时组合定义,不要覆盖槽位:
175
+ // ```ts
176
+ // const onlyUser = defineServer({
177
+ // ...server,
178
+ // routers: ({ app, services }) => app.register(createUserRouter(services.user)),
179
+ // })
180
+ // const testServer = await createTestServer(onlyUser)
181
+ // ```
182
+ //
183
+ // 返回值 `TestServer` 就是测试需要的一切:`app`(原生 Fastify,用 `inject()`)/
184
+ // `env`(`env.DATABASE_URL` 就是本次实际连的测试连接串)/ `resources` / `config` /
185
+ // `clients` / `services` / `log`。没有 `close()` 之类同义包装——关闭就是 `app.close()`。
186
+ export { createTestServer } from '../core/test-support/test-server.js';
187
+ // ── 工具进程的 env 出口(**不在任何入口里跑**的进程)──────────────
188
+ //
189
+ // `prisma.config.ts` / `scripts/*.ts` / 被它们静态 import 的配置模块:ES 模块顶层求值早于
190
+ // 入口函数执行,所以「入口里加载 env」救不了这些文件。这个函数就是它们唯一的开口,只加载
191
+ // 运行期分层、不带任何测试闸门。
192
+ //
193
+ // **什么时候需要它**:你的文件**不是** `startServer` / `createTestServer` 启动的,
194
+ // 却要读 `process.env`(数据库连接串、Redis 地址、脚本参数)。
195
+ //
196
+ // ```ts
197
+ // // prisma.config.ts —— 必须在任何读取 env 的 import 之前调用
198
+ // import { loadRuntimeEnvironment } from '@taicode/common-server/app'
199
+ // loadRuntimeEnvironment()
200
+ //
201
+ // // scripts/seed.ts
202
+ // import { loadRuntimeEnvironment } from '@taicode/common-server/app'
203
+ // const env = loadRuntimeEnvironment()
204
+ // console.log(env.DATABASE_URL)
205
+ // ```
206
+ //
207
+ // **什么时候不要用它**:`source/server.ts` / `source/index.ts` / 测试文件。前者由
208
+ // `startServer` 负责,后者由 `createTestServer` 负责——在那些地方再调一次只是重复读 dotenv,
209
+ // 还会让人误以为 env 需要自己加载。
210
+ export { loadRuntimeEnvironment } from '../core/test-support/environment.js';
211
+ // ── 可替换的标准中间件工厂 ────────────────────────────────────────
212
+ //
213
+ // 只在**要改默认行为**时才出现;不写就是框架默认。三者都接收 `middlewares` 槽位的 `ctx`:
214
+ //
215
+ // ```ts
216
+ // middlewares: (ctx) => ({
217
+ // cors: createCorsMiddleware(ctx), // 允许的源来自 config 的 `cors` 键(请求期现读)
218
+ // auth: createAuthMiddleware(ctx, { client }), // client 必填:鉴权提供方实现
219
+ // rateLimit: createRateLimitMiddleware(ctx, { store }), // store 可选,缺省进程内 memory
220
+ // })
221
+ // ```
222
+ //
223
+ // `cors` / `rateLimit` 都**没有行为开关**,配置面只有输入参数:
224
+ // - `cors`:允许的源来自 `config.cors`(`{ enabled, origins }`);未配置 → 放行任意源并 warn 一次。
225
+ // - `rateLimit`:**限流规则写在路由上**,不在中间件里:
226
+ // ```ts
227
+ // app.get('/user', {
228
+ // schema: ...,
229
+ // config: { rateLimit: { limit: 100, window: 60, keys: ['ip'] } }, // 未声明的路由不空转
230
+ // }, handler)
231
+ // ```
232
+ // 需要 Redis 存储时,在 `services` 里构造 `RedisRateLimitStore` 再注入 `store`
233
+ // (中间件拿不到 `resources`,这是刻意的)。
234
+ //
235
+ // `auth` 的两件事由框架固定、**不可关闭**:① 跳过判定(`OPTIONS` / 未匹配路由 /
236
+ // 路由声明 `NoLoginRequired`);② 启动时从 `app.swagger()` 采集权限目录并上报。
237
+ // 你只需要实现 `AuthClient` 的 `verify` / `registerPermissionOperations` 两个方法。
238
+ export { createCorsMiddleware } from '../cors/index.js';
239
+ export { createAuthMiddleware } from '../auth/index.js';
240
+ export { createRateLimitMiddleware } from '../rate-limit/index.js';
241
+ // ── 请求期 Redis / 缓存 helper(资源包里自行构造)─────────────────
242
+ //
243
+ // 框架**不替你建 Redis**;在 `resources` 里按需构造,并在创建处登记释放:
244
+ //
245
+ // ```ts
246
+ // resources: ({ env, log, disposer }) => {
247
+ // const redis = createRedis(env, log) // 无 REDIS_URL → undefined
248
+ // if (redis) disposer.add(() => redis.dispose())
249
+ // return { redis, cache: createCache({ env, prefix: 'release', redis }) }
250
+ // }
251
+ // ```
252
+ //
253
+ // 两者都是**惰性包装**:构造时不建连、不 ping,首次真正使用才连——「出 spec 不连库 / 不连
254
+ // Redis」因此是结构性的,而不是靠调用方自觉。`createCache` 不传 `redis` 也能用(自建客户端,
255
+ // 或在没有 `REDIS_URL` 时退化成纯进程内一级缓存)。
256
+ export { createRedis, createCache } from '../redis/index.js';
@@ -0,0 +1,72 @@
1
+ import type { AuthClient, AuthVerifyPayload } from '../core/modules/auth-provider/index.js';
2
+ import type { Middleware, MiddlewareContext } from '../core/types.js';
3
+ /**
4
+ * 标准中间件单元 `auth`(可替换)。
5
+ *
6
+ * 本单元只做「**框架语义**」,不碰任何鉴权提供方的 HTTP:
7
+ *
8
+ * 1. 跳过判定(**固定**:`OPTIONS` → 未匹配路由 → 路由声明 `NoLoginRequired`);
9
+ * 2. 取凭证(`Authorization: Bearer` / `Authorization: apikey-*` / `cookieNames` 声明的 cookie);
10
+ * 3. 调 `client.verify`,把结果写回 `request.user` / `request.token`;
11
+ * 4. `onReady` 时调 `client.registerPermissionOperations`(**强制**,失败不致命)。
12
+ *
13
+ * 权限目录**只从 OpenAPI 文档派生**(`app.swagger()`):core 保证「所有路由必须声明 schema」
14
+ * (缺失直接启动失败),所以文档里出现什么,权限系统里就有什么,不存在两套来源漂移的可能。
15
+ *
16
+ * **提供方是业务注入的,且可替换**(本文件的 `client`,类型见
17
+ * `core/modules/auth-provider`):account 只是当前的主要实现,不是框架的预设——
18
+ * 自建 IAM、OIDC 网关、进程内静态校验都可以填进来。客户端构造需要地址、凭证、
19
+ * 协议与 HTTP 栈,这些只有业务侧才知道怎么配,框架不提供实现(设计 §5.2.2)。
20
+ *
21
+ * ## 为什么配置面只有两个字段
22
+ *
23
+ * `skip` / `mapError` / `registerPermissions` 曾经也是选项,现全部删除:
24
+ *
25
+ * - **跳过逻辑不可自定义**:放行是安全决策,一旦可按服务改写,「这条路由到底要不要
26
+ * 登录」就不再能从路由声明上读出来。约定只剩一条——**需要公开就声明
27
+ * `config.accessControls: ['NoLoginRequired']`**。
28
+ * - **错误映射不可自定义**:错误分类是响应契约的一部分(401/403 还是 500),让调用方
29
+ * 替换就等于允许各仓自造状态码。标准做法是提供方**自己抛** `UserError` /
30
+ * `SystemError`,框架原样透出;其它一切(网络 / 超时 / 非 JSON)统一
31
+ * `SystemError('EXTERNAL_SERVICE_ERROR')`。
32
+ * - **权限自注册不可关闭**:权限目录是 account 侧判权的前提,关掉它等于让本服务的
33
+ * 全部接口在权限系统里变成「未知操作」,只有坏处。
34
+ *
35
+ * 剩下两个字段都是**输入参数**(不是行为开关):提供方客户端 + 凭证在哪个 cookie 里。
36
+ */
37
+ /** `verify` 的入参:框架校验入参 + 服务名 */
38
+ export type AuthVerifyInput = AuthVerifyPayload;
39
+ /** 请求元信息 / 校验结果(形状定义在 auth-provider 契约里) */
40
+ export type { AuthVerifyMetadata, AuthVerifyResult } from '../core/modules/auth-provider/index.js';
41
+ /**
42
+ * `auth` 中间件的配置面:**只接受输入参数**,不提供行为开关。
43
+ *
44
+ * 标准行为(跳过判定 / 错误归类 / 权限自注册)由框架固定,不开放覆盖——
45
+ * 见文件头的「为什么配置面只有两个字段」。
46
+ */
47
+ export interface AuthMiddlewareOptions {
48
+ /**
49
+ * 鉴权提供方客户端(**必填**,业务服务实现;框架只定义契约,**允许任意实现替换**)。
50
+ *
51
+ * 由业务在自己的 `middlewares` 槽位里构造(可读 `ctx.config` / `ctx.services`),
52
+ * 职责:校验凭证 + 上报权限目录。account 只是其中一种实现——自带校验逻辑的服务
53
+ * (如 account 自己)实现同一个接口走进程内调用即可,不必绕 HTTP 回自己。
54
+ * 契约见 `core/modules/auth-provider`。
55
+ */
56
+ client: AuthClient;
57
+ /**
58
+ * 读取 token 的 cookie 名(**显式声明优先**)。
59
+ *
60
+ * 未传或传空数组时,请求期现读配置的 `server.cookieNames`(各仓的 cookie 名由运维改配置,
61
+ * 不能在注册期就定下);仍为空则回落 `['token']`。
62
+ */
63
+ cookieNames?: readonly string[];
64
+ }
65
+ /**
66
+ * 构造标准 `auth` 中间件。
67
+ *
68
+ * `client` **必填**(类型上)且必须有运行期实现:装了鉴权却没有校验实现是配置错误,
69
+ * 构造期直接抛错——不留「请求期才 fail-closed」的窗口,也不允许静默放行。
70
+ */
71
+ export declare function createAuthMiddleware<C = unknown, S = unknown>(ctx: MiddlewareContext<C, S>, options: AuthMiddlewareOptions): Middleware;
72
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/auth/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAA;AAG3F,OAAO,KAAK,EAA2B,UAAU,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAG9F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,gCAAgC;AAChC,MAAM,MAAM,eAAe,GAAG,iBAAiB,CAAA;AAE/C,4CAA4C;AAC5C,YAAY,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAA;AAElG;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;;;OAOG;IACH,MAAM,EAAE,UAAU,CAAA;IAClB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAChC;AAqID;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,qBAAqB,GAAG,UAAU,CAkEvI"}
@@ -0,0 +1,176 @@
1
+ import { catchIt, SystemError, UserError } from '@taicode/common-base';
2
+ import { readConfigKey } from '../core/boot/context.js';
3
+ import { readServerIdentity } from '../core/modules/identity/index.js';
4
+ import { extractPermissionOperations } from '../core/modules/permission-operations/index.js';
5
+ /** cookie 名缺省值(既未显式传入、配置也没给时使用) */
6
+ const DEFAULT_COOKIE_NAMES = ['token'];
7
+ /**
8
+ * 解析 cookie 名:显式参数 → 配置 `server.cookieNames` → 缺省值。
9
+ *
10
+ * **必须请求期调用**:出 spec 路径不跑 `config` 槽位,`ctx.config` 读到即抛 `CONFIG_UNAVAILABLE`。
11
+ */
12
+ function resolveCookieNames(config, declared) {
13
+ if (declared !== undefined && declared.length > 0) {
14
+ return declared;
15
+ }
16
+ const server = readConfigKey(config, 'server');
17
+ return Array.isArray(server?.cookieNames) && server.cookieNames.length > 0 ? server.cookieNames : DEFAULT_COOKIE_NAMES;
18
+ }
19
+ function extractAuth(request, cookieNames) {
20
+ const authorization = request.headers.authorization;
21
+ if (typeof authorization === 'string' && authorization.startsWith('Bearer ')) {
22
+ return { token: authorization.slice('Bearer '.length).trim() };
23
+ }
24
+ if (typeof authorization === 'string' && authorization.startsWith('apikey-')) {
25
+ return { apiKey: authorization.slice('apikey-'.length).trim() };
26
+ }
27
+ for (const name of cookieNames) {
28
+ const value = request.cookies?.[name];
29
+ if (typeof value === 'string' && value) {
30
+ return { token: value };
31
+ }
32
+ }
33
+ return {};
34
+ }
35
+ /**
36
+ * 固定跳过判定(**不可覆盖**):`OPTIONS` → 未匹配路由 → 路由声明 `NoLoginRequired`。
37
+ *
38
+ * 不按路径前缀特判文档出口:`GET /system/openapi` 自己声明 `NoLoginRequired`,
39
+ * **路由是唯一事实来源**——这样「哪些接口免登录」永远能从路由声明上读出来。
40
+ */
41
+ function shouldSkip(request) {
42
+ if (request.method === 'OPTIONS') {
43
+ return true;
44
+ }
45
+ if (!request.routeOptions?.url) {
46
+ return true;
47
+ }
48
+ return request.routeOptions.config?.accessControls?.includes('NoLoginRequired') === true;
49
+ }
50
+ /**
51
+ * 固定错误归类(**不可覆盖**):`UserError` / `SystemError` 原样透出,其余 → `EXTERNAL_SERVICE_ERROR`。
52
+ *
53
+ * 提供方若想表达「凭证无效 / 权限不足」,必须自己抛标准错误——这正是「按标准设计实现」的落点。
54
+ */
55
+ function toStandardAuthError(error) {
56
+ if (UserError.is(error) || SystemError.is(error)) {
57
+ return error;
58
+ }
59
+ return new SystemError('EXTERNAL_SERVICE_ERROR', { cause: error });
60
+ }
61
+ /**
62
+ * 从 OpenAPI 文档收集权限目录(**去重 + 稳定排序**)。
63
+ *
64
+ * 唯一来源就是 `app.swagger()`:不再同时维护一份 `onRoute` 注册表。两套来源必然漂移
65
+ * (`HEAD` / 前缀 / 插件路由只要有一处处理不同就对不上),而文档既能保证与对外契约一致,
66
+ * 也让「文档里有什么、权限系统里就有什么」成为可验证的事实。
67
+ *
68
+ * 同一 `operationId` 出现两次是路由声明问题(core 的 schema 守卫只保证字段存在,不保证唯一),
69
+ * 按首次出现保留并告警。稳定排序让目录内容不随注册顺序抖动,方便提供方 diff 与缓存。
70
+ */
71
+ function collectPermissionOperations(app, log) {
72
+ const swagger = app.swagger;
73
+ if (typeof swagger !== 'function') {
74
+ log.warn('[PermissionOperation][auth] 未启用 OpenAPI 文档,跳过权限目录自注册');
75
+ return [];
76
+ }
77
+ const collected = extractPermissionOperations(swagger.call(app));
78
+ const seen = new Set();
79
+ const operations = [];
80
+ const duplicates = [];
81
+ for (const operation of collected) {
82
+ if (seen.has(operation.operation)) {
83
+ duplicates.push(operation.operation);
84
+ continue;
85
+ }
86
+ seen.add(operation.operation);
87
+ operations.push(operation);
88
+ }
89
+ if (duplicates.length > 0) {
90
+ log.warn({ operations: duplicates }, '[PermissionOperation][auth] 检测到重复 operationId,已按首次声明去重(请修正路由声明)');
91
+ }
92
+ operations.sort((a, b) => (a.operation < b.operation ? -1 : a.operation > b.operation ? 1 : 0));
93
+ return operations;
94
+ }
95
+ /** 提交权限目录(失败**不致命**:只记日志,不中断启动) */
96
+ async function submitPermissionOperations(client, log, identity, operations) {
97
+ const { service, version } = identity;
98
+ if (!version) {
99
+ log.warn({ service }, '[PermissionOperation][auth] 身份块 version 为空:权限目录将无法按版本归组');
100
+ }
101
+ if (operations.length === 0) {
102
+ log.warn({ service, version }, '[PermissionOperation][auth] 未采集到任何带 operationId 的路由,跳过权限目录自注册(请检查路由 schema)');
103
+ return;
104
+ }
105
+ const result = await catchIt(client.registerPermissionOperations({ service, version, operations }));
106
+ if (result.isError()) {
107
+ log.error({ error: result.error, service, version, count: operations.length }, '[PermissionOperation][auth] 权限目录自注册失败(不阻断启动)');
108
+ return;
109
+ }
110
+ log.info({ service, version, count: operations.length }, '[PermissionOperation][auth] 权限目录自注册完成');
111
+ }
112
+ /**
113
+ * 构造标准 `auth` 中间件。
114
+ *
115
+ * `client` **必填**(类型上)且必须有运行期实现:装了鉴权却没有校验实现是配置错误,
116
+ * 构造期直接抛错——不留「请求期才 fail-closed」的窗口,也不允许静默放行。
117
+ */
118
+ export function createAuthMiddleware(ctx, options) {
119
+ const client = options?.client;
120
+ if (!client || typeof client.verify !== 'function') {
121
+ throw new Error('[auth] auth 中间件缺少校验实现:请通过 `createAuthMiddleware(ctx, { client })` 注入鉴权提供方');
122
+ }
123
+ return (app) => {
124
+ const identity = readServerIdentity(app);
125
+ if (!identity) {
126
+ throw new Error('[auth] 读不到身份块:`createAuthMiddleware` 必须挂在 `startServer` / `generateOpenApi` 的 app 上');
127
+ }
128
+ app.addHook('preValidation', async (request) => {
129
+ if (shouldSkip(request)) {
130
+ return;
131
+ }
132
+ // cookie 名**请求期**解析:显式参数优先,其次现读配置(配置可被运维改动)
133
+ const { token, apiKey } = extractAuth(request, resolveCookieNames(ctx.config, options.cookieNames));
134
+ if (!token && !apiKey) {
135
+ throw new UserError('INVALID_TOKEN', undefined, '缺少访问凭证');
136
+ }
137
+ const verifyInput = {
138
+ token,
139
+ apiKey,
140
+ service: identity.service,
141
+ // 权限目录同源、与 url 解耦:优先路由 `schema.operationId`,未声明时回落 url
142
+ operation: request.routeOptions?.schema?.operationId ?? request.routeOptions?.url,
143
+ resource: request.params,
144
+ accessControls: request.routeOptions?.config?.accessControls,
145
+ metadata: {
146
+ requestId: request.id,
147
+ method: request.method,
148
+ url: request.url,
149
+ ip: request.ip,
150
+ ips: request.ips,
151
+ userAgent: request.headers['user-agent'],
152
+ referrer: request.headers.referer,
153
+ },
154
+ };
155
+ try {
156
+ const result = await client.verify(verifyInput);
157
+ request.user = result.user;
158
+ request.token = result.token ?? token;
159
+ }
160
+ catch (error) {
161
+ throw toStandardAuthError(error);
162
+ }
163
+ });
164
+ // 权限目录自注册:**运行期无条件执行**(唯一前提是有 client,而 client 是必填的)。
165
+ //
166
+ // 时点必须在 `onReady`:`app.swagger()` 只有在 `ready()` 之后才可用(swagger 自身也挂
167
+ // `onReady`,且它在 core 阶段先注册,故本钩子执行时文档已就绪)。
168
+ //
169
+ // **为什么不需要区分入口**:`generateOpenApi` 根本不注册中间件(它只装路由与 schema
170
+ // 契约),所以本单元在出文档路径里压根不会被构造,不存在「构建期误写权限系统」的可能。
171
+ // 这也是「出文档不装配运行期能力」的直接收益:副作用随能力一起消失,不需要额外标记。
172
+ app.addHook('onReady', async () => {
173
+ await submitPermissionOperations(client, ctx.log, identity, collectPermissionOperations(app, ctx.log));
174
+ });
175
+ };
176
+ }
@@ -0,0 +1,64 @@
1
+ import type { ErrorClassifier } from './modules/response/index.js';
2
+ import type { ConfigEnv } from './env.js';
3
+ import type { AppIdentity } from './types.js';
4
+ import type { FastifyInstance } from 'fastify';
5
+ /**
6
+ * core 步骤 `createFastify`(`prepare`)。
7
+ *
8
+ * **总是**建 pino logger(level = `LOG_LEVEL`,默认 `info`) + 内置 `requestId`(入站 `x-request-id`
9
+ * 复用 / `randomUUID`,日志字段 `requestId`)。`trustProxy: true` 与四家现状一致。
10
+ *
11
+ * 固定装配,**不从包对外导出**:对外入口只有 `defineServer` / `startServer` / `generateOpenApi`。
12
+ */
13
+ export declare function createFastify(env: ConfigEnv): FastifyInstance;
14
+ /**
15
+ * 出文档用的**最小实例**(`generateOpenApi` 专用)。
16
+ *
17
+ * 没有 logger、没有 `requestId`、没有 `trustProxy`——这些只在**有请求**时才有意义,
18
+ * 而构建期一条请求都不会发。`logger: false` 下 `app.log` 仍是 `abstract-logging` 的
19
+ * 空实现,满足 `LoggerLike`,因此下游单元拿到的 `ctx.log` 调用不会炸,也不会产生输出。
20
+ */
21
+ export declare function createDocumentFastify(): FastifyInstance;
22
+ /** core 装配入参 */
23
+ export interface CoreRegistrationOptions {
24
+ /** 身份块(`service` / `title` / `version`):openapi + 内置单元从这里读 */
25
+ identity: AppIdentity;
26
+ env: ConfigEnv;
27
+ /** 资源错误分类(各资源经 `ctx.registerClassifyError` 注册;缺省 = 落 `UNKNOWN_ERROR`) */
28
+ classifyResourceError?: ErrorClassifier;
29
+ /** 取**已加载**配置中某个键的访问器(cookie domain 等**惰性**取值;不得在构造期调用) */
30
+ readConfig: (key: string) => unknown;
31
+ }
32
+ /**
33
+ * **schema 契约**(固定序,不可替换):`identity` → `schema`(zod compiler)→ 路由契约守卫。
34
+ *
35
+ * 两个入口都必须有它:
36
+ * - `startServer` 要让 zod 真的校验/序列化请求,并让「路由缺 `schema`」在注册处就失败;
37
+ * - `generateOpenApi` 要把 zod 转成 JSON Schema 出文档,也要同一个守卫——**文档就是权限目录**,
38
+ * 构建期放过的路由会在线上变成「接口永远判不过」。
39
+ *
40
+ * 单独成函数是为了让「运行期 core」与「文档 core」两条装配路径共用同一段契约,
41
+ * 而不用把整段运行期能力拖进出文档路径。
42
+ */
43
+ export declare function registerSchemaContract(app: FastifyInstance, options: Pick<CoreRegistrationOptions, 'identity'>): void;
44
+ /**
45
+ * **文档 core**(`generateOpenApi` 专用):schema 契约 + swagger。
46
+ *
47
+ * 只有这三件事与「把 zod schema 转成 OpenAPI 文档」有关:身份(`info.title` /
48
+ * `info.version`)、zod compiler(转换前得能读懂 zod)、守卫(不让文档缺条目)、swagger(转换器)。
49
+ * `requestContext` / `cookie` / `response` / `requestId` 全部**不装**——它们只影响
50
+ * 请求怎么被处理,而构建期一条请求都不会发。
51
+ */
52
+ export declare function registerDocumentCore(app: FastifyInstance, options: Pick<CoreRegistrationOptions, 'identity'>): Promise<void>;
53
+ /**
54
+ * core 装配(固定序,不可替换):`identity` → `schema`(+ 路由契约守卫)→ `requestContext`
55
+ * → `cookie` → `response` → `openapi` → `requestId` 回吐。
56
+ *
57
+ * 全部为框架内置能力,**不暴露选项面**;`request.ctx` 的装配也在这一步完成(`type-augment` 的
58
+ * 类型承诺因此总有运行期对应物)。**构造期不读配置**(`cookie` 的 domain 在请求期惰性读取),
59
+ * 故出 spec 路径(`readConfig` 不可用)不会触发。
60
+ *
61
+ * 这里**不建路由注册表**:权限目录直接由 `app.swagger()` 生成的文档派生(OpenAPI 是唯一来源)。
62
+ */
63
+ export declare function registerCore(app: FastifyInstance, options: CoreRegistrationOptions): Promise<void>;
64
+ //# sourceMappingURL=assemble.d.ts.map