@sixthsummit/ship-api 0.0.0-stage → 4.1.1

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 (556) hide show
  1. package/CHANGELOG.md +605 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +4 -0
  4. package/README.md +58 -2
  5. package/cli/commands/add.js +537 -0
  6. package/cli/commands/contract.js +2 -0
  7. package/cli/commands/create.js +250 -0
  8. package/cli/commands/dev.js +227 -0
  9. package/cli/commands/doctor.js +286 -0
  10. package/cli/commands/generate.js +937 -0
  11. package/cli/commands/graph.js +2 -0
  12. package/cli/commands/migrate-orm.js +1171 -0
  13. package/cli/commands/update.js +37 -0
  14. package/cli/ship-api.js +285 -0
  15. package/lib/app/auth/AuthProvider.d.ts +91 -0
  16. package/lib/app/auth/AuthProvider.d.ts.map +1 -0
  17. package/lib/app/auth/AuthProvider.js +13 -0
  18. package/lib/app/auth/AuthProvider.js.map +1 -0
  19. package/lib/app/auth/adapters/firebase.d.ts +79 -0
  20. package/lib/app/auth/adapters/firebase.d.ts.map +1 -0
  21. package/lib/app/auth/adapters/firebase.js +122 -0
  22. package/lib/app/auth/adapters/firebase.js.map +1 -0
  23. package/lib/app/auth/adapters/jwtCookie.d.ts +55 -0
  24. package/lib/app/auth/adapters/jwtCookie.d.ts.map +1 -0
  25. package/lib/app/auth/adapters/jwtCookie.js +120 -0
  26. package/lib/app/auth/adapters/jwtCookie.js.map +1 -0
  27. package/lib/app/auth/index.d.ts +8 -0
  28. package/lib/app/auth/index.d.ts.map +1 -0
  29. package/lib/app/auth/index.js +7 -0
  30. package/lib/app/auth/index.js.map +1 -0
  31. package/lib/app/auth/jwt/AuthFlow.d.ts +94 -0
  32. package/lib/app/auth/jwt/AuthFlow.d.ts.map +1 -0
  33. package/lib/app/auth/jwt/AuthFlow.js +127 -0
  34. package/lib/app/auth/jwt/AuthFlow.js.map +1 -0
  35. package/lib/app/auth/jwt/DrizzleRefreshTokenStore.d.ts +80 -0
  36. package/lib/app/auth/jwt/DrizzleRefreshTokenStore.d.ts.map +1 -0
  37. package/lib/app/auth/jwt/DrizzleRefreshTokenStore.js +134 -0
  38. package/lib/app/auth/jwt/DrizzleRefreshTokenStore.js.map +1 -0
  39. package/lib/app/auth/jwt/JwtSigner.d.ts +123 -0
  40. package/lib/app/auth/jwt/JwtSigner.d.ts.map +1 -0
  41. package/lib/app/auth/jwt/JwtSigner.js +118 -0
  42. package/lib/app/auth/jwt/JwtSigner.js.map +1 -0
  43. package/lib/app/auth/jwt/RefreshTokenStore.d.ts +97 -0
  44. package/lib/app/auth/jwt/RefreshTokenStore.d.ts.map +1 -0
  45. package/lib/app/auth/jwt/RefreshTokenStore.js +122 -0
  46. package/lib/app/auth/jwt/RefreshTokenStore.js.map +1 -0
  47. package/lib/app/auth/permissionDefinition.d.ts +20 -0
  48. package/lib/app/auth/permissionDefinition.d.ts.map +1 -0
  49. package/lib/app/auth/permissionDefinition.js +2 -0
  50. package/lib/app/auth/permissionDefinition.js.map +1 -0
  51. package/lib/app/context/RequestContext.d.ts +59 -0
  52. package/lib/app/context/RequestContext.d.ts.map +1 -0
  53. package/lib/app/context/RequestContext.js +25 -0
  54. package/lib/app/context/RequestContext.js.map +1 -0
  55. package/lib/app/db/QueryOptions.d.ts +82 -0
  56. package/lib/app/db/QueryOptions.d.ts.map +1 -0
  57. package/lib/app/db/QueryOptions.js +37 -0
  58. package/lib/app/db/QueryOptions.js.map +1 -0
  59. package/lib/app/db/baseFields.d.ts +60 -0
  60. package/lib/app/db/baseFields.d.ts.map +1 -0
  61. package/lib/app/db/baseFields.js +54 -0
  62. package/lib/app/db/baseFields.js.map +1 -0
  63. package/lib/app/db/buildWhere.d.ts +22 -0
  64. package/lib/app/db/buildWhere.d.ts.map +1 -0
  65. package/lib/app/db/buildWhere.js +75 -0
  66. package/lib/app/db/buildWhere.js.map +1 -0
  67. package/lib/app/db/client.d.ts +111 -0
  68. package/lib/app/db/client.d.ts.map +1 -0
  69. package/lib/app/db/client.js +99 -0
  70. package/lib/app/db/client.js.map +1 -0
  71. package/lib/app/db/tenantScoped.d.ts +59 -0
  72. package/lib/app/db/tenantScoped.d.ts.map +1 -0
  73. package/lib/app/db/tenantScoped.js +54 -0
  74. package/lib/app/db/tenantScoped.js.map +1 -0
  75. package/lib/app/db/transaction.d.ts +58 -0
  76. package/lib/app/db/transaction.d.ts.map +1 -0
  77. package/lib/app/db/transaction.js +106 -0
  78. package/lib/app/db/transaction.js.map +1 -0
  79. package/lib/app/health/HealthCheck.d.ts +121 -0
  80. package/lib/app/health/HealthCheck.d.ts.map +1 -0
  81. package/lib/app/health/HealthCheck.js +151 -0
  82. package/lib/app/health/HealthCheck.js.map +1 -0
  83. package/lib/app/health/redisHealthCheck.d.ts +14 -0
  84. package/lib/app/health/redisHealthCheck.d.ts.map +1 -0
  85. package/lib/app/health/redisHealthCheck.js +21 -0
  86. package/lib/app/health/redisHealthCheck.js.map +1 -0
  87. package/lib/app/lifecycle/Bootstrapper.d.ts +92 -0
  88. package/lib/app/lifecycle/Bootstrapper.d.ts.map +1 -0
  89. package/lib/app/lifecycle/Bootstrapper.js +99 -0
  90. package/lib/app/lifecycle/Bootstrapper.js.map +1 -0
  91. package/lib/app/registry/routes.d.ts +89 -0
  92. package/lib/app/registry/routes.d.ts.map +1 -0
  93. package/lib/app/registry/routes.js +72 -0
  94. package/lib/app/registry/routes.js.map +1 -0
  95. package/lib/app/services/DrizzleEntityService.d.ts +123 -0
  96. package/lib/app/services/DrizzleEntityService.d.ts.map +1 -0
  97. package/lib/app/services/DrizzleEntityService.js +342 -0
  98. package/lib/app/services/DrizzleEntityService.js.map +1 -0
  99. package/lib/app/services/RedisProvider.d.ts +52 -0
  100. package/lib/app/services/RedisProvider.d.ts.map +1 -0
  101. package/lib/app/services/RedisProvider.js +75 -0
  102. package/lib/app/services/RedisProvider.js.map +1 -0
  103. package/lib/app/services/cache/Cache.d.ts +70 -0
  104. package/lib/app/services/cache/Cache.d.ts.map +1 -0
  105. package/lib/app/services/cache/Cache.js +18 -0
  106. package/lib/app/services/cache/Cache.js.map +1 -0
  107. package/lib/app/services/cache/InMemoryCache.d.ts +35 -0
  108. package/lib/app/services/cache/InMemoryCache.d.ts.map +1 -0
  109. package/lib/app/services/cache/InMemoryCache.js +76 -0
  110. package/lib/app/services/cache/InMemoryCache.js.map +1 -0
  111. package/lib/app/services/cache/RedisCache.d.ts +99 -0
  112. package/lib/app/services/cache/RedisCache.d.ts.map +1 -0
  113. package/lib/app/services/cache/RedisCache.js +150 -0
  114. package/lib/app/services/cache/RedisCache.js.map +1 -0
  115. package/lib/app/services/cache/cached.d.ts +30 -0
  116. package/lib/app/services/cache/cached.d.ts.map +1 -0
  117. package/lib/app/services/cache/cached.js +38 -0
  118. package/lib/app/services/cache/cached.js.map +1 -0
  119. package/lib/app/services/cache/index.d.ts +5 -0
  120. package/lib/app/services/cache/index.d.ts.map +1 -0
  121. package/lib/app/services/cache/index.js +4 -0
  122. package/lib/app/services/cache/index.js.map +1 -0
  123. package/lib/app/services/cron/defineCron.d.ts +57 -0
  124. package/lib/app/services/cron/defineCron.d.ts.map +1 -0
  125. package/lib/app/services/cron/defineCron.js +15 -0
  126. package/lib/app/services/cron/defineCron.js.map +1 -0
  127. package/lib/app/services/cron/index.d.ts +2 -0
  128. package/lib/app/services/cron/index.d.ts.map +1 -0
  129. package/lib/app/services/cron/index.js +2 -0
  130. package/lib/app/services/cron/index.js.map +1 -0
  131. package/lib/app/services/hooks/LifecycleHooks.d.ts +61 -0
  132. package/lib/app/services/hooks/LifecycleHooks.d.ts.map +1 -0
  133. package/lib/app/services/hooks/LifecycleHooks.js +85 -0
  134. package/lib/app/services/hooks/LifecycleHooks.js.map +1 -0
  135. package/lib/app/services/jobs/JobsManager.d.ts +67 -0
  136. package/lib/app/services/jobs/JobsManager.d.ts.map +1 -0
  137. package/lib/app/services/jobs/JobsManager.js +121 -0
  138. package/lib/app/services/jobs/JobsManager.js.map +1 -0
  139. package/lib/app/services/jobs/bullBoard.d.ts +72 -0
  140. package/lib/app/services/jobs/bullBoard.d.ts.map +1 -0
  141. package/lib/app/services/jobs/bullBoard.js +96 -0
  142. package/lib/app/services/jobs/bullBoard.js.map +1 -0
  143. package/lib/app/services/jobs/defineJob.d.ts +81 -0
  144. package/lib/app/services/jobs/defineJob.d.ts.map +1 -0
  145. package/lib/app/services/jobs/defineJob.js +49 -0
  146. package/lib/app/services/jobs/defineJob.js.map +1 -0
  147. package/lib/app/services/jobs/index.d.ts +4 -0
  148. package/lib/app/services/jobs/index.d.ts.map +1 -0
  149. package/lib/app/services/jobs/index.js +4 -0
  150. package/lib/app/services/jobs/index.js.map +1 -0
  151. package/lib/app/services/rateLimit/InMemorySlidingWindowBackend.d.ts +23 -0
  152. package/lib/app/services/rateLimit/InMemorySlidingWindowBackend.d.ts.map +1 -0
  153. package/lib/app/services/rateLimit/InMemorySlidingWindowBackend.js +51 -0
  154. package/lib/app/services/rateLimit/InMemorySlidingWindowBackend.js.map +1 -0
  155. package/lib/app/services/rateLimit/RateLimitBackend.d.ts +41 -0
  156. package/lib/app/services/rateLimit/RateLimitBackend.d.ts.map +1 -0
  157. package/lib/app/services/rateLimit/RateLimitBackend.js +19 -0
  158. package/lib/app/services/rateLimit/RateLimitBackend.js.map +1 -0
  159. package/lib/app/services/rateLimit/RedisSlidingWindowBackend.d.ts +16 -0
  160. package/lib/app/services/rateLimit/RedisSlidingWindowBackend.d.ts.map +1 -0
  161. package/lib/app/services/rateLimit/RedisSlidingWindowBackend.js +80 -0
  162. package/lib/app/services/rateLimit/RedisSlidingWindowBackend.js.map +1 -0
  163. package/lib/app/services/rateLimit/index.d.ts +4 -0
  164. package/lib/app/services/rateLimit/index.d.ts.map +1 -0
  165. package/lib/app/services/rateLimit/index.js +3 -0
  166. package/lib/app/services/rateLimit/index.js.map +1 -0
  167. package/lib/app/services/storage/DiskStorageAdapter.d.ts +62 -0
  168. package/lib/app/services/storage/DiskStorageAdapter.d.ts.map +1 -0
  169. package/lib/app/services/storage/DiskStorageAdapter.js +295 -0
  170. package/lib/app/services/storage/DiskStorageAdapter.js.map +1 -0
  171. package/lib/app/services/storage/GCSStorageAdapter.d.ts +44 -0
  172. package/lib/app/services/storage/GCSStorageAdapter.d.ts.map +1 -0
  173. package/lib/app/services/storage/GCSStorageAdapter.js +133 -0
  174. package/lib/app/services/storage/GCSStorageAdapter.js.map +1 -0
  175. package/lib/app/services/storage/S3StorageAdapter.d.ts +57 -0
  176. package/lib/app/services/storage/S3StorageAdapter.d.ts.map +1 -0
  177. package/lib/app/services/storage/S3StorageAdapter.js +162 -0
  178. package/lib/app/services/storage/S3StorageAdapter.js.map +1 -0
  179. package/lib/app/services/storage/StorageService.d.ts +88 -0
  180. package/lib/app/services/storage/StorageService.d.ts.map +1 -0
  181. package/lib/app/services/storage/StorageService.js +18 -0
  182. package/lib/app/services/storage/StorageService.js.map +1 -0
  183. package/lib/app/services/storage/index.d.ts +5 -0
  184. package/lib/app/services/storage/index.d.ts.map +1 -0
  185. package/lib/app/services/storage/index.js +4 -0
  186. package/lib/app/services/storage/index.js.map +1 -0
  187. package/lib/app/utils/ContextValidators.d.ts +46 -0
  188. package/lib/app/utils/ContextValidators.d.ts.map +1 -0
  189. package/lib/app/utils/ContextValidators.js +81 -0
  190. package/lib/app/utils/ContextValidators.js.map +1 -0
  191. package/lib/app/utils/defineEnv.d.ts +80 -0
  192. package/lib/app/utils/defineEnv.d.ts.map +1 -0
  193. package/lib/app/utils/defineEnv.js +95 -0
  194. package/lib/app/utils/defineEnv.js.map +1 -0
  195. package/lib/client.d.ts +139 -0
  196. package/lib/client.d.ts.map +1 -0
  197. package/lib/client.js +98 -0
  198. package/lib/client.js.map +1 -0
  199. package/lib/contract/application.d.ts +3 -0
  200. package/lib/contract/application.d.ts.map +1 -0
  201. package/lib/contract/application.js +2 -0
  202. package/lib/contract/application.js.map +1 -0
  203. package/lib/contract/client.d.ts +3 -0
  204. package/lib/contract/client.d.ts.map +1 -0
  205. package/lib/contract/client.js +3 -0
  206. package/lib/contract/client.js.map +1 -0
  207. package/lib/contract/index.d.ts +3 -0
  208. package/lib/contract/index.d.ts.map +1 -0
  209. package/lib/contract/index.js +3 -0
  210. package/lib/contract/index.js.map +1 -0
  211. package/lib/contract/manifest.d.ts +3 -0
  212. package/lib/contract/manifest.d.ts.map +1 -0
  213. package/lib/contract/manifest.js +2 -0
  214. package/lib/contract/manifest.js.map +1 -0
  215. package/lib/contract/openapi.d.ts +3 -0
  216. package/lib/contract/openapi.d.ts.map +1 -0
  217. package/lib/contract/openapi.js +3 -0
  218. package/lib/contract/openapi.js.map +1 -0
  219. package/lib/contract/project.d.ts +3 -0
  220. package/lib/contract/project.d.ts.map +1 -0
  221. package/lib/contract/project.js +3 -0
  222. package/lib/contract/project.js.map +1 -0
  223. package/lib/contract/schema.d.ts +3 -0
  224. package/lib/contract/schema.d.ts.map +1 -0
  225. package/lib/contract/schema.js +3 -0
  226. package/lib/contract/schema.js.map +1 -0
  227. package/lib/drizzle/index.d.ts +3 -0
  228. package/lib/drizzle/index.d.ts.map +1 -0
  229. package/lib/drizzle/index.js +3 -0
  230. package/lib/drizzle/index.js.map +1 -0
  231. package/lib/hono/auth.d.ts +6 -0
  232. package/lib/hono/auth.d.ts.map +1 -0
  233. package/lib/hono/auth.js +54 -0
  234. package/lib/hono/auth.js.map +1 -0
  235. package/lib/hono/index.d.ts +4 -0
  236. package/lib/hono/index.d.ts.map +1 -0
  237. package/lib/hono/index.js +4 -0
  238. package/lib/hono/index.js.map +1 -0
  239. package/lib/http/app/createApp.d.ts +132 -0
  240. package/lib/http/app/createApp.d.ts.map +1 -0
  241. package/lib/http/app/createApp.js +215 -0
  242. package/lib/http/app/createApp.js.map +1 -0
  243. package/lib/http/app/devRoutes.d.ts +31 -0
  244. package/lib/http/app/devRoutes.d.ts.map +1 -0
  245. package/lib/http/app/devRoutes.js +145 -0
  246. package/lib/http/app/devRoutes.js.map +1 -0
  247. package/lib/http/app/errors.d.ts +45 -0
  248. package/lib/http/app/errors.d.ts.map +1 -0
  249. package/lib/http/app/errors.js +93 -0
  250. package/lib/http/app/errors.js.map +1 -0
  251. package/lib/http/app/health.d.ts +66 -0
  252. package/lib/http/app/health.d.ts.map +1 -0
  253. package/lib/http/app/health.js +104 -0
  254. package/lib/http/app/health.js.map +1 -0
  255. package/lib/http/errors/AppError.d.ts +10 -0
  256. package/lib/http/errors/AppError.d.ts.map +1 -0
  257. package/lib/http/errors/AppError.js +19 -0
  258. package/lib/http/errors/AppError.js.map +1 -0
  259. package/lib/http/errors/AuthenticationError.d.ts +8 -0
  260. package/lib/http/errors/AuthenticationError.d.ts.map +1 -0
  261. package/lib/http/errors/AuthenticationError.js +10 -0
  262. package/lib/http/errors/AuthenticationError.js.map +1 -0
  263. package/lib/http/errors/AuthorizationError.d.ts +8 -0
  264. package/lib/http/errors/AuthorizationError.d.ts.map +1 -0
  265. package/lib/http/errors/AuthorizationError.js +10 -0
  266. package/lib/http/errors/AuthorizationError.js.map +1 -0
  267. package/lib/http/errors/BadRequestError.d.ts +8 -0
  268. package/lib/http/errors/BadRequestError.d.ts.map +1 -0
  269. package/lib/http/errors/BadRequestError.js +10 -0
  270. package/lib/http/errors/BadRequestError.js.map +1 -0
  271. package/lib/http/errors/ConflictError.d.ts +8 -0
  272. package/lib/http/errors/ConflictError.d.ts.map +1 -0
  273. package/lib/http/errors/ConflictError.js +10 -0
  274. package/lib/http/errors/ConflictError.js.map +1 -0
  275. package/lib/http/errors/InternalServerError.d.ts +8 -0
  276. package/lib/http/errors/InternalServerError.d.ts.map +1 -0
  277. package/lib/http/errors/InternalServerError.js +10 -0
  278. package/lib/http/errors/InternalServerError.js.map +1 -0
  279. package/lib/http/errors/NotFoundError.d.ts +8 -0
  280. package/lib/http/errors/NotFoundError.d.ts.map +1 -0
  281. package/lib/http/errors/NotFoundError.js +10 -0
  282. package/lib/http/errors/NotFoundError.js.map +1 -0
  283. package/lib/http/errors/RateLimitError.d.ts +13 -0
  284. package/lib/http/errors/RateLimitError.d.ts.map +1 -0
  285. package/lib/http/errors/RateLimitError.js +16 -0
  286. package/lib/http/errors/RateLimitError.js.map +1 -0
  287. package/lib/http/errors/ServiceUnavailableError.d.ts +8 -0
  288. package/lib/http/errors/ServiceUnavailableError.d.ts.map +1 -0
  289. package/lib/http/errors/ServiceUnavailableError.js +10 -0
  290. package/lib/http/errors/ServiceUnavailableError.js.map +1 -0
  291. package/lib/http/errors/ValidationError.d.ts +9 -0
  292. package/lib/http/errors/ValidationError.d.ts.map +1 -0
  293. package/lib/http/errors/ValidationError.js +12 -0
  294. package/lib/http/errors/ValidationError.js.map +1 -0
  295. package/lib/http/errors/index.d.ts +11 -0
  296. package/lib/http/errors/index.d.ts.map +1 -0
  297. package/lib/http/errors/index.js +12 -0
  298. package/lib/http/errors/index.js.map +1 -0
  299. package/lib/http/middleware/apiKey.d.ts +9 -0
  300. package/lib/http/middleware/apiKey.d.ts.map +1 -0
  301. package/lib/http/middleware/apiKey.js +71 -0
  302. package/lib/http/middleware/apiKey.js.map +1 -0
  303. package/lib/http/middleware/csrf.d.ts +63 -0
  304. package/lib/http/middleware/csrf.d.ts.map +1 -0
  305. package/lib/http/middleware/csrf.js +169 -0
  306. package/lib/http/middleware/csrf.js.map +1 -0
  307. package/lib/http/middleware/httpLogger.d.ts +39 -0
  308. package/lib/http/middleware/httpLogger.d.ts.map +1 -0
  309. package/lib/http/middleware/httpLogger.js +118 -0
  310. package/lib/http/middleware/httpLogger.js.map +1 -0
  311. package/lib/http/middleware/idempotency.d.ts +48 -0
  312. package/lib/http/middleware/idempotency.d.ts.map +1 -0
  313. package/lib/http/middleware/idempotency.js +180 -0
  314. package/lib/http/middleware/idempotency.js.map +1 -0
  315. package/lib/http/middleware/rateLimit.d.ts +105 -0
  316. package/lib/http/middleware/rateLimit.d.ts.map +1 -0
  317. package/lib/http/middleware/rateLimit.js +84 -0
  318. package/lib/http/middleware/rateLimit.js.map +1 -0
  319. package/lib/http/middleware/requireAuth.d.ts +58 -0
  320. package/lib/http/middleware/requireAuth.d.ts.map +1 -0
  321. package/lib/http/middleware/requireAuth.js +63 -0
  322. package/lib/http/middleware/requireAuth.js.map +1 -0
  323. package/lib/http/middleware/requirePermission.d.ts +23 -0
  324. package/lib/http/middleware/requirePermission.d.ts.map +1 -0
  325. package/lib/http/middleware/requirePermission.js +50 -0
  326. package/lib/http/middleware/requirePermission.js.map +1 -0
  327. package/lib/http/middleware/resolveTenant.d.ts +41 -0
  328. package/lib/http/middleware/resolveTenant.d.ts.map +1 -0
  329. package/lib/http/middleware/resolveTenant.js +17 -0
  330. package/lib/http/middleware/resolveTenant.js.map +1 -0
  331. package/lib/http/streaming/sse.d.ts +31 -0
  332. package/lib/http/streaming/sse.d.ts.map +1 -0
  333. package/lib/http/streaming/sse.js +11 -0
  334. package/lib/http/streaming/sse.js.map +1 -0
  335. package/lib/http/streaming/streamLLM.d.ts +94 -0
  336. package/lib/http/streaming/streamLLM.d.ts.map +1 -0
  337. package/lib/http/streaming/streamLLM.js +94 -0
  338. package/lib/http/streaming/streamLLM.js.map +1 -0
  339. package/lib/http/utils/authCookies.d.ts +74 -0
  340. package/lib/http/utils/authCookies.d.ts.map +1 -0
  341. package/lib/http/utils/authCookies.js +102 -0
  342. package/lib/http/utils/authCookies.js.map +1 -0
  343. package/lib/http/utils/clientIp.d.ts +85 -0
  344. package/lib/http/utils/clientIp.d.ts.map +1 -0
  345. package/lib/http/utils/clientIp.js +249 -0
  346. package/lib/http/utils/clientIp.js.map +1 -0
  347. package/lib/http/utils/index.d.ts +4 -0
  348. package/lib/http/utils/index.d.ts.map +1 -0
  349. package/lib/http/utils/index.js +5 -0
  350. package/lib/http/utils/index.js.map +1 -0
  351. package/lib/http/utils/metaTags.d.ts +49 -0
  352. package/lib/http/utils/metaTags.d.ts.map +1 -0
  353. package/lib/http/utils/metaTags.js +32 -0
  354. package/lib/http/utils/metaTags.js.map +1 -0
  355. package/lib/http/utils/publicSuffix.d.ts +34 -0
  356. package/lib/http/utils/publicSuffix.d.ts.map +1 -0
  357. package/lib/http/utils/publicSuffix.js +276 -0
  358. package/lib/http/utils/publicSuffix.js.map +1 -0
  359. package/lib/http/utils/uploads.d.ts +92 -0
  360. package/lib/http/utils/uploads.d.ts.map +1 -0
  361. package/lib/http/utils/uploads.js +126 -0
  362. package/lib/http/utils/uploads.js.map +1 -0
  363. package/lib/http/utils/validate.d.ts +41 -0
  364. package/lib/http/utils/validate.d.ts.map +1 -0
  365. package/lib/http/utils/validate.js +55 -0
  366. package/lib/http/utils/validate.js.map +1 -0
  367. package/lib/http/utils/webhooks.d.ts +63 -0
  368. package/lib/http/utils/webhooks.d.ts.map +1 -0
  369. package/lib/http/utils/webhooks.js +133 -0
  370. package/lib/http/utils/webhooks.js.map +1 -0
  371. package/lib/http/ws/auth.d.ts +46 -0
  372. package/lib/http/ws/auth.d.ts.map +1 -0
  373. package/lib/http/ws/auth.js +123 -0
  374. package/lib/http/ws/auth.js.map +1 -0
  375. package/lib/index.d.ts +80 -0
  376. package/lib/index.d.ts.map +1 -0
  377. package/lib/index.js +61 -0
  378. package/lib/index.js.map +1 -0
  379. package/lib/kernel/index.d.ts +3 -0
  380. package/lib/kernel/index.d.ts.map +1 -0
  381. package/lib/kernel/index.js +3 -0
  382. package/lib/kernel/index.js.map +1 -0
  383. package/lib/libraries/.gitkeep +0 -0
  384. package/lib/libraries/ai/CHANGELOG.md +17 -0
  385. package/lib/libraries/ai/README.md +164 -0
  386. package/lib/libraries/ai/adapters/AnthropicAdapter.ts +382 -0
  387. package/lib/libraries/ai/adapters/LLMProvider.ts +76 -0
  388. package/lib/libraries/ai/adapters/OpenAIAdapter.ts +466 -0
  389. package/lib/libraries/ai/experimental/index.ts +20 -0
  390. package/lib/libraries/ai/index.ts +128 -0
  391. package/lib/libraries/ai/library.json +19 -0
  392. package/lib/libraries/ai/loop/agentLoop.ts +377 -0
  393. package/lib/libraries/ai/prompts/definePrompt.ts +0 -0
  394. package/lib/libraries/ai/rag/retrieveAndAnswer.ts +177 -0
  395. package/lib/libraries/ai/streaming/streamLLM.ts +94 -0
  396. package/lib/libraries/ai/structured/completeStructured.ts +143 -0
  397. package/lib/libraries/ai/tokens/Tokenizer.ts +216 -0
  398. package/lib/libraries/ai/tools/defineTool.ts +208 -0
  399. package/lib/libraries/ai/types.ts +260 -0
  400. package/lib/libraries/chunking/ChunkingService.ts +103 -0
  401. package/lib/libraries/chunking/README.md +104 -0
  402. package/lib/libraries/chunking/docs/api-reference.md +549 -0
  403. package/lib/libraries/chunking/docs/best-practices.md +321 -0
  404. package/lib/libraries/chunking/docs/code-organization.md +538 -0
  405. package/lib/libraries/chunking/docs/configuration.md +418 -0
  406. package/lib/libraries/chunking/docs/index.md +236 -0
  407. package/lib/libraries/chunking/docs/quick-start.md +298 -0
  408. package/lib/libraries/chunking/docs/strategies.md +407 -0
  409. package/lib/libraries/chunking/docs/summary.md +258 -0
  410. package/lib/libraries/chunking/docs/troubleshooting.md +527 -0
  411. package/lib/libraries/chunking/index.ts +17 -0
  412. package/lib/libraries/chunking/library.json +16 -0
  413. package/lib/libraries/chunking/strategies/ChunkingStrategy.ts +13 -0
  414. package/lib/libraries/chunking/strategies/FixedLengthChunkingStrategy.ts +88 -0
  415. package/lib/libraries/chunking/strategies/SemanticChunkingStrategy.ts +389 -0
  416. package/lib/libraries/chunking/strategies/SlidingWindowChunkingStrategy.ts +258 -0
  417. package/lib/libraries/chunking/types/index.ts +63 -0
  418. package/lib/libraries/email/EmailService.ts +591 -0
  419. package/lib/libraries/email/README.md +777 -0
  420. package/lib/libraries/email/TemplateRegistry.ts +148 -0
  421. package/lib/libraries/email/TemplateRenderer.ts +273 -0
  422. package/lib/libraries/email/index.ts +4 -0
  423. package/lib/libraries/email/initializeEmailService.ts +60 -0
  424. package/lib/libraries/email/library.json +12 -0
  425. package/lib/libraries/email/types/EmailAddress.ts +4 -0
  426. package/lib/libraries/email/types/EmailAttachment.ts +11 -0
  427. package/lib/libraries/email/types/EmailTag.ts +9 -0
  428. package/lib/libraries/email/types/EmailTemplate.ts +124 -0
  429. package/lib/libraries/email/types/SendBatchEmailsOptions.ts +9 -0
  430. package/lib/libraries/email/types/SendBatchEmailsResult.ts +9 -0
  431. package/lib/libraries/email/types/SendEmailOptions.ts +33 -0
  432. package/lib/libraries/email/types/SendEmailResult.ts +9 -0
  433. package/lib/libraries/email/types/index.ts +8 -0
  434. package/lib/libraries/weaviate/QueryBuilder.ts +292 -0
  435. package/lib/libraries/weaviate/README.md +284 -0
  436. package/lib/libraries/weaviate/Weaviate.ts +1419 -0
  437. package/lib/libraries/weaviate/WeaviateConfig.ts +268 -0
  438. package/lib/libraries/weaviate/docs/.gitkeep +1 -0
  439. package/lib/libraries/weaviate/docs/API_REFERENCE.md +1067 -0
  440. package/lib/libraries/weaviate/docs/CONFIGURATION.md +320 -0
  441. package/lib/libraries/weaviate/docs/ERROR_HANDLING.md +271 -0
  442. package/lib/libraries/weaviate/docs/MULTI_TENANCY.md +348 -0
  443. package/lib/libraries/weaviate/docs/PERFORMANCE.md +602 -0
  444. package/lib/libraries/weaviate/docs/PLUGIN_DEVELOPMENT.md +547 -0
  445. package/lib/libraries/weaviate/docs/QUICK_START.md +443 -0
  446. package/lib/libraries/weaviate/docs/README.md +269 -0
  447. package/lib/libraries/weaviate/docs/SCHEMA_GUIDE.md +630 -0
  448. package/lib/libraries/weaviate/docs/WEAVIATE_README.md +520 -0
  449. package/lib/libraries/weaviate/errors/WeaviateError.ts +92 -0
  450. package/lib/libraries/weaviate/errors/index.ts +1 -0
  451. package/lib/libraries/weaviate/index.ts +35 -0
  452. package/lib/libraries/weaviate/library.json +26 -0
  453. package/lib/libraries/weaviate/plugins/index.ts +2 -0
  454. package/lib/libraries/weaviate/schemas/SchemaRegistry.ts +284 -0
  455. package/lib/libraries/weaviate/schemas/index.ts +2 -0
  456. package/lib/libraries/weaviate/types/BM25SearchOptions.ts +9 -0
  457. package/lib/libraries/weaviate/types/ExtendedWeaviateClient.ts +7 -0
  458. package/lib/libraries/weaviate/types/HybridSearchOptions.ts +11 -0
  459. package/lib/libraries/weaviate/types/MultiTenancy.ts +81 -0
  460. package/lib/libraries/weaviate/types/Plugin.ts +17 -0
  461. package/lib/libraries/weaviate/types/SchemaConfig.ts +25 -0
  462. package/lib/libraries/weaviate/types/SearchMethod.ts +8 -0
  463. package/lib/libraries/weaviate/types/SearchOptions.ts +16 -0
  464. package/lib/libraries/weaviate/types/SearchRequest.ts +19 -0
  465. package/lib/libraries/weaviate/types/SearchResult.ts +16 -0
  466. package/lib/libraries/weaviate/types/SearchableField.ts +87 -0
  467. package/lib/libraries/weaviate/types/VectorIndexConfig.ts +19 -0
  468. package/lib/libraries/weaviate/types/VectorSearchOptions.ts +18 -0
  469. package/lib/libraries/weaviate/types/VectorizerConfig.ts +8 -0
  470. package/lib/libraries/weaviate/types/index.ts +29 -0
  471. package/lib/libraries/weaviate/utils/TenantContextManager.ts +94 -0
  472. package/lib/modules/accounts/index.ts +47 -0
  473. package/lib/modules/accounts/module.json +15 -0
  474. package/lib/modules/accounts/permissions.ts +33 -0
  475. package/lib/modules/accounts/routes.ts +200 -0
  476. package/lib/modules/accounts/schema.ts +219 -0
  477. package/lib/modules/accounts/services/AccountService.ts +44 -0
  478. package/lib/modules/accounts/validation/schemas.ts +70 -0
  479. package/lib/modules/oauth/adapters/GmailOAuthAdapter.ts +35 -0
  480. package/lib/modules/oauth/adapters/GoogleOAuthAdapter.ts +278 -0
  481. package/lib/modules/oauth/adapters/MicrosoftOAuthAdapter.ts +269 -0
  482. package/lib/modules/oauth/adapters/MockOAuthAdapter.ts +138 -0
  483. package/lib/modules/oauth/adapters/OAuthAdapter.ts +211 -0
  484. package/lib/modules/oauth/adapters/OAuthAdapterRegistry.ts +77 -0
  485. package/lib/modules/oauth/adapters/OutlookOAuthAdapter.ts +38 -0
  486. package/lib/modules/oauth/index.ts +79 -0
  487. package/lib/modules/oauth/module.json +23 -0
  488. package/lib/modules/oauth/permissions.ts +39 -0
  489. package/lib/modules/oauth/routes.ts +497 -0
  490. package/lib/modules/oauth/schema.ts +127 -0
  491. package/lib/modules/oauth/services/OAuthConnectionService.ts +147 -0
  492. package/lib/modules/oauth/state.ts +234 -0
  493. package/lib/modules/oauth/stateJtiCache.ts +85 -0
  494. package/lib/modules/oauth/verifyIdToken.ts +178 -0
  495. package/lib/modules/outbox/EventEmitter.ts +106 -0
  496. package/lib/modules/outbox/OutboxDrainer.ts +163 -0
  497. package/lib/modules/outbox/handlers/EventHandler.ts +115 -0
  498. package/lib/modules/outbox/index.ts +43 -0
  499. package/lib/modules/outbox/module.json +15 -0
  500. package/lib/modules/outbox/permissions.ts +36 -0
  501. package/lib/modules/outbox/routes.ts +219 -0
  502. package/lib/modules/outbox/schema.ts +207 -0
  503. package/lib/modules/outbox/services/OutboxEventService.ts +223 -0
  504. package/lib/observability/logger.d.ts +30 -0
  505. package/lib/observability/logger.d.ts.map +1 -0
  506. package/lib/observability/logger.js +110 -0
  507. package/lib/observability/logger.js.map +1 -0
  508. package/lib/observability/metrics.d.ts +3 -0
  509. package/lib/observability/metrics.d.ts.map +1 -0
  510. package/lib/observability/metrics.js +3 -0
  511. package/lib/observability/metrics.js.map +1 -0
  512. package/lib/observability/otel.d.ts +3 -0
  513. package/lib/observability/otel.d.ts.map +1 -0
  514. package/lib/observability/otel.js +3 -0
  515. package/lib/observability/otel.js.map +1 -0
  516. package/lib/observability/safeErrorFields.d.ts +14 -0
  517. package/lib/observability/safeErrorFields.d.ts.map +1 -0
  518. package/lib/observability/safeErrorFields.js +14 -0
  519. package/lib/observability/safeErrorFields.js.map +1 -0
  520. package/lib/observability/tracing.d.ts +3 -0
  521. package/lib/observability/tracing.d.ts.map +1 -0
  522. package/lib/observability/tracing.js +3 -0
  523. package/lib/observability/tracing.js.map +1 -0
  524. package/lib/package.json +4 -0
  525. package/lib/testing.d.ts +3 -0
  526. package/lib/testing.d.ts.map +1 -0
  527. package/lib/testing.js +3 -0
  528. package/lib/testing.js.map +1 -0
  529. package/package.json +193 -3
  530. package/templates/default/.claude/agents/qa-brief.md +106 -0
  531. package/templates/default/.claude/commands/sherpa-brief.md +23 -0
  532. package/templates/default/.cursor/rules/api.mdc +80 -0
  533. package/templates/default/.cursor/rules/commits.mdc +88 -0
  534. package/templates/default/.cursor/rules/security.mdc +92 -0
  535. package/templates/default/.cursor/rules/testing.mdc +123 -0
  536. package/templates/default/.cursor/rules/typescript.mdc +86 -0
  537. package/templates/default/.env.example +79 -0
  538. package/templates/default/.github/workflows/sherpa-brief.yml +180 -0
  539. package/templates/default/AGENTS.md +166 -0
  540. package/templates/default/CLAUDE.md +17 -0
  541. package/templates/default/README.md +97 -0
  542. package/templates/default/_gitignore +27 -0
  543. package/templates/default/docker-compose.yml +83 -0
  544. package/templates/default/drizzle.config.ts +34 -0
  545. package/templates/default/eslint.config.mjs +106 -0
  546. package/templates/default/package.json +57 -0
  547. package/templates/default/ship-api.config.ts +21 -0
  548. package/templates/default/src/client.ts +34 -0
  549. package/templates/default/src/config/modules.ts +23 -0
  550. package/templates/default/src/db/schema.ts +26 -0
  551. package/templates/default/src/environment.ts +81 -0
  552. package/templates/default/src/index.test.ts +53 -0
  553. package/templates/default/src/index.ts +11 -0
  554. package/templates/default/src/instrumentation.ts +13 -0
  555. package/templates/default/src/server.ts +90 -0
  556. package/templates/default/tsconfig.json +24 -0
