@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,70 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * v4 validation surface — Zod schemas piped through `validate('json' | ...)`
5
+ * at the route, with `c.req.valid('json')` reading parsed input. The route
6
+ * registry captures these schemas so MCP tools, the typed-client export, and
7
+ * the eventual OpenAPI compat layer all see the same contract.
8
+ *
9
+ * Field shapes mirror this module's `accounts` table (../schema.ts).
10
+ * Consumers who customize the schema via `createApp({ schema })` should also
11
+ * customize these schemas (extend / override) so server-side validation
12
+ * matches the persisted shape.
13
+ */
14
+
15
+ const FIREBASE_UID_MAX = 128;
16
+ const EMAIL_MAX = 320;
17
+ const DISPLAY_NAME_MAX = 200;
18
+
19
+ export const createAccountSchema = z
20
+ .object({
21
+ /**
22
+ * Stable subject identifier from the AuthProvider. Optional at create
23
+ * time so service-side flows (e.g., admin-creates-pending-account)
24
+ * can fill it in later when the user first signs in.
25
+ */
26
+ firebaseUid: z.string().min(1).max(FIREBASE_UID_MAX).optional(),
27
+ email: z.string().email().max(EMAIL_MAX),
28
+ emailVerified: z.boolean().optional(),
29
+ displayName: z.string().min(1).max(DISPLAY_NAME_MAX).optional(),
30
+ isActive: z.boolean().optional(),
31
+ roleId: z.string().uuid().optional(),
32
+ })
33
+ .strict();
34
+
35
+ export const updateAccountSchema = z
36
+ .object({
37
+ firebaseUid: z.string().min(1).max(FIREBASE_UID_MAX).optional(),
38
+ email: z.string().email().max(EMAIL_MAX).optional(),
39
+ emailVerified: z.boolean().optional(),
40
+ displayName: z.string().min(1).max(DISPLAY_NAME_MAX).optional(),
41
+ isActive: z.boolean().optional(),
42
+ /** `null` clears the role assignment (FK is nullable). */
43
+ roleId: z.string().uuid().nullable().optional(),
44
+ })
45
+ .strict();
46
+
47
+ export const accountIdParamSchema = z.object({
48
+ id: z.string().uuid(),
49
+ });
50
+
51
+ /**
52
+ * `?search=foo&page=1&perPage=20&isActive=true&roleId=...`
53
+ *
54
+ * `coerce.number` lets the client send the values as strings (the only
55
+ * shape `c.req.query()` produces) and still get number-typed values out.
56
+ */
57
+ export const listAccountsQuerySchema = z
58
+ .object({
59
+ search: z.string().min(1).optional(),
60
+ isActive: z.enum(["true", "false"]).optional(),
61
+ roleId: z.string().uuid().optional(),
62
+ page: z.coerce.number().int().positive().default(1),
63
+ perPage: z.coerce.number().int().positive().max(100).default(20),
64
+ })
65
+ .strict();
66
+
67
+ export type CreateAccountInput = z.infer<typeof createAccountSchema>;
68
+ export type UpdateAccountInput = z.infer<typeof updateAccountSchema>;
69
+ export type ListAccountsQuery = z.infer<typeof listAccountsQuerySchema>;
70
+ export type AccountIdParam = z.infer<typeof accountIdParamSchema>;
@@ -0,0 +1,35 @@
1
+ import { GoogleOAuthAdapter, type GoogleOAuthAdapterOptions } from "./GoogleOAuthAdapter.js";
2
+
3
+ /**
4
+ * Gmail-flavored Google OAuth adapter — convenience subclass that
5
+ * pre-fills `providerCode: "gmail"`.
6
+ *
7
+ * Same OAuth 2.0 flow as `GoogleOAuthAdapter` (Gmail uses the same
8
+ * Google Identity endpoints; Gmail-specific scopes like
9
+ * `https://www.googleapis.com/auth/gmail.readonly` are caller-
10
+ * supplied via `AuthUrlOptions.scopes`, not adapter-specific).
11
+ *
12
+ * Why a separate class instead of a runtime tag: connection rows
13
+ * carry `providerCode` as the cross-table key, and consumers
14
+ * frequently want Gmail-scoped connections to live alongside
15
+ * generic Google sign-in connections without colliding on the
16
+ * unique (account_id, provider_code) composite. Registering both
17
+ * `GoogleOAuthAdapter` (`"google"`) and `GmailOAuthAdapter`
18
+ * (`"gmail"`) in the same registry gives consumers two distinct
19
+ * provider rows per account.
20
+ *
21
+ * Usage:
22
+ *
23
+ * const adapters = oauthAdapterRegistry(
24
+ * new GoogleOAuthAdapter(),
25
+ * new GmailOAuthAdapter(),
26
+ * );
27
+ *
28
+ * All other options forward to the underlying `GoogleOAuthAdapter`
29
+ * (defaultAccessType, defaultPrompt, fetchImpl, …).
30
+ */
31
+ export class GmailOAuthAdapter extends GoogleOAuthAdapter {
32
+ constructor(opts: Omit<GoogleOAuthAdapterOptions, "providerCode"> = {}) {
33
+ super({ ...opts, providerCode: "gmail" });
34
+ }
35
+ }
@@ -0,0 +1,278 @@
1
+ import type {
2
+ AuthUrlOptions,
3
+ ExchangeCodeOptions,
4
+ OAuthAdapter,
5
+ OAuthClientCredentials,
6
+ TokenResponse,
7
+ } from "./OAuthAdapter.js";
8
+ import {
9
+ InvalidCredentialsError,
10
+ OAuthRateLimitError,
11
+ TokenExchangeError,
12
+ TokenRefreshError,
13
+ } from "./OAuthAdapter.js";
14
+
15
+ /**
16
+ * Google OAuth 2.0 adapter — fetch-based, no SDK dependency.
17
+ *
18
+ * Implements the framework's `OAuthAdapter` interface against
19
+ * Google's OAuth 2.0 endpoints directly:
20
+ * - Authorization: https://accounts.google.com/o/oauth2/v2/auth
21
+ * - Token exchange: https://oauth2.googleapis.com/token
22
+ * - User info: https://openidconnect.googleapis.com/v1/userinfo
23
+ * - Revoke: https://oauth2.googleapis.com/revoke
24
+ *
25
+ * Replaces v3's `googleapis`-SDK-backed adapter. Fetch-based means
26
+ * the adapter works in every runtime (Node, Workers, Bun) without
27
+ * a 5+ MB SDK in the bundle. Consumers who want the full Google
28
+ * SDK ergonomics for non-OAuth API calls (Gmail / Drive / Calendar
29
+ * etc.) install `googleapis` separately.
30
+ *
31
+ * Provider-specific defaults the framework's contract doesn't
32
+ * model:
33
+ * - `access_type: "offline"` — required to receive a refresh
34
+ * token. Set via `providerOptions` if you want the v3 default
35
+ * behavior.
36
+ * - `prompt: "consent"` — forces re-consent so a fresh refresh
37
+ * token is reissued even when the user has already granted
38
+ * access. Useful for "reconnect" flows.
39
+ * - `include_granted_scopes: true` — incremental authorization
40
+ * across multiple Google scopes.
41
+ *
42
+ * Default authorize URL adds `access_type=offline&prompt=consent`
43
+ * automatically — that's the v3 behavior and the most common
44
+ * Google flow. Override via `opts.providerOptions` per-call:
45
+ * ```ts
46
+ * adapter.buildAuthorizationUrl(creds, {
47
+ * state, scopes,
48
+ * providerOptions: { prompt: "select_account" },
49
+ * });
50
+ * ```
51
+ */
52
+
53
+ const AUTHORIZE_ENDPOINT = "https://accounts.google.com/o/oauth2/v2/auth";
54
+ const TOKEN_ENDPOINT = "https://oauth2.googleapis.com/token";
55
+ const USERINFO_ENDPOINT = "https://openidconnect.googleapis.com/v1/userinfo";
56
+ const REVOKE_ENDPOINT = "https://oauth2.googleapis.com/revoke";
57
+
58
+ export interface GoogleOAuthAdapterOptions {
59
+ /** Stable provider identifier. Default `"google"`. */
60
+ providerCode?: string;
61
+ /** Override `fetch` (tests). */
62
+ fetchImpl?: typeof fetch;
63
+ /** Default `access_type`. Default `"offline"` (returns a refresh token). */
64
+ defaultAccessType?: "online" | "offline";
65
+ /** Default `prompt`. Default `"consent"` (forces fresh refresh token). */
66
+ defaultPrompt?: "none" | "consent" | "select_account";
67
+ }
68
+
69
+ export class GoogleOAuthAdapter implements OAuthAdapter {
70
+ readonly providerCode: string;
71
+ private readonly fetchImpl: typeof fetch;
72
+ private readonly defaultAccessType: "online" | "offline";
73
+ private readonly defaultPrompt: "none" | "consent" | "select_account";
74
+
75
+ constructor(opts: GoogleOAuthAdapterOptions = {}) {
76
+ this.providerCode = opts.providerCode ?? "google";
77
+ this.fetchImpl = opts.fetchImpl ?? globalThis.fetch;
78
+ this.defaultAccessType = opts.defaultAccessType ?? "offline";
79
+ this.defaultPrompt = opts.defaultPrompt ?? "consent";
80
+ }
81
+
82
+ buildAuthorizationUrl(credentials: OAuthClientCredentials, opts: AuthUrlOptions): string {
83
+ const params = new URLSearchParams({
84
+ client_id: credentials.clientId,
85
+ redirect_uri: credentials.redirectUri,
86
+ response_type: "code",
87
+ scope: opts.scopes.join(" "),
88
+ state: opts.state,
89
+ access_type: this.defaultAccessType,
90
+ prompt: this.defaultPrompt,
91
+ include_granted_scopes: "true",
92
+ });
93
+
94
+ // PKCE: emit challenge params when supplied. Adapters that don't
95
+ // receive a challenge (consumers running against the old contract)
96
+ // still produce a valid URL — the params are simply omitted.
97
+ if (opts.codeChallenge) {
98
+ params.set("code_challenge", opts.codeChallenge);
99
+ params.set("code_challenge_method", opts.codeChallengeMethod ?? "S256");
100
+ }
101
+
102
+ // Provider-specific overrides win.
103
+ if (opts.providerOptions) {
104
+ for (const [key, val] of Object.entries(opts.providerOptions)) {
105
+ params.set(key, String(val));
106
+ }
107
+ }
108
+
109
+ return `${AUTHORIZE_ENDPOINT}?${params.toString()}`;
110
+ }
111
+
112
+ async exchangeCodeForTokens(
113
+ code: string,
114
+ credentials: OAuthClientCredentials,
115
+ opts: ExchangeCodeOptions = {},
116
+ ): Promise<TokenResponse> {
117
+ const formBody = new URLSearchParams({
118
+ code,
119
+ client_id: credentials.clientId,
120
+ client_secret: credentials.clientSecret,
121
+ redirect_uri: credentials.redirectUri,
122
+ grant_type: "authorization_code",
123
+ });
124
+ if (opts.codeVerifier) formBody.set("code_verifier", opts.codeVerifier);
125
+
126
+ const response = await this.fetchImpl(TOKEN_ENDPOINT, {
127
+ method: "POST",
128
+ headers: { "content-type": "application/x-www-form-urlencoded" },
129
+ body: formBody.toString(),
130
+ signal: opts.signal,
131
+ });
132
+
133
+ if (!response.ok) {
134
+ throw this.translateError(response, "exchange");
135
+ }
136
+
137
+ const body = (await response.json()) as GoogleTokenResponse;
138
+ return tokenResponseFromGoogle(body);
139
+ }
140
+
141
+ async refreshTokens(
142
+ refreshToken: string,
143
+ credentials: OAuthClientCredentials,
144
+ opts: { signal?: AbortSignal } = {},
145
+ ): Promise<TokenResponse> {
146
+ const response = await this.fetchImpl(TOKEN_ENDPOINT, {
147
+ method: "POST",
148
+ headers: { "content-type": "application/x-www-form-urlencoded" },
149
+ body: new URLSearchParams({
150
+ refresh_token: refreshToken,
151
+ client_id: credentials.clientId,
152
+ client_secret: credentials.clientSecret,
153
+ grant_type: "refresh_token",
154
+ }).toString(),
155
+ signal: opts.signal,
156
+ });
157
+
158
+ if (!response.ok) {
159
+ throw this.translateError(response, "refresh");
160
+ }
161
+
162
+ const body = (await response.json()) as GoogleTokenResponse;
163
+ // Refresh responses don't always include a fresh refresh_token —
164
+ // when omitted, Google expects callers to keep using the
165
+ // existing one. Pass through what they sent (typically just
166
+ // the new access_token + expires_in).
167
+ return {
168
+ ...tokenResponseFromGoogle(body),
169
+ // Preserve the original refresh token when Google doesn't
170
+ // rotate (most refresh responses don't).
171
+ refreshToken: body.refresh_token ?? refreshToken,
172
+ };
173
+ }
174
+
175
+ async getProviderAccountId(
176
+ tokens: TokenResponse,
177
+ _credentials: OAuthClientCredentials,
178
+ opts: { signal?: AbortSignal } = {},
179
+ ): Promise<string> {
180
+ void _credentials;
181
+ if (!tokens.accessToken) {
182
+ throw new TokenExchangeError(
183
+ this.providerCode,
184
+ "cannot resolve provider account id without an access token",
185
+ );
186
+ }
187
+ const response = await this.fetchImpl(USERINFO_ENDPOINT, {
188
+ headers: { authorization: `Bearer ${tokens.accessToken}` },
189
+ signal: opts.signal,
190
+ });
191
+ if (!response.ok) {
192
+ throw this.translateError(response, "userinfo");
193
+ }
194
+ const body = (await response.json()) as GoogleUserInfo;
195
+ if (!body.sub) {
196
+ throw new TokenExchangeError(this.providerCode, "userinfo response missing `sub` claim");
197
+ }
198
+ return body.sub;
199
+ }
200
+
201
+ async revokeAccess(
202
+ accessToken: string,
203
+ _credentials: OAuthClientCredentials,
204
+ opts: { signal?: AbortSignal } = {},
205
+ ): Promise<void> {
206
+ void _credentials;
207
+ // Google's revoke endpoint accepts the token via querystring.
208
+ // Failures are best-effort; the routes layer doesn't abort the
209
+ // local clear when revoke throws (per OAuthAdapter contract).
210
+ await this.fetchImpl(`${REVOKE_ENDPOINT}?token=${encodeURIComponent(accessToken)}`, {
211
+ method: "POST",
212
+ signal: opts.signal,
213
+ });
214
+ }
215
+
216
+ private translateError(
217
+ response: Response,
218
+ operation: "exchange" | "refresh" | "userinfo",
219
+ ): Error {
220
+ if (response.status === 401) {
221
+ return new InvalidCredentialsError(
222
+ this.providerCode,
223
+ `Google ${operation}: invalid credentials (401)`,
224
+ );
225
+ }
226
+ if (response.status === 429) {
227
+ const retryAfter = response.headers.get("retry-after");
228
+ return new OAuthRateLimitError(
229
+ this.providerCode,
230
+ `Google ${operation}: rate limit (429)`,
231
+ retryAfter ? Number.parseInt(retryAfter, 10) : undefined,
232
+ );
233
+ }
234
+ if (operation === "exchange") {
235
+ return new TokenExchangeError(
236
+ this.providerCode,
237
+ `Google ${operation}: ${response.status} ${response.statusText}`,
238
+ );
239
+ }
240
+ return new TokenRefreshError(
241
+ this.providerCode,
242
+ `Google ${operation}: ${response.status} ${response.statusText}`,
243
+ );
244
+ }
245
+ }
246
+
247
+ // ─── Internal types ────────────────────────────────────────────────────
248
+
249
+ interface GoogleTokenResponse {
250
+ access_token: string;
251
+ refresh_token?: string;
252
+ expires_in?: number;
253
+ scope?: string;
254
+ token_type?: string;
255
+ id_token?: string;
256
+ }
257
+
258
+ interface GoogleUserInfo {
259
+ sub: string;
260
+ email?: string;
261
+ email_verified?: boolean;
262
+ name?: string;
263
+ picture?: string;
264
+ }
265
+
266
+ function tokenResponseFromGoogle(body: GoogleTokenResponse): TokenResponse {
267
+ return {
268
+ accessToken: body.access_token,
269
+ refreshToken: body.refresh_token,
270
+ expiresAt:
271
+ body.expires_in !== undefined ? new Date(Date.now() + body.expires_in * 1000) : undefined,
272
+ scope: body.scope,
273
+ tokenType: body.token_type,
274
+ metadata: {
275
+ ...(body.id_token ? { id_token: body.id_token } : {}),
276
+ },
277
+ };
278
+ }
@@ -0,0 +1,269 @@
1
+ import type {
2
+ AuthUrlOptions,
3
+ ExchangeCodeOptions,
4
+ OAuthAdapter,
5
+ OAuthClientCredentials,
6
+ TokenResponse,
7
+ } from "./OAuthAdapter.js";
8
+ import {
9
+ InvalidCredentialsError,
10
+ OAuthRateLimitError,
11
+ TokenExchangeError,
12
+ TokenRefreshError,
13
+ } from "./OAuthAdapter.js";
14
+
15
+ /**
16
+ * Microsoft / Azure AD OAuth 2.0 adapter — fetch-based, no SDK.
17
+ *
18
+ * Implements the framework's `OAuthAdapter` interface against
19
+ * Microsoft's v2.0 endpoints directly:
20
+ * - Authorization: https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
21
+ * - Token exchange: https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
22
+ * - User info: https://graph.microsoft.com/v1.0/me
23
+ * - Revoke: standard OAuth 2.0 has no Microsoft revoke endpoint.
24
+ * `revokeAccess` is a best-effort no-op (returns silently); the
25
+ * routes layer's local clear runs unconditionally per the
26
+ * `OAuthAdapter` contract.
27
+ *
28
+ * Tenant handling: defaults to `"common"` (multi-tenant apps —
29
+ * accepts personal MS accounts + work accounts). Override via
30
+ * `tenant` in the constructor for single-tenant deployments
31
+ * (`new MicrosoftOAuthAdapter({ tenant: "contoso.onmicrosoft.com" })`)
32
+ * or per-call via `opts.providerOptions.tenant` on `buildAuthorizationUrl`.
33
+ *
34
+ * Microsoft's `provider_account_id` resolves from the Graph `/me`
35
+ * endpoint's `id` field — a stable directory object identifier
36
+ * suitable for cross-session linkage. The `oid` claim from the
37
+ * id_token is equivalent for token-only resolution paths.
38
+ */
39
+
40
+ const AUTHORIZE_PATH = "/oauth2/v2.0/authorize";
41
+ const TOKEN_PATH = "/oauth2/v2.0/token";
42
+ const ME_ENDPOINT = "https://graph.microsoft.com/v1.0/me";
43
+
44
+ export interface MicrosoftOAuthAdapterOptions {
45
+ /** Stable provider identifier. Default `"microsoft"`. */
46
+ providerCode?: string;
47
+ /**
48
+ * Microsoft tenant. Default `"common"` (multi-tenant). Use
49
+ * `"organizations"` to restrict to work/school accounts,
50
+ * `"consumers"` for personal MS accounts only, or a tenant ID /
51
+ * domain for a single-tenant app.
52
+ */
53
+ tenant?: string;
54
+ /** Override `fetch` (tests). */
55
+ fetchImpl?: typeof fetch;
56
+ }
57
+
58
+ export class MicrosoftOAuthAdapter implements OAuthAdapter {
59
+ readonly providerCode: string;
60
+ private readonly tenant: string;
61
+ private readonly fetchImpl: typeof fetch;
62
+
63
+ constructor(opts: MicrosoftOAuthAdapterOptions = {}) {
64
+ this.providerCode = opts.providerCode ?? "microsoft";
65
+ this.tenant = opts.tenant ?? "common";
66
+ this.fetchImpl = opts.fetchImpl ?? globalThis.fetch;
67
+ }
68
+
69
+ buildAuthorizationUrl(credentials: OAuthClientCredentials, opts: AuthUrlOptions): string {
70
+ const tenant = this.resolveTenant(opts.providerOptions);
71
+ const params = new URLSearchParams({
72
+ client_id: credentials.clientId,
73
+ redirect_uri: credentials.redirectUri,
74
+ response_type: "code",
75
+ scope: opts.scopes.join(" "),
76
+ state: opts.state,
77
+ response_mode: "query",
78
+ });
79
+
80
+ // PKCE: emit challenge params when supplied (F12).
81
+ if (opts.codeChallenge) {
82
+ params.set("code_challenge", opts.codeChallenge);
83
+ params.set("code_challenge_method", opts.codeChallengeMethod ?? "S256");
84
+ }
85
+
86
+ // Pass-through provider options excluding `tenant` (consumed above).
87
+ if (opts.providerOptions) {
88
+ for (const [key, val] of Object.entries(opts.providerOptions)) {
89
+ if (key === "tenant") continue;
90
+ params.set(key, String(val));
91
+ }
92
+ }
93
+
94
+ return `https://login.microsoftonline.com/${encodeURIComponent(tenant)}${AUTHORIZE_PATH}?${params.toString()}`;
95
+ }
96
+
97
+ async exchangeCodeForTokens(
98
+ code: string,
99
+ credentials: OAuthClientCredentials,
100
+ opts: ExchangeCodeOptions = {},
101
+ ): Promise<TokenResponse> {
102
+ const url = this.tokenUrl();
103
+ const formBody = new URLSearchParams({
104
+ code,
105
+ client_id: credentials.clientId,
106
+ client_secret: credentials.clientSecret,
107
+ redirect_uri: credentials.redirectUri,
108
+ grant_type: "authorization_code",
109
+ });
110
+ if (opts.codeVerifier) formBody.set("code_verifier", opts.codeVerifier);
111
+
112
+ const response = await this.fetchImpl(url, {
113
+ method: "POST",
114
+ headers: { "content-type": "application/x-www-form-urlencoded" },
115
+ body: formBody.toString(),
116
+ signal: opts.signal,
117
+ });
118
+
119
+ if (!response.ok) {
120
+ throw this.translateError(response, "exchange");
121
+ }
122
+
123
+ const body = (await response.json()) as MicrosoftTokenResponse;
124
+ return tokenResponseFromMicrosoft(body);
125
+ }
126
+
127
+ async refreshTokens(
128
+ refreshToken: string,
129
+ credentials: OAuthClientCredentials,
130
+ opts: { signal?: AbortSignal } = {},
131
+ ): Promise<TokenResponse> {
132
+ const url = this.tokenUrl();
133
+ const response = await this.fetchImpl(url, {
134
+ method: "POST",
135
+ headers: { "content-type": "application/x-www-form-urlencoded" },
136
+ body: new URLSearchParams({
137
+ refresh_token: refreshToken,
138
+ client_id: credentials.clientId,
139
+ client_secret: credentials.clientSecret,
140
+ grant_type: "refresh_token",
141
+ }).toString(),
142
+ signal: opts.signal,
143
+ });
144
+
145
+ if (!response.ok) {
146
+ throw this.translateError(response, "refresh");
147
+ }
148
+
149
+ const body = (await response.json()) as MicrosoftTokenResponse;
150
+ // Microsoft typically rotates refresh tokens on refresh; pass
151
+ // through what they send. Fall back to the original on the
152
+ // off-chance Microsoft omits it (consistent with Google's
153
+ // behavior for the same edge case).
154
+ return {
155
+ ...tokenResponseFromMicrosoft(body),
156
+ refreshToken: body.refresh_token ?? refreshToken,
157
+ };
158
+ }
159
+
160
+ async getProviderAccountId(
161
+ tokens: TokenResponse,
162
+ _credentials: OAuthClientCredentials,
163
+ opts: { signal?: AbortSignal } = {},
164
+ ): Promise<string> {
165
+ void _credentials;
166
+ if (!tokens.accessToken) {
167
+ throw new TokenExchangeError(
168
+ this.providerCode,
169
+ "cannot resolve provider account id without an access token",
170
+ );
171
+ }
172
+ const response = await this.fetchImpl(ME_ENDPOINT, {
173
+ headers: { authorization: `Bearer ${tokens.accessToken}` },
174
+ signal: opts.signal,
175
+ });
176
+ if (!response.ok) {
177
+ throw this.translateError(response, "userinfo");
178
+ }
179
+ const body = (await response.json()) as MicrosoftMeResponse;
180
+ if (!body.id) {
181
+ throw new TokenExchangeError(this.providerCode, "Graph /me response missing `id` field");
182
+ }
183
+ return body.id;
184
+ }
185
+
186
+ // Microsoft has no token-revoke endpoint in OAuth 2.0. Best-effort
187
+ // no-op per the OAuthAdapter contract; the routes layer's local
188
+ // clear runs regardless.
189
+ async revokeAccess(): Promise<void> {
190
+ return;
191
+ }
192
+
193
+ // ─── Internals ──────────────────────────────────────────────────────
194
+
195
+ private resolveTenant(providerOptions: AuthUrlOptions["providerOptions"]): string {
196
+ const override = providerOptions?.tenant;
197
+ if (typeof override === "string" && override.length > 0) return override;
198
+ return this.tenant;
199
+ }
200
+
201
+ private tokenUrl(tenantOverride?: string): string {
202
+ const tenant = tenantOverride ?? this.tenant;
203
+ return `https://login.microsoftonline.com/${encodeURIComponent(tenant)}${TOKEN_PATH}`;
204
+ }
205
+
206
+ private translateError(
207
+ response: Response,
208
+ operation: "exchange" | "refresh" | "userinfo",
209
+ ): Error {
210
+ if (response.status === 401) {
211
+ return new InvalidCredentialsError(
212
+ this.providerCode,
213
+ `Microsoft ${operation}: invalid credentials (401)`,
214
+ );
215
+ }
216
+ if (response.status === 429) {
217
+ const retryAfter = response.headers.get("retry-after");
218
+ return new OAuthRateLimitError(
219
+ this.providerCode,
220
+ `Microsoft ${operation}: rate limit (429)`,
221
+ retryAfter ? Number.parseInt(retryAfter, 10) : undefined,
222
+ );
223
+ }
224
+ if (operation === "exchange") {
225
+ return new TokenExchangeError(
226
+ this.providerCode,
227
+ `Microsoft ${operation}: ${response.status} ${response.statusText}`,
228
+ );
229
+ }
230
+ return new TokenRefreshError(
231
+ this.providerCode,
232
+ `Microsoft ${operation}: ${response.status} ${response.statusText}`,
233
+ );
234
+ }
235
+ }
236
+
237
+ // ─── Internal types ────────────────────────────────────────────────────
238
+
239
+ interface MicrosoftTokenResponse {
240
+ token_type?: string;
241
+ scope?: string;
242
+ expires_in?: number;
243
+ ext_expires_in?: number;
244
+ access_token: string;
245
+ refresh_token?: string;
246
+ id_token?: string;
247
+ }
248
+
249
+ interface MicrosoftMeResponse {
250
+ id?: string;
251
+ userPrincipalName?: string;
252
+ mail?: string;
253
+ displayName?: string;
254
+ }
255
+
256
+ function tokenResponseFromMicrosoft(body: MicrosoftTokenResponse): TokenResponse {
257
+ return {
258
+ accessToken: body.access_token,
259
+ refreshToken: body.refresh_token,
260
+ expiresAt:
261
+ body.expires_in !== undefined ? new Date(Date.now() + body.expires_in * 1000) : undefined,
262
+ scope: body.scope,
263
+ tokenType: body.token_type,
264
+ metadata: {
265
+ ...(body.id_token ? { id_token: body.id_token } : {}),
266
+ ...(body.ext_expires_in !== undefined ? { ext_expires_in: body.ext_expires_in } : {}),
267
+ },
268
+ };
269
+ }