@shipfox/api-auth 2.0.0

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 (319) hide show
  1. package/.turbo/turbo-build.log +2 -0
  2. package/.turbo/turbo-type$colon$emit.log +1 -0
  3. package/.turbo/turbo-type.log +1 -0
  4. package/CHANGELOG.md +116 -0
  5. package/LICENSE +21 -0
  6. package/README.md +336 -0
  7. package/dist/config.d.ts +22 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +95 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/core/auth.d.ts +108 -0
  12. package/dist/core/auth.d.ts.map +1 -0
  13. package/dist/core/auth.js +476 -0
  14. package/dist/core/auth.js.map +1 -0
  15. package/dist/core/entities/email-verification.d.ts +9 -0
  16. package/dist/core/entities/email-verification.d.ts.map +1 -0
  17. package/dist/core/entities/email-verification.js +3 -0
  18. package/dist/core/entities/email-verification.js.map +1 -0
  19. package/dist/core/entities/password-reset.d.ts +9 -0
  20. package/dist/core/entities/password-reset.d.ts.map +1 -0
  21. package/dist/core/entities/password-reset.js +3 -0
  22. package/dist/core/entities/password-reset.js.map +1 -0
  23. package/dist/core/entities/refresh-token.d.ts +12 -0
  24. package/dist/core/entities/refresh-token.d.ts.map +1 -0
  25. package/dist/core/entities/refresh-token.js +3 -0
  26. package/dist/core/entities/refresh-token.js.map +1 -0
  27. package/dist/core/entities/user.d.ts +12 -0
  28. package/dist/core/entities/user.d.ts.map +1 -0
  29. package/dist/core/entities/user.js +3 -0
  30. package/dist/core/entities/user.js.map +1 -0
  31. package/dist/core/errors.d.ts +54 -0
  32. package/dist/core/errors.d.ts.map +1 -0
  33. package/dist/core/errors.js +106 -0
  34. package/dist/core/errors.js.map +1 -0
  35. package/dist/core/job-lease-token.d.ts +12 -0
  36. package/dist/core/job-lease-token.d.ts.map +1 -0
  37. package/dist/core/job-lease-token.js +58 -0
  38. package/dist/core/job-lease-token.js.map +1 -0
  39. package/dist/core/jwt.d.ts +37 -0
  40. package/dist/core/jwt.d.ts.map +1 -0
  41. package/dist/core/jwt.js +46 -0
  42. package/dist/core/jwt.js.map +1 -0
  43. package/dist/core/password.d.ts +10 -0
  44. package/dist/core/password.d.ts.map +1 -0
  45. package/dist/core/password.js +13 -0
  46. package/dist/core/password.js.map +1 -0
  47. package/dist/core/rate-limit.d.ts +34 -0
  48. package/dist/core/rate-limit.d.ts.map +1 -0
  49. package/dist/core/rate-limit.js +76 -0
  50. package/dist/core/rate-limit.js.map +1 -0
  51. package/dist/core/runner-session-token.d.ts +6 -0
  52. package/dist/core/runner-session-token.d.ts.map +1 -0
  53. package/dist/core/runner-session-token.js +37 -0
  54. package/dist/core/runner-session-token.js.map +1 -0
  55. package/dist/db/db.d.ts +1723 -0
  56. package/dist/db/db.d.ts.map +1 -0
  57. package/dist/db/db.js +28 -0
  58. package/dist/db/db.js.map +1 -0
  59. package/dist/db/email-verifications.d.ts +39 -0
  60. package/dist/db/email-verifications.d.ts.map +1 -0
  61. package/dist/db/email-verifications.js +95 -0
  62. package/dist/db/email-verifications.js.map +1 -0
  63. package/dist/db/migrations.d.ts +2 -0
  64. package/dist/db/migrations.d.ts.map +1 -0
  65. package/dist/db/migrations.js +5 -0
  66. package/dist/db/migrations.js.map +1 -0
  67. package/dist/db/password-resets.d.ts +23 -0
  68. package/dist/db/password-resets.d.ts.map +1 -0
  69. package/dist/db/password-resets.js +37 -0
  70. package/dist/db/password-resets.js.map +1 -0
  71. package/dist/db/rate-limits.d.ts +18 -0
  72. package/dist/db/rate-limits.d.ts.map +1 -0
  73. package/dist/db/rate-limits.js +44 -0
  74. package/dist/db/rate-limits.js.map +1 -0
  75. package/dist/db/refresh-tokens.d.ts +44 -0
  76. package/dist/db/refresh-tokens.d.ts.map +1 -0
  77. package/dist/db/refresh-tokens.js +71 -0
  78. package/dist/db/refresh-tokens.js.map +1 -0
  79. package/dist/db/schema/common.d.ts +2 -0
  80. package/dist/db/schema/common.d.ts.map +1 -0
  81. package/dist/db/schema/common.js +4 -0
  82. package/dist/db/schema/common.js.map +1 -0
  83. package/dist/db/schema/email-verifications.d.ts +114 -0
  84. package/dist/db/schema/email-verifications.d.ts.map +1 -0
  85. package/dist/db/schema/email-verifications.js +35 -0
  86. package/dist/db/schema/email-verifications.js.map +1 -0
  87. package/dist/db/schema/outbox.d.ts +195 -0
  88. package/dist/db/schema/outbox.d.ts.map +1 -0
  89. package/dist/db/schema/outbox.js +5 -0
  90. package/dist/db/schema/outbox.js.map +1 -0
  91. package/dist/db/schema/password-resets.d.ts +114 -0
  92. package/dist/db/schema/password-resets.d.ts.map +1 -0
  93. package/dist/db/schema/password-resets.js +35 -0
  94. package/dist/db/schema/password-resets.js.map +1 -0
  95. package/dist/db/schema/rate-limits.d.ts +145 -0
  96. package/dist/db/schema/rate-limits.d.ts.map +1 -0
  97. package/dist/db/schema/rate-limits.js +25 -0
  98. package/dist/db/schema/rate-limits.js.map +1 -0
  99. package/dist/db/schema/refresh-tokens.d.ts +165 -0
  100. package/dist/db/schema/refresh-tokens.d.ts.map +1 -0
  101. package/dist/db/schema/refresh-tokens.js +47 -0
  102. package/dist/db/schema/refresh-tokens.js.map +1 -0
  103. package/dist/db/schema/users.d.ts +149 -0
  104. package/dist/db/schema/users.d.ts.map +1 -0
  105. package/dist/db/schema/users.js +40 -0
  106. package/dist/db/schema/users.js.map +1 -0
  107. package/dist/db/users.d.ts +28 -0
  108. package/dist/db/users.d.ts.map +1 -0
  109. package/dist/db/users.js +83 -0
  110. package/dist/db/users.js.map +1 -0
  111. package/dist/index.d.ts +14 -0
  112. package/dist/index.d.ts.map +1 -0
  113. package/dist/index.js +52 -0
  114. package/dist/index.js.map +1 -0
  115. package/dist/metrics/index.d.ts +2 -0
  116. package/dist/metrics/index.d.ts.map +1 -0
  117. package/dist/metrics/index.js +3 -0
  118. package/dist/metrics/index.js.map +1 -0
  119. package/dist/metrics/instance.d.ts +16 -0
  120. package/dist/metrics/instance.d.ts.map +1 -0
  121. package/dist/metrics/instance.js +52 -0
  122. package/dist/metrics/instance.js.map +1 -0
  123. package/dist/presentation/auth/bearer-token-auth.d.ts +15 -0
  124. package/dist/presentation/auth/bearer-token-auth.d.ts.map +1 -0
  125. package/dist/presentation/auth/bearer-token-auth.js +31 -0
  126. package/dist/presentation/auth/bearer-token-auth.js.map +1 -0
  127. package/dist/presentation/auth/jwt-auth.d.ts +10 -0
  128. package/dist/presentation/auth/jwt-auth.d.ts.map +1 -0
  129. package/dist/presentation/auth/jwt-auth.js +31 -0
  130. package/dist/presentation/auth/jwt-auth.js.map +1 -0
  131. package/dist/presentation/auth/lease-token-auth.d.ts +15 -0
  132. package/dist/presentation/auth/lease-token-auth.d.ts.map +1 -0
  133. package/dist/presentation/auth/lease-token-auth.js +27 -0
  134. package/dist/presentation/auth/lease-token-auth.js.map +1 -0
  135. package/dist/presentation/auth/refresh-cookie.d.ts +7 -0
  136. package/dist/presentation/auth/refresh-cookie.d.ts.map +1 -0
  137. package/dist/presentation/auth/refresh-cookie.js +29 -0
  138. package/dist/presentation/auth/refresh-cookie.js.map +1 -0
  139. package/dist/presentation/auth/runner-session-auth.d.ts +3 -0
  140. package/dist/presentation/auth/runner-session-auth.d.ts.map +1 -0
  141. package/dist/presentation/auth/runner-session-auth.js +16 -0
  142. package/dist/presentation/auth/runner-session-auth.js.map +1 -0
  143. package/dist/presentation/dto/user.d.ts +8 -0
  144. package/dist/presentation/dto/user.d.ts.map +1 -0
  145. package/dist/presentation/dto/user.js +19 -0
  146. package/dist/presentation/dto/user.js.map +1 -0
  147. package/dist/presentation/e2eRoutes/create-session.d.ts +2 -0
  148. package/dist/presentation/e2eRoutes/create-session.d.ts.map +1 -0
  149. package/dist/presentation/e2eRoutes/create-session.js +49 -0
  150. package/dist/presentation/e2eRoutes/create-session.js.map +1 -0
  151. package/dist/presentation/e2eRoutes/create-user.d.ts +2 -0
  152. package/dist/presentation/e2eRoutes/create-user.d.ts.map +1 -0
  153. package/dist/presentation/e2eRoutes/create-user.js +42 -0
  154. package/dist/presentation/e2eRoutes/create-user.js.map +1 -0
  155. package/dist/presentation/e2eRoutes/index.d.ts +3 -0
  156. package/dist/presentation/e2eRoutes/index.d.ts.map +1 -0
  157. package/dist/presentation/e2eRoutes/index.js +15 -0
  158. package/dist/presentation/e2eRoutes/index.js.map +1 -0
  159. package/dist/presentation/routes/email-verification/verify-email-confirm.d.ts +2 -0
  160. package/dist/presentation/routes/email-verification/verify-email-confirm.d.ts.map +1 -0
  161. package/dist/presentation/routes/email-verification/verify-email-confirm.js +35 -0
  162. package/dist/presentation/routes/email-verification/verify-email-confirm.js.map +1 -0
  163. package/dist/presentation/routes/email-verification/verify-email-resend.d.ts +2 -0
  164. package/dist/presentation/routes/email-verification/verify-email-resend.d.ts.map +1 -0
  165. package/dist/presentation/routes/email-verification/verify-email-resend.js +27 -0
  166. package/dist/presentation/routes/email-verification/verify-email-resend.js.map +1 -0
  167. package/dist/presentation/routes/index.d.ts +3 -0
  168. package/dist/presentation/routes/index.d.ts.map +1 -0
  169. package/dist/presentation/routes/index.js +31 -0
  170. package/dist/presentation/routes/index.js.map +1 -0
  171. package/dist/presentation/routes/password/change-password.d.ts +2 -0
  172. package/dist/presentation/routes/password/change-password.d.ts.map +1 -0
  173. package/dist/presentation/routes/password/change-password.js +50 -0
  174. package/dist/presentation/routes/password/change-password.js.map +1 -0
  175. package/dist/presentation/routes/password/password-reset-confirm.d.ts +2 -0
  176. package/dist/presentation/routes/password/password-reset-confirm.d.ts.map +1 -0
  177. package/dist/presentation/routes/password/password-reset-confirm.js +36 -0
  178. package/dist/presentation/routes/password/password-reset-confirm.js.map +1 -0
  179. package/dist/presentation/routes/password/password-reset-request.d.ts +2 -0
  180. package/dist/presentation/routes/password/password-reset-request.d.ts.map +1 -0
  181. package/dist/presentation/routes/password/password-reset-request.js +26 -0
  182. package/dist/presentation/routes/password/password-reset-request.js.map +1 -0
  183. package/dist/presentation/routes/rate-limit.d.ts +10 -0
  184. package/dist/presentation/routes/rate-limit.d.ts.map +1 -0
  185. package/dist/presentation/routes/rate-limit.js +101 -0
  186. package/dist/presentation/routes/rate-limit.js.map +1 -0
  187. package/dist/presentation/routes/registration/signup.d.ts +2 -0
  188. package/dist/presentation/routes/registration/signup.d.ts.map +1 -0
  189. package/dist/presentation/routes/registration/signup.js +82 -0
  190. package/dist/presentation/routes/registration/signup.js.map +1 -0
  191. package/dist/presentation/routes/session/login.d.ts +2 -0
  192. package/dist/presentation/routes/session/login.d.ts.map +1 -0
  193. package/dist/presentation/routes/session/login.js +48 -0
  194. package/dist/presentation/routes/session/login.js.map +1 -0
  195. package/dist/presentation/routes/session/logout.d.ts +2 -0
  196. package/dist/presentation/routes/session/logout.d.ts.map +1 -0
  197. package/dist/presentation/routes/session/logout.js +25 -0
  198. package/dist/presentation/routes/session/logout.js.map +1 -0
  199. package/dist/presentation/routes/session/me.d.ts +2 -0
  200. package/dist/presentation/routes/session/me.d.ts.map +1 -0
  201. package/dist/presentation/routes/session/me.js +42 -0
  202. package/dist/presentation/routes/session/me.js.map +1 -0
  203. package/dist/presentation/routes/session/refresh.d.ts +2 -0
  204. package/dist/presentation/routes/session/refresh.d.ts.map +1 -0
  205. package/dist/presentation/routes/session/refresh.js +49 -0
  206. package/dist/presentation/routes/session/refresh.js.map +1 -0
  207. package/dist/presentation/subscribers/index.d.ts +3 -0
  208. package/dist/presentation/subscribers/index.d.ts.map +1 -0
  209. package/dist/presentation/subscribers/index.js +4 -0
  210. package/dist/presentation/subscribers/index.js.map +1 -0
  211. package/dist/presentation/subscribers/on-email-verification-send-requested.d.ts +3 -0
  212. package/dist/presentation/subscribers/on-email-verification-send-requested.d.ts.map +1 -0
  213. package/dist/presentation/subscribers/on-email-verification-send-requested.js +13 -0
  214. package/dist/presentation/subscribers/on-email-verification-send-requested.js.map +1 -0
  215. package/dist/presentation/subscribers/on-password-reset-send-requested.d.ts +3 -0
  216. package/dist/presentation/subscribers/on-password-reset-send-requested.d.ts.map +1 -0
  217. package/dist/presentation/subscribers/on-password-reset-send-requested.js +14 -0
  218. package/dist/presentation/subscribers/on-password-reset-send-requested.js.map +1 -0
  219. package/dist/tsconfig.test.tsbuildinfo +1 -0
  220. package/drizzle/0000_initial.sql +81 -0
  221. package/drizzle/meta/0000_snapshot.json +643 -0
  222. package/drizzle/meta/_journal.json +13 -0
  223. package/drizzle.config.ts +7 -0
  224. package/package.json +88 -0
  225. package/src/config.ts +88 -0
  226. package/src/core/auth.test.ts +675 -0
  227. package/src/core/auth.ts +560 -0
  228. package/src/core/entities/email-verification.ts +8 -0
  229. package/src/core/entities/password-reset.ts +8 -0
  230. package/src/core/entities/refresh-token.ts +11 -0
  231. package/src/core/entities/user.ts +12 -0
  232. package/src/core/errors.ts +123 -0
  233. package/src/core/job-lease-token.test.ts +201 -0
  234. package/src/core/job-lease-token.ts +83 -0
  235. package/src/core/jwt.test.ts +180 -0
  236. package/src/core/jwt.ts +66 -0
  237. package/src/core/password.test.ts +28 -0
  238. package/src/core/password.ts +21 -0
  239. package/src/core/rate-limit.test.ts +462 -0
  240. package/src/core/rate-limit.ts +130 -0
  241. package/src/core/runner-session-token.test.ts +126 -0
  242. package/src/core/runner-session-token.ts +49 -0
  243. package/src/db/db.ts +28 -0
  244. package/src/db/email-verifications.test.ts +61 -0
  245. package/src/db/email-verifications.ts +160 -0
  246. package/src/db/migrations.ts +4 -0
  247. package/src/db/password-resets.test.ts +61 -0
  248. package/src/db/password-resets.ts +69 -0
  249. package/src/db/rate-limits.ts +69 -0
  250. package/src/db/refresh-tokens.test.ts +164 -0
  251. package/src/db/refresh-tokens.ts +149 -0
  252. package/src/db/schema/common.ts +3 -0
  253. package/src/db/schema/email-verifications.ts +37 -0
  254. package/src/db/schema/outbox.ts +4 -0
  255. package/src/db/schema/password-resets.ts +37 -0
  256. package/src/db/schema/rate-limits.ts +27 -0
  257. package/src/db/schema/refresh-tokens.ts +43 -0
  258. package/src/db/schema/users.ts +37 -0
  259. package/src/db/users.test.ts +75 -0
  260. package/src/db/users.ts +121 -0
  261. package/src/index.test.ts +39 -0
  262. package/src/index.ts +69 -0
  263. package/src/metrics/index.ts +13 -0
  264. package/src/metrics/instance.test.ts +69 -0
  265. package/src/metrics/instance.ts +77 -0
  266. package/src/presentation/auth/bearer-token-auth.test.ts +99 -0
  267. package/src/presentation/auth/bearer-token-auth.ts +51 -0
  268. package/src/presentation/auth/jwt-auth.test.ts +136 -0
  269. package/src/presentation/auth/jwt-auth.ts +39 -0
  270. package/src/presentation/auth/lease-token-auth.test.ts +56 -0
  271. package/src/presentation/auth/lease-token-auth.ts +25 -0
  272. package/src/presentation/auth/refresh-cookie.test.ts +39 -0
  273. package/src/presentation/auth/refresh-cookie.ts +34 -0
  274. package/src/presentation/auth/runner-session-auth.test.ts +54 -0
  275. package/src/presentation/auth/runner-session-auth.ts +13 -0
  276. package/src/presentation/dto/user.ts +21 -0
  277. package/src/presentation/e2eRoutes/create-session.ts +39 -0
  278. package/src/presentation/e2eRoutes/create-user.ts +38 -0
  279. package/src/presentation/e2eRoutes/index.test.ts +102 -0
  280. package/src/presentation/e2eRoutes/index.ts +10 -0
  281. package/src/presentation/routes/email-verification/verify-email-confirm.test.ts +66 -0
  282. package/src/presentation/routes/email-verification/verify-email-confirm.ts +37 -0
  283. package/src/presentation/routes/email-verification/verify-email-resend.test.ts +100 -0
  284. package/src/presentation/routes/email-verification/verify-email-resend.ts +26 -0
  285. package/src/presentation/routes/index.ts +29 -0
  286. package/src/presentation/routes/password/change-password.test.ts +106 -0
  287. package/src/presentation/routes/password/change-password.ts +45 -0
  288. package/src/presentation/routes/password/password-reset-confirm.test.ts +63 -0
  289. package/src/presentation/routes/password/password-reset-confirm.ts +35 -0
  290. package/src/presentation/routes/password/password-reset-request.test.ts +56 -0
  291. package/src/presentation/routes/password/password-reset-request.ts +25 -0
  292. package/src/presentation/routes/rate-limit.test.ts +341 -0
  293. package/src/presentation/routes/rate-limit.ts +119 -0
  294. package/src/presentation/routes/registration/signup.test.ts +284 -0
  295. package/src/presentation/routes/registration/signup.ts +81 -0
  296. package/src/presentation/routes/session/login.test.ts +77 -0
  297. package/src/presentation/routes/session/login.ts +50 -0
  298. package/src/presentation/routes/session/logout.test.ts +55 -0
  299. package/src/presentation/routes/session/logout.ts +23 -0
  300. package/src/presentation/routes/session/me.test.ts +56 -0
  301. package/src/presentation/routes/session/me.ts +35 -0
  302. package/src/presentation/routes/session/refresh.test.ts +89 -0
  303. package/src/presentation/routes/session/refresh.ts +54 -0
  304. package/src/presentation/subscribers/email-send-requested.test.ts +77 -0
  305. package/src/presentation/subscribers/index.ts +2 -0
  306. package/src/presentation/subscribers/on-email-verification-send-requested.ts +10 -0
  307. package/src/presentation/subscribers/on-password-reset-send-requested.ts +13 -0
  308. package/test/env.ts +10 -0
  309. package/test/factories/index.ts +1 -0
  310. package/test/factories/user.ts +36 -0
  311. package/test/globalSetup.ts +18 -0
  312. package/test/index.ts +1 -0
  313. package/test/routes.ts +275 -0
  314. package/test/setup.ts +17 -0
  315. package/tsconfig.build.json +9 -0
  316. package/tsconfig.build.tsbuildinfo +1 -0
  317. package/tsconfig.json +4 -0
  318. package/tsconfig.test.json +8 -0
  319. package/vitest.config.ts +11 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/core/entities/email-verification.ts"],"sourcesContent":["export interface EmailVerification {\n id: string;\n userId: string;\n hashedToken: string;\n expiresAt: Date;\n usedAt: Date | null;\n createdAt: Date;\n}\n"],"names":[],"mappings":"AAAA,WAOC"}