@@ -0,0 +1,219 @@
1
+ import type {
2
+ AuthenticatedAccount,
3
+ AuthProvider,
4
+ } from "@sixthsummit/ship-api/app/auth/AuthProvider";
5
+ import type { AppEnv } from "@sixthsummit/ship-api/http/app/createApp";
6
+ import { createModuleApp } from "@sixthsummit/ship-api/http/app/createApp";
7
+ import { NotFoundError } from "@sixthsummit/ship-api/http/errors/NotFoundError";
8
+ import { requireAuth } from "@sixthsummit/ship-api/http/middleware/requireAuth";
9
+ import { requirePermission } from "@sixthsummit/ship-api/http/middleware/requirePermission";
10
+ import { validate } from "@sixthsummit/ship-api/http/utils/validate";
11
+ import type { Hono, Schema } from "hono";
12
+ import type { BlankSchema } from "hono/types";
13
+ import { z } from "zod";
14
+
15
+ import type { OutboxDrainer } from "./OutboxDrainer.js";
16
+ import { OUTBOX_PERMISSIONS } from "./permissions.js";
17
+ import type { OutboxEvent } from "./schema.js";
18
+ import type { OutboxEventService } from "./services/OutboxEventService.js";
19
+
20
+ /**
21
+ * v4 outbox routes — `defineOutboxRoutes(app, deps)`.
22
+ *
23
+ * Wires:
24
+ *
25
+ * GET /outbox list events (filterable)
26
+ * GET /outbox/stats per-status counts
27
+ * GET /outbox/count total count
28
+ * GET /outbox/:id single event
29
+ * POST /outbox/drain admin: trigger a drain pass
30
+ * POST /outbox/recover admin: reset stale processing
31
+ *
32
+ * Drain + recover are POST (mutating actions), gated by the admin
33
+ * `outbox:drain` / `outbox:recover` permissions. Drain returns the
34
+ * structured per-pass result so the operator sees what just
35
+ * happened. Read-only endpoints sit behind `outbox:read`.
36
+ *
37
+ * Drain by default does *one pass*. Pass `?untilEmpty=true` to flush
38
+ * the entire queue (catch-up after an outage). `batchSize` is also
39
+ * tunable via query param.
40
+ */
41
+
42
+ export interface OutboxRoutesDeps<TAccount extends AuthenticatedAccount = AuthenticatedAccount> {
43
+ service: OutboxEventService;
44
+ drainer: OutboxDrainer;
45
+ provider: AuthProvider<TAccount>;
46
+ }
47
+
48
+ const idParam = z.object({
49
+ id: z.string().uuid(),
50
+ });
51
+
52
+ const listQuery = z
53
+ .object({
54
+ search: z.string().min(1).optional(),
55
+ eventType: z.string().min(1).optional(),
56
+ status: z.enum(["pending", "processing", "published", "failed"]).optional(),
57
+ page: z.coerce.number().int().positive().default(1),
58
+ perPage: z.coerce.number().int().positive().max(200).default(50),
59
+ })
60
+ .strict();
61
+
62
+ const drainBody = z
63
+ .object({
64
+ batchSize: z.number().int().positive().max(500).optional(),
65
+ untilEmpty: z.boolean().optional(),
66
+ })
67
+ .strict();
68
+
69
+ const recoverBody = z
70
+ .object({
71
+ /** Threshold in ms; rows in 'processing' older than this get reset. */
72
+ staleThresholdMs: z.number().int().positive().optional(),
73
+ })
74
+ .strict();
75
+
76
+ /**
77
+ * ⚠️ FOOT-GUN: do NOT thread one shared `app` through several modules'
78
+ * `defineXxxRoutes` calls — it accumulates one giant Hono route-type and
79
+ * detonates `tsc` (TS2589) at scale. Prefer {@link buildOutboxApp} mounted via
80
+ * `root.route("/", buildOutboxApp(deps))`. This raw form is kept for advanced
81
+ * composition.
82
+ */
83
+ // Generic over Hono's schema param `S` so an already-chained app keeps its
84
+ // previously registered route types — `Hono<AppEnv>` here would widen them
85
+ // away. See defineAccountsRoutes for the full rationale.
86
+ export function defineOutboxRoutes<
87
+ TAccount extends AuthenticatedAccount = AuthenticatedAccount,
88
+ S extends Schema = BlankSchema,
89
+ >(app: Hono<AppEnv, S>, deps: OutboxRoutesDeps<TAccount>) {
90
+ const auth = requireAuth({ provider: deps.provider });
91
+
92
+ return app
93
+ .get(
94
+ "/outbox",
95
+ auth,
96
+ requirePermission(OUTBOX_PERMISSIONS.outboxRead),
97
+ validate("query", listQuery),
98
+ async (c) => {
99
+ const q = c.req.valid("query");
100
+ const offset = (q.page - 1) * q.perPage;
101
+ const where: Record<string, unknown> = {};
102
+ if (q.eventType) where.eventType = q.eventType;
103
+ if (q.status) where.status = q.status;
104
+ const result = await deps.service.list({
105
+ search: q.search,
106
+ where: Object.keys(where).length > 0 ? where : undefined,
107
+ limit: q.perPage,
108
+ offset,
109
+ });
110
+ const sanitized = (result.rows as OutboxEvent[]).map(summarizeEvent);
111
+ return c.json(
112
+ {
113
+ rows: sanitized,
114
+ total: result.total,
115
+ page: q.page,
116
+ perPage: q.perPage,
117
+ },
118
+ 200,
119
+ );
120
+ },
121
+ )
122
+ .get("/outbox/stats", auth, requirePermission(OUTBOX_PERMISSIONS.outboxRead), async (c) => {
123
+ const stats = await deps.service.getStatistics();
124
+ return c.json(stats, 200);
125
+ })
126
+ .get(
127
+ "/outbox/count",
128
+ auth,
129
+ requirePermission(OUTBOX_PERMISSIONS.outboxRead),
130
+ validate("query", listQuery),
131
+ async (c) => {
132
+ const q = c.req.valid("query");
133
+ const where: Record<string, unknown> = {};
134
+ if (q.eventType) where.eventType = q.eventType;
135
+ if (q.status) where.status = q.status;
136
+ const count = await deps.service.count({
137
+ where: Object.keys(where).length > 0 ? where : undefined,
138
+ });
139
+ return c.json({ count }, 200);
140
+ },
141
+ )
142
+ .get(
143
+ "/outbox/:id",
144
+ auth,
145
+ requirePermission(OUTBOX_PERMISSIONS.outboxRead),
146
+ validate("param", idParam),
147
+ async (c) => {
148
+ const { id } = c.req.valid("param");
149
+ const event = (await deps.service.get(id)) as OutboxEvent | null;
150
+ if (!event) throw new NotFoundError("Outbox event not found");
151
+ return c.json(summarizeEvent(event), 200);
152
+ },
153
+ )
154
+ .post(
155
+ "/outbox/drain",
156
+ auth,
157
+ requirePermission(OUTBOX_PERMISSIONS.outboxDrain),
158
+ validate("json", drainBody),
159
+ async (c) => {
160
+ const body = c.req.valid("json");
161
+ const result = body.untilEmpty
162
+ ? await deps.drainer.runUntilEmpty({ batchSize: body.batchSize })
163
+ : await deps.drainer.runOnce({ batchSize: body.batchSize });
164
+ return c.json(result, 200);
165
+ },
166
+ )
167
+ .post(
168
+ "/outbox/recover",
169
+ auth,
170
+ requirePermission(OUTBOX_PERMISSIONS.outboxRecover),
171
+ validate("json", recoverBody),
172
+ async (c) => {
173
+ const body = c.req.valid("json");
174
+ const result = await deps.service.recoverStaleProcessing(body.staleThresholdMs);
175
+ return c.json(result, 200);
176
+ },
177
+ );
178
+ }
179
+
180
+ /**
181
+ * Build the outbox module as its own sub-app, ready to mount on the root with
182
+ * `root.route("/", buildOutboxApp(deps))`. Canonical wiring — see
183
+ * {@link buildAccountsApp} for the rationale. Routes are tagged under the
184
+ * `outbox` module in `/dev/routes` / `list_routes`.
185
+ */
186
+ export function buildOutboxApp<TAccount extends AuthenticatedAccount = AuthenticatedAccount>(
187
+ deps: OutboxRoutesDeps<TAccount>,
188
+ ) {
189
+ return defineOutboxRoutes(createModuleApp("outbox"), deps);
190
+ }
191
+
192
+ /**
193
+ * Strip the heavy `payload` from list-view responses so admin UIs
194
+ * don't transfer megabytes of event bodies just to render a status
195
+ * dashboard. Single-event endpoint returns the full row including
196
+ * payload.
197
+ */
198
+ function summarizeEvent(event: OutboxEvent) {
199
+ return {
200
+ id: event.id,
201
+ eventId: event.eventId,
202
+ eventType: event.eventType,
203
+ eventVersion: event.eventVersion,
204
+ aggregateType: event.aggregateType,
205
+ aggregateId: event.aggregateId,
206
+ ownerUserId: event.ownerUserId,
207
+ tenantId: event.tenantId,
208
+ correlationId: event.correlationId,
209
+ status: event.status,
210
+ publishAttempts: event.publishAttempts,
211
+ nextAttemptAt: event.nextAttemptAt,
212
+ publishedAt: event.publishedAt,
213
+ lastError: event.lastError,
214
+ occurredAt: event.occurredAt,
215
+ createdAt: event.createdAt,
216
+ updatedAt: event.updatedAt,
217
+ payload: event.payload,
218
+ };
219
+ }
@@ -0,0 +1,207 @@
1
+ import { baseFields } from "@sixthsummit/ship-api/app/db/baseFields";
2
+ import { sql } from "drizzle-orm";
3
+ import {
4
+ index,
5
+ integer,
6
+ jsonb,
7
+ pgEnum,
8
+ pgTable,
9
+ text,
10
+ timestamp,
11
+ uuid,
12
+ varchar,
13
+ } from "drizzle-orm/pg-core";
14
+
15
+ /**
16
+ * v4 transactional outbox table — ports v3's `OutboxEvent` TypeORM
17
+ * entity. Implements the outbox pattern: domain operations write
18
+ * events to this table inside the same transaction as the business
19
+ * data; a separate worker drains pending rows and publishes to
20
+ * downstream systems (queue, webhook, log, etc.) with at-least-once
21
+ * delivery and exponential backoff on failure.
22
+ *
23
+ * Key v4 differences from v3:
24
+ *
25
+ * - `id` switches from `bigint identity` to `uuid` for consistency
26
+ * with the rest of the v4 framework. FIFO ordering uses the
27
+ * `(created_at, event_id)` index instead of monotonic bigint
28
+ * incrementing.
29
+ *
30
+ * - `status` becomes a Postgres `pgEnum` instead of a raw text
31
+ * column. Type-checked at the SQL boundary; cheaper indexes than
32
+ * text comparison.
33
+ *
34
+ * - Partial indexes preserved for the hot drain queries — the
35
+ * `pending` index covers only rows that haven't been published,
36
+ * and the `processing` index covers only in-flight rows. Both
37
+ * are tiny relative to the full table and stay fast as the
38
+ * published-events table grows.
39
+ *
40
+ * - Audit columns (`createdAt` / `updatedAt` / `deletedAt` /
41
+ * `createdBy` / `updatedBy`) standardized via `baseFields`. v3
42
+ * had createdAt + updatedAt only; v4 uniformity is worth the
43
+ * extra (nullable) columns.
44
+ *
45
+ * The v3 `Job` entity + JobController + job-queue subsystem are
46
+ * intentionally NOT ported. v4's BullMQ machinery (`defineJob` +
47
+ * `JobRegistry` from alpha-2 step 12) is the canonical job substrate;
48
+ * porting v3's competing TypeORM-backed queue would create two
49
+ * conflicting source-of-truth queues. Migration guide: move each
50
+ * v3 Job processor to a `defineJob({ queue, name, processor })` call.
51
+ */
52
+
53
+ export const outboxEventStatus = pgEnum("outbox_event_status", [
54
+ "pending",
55
+ "processing",
56
+ "published",
57
+ "failed",
58
+ ]);
59
+
60
+ export const outboxEvents = pgTable(
61
+ "outbox_events",
62
+ {
63
+ id: uuid("id").primaryKey().defaultRandom(),
64
+
65
+ /**
66
+ * External identifier for the event — the value downstream
67
+ * consumers see. Distinct from `id` to allow re-publishing the
68
+ * same logical event under a new row when a permanent failure
69
+ * gets manually resolved.
70
+ */
71
+ eventId: uuid("event_id").notNull().defaultRandom(),
72
+
73
+ /**
74
+ * Domain event type ("account.created", "post.published", ...).
75
+ * Matches the consumer's `EventType` discriminated union.
76
+ */
77
+ eventType: text("event_type").notNull(),
78
+
79
+ /** Schema version for the payload. Bump when the payload shape changes. */
80
+ eventVersion: integer("event_version").notNull().default(1),
81
+
82
+ /** When the domain operation occurred (may differ from `createdAt`). */
83
+ occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull().default(sql`now()`),
84
+
85
+ /** Aggregate type (entity-class identifier) the event belongs to. */
86
+ aggregateType: text("aggregate_type"),
87
+
88
+ /** Aggregate id within `aggregateType`. UUID-shaped string for v4. */
89
+ aggregateId: uuid("aggregate_id"),
90
+
91
+ /** Owner of the aggregate (typically `accounts.id`). */
92
+ ownerUserId: uuid("owner_user_id"),
93
+
94
+ /**
95
+ * Multi-tenant scoping (A2-1: `uuid` to match `RequestContext.tenantId` and
96
+ * every other v4 id). Nullable — the outbox also carries system/global
97
+ * events with no tenant. No FK: the outbox module doesn't own a `tenants`
98
+ * table, and system events legitimately have a null tenant.
99
+ */
100
+ tenantId: uuid("tenant_id"),
101
+
102
+ /**
103
+ * Stable key for upstream-deduplication. Set by the producer when
104
+ * the same logical event might be enqueued twice (idempotency
105
+ * boundary).
106
+ */
107
+ dedupeKey: text("dedupe_key"),
108
+
109
+ /** Trace correlation id — flows through to downstream telemetry. */
110
+ correlationId: varchar("correlation_id", { length: 255 }),
111
+
112
+ /** Event payload. Consumer-shaped JSON. */
113
+ payload: jsonb("payload").$type<Record<string, unknown>>().notNull(),
114
+
115
+ /** Lifecycle state — see the `outboxEventStatus` enum. */
116
+ status: outboxEventStatus("status").notNull().default("pending"),
117
+
118
+ /** Number of publish attempts that have been made (incl. failed). */
119
+ publishAttempts: integer("publish_attempts").notNull().default(0),
120
+
121
+ /** When the next retry should fire. Null when not scheduled. */
122
+ nextAttemptAt: timestamp("next_attempt_at", { withTimezone: true }),
123
+
124
+ /** When the publish succeeded. Null until then. */
125
+ publishedAt: timestamp("published_at", { withTimezone: true }),
126
+
127
+ /** Last failure message (truncated to a reasonable length by callers). */
128
+ lastError: text("last_error"),
129
+
130
+ /** Maximum number of attempts before giving up and marking failed. */
131
+ maxRetries: integer("max_retries").notNull().default(10),
132
+
133
+ /** When the most recent attempt started. */
134
+ startedAt: timestamp("started_at", { withTimezone: true }),
135
+
136
+ ...baseFields,
137
+ },
138
+ (table) => [
139
+ // Hot drain query: rows pending or processing that haven't been
140
+ // published yet, ordered by next-attempt → created. Partial index
141
+ // stays small relative to the full table even after years of
142
+ // published events accumulate.
143
+ index("outbox_events_pending_ix")
144
+ .on(table.nextAttemptAt, table.createdAt)
145
+ .where(sql`status IN ('pending','processing') AND published_at IS NULL`),
146
+ index("outbox_events_type_ix").on(table.eventType, table.createdAt),
147
+ index("outbox_events_owner_ix").on(table.ownerUserId),
148
+ index("outbox_events_status_ix").on(table.status),
149
+ // Stale-processing recovery: only rows in processing state. Tiny
150
+ // index — most events don't get stuck in processing.
151
+ index("outbox_events_processing_ix")
152
+ .on(table.startedAt)
153
+ .where(sql`status = 'processing'`),
154
+ // Aggregate-scoped lookups (e.g., "all events for this account").
155
+ index("outbox_events_aggregate_ix").on(table.aggregateType, table.aggregateId),
156
+ ],
157
+ );
158
+
159
+ export type OutboxEvent = typeof outboxEvents.$inferSelect;
160
+ export type NewOutboxEvent = typeof outboxEvents.$inferInsert;
161
+ export type OutboxEventStatus = (typeof outboxEventStatus.enumValues)[number];
162
+
163
+ // ─── Status helpers (pure functions) ──────────────────────────────────
164
+ //
165
+ // v3 had these as instance methods on the TypeORM entity class. v4
166
+ // rows are plain objects; status logic moves to module-level pure
167
+ // functions the service / drain worker calls on the row.
168
+
169
+ /**
170
+ * True when a pending event is ready to publish: status is `pending`,
171
+ * no publishedAt set, and (if scheduled) the next-attempt time has
172
+ * passed. The drain query also filters by index — this helper is for
173
+ * service-layer assertions and tests.
174
+ */
175
+ export function isReadyForPublish(
176
+ event: Pick<OutboxEvent, "status" | "publishedAt" | "nextAttemptAt">,
177
+ now: Date = new Date(),
178
+ ): boolean {
179
+ if (event.status !== "pending") return false;
180
+ if (event.publishedAt) return false;
181
+ if (event.nextAttemptAt && event.nextAttemptAt > now) return false;
182
+ return true;
183
+ }
184
+
185
+ export function hasExhaustedRetries(
186
+ event: Pick<OutboxEvent, "publishAttempts" | "maxRetries">,
187
+ ): boolean {
188
+ return event.publishAttempts >= event.maxRetries;
189
+ }
190
+
191
+ /**
192
+ * Compute the next-attempt time using exponential backoff with jitter.
193
+ * `baseMs * 2^(attempts - 1)` capped at `maxMs`. Used by the drain
194
+ * worker when a publish fails and the event is still under the retry
195
+ * budget.
196
+ */
197
+ export function computeNextAttempt(
198
+ attempts: number,
199
+ baseMs: number = 1_000,
200
+ maxMs: number = 60 * 60 * 1_000,
201
+ ): Date {
202
+ const exponential = baseMs * 2 ** Math.max(0, attempts - 1);
203
+ const capped = Math.min(exponential, maxMs);
204
+ // ±20% jitter to avoid thundering-herd on retries.
205
+ const jittered = capped * (0.8 + Math.random() * 0.4);
206
+ return new Date(Date.now() + jittered);
207
+ }
@@ -0,0 +1,223 @@
1
+ import { DrizzleEntityService } from "@sixthsummit/ship-api/app/services/DrizzleEntityService";
2
+ // eslint-disable-next-line @typescript-eslint/no-restricted-imports -- the drainer needs row-level locking + atomic `sql` status transitions that QueryOptions can't express
3
+ import { and, asc, eq, isNull, lte, or, sql } from "drizzle-orm";
4
+ import {
5
+ computeNextAttempt,
6
+ type OutboxEvent,
7
+ type OutboxEventStatus,
8
+ outboxEvents,
9
+ } from "../schema.js";
10
+
11
+ /**
12
+ * v4 `OutboxEventService` — extends `DrizzleEntityService` for CRUD
13
+ * + the outbox-specific lifecycle transitions the drain worker needs.
14
+ *
15
+ * Surface inherited from the base:
16
+ * - `get` / `getAll` / `list` / `count` / `create` / `update` /
17
+ * `delete` with soft-delete + audit-column auto-stamping.
18
+ *
19
+ * Domain-specific methods added here:
20
+ *
21
+ * - `findReadyToPublish(limit)` — paginated query of rows where
22
+ * status='pending' AND publishedAt IS NULL AND
23
+ * (nextAttemptAt IS NULL OR nextAttemptAt <= now). FIFO ordered
24
+ * by `(createdAt, id)`. Driven by the drain worker.
25
+ *
26
+ * - `claimForProcessing(ids[])` — atomic status transition from
27
+ * 'pending' to 'processing' for the listed ids, incrementing
28
+ * `publishAttempts` and stamping `startedAt`. Returns only the
29
+ * ids that actually transitioned (compete with concurrent drain
30
+ * workers safely).
31
+ *
32
+ * - `markPublished(id)` — terminal success transition.
33
+ *
34
+ * - `markFailed(id, error)` — terminal failure (no more retries).
35
+ * Used by the drain worker when `hasExhaustedRetries()` is true
36
+ * after a failure.
37
+ *
38
+ * - `markForRetry(id, error, attempts)` — non-terminal failure;
39
+ * reverts status to 'pending', stamps `lastError`, and schedules
40
+ * `nextAttemptAt` via the exponential-backoff helper.
41
+ *
42
+ * - `recoverStaleProcessing(staleThresholdMs)` — admin tooling:
43
+ * finds rows stuck in 'processing' for longer than the threshold
44
+ * (worker died mid-publish) and resets them to 'pending' so the
45
+ * next drain picks them up.
46
+ *
47
+ * The drain orchestration logic itself (loop, batching, error
48
+ * handling, observability) lands in a separate `OutboxDrainer` class
49
+ * in a follow-up commit; the service only owns DB transitions.
50
+ */
51
+ export class OutboxEventService extends DrizzleEntityService<
52
+ typeof outboxEvents,
53
+ { outboxEvents: typeof outboxEvents }
54
+ > {
55
+ protected getTable() {
56
+ return outboxEvents;
57
+ }
58
+
59
+ protected override getDefaultSearchFields(): readonly string[] {
60
+ return ["eventType", "correlationId"];
61
+ }
62
+
63
+ /**
64
+ * Read up to `limit` rows that are ready to publish, ordered FIFO.
65
+ * The pending partial index covers this query.
66
+ */
67
+ async findReadyToPublish(limit: number = 100, now: Date = new Date()): Promise<OutboxEvent[]> {
68
+ const rows = await this.db
69
+ .select()
70
+ .from(outboxEvents)
71
+ .where(
72
+ and(
73
+ eq(outboxEvents.status, "pending"),
74
+ isNull(outboxEvents.publishedAt),
75
+ or(isNull(outboxEvents.nextAttemptAt), lte(outboxEvents.nextAttemptAt, now)),
76
+ ),
77
+ )
78
+ .orderBy(asc(outboxEvents.createdAt), asc(outboxEvents.id))
79
+ .limit(limit);
80
+ return rows as OutboxEvent[];
81
+ }
82
+
83
+ /**
84
+ * Atomically transition the listed rows from 'pending' to
85
+ * 'processing'. Increments publishAttempts and stamps startedAt.
86
+ * Returns only the ids that actually transitioned — concurrent
87
+ * drain workers compete safely; whichever worker's UPDATE wins gets
88
+ * the row.
89
+ */
90
+ async claimForProcessing(ids: readonly string[]): Promise<string[]> {
91
+ if (ids.length === 0) return [];
92
+ const now = new Date();
93
+ const rows = await this.db
94
+ .update(outboxEvents)
95
+ .set({
96
+ status: "processing",
97
+ startedAt: now,
98
+ publishAttempts: sql`${outboxEvents.publishAttempts} + 1`,
99
+ updatedAt: now,
100
+ } as never)
101
+ .where(
102
+ and(
103
+ // Inline as one IN clause to avoid one update-per-id round trip.
104
+ sql`${outboxEvents.id} = ANY(ARRAY[${sql.join(
105
+ ids.map((id) => sql`${id}`),
106
+ sql`, `,
107
+ )}]::uuid[])`,
108
+ eq(outboxEvents.status, "pending"),
109
+ ),
110
+ )
111
+ .returning({ id: outboxEvents.id as never });
112
+ return (rows as Array<{ id: string }>).map((r) => r.id);
113
+ }
114
+
115
+ async markPublished(id: string): Promise<OutboxEvent | null> {
116
+ const now = new Date();
117
+ const [row] = await this.db
118
+ .update(outboxEvents)
119
+ .set({
120
+ status: "published",
121
+ publishedAt: now,
122
+ lastError: null,
123
+ nextAttemptAt: null,
124
+ updatedAt: now,
125
+ } as never)
126
+ .where(eq(outboxEvents.id, id))
127
+ .returning();
128
+ return (row as OutboxEvent | undefined) ?? null;
129
+ }
130
+
131
+ async markFailed(id: string, error: string): Promise<OutboxEvent | null> {
132
+ const now = new Date();
133
+ const [row] = await this.db
134
+ .update(outboxEvents)
135
+ .set({
136
+ status: "failed",
137
+ lastError: truncateError(error),
138
+ nextAttemptAt: null,
139
+ updatedAt: now,
140
+ } as never)
141
+ .where(eq(outboxEvents.id, id))
142
+ .returning();
143
+ return (row as OutboxEvent | undefined) ?? null;
144
+ }
145
+
146
+ /**
147
+ * Non-terminal failure: schedule a retry with exponential backoff
148
+ * and revert status to 'pending' so the next drain picks it up.
149
+ * Caller owns the attempt-counting logic — typically calls
150
+ * `markForRetry` only when `hasExhaustedRetries(event)` is false.
151
+ */
152
+ async markForRetry(id: string, error: string, attempts: number): Promise<OutboxEvent | null> {
153
+ const now = new Date();
154
+ const nextAt = computeNextAttempt(attempts);
155
+ const [row] = await this.db
156
+ .update(outboxEvents)
157
+ .set({
158
+ status: "pending",
159
+ lastError: truncateError(error),
160
+ nextAttemptAt: nextAt,
161
+ publishedAt: null,
162
+ updatedAt: now,
163
+ } as never)
164
+ .where(eq(outboxEvents.id, id))
165
+ .returning();
166
+ return (row as OutboxEvent | undefined) ?? null;
167
+ }
168
+
169
+ /**
170
+ * Admin tooling — find rows stuck in 'processing' beyond the
171
+ * threshold and reset them to 'pending' so the next drain picks
172
+ * them up. Returns the count reset (callers report it).
173
+ */
174
+ async recoverStaleProcessing(
175
+ staleThresholdMs: number = 30 * 60 * 1_000,
176
+ ): Promise<{ recovered: number }> {
177
+ const cutoff = new Date(Date.now() - staleThresholdMs);
178
+ const now = new Date();
179
+ const rows = await this.db
180
+ .update(outboxEvents)
181
+ .set({
182
+ status: "pending",
183
+ startedAt: null,
184
+ nextAttemptAt: now,
185
+ updatedAt: now,
186
+ } as never)
187
+ .where(and(eq(outboxEvents.status, "processing"), lte(outboxEvents.startedAt, cutoff)))
188
+ .returning({ id: outboxEvents.id as never });
189
+ return { recovered: (rows as Array<{ id: string }>).length };
190
+ }
191
+
192
+ /**
193
+ * Aggregate counts by status — used by the stats endpoint and by
194
+ * monitoring dashboards. Returns 0 for missing buckets so the
195
+ * shape stays stable.
196
+ */
197
+ async getStatistics(): Promise<Record<OutboxEventStatus, number>> {
198
+ const rows = (await this.db
199
+ .select({
200
+ status: outboxEvents.status,
201
+ count: sql<number>`count(*)::int`,
202
+ })
203
+ .from(outboxEvents)
204
+ .groupBy(outboxEvents.status)) as Array<{
205
+ status: OutboxEventStatus;
206
+ count: number;
207
+ }>;
208
+ const stats: Record<OutboxEventStatus, number> = {
209
+ pending: 0,
210
+ processing: 0,
211
+ published: 0,
212
+ failed: 0,
213
+ };
214
+ for (const row of rows) stats[row.status] = row.count;
215
+ return stats;
216
+ }
217
+ }
218
+
219
+ const MAX_ERROR_LENGTH = 4096;
220
+ function truncateError(message: string): string {
221
+ if (message.length <= MAX_ERROR_LENGTH) return message;
222
+ return message.slice(0, MAX_ERROR_LENGTH - 3) + "...";
223
+ }
@@ -0,0 +1,30 @@
1
+ import pino, { type Logger } from "pino";
2
+ export { getRequestContext, type RequestContext, runWithRequestContext, setRequestContextField, } from "../app/context/RequestContext.js";
3
+ export interface CreateLoggerOptions {
4
+ /** Override log level. Defaults to `LOG_LEVEL` env then `"info"`. */
5
+ level?: pino.Level;
6
+ /**
7
+ * Custom destination (anything pino accepts: a stream, a file path via
8
+ * `pino.destination`, a sonic-boom instance, or any object with a `write`
9
+ * method). Useful for tests.
10
+ */
11
+ destination?: pino.DestinationStream;
12
+ /**
13
+ * Force pino-pretty mode regardless of env. Set `false` to force ND-JSON
14
+ * in dev (e.g., when running under a log-aggregating supervisor).
15
+ */
16
+ pretty?: boolean;
17
+ /**
18
+ * Extra redaction paths to *add* to the framework defaults. Use this for
19
+ * domain-specific secret keys (e.g., third-party webhook signatures).
20
+ */
21
+ extraRedactPaths?: readonly string[];
22
+ }
23
+ export declare function createLogger(opts?: CreateLoggerOptions): Logger;
24
+ /**
25
+ * Default framework-wide logger. Most callsites should import this and either
26
+ * use it directly or call `logger.child({ module: "<name>" })` for a scoped
27
+ * sub-logger.
28
+ */
29
+ export declare const logger: Logger;
30
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/observability/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,EAAE,EAAE,KAAK,MAAM,EAAsB,MAAM,MAAM,CAAC;AAM7D,OAAO,EACL,iBAAiB,EACjB,KAAK,cAAc,EACnB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,kCAAkC,CAAC;AAmD1C,MAAM,WAAW,mBAAmB;IAClC,qEAAqE;IACrE,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC;IACnB;;;;OAIG;IACH,WAAW,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC;IACrC;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AA0BD,wBAAgB,YAAY,CAAC,IAAI,GAAE,mBAAwB,GAAG,MAAM,CA0BnE;AAED;;;;GAIG;AACH,eAAO,MAAM,MAAM,EAAE,MAAuB,CAAC"}