@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,88 @@
1
+ ---
2
+ alwaysApply: true
3
+ description: "Conventional Commits for consumer apps"
4
+ tags: ["commits", "git", "conventional-commits"]
5
+ globs: ["**/*"]
6
+ ---
7
+
8
+ # Commit Conventions
9
+
10
+ This project uses [Conventional Commits](https://www.conventionalcommits.org/) for clarity in review and history. If you wire in a release automation later (Changesets, release-please, semantic-release), it will read these prefixes — but the convention is useful on its own even without one.
11
+
12
+ ## Format
13
+
14
+ ```
15
+ <type>(<scope>): <short description>
16
+
17
+ <optional body — explain WHY, not WHAT>
18
+
19
+ <optional footer — BREAKING CHANGE: ..., refs: ...>
20
+ ```
21
+
22
+ ## Types
23
+
24
+ | Type | Use for |
25
+ |---|---|
26
+ | `feat` | new user-facing feature |
27
+ | `fix` | bug fix |
28
+ | `feat!` / `BREAKING CHANGE:` footer | breaking change |
29
+ | `docs` | documentation only |
30
+ | `style` | whitespace, formatting (no behavior change) |
31
+ | `refactor` | code change without behavior change |
32
+ | `perf` | performance fix |
33
+ | `test` | test additions / changes |
34
+ | `build` | build system, deps |
35
+ | `ci` | CI / workflow / pipeline changes |
36
+ | `chore` | tooling, internal cleanup |
37
+ | `revert` | reverting a prior commit |
38
+
39
+ If you adopt a release automation that reads commit types (e.g. release-please), `feat:` → minor, `fix:`/`perf:` → patch, `feat!:` → major. Otherwise these are descriptive only.
40
+
41
+ ## Scope
42
+
43
+ Optional. Use the area of the change. Common scopes for ShipAPI apps:
44
+
45
+ - `(api)` / `(routes)` / `(modules)` — module surface changes
46
+ - `(db)` — schema, migrations, queries
47
+ - `(auth)` — authentication or permissions
48
+ - `(jobs)` — BullMQ jobs / cron
49
+ - `(test)` — when type is `chore` / `refactor` and only tests change
50
+
51
+ Skip the scope when it's not informative — a one-word commit needs no scope.
52
+
53
+ ## Examples
54
+
55
+ ```
56
+ feat(api): add POST /posts/:id/publish
57
+
58
+ Endpoint already gates on posts:publish permission and emits a
59
+ post.published outbox event for the notifications worker.
60
+
61
+ ---
62
+
63
+ fix(auth): refresh token rotation no longer races on logout
64
+
65
+ The refresh table delete and new-token insert ran in separate
66
+ transactions; concurrent logout + refresh could double-spend a
67
+ token. Wrap both in withTransaction.
68
+
69
+ ---
70
+
71
+ ci: skip e2e suite on docs-only PRs
72
+
73
+ paths-ignore was matching .md files but not the docs/ tree.
74
+
75
+ ---
76
+
77
+ feat!(api): drop /v1/* routes; clients must move to /v2/*
78
+
79
+ BREAKING CHANGE: Endpoints under /v1/ have been removed. See
80
+ docs/MIGRATION_V1_TO_V2.md for the field-by-field map.
81
+ ```
82
+
83
+ ## Don't
84
+
85
+ - Don't use `git commit --amend` after pushing — it rewrites history and breaks anyone who pulled.
86
+ - Don't `--no-verify`. If a hook fails, fix the underlying issue. Bypassing hooks is how secrets get committed.
87
+ - Don't write multi-paragraph commit bodies for trivial changes. The body should add information the diff doesn't.
88
+ - Don't reference internal ticket IDs in the title — the body is fine, but titles get rendered in CHANGELOG.
@@ -0,0 +1,92 @@
1
+ ---
2
+ alwaysApply: true
3
+ description: "Security guidelines for ShipAPI v4 apps"
4
+ tags: ["security", "authentication", "authorization"]
5
+ globs: ["modules/**/*.ts", "src/index.ts", "src/environment.ts"]
6
+ ---
7
+
8
+ # Security Guidelines
9
+
10
+ ## Authentication
11
+
12
+ ShipAPI v4 uses a pluggable `AuthProvider` interface. The default adapter is `FirebaseAuthProvider`; v4.x will add Better-Auth / Clerk / WorkOS / Auth.js adapters.
13
+
14
+ ### Token verification
15
+
16
+ - Bearer tokens (Authorization header or session cookie) are verified by the configured `AuthProvider`.
17
+ - The framework's `JwtAuthFlow` issues stateless ES256 JWT cookies (`httpOnly, secure, sameSite=lax`) plus a `refresh_tokens` table for revocation.
18
+ - **Never disable signature verification.** Don't bypass the provider chain "for tests" — use a `MockAuthProvider` adapter instead.
19
+
20
+ ### Middleware
21
+
22
+ - `requireAuth({ provider })` — rejects with 401 if no valid token. Set `optional: true` only for routes that have a public + authenticated mode.
23
+ - `requirePermission(slug)` — rejects with 403 if the resolved account lacks the slug.
24
+ - **Authorization runs at the route, not the controller.** Always chain `requireAuth → requirePermission` on protected routes. The framework's `ship-reviewer` plugin agent flags missing chains.
25
+
26
+ ### Permission slugs
27
+
28
+ - Format: `module:resource:action` (e.g., `posts:create`, `accounts:list`, `billing:invoice:read`).
29
+ - Define as constants in `modules/<name>/permissions.ts`. Reference the constant from both `requirePermission(slug)` and any seed-data inserts.
30
+ - Permissions are durable — adding new ones is fine, renaming or removing one needs a migration plan.
31
+
32
+ ### Secrets
33
+
34
+ - **No hardcoded fallbacks** in `src/environment.ts`. `defineEnv(zodSchema)` fail-fasts at boot — that's the design. A boot failure is preferable to running on an attacker-known default.
35
+ - Never commit `.env` files. The template's `.env.example` is the only env file checked in.
36
+ - Rotate `JWT_SIGNING_KEY` per the framework's documented procedure (add new key to `JWT_VERIFICATION_KEYS` first, cut signing over, wait > max token lifetime, remove old key).
37
+
38
+ ## Input validation
39
+
40
+ - All request input goes through Zod via `validate("json"|"query"|"param", schema)`. Read with `c.req.valid(...)`.
41
+ - Use `.strict()` on object schemas to reject unknown fields — defense against parameter-injection accidents and forward-compat bugs.
42
+ - Validate at the boundary; don't re-validate inside services.
43
+
44
+ ### Webhooks
45
+
46
+ - Webhook routes (`POST /webhooks/<provider>`) need raw-body signature verification. Use `parseWebhook(c, { provider, secret })` — handles Stripe, GitHub, Slack, Twilio out of the box; pluggable via the `WebhookVerifier` interface for custom providers.
47
+ - Don't apply `validate("json", ...)` before signature verification — Zod consuming the body breaks the raw-body contract some signatures depend on.
48
+
49
+ ### File uploads
50
+
51
+ - Use `parseUpload(c, schema)` from the framework — Web Standards FormData with magic-byte MIME validation via `file-type`.
52
+ - Be aware that uploads are buffered in memory up to `bodyLimit` (default 25 MB) before the handler runs. For large files, drop to `c.req.raw.body` and pipe directly to a `StorageService` adapter.
53
+ - Always validate MIME via magic bytes, not the Content-Type header (which clients control).
54
+
55
+ ## CSRF
56
+
57
+ - **Default**: `httpOnly, secure, sameSite=lax` cookies + automatic Origin / Sec-Fetch-Site checking on mutating requests. Protects against top-level navigation CSRF.
58
+ - **Hardened mode**: `csrf({ doubleSubmit: true })` middleware adds an `X-CSRF-Token` double-submit cookie. Opt in for third-party-iframed apps or multi-subdomain consumers.
59
+
60
+ ## Rate limit
61
+
62
+ - `rateLimit({ windowMs, max, keyGenerator, scope })` — Redis-backed sliding window. Apply to login / signup / password-reset / any endpoint where unauthenticated retry is cheap.
63
+ - **Default fail-mode is fail-closed** when Redis is unavailable. Override with `onRedisUnavailable: 'allow'` only with a deliberate threat-model decision.
64
+ - Emits RFC-draft `RateLimit-Limit` / `RateLimit-Remaining` / `RateLimit-Policy` headers.
65
+
66
+ ## SQL injection
67
+
68
+ - Drizzle uses parameterized queries by default — `eq(table.col, userInput)` is safe.
69
+ - Don't drop to raw SQL via `sql\`...\${input}...\`` with user input interpolated. If you need raw SQL, parameterize via `sql.placeholder` or build the string from a constant whitelist.
70
+
71
+ ## Logging
72
+
73
+ - Sensitive fields are redacted by pino's redaction list: `authorization`, `cookie`, `*.password`, `*.token`, `firebaseCredentials`.
74
+ - **Never `console.log` user PII or secrets.** `console.*` bypasses redaction; use `logger`.
75
+ - Don't log full request bodies on routes that accept secrets (login, password reset, payment intent).
76
+
77
+ ## WebSocket auth
78
+
79
+ - The framework uses subprotocol-header authentication: client opens `new WebSocket(url, ['ship-api.v1', \`bearer.${token}\`])`. Server reads `Sec-WebSocket-Protocol`, runs the same `AuthProvider` chain as `requireAuth`, rejects the upgrade with 401 if invalid.
80
+ - Don't auth via URL `?token=...` — leaks into access logs. Don't auth via first-message handshake — creates "connected but unauthenticated" footgun.
81
+
82
+ ## Audit
83
+
84
+ - `audit-ci` runs in CI and hard-fails on `high` / `critical` findings. Don't `--allow-list` a high finding without a tracking issue + remediation date.
85
+ - Run `npm run audit` locally before opening a PR that bumps deps.
86
+
87
+ ## When in doubt
88
+
89
+ - Default to fail-closed.
90
+ - Default to validating at boundaries.
91
+ - Default to using the framework's middleware factories rather than rolling your own.
92
+ - If a security-relevant change feels surprising, check `docs/V4_LAUNCH.md` and the framework's `.cursor/rules/security.mdc` for the intended pattern.
@@ -0,0 +1,123 @@
1
+ ---
2
+ alwaysApply: true
3
+ description: "Vitest testing patterns for ShipAPI v4 apps"
4
+ tags: ["testing", "vitest"]
5
+ globs: ["src/**/*.test.ts", "tests/**/*.ts"]
6
+ ---
7
+
8
+ # Testing Guidelines
9
+
10
+ ## Framework
11
+
12
+ [Vitest](https://vitest.dev). The template ships with `vitest` configured; run with `npm test`.
13
+
14
+ - `npm test` — full run.
15
+ - `npm test -- --watch` — watch mode for active development.
16
+ - `npm test -- --changed` — only re-run tests whose source-of-truth changed since `main`.
17
+ - `npm test -- modules/<name>` — module-scoped run.
18
+
19
+ ## Test file co-location
20
+
21
+ Co-locate unit tests with the code under test:
22
+
23
+ ```
24
+ modules/posts/
25
+ ├── services/PostService.ts
26
+ ├── services/PostService.test.ts # service unit tests
27
+ ├── routes.ts
28
+ └── routes.test.ts # route integration tests
29
+ ```
30
+
31
+ Integration tests that span modules live under `tests/integration/`.
32
+
33
+ ## Service unit tests (fake DB)
34
+
35
+ For service-level tests, mock the DB at the lowest level — you're testing service logic, not Drizzle:
36
+
37
+ ```ts
38
+ import { describe, it, expect, vi } from "vitest";
39
+ import { PostService } from "./PostService";
40
+
41
+ describe("PostService", () => {
42
+ it("filters out soft-deleted rows by default", async () => {
43
+ const fakeDb = { query: { posts: { findMany: vi.fn().mockResolvedValue([]) } } };
44
+ const service = new PostService(fakeDb as any);
45
+ await service.list({});
46
+ expect(fakeDb.query.posts.findMany).toHaveBeenCalledWith(
47
+ expect.objectContaining({ where: expect.anything() })
48
+ );
49
+ });
50
+ });
51
+ ```
52
+
53
+ For multi-method flows, use `testcontainers` against a real Postgres (see integration tests below).
54
+
55
+ ## Route integration tests (full chain)
56
+
57
+ Test the full middleware chain (auth → permission → validate → handler → service) via `app.request(...)` against the chained Hono app. The framework's reference modules ship a harness — mirror that shape:
58
+
59
+ ```ts
60
+ import { describe, it, expect } from "vitest";
61
+ import { app } from "../../index"; // your composed app
62
+
63
+ describe("POST /posts", () => {
64
+ it("rejects unauthenticated requests", async () => {
65
+ const res = await app.request("/posts", {
66
+ method: "POST",
67
+ headers: { "content-type": "application/json" },
68
+ body: JSON.stringify({ title: "x", body: "y" }),
69
+ });
70
+ expect(res.status).toBe(401);
71
+ });
72
+
73
+ it("creates a post for an authenticated user with permission", async () => {
74
+ const res = await app.request("/posts", {
75
+ method: "POST",
76
+ headers: { "content-type": "application/json", cookie: signedAuthCookie() },
77
+ body: JSON.stringify({ title: "x", body: "y" }),
78
+ });
79
+ expect(res.status).toBe(201);
80
+ const json = await res.json();
81
+ expect(json).toMatchObject({ id: expect.any(String), title: "x" });
82
+ });
83
+ });
84
+ ```
85
+
86
+ `signedAuthCookie()` is a test helper you write once that mints a valid session cookie via the framework's `JwtSigner`. Keep helpers in `tests/helpers/`.
87
+
88
+ ## Real-DB integration tests
89
+
90
+ For tests that exercise queries / migrations / transactions against a real Postgres, use `@testcontainers/postgresql`:
91
+
92
+ ```ts
93
+ import { PostgreSqlContainer } from "@testcontainers/postgresql";
94
+
95
+ let container: StartedPostgreSqlContainer;
96
+ beforeAll(async () => { container = await new PostgreSqlContainer().start(); });
97
+ afterAll(async () => { await container.stop(); });
98
+ ```
99
+
100
+ Run integration tests under a separate Vitest config (`vitest.integration.config.ts`) so they don't slow the regular suite.
101
+
102
+ ## Mocking
103
+
104
+ - **Mock at boundaries, not internals.** Mock the framework's `AuthProvider`, `Cache`, `JobQueue` — not your own service methods. If you find yourself mocking your own service heavily, the test is at the wrong level.
105
+ - Use `vi.fn()` over `jest.fn()` (the migration is mechanical; vitest exposes `vi`).
106
+ - Use `vi.spyOn(obj, "method").mockReturnValue(...)` for method spies — don't reassign methods directly.
107
+
108
+ ## What to assert
109
+
110
+ - **Status codes + response shape**, not exact response bodies. Use `toMatchObject` over `toEqual` so non-deterministic fields (timestamps, IDs) don't make tests brittle.
111
+ - **Side effects**: did the service call the cache? Did it emit an outbox event? Did it log? Spy on those.
112
+ - **Error paths**: assert the exact AppError subclass thrown (`ConflictError`, `NotFoundError`), not just "an error was thrown".
113
+
114
+ ## What NOT to do
115
+
116
+ - **Don't mock pg/Drizzle directly** in unit tests. Either go fake-DB (a hand-rolled stub object) or testcontainers. Mocking Drizzle leads to tests that pass but don't reflect SQL behavior.
117
+ - **Don't share mutable state across tests.** Each test gets a fresh fixture. If setup is expensive, use `beforeAll` + a reset in `beforeEach`.
118
+ - **Don't test framework internals** — those are tested in `@sixthsummit/ship-api`'s own test suite. You test your code.
119
+ - **Don't add tests just for coverage.** A test that asserts trivia (`expect(x).toBeDefined()`) is worse than no test — it lies about what's verified.
120
+
121
+ ## Coverage
122
+
123
+ The template ships with no enforced coverage gate; opt in by editing `vitest.config.ts` if you want a floor. The framework itself targets 80% line / 70% branch on `packages/core/src/**` per `docs/V4_STATUS.md` — your app can do whatever fits the team.
@@ -0,0 +1,86 @@
1
+ ---
2
+ alwaysApply: true
3
+ description: "TypeScript coding standards for ShipAPI v4 apps"
4
+ tags: ["typescript", "type-safety"]
5
+ globs: ["src/**/*.ts", "tests/**/*.ts"]
6
+ ---
7
+
8
+ # TypeScript Coding Standards
9
+
10
+ ## Strictness
11
+
12
+ - The template runs with `strict: true`. Don't disable individual flags (`strictNullChecks`, `noImplicitAny`, etc.) per-file or per-tsconfig.
13
+ - `tsc --noEmit` runs in `npm run type-check` and CI. Type errors block the pipeline.
14
+
15
+ ## `any`, `unknown`, `never`
16
+
17
+ - **No `any`.** Use `unknown` and narrow with `instanceof`, type guards, or Zod parsing.
18
+ - Use `unknown` for genuinely-unknown payloads (webhook bodies before signature verification, third-party callbacks). Narrow via Zod before use.
19
+ - Reach for `never` to mark exhaustiveness checks: `const _exhaustive: never = x;` in a `switch` default fails compile if a new case is added.
20
+
21
+ ## Imports
22
+
23
+ - Import the framework via package-export paths: `@sixthsummit/ship-api`, `@sixthsummit/ship-api/client`, `@sixthsummit/ship-api/observability/logger`, etc.
24
+ - **Never import from `node_modules/@sixthsummit/ship-api/lib/`.** Those are build artifacts; the path is not part of the public API.
25
+ - Within your app, use relative imports for module-internal references and absolute paths (configured in `tsconfig.json` via `paths`) for cross-module references.
26
+
27
+ ## Type-driven schema flow
28
+
29
+ ShipAPI v4 propagates types end-to-end via:
30
+
31
+ ```
32
+ Drizzle table (schema.ts)
33
+ ↓ drizzle-zod
34
+ Zod schema (validation/schemas.ts)
35
+ ↓ validate("json", schema)
36
+ Hono route handler (c.req.valid("json"))
37
+ ↓ typeof app
38
+ ShipApiClient type (exported from src/index.ts)
39
+ ↓ hc<ShipApiClient>(BASE_URL)
40
+ Typed RPC client on the consumer
41
+ ```
42
+
43
+ This means: **schema changes propagate through TypeScript types alone, no codegen.** Don't add manual type duplications between layers — let inference flow.
44
+
45
+ ## Null safety
46
+
47
+ - Prefer `T | undefined` for "not yet known" / "may not be present"; use `T | null` only when the database column is nullable (or another external system distinguishes null from absent).
48
+ - Don't use the non-null assertion `!` to suppress null errors. If TS thinks a value can be null, narrow it with a check or fix the type.
49
+ - Optional chaining (`?.`) and nullish coalescing (`??`) over `&&` / `||` for default-value patterns when you mean "null or undefined", not "any falsy".
50
+
51
+ ## Branded types
52
+
53
+ For IDs and other opaque scalars where mixing types would be a bug:
54
+
55
+ ```ts
56
+ type AccountId = string & { readonly _brand: "AccountId" };
57
+ type PostId = string & { readonly _brand: "PostId" };
58
+ ```
59
+
60
+ Then `getPost(accountId)` fails to compile. Branded types are zero-cost at runtime.
61
+
62
+ ## Generics
63
+
64
+ - Default to inference. Explicit generics belong on factory APIs (`createApp<TSchema>`), not on call sites where TS can infer.
65
+ - Constrain generics with `extends` where it documents intent: `function fn<T extends { id: string }>(x: T)`.
66
+ - Avoid `any` as a generic constraint. `unknown` is almost always better.
67
+
68
+ ## Error narrowing
69
+
70
+ Use `instanceof` against the AppError taxonomy when you need to react to specific errors:
71
+
72
+ ```ts
73
+ try { await service.create(input); }
74
+ catch (err) {
75
+ if (err instanceof ConflictError) return c.json({ message: "exists" }, 409);
76
+ throw err;
77
+ }
78
+ ```
79
+
80
+ Otherwise let `registerErrorHandlers(app)` handle it — don't catch errors just to re-throw.
81
+
82
+ ## Conventions
83
+
84
+ - File names: `PascalCase` for classes / services (`PostService.ts`), `camelCase` for utilities (`buildQuery.ts`), `kebab-case` for route directories.
85
+ - Exported types from a module: name the type after what it represents (`Post`, `CreatePostInput`), not how it's derived (`PostType`, `CreatePostBody`).
86
+ - Prefer `type` over `interface` unless you specifically need declaration merging.
@@ -0,0 +1,79 @@
1
+ # Required ─────────────────────────────────────────────────────────────
2
+
3
+ # Postgres connection string — used by both runtime + drizzle-kit.
4
+ DATABASE_URL=postgres://ship_api:ship_api@localhost:5432/ship_api
5
+
6
+ # HMAC-SHA256 secret for OAuth state signing. ≥32 random bytes,
7
+ # rotated separately from JWT keys. Do not commit.
8
+ #
9
+ # Zero-downtime rotation: the framework's `StateSecret` type accepts
10
+ # either a single string OR an ordered array (head signs, tail still
11
+ # verifies). During a rotation window, source two env vars in your
12
+ # environment.ts and pass `[env.OAUTH_STATE_SECRET_NEW, env.OAUTH_STATE_SECRET_OLD]`
13
+ # as `stateSecret` to defineOAuthRoutes; once the rotation window
14
+ # (default 10 min) has fully drained, drop OLD from the array.
15
+ OAUTH_STATE_SECRET=replace-with-32-random-bytes
16
+
17
+ # JWT signing — ES256 key pair. Rotate via add-new-key →
18
+ # cut-signing → drain-old-key. The signing key is private; the
19
+ # verification keys are a JSON array of JWKS supporting >1 key
20
+ # during rotation windows.
21
+ JWT_SIGNING_KEY=
22
+ JWT_VERIFICATION_KEYS=[]
23
+
24
+ # Optional ─────────────────────────────────────────────────────────────
25
+
26
+ PORT=3000
27
+ NODE_ENV=development
28
+ LOG_LEVEL=info
29
+
30
+ # CORS allowlist (comma-separated). When set, the framework wires
31
+ # `hono/cors` with `credentials: true` against this list. Required if
32
+ # your TypeScript client lives on a different origin from the API.
33
+ #
34
+ # `CORS_ORIGINS=*` is NOT supported with cookie auth — browsers reject
35
+ # the wildcard + credentials combo, and `createApp()` throws at boot
36
+ # rather than letting the misconfig sit silently. Use explicit origins:
37
+ #
38
+ # CORS_ORIGINS=https://app.example.com,https://admin.example.com
39
+ #
40
+ # Leave unset for a single-origin deployment (same domain for API + web).
41
+ CORS_ORIGINS=
42
+
43
+ # OpenTelemetry — disable in test, enable + point at a collector
44
+ # in prod. The auto-instrumentations cover HTTP / pg / ioredis /
45
+ # undici / pino with no per-call wiring.
46
+ OTEL_SDK_DISABLED=true
47
+ OTEL_EXPORTER_OTLP_ENDPOINT=
48
+ OTEL_SERVICE_NAME=ship-api-app
49
+ ENVIRONMENT_NAME=development
50
+
51
+ # Prometheus metrics exporter (independent port, off by default).
52
+ METRICS_ENABLED=false
53
+ METRICS_PORT=9464
54
+
55
+ # Redis — required when using rate limiting / cache / BullMQ.
56
+ REDIS_URL=redis://localhost:6379
57
+
58
+ # Admin API key for the Bull-Board dashboard (and other admin
59
+ # surfaces). ≥32 random bytes. Required only when you mount the
60
+ # dashboard via `createBullBoardApp({ apiKey: env.ADMIN_API_KEY })`.
61
+ # DO NOT expose the dashboard on a public hostname even with the key
62
+ # set — operators should additionally guard at the network edge
63
+ # (private subnet / VPN / ingress allowlist).
64
+ ADMIN_API_KEY=
65
+
66
+ # Firebase auth (the v4.0 default AuthProvider). Replace with
67
+ # Better-Auth / Clerk / WorkOS / Auth.js adapter creds when you
68
+ # swap providers.
69
+ FIREBASE_CREDENTIALS=
70
+
71
+ # OAuth provider credentials. Add only the providers your app
72
+ # supports — the credentials resolver returns null for unconfigured
73
+ # providers and the routes layer 400s with a clear message.
74
+ OAUTH_GOOGLE_CLIENT_ID=
75
+ OAUTH_GOOGLE_CLIENT_SECRET=
76
+ OAUTH_GOOGLE_REDIRECT_URI=http://localhost:3000/oauth/google/callback
77
+ OAUTH_MICROSOFT_CLIENT_ID=
78
+ OAUTH_MICROSOFT_CLIENT_SECRET=
79
+ OAUTH_MICROSOFT_REDIRECT_URI=http://localhost:3000/oauth/microsoft/callback
@@ -0,0 +1,180 @@
1
+ name: Sherpa QA brief
2
+
3
+ # Generates a plain-English QA brief for the Sherpa toolkit:
4
+ # - On PR-to-dev: posts (or updates) a preview brief as a sticky PR comment.
5
+ # - On push to dev (i.e. merge to dev → deploy to dev site): posts the final
6
+ # brief to the QA Slack channel + uploads brief.md as a workflow artifact.
7
+ #
8
+ # The brief is produced by the ship-api plugin's `qa-brief` agent running
9
+ # headless via the Claude Code CLI. Engineers do nothing — Cursor and Claude
10
+ # Code users both get the same output through this CI path.
11
+ #
12
+ # Secrets required:
13
+ # ANTHROPIC_API_KEY — Claude API key for the headless agent run
14
+ # SLACK_QA_WEBHOOK_URL — Incoming Webhook for the QA channel (only used on push)
15
+ # GH_PACKAGES_TOKEN — read-access to @sixthsummit npm scope (if private deps)
16
+ #
17
+ # Override `STACK_LABEL` per repo if you customize the stack identity.
18
+
19
+ on:
20
+ pull_request:
21
+ branches: [dev]
22
+ types: [opened, synchronize, reopened]
23
+ push:
24
+ branches: [dev]
25
+
26
+ permissions:
27
+ contents: read
28
+ pull-requests: write
29
+
30
+ concurrency:
31
+ group: sherpa-brief-${{ github.ref }}
32
+ cancel-in-progress: true
33
+
34
+ env:
35
+ NODE_VERSION: '20'
36
+ STACK_LABEL: 'ShipAPI (backend)'
37
+
38
+ jobs:
39
+ brief:
40
+ name: Generate QA brief
41
+ runs-on: ubuntu-latest
42
+ if: github.event.pull_request.draft != true
43
+ steps:
44
+ - name: Checkout
45
+ uses: actions/checkout@v4
46
+ with:
47
+ fetch-depth: 0
48
+
49
+ - name: Setup Node.js
50
+ uses: actions/setup-node@v4
51
+ with:
52
+ node-version: ${{ env.NODE_VERSION }}
53
+ cache: 'npm'
54
+
55
+ - name: Resolve diff range and PR context
56
+ id: refs
57
+ env:
58
+ EVENT_NAME: ${{ github.event_name }}
59
+ PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
60
+ PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
61
+ PR_TITLE: ${{ github.event.pull_request.title }}
62
+ PR_NUMBER: ${{ github.event.pull_request.number }}
63
+ PR_BRANCH: ${{ github.event.pull_request.head.ref }}
64
+ PR_BODY: ${{ github.event.pull_request.body }}
65
+ PUSH_BEFORE: ${{ github.event.before }}
66
+ PUSH_AFTER: ${{ github.sha }}
67
+ PUSH_BRANCH: ${{ github.ref_name }}
68
+ run: |
69
+ set -euo pipefail
70
+ if [[ "$EVENT_NAME" == "pull_request" ]]; then
71
+ echo "base=$PR_BASE_SHA" >> "$GITHUB_OUTPUT"
72
+ echo "head=$PR_HEAD_SHA" >> "$GITHUB_OUTPUT"
73
+ echo "branch=$PR_BRANCH" >> "$GITHUB_OUTPUT"
74
+ echo "pr_title=$PR_TITLE" >> "$GITHUB_OUTPUT"
75
+ echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT"
76
+ printf '%s' "$PR_BODY" > pr_body.txt
77
+ else
78
+ BASE="$PUSH_BEFORE"
79
+ if [[ -z "$BASE" || "$BASE" == "0000000000000000000000000000000000000000" ]]; then
80
+ BASE="$(git rev-parse HEAD~1)"
81
+ fi
82
+ echo "base=$BASE" >> "$GITHUB_OUTPUT"
83
+ echo "head=$PUSH_AFTER" >> "$GITHUB_OUTPUT"
84
+ echo "branch=$PUSH_BRANCH" >> "$GITHUB_OUTPUT"
85
+ git log -1 --pretty=%s "$PUSH_AFTER" > .commit_subject
86
+ echo "pr_title=$(cat .commit_subject)" >> "$GITHUB_OUTPUT"
87
+ echo "pr_number=" >> "$GITHUB_OUTPUT"
88
+ git log -1 --pretty=%b "$PUSH_AFTER" > pr_body.txt
89
+ fi
90
+
91
+ - name: Install Claude Code CLI
92
+ run: npm install -g @anthropic-ai/claude-code
93
+
94
+ - name: Run qa-brief agent
95
+ env:
96
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
97
+ BASE_REF: ${{ steps.refs.outputs.base }}
98
+ HEAD_REF: ${{ steps.refs.outputs.head }}
99
+ PR_TITLE: ${{ steps.refs.outputs.pr_title }}
100
+ PR_NUMBER: ${{ steps.refs.outputs.pr_number }}
101
+ REPO: ${{ github.repository }}
102
+ BRANCH: ${{ steps.refs.outputs.branch }}
103
+ STACK_LABEL: ${{ env.STACK_LABEL }}
104
+ run: |
105
+ set -euo pipefail
106
+ export PR_BODY="$(cat pr_body.txt)"
107
+ claude -p "Invoke the qa-brief subagent. Use BASE_REF=$BASE_REF and HEAD_REF=$HEAD_REF. Output ONLY the brief markdown — no preamble, no commentary, no fenced code wrapper around the whole thing. The header must use STACK_LABEL=\"$STACK_LABEL\", REPO=\"$REPO\", BRANCH=\"$BRANCH\", and PR=\"$PR_NUMBER\"." > brief.md
108
+ echo '--- generated brief ---'
109
+ cat brief.md
110
+
111
+ - name: Upload brief artifact
112
+ uses: actions/upload-artifact@v4
113
+ with:
114
+ name: sherpa-brief-${{ github.run_id }}
115
+ path: brief.md
116
+ retention-days: 30
117
+
118
+ - name: Post sticky PR comment
119
+ if: github.event_name == 'pull_request'
120
+ uses: marocchino/sticky-pull-request-comment@v2
121
+ with:
122
+ header: sherpa-brief
123
+ path: brief.md
124
+
125
+ - name: Notify Slack on merge to dev
126
+ if: github.event_name == 'push'
127
+ env:
128
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_QA_WEBHOOK_URL }}
129
+ STACK_LABEL: ${{ env.STACK_LABEL }}
130
+ run: |
131
+ set -euo pipefail
132
+ if [[ -z "${SLACK_WEBHOOK_URL:-}" ]]; then
133
+ echo "::warning::SLACK_QA_WEBHOOK_URL not set; skipping Slack notification."
134
+ exit 0
135
+ fi
136
+ ARTIFACT_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
137
+ COMMIT_URL="${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}"
138
+ TITLE="$(head -1 brief.md | sed 's/^# *//')"
139
+ # Slack section text caps at ~3000 chars; truncate the inline snippet
140
+ # and rely on the artifact link for the full brief.
141
+ PREVIEW="$(head -c 2500 brief.md)"
142
+ if [[ "$(wc -c < brief.md)" -gt 2500 ]]; then
143
+ PREVIEW="${PREVIEW}
144
+
145
+ … (truncated — open the full brief from the link below)"
146
+ fi
147
+ jq -n \
148
+ --arg title "$TITLE" \
149
+ --arg stack "$STACK_LABEL" \
150
+ --arg repo "${{ github.repository }}" \
151
+ --arg branch "${{ steps.refs.outputs.branch }}" \
152
+ --arg artifact "$ARTIFACT_URL" \
153
+ --arg commit "$COMMIT_URL" \
154
+ --arg preview "$PREVIEW" \
155
+ '{
156
+ text: ("New QA brief: " + $title),
157
+ blocks: [
158
+ { "type": "header",
159
+ "text": { "type": "plain_text", "text": $title } },
160
+ { "type": "section",
161
+ "fields": [
162
+ { "type": "mrkdwn", "text": ("*Stack:*\n" + $stack) },
163
+ { "type": "mrkdwn", "text": ("*Repo:*\n" + $repo) },
164
+ { "type": "mrkdwn", "text": ("*Branch:*\n`" + $branch + "`") }
165
+ ] },
166
+ { "type": "section",
167
+ "text": { "type": "mrkdwn", "text": $preview } },
168
+ { "type": "actions",
169
+ "elements": [
170
+ { "type": "button",
171
+ "text": { "type": "plain_text", "text": "Open full brief" },
172
+ "url": $artifact },
173
+ { "type": "button",
174
+ "text": { "type": "plain_text", "text": "View commit" },
175
+ "url": $commit }
176
+ ] }
177
+ ]
178
+ }' > slack-payload.json
179
+ curl -sS --fail -X POST -H 'Content-Type: application/json' \
180
+ --data @slack-payload.json "$SLACK_WEBHOOK_URL"