@@ -0,0 +1,9 @@
1
+ export interface PasswordReset {
2
+ id: string;
3
+ userId: string;
4
+ hashedToken: string;
5
+ expiresAt: Date;
6
+ usedAt: Date | null;
7
+ createdAt: Date;
8
+ }
9
+ //# sourceMappingURL=password-reset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password-reset.d.ts","sourceRoot":"","sources":["../../../src/core/entities/password-reset.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,IAAI,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,IAAI,CAAC;CACjB"}
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=password-reset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/core/entities/password-reset.ts"],"sourcesContent":["export interface PasswordReset {\n id: string;\n userId: string;\n hashedToken: string;\n expiresAt: Date;\n usedAt: Date | null;\n createdAt: Date;\n}\n"],"names":[],"mappings":"AAAA,WAOC"}
@@ -0,0 +1,12 @@
1
+ export interface RefreshToken {
2
+ id: string;
3
+ userId: string;
4
+ hashedToken: string;
5
+ expiresAt: Date;
6
+ revokedAt: Date | null;
7
+ rotatedAt: Date | null;
8
+ lastUsedAt: Date | null;
9
+ createdAt: Date;
10
+ updatedAt: Date;
11
+ }
12
+ //# sourceMappingURL=refresh-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh-token.d.ts","sourceRoot":"","sources":["../../../src/core/entities/refresh-token.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB"}
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=refresh-token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/core/entities/refresh-token.ts"],"sourcesContent":["export interface RefreshToken {\n id: string;\n userId: string;\n hashedToken: string;\n expiresAt: Date;\n revokedAt: Date | null;\n rotatedAt: Date | null;\n lastUsedAt: Date | null;\n createdAt: Date;\n updatedAt: Date;\n}\n"],"names":[],"mappings":"AAAA,WAUC"}
@@ -0,0 +1,12 @@
1
+ export type UserStatus = 'active' | 'suspended' | 'deleted';
2
+ export interface User {
3
+ id: string;
4
+ email: string;
5
+ hashedPassword: string | null;
6
+ name: string | null;
7
+ emailVerifiedAt: Date | null;
8
+ status: UserStatus;
9
+ createdAt: Date;
10
+ updatedAt: Date;
11
+ }
12
+ //# sourceMappingURL=user.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../../src/core/entities/user.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;AAE5D,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,eAAe,EAAE,IAAI,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB"}
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=user.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/core/entities/user.ts"],"sourcesContent":["export type UserStatus = 'active' | 'suspended' | 'deleted';\n\nexport interface User {\n id: string;\n email: string;\n hashedPassword: string | null;\n name: string | null;\n emailVerifiedAt: Date | null;\n status: UserStatus;\n createdAt: Date;\n updatedAt: Date;\n}\n"],"names":[],"mappings":"AAEA,WASC"}
@@ -0,0 +1,54 @@
1
+ export declare class WorkspaceNotFoundError extends Error {
2
+ constructor(workspaceId: string);
3
+ }
4
+ export declare class ApiKeyNotFoundError extends Error {
5
+ constructor(id: string);
6
+ }
7
+ export declare class InvitationNotFoundError extends Error {
8
+ constructor(id: string);
9
+ }
10
+ export declare class InvitationWorkspaceMismatchError extends Error {
11
+ constructor();
12
+ }
13
+ export declare class MembershipNotFoundError extends Error {
14
+ constructor(userId: string, workspaceId: string);
15
+ }
16
+ export declare class UserNotFoundError extends Error {
17
+ constructor(idOrEmail: string);
18
+ }
19
+ export declare class EmailTakenError extends Error {
20
+ constructor(email: string);
21
+ }
22
+ export declare class InvalidCredentialsError extends Error {
23
+ constructor();
24
+ }
25
+ export declare class EmailNotVerifiedError extends Error {
26
+ constructor();
27
+ }
28
+ export declare class AuthDependencyUnavailableError extends Error {
29
+ readonly dependency: string;
30
+ readonly cause: unknown;
31
+ constructor(dependency: string, cause: unknown);
32
+ }
33
+ export declare class TokenInvalidError extends Error {
34
+ constructor(reason?: string);
35
+ }
36
+ export declare class TokenExpiredError extends Error {
37
+ constructor();
38
+ }
39
+ export declare class TokenAlreadyUsedError extends Error {
40
+ constructor();
41
+ }
42
+ export declare class MembershipRequiredError extends Error {
43
+ constructor(workspaceId: string);
44
+ }
45
+ export declare class LastMemberError extends Error {
46
+ constructor(workspaceId: string);
47
+ }
48
+ export declare class InvitationEmailMismatchError extends Error {
49
+ constructor();
50
+ }
51
+ export declare class OpenInvitationExistsError extends Error {
52
+ constructor(email: string);
53
+ }
54
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,EAAE,EAAE,MAAM;CAIvB;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,EAAE,EAAE,MAAM;CAIvB;AAED,qBAAa,gCAAiC,SAAQ,KAAK;;CAK1D;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;CAIhD;AAED,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,SAAS,EAAE,MAAM;CAI9B;AAED,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,KAAK,EAAE,MAAM;CAI1B;AAED,qBAAa,uBAAwB,SAAQ,KAAK;;CAKjD;AAED,qBAAa,qBAAsB,SAAQ,KAAK;;CAK/C;AAED,qBAAa,8BAA+B,SAAQ,KAAK;IACvD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,SAAkB,KAAK,EAAE,OAAO,CAAC;gBAErB,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAM/C;AAED,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,MAAM,CAAC,EAAE,MAAM;CAI5B;AAED,qBAAa,iBAAkB,SAAQ,KAAK;;CAK3C;AAED,qBAAa,qBAAsB,SAAQ,KAAK;;CAK/C;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,4BAA6B,SAAQ,KAAK;;CAKtD;AAED,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,KAAK,EAAE,MAAM;CAI1B"}
@@ -0,0 +1,106 @@
1
+ export class WorkspaceNotFoundError extends Error {
2
+ constructor(workspaceId){
3
+ super(`Workspace not found: ${workspaceId}`);
4
+ this.name = 'WorkspaceNotFoundError';
5
+ }
6
+ }
7
+ export class ApiKeyNotFoundError extends Error {
8
+ constructor(id){
9
+ super(`API key not found: ${id}`);
10
+ this.name = 'ApiKeyNotFoundError';
11
+ }
12
+ }
13
+ export class InvitationNotFoundError extends Error {
14
+ constructor(id){
15
+ super(`Invitation not found: ${id}`);
16
+ this.name = 'InvitationNotFoundError';
17
+ }
18
+ }
19
+ export class InvitationWorkspaceMismatchError extends Error {
20
+ constructor(){
21
+ super('Invitation does not belong to this workspace');
22
+ this.name = 'InvitationWorkspaceMismatchError';
23
+ }
24
+ }
25
+ export class MembershipNotFoundError extends Error {
26
+ constructor(userId, workspaceId){
27
+ super(`Membership not found for user ${userId} in workspace ${workspaceId}`);
28
+ this.name = 'MembershipNotFoundError';
29
+ }
30
+ }
31
+ export class UserNotFoundError extends Error {
32
+ constructor(idOrEmail){
33
+ super(`User not found: ${idOrEmail}`);
34
+ this.name = 'UserNotFoundError';
35
+ }
36
+ }
37
+ export class EmailTakenError extends Error {
38
+ constructor(email){
39
+ super(`Email already registered: ${email}`);
40
+ this.name = 'EmailTakenError';
41
+ }
42
+ }
43
+ export class InvalidCredentialsError extends Error {
44
+ constructor(){
45
+ super('Invalid credentials');
46
+ this.name = 'InvalidCredentialsError';
47
+ }
48
+ }
49
+ export class EmailNotVerifiedError extends Error {
50
+ constructor(){
51
+ super('Email not verified');
52
+ this.name = 'EmailNotVerifiedError';
53
+ }
54
+ }
55
+ export class AuthDependencyUnavailableError extends Error {
56
+ constructor(dependency, cause){
57
+ super(`Authentication dependency unavailable: ${dependency}`);
58
+ this.name = 'AuthDependencyUnavailableError';
59
+ this.dependency = dependency;
60
+ this.cause = cause;
61
+ }
62
+ }
63
+ export class TokenInvalidError extends Error {
64
+ constructor(reason){
65
+ super(reason ? `Invalid token: ${reason}` : 'Invalid token');
66
+ this.name = 'TokenInvalidError';
67
+ }
68
+ }
69
+ export class TokenExpiredError extends Error {
70
+ constructor(){
71
+ super('Token has expired');
72
+ this.name = 'TokenExpiredError';
73
+ }
74
+ }
75
+ export class TokenAlreadyUsedError extends Error {
76
+ constructor(){
77
+ super('Token has already been used');
78
+ this.name = 'TokenAlreadyUsedError';
79
+ }
80
+ }
81
+ export class MembershipRequiredError extends Error {
82
+ constructor(workspaceId){
83
+ super(`Membership required for workspace: ${workspaceId}`);
84
+ this.name = 'MembershipRequiredError';
85
+ }
86
+ }
87
+ export class LastMemberError extends Error {
88
+ constructor(workspaceId){
89
+ super(`Cannot remove the last member of workspace: ${workspaceId}`);
90
+ this.name = 'LastMemberError';
91
+ }
92
+ }
93
+ export class InvitationEmailMismatchError extends Error {
94
+ constructor(){
95
+ super('Invitation email does not match authenticated user');
96
+ this.name = 'InvitationEmailMismatchError';
97
+ }
98
+ }
99
+ export class OpenInvitationExistsError extends Error {
100
+ constructor(email){
101
+ super(`An open invitation already exists for: ${email}`);
102
+ this.name = 'OpenInvitationExistsError';
103
+ }
104
+ }
105
+
106
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/errors.ts"],"sourcesContent":["export class WorkspaceNotFoundError extends Error {\n constructor(workspaceId: string) {\n super(`Workspace not found: ${workspaceId}`);\n this.name = 'WorkspaceNotFoundError';\n }\n}\n\nexport class ApiKeyNotFoundError extends Error {\n constructor(id: string) {\n super(`API key not found: ${id}`);\n this.name = 'ApiKeyNotFoundError';\n }\n}\n\nexport class InvitationNotFoundError extends Error {\n constructor(id: string) {\n super(`Invitation not found: ${id}`);\n this.name = 'InvitationNotFoundError';\n }\n}\n\nexport class InvitationWorkspaceMismatchError extends Error {\n constructor() {\n super('Invitation does not belong to this workspace');\n this.name = 'InvitationWorkspaceMismatchError';\n }\n}\n\nexport class MembershipNotFoundError extends Error {\n constructor(userId: string, workspaceId: string) {\n super(`Membership not found for user ${userId} in workspace ${workspaceId}`);\n this.name = 'MembershipNotFoundError';\n }\n}\n\nexport class UserNotFoundError extends Error {\n constructor(idOrEmail: string) {\n super(`User not found: ${idOrEmail}`);\n this.name = 'UserNotFoundError';\n }\n}\n\nexport class EmailTakenError extends Error {\n constructor(email: string) {\n super(`Email already registered: ${email}`);\n this.name = 'EmailTakenError';\n }\n}\n\nexport class InvalidCredentialsError extends Error {\n constructor() {\n super('Invalid credentials');\n this.name = 'InvalidCredentialsError';\n }\n}\n\nexport class EmailNotVerifiedError extends Error {\n constructor() {\n super('Email not verified');\n this.name = 'EmailNotVerifiedError';\n }\n}\n\nexport class AuthDependencyUnavailableError extends Error {\n readonly dependency: string;\n override readonly cause: unknown;\n\n constructor(dependency: string, cause: unknown) {\n super(`Authentication dependency unavailable: ${dependency}`);\n this.name = 'AuthDependencyUnavailableError';\n this.dependency = dependency;\n this.cause = cause;\n }\n}\n\nexport class TokenInvalidError extends Error {\n constructor(reason?: string) {\n super(reason ? `Invalid token: ${reason}` : 'Invalid token');\n this.name = 'TokenInvalidError';\n }\n}\n\nexport class TokenExpiredError extends Error {\n constructor() {\n super('Token has expired');\n this.name = 'TokenExpiredError';\n }\n}\n\nexport class TokenAlreadyUsedError extends Error {\n constructor() {\n super('Token has already been used');\n this.name = 'TokenAlreadyUsedError';\n }\n}\n\nexport class MembershipRequiredError extends Error {\n constructor(workspaceId: string) {\n super(`Membership required for workspace: ${workspaceId}`);\n this.name = 'MembershipRequiredError';\n }\n}\n\nexport class LastMemberError extends Error {\n constructor(workspaceId: string) {\n super(`Cannot remove the last member of workspace: ${workspaceId}`);\n this.name = 'LastMemberError';\n }\n}\n\nexport class InvitationEmailMismatchError extends Error {\n constructor() {\n super('Invitation email does not match authenticated user');\n this.name = 'InvitationEmailMismatchError';\n }\n}\n\nexport class OpenInvitationExistsError extends Error {\n constructor(email: string) {\n super(`An open invitation already exists for: ${email}`);\n this.name = 'OpenInvitationExistsError';\n }\n}\n"],"names":["WorkspaceNotFoundError","Error","workspaceId","name","ApiKeyNotFoundError","id","InvitationNotFoundError","InvitationWorkspaceMismatchError","MembershipNotFoundError","userId","UserNotFoundError","idOrEmail","EmailTakenError","email","InvalidCredentialsError","EmailNotVerifiedError","AuthDependencyUnavailableError","dependency","cause","TokenInvalidError","reason","TokenExpiredError","TokenAlreadyUsedError","MembershipRequiredError","LastMemberError","InvitationEmailMismatchError","OpenInvitationExistsError"],"mappings":"AAAA,OAAO,MAAMA,+BAA+BC;IAC1C,YAAYC,WAAmB,CAAE;QAC/B,KAAK,CAAC,CAAC,qBAAqB,EAAEA,aAAa;QAC3C,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMC,4BAA4BH;IACvC,YAAYI,EAAU,CAAE;QACtB,KAAK,CAAC,CAAC,mBAAmB,EAAEA,IAAI;QAChC,IAAI,CAACF,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMG,gCAAgCL;IAC3C,YAAYI,EAAU,CAAE;QACtB,KAAK,CAAC,CAAC,sBAAsB,EAAEA,IAAI;QACnC,IAAI,CAACF,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMI,yCAAyCN;IACpD,aAAc;QACZ,KAAK,CAAC;QACN,IAAI,CAACE,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMK,gCAAgCP;IAC3C,YAAYQ,MAAc,EAAEP,WAAmB,CAAE;QAC/C,KAAK,CAAC,CAAC,8BAA8B,EAAEO,OAAO,cAAc,EAAEP,aAAa;QAC3E,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMO,0BAA0BT;IACrC,YAAYU,SAAiB,CAAE;QAC7B,KAAK,CAAC,CAAC,gBAAgB,EAAEA,WAAW;QACpC,IAAI,CAACR,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMS,wBAAwBX;IACnC,YAAYY,KAAa,CAAE;QACzB,KAAK,CAAC,CAAC,0BAA0B,EAAEA,OAAO;QAC1C,IAAI,CAACV,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMW,gCAAgCb;IAC3C,aAAc;QACZ,KAAK,CAAC;QACN,IAAI,CAACE,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMY,8BAA8Bd;IACzC,aAAc;QACZ,KAAK,CAAC;QACN,IAAI,CAACE,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMa,uCAAuCf;IAIlD,YAAYgB,UAAkB,EAAEC,KAAc,CAAE;QAC9C,KAAK,CAAC,CAAC,uCAAuC,EAAED,YAAY;QAC5D,IAAI,CAACd,IAAI,GAAG;QACZ,IAAI,CAACc,UAAU,GAAGA;QAClB,IAAI,CAACC,KAAK,GAAGA;IACf;AACF;AAEA,OAAO,MAAMC,0BAA0BlB;IACrC,YAAYmB,MAAe,CAAE;QAC3B,KAAK,CAACA,SAAS,CAAC,eAAe,EAAEA,QAAQ,GAAG;QAC5C,IAAI,CAACjB,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMkB,0BAA0BpB;IACrC,aAAc;QACZ,KAAK,CAAC;QACN,IAAI,CAACE,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMmB,8BAA8BrB;IACzC,aAAc;QACZ,KAAK,CAAC;QACN,IAAI,CAACE,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMoB,gCAAgCtB;IAC3C,YAAYC,WAAmB,CAAE;QAC/B,KAAK,CAAC,CAAC,mCAAmC,EAAEA,aAAa;QACzD,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMqB,wBAAwBvB;IACnC,YAAYC,WAAmB,CAAE;QAC/B,KAAK,CAAC,CAAC,4CAA4C,EAAEA,aAAa;QAClE,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMsB,qCAAqCxB;IAChD,aAAc;QACZ,KAAK,CAAC;QACN,IAAI,CAACE,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMuB,kCAAkCzB;IAC7C,YAAYY,KAAa,CAAE;QACzB,KAAK,CAAC,CAAC,uCAAuC,EAAEA,OAAO;QACvD,IAAI,CAACV,IAAI,GAAG;IACd;AACF"}
@@ -0,0 +1,12 @@
1
+ import { type JobLeaseTokenClaims } from '@shipfox/api-auth-dto';
2
+ export type IssueJobLeaseTokenParams = Omit<JobLeaseTokenClaims, 'aud' | 'iat' | 'exp'>;
3
+ type JobLeaseParamSource = Pick<JobLeaseTokenClaims, 'workflowRunId' | 'workflowRunAttemptId' | 'jobId' | 'jobExecutionId' | 'projectId' | 'workspaceId' | 'runnerSessionId'>;
4
+ export declare function jobLeaseParamsFrom(source: JobLeaseParamSource, stepScope?: {
5
+ currentStepId: string;
6
+ currentStepAttempt: number;
7
+ }): IssueJobLeaseTokenParams;
8
+ export declare function issueJobLeaseToken(claims: IssueJobLeaseTokenParams): Promise<string>;
9
+ /** Returns the claims on success, or `null` for any invalid input — never throws. */
10
+ export declare function verifyJobLeaseToken(token: string): Promise<JobLeaseTokenClaims | null>;
11
+ export {};
12
+ //# sourceMappingURL=job-lease-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-lease-token.d.ts","sourceRoot":"","sources":["../../src/core/job-lease-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,mBAAmB,EAEzB,MAAM,uBAAuB,CAAC;AAM/B,MAAM,MAAM,wBAAwB,GAAG,IAAI,CAAC,mBAAmB,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC;AAExF,KAAK,mBAAmB,GAAG,IAAI,CAC7B,mBAAmB,EACjB,eAAe,GACf,sBAAsB,GACtB,OAAO,GACP,gBAAgB,GAChB,WAAW,GACX,aAAa,GACb,iBAAiB,CACpB,CAAC;AAEF,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,mBAAmB,EAC3B,SAAS,CAAC,EAAE;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAA;CAAC,GAC9D,wBAAwB,CAW1B;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CA0B1F;AAED,qFAAqF;AACrF,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAc5F"}
@@ -0,0 +1,58 @@
1
+ import { JOB_LEASE_TOKEN_AUDIENCE, jobLeaseTokenClaimsSchema } from '@shipfox/api-auth-dto';
2
+ import { signHs256, verifyHs256 } from '@shipfox/node-jwt';
3
+ import { config } from '#config.js';
4
+ import { recordTokenIssued, recordTokenVerified } from '#metrics/index.js';
5
+ export function jobLeaseParamsFrom(source, stepScope) {
6
+ return {
7
+ workflowRunId: source.workflowRunId,
8
+ workflowRunAttemptId: source.workflowRunAttemptId,
9
+ jobId: source.jobId,
10
+ jobExecutionId: source.jobExecutionId,
11
+ projectId: source.projectId,
12
+ workspaceId: source.workspaceId,
13
+ runnerSessionId: source.runnerSessionId,
14
+ ...stepScope ? stepScope : {}
15
+ };
16
+ }
17
+ export async function issueJobLeaseToken(claims) {
18
+ const token = await signHs256({
19
+ payload: {
20
+ workflowRunId: claims.workflowRunId,
21
+ ...claims.workflowRunAttempt === undefined ? {} : {
22
+ workflowRunAttempt: claims.workflowRunAttempt
23
+ },
24
+ workflowRunAttemptId: claims.workflowRunAttemptId,
25
+ jobId: claims.jobId,
26
+ jobExecutionId: claims.jobExecutionId,
27
+ projectId: claims.projectId,
28
+ workspaceId: claims.workspaceId,
29
+ runnerSessionId: claims.runnerSessionId,
30
+ ...claims.currentStepId && claims.currentStepAttempt !== undefined ? {
31
+ currentStepId: claims.currentStepId,
32
+ currentStepAttempt: claims.currentStepAttempt
33
+ } : {}
34
+ },
35
+ secret: config.AUTH_JOB_LEASE_TOKEN_SECRET,
36
+ expiresIn: config.AUTH_JOB_LEASE_TOKEN_EXPIRES_IN,
37
+ audience: JOB_LEASE_TOKEN_AUDIENCE
38
+ });
39
+ recordTokenIssued('job_lease');
40
+ return token;
41
+ }
42
+ /** Returns the claims on success, or `null` for any invalid input — never throws. */ export async function verifyJobLeaseToken(token) {
43
+ try {
44
+ const claims = await verifyHs256({
45
+ token,
46
+ secret: config.AUTH_JOB_LEASE_TOKEN_SECRET,
47
+ schema: jobLeaseTokenClaimsSchema,
48
+ audience: JOB_LEASE_TOKEN_AUDIENCE
49
+ });
50
+ recordTokenVerified('job_lease', 'ok');
51
+ return claims;
52
+ } catch {
53
+ recordTokenVerified('job_lease', 'rejected');
54
+ return null;
55
+ }
56
+ }
57
+
58
+ //# sourceMappingURL=job-lease-token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/job-lease-token.ts"],"sourcesContent":["import {\n JOB_LEASE_TOKEN_AUDIENCE,\n type JobLeaseTokenClaims,\n jobLeaseTokenClaimsSchema,\n} from '@shipfox/api-auth-dto';\nimport {signHs256, verifyHs256} from '@shipfox/node-jwt';\nimport {config} from '#config.js';\nimport {recordTokenIssued, recordTokenVerified} from '#metrics/index.js';\n\n// `aud`, `iat` and `exp` are set by the codec (jose); callers supply the business ids only.\nexport type IssueJobLeaseTokenParams = Omit<JobLeaseTokenClaims, 'aud' | 'iat' | 'exp'>;\n\ntype JobLeaseParamSource = Pick<\n JobLeaseTokenClaims,\n | 'workflowRunId'\n | 'workflowRunAttemptId'\n | 'jobId'\n | 'jobExecutionId'\n | 'projectId'\n | 'workspaceId'\n | 'runnerSessionId'\n>;\n\nexport function jobLeaseParamsFrom(\n source: JobLeaseParamSource,\n stepScope?: {currentStepId: string; currentStepAttempt: number},\n): IssueJobLeaseTokenParams {\n return {\n workflowRunId: source.workflowRunId,\n workflowRunAttemptId: source.workflowRunAttemptId,\n jobId: source.jobId,\n jobExecutionId: source.jobExecutionId,\n projectId: source.projectId,\n workspaceId: source.workspaceId,\n runnerSessionId: source.runnerSessionId,\n ...(stepScope ? stepScope : {}),\n };\n}\n\nexport async function issueJobLeaseToken(claims: IssueJobLeaseTokenParams): Promise<string> {\n const token = await signHs256({\n payload: {\n workflowRunId: claims.workflowRunId,\n ...(claims.workflowRunAttempt === undefined\n ? {}\n : {workflowRunAttempt: claims.workflowRunAttempt}),\n workflowRunAttemptId: claims.workflowRunAttemptId,\n jobId: claims.jobId,\n jobExecutionId: claims.jobExecutionId,\n projectId: claims.projectId,\n workspaceId: claims.workspaceId,\n runnerSessionId: claims.runnerSessionId,\n ...(claims.currentStepId && claims.currentStepAttempt !== undefined\n ? {\n currentStepId: claims.currentStepId,\n currentStepAttempt: claims.currentStepAttempt,\n }\n : {}),\n },\n secret: config.AUTH_JOB_LEASE_TOKEN_SECRET,\n expiresIn: config.AUTH_JOB_LEASE_TOKEN_EXPIRES_IN,\n audience: JOB_LEASE_TOKEN_AUDIENCE,\n });\n recordTokenIssued('job_lease');\n return token;\n}\n\n/** Returns the claims on success, or `null` for any invalid input — never throws. */\nexport async function verifyJobLeaseToken(token: string): Promise<JobLeaseTokenClaims | null> {\n try {\n const claims = await verifyHs256({\n token,\n secret: config.AUTH_JOB_LEASE_TOKEN_SECRET,\n schema: jobLeaseTokenClaimsSchema,\n audience: JOB_LEASE_TOKEN_AUDIENCE,\n });\n recordTokenVerified('job_lease', 'ok');\n return claims;\n } catch {\n recordTokenVerified('job_lease', 'rejected');\n return null;\n }\n}\n"],"names":["JOB_LEASE_TOKEN_AUDIENCE","jobLeaseTokenClaimsSchema","signHs256","verifyHs256","config","recordTokenIssued","recordTokenVerified","jobLeaseParamsFrom","source","stepScope","workflowRunId","workflowRunAttemptId","jobId","jobExecutionId","projectId","workspaceId","runnerSessionId","issueJobLeaseToken","claims","token","payload","workflowRunAttempt","undefined","currentStepId","currentStepAttempt","secret","AUTH_JOB_LEASE_TOKEN_SECRET","expiresIn","AUTH_JOB_LEASE_TOKEN_EXPIRES_IN","audience","verifyJobLeaseToken","schema"],"mappings":"AAAA,SACEA,wBAAwB,EAExBC,yBAAyB,QACpB,wBAAwB;AAC/B,SAAQC,SAAS,EAAEC,WAAW,QAAO,oBAAoB;AACzD,SAAQC,MAAM,QAAO,aAAa;AAClC,SAAQC,iBAAiB,EAAEC,mBAAmB,QAAO,oBAAoB;AAgBzE,OAAO,SAASC,mBACdC,MAA2B,EAC3BC,SAA+D;IAE/D,OAAO;QACLC,eAAeF,OAAOE,aAAa;QACnCC,sBAAsBH,OAAOG,oBAAoB;QACjDC,OAAOJ,OAAOI,KAAK;QACnBC,gBAAgBL,OAAOK,cAAc;QACrCC,WAAWN,OAAOM,SAAS;QAC3BC,aAAaP,OAAOO,WAAW;QAC/BC,iBAAiBR,OAAOQ,eAAe;QACvC,GAAIP,YAAYA,YAAY,CAAC,CAAC;IAChC;AACF;AAEA,OAAO,eAAeQ,mBAAmBC,MAAgC;IACvE,MAAMC,QAAQ,MAAMjB,UAAU;QAC5BkB,SAAS;YACPV,eAAeQ,OAAOR,aAAa;YACnC,GAAIQ,OAAOG,kBAAkB,KAAKC,YAC9B,CAAC,IACD;gBAACD,oBAAoBH,OAAOG,kBAAkB;YAAA,CAAC;YACnDV,sBAAsBO,OAAOP,oBAAoB;YACjDC,OAAOM,OAAON,KAAK;YACnBC,gBAAgBK,OAAOL,cAAc;YACrCC,WAAWI,OAAOJ,SAAS;YAC3BC,aAAaG,OAAOH,WAAW;YAC/BC,iBAAiBE,OAAOF,eAAe;YACvC,GAAIE,OAAOK,aAAa,IAAIL,OAAOM,kBAAkB,KAAKF,YACtD;gBACEC,eAAeL,OAAOK,aAAa;gBACnCC,oBAAoBN,OAAOM,kBAAkB;YAC/C,IACA,CAAC,CAAC;QACR;QACAC,QAAQrB,OAAOsB,2BAA2B;QAC1CC,WAAWvB,OAAOwB,+BAA+B;QACjDC,UAAU7B;IACZ;IACAK,kBAAkB;IAClB,OAAOc;AACT;AAEA,mFAAmF,GACnF,OAAO,eAAeW,oBAAoBX,KAAa;IACrD,IAAI;QACF,MAAMD,SAAS,MAAMf,YAAY;YAC/BgB;YACAM,QAAQrB,OAAOsB,2BAA2B;YAC1CK,QAAQ9B;YACR4B,UAAU7B;QACZ;QACAM,oBAAoB,aAAa;QACjC,OAAOY;IACT,EAAE,OAAM;QACNZ,oBAAoB,aAAa;QACjC,OAAO;IACT;AACF"}
@@ -0,0 +1,37 @@
1
+ import { z } from 'zod';
2
+ export declare const tokenMembershipSchema: z.ZodObject<{
3
+ workspaceId: z.ZodString;
4
+ role: z.ZodEnum<{
5
+ admin: "admin";
6
+ }>;
7
+ }, z.core.$strip>;
8
+ export type TokenMembership = z.infer<typeof tokenMembershipSchema>;
9
+ export declare const userTokenClaimsSchema: z.ZodObject<{
10
+ sub: z.ZodString;
11
+ email: z.ZodString;
12
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
13
+ memberships: z.ZodArray<z.ZodObject<{
14
+ workspaceId: z.ZodString;
15
+ role: z.ZodEnum<{
16
+ admin: "admin";
17
+ }>;
18
+ }, z.core.$strip>>;
19
+ iat: z.ZodNumber;
20
+ exp: z.ZodNumber;
21
+ }, z.core.$strip>;
22
+ export type UserTokenClaims = z.infer<typeof userTokenClaimsSchema>;
23
+ export interface SignUserTokenParams {
24
+ userId: string;
25
+ email: string;
26
+ name?: string | null | undefined;
27
+ memberships: TokenMembership[];
28
+ secret: string;
29
+ expiresIn: string;
30
+ }
31
+ export interface VerifyUserTokenParams {
32
+ token: string;
33
+ secret: string;
34
+ }
35
+ export declare function signUserToken(params: SignUserTokenParams): Promise<string>;
36
+ export declare function verifyUserToken(params: VerifyUserTokenParams): Promise<UserTokenClaims>;
37
+ //# sourceMappingURL=jwt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/core/jwt.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,eAAO,MAAM,qBAAqB;;;;;iBAGhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;iBAOhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAahF;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CAa7F"}
@@ -0,0 +1,46 @@
1
+ import { workspaceRoleSchema } from '@shipfox/api-workspaces-dto';
2
+ import { signHs256, verifyHs256 } from '@shipfox/node-jwt';
3
+ import { z } from 'zod';
4
+ import { recordTokenIssued, recordTokenVerified } from '#metrics/index.js';
5
+ export const tokenMembershipSchema = z.object({
6
+ workspaceId: z.string().uuid(),
7
+ role: workspaceRoleSchema
8
+ });
9
+ export const userTokenClaimsSchema = z.object({
10
+ sub: z.string().uuid(),
11
+ email: z.string().email(),
12
+ name: z.string().nullable().optional(),
13
+ memberships: z.array(tokenMembershipSchema),
14
+ iat: z.number().int(),
15
+ exp: z.number().int()
16
+ });
17
+ export async function signUserToken(params) {
18
+ const token = await signHs256({
19
+ payload: {
20
+ email: params.email,
21
+ name: params.name ?? null,
22
+ memberships: params.memberships
23
+ },
24
+ secret: params.secret,
25
+ expiresIn: params.expiresIn,
26
+ subject: params.userId
27
+ });
28
+ recordTokenIssued('session');
29
+ return token;
30
+ }
31
+ export async function verifyUserToken(params) {
32
+ try {
33
+ const claims = await verifyHs256({
34
+ token: params.token,
35
+ secret: params.secret,
36
+ schema: userTokenClaimsSchema
37
+ });
38
+ recordTokenVerified('session', 'ok');
39
+ return claims;
40
+ } catch (error) {
41
+ recordTokenVerified('session', 'rejected');
42
+ throw error;
43
+ }
44
+ }
45
+
46
+ //# sourceMappingURL=jwt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/jwt.ts"],"sourcesContent":["import {workspaceRoleSchema} from '@shipfox/api-workspaces-dto';\nimport {signHs256, verifyHs256} from '@shipfox/node-jwt';\nimport {z} from 'zod';\nimport {recordTokenIssued, recordTokenVerified} from '#metrics/index.js';\n\nexport const tokenMembershipSchema = z.object({\n workspaceId: z.string().uuid(),\n role: workspaceRoleSchema,\n});\n\nexport type TokenMembership = z.infer<typeof tokenMembershipSchema>;\n\nexport const userTokenClaimsSchema = z.object({\n sub: z.string().uuid(),\n email: z.string().email(),\n name: z.string().nullable().optional(),\n memberships: z.array(tokenMembershipSchema),\n iat: z.number().int(),\n exp: z.number().int(),\n});\n\nexport type UserTokenClaims = z.infer<typeof userTokenClaimsSchema>;\n\nexport interface SignUserTokenParams {\n userId: string;\n email: string;\n name?: string | null | undefined;\n memberships: TokenMembership[];\n secret: string;\n expiresIn: string;\n}\n\nexport interface VerifyUserTokenParams {\n token: string;\n secret: string;\n}\n\nexport async function signUserToken(params: SignUserTokenParams): Promise<string> {\n const token = await signHs256({\n payload: {\n email: params.email,\n name: params.name ?? null,\n memberships: params.memberships,\n },\n secret: params.secret,\n expiresIn: params.expiresIn,\n subject: params.userId,\n });\n recordTokenIssued('session');\n return token;\n}\n\nexport async function verifyUserToken(params: VerifyUserTokenParams): Promise<UserTokenClaims> {\n try {\n const claims = await verifyHs256({\n token: params.token,\n secret: params.secret,\n schema: userTokenClaimsSchema,\n });\n recordTokenVerified('session', 'ok');\n return claims;\n } catch (error) {\n recordTokenVerified('session', 'rejected');\n throw error;\n }\n}\n"],"names":["workspaceRoleSchema","signHs256","verifyHs256","z","recordTokenIssued","recordTokenVerified","tokenMembershipSchema","object","workspaceId","string","uuid","role","userTokenClaimsSchema","sub","email","name","nullable","optional","memberships","array","iat","number","int","exp","signUserToken","params","token","payload","secret","expiresIn","subject","userId","verifyUserToken","claims","schema","error"],"mappings":"AAAA,SAAQA,mBAAmB,QAAO,8BAA8B;AAChE,SAAQC,SAAS,EAAEC,WAAW,QAAO,oBAAoB;AACzD,SAAQC,CAAC,QAAO,MAAM;AACtB,SAAQC,iBAAiB,EAAEC,mBAAmB,QAAO,oBAAoB;AAEzE,OAAO,MAAMC,wBAAwBH,EAAEI,MAAM,CAAC;IAC5CC,aAAaL,EAAEM,MAAM,GAAGC,IAAI;IAC5BC,MAAMX;AACR,GAAG;AAIH,OAAO,MAAMY,wBAAwBT,EAAEI,MAAM,CAAC;IAC5CM,KAAKV,EAAEM,MAAM,GAAGC,IAAI;IACpBI,OAAOX,EAAEM,MAAM,GAAGK,KAAK;IACvBC,MAAMZ,EAAEM,MAAM,GAAGO,QAAQ,GAAGC,QAAQ;IACpCC,aAAaf,EAAEgB,KAAK,CAACb;IACrBc,KAAKjB,EAAEkB,MAAM,GAAGC,GAAG;IACnBC,KAAKpB,EAAEkB,MAAM,GAAGC,GAAG;AACrB,GAAG;AAkBH,OAAO,eAAeE,cAAcC,MAA2B;IAC7D,MAAMC,QAAQ,MAAMzB,UAAU;QAC5B0B,SAAS;YACPb,OAAOW,OAAOX,KAAK;YACnBC,MAAMU,OAAOV,IAAI,IAAI;YACrBG,aAAaO,OAAOP,WAAW;QACjC;QACAU,QAAQH,OAAOG,MAAM;QACrBC,WAAWJ,OAAOI,SAAS;QAC3BC,SAASL,OAAOM,MAAM;IACxB;IACA3B,kBAAkB;IAClB,OAAOsB;AACT;AAEA,OAAO,eAAeM,gBAAgBP,MAA6B;IACjE,IAAI;QACF,MAAMQ,SAAS,MAAM/B,YAAY;YAC/BwB,OAAOD,OAAOC,KAAK;YACnBE,QAAQH,OAAOG,MAAM;YACrBM,QAAQtB;QACV;QACAP,oBAAoB,WAAW;QAC/B,OAAO4B;IACT,EAAE,OAAOE,OAAO;QACd9B,oBAAoB,WAAW;QAC/B,MAAM8B;IACR;AACF"}
@@ -0,0 +1,10 @@
1
+ export interface HashPasswordParams {
2
+ password: string;
3
+ }
4
+ export interface VerifyPasswordParams {
5
+ password: string;
6
+ hash: string;
7
+ }
8
+ export declare function hashPassword(params: HashPasswordParams): Promise<string>;
9
+ export declare function verifyPassword(params: VerifyPasswordParams): Promise<boolean>;
10
+ //# sourceMappingURL=password.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../src/core/password.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAKD,wBAAgB,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAExE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,CAE7E"}
@@ -0,0 +1,13 @@
1
+ import { hash, verify } from '@node-rs/argon2';
2
+ // Algorithm.Argon2id = 2; using literal here to avoid const-enum import under verbatimModuleSyntax.
3
+ const HASH_OPTIONS = {
4
+ algorithm: 2
5
+ };
6
+ export function hashPassword(params) {
7
+ return hash(params.password, HASH_OPTIONS);
8
+ }
9
+ export function verifyPassword(params) {
10
+ return verify(params.hash, params.password);
11
+ }
12
+
13
+ //# sourceMappingURL=password.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/password.ts"],"sourcesContent":["import {hash, verify} from '@node-rs/argon2';\n\nexport interface HashPasswordParams {\n password: string;\n}\n\nexport interface VerifyPasswordParams {\n password: string;\n hash: string;\n}\n\n// Algorithm.Argon2id = 2; using literal here to avoid const-enum import under verbatimModuleSyntax.\nconst HASH_OPTIONS = {algorithm: 2} as const;\n\nexport function hashPassword(params: HashPasswordParams): Promise<string> {\n return hash(params.password, HASH_OPTIONS);\n}\n\nexport function verifyPassword(params: VerifyPasswordParams): Promise<boolean> {\n return verify(params.hash, params.password);\n}\n"],"names":["hash","verify","HASH_OPTIONS","algorithm","hashPassword","params","password","verifyPassword"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,MAAM,QAAO,kBAAkB;AAW7C,oGAAoG;AACpG,MAAMC,eAAe;IAACC,WAAW;AAAC;AAElC,OAAO,SAASC,aAAaC,MAA0B;IACrD,OAAOL,KAAKK,OAAOC,QAAQ,EAAEJ;AAC/B;AAEA,OAAO,SAASK,eAAeF,MAA4B;IACzD,OAAOJ,OAAOI,OAAOL,IAAI,EAAEK,OAAOC,QAAQ;AAC5C"}
@@ -0,0 +1,34 @@
1
+ import { RateLimitExceededError, type RateLimitPolicy, RateLimitUnavailableError } from '@shipfox/node-rate-limit';
2
+ import { type AuthRateLimitAction, type AuthRateLimitScope } from '#metrics/index.js';
3
+ export type { AuthRateLimitAction, AuthRateLimitOutcome, AuthRateLimitScope, } from '#metrics/index.js';
4
+ export type AuthRateLimitPolicy = RateLimitPolicy;
5
+ export interface CheckAuthRateLimitParams extends AuthRateLimitPolicy {
6
+ action: AuthRateLimitAction;
7
+ scope: AuthRateLimitScope;
8
+ identifier: string;
9
+ now?: Date | undefined;
10
+ timeoutMs?: number | undefined;
11
+ }
12
+ export declare class AuthRateLimitExceededError extends RateLimitExceededError<AuthRateLimitAction, AuthRateLimitScope> {
13
+ constructor(params: {
14
+ action: AuthRateLimitAction;
15
+ scope: AuthRateLimitScope;
16
+ retryAfterSeconds: number;
17
+ identifierHmacPrefix: string;
18
+ });
19
+ }
20
+ export declare class AuthRateLimitUnavailableError extends RateLimitUnavailableError<AuthRateLimitAction, AuthRateLimitScope> {
21
+ constructor(params: {
22
+ action: AuthRateLimitAction;
23
+ scope: AuthRateLimitScope;
24
+ identifierHmacPrefix: string;
25
+ cause: unknown;
26
+ });
27
+ }
28
+ export declare function hashAuthRateLimitIdentifier(params: {
29
+ action: AuthRateLimitAction;
30
+ scope: AuthRateLimitScope;
31
+ identifier: string;
32
+ }): string;
33
+ export declare function checkAuthRateLimit(params: CheckAuthRateLimitParams): Promise<void>;
34
+ //# sourceMappingURL=rate-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/core/rate-limit.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,sBAAsB,EACtB,KAAK,eAAe,EACpB,yBAAyB,EAC1B,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EAGxB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,MAAM,mBAAmB,GAAG,eAAe,CAAC;AAElD,MAAM,WAAW,wBAAyB,SAAQ,mBAAmB;IACnE,MAAM,EAAE,mBAAmB,CAAC;IAC5B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,qBAAa,0BAA2B,SAAQ,sBAAsB,CACpE,mBAAmB,EACnB,kBAAkB,CACnB;gBACa,MAAM,EAAE;QAClB,MAAM,EAAE,mBAAmB,CAAC;QAC5B,KAAK,EAAE,kBAAkB,CAAC;QAC1B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,oBAAoB,EAAE,MAAM,CAAC;KAC9B;CAKF;AAED,qBAAa,6BAA8B,SAAQ,yBAAyB,CAC1E,mBAAmB,EACnB,kBAAkB,CACnB;gBACa,MAAM,EAAE;QAClB,MAAM,EAAE,mBAAmB,CAAC;QAC5B,KAAK,EAAE,kBAAkB,CAAC;QAC1B,oBAAoB,EAAE,MAAM,CAAC;QAC7B,KAAK,EAAE,OAAO,CAAC;KAChB;CAKF;AAgBD,wBAAgB,2BAA2B,CAAC,MAAM,EAAE;IAClD,MAAM,EAAE,mBAAmB,CAAC;IAC5B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CAQT;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoCxF"}
@@ -0,0 +1,76 @@
1
+ import { createHmac } from 'node:crypto';
2
+ import { checkRateLimit, hashRateLimitIdentifier, RateLimitExceededError, RateLimitUnavailableError } from '@shipfox/node-rate-limit';
3
+ import { config } from '#config.js';
4
+ import { consumeAuthRateLimit, pruneExpiredAuthRateLimits } from '#db/rate-limits.js';
5
+ import { recordAuthRateLimitCheck, recordAuthRateLimitPruneFailure } from '#metrics/index.js';
6
+ export class AuthRateLimitExceededError extends RateLimitExceededError {
7
+ constructor(params){
8
+ super(params);
9
+ this.name = 'AuthRateLimitExceededError';
10
+ this.message = 'Authentication rate limit exceeded';
11
+ }
12
+ }
13
+ export class AuthRateLimitUnavailableError extends RateLimitUnavailableError {
14
+ constructor(params){
15
+ super(params);
16
+ this.name = 'AuthRateLimitUnavailableError';
17
+ this.message = 'Authentication rate limiter unavailable';
18
+ }
19
+ }
20
+ const DEFAULT_TIMEOUT_MS = 250;
21
+ const IDENTIFIER_SECRET_DERIVATION_DOMAIN = 'shipfox.auth.rate-limit.identifier-secret.v1';
22
+ const IDENTIFIER_HASH_DOMAIN = 'shipfox.auth.rate-limit.identifier.v1';
23
+ function effectiveIdentifierSecret() {
24
+ if (config.RATE_LIMIT_IDENTIFIER_SECRET) {
25
+ return config.RATE_LIMIT_IDENTIFIER_SECRET;
26
+ }
27
+ return createHmac('sha256', config.AUTH_JWT_SECRET).update(IDENTIFIER_SECRET_DERIVATION_DOMAIN).digest();
28
+ }
29
+ export function hashAuthRateLimitIdentifier(params) {
30
+ return hashRateLimitIdentifier({
31
+ action: params.action,
32
+ scope: params.scope,
33
+ identifier: params.identifier,
34
+ secret: effectiveIdentifierSecret(),
35
+ domain: IDENTIFIER_HASH_DOMAIN
36
+ });
37
+ }
38
+ export async function checkAuthRateLimit(params) {
39
+ try {
40
+ await checkRateLimit({
41
+ action: params.action,
42
+ scope: params.scope,
43
+ identifier: params.identifier,
44
+ limit: params.limit,
45
+ windowSeconds: params.windowSeconds,
46
+ identifierSecret: effectiveIdentifierSecret(),
47
+ identifierHashDomain: IDENTIFIER_HASH_DOMAIN,
48
+ consume: consumeAuthRateLimit,
49
+ prune: pruneExpiredAuthRateLimits,
50
+ onCheck: recordAuthRateLimitCheck,
51
+ onPruneFailure: recordAuthRateLimitPruneFailure,
52
+ now: params.now,
53
+ timeoutMs: params.timeoutMs ?? DEFAULT_TIMEOUT_MS
54
+ });
55
+ } catch (error) {
56
+ if (error instanceof RateLimitExceededError) {
57
+ throw new AuthRateLimitExceededError({
58
+ action: error.action,
59
+ scope: error.scope,
60
+ retryAfterSeconds: error.retryAfterSeconds,
61
+ identifierHmacPrefix: error.identifierHmacPrefix
62
+ });
63
+ }
64
+ if (error instanceof RateLimitUnavailableError) {
65
+ throw new AuthRateLimitUnavailableError({
66
+ action: error.action,
67
+ scope: error.scope,
68
+ identifierHmacPrefix: error.identifierHmacPrefix,
69
+ cause: error.cause
70
+ });
71
+ }
72
+ throw error;
73
+ }
74
+ }
75
+
76
+ //# sourceMappingURL=rate-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/rate-limit.ts"],"sourcesContent":["import {createHmac} from 'node:crypto';\nimport {\n checkRateLimit,\n hashRateLimitIdentifier,\n RateLimitExceededError,\n type RateLimitPolicy,\n RateLimitUnavailableError,\n} from '@shipfox/node-rate-limit';\nimport {config} from '#config.js';\nimport {consumeAuthRateLimit, pruneExpiredAuthRateLimits} from '#db/rate-limits.js';\nimport {\n type AuthRateLimitAction,\n type AuthRateLimitScope,\n recordAuthRateLimitCheck,\n recordAuthRateLimitPruneFailure,\n} from '#metrics/index.js';\n\nexport type {\n AuthRateLimitAction,\n AuthRateLimitOutcome,\n AuthRateLimitScope,\n} from '#metrics/index.js';\n\nexport type AuthRateLimitPolicy = RateLimitPolicy;\n\nexport interface CheckAuthRateLimitParams extends AuthRateLimitPolicy {\n action: AuthRateLimitAction;\n scope: AuthRateLimitScope;\n identifier: string;\n now?: Date | undefined;\n timeoutMs?: number | undefined;\n}\n\nexport class AuthRateLimitExceededError extends RateLimitExceededError<\n AuthRateLimitAction,\n AuthRateLimitScope\n> {\n constructor(params: {\n action: AuthRateLimitAction;\n scope: AuthRateLimitScope;\n retryAfterSeconds: number;\n identifierHmacPrefix: string;\n }) {\n super(params);\n this.name = 'AuthRateLimitExceededError';\n this.message = 'Authentication rate limit exceeded';\n }\n}\n\nexport class AuthRateLimitUnavailableError extends RateLimitUnavailableError<\n AuthRateLimitAction,\n AuthRateLimitScope\n> {\n constructor(params: {\n action: AuthRateLimitAction;\n scope: AuthRateLimitScope;\n identifierHmacPrefix: string;\n cause: unknown;\n }) {\n super(params);\n this.name = 'AuthRateLimitUnavailableError';\n this.message = 'Authentication rate limiter unavailable';\n }\n}\n\nconst DEFAULT_TIMEOUT_MS = 250;\nconst IDENTIFIER_SECRET_DERIVATION_DOMAIN = 'shipfox.auth.rate-limit.identifier-secret.v1';\nconst IDENTIFIER_HASH_DOMAIN = 'shipfox.auth.rate-limit.identifier.v1';\n\nfunction effectiveIdentifierSecret(): Buffer | string {\n if (config.RATE_LIMIT_IDENTIFIER_SECRET) {\n return config.RATE_LIMIT_IDENTIFIER_SECRET;\n }\n\n return createHmac('sha256', config.AUTH_JWT_SECRET)\n .update(IDENTIFIER_SECRET_DERIVATION_DOMAIN)\n .digest();\n}\n\nexport function hashAuthRateLimitIdentifier(params: {\n action: AuthRateLimitAction;\n scope: AuthRateLimitScope;\n identifier: string;\n}): string {\n return hashRateLimitIdentifier({\n action: params.action,\n scope: params.scope,\n identifier: params.identifier,\n secret: effectiveIdentifierSecret(),\n domain: IDENTIFIER_HASH_DOMAIN,\n });\n}\n\nexport async function checkAuthRateLimit(params: CheckAuthRateLimitParams): Promise<void> {\n try {\n await checkRateLimit({\n action: params.action,\n scope: params.scope,\n identifier: params.identifier,\n limit: params.limit,\n windowSeconds: params.windowSeconds,\n identifierSecret: effectiveIdentifierSecret(),\n identifierHashDomain: IDENTIFIER_HASH_DOMAIN,\n consume: consumeAuthRateLimit,\n prune: pruneExpiredAuthRateLimits,\n onCheck: recordAuthRateLimitCheck,\n onPruneFailure: recordAuthRateLimitPruneFailure,\n now: params.now,\n timeoutMs: params.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n });\n } catch (error) {\n if (error instanceof RateLimitExceededError) {\n throw new AuthRateLimitExceededError({\n action: error.action,\n scope: error.scope,\n retryAfterSeconds: error.retryAfterSeconds,\n identifierHmacPrefix: error.identifierHmacPrefix,\n });\n }\n if (error instanceof RateLimitUnavailableError) {\n throw new AuthRateLimitUnavailableError({\n action: error.action,\n scope: error.scope,\n identifierHmacPrefix: error.identifierHmacPrefix,\n cause: error.cause,\n });\n }\n throw error;\n }\n}\n"],"names":["createHmac","checkRateLimit","hashRateLimitIdentifier","RateLimitExceededError","RateLimitUnavailableError","config","consumeAuthRateLimit","pruneExpiredAuthRateLimits","recordAuthRateLimitCheck","recordAuthRateLimitPruneFailure","AuthRateLimitExceededError","params","name","message","AuthRateLimitUnavailableError","DEFAULT_TIMEOUT_MS","IDENTIFIER_SECRET_DERIVATION_DOMAIN","IDENTIFIER_HASH_DOMAIN","effectiveIdentifierSecret","RATE_LIMIT_IDENTIFIER_SECRET","AUTH_JWT_SECRET","update","digest","hashAuthRateLimitIdentifier","action","scope","identifier","secret","domain","checkAuthRateLimit","limit","windowSeconds","identifierSecret","identifierHashDomain","consume","prune","onCheck","onPruneFailure","now","timeoutMs","error","retryAfterSeconds","identifierHmacPrefix","cause"],"mappings":"AAAA,SAAQA,UAAU,QAAO,cAAc;AACvC,SACEC,cAAc,EACdC,uBAAuB,EACvBC,sBAAsB,EAEtBC,yBAAyB,QACpB,2BAA2B;AAClC,SAAQC,MAAM,QAAO,aAAa;AAClC,SAAQC,oBAAoB,EAAEC,0BAA0B,QAAO,qBAAqB;AACpF,SAGEC,wBAAwB,EACxBC,+BAA+B,QAC1B,oBAAoB;AAkB3B,OAAO,MAAMC,mCAAmCP;IAI9C,YAAYQ,MAKX,CAAE;QACD,KAAK,CAACA;QACN,IAAI,CAACC,IAAI,GAAG;QACZ,IAAI,CAACC,OAAO,GAAG;IACjB;AACF;AAEA,OAAO,MAAMC,sCAAsCV;IAIjD,YAAYO,MAKX,CAAE;QACD,KAAK,CAACA;QACN,IAAI,CAACC,IAAI,GAAG;QACZ,IAAI,CAACC,OAAO,GAAG;IACjB;AACF;AAEA,MAAME,qBAAqB;AAC3B,MAAMC,sCAAsC;AAC5C,MAAMC,yBAAyB;AAE/B,SAASC;IACP,IAAIb,OAAOc,4BAA4B,EAAE;QACvC,OAAOd,OAAOc,4BAA4B;IAC5C;IAEA,OAAOnB,WAAW,UAAUK,OAAOe,eAAe,EAC/CC,MAAM,CAACL,qCACPM,MAAM;AACX;AAEA,OAAO,SAASC,4BAA4BZ,MAI3C;IACC,OAAOT,wBAAwB;QAC7BsB,QAAQb,OAAOa,MAAM;QACrBC,OAAOd,OAAOc,KAAK;QACnBC,YAAYf,OAAOe,UAAU;QAC7BC,QAAQT;QACRU,QAAQX;IACV;AACF;AAEA,OAAO,eAAeY,mBAAmBlB,MAAgC;IACvE,IAAI;QACF,MAAMV,eAAe;YACnBuB,QAAQb,OAAOa,MAAM;YACrBC,OAAOd,OAAOc,KAAK;YACnBC,YAAYf,OAAOe,UAAU;YAC7BI,OAAOnB,OAAOmB,KAAK;YACnBC,eAAepB,OAAOoB,aAAa;YACnCC,kBAAkBd;YAClBe,sBAAsBhB;YACtBiB,SAAS5B;YACT6B,OAAO5B;YACP6B,SAAS5B;YACT6B,gBAAgB5B;YAChB6B,KAAK3B,OAAO2B,GAAG;YACfC,WAAW5B,OAAO4B,SAAS,IAAIxB;QACjC;IACF,EAAE,OAAOyB,OAAO;QACd,IAAIA,iBAAiBrC,wBAAwB;YAC3C,MAAM,IAAIO,2BAA2B;gBACnCc,QAAQgB,MAAMhB,MAAM;gBACpBC,OAAOe,MAAMf,KAAK;gBAClBgB,mBAAmBD,MAAMC,iBAAiB;gBAC1CC,sBAAsBF,MAAME,oBAAoB;YAClD;QACF;QACA,IAAIF,iBAAiBpC,2BAA2B;YAC9C,MAAM,IAAIU,8BAA8B;gBACtCU,QAAQgB,MAAMhB,MAAM;gBACpBC,OAAOe,MAAMf,KAAK;gBAClBiB,sBAAsBF,MAAME,oBAAoB;gBAChDC,OAAOH,MAAMG,KAAK;YACpB;QACF;QACA,MAAMH;IACR;AACF"}
@@ -0,0 +1,6 @@
1
+ import { type RunnerSessionTokenClaims } from '@shipfox/api-auth-dto';
2
+ export type IssueRunnerSessionTokenParams = Omit<RunnerSessionTokenClaims, 'aud' | 'iat' | 'exp'>;
3
+ export declare function issueRunnerSessionToken(claims: IssueRunnerSessionTokenParams): Promise<string>;
4
+ /** Returns the claims on success, or `null` for any invalid input — never throws. */
5
+ export declare function verifyRunnerSessionToken(token: string): Promise<RunnerSessionTokenClaims | null>;
6
+ //# sourceMappingURL=runner-session-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner-session-token.d.ts","sourceRoot":"","sources":["../../src/core/runner-session-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,wBAAwB,EAE9B,MAAM,uBAAuB,CAAC;AAM/B,MAAM,MAAM,6BAA6B,GAAG,IAAI,CAAC,wBAAwB,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC;AAElG,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,MAAM,CAAC,CAejB;AAED,qFAAqF;AACrF,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAc1C"}