@shipfox/api-runners 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 (465) 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 +187 -0
  5. package/LICENSE +21 -0
  6. package/dist/config.d.ts +30 -0
  7. package/dist/config.d.ts.map +1 -0
  8. package/dist/config.js +208 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/core/demand.d.ts +33 -0
  11. package/dist/core/demand.d.ts.map +1 -0
  12. package/dist/core/demand.js +169 -0
  13. package/dist/core/demand.js.map +1 -0
  14. package/dist/core/entities/ephemeral-registration-token.d.ts +14 -0
  15. package/dist/core/entities/ephemeral-registration-token.d.ts.map +1 -0
  16. package/dist/core/entities/ephemeral-registration-token.js +3 -0
  17. package/dist/core/entities/ephemeral-registration-token.js.map +1 -0
  18. package/dist/core/entities/manual-registration-token.d.ts +12 -0
  19. package/dist/core/entities/manual-registration-token.d.ts.map +1 -0
  20. package/dist/core/entities/manual-registration-token.js +3 -0
  21. package/dist/core/entities/manual-registration-token.js.map +1 -0
  22. package/dist/core/entities/provisioned-runner.d.ts +24 -0
  23. package/dist/core/entities/provisioned-runner.d.ts.map +1 -0
  24. package/dist/core/entities/provisioned-runner.js +3 -0
  25. package/dist/core/entities/provisioned-runner.js.map +1 -0
  26. package/dist/core/entities/provisioner-token.d.ts +18 -0
  27. package/dist/core/entities/provisioner-token.d.ts.map +1 -0
  28. package/dist/core/entities/provisioner-token.js +3 -0
  29. package/dist/core/entities/provisioner-token.js.map +1 -0
  30. package/dist/core/entities/reservation.d.ts +10 -0
  31. package/dist/core/entities/reservation.d.ts.map +1 -0
  32. package/dist/core/entities/reservation.js +3 -0
  33. package/dist/core/entities/reservation.js.map +1 -0
  34. package/dist/core/entities/runner-session.d.ts +18 -0
  35. package/dist/core/entities/runner-session.d.ts.map +1 -0
  36. package/dist/core/entities/runner-session.js +3 -0
  37. package/dist/core/entities/runner-session.js.map +1 -0
  38. package/dist/core/ephemeral-registration-tokens.d.ts +31 -0
  39. package/dist/core/ephemeral-registration-tokens.d.ts.map +1 -0
  40. package/dist/core/ephemeral-registration-tokens.js +61 -0
  41. package/dist/core/ephemeral-registration-tokens.js.map +1 -0
  42. package/dist/core/errors.d.ts +62 -0
  43. package/dist/core/errors.d.ts.map +1 -0
  44. package/dist/core/errors.js +92 -0
  45. package/dist/core/errors.js.map +1 -0
  46. package/dist/core/index.d.ts +14 -0
  47. package/dist/core/index.d.ts.map +1 -0
  48. package/dist/core/index.js +10 -0
  49. package/dist/core/index.js.map +1 -0
  50. package/dist/core/job-executions.d.ts +14 -0
  51. package/dist/core/job-executions.d.ts.map +1 -0
  52. package/dist/core/job-executions.js +37 -0
  53. package/dist/core/job-executions.js.map +1 -0
  54. package/dist/core/maintenance-policy.d.ts +2 -0
  55. package/dist/core/maintenance-policy.d.ts.map +1 -0
  56. package/dist/core/maintenance-policy.js +3 -0
  57. package/dist/core/maintenance-policy.js.map +1 -0
  58. package/dist/core/maintenance.d.ts +33 -0
  59. package/dist/core/maintenance.d.ts.map +1 -0
  60. package/dist/core/maintenance.js +55 -0
  61. package/dist/core/maintenance.js.map +1 -0
  62. package/dist/core/manual-registration-tokens.d.ts +17 -0
  63. package/dist/core/manual-registration-tokens.d.ts.map +1 -0
  64. package/dist/core/manual-registration-tokens.js +28 -0
  65. package/dist/core/manual-registration-tokens.js.map +1 -0
  66. package/dist/core/provisioned-runners.d.ts +67 -0
  67. package/dist/core/provisioned-runners.d.ts.map +1 -0
  68. package/dist/core/provisioned-runners.js +162 -0
  69. package/dist/core/provisioned-runners.js.map +1 -0
  70. package/dist/core/provisioner-tokens.d.ts +20 -0
  71. package/dist/core/provisioner-tokens.d.ts.map +1 -0
  72. package/dist/core/provisioner-tokens.js +36 -0
  73. package/dist/core/provisioner-tokens.js.map +1 -0
  74. package/dist/core/rate-limit.d.ts +35 -0
  75. package/dist/core/rate-limit.d.ts.map +1 -0
  76. package/dist/core/rate-limit.js +74 -0
  77. package/dist/core/rate-limit.js.map +1 -0
  78. package/dist/core/runner-sessions.d.ts +26 -0
  79. package/dist/core/runner-sessions.d.ts.map +1 -0
  80. package/dist/core/runner-sessions.js +41 -0
  81. package/dist/core/runner-sessions.js.map +1 -0
  82. package/dist/core/runner-tool-capabilities.d.ts +24 -0
  83. package/dist/core/runner-tool-capabilities.d.ts.map +1 -0
  84. package/dist/core/runner-tool-capabilities.js +43 -0
  85. package/dist/core/runner-tool-capabilities.js.map +1 -0
  86. package/dist/db/db.d.ts +4478 -0
  87. package/dist/db/db.d.ts.map +1 -0
  88. package/dist/db/db.js +36 -0
  89. package/dist/db/db.js.map +1 -0
  90. package/dist/db/ephemeral-registration-tokens.d.ts +47 -0
  91. package/dist/db/ephemeral-registration-tokens.d.ts.map +1 -0
  92. package/dist/db/ephemeral-registration-tokens.js +170 -0
  93. package/dist/db/ephemeral-registration-tokens.js.map +1 -0
  94. package/dist/db/index.d.ts +19 -0
  95. package/dist/db/index.d.ts.map +1 -0
  96. package/dist/db/index.js +15 -0
  97. package/dist/db/index.js.map +1 -0
  98. package/dist/db/job-executions.d.ts +128 -0
  99. package/dist/db/job-executions.d.ts.map +1 -0
  100. package/dist/db/job-executions.js +354 -0
  101. package/dist/db/job-executions.js.map +1 -0
  102. package/dist/db/manual-registration-tokens.d.ts +16 -0
  103. package/dist/db/manual-registration-tokens.d.ts.map +1 -0
  104. package/dist/db/manual-registration-tokens.js +37 -0
  105. package/dist/db/manual-registration-tokens.js.map +1 -0
  106. package/dist/db/provisioned-runners.d.ts +79 -0
  107. package/dist/db/provisioned-runners.d.ts.map +1 -0
  108. package/dist/db/provisioned-runners.js +466 -0
  109. package/dist/db/provisioned-runners.js.map +1 -0
  110. package/dist/db/provisioner-tokens.d.ts +26 -0
  111. package/dist/db/provisioner-tokens.d.ts.map +1 -0
  112. package/dist/db/provisioner-tokens.js +54 -0
  113. package/dist/db/provisioner-tokens.js.map +1 -0
  114. package/dist/db/rate-limits.d.ts +18 -0
  115. package/dist/db/rate-limits.d.ts.map +1 -0
  116. package/dist/db/rate-limits.js +44 -0
  117. package/dist/db/rate-limits.js.map +1 -0
  118. package/dist/db/reservations.d.ts +48 -0
  119. package/dist/db/reservations.d.ts.map +1 -0
  120. package/dist/db/reservations.js +162 -0
  121. package/dist/db/reservations.js.map +1 -0
  122. package/dist/db/runner-sessions.d.ts +18 -0
  123. package/dist/db/runner-sessions.d.ts.map +1 -0
  124. package/dist/db/runner-sessions.js +38 -0
  125. package/dist/db/runner-sessions.js.map +1 -0
  126. package/dist/db/schema/common.d.ts +2 -0
  127. package/dist/db/schema/common.d.ts.map +1 -0
  128. package/dist/db/schema/common.js +4 -0
  129. package/dist/db/schema/common.js.map +1 -0
  130. package/dist/db/schema/ephemeral-registration-tokens.d.ts +199 -0
  131. package/dist/db/schema/ephemeral-registration-tokens.d.ts.map +1 -0
  132. package/dist/db/schema/ephemeral-registration-tokens.js +45 -0
  133. package/dist/db/schema/ephemeral-registration-tokens.js.map +1 -0
  134. package/dist/db/schema/manual-registration-tokens.d.ts +165 -0
  135. package/dist/db/schema/manual-registration-tokens.d.ts.map +1 -0
  136. package/dist/db/schema/manual-registration-tokens.js +40 -0
  137. package/dist/db/schema/manual-registration-tokens.js.map +1 -0
  138. package/dist/db/schema/outbox.d.ts +195 -0
  139. package/dist/db/schema/outbox.d.ts.map +1 -0
  140. package/dist/db/schema/outbox.js +5 -0
  141. package/dist/db/schema/outbox.js.map +1 -0
  142. package/dist/db/schema/pending-job-executions.d.ts +189 -0
  143. package/dist/db/schema/pending-job-executions.d.ts.map +1 -0
  144. package/dist/db/schema/pending-job-executions.js +21 -0
  145. package/dist/db/schema/pending-job-executions.js.map +1 -0
  146. package/dist/db/schema/provisioned-runners.d.ts +379 -0
  147. package/dist/db/schema/provisioned-runners.d.ts.map +1 -0
  148. package/dist/db/schema/provisioned-runners.js +83 -0
  149. package/dist/db/schema/provisioned-runners.js.map +1 -0
  150. package/dist/db/schema/provisioner-tokens.d.ts +216 -0
  151. package/dist/db/schema/provisioner-tokens.d.ts.map +1 -0
  152. package/dist/db/schema/provisioner-tokens.js +48 -0
  153. package/dist/db/schema/provisioner-tokens.js.map +1 -0
  154. package/dist/db/schema/rate-limits.d.ts +145 -0
  155. package/dist/db/schema/rate-limits.d.ts.map +1 -0
  156. package/dist/db/schema/rate-limits.js +25 -0
  157. package/dist/db/schema/rate-limits.js.map +1 -0
  158. package/dist/db/schema/reservations.d.ts +157 -0
  159. package/dist/db/schema/reservations.d.ts.map +1 -0
  160. package/dist/db/schema/reservations.js +34 -0
  161. package/dist/db/schema/reservations.js.map +1 -0
  162. package/dist/db/schema/runner-sessions.d.ts +298 -0
  163. package/dist/db/schema/runner-sessions.d.ts.map +1 -0
  164. package/dist/db/schema/runner-sessions.js +61 -0
  165. package/dist/db/schema/runner-sessions.js.map +1 -0
  166. package/dist/db/schema/running-job-executions.d.ts +334 -0
  167. package/dist/db/schema/running-job-executions.d.ts.map +1 -0
  168. package/dist/db/schema/running-job-executions.js +41 -0
  169. package/dist/db/schema/running-job-executions.js.map +1 -0
  170. package/dist/index.d.ts +6 -0
  171. package/dist/index.d.ts.map +1 -0
  172. package/dist/index.js +56 -0
  173. package/dist/index.js.map +1 -0
  174. package/dist/metrics/index.d.ts +3 -0
  175. package/dist/metrics/index.d.ts.map +1 -0
  176. package/dist/metrics/index.js +4 -0
  177. package/dist/metrics/index.js.map +1 -0
  178. package/dist/metrics/instance.d.ts +34 -0
  179. package/dist/metrics/instance.d.ts.map +1 -0
  180. package/dist/metrics/instance.js +60 -0
  181. package/dist/metrics/instance.js.map +1 -0
  182. package/dist/metrics/service.d.ts +2 -0
  183. package/dist/metrics/service.d.ts.map +1 -0
  184. package/dist/metrics/service.js +21 -0
  185. package/dist/metrics/service.js.map +1 -0
  186. package/dist/presentation/auth/index.d.ts +3 -0
  187. package/dist/presentation/auth/index.d.ts.map +1 -0
  188. package/dist/presentation/auth/index.js +4 -0
  189. package/dist/presentation/auth/index.js.map +1 -0
  190. package/dist/presentation/auth/provisioner-token-auth.d.ts +3 -0
  191. package/dist/presentation/auth/provisioner-token-auth.d.ts.map +1 -0
  192. package/dist/presentation/auth/provisioner-token-auth.js +81 -0
  193. package/dist/presentation/auth/provisioner-token-auth.js.map +1 -0
  194. package/dist/presentation/auth/runner-registration-token-auth.d.ts +17 -0
  195. package/dist/presentation/auth/runner-registration-token-auth.d.ts.map +1 -0
  196. package/dist/presentation/auth/runner-registration-token-auth.js +77 -0
  197. package/dist/presentation/auth/runner-registration-token-auth.js.map +1 -0
  198. package/dist/presentation/dto/active-provisioner.d.ts +8 -0
  199. package/dist/presentation/dto/active-provisioner.d.ts.map +1 -0
  200. package/dist/presentation/dto/active-provisioner.js +10 -0
  201. package/dist/presentation/dto/active-provisioner.js.map +1 -0
  202. package/dist/presentation/dto/index.d.ts +7 -0
  203. package/dist/presentation/dto/index.d.ts.map +1 -0
  204. package/dist/presentation/dto/index.js +8 -0
  205. package/dist/presentation/dto/index.js.map +1 -0
  206. package/dist/presentation/dto/manual-registration-token.d.ts +12 -0
  207. package/dist/presentation/dto/manual-registration-token.d.ts.map +1 -0
  208. package/dist/presentation/dto/manual-registration-token.js +14 -0
  209. package/dist/presentation/dto/manual-registration-token.js.map +1 -0
  210. package/dist/presentation/dto/mint-registration-tokens.d.ts +5 -0
  211. package/dist/presentation/dto/mint-registration-tokens.d.ts.map +1 -0
  212. package/dist/presentation/dto/mint-registration-tokens.js +19 -0
  213. package/dist/presentation/dto/mint-registration-tokens.js.map +1 -0
  214. package/dist/presentation/dto/poll-demand.d.ts +4 -0
  215. package/dist/presentation/dto/poll-demand.d.ts.map +1 -0
  216. package/dist/presentation/dto/poll-demand.js +19 -0
  217. package/dist/presentation/dto/poll-demand.js.map +1 -0
  218. package/dist/presentation/dto/provisioned-runners.d.ts +38 -0
  219. package/dist/presentation/dto/provisioned-runners.d.ts.map +1 -0
  220. package/dist/presentation/dto/provisioned-runners.js +44 -0
  221. package/dist/presentation/dto/provisioned-runners.js.map +1 -0
  222. package/dist/presentation/dto/provisioner-token.d.ts +15 -0
  223. package/dist/presentation/dto/provisioner-token.d.ts.map +1 -0
  224. package/dist/presentation/dto/provisioner-token.js +17 -0
  225. package/dist/presentation/dto/provisioner-token.js.map +1 -0
  226. package/dist/presentation/index.d.ts +4 -0
  227. package/dist/presentation/index.d.ts.map +1 -0
  228. package/dist/presentation/index.js +5 -0
  229. package/dist/presentation/index.js.map +1 -0
  230. package/dist/presentation/routes/create-manual-registration-token.d.ts +2 -0
  231. package/dist/presentation/routes/create-manual-registration-token.d.ts.map +1 -0
  232. package/dist/presentation/routes/create-manual-registration-token.js +44 -0
  233. package/dist/presentation/routes/create-manual-registration-token.js.map +1 -0
  234. package/dist/presentation/routes/create-provisioner-token.d.ts +2 -0
  235. package/dist/presentation/routes/create-provisioner-token.d.ts.map +1 -0
  236. package/dist/presentation/routes/create-provisioner-token.js +42 -0
  237. package/dist/presentation/routes/create-provisioner-token.js.map +1 -0
  238. package/dist/presentation/routes/get-provisioner-me.d.ts +2 -0
  239. package/dist/presentation/routes/get-provisioner-me.d.ts.map +1 -0
  240. package/dist/presentation/routes/get-provisioner-me.js +22 -0
  241. package/dist/presentation/routes/get-provisioner-me.js.map +1 -0
  242. package/dist/presentation/routes/heartbeat.d.ts +2 -0
  243. package/dist/presentation/routes/heartbeat.d.ts.map +1 -0
  244. package/dist/presentation/routes/heartbeat.js +64 -0
  245. package/dist/presentation/routes/heartbeat.js.map +1 -0
  246. package/dist/presentation/routes/index.d.ts +4 -0
  247. package/dist/presentation/routes/index.d.ts.map +1 -0
  248. package/dist/presentation/routes/index.js +97 -0
  249. package/dist/presentation/routes/index.js.map +1 -0
  250. package/dist/presentation/routes/list-active-provisioners.d.ts +2 -0
  251. package/dist/presentation/routes/list-active-provisioners.d.ts.map +1 -0
  252. package/dist/presentation/routes/list-active-provisioners.js +32 -0
  253. package/dist/presentation/routes/list-active-provisioners.js.map +1 -0
  254. package/dist/presentation/routes/list-active-runners.d.ts +2 -0
  255. package/dist/presentation/routes/list-active-runners.d.ts.map +1 -0
  256. package/dist/presentation/routes/list-active-runners.js +32 -0
  257. package/dist/presentation/routes/list-active-runners.js.map +1 -0
  258. package/dist/presentation/routes/list-manual-registration-tokens.d.ts +2 -0
  259. package/dist/presentation/routes/list-manual-registration-tokens.d.ts.map +1 -0
  260. package/dist/presentation/routes/list-manual-registration-tokens.js +32 -0
  261. package/dist/presentation/routes/list-manual-registration-tokens.js.map +1 -0
  262. package/dist/presentation/routes/list-provisioner-tokens.d.ts +2 -0
  263. package/dist/presentation/routes/list-provisioner-tokens.d.ts.map +1 -0
  264. package/dist/presentation/routes/list-provisioner-tokens.js +32 -0
  265. package/dist/presentation/routes/list-provisioner-tokens.js.map +1 -0
  266. package/dist/presentation/routes/mint-registration-tokens.d.ts +2 -0
  267. package/dist/presentation/routes/mint-registration-tokens.d.ts.map +1 -0
  268. package/dist/presentation/routes/mint-registration-tokens.js +74 -0
  269. package/dist/presentation/routes/mint-registration-tokens.js.map +1 -0
  270. package/dist/presentation/routes/poll-demand.d.ts +2 -0
  271. package/dist/presentation/routes/poll-demand.d.ts.map +1 -0
  272. package/dist/presentation/routes/poll-demand.js +53 -0
  273. package/dist/presentation/routes/poll-demand.js.map +1 -0
  274. package/dist/presentation/routes/rate-limit.d.ts +4 -0
  275. package/dist/presentation/routes/rate-limit.d.ts.map +1 -0
  276. package/dist/presentation/routes/rate-limit.js +94 -0
  277. package/dist/presentation/routes/rate-limit.js.map +1 -0
  278. package/dist/presentation/routes/reconcile-provisioned-runners.d.ts +2 -0
  279. package/dist/presentation/routes/reconcile-provisioned-runners.d.ts.map +1 -0
  280. package/dist/presentation/routes/reconcile-provisioned-runners.js +27 -0
  281. package/dist/presentation/routes/reconcile-provisioned-runners.js.map +1 -0
  282. package/dist/presentation/routes/register.d.ts +2 -0
  283. package/dist/presentation/routes/register.d.ts.map +1 -0
  284. package/dist/presentation/routes/register.js +63 -0
  285. package/dist/presentation/routes/register.js.map +1 -0
  286. package/dist/presentation/routes/report-provisioned-runners.d.ts +2 -0
  287. package/dist/presentation/routes/report-provisioned-runners.d.ts.map +1 -0
  288. package/dist/presentation/routes/report-provisioned-runners.js +37 -0
  289. package/dist/presentation/routes/report-provisioned-runners.js.map +1 -0
  290. package/dist/presentation/routes/request-job.d.ts +2 -0
  291. package/dist/presentation/routes/request-job.d.ts.map +1 -0
  292. package/dist/presentation/routes/request-job.js +45 -0
  293. package/dist/presentation/routes/request-job.js.map +1 -0
  294. package/dist/presentation/routes/revoke-manual-registration-token.d.ts +2 -0
  295. package/dist/presentation/routes/revoke-manual-registration-token.d.ts.map +1 -0
  296. package/dist/presentation/routes/revoke-manual-registration-token.js +42 -0
  297. package/dist/presentation/routes/revoke-manual-registration-token.js.map +1 -0
  298. package/dist/presentation/routes/revoke-provisioner-token.d.ts +2 -0
  299. package/dist/presentation/routes/revoke-provisioner-token.d.ts.map +1 -0
  300. package/dist/presentation/routes/revoke-provisioner-token.js +44 -0
  301. package/dist/presentation/routes/revoke-provisioner-token.js.map +1 -0
  302. package/dist/presentation/routes/workspace-membership.d.ts +6 -0
  303. package/dist/presentation/routes/workspace-membership.d.ts.map +1 -0
  304. package/dist/presentation/routes/workspace-membership.js +6 -0
  305. package/dist/presentation/routes/workspace-membership.js.map +1 -0
  306. package/dist/presentation/subscribers/on-workflows-job-execution-timed-out.d.ts +3 -0
  307. package/dist/presentation/subscribers/on-workflows-job-execution-timed-out.d.ts.map +1 -0
  308. package/dist/presentation/subscribers/on-workflows-job-execution-timed-out.js +14 -0
  309. package/dist/presentation/subscribers/on-workflows-job-execution-timed-out.js.map +1 -0
  310. package/dist/temporal/activities/index.d.ts +9 -0
  311. package/dist/temporal/activities/index.d.ts.map +1 -0
  312. package/dist/temporal/activities/index.js +12 -0
  313. package/dist/temporal/activities/index.js.map +1 -0
  314. package/dist/temporal/activities/maintenance-activities.d.ts +31 -0
  315. package/dist/temporal/activities/maintenance-activities.d.ts.map +1 -0
  316. package/dist/temporal/activities/maintenance-activities.js +18 -0
  317. package/dist/temporal/activities/maintenance-activities.js.map +1 -0
  318. package/dist/temporal/constants.d.ts +2 -0
  319. package/dist/temporal/constants.d.ts.map +1 -0
  320. package/dist/temporal/constants.js +3 -0
  321. package/dist/temporal/constants.js.map +1 -0
  322. package/dist/temporal/workflows/index.d.ts +2 -0
  323. package/dist/temporal/workflows/index.d.ts.map +1 -0
  324. package/dist/temporal/workflows/index.js +3 -0
  325. package/dist/temporal/workflows/index.js.map +1 -0
  326. package/dist/temporal/workflows/stuck-job-detector.d.ts +2 -0
  327. package/dist/temporal/workflows/stuck-job-detector.d.ts.map +1 -0
  328. package/dist/temporal/workflows/stuck-job-detector.js +61 -0
  329. package/dist/temporal/workflows/stuck-job-detector.js.map +1 -0
  330. package/dist/tsconfig.test.tsbuildinfo +1 -0
  331. package/drizzle/0000_initial.sql +185 -0
  332. package/drizzle/meta/0000_snapshot.json +1582 -0
  333. package/drizzle/meta/_journal.json +13 -0
  334. package/drizzle.config.ts +7 -0
  335. package/package.json +82 -0
  336. package/src/config.test.ts +374 -0
  337. package/src/config.ts +330 -0
  338. package/src/core/demand.test.ts +301 -0
  339. package/src/core/demand.ts +239 -0
  340. package/src/core/entities/ephemeral-registration-token.ts +13 -0
  341. package/src/core/entities/manual-registration-token.ts +11 -0
  342. package/src/core/entities/provisioned-runner.ts +30 -0
  343. package/src/core/entities/provisioner-token.ts +16 -0
  344. package/src/core/entities/reservation.ts +9 -0
  345. package/src/core/entities/runner-session.ts +18 -0
  346. package/src/core/ephemeral-registration-tokens.test.ts +108 -0
  347. package/src/core/ephemeral-registration-tokens.ts +112 -0
  348. package/src/core/errors.ts +128 -0
  349. package/src/core/index.ts +56 -0
  350. package/src/core/job-executions.ts +47 -0
  351. package/src/core/maintenance-policy.ts +1 -0
  352. package/src/core/maintenance.test.ts +251 -0
  353. package/src/core/maintenance.ts +74 -0
  354. package/src/core/manual-registration-tokens.test.ts +44 -0
  355. package/src/core/manual-registration-tokens.ts +51 -0
  356. package/src/core/provisioned-runners.test.ts +101 -0
  357. package/src/core/provisioned-runners.ts +301 -0
  358. package/src/core/provisioner-tokens.test.ts +61 -0
  359. package/src/core/provisioner-tokens.ts +61 -0
  360. package/src/core/rate-limit.test.ts +158 -0
  361. package/src/core/rate-limit.ts +121 -0
  362. package/src/core/runner-sessions.test.ts +209 -0
  363. package/src/core/runner-sessions.ts +66 -0
  364. package/src/core/runner-tool-capabilities.test.ts +141 -0
  365. package/src/core/runner-tool-capabilities.ts +75 -0
  366. package/src/db/db.ts +38 -0
  367. package/src/db/ephemeral-registration-tokens.test.ts +332 -0
  368. package/src/db/ephemeral-registration-tokens.ts +348 -0
  369. package/src/db/index.ts +90 -0
  370. package/src/db/job-executions.test.ts +1500 -0
  371. package/src/db/job-executions.ts +647 -0
  372. package/src/db/manual-registration-tokens.test.ts +99 -0
  373. package/src/db/manual-registration-tokens.ts +87 -0
  374. package/src/db/provisioned-runners.test.ts +1812 -0
  375. package/src/db/provisioned-runners.ts +886 -0
  376. package/src/db/provisioner-tokens.test.ts +133 -0
  377. package/src/db/provisioner-tokens.ts +142 -0
  378. package/src/db/rate-limits.test.ts +74 -0
  379. package/src/db/rate-limits.ts +69 -0
  380. package/src/db/reservations.test.ts +399 -0
  381. package/src/db/reservations.ts +296 -0
  382. package/src/db/runner-sessions.test.ts +153 -0
  383. package/src/db/runner-sessions.ts +97 -0
  384. package/src/db/schema/common.ts +3 -0
  385. package/src/db/schema/ephemeral-registration-tokens.ts +58 -0
  386. package/src/db/schema/manual-registration-tokens.ts +40 -0
  387. package/src/db/schema/outbox.ts +4 -0
  388. package/src/db/schema/pending-job-executions.ts +25 -0
  389. package/src/db/schema/provisioned-runners.ts +89 -0
  390. package/src/db/schema/provisioner-tokens.ts +50 -0
  391. package/src/db/schema/rate-limits.ts +27 -0
  392. package/src/db/schema/reservations.ts +38 -0
  393. package/src/db/schema/runner-sessions.ts +77 -0
  394. package/src/db/schema/running-job-executions.ts +50 -0
  395. package/src/index.ts +63 -0
  396. package/src/metrics/index.ts +13 -0
  397. package/src/metrics/instance.ts +115 -0
  398. package/src/metrics/service.ts +22 -0
  399. package/src/presentation/auth/index.ts +6 -0
  400. package/src/presentation/auth/provisioner-token-auth.ts +76 -0
  401. package/src/presentation/auth/runner-registration-token-auth.ts +105 -0
  402. package/src/presentation/dto/active-provisioner.ts +15 -0
  403. package/src/presentation/dto/index.ts +13 -0
  404. package/src/presentation/dto/manual-registration-token.ts +23 -0
  405. package/src/presentation/dto/mint-registration-tokens.ts +35 -0
  406. package/src/presentation/dto/poll-demand.ts +20 -0
  407. package/src/presentation/dto/provisioned-runners.ts +88 -0
  408. package/src/presentation/dto/provisioner-token.ts +29 -0
  409. package/src/presentation/index.ts +6 -0
  410. package/src/presentation/routes/create-manual-registration-token.ts +43 -0
  411. package/src/presentation/routes/create-provisioner-token.ts +41 -0
  412. package/src/presentation/routes/get-provisioner-me.ts +22 -0
  413. package/src/presentation/routes/heartbeat.test.ts +325 -0
  414. package/src/presentation/routes/heartbeat.ts +80 -0
  415. package/src/presentation/routes/index.ts +86 -0
  416. package/src/presentation/routes/list-active-provisioners.ts +25 -0
  417. package/src/presentation/routes/list-active-runners.test.ts +366 -0
  418. package/src/presentation/routes/list-active-runners.ts +25 -0
  419. package/src/presentation/routes/list-manual-registration-tokens.ts +25 -0
  420. package/src/presentation/routes/list-provisioner-tokens.ts +25 -0
  421. package/src/presentation/routes/manual-registration-tokens.test.ts +213 -0
  422. package/src/presentation/routes/mint-registration-tokens.test.ts +453 -0
  423. package/src/presentation/routes/mint-registration-tokens.ts +82 -0
  424. package/src/presentation/routes/poll-demand-release.test.ts +80 -0
  425. package/src/presentation/routes/poll-demand.test.ts +323 -0
  426. package/src/presentation/routes/poll-demand.ts +56 -0
  427. package/src/presentation/routes/provisioner-me.test.ts +172 -0
  428. package/src/presentation/routes/provisioner-tokens.test.ts +219 -0
  429. package/src/presentation/routes/rate-limit.ts +115 -0
  430. package/src/presentation/routes/reconcile-provisioned-runners.test.ts +380 -0
  431. package/src/presentation/routes/reconcile-provisioned-runners.ts +30 -0
  432. package/src/presentation/routes/register.test.ts +453 -0
  433. package/src/presentation/routes/register.ts +75 -0
  434. package/src/presentation/routes/report-provisioned-runners.test.ts +249 -0
  435. package/src/presentation/routes/report-provisioned-runners.ts +40 -0
  436. package/src/presentation/routes/request-job.test.ts +222 -0
  437. package/src/presentation/routes/request-job.ts +47 -0
  438. package/src/presentation/routes/revoke-manual-registration-token.ts +35 -0
  439. package/src/presentation/routes/revoke-provisioner-token.ts +37 -0
  440. package/src/presentation/routes/workspace-membership.ts +9 -0
  441. package/src/presentation/subscribers/on-workflows-job-execution-timed-out.test.ts +147 -0
  442. package/src/presentation/subscribers/on-workflows-job-execution-timed-out.ts +17 -0
  443. package/src/temporal/activities/index.ts +17 -0
  444. package/src/temporal/activities/maintenance-activities.test.ts +104 -0
  445. package/src/temporal/activities/maintenance-activities.ts +41 -0
  446. package/src/temporal/constants.ts +1 -0
  447. package/src/temporal/workflows/index.ts +1 -0
  448. package/src/temporal/workflows/stuck-job-detector.test.ts +93 -0
  449. package/src/temporal/workflows/stuck-job-detector.ts +67 -0
  450. package/test/env.ts +11 -0
  451. package/test/factories/ephemeral-registration-token.ts +41 -0
  452. package/test/factories/manual-registration-token.ts +37 -0
  453. package/test/factories/pending-job.ts +44 -0
  454. package/test/factories/provisioned-runner.ts +78 -0
  455. package/test/factories/provisioner-token.ts +41 -0
  456. package/test/factories/reservation.ts +33 -0
  457. package/test/factories/runner-session.ts +32 -0
  458. package/test/globalSetup.ts +23 -0
  459. package/test/index.ts +16 -0
  460. package/test/setup.ts +17 -0
  461. package/tsconfig.build.json +9 -0
  462. package/tsconfig.build.tsbuildinfo +1 -0
  463. package/tsconfig.json +3 -0
  464. package/tsconfig.test.json +8 -0
  465. package/vitest.config.ts +14 -0
@@ -0,0 +1,162 @@
1
+ import { isTerminalState, listActiveProvisionedRunners, listActiveRunningJobExecutions, reconcileProvisionedRunners as reconcileProvisionedRunnersDb, reportProvisionedRunners as reportProvisionedRunnersDb } from '#db/index.js';
2
+ import { provisionedRunnerAbsentTerminatedCount, provisionedRunnerReconcileCallCount, provisionedRunnerReportCount, provisionedRunnerTerminateIntentHonoredCount, provisionedRunnerTerminateIntentIssuedCount, reservationReleasedCount } from '#metrics/instance.js';
3
+ import { config } from '../config.js';
4
+ export async function reportProvisionedRunners(params) {
5
+ const result = await reportProvisionedRunnersDb(params);
6
+ for (const event of params.events){
7
+ provisionedRunnerReportCount.add(1, {
8
+ state: event.state
9
+ });
10
+ }
11
+ for (const intent of result.terminateIntentsHonored){
12
+ provisionedRunnerTerminateIntentHonoredCount.add(1, {
13
+ reason: intent.reason
14
+ });
15
+ }
16
+ if (result.reservationsReleased > 0) reservationReleasedCount.add(result.reservationsReleased);
17
+ return result;
18
+ }
19
+ export async function reconcileProvisionedRunners(params) {
20
+ const result = await reconcileProvisionedRunnersDb({
21
+ ...params,
22
+ terminateGraceSeconds: config.RUNNER_RECONCILE_TERMINATE_GRACE_SECONDS
23
+ });
24
+ if (result.reservationsReleased > 0) reservationReleasedCount.add(result.reservationsReleased);
25
+ provisionedRunnerReconcileCallCount.add(1);
26
+ if (result.absentIds.length > 0) provisionedRunnerAbsentTerminatedCount.add(result.absentIds.length);
27
+ const runners = reconcileProvisionedRunnersFromDbResult({
28
+ observedProvisionedRunnerIds: params.observedProvisionedRunnerIds,
29
+ observedRows: result.observedRows,
30
+ boundJobExecutionsByProvisionedRunnerId: result.boundJobExecutionsByProvisionedRunnerId
31
+ });
32
+ for (const runner of runners){
33
+ if (runner.desiredIntentReason) {
34
+ provisionedRunnerTerminateIntentIssuedCount.add(1, {
35
+ surface: 'reconcile',
36
+ reason: runner.desiredIntentReason
37
+ });
38
+ }
39
+ }
40
+ return {
41
+ runners,
42
+ terminatedAbsentProvisionedRunnerIds: result.absentIds
43
+ };
44
+ }
45
+ export function reconcileProvisionedRunnersFromDbResult(params) {
46
+ const rowsByProvisionedRunnerId = new Map(params.observedRows.map((row)=>[
47
+ row.provisionedRunnerId,
48
+ row
49
+ ]));
50
+ return params.observedProvisionedRunnerIds.map((provisionedRunnerId)=>{
51
+ const row = rowsByProvisionedRunnerId.get(provisionedRunnerId);
52
+ const boundJobExecution = params.boundJobExecutionsByProvisionedRunnerId.get(provisionedRunnerId);
53
+ const desiredIntentReason = getDesiredIntentReason(row, boundJobExecution);
54
+ return {
55
+ provisionedRunnerId,
56
+ state: row?.state ?? null,
57
+ reservationId: row?.reservationId ?? null,
58
+ runnerSessionId: row?.runnerSessionId ?? null,
59
+ boundJobExecution: boundJobExecution ? toReconciledBoundJobExecution(boundJobExecution) : null,
60
+ desiredIntent: desiredIntentReason ? 'terminate' : 'keep',
61
+ desiredIntentReason
62
+ };
63
+ });
64
+ }
65
+ export async function listActiveRunners(params) {
66
+ const [provisionedRunnerRows, jobExecutionRows] = await Promise.all([
67
+ listActiveProvisionedRunners({
68
+ workspaceId: params.workspaceId,
69
+ windowSeconds: config.RUNNER_ACTIVE_WINDOW_SECONDS
70
+ }),
71
+ listActiveRunningJobExecutions({
72
+ workspaceId: params.workspaceId,
73
+ windowSeconds: config.RUNNER_ACTIVE_WINDOW_SECONDS
74
+ })
75
+ ]);
76
+ return mergeActiveRunners(provisionedRunnerRows, jobExecutionRows);
77
+ }
78
+ function toReconciledBoundJobExecution(jobExecution) {
79
+ return {
80
+ jobId: jobExecution.jobId,
81
+ jobExecutionId: jobExecution.jobExecutionId,
82
+ workflowRunAttemptId: jobExecution.workflowRunAttemptId,
83
+ lastHeartbeatAt: jobExecution.lastHeartbeatAt,
84
+ cancellationRequestedAt: jobExecution.cancellationRequestedAt
85
+ };
86
+ }
87
+ export function desiredIntent(row, boundJobExecution) {
88
+ return getDesiredIntentReason(row, boundJobExecution) ? 'terminate' : 'keep';
89
+ }
90
+ function getDesiredIntentReason(row, boundJobExecution) {
91
+ if (!row) return null;
92
+ if (isTerminalState(row.state)) return 'terminal-state';
93
+ if (boundJobExecution?.cancellationRequestedAt) return 'job-cancelled';
94
+ return null;
95
+ }
96
+ function mergeActiveRunners(provisionedRunners, jobExecutions) {
97
+ const jobExecutionsByRunnerSessionId = new Map();
98
+ const jobExecutionsByProvisionedRunnerId = new Map();
99
+ for (const jobExecution of jobExecutions){
100
+ const runnerJobExecutions = jobExecutionsByRunnerSessionId.get(jobExecution.runnerSessionId) ?? [];
101
+ runnerJobExecutions.push(jobExecution);
102
+ jobExecutionsByRunnerSessionId.set(jobExecution.runnerSessionId, runnerJobExecutions);
103
+ if (jobExecution.provisionerId && jobExecution.provisionedRunnerId) {
104
+ const key = provisionedRunnerKey(jobExecution.provisionerId, jobExecution.provisionedRunnerId);
105
+ const provisionedRunnerJobExecutions = jobExecutionsByProvisionedRunnerId.get(key) ?? [];
106
+ provisionedRunnerJobExecutions.push(jobExecution);
107
+ jobExecutionsByProvisionedRunnerId.set(key, provisionedRunnerJobExecutions);
108
+ }
109
+ }
110
+ const merged = [];
111
+ const usedJobExecutionIds = new Set();
112
+ for (const provisionedRunner of provisionedRunners){
113
+ const provisionedRunnerJobExecutions = jobExecutionsByProvisionedRunnerId.get(provisionedRunnerKey(provisionedRunner.provisionerId, provisionedRunner.provisionedRunnerId)) ?? (provisionedRunner.runnerSessionId ? jobExecutionsByRunnerSessionId.get(provisionedRunner.runnerSessionId) : undefined);
114
+ if (!provisionedRunnerJobExecutions || provisionedRunnerJobExecutions.length === 0) {
115
+ merged.push(toActiveRunner(provisionedRunner, undefined));
116
+ continue;
117
+ }
118
+ let emitted = false;
119
+ for (const jobExecution of provisionedRunnerJobExecutions){
120
+ if (usedJobExecutionIds.has(jobExecution.jobExecutionId)) continue;
121
+ usedJobExecutionIds.add(jobExecution.jobExecutionId);
122
+ merged.push(toActiveRunner(provisionedRunner, jobExecution));
123
+ emitted = true;
124
+ }
125
+ if (!emitted) merged.push(toActiveRunner(provisionedRunner, undefined));
126
+ }
127
+ for (const jobExecution of jobExecutions){
128
+ if (usedJobExecutionIds.has(jobExecution.jobExecutionId)) continue;
129
+ merged.push(toActiveRunner(undefined, jobExecution));
130
+ }
131
+ return merged.sort(compareActiveRunners);
132
+ }
133
+ function provisionedRunnerKey(provisionerId, provisionedRunnerId) {
134
+ return `${provisionerId}:${provisionedRunnerId}`;
135
+ }
136
+ function toActiveRunner(provisionedRunner, jobExecution) {
137
+ return {
138
+ runnerSessionId: provisionedRunner?.runnerSessionId ?? jobExecution?.runnerSessionId ?? null,
139
+ provisionedRunnerId: provisionedRunner?.provisionedRunnerId ?? jobExecution?.provisionedRunnerId ?? null,
140
+ provisionerId: provisionedRunner?.provisionerId ?? jobExecution?.provisionerId ?? null,
141
+ state: jobExecution ? 'busy' : toActiveRunnerState(provisionedRunner?.state ?? 'running'),
142
+ labels: provisionedRunner?.labels ?? jobExecution?.runnerLabels ?? [],
143
+ templateKey: provisionedRunner?.templateKey ?? null,
144
+ providerKind: provisionedRunner?.providerKind ?? null,
145
+ jobId: jobExecution?.jobId ?? null,
146
+ workflowRunAttemptId: jobExecution?.workflowRunAttemptId ?? null,
147
+ projectId: jobExecution?.projectId ?? null,
148
+ reportedAt: provisionedRunner?.reportedAt ?? null,
149
+ lastHeartbeatAt: jobExecution?.lastHeartbeatAt ?? null
150
+ };
151
+ }
152
+ function toActiveRunnerState(state) {
153
+ if (state === 'starting' || state === 'stopping') return state;
154
+ return 'running';
155
+ }
156
+ function compareActiveRunners(a, b) {
157
+ const aTime = Math.max(a.lastHeartbeatAt?.getTime() ?? 0, a.reportedAt?.getTime() ?? 0);
158
+ const bTime = Math.max(b.lastHeartbeatAt?.getTime() ?? 0, b.reportedAt?.getTime() ?? 0);
159
+ return bTime - aTime;
160
+ }
161
+
162
+ //# sourceMappingURL=provisioned-runners.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/provisioned-runners.ts"],"sourcesContent":["import type {ProvisionedRunner, ProvisionedRunnerState} from '#core/entities/provisioned-runner.js';\nimport {\n isTerminalState,\n listActiveProvisionedRunners,\n listActiveRunningJobExecutions,\n type ProvisionedRunnerReportEvent,\n reconcileProvisionedRunners as reconcileProvisionedRunnersDb,\n reportProvisionedRunners as reportProvisionedRunnersDb,\n} from '#db/index.js';\nimport type {\n ActiveRunningJobExecution,\n ProvisionedRunnerBoundJobExecution,\n} from '#db/job-executions.js';\nimport {\n provisionedRunnerAbsentTerminatedCount,\n provisionedRunnerReconcileCallCount,\n provisionedRunnerReportCount,\n provisionedRunnerTerminateIntentHonoredCount,\n provisionedRunnerTerminateIntentIssuedCount,\n reservationReleasedCount,\n} from '#metrics/instance.js';\nimport {config} from '../config.js';\n\nexport interface ReportProvisionedRunnersParams {\n workspaceId: string;\n provisionerId: string;\n events: ProvisionedRunnerReportEvent[];\n}\n\nexport interface ReportProvisionedRunnersResult {\n accepted: number;\n reservationsReleased: number;\n}\n\nexport interface ReconcileProvisionedRunnersParams {\n workspaceId: string;\n provisionerId: string;\n observedProvisionedRunnerIds: string[];\n}\n\nexport type ReconcileDesiredIntent = 'keep' | 'terminate';\ntype ReconcileDesiredIntentReason = 'job-cancelled' | 'terminal-state';\n\nexport interface ReconciledBoundJobExecution {\n jobId: string;\n jobExecutionId: string;\n workflowRunAttemptId: string;\n lastHeartbeatAt: Date;\n cancellationRequestedAt: Date | null;\n}\n\nexport interface ReconciledProvisionedRunner {\n provisionedRunnerId: string;\n state: ProvisionedRunnerState | null;\n reservationId: string | null;\n runnerSessionId: string | null;\n boundJobExecution: ReconciledBoundJobExecution | null;\n desiredIntent: ReconcileDesiredIntent;\n desiredIntentReason: ReconcileDesiredIntentReason | null;\n}\n\nexport interface ReconcileProvisionedRunnersResult {\n runners: ReconciledProvisionedRunner[];\n terminatedAbsentProvisionedRunnerIds: string[];\n}\n\nexport type ActiveRunnerState = 'starting' | 'running' | 'stopping' | 'busy';\n\nexport interface ActiveRunner {\n runnerSessionId: string | null;\n provisionedRunnerId: string | null;\n provisionerId: string | null;\n state: ActiveRunnerState;\n labels: string[];\n templateKey: string | null;\n providerKind: string | null;\n jobId: string | null;\n workflowRunAttemptId: string | null;\n projectId: string | null;\n reportedAt: Date | null;\n lastHeartbeatAt: Date | null;\n}\n\nexport async function reportProvisionedRunners(\n params: ReportProvisionedRunnersParams,\n): Promise<ReportProvisionedRunnersResult> {\n const result = await reportProvisionedRunnersDb(params);\n\n for (const event of params.events) {\n provisionedRunnerReportCount.add(1, {state: event.state});\n }\n for (const intent of result.terminateIntentsHonored) {\n provisionedRunnerTerminateIntentHonoredCount.add(1, {reason: intent.reason});\n }\n if (result.reservationsReleased > 0) reservationReleasedCount.add(result.reservationsReleased);\n\n return result;\n}\n\nexport async function reconcileProvisionedRunners(\n params: ReconcileProvisionedRunnersParams,\n): Promise<ReconcileProvisionedRunnersResult> {\n const result = await reconcileProvisionedRunnersDb({\n ...params,\n terminateGraceSeconds: config.RUNNER_RECONCILE_TERMINATE_GRACE_SECONDS,\n });\n\n if (result.reservationsReleased > 0) reservationReleasedCount.add(result.reservationsReleased);\n provisionedRunnerReconcileCallCount.add(1);\n if (result.absentIds.length > 0)\n provisionedRunnerAbsentTerminatedCount.add(result.absentIds.length);\n\n const runners = reconcileProvisionedRunnersFromDbResult({\n observedProvisionedRunnerIds: params.observedProvisionedRunnerIds,\n observedRows: result.observedRows,\n boundJobExecutionsByProvisionedRunnerId: result.boundJobExecutionsByProvisionedRunnerId,\n });\n for (const runner of runners) {\n if (runner.desiredIntentReason) {\n provisionedRunnerTerminateIntentIssuedCount.add(1, {\n surface: 'reconcile',\n reason: runner.desiredIntentReason,\n });\n }\n }\n\n return {\n runners,\n terminatedAbsentProvisionedRunnerIds: result.absentIds,\n };\n}\n\nexport function reconcileProvisionedRunnersFromDbResult(params: {\n observedProvisionedRunnerIds: string[];\n observedRows: ProvisionedRunner[];\n boundJobExecutionsByProvisionedRunnerId: Map<string, ProvisionedRunnerBoundJobExecution>;\n}): ReconciledProvisionedRunner[] {\n const rowsByProvisionedRunnerId = new Map(\n params.observedRows.map((row) => [row.provisionedRunnerId, row]),\n );\n\n return params.observedProvisionedRunnerIds.map((provisionedRunnerId) => {\n const row = rowsByProvisionedRunnerId.get(provisionedRunnerId);\n const boundJobExecution =\n params.boundJobExecutionsByProvisionedRunnerId.get(provisionedRunnerId);\n\n const desiredIntentReason = getDesiredIntentReason(row, boundJobExecution);\n\n return {\n provisionedRunnerId,\n state: row?.state ?? null,\n reservationId: row?.reservationId ?? null,\n runnerSessionId: row?.runnerSessionId ?? null,\n boundJobExecution: boundJobExecution\n ? toReconciledBoundJobExecution(boundJobExecution)\n : null,\n desiredIntent: desiredIntentReason ? 'terminate' : 'keep',\n desiredIntentReason,\n };\n });\n}\n\nexport async function listActiveRunners(params: {workspaceId: string}): Promise<ActiveRunner[]> {\n const [provisionedRunnerRows, jobExecutionRows] = await Promise.all([\n listActiveProvisionedRunners({\n workspaceId: params.workspaceId,\n windowSeconds: config.RUNNER_ACTIVE_WINDOW_SECONDS,\n }),\n listActiveRunningJobExecutions({\n workspaceId: params.workspaceId,\n windowSeconds: config.RUNNER_ACTIVE_WINDOW_SECONDS,\n }),\n ]);\n\n return mergeActiveRunners(provisionedRunnerRows, jobExecutionRows);\n}\n\nfunction toReconciledBoundJobExecution(\n jobExecution: ProvisionedRunnerBoundJobExecution,\n): ReconciledBoundJobExecution {\n return {\n jobId: jobExecution.jobId,\n jobExecutionId: jobExecution.jobExecutionId,\n workflowRunAttemptId: jobExecution.workflowRunAttemptId,\n lastHeartbeatAt: jobExecution.lastHeartbeatAt,\n cancellationRequestedAt: jobExecution.cancellationRequestedAt,\n };\n}\n\nexport function desiredIntent(\n row: ProvisionedRunner | undefined,\n boundJobExecution: ProvisionedRunnerBoundJobExecution | undefined,\n): ReconcileDesiredIntent {\n return getDesiredIntentReason(row, boundJobExecution) ? 'terminate' : 'keep';\n}\n\nfunction getDesiredIntentReason(\n row: ProvisionedRunner | undefined,\n boundJobExecution: ProvisionedRunnerBoundJobExecution | undefined,\n): ReconcileDesiredIntentReason | null {\n if (!row) return null;\n if (isTerminalState(row.state)) return 'terminal-state';\n if (boundJobExecution?.cancellationRequestedAt) return 'job-cancelled';\n return null;\n}\n\nfunction mergeActiveRunners(\n provisionedRunners: ProvisionedRunner[],\n jobExecutions: ActiveRunningJobExecution[],\n): ActiveRunner[] {\n const jobExecutionsByRunnerSessionId = new Map<string, ActiveRunningJobExecution[]>();\n const jobExecutionsByProvisionedRunnerId = new Map<string, ActiveRunningJobExecution[]>();\n for (const jobExecution of jobExecutions) {\n const runnerJobExecutions =\n jobExecutionsByRunnerSessionId.get(jobExecution.runnerSessionId) ?? [];\n runnerJobExecutions.push(jobExecution);\n jobExecutionsByRunnerSessionId.set(jobExecution.runnerSessionId, runnerJobExecutions);\n\n if (jobExecution.provisionerId && jobExecution.provisionedRunnerId) {\n const key = provisionedRunnerKey(\n jobExecution.provisionerId,\n jobExecution.provisionedRunnerId,\n );\n const provisionedRunnerJobExecutions = jobExecutionsByProvisionedRunnerId.get(key) ?? [];\n provisionedRunnerJobExecutions.push(jobExecution);\n jobExecutionsByProvisionedRunnerId.set(key, provisionedRunnerJobExecutions);\n }\n }\n\n const merged: ActiveRunner[] = [];\n const usedJobExecutionIds = new Set<string>();\n\n for (const provisionedRunner of provisionedRunners) {\n const provisionedRunnerJobExecutions =\n jobExecutionsByProvisionedRunnerId.get(\n provisionedRunnerKey(\n provisionedRunner.provisionerId,\n provisionedRunner.provisionedRunnerId,\n ),\n ) ??\n (provisionedRunner.runnerSessionId\n ? jobExecutionsByRunnerSessionId.get(provisionedRunner.runnerSessionId)\n : undefined);\n if (!provisionedRunnerJobExecutions || provisionedRunnerJobExecutions.length === 0) {\n merged.push(toActiveRunner(provisionedRunner, undefined));\n continue;\n }\n\n let emitted = false;\n for (const jobExecution of provisionedRunnerJobExecutions) {\n if (usedJobExecutionIds.has(jobExecution.jobExecutionId)) continue;\n usedJobExecutionIds.add(jobExecution.jobExecutionId);\n merged.push(toActiveRunner(provisionedRunner, jobExecution));\n emitted = true;\n }\n if (!emitted) merged.push(toActiveRunner(provisionedRunner, undefined));\n }\n\n for (const jobExecution of jobExecutions) {\n if (usedJobExecutionIds.has(jobExecution.jobExecutionId)) continue;\n merged.push(toActiveRunner(undefined, jobExecution));\n }\n\n return merged.sort(compareActiveRunners);\n}\n\nfunction provisionedRunnerKey(provisionerId: string, provisionedRunnerId: string): string {\n return `${provisionerId}:${provisionedRunnerId}`;\n}\n\nfunction toActiveRunner(\n provisionedRunner: ProvisionedRunner | undefined,\n jobExecution: ActiveRunningJobExecution | undefined,\n): ActiveRunner {\n return {\n runnerSessionId: provisionedRunner?.runnerSessionId ?? jobExecution?.runnerSessionId ?? null,\n provisionedRunnerId:\n provisionedRunner?.provisionedRunnerId ?? jobExecution?.provisionedRunnerId ?? null,\n provisionerId: provisionedRunner?.provisionerId ?? jobExecution?.provisionerId ?? null,\n state: jobExecution ? 'busy' : toActiveRunnerState(provisionedRunner?.state ?? 'running'),\n labels: provisionedRunner?.labels ?? jobExecution?.runnerLabels ?? [],\n templateKey: provisionedRunner?.templateKey ?? null,\n providerKind: provisionedRunner?.providerKind ?? null,\n jobId: jobExecution?.jobId ?? null,\n workflowRunAttemptId: jobExecution?.workflowRunAttemptId ?? null,\n projectId: jobExecution?.projectId ?? null,\n reportedAt: provisionedRunner?.reportedAt ?? null,\n lastHeartbeatAt: jobExecution?.lastHeartbeatAt ?? null,\n };\n}\n\nfunction toActiveRunnerState(state: ProvisionedRunnerState): ActiveRunnerState {\n if (state === 'starting' || state === 'stopping') return state;\n return 'running';\n}\n\nfunction compareActiveRunners(a: ActiveRunner, b: ActiveRunner): number {\n const aTime = Math.max(a.lastHeartbeatAt?.getTime() ?? 0, a.reportedAt?.getTime() ?? 0);\n const bTime = Math.max(b.lastHeartbeatAt?.getTime() ?? 0, b.reportedAt?.getTime() ?? 0);\n return bTime - aTime;\n}\n"],"names":["isTerminalState","listActiveProvisionedRunners","listActiveRunningJobExecutions","reconcileProvisionedRunners","reconcileProvisionedRunnersDb","reportProvisionedRunners","reportProvisionedRunnersDb","provisionedRunnerAbsentTerminatedCount","provisionedRunnerReconcileCallCount","provisionedRunnerReportCount","provisionedRunnerTerminateIntentHonoredCount","provisionedRunnerTerminateIntentIssuedCount","reservationReleasedCount","config","params","result","event","events","add","state","intent","terminateIntentsHonored","reason","reservationsReleased","terminateGraceSeconds","RUNNER_RECONCILE_TERMINATE_GRACE_SECONDS","absentIds","length","runners","reconcileProvisionedRunnersFromDbResult","observedProvisionedRunnerIds","observedRows","boundJobExecutionsByProvisionedRunnerId","runner","desiredIntentReason","surface","terminatedAbsentProvisionedRunnerIds","rowsByProvisionedRunnerId","Map","map","row","provisionedRunnerId","get","boundJobExecution","getDesiredIntentReason","reservationId","runnerSessionId","toReconciledBoundJobExecution","desiredIntent","listActiveRunners","provisionedRunnerRows","jobExecutionRows","Promise","all","workspaceId","windowSeconds","RUNNER_ACTIVE_WINDOW_SECONDS","mergeActiveRunners","jobExecution","jobId","jobExecutionId","workflowRunAttemptId","lastHeartbeatAt","cancellationRequestedAt","provisionedRunners","jobExecutions","jobExecutionsByRunnerSessionId","jobExecutionsByProvisionedRunnerId","runnerJobExecutions","push","set","provisionerId","key","provisionedRunnerKey","provisionedRunnerJobExecutions","merged","usedJobExecutionIds","Set","provisionedRunner","undefined","toActiveRunner","emitted","has","sort","compareActiveRunners","toActiveRunnerState","labels","runnerLabels","templateKey","providerKind","projectId","reportedAt","a","b","aTime","Math","max","getTime","bTime"],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { ActiveProvisionerToken, ProvisionerToken } from './entities/provisioner-token.js';
2
+ export interface CreateWorkspaceProvisionerTokenParams {
3
+ workspaceId: string;
4
+ createdByUserId: string;
5
+ name?: string | undefined;
6
+ ttlSeconds?: number | undefined;
7
+ }
8
+ export interface CreateWorkspaceProvisionerTokenResult {
9
+ token: ProvisionerToken;
10
+ rawToken: string;
11
+ }
12
+ export declare function createWorkspaceProvisionerToken(params: CreateWorkspaceProvisionerTokenParams): Promise<CreateWorkspaceProvisionerTokenResult>;
13
+ export declare function listUsableProvisionerTokens(workspaceId: string): Promise<ProvisionerToken[]>;
14
+ export declare function listActiveProvisioners(workspaceId: string): Promise<ActiveProvisionerToken[]>;
15
+ export declare function revokeWorkspaceProvisionerToken(params: {
16
+ tokenId: string;
17
+ workspaceId: string;
18
+ revokedByUserId: string;
19
+ }): Promise<ProvisionerToken>;
20
+ //# sourceMappingURL=provisioner-tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provisioner-tokens.d.ts","sourceRoot":"","sources":["../../src/core/provisioner-tokens.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,sBAAsB,EAAE,gBAAgB,EAAC,MAAM,iCAAiC,CAAC;AAG9F,MAAM,WAAW,qCAAqC;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAED,MAAM,WAAW,qCAAqC;IACpD,KAAK,EAAE,gBAAgB,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,+BAA+B,CACnD,MAAM,EAAE,qCAAqC,GAC5C,OAAO,CAAC,qCAAqC,CAAC,CAchD;AAED,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAE5F;AAED,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAK7F;AAED,wBAAsB,+BAA+B,CAAC,MAAM,EAAE;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAI5B"}
@@ -0,0 +1,36 @@
1
+ import { extractDisplayPrefix, generateOpaqueToken, hashOpaqueToken } from '@shipfox/node-tokens';
2
+ import { createProvisionerToken, listActiveProvisionerTokens, listUsableProvisionerTokensByWorkspaceId, revokeProvisionerToken } from '#db/provisioner-tokens.js';
3
+ import { config } from '../config.js';
4
+ import { ProvisionerTokenNotFoundError } from './errors.js';
5
+ export async function createWorkspaceProvisionerToken(params) {
6
+ const rawToken = generateOpaqueToken('provisionerToken');
7
+ const expiresAt = params.ttlSeconds ? new Date(Date.now() + params.ttlSeconds * 1000) : undefined;
8
+ const token = await createProvisionerToken({
9
+ workspaceId: params.workspaceId,
10
+ hashedToken: hashOpaqueToken(rawToken),
11
+ prefix: extractDisplayPrefix(rawToken),
12
+ name: params.name,
13
+ createdByUserId: params.createdByUserId,
14
+ expiresAt
15
+ });
16
+ return {
17
+ token,
18
+ rawToken
19
+ };
20
+ }
21
+ export function listUsableProvisionerTokens(workspaceId) {
22
+ return listUsableProvisionerTokensByWorkspaceId(workspaceId);
23
+ }
24
+ export function listActiveProvisioners(workspaceId) {
25
+ return listActiveProvisionerTokens({
26
+ workspaceId,
27
+ windowSeconds: config.PROVISIONER_ACTIVE_WINDOW_SECONDS
28
+ });
29
+ }
30
+ export async function revokeWorkspaceProvisionerToken(params) {
31
+ const token = await revokeProvisionerToken(params);
32
+ if (!token) throw new ProvisionerTokenNotFoundError(params.tokenId);
33
+ return token;
34
+ }
35
+
36
+ //# sourceMappingURL=provisioner-tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/provisioner-tokens.ts"],"sourcesContent":["import {extractDisplayPrefix, generateOpaqueToken, hashOpaqueToken} from '@shipfox/node-tokens';\nimport {\n createProvisionerToken,\n listActiveProvisionerTokens,\n listUsableProvisionerTokensByWorkspaceId,\n revokeProvisionerToken,\n} from '#db/provisioner-tokens.js';\nimport {config} from '../config.js';\nimport type {ActiveProvisionerToken, ProvisionerToken} from './entities/provisioner-token.js';\nimport {ProvisionerTokenNotFoundError} from './errors.js';\n\nexport interface CreateWorkspaceProvisionerTokenParams {\n workspaceId: string;\n createdByUserId: string;\n name?: string | undefined;\n ttlSeconds?: number | undefined;\n}\n\nexport interface CreateWorkspaceProvisionerTokenResult {\n token: ProvisionerToken;\n rawToken: string;\n}\n\nexport async function createWorkspaceProvisionerToken(\n params: CreateWorkspaceProvisionerTokenParams,\n): Promise<CreateWorkspaceProvisionerTokenResult> {\n const rawToken = generateOpaqueToken('provisionerToken');\n const expiresAt = params.ttlSeconds ? new Date(Date.now() + params.ttlSeconds * 1000) : undefined;\n\n const token = await createProvisionerToken({\n workspaceId: params.workspaceId,\n hashedToken: hashOpaqueToken(rawToken),\n prefix: extractDisplayPrefix(rawToken),\n name: params.name,\n createdByUserId: params.createdByUserId,\n expiresAt,\n });\n\n return {token, rawToken};\n}\n\nexport function listUsableProvisionerTokens(workspaceId: string): Promise<ProvisionerToken[]> {\n return listUsableProvisionerTokensByWorkspaceId(workspaceId);\n}\n\nexport function listActiveProvisioners(workspaceId: string): Promise<ActiveProvisionerToken[]> {\n return listActiveProvisionerTokens({\n workspaceId,\n windowSeconds: config.PROVISIONER_ACTIVE_WINDOW_SECONDS,\n });\n}\n\nexport async function revokeWorkspaceProvisionerToken(params: {\n tokenId: string;\n workspaceId: string;\n revokedByUserId: string;\n}): Promise<ProvisionerToken> {\n const token = await revokeProvisionerToken(params);\n if (!token) throw new ProvisionerTokenNotFoundError(params.tokenId);\n return token;\n}\n"],"names":["extractDisplayPrefix","generateOpaqueToken","hashOpaqueToken","createProvisionerToken","listActiveProvisionerTokens","listUsableProvisionerTokensByWorkspaceId","revokeProvisionerToken","config","ProvisionerTokenNotFoundError","createWorkspaceProvisionerToken","params","rawToken","expiresAt","ttlSeconds","Date","now","undefined","token","workspaceId","hashedToken","prefix","name","createdByUserId","listUsableProvisionerTokens","listActiveProvisioners","windowSeconds","PROVISIONER_ACTIVE_WINDOW_SECONDS","revokeWorkspaceProvisionerToken","tokenId"],"mappings":"AAAA,SAAQA,oBAAoB,EAAEC,mBAAmB,EAAEC,eAAe,QAAO,uBAAuB;AAChG,SACEC,sBAAsB,EACtBC,2BAA2B,EAC3BC,wCAAwC,EACxCC,sBAAsB,QACjB,4BAA4B;AACnC,SAAQC,MAAM,QAAO,eAAe;AAEpC,SAAQC,6BAA6B,QAAO,cAAc;AAc1D,OAAO,eAAeC,gCACpBC,MAA6C;IAE7C,MAAMC,WAAWV,oBAAoB;IACrC,MAAMW,YAAYF,OAAOG,UAAU,GAAG,IAAIC,KAAKA,KAAKC,GAAG,KAAKL,OAAOG,UAAU,GAAG,QAAQG;IAExF,MAAMC,QAAQ,MAAMd,uBAAuB;QACzCe,aAAaR,OAAOQ,WAAW;QAC/BC,aAAajB,gBAAgBS;QAC7BS,QAAQpB,qBAAqBW;QAC7BU,MAAMX,OAAOW,IAAI;QACjBC,iBAAiBZ,OAAOY,eAAe;QACvCV;IACF;IAEA,OAAO;QAACK;QAAON;IAAQ;AACzB;AAEA,OAAO,SAASY,4BAA4BL,WAAmB;IAC7D,OAAOb,yCAAyCa;AAClD;AAEA,OAAO,SAASM,uBAAuBN,WAAmB;IACxD,OAAOd,4BAA4B;QACjCc;QACAO,eAAelB,OAAOmB,iCAAiC;IACzD;AACF;AAEA,OAAO,eAAeC,gCAAgCjB,MAIrD;IACC,MAAMO,QAAQ,MAAMX,uBAAuBI;IAC3C,IAAI,CAACO,OAAO,MAAM,IAAIT,8BAA8BE,OAAOkB,OAAO;IAClE,OAAOX;AACT"}
@@ -0,0 +1,35 @@
1
+ import { RateLimitExceededError, type RateLimitOutcome, type RateLimitPolicy, RateLimitUnavailableError } from '@shipfox/node-rate-limit';
2
+ export type RunnersRateLimitAction = 'provisioner-mint' | 'ephemeral-register';
3
+ export type RunnersRateLimitScope = 'provisioner' | 'ephemeral-token';
4
+ export type RunnersRateLimitOutcome = RateLimitOutcome;
5
+ export type RunnersRateLimitPolicy = RateLimitPolicy;
6
+ export interface CheckRunnersRateLimitParams extends RunnersRateLimitPolicy {
7
+ action: RunnersRateLimitAction;
8
+ scope: RunnersRateLimitScope;
9
+ identifier: string;
10
+ now?: Date | undefined;
11
+ timeoutMs?: number | undefined;
12
+ }
13
+ export declare class RunnersRateLimitExceededError extends RateLimitExceededError<RunnersRateLimitAction, RunnersRateLimitScope> {
14
+ constructor(params: {
15
+ action: RunnersRateLimitAction;
16
+ scope: RunnersRateLimitScope;
17
+ retryAfterSeconds: number;
18
+ identifierHmacPrefix: string;
19
+ });
20
+ }
21
+ export declare class RunnersRateLimitUnavailableError extends RateLimitUnavailableError<RunnersRateLimitAction, RunnersRateLimitScope> {
22
+ constructor(params: {
23
+ action: RunnersRateLimitAction;
24
+ scope: RunnersRateLimitScope;
25
+ identifierHmacPrefix: string;
26
+ cause: unknown;
27
+ });
28
+ }
29
+ export declare function hashRunnersRateLimitIdentifier(params: {
30
+ action: RunnersRateLimitAction;
31
+ scope: RunnersRateLimitScope;
32
+ identifier: string;
33
+ }): string;
34
+ export declare function checkRunnersRateLimit(params: CheckRunnersRateLimitParams): Promise<void>;
35
+ //# 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":"AAEA,OAAO,EAGL,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,yBAAyB,EAC1B,MAAM,0BAA0B,CAAC;AAKlC,MAAM,MAAM,sBAAsB,GAAG,kBAAkB,GAAG,oBAAoB,CAAC;AAC/E,MAAM,MAAM,qBAAqB,GAAG,aAAa,GAAG,iBAAiB,CAAC;AACtE,MAAM,MAAM,uBAAuB,GAAG,gBAAgB,CAAC;AACvD,MAAM,MAAM,sBAAsB,GAAG,eAAe,CAAC;AAErD,MAAM,WAAW,2BAA4B,SAAQ,sBAAsB;IACzE,MAAM,EAAE,sBAAsB,CAAC;IAC/B,KAAK,EAAE,qBAAqB,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,qBAAa,6BAA8B,SAAQ,sBAAsB,CACvE,sBAAsB,EACtB,qBAAqB,CACtB;gBACa,MAAM,EAAE;QAClB,MAAM,EAAE,sBAAsB,CAAC;QAC/B,KAAK,EAAE,qBAAqB,CAAC;QAC7B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,oBAAoB,EAAE,MAAM,CAAC;KAC9B;CAIF;AAED,qBAAa,gCAAiC,SAAQ,yBAAyB,CAC7E,sBAAsB,EACtB,qBAAqB,CACtB;gBACa,MAAM,EAAE;QAClB,MAAM,EAAE,sBAAsB,CAAC;QAC/B,KAAK,EAAE,qBAAqB,CAAC;QAC7B,oBAAoB,EAAE,MAAM,CAAC;QAC7B,KAAK,EAAE,OAAO,CAAC;KAChB;CAIF;AAKD,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,MAAM,EAAE,sBAAsB,CAAC;IAC/B,KAAK,EAAE,qBAAqB,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CAQT;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAoC9F"}
@@ -0,0 +1,74 @@
1
+ import { createHmac } from 'node:crypto';
2
+ import { config as authConfig } from '@shipfox/api-auth/config';
3
+ import { checkRateLimit, hashRateLimitIdentifier, RateLimitExceededError, RateLimitUnavailableError } from '@shipfox/node-rate-limit';
4
+ import { config } from '#config.js';
5
+ import { consumeRunnersRateLimit, pruneExpiredRunnersRateLimits } from '#db/rate-limits.js';
6
+ import { recordRunnersRateLimitCheck, recordRunnersRateLimitPruneFailure } from '#metrics/index.js';
7
+ export class RunnersRateLimitExceededError extends RateLimitExceededError {
8
+ constructor(params){
9
+ super(params);
10
+ this.name = 'RunnersRateLimitExceededError';
11
+ }
12
+ }
13
+ export class RunnersRateLimitUnavailableError extends RateLimitUnavailableError {
14
+ constructor(params){
15
+ super(params);
16
+ this.name = 'RunnersRateLimitUnavailableError';
17
+ }
18
+ }
19
+ const IDENTIFIER_HASH_DOMAIN = 'shipfox.runners.rate-limit.identifier.v1';
20
+ const IDENTIFIER_SECRET_DERIVATION_DOMAIN = 'shipfox.runners.rate-limit.identifier-secret.v1';
21
+ export function hashRunnersRateLimitIdentifier(params) {
22
+ return hashRateLimitIdentifier({
23
+ action: params.action,
24
+ scope: params.scope,
25
+ identifier: params.identifier,
26
+ secret: effectiveIdentifierSecret(),
27
+ domain: IDENTIFIER_HASH_DOMAIN
28
+ });
29
+ }
30
+ export async function checkRunnersRateLimit(params) {
31
+ try {
32
+ await checkRateLimit({
33
+ action: params.action,
34
+ scope: params.scope,
35
+ identifier: params.identifier,
36
+ limit: params.limit,
37
+ windowSeconds: params.windowSeconds,
38
+ identifierSecret: effectiveIdentifierSecret(),
39
+ identifierHashDomain: IDENTIFIER_HASH_DOMAIN,
40
+ consume: consumeRunnersRateLimit,
41
+ prune: pruneExpiredRunnersRateLimits,
42
+ onCheck: recordRunnersRateLimitCheck,
43
+ onPruneFailure: recordRunnersRateLimitPruneFailure,
44
+ now: params.now,
45
+ timeoutMs: params.timeoutMs ?? config.RUNNERS_RATE_LIMIT_TIMEOUT_MS
46
+ });
47
+ } catch (error) {
48
+ if (error instanceof RateLimitExceededError) {
49
+ throw new RunnersRateLimitExceededError({
50
+ action: error.action,
51
+ scope: error.scope,
52
+ retryAfterSeconds: error.retryAfterSeconds,
53
+ identifierHmacPrefix: error.identifierHmacPrefix
54
+ });
55
+ }
56
+ if (error instanceof RateLimitUnavailableError) {
57
+ throw new RunnersRateLimitUnavailableError({
58
+ action: error.action,
59
+ scope: error.scope,
60
+ identifierHmacPrefix: error.identifierHmacPrefix,
61
+ cause: error.cause
62
+ });
63
+ }
64
+ throw error;
65
+ }
66
+ }
67
+ function effectiveIdentifierSecret() {
68
+ if (config.RATE_LIMIT_IDENTIFIER_SECRET) {
69
+ return config.RATE_LIMIT_IDENTIFIER_SECRET;
70
+ }
71
+ return createHmac('sha256', authConfig.AUTH_JWT_SECRET).update(IDENTIFIER_SECRET_DERIVATION_DOMAIN).digest();
72
+ }
73
+
74
+ //# sourceMappingURL=rate-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/rate-limit.ts"],"sourcesContent":["import {createHmac} from 'node:crypto';\nimport {config as authConfig} from '@shipfox/api-auth/config';\nimport {\n checkRateLimit,\n hashRateLimitIdentifier,\n RateLimitExceededError,\n type RateLimitOutcome,\n type RateLimitPolicy,\n RateLimitUnavailableError,\n} from '@shipfox/node-rate-limit';\nimport {config} from '#config.js';\nimport {consumeRunnersRateLimit, pruneExpiredRunnersRateLimits} from '#db/rate-limits.js';\nimport {recordRunnersRateLimitCheck, recordRunnersRateLimitPruneFailure} from '#metrics/index.js';\n\nexport type RunnersRateLimitAction = 'provisioner-mint' | 'ephemeral-register';\nexport type RunnersRateLimitScope = 'provisioner' | 'ephemeral-token';\nexport type RunnersRateLimitOutcome = RateLimitOutcome;\nexport type RunnersRateLimitPolicy = RateLimitPolicy;\n\nexport interface CheckRunnersRateLimitParams extends RunnersRateLimitPolicy {\n action: RunnersRateLimitAction;\n scope: RunnersRateLimitScope;\n identifier: string;\n now?: Date | undefined;\n timeoutMs?: number | undefined;\n}\n\nexport class RunnersRateLimitExceededError extends RateLimitExceededError<\n RunnersRateLimitAction,\n RunnersRateLimitScope\n> {\n constructor(params: {\n action: RunnersRateLimitAction;\n scope: RunnersRateLimitScope;\n retryAfterSeconds: number;\n identifierHmacPrefix: string;\n }) {\n super(params);\n this.name = 'RunnersRateLimitExceededError';\n }\n}\n\nexport class RunnersRateLimitUnavailableError extends RateLimitUnavailableError<\n RunnersRateLimitAction,\n RunnersRateLimitScope\n> {\n constructor(params: {\n action: RunnersRateLimitAction;\n scope: RunnersRateLimitScope;\n identifierHmacPrefix: string;\n cause: unknown;\n }) {\n super(params);\n this.name = 'RunnersRateLimitUnavailableError';\n }\n}\n\nconst IDENTIFIER_HASH_DOMAIN = 'shipfox.runners.rate-limit.identifier.v1';\nconst IDENTIFIER_SECRET_DERIVATION_DOMAIN = 'shipfox.runners.rate-limit.identifier-secret.v1';\n\nexport function hashRunnersRateLimitIdentifier(params: {\n action: RunnersRateLimitAction;\n scope: RunnersRateLimitScope;\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 checkRunnersRateLimit(params: CheckRunnersRateLimitParams): 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: consumeRunnersRateLimit,\n prune: pruneExpiredRunnersRateLimits,\n onCheck: recordRunnersRateLimitCheck,\n onPruneFailure: recordRunnersRateLimitPruneFailure,\n now: params.now,\n timeoutMs: params.timeoutMs ?? config.RUNNERS_RATE_LIMIT_TIMEOUT_MS,\n });\n } catch (error) {\n if (error instanceof RateLimitExceededError) {\n throw new RunnersRateLimitExceededError({\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 RunnersRateLimitUnavailableError({\n action: error.action,\n scope: error.scope,\n identifierHmacPrefix: error.identifierHmacPrefix,\n cause: error.cause,\n });\n }\n throw error;\n }\n}\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', authConfig.AUTH_JWT_SECRET)\n .update(IDENTIFIER_SECRET_DERIVATION_DOMAIN)\n .digest();\n}\n"],"names":["createHmac","config","authConfig","checkRateLimit","hashRateLimitIdentifier","RateLimitExceededError","RateLimitUnavailableError","consumeRunnersRateLimit","pruneExpiredRunnersRateLimits","recordRunnersRateLimitCheck","recordRunnersRateLimitPruneFailure","RunnersRateLimitExceededError","params","name","RunnersRateLimitUnavailableError","IDENTIFIER_HASH_DOMAIN","IDENTIFIER_SECRET_DERIVATION_DOMAIN","hashRunnersRateLimitIdentifier","action","scope","identifier","secret","effectiveIdentifierSecret","domain","checkRunnersRateLimit","limit","windowSeconds","identifierSecret","identifierHashDomain","consume","prune","onCheck","onPruneFailure","now","timeoutMs","RUNNERS_RATE_LIMIT_TIMEOUT_MS","error","retryAfterSeconds","identifierHmacPrefix","cause","RATE_LIMIT_IDENTIFIER_SECRET","AUTH_JWT_SECRET","update","digest"],"mappings":"AAAA,SAAQA,UAAU,QAAO,cAAc;AACvC,SAAQC,UAAUC,UAAU,QAAO,2BAA2B;AAC9D,SACEC,cAAc,EACdC,uBAAuB,EACvBC,sBAAsB,EAGtBC,yBAAyB,QACpB,2BAA2B;AAClC,SAAQL,MAAM,QAAO,aAAa;AAClC,SAAQM,uBAAuB,EAAEC,6BAA6B,QAAO,qBAAqB;AAC1F,SAAQC,2BAA2B,EAAEC,kCAAkC,QAAO,oBAAoB;AAelG,OAAO,MAAMC,sCAAsCN;IAIjD,YAAYO,MAKX,CAAE;QACD,KAAK,CAACA;QACN,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMC,yCAAyCR;IAIpD,YAAYM,MAKX,CAAE;QACD,KAAK,CAACA;QACN,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,MAAME,yBAAyB;AAC/B,MAAMC,sCAAsC;AAE5C,OAAO,SAASC,+BAA+BL,MAI9C;IACC,OAAOR,wBAAwB;QAC7Bc,QAAQN,OAAOM,MAAM;QACrBC,OAAOP,OAAOO,KAAK;QACnBC,YAAYR,OAAOQ,UAAU;QAC7BC,QAAQC;QACRC,QAAQR;IACV;AACF;AAEA,OAAO,eAAeS,sBAAsBZ,MAAmC;IAC7E,IAAI;QACF,MAAMT,eAAe;YACnBe,QAAQN,OAAOM,MAAM;YACrBC,OAAOP,OAAOO,KAAK;YACnBC,YAAYR,OAAOQ,UAAU;YAC7BK,OAAOb,OAAOa,KAAK;YACnBC,eAAed,OAAOc,aAAa;YACnCC,kBAAkBL;YAClBM,sBAAsBb;YACtBc,SAAStB;YACTuB,OAAOtB;YACPuB,SAAStB;YACTuB,gBAAgBtB;YAChBuB,KAAKrB,OAAOqB,GAAG;YACfC,WAAWtB,OAAOsB,SAAS,IAAIjC,OAAOkC,6BAA6B;QACrE;IACF,EAAE,OAAOC,OAAO;QACd,IAAIA,iBAAiB/B,wBAAwB;YAC3C,MAAM,IAAIM,8BAA8B;gBACtCO,QAAQkB,MAAMlB,MAAM;gBACpBC,OAAOiB,MAAMjB,KAAK;gBAClBkB,mBAAmBD,MAAMC,iBAAiB;gBAC1CC,sBAAsBF,MAAME,oBAAoB;YAClD;QACF;QACA,IAAIF,iBAAiB9B,2BAA2B;YAC9C,MAAM,IAAIQ,iCAAiC;gBACzCI,QAAQkB,MAAMlB,MAAM;gBACpBC,OAAOiB,MAAMjB,KAAK;gBAClBmB,sBAAsBF,MAAME,oBAAoB;gBAChDC,OAAOH,MAAMG,KAAK;YACpB;QACF;QACA,MAAMH;IACR;AACF;AAEA,SAASd;IACP,IAAIrB,OAAOuC,4BAA4B,EAAE;QACvC,OAAOvC,OAAOuC,4BAA4B;IAC5C;IAEA,OAAOxC,WAAW,UAAUE,WAAWuC,eAAe,EACnDC,MAAM,CAAC1B,qCACP2B,MAAM;AACX"}
@@ -0,0 +1,26 @@
1
+ import type { RunnerToolCapabilitiesDto } from '@shipfox/api-runners-dto';
2
+ import type { RunnerSession } from './entities/runner-session.js';
3
+ export interface RegisterRunnerSessionResult {
4
+ session: RunnerSession;
5
+ sessionToken: string;
6
+ mode: 'manual' | 'ephemeral';
7
+ maxClaims: number | null;
8
+ }
9
+ export type RunnerRegistrationCredential = {
10
+ kind: 'manual';
11
+ registrationTokenId: string;
12
+ workspaceId: string;
13
+ } | {
14
+ kind: 'ephemeral';
15
+ ephemeralTokenId: string;
16
+ workspaceId: string;
17
+ provisionerId: string;
18
+ reservationId: string | null;
19
+ provisionedRunnerId: string;
20
+ };
21
+ export declare function registerRunnerSession(params: {
22
+ credential: RunnerRegistrationCredential;
23
+ labels: string[];
24
+ toolCapabilities?: RunnerToolCapabilitiesDto | null;
25
+ }): Promise<RegisterRunnerSessionResult>;
26
+ //# sourceMappingURL=runner-sessions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner-sessions.d.ts","sourceRoot":"","sources":["../../src/core/runner-sessions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,0BAA0B,CAAC;AAIxE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,8BAA8B,CAAC;AAGhE,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,aAAa,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,QAAQ,GAAG,WAAW,CAAC;IAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,MAAM,4BAA4B,GACpC;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;CACrB,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEN,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,UAAU,EAAE,4BAA4B,CAAC;IACzC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,gBAAgB,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;CACrD,GAAG,OAAO,CAAC,2BAA2B,CAAC,CA+BvC"}
@@ -0,0 +1,41 @@
1
+ import { issueRunnerSessionToken } from '@shipfox/api-auth';
2
+ import { canonicalizeLabels } from '@shipfox/runner-labels';
3
+ import { createRunnerSessionConsumingEphemeralToken } from '#db/ephemeral-registration-tokens.js';
4
+ import { createRunnerSession } from '#db/runner-sessions.js';
5
+ import { EmptyRunnerLabelsError } from './errors.js';
6
+ export async function registerRunnerSession(params) {
7
+ const labels = [
8
+ ...canonicalizeLabels(params.labels)
9
+ ];
10
+ if (labels.length === 0) throw new EmptyRunnerLabelsError();
11
+ const mode = params.credential.kind;
12
+ const maxClaims = params.credential.kind === 'ephemeral' ? 1 : null;
13
+ const session = params.credential.kind === 'manual' ? await createRunnerSession({
14
+ workspaceId: params.credential.workspaceId,
15
+ scope: 'workspace',
16
+ registrationTokenId: params.credential.registrationTokenId,
17
+ labels,
18
+ toolCapabilities: params.toolCapabilities ?? null
19
+ }) : await createRunnerSessionConsumingEphemeralToken({
20
+ ephemeralTokenId: params.credential.ephemeralTokenId,
21
+ workspaceId: params.credential.workspaceId,
22
+ labels,
23
+ toolCapabilities: params.toolCapabilities ?? null,
24
+ maxClaims: 1
25
+ });
26
+ const sessionToken = await issueRunnerSessionToken({
27
+ runnerSessionId: session.id,
28
+ workspaceId: session.workspaceId,
29
+ scope: session.scope,
30
+ labels: session.labels,
31
+ maxClaims
32
+ });
33
+ return {
34
+ session,
35
+ sessionToken,
36
+ mode,
37
+ maxClaims
38
+ };
39
+ }
40
+
41
+ //# sourceMappingURL=runner-sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/runner-sessions.ts"],"sourcesContent":["import {issueRunnerSessionToken} from '@shipfox/api-auth';\nimport type {RunnerToolCapabilitiesDto} from '@shipfox/api-runners-dto';\nimport {canonicalizeLabels} from '@shipfox/runner-labels';\nimport {createRunnerSessionConsumingEphemeralToken} from '#db/ephemeral-registration-tokens.js';\nimport {createRunnerSession} from '#db/runner-sessions.js';\nimport type {RunnerSession} from './entities/runner-session.js';\nimport {EmptyRunnerLabelsError} from './errors.js';\n\nexport interface RegisterRunnerSessionResult {\n session: RunnerSession;\n sessionToken: string;\n mode: 'manual' | 'ephemeral';\n maxClaims: number | null;\n}\n\nexport type RunnerRegistrationCredential =\n | {\n kind: 'manual';\n registrationTokenId: string;\n workspaceId: string;\n }\n | {\n kind: 'ephemeral';\n ephemeralTokenId: string;\n workspaceId: string;\n provisionerId: string;\n reservationId: string | null;\n provisionedRunnerId: string;\n };\n\nexport async function registerRunnerSession(params: {\n credential: RunnerRegistrationCredential;\n labels: string[];\n toolCapabilities?: RunnerToolCapabilitiesDto | null;\n}): Promise<RegisterRunnerSessionResult> {\n const labels = [...canonicalizeLabels(params.labels)];\n if (labels.length === 0) throw new EmptyRunnerLabelsError();\n\n const mode = params.credential.kind;\n const maxClaims = params.credential.kind === 'ephemeral' ? 1 : null;\n const session =\n params.credential.kind === 'manual'\n ? await createRunnerSession({\n workspaceId: params.credential.workspaceId,\n scope: 'workspace',\n registrationTokenId: params.credential.registrationTokenId,\n labels,\n toolCapabilities: params.toolCapabilities ?? null,\n })\n : await createRunnerSessionConsumingEphemeralToken({\n ephemeralTokenId: params.credential.ephemeralTokenId,\n workspaceId: params.credential.workspaceId,\n labels,\n toolCapabilities: params.toolCapabilities ?? null,\n maxClaims: 1,\n });\n const sessionToken = await issueRunnerSessionToken({\n runnerSessionId: session.id,\n workspaceId: session.workspaceId,\n scope: session.scope,\n labels: session.labels,\n maxClaims,\n });\n\n return {session, sessionToken, mode, maxClaims};\n}\n"],"names":["issueRunnerSessionToken","canonicalizeLabels","createRunnerSessionConsumingEphemeralToken","createRunnerSession","EmptyRunnerLabelsError","registerRunnerSession","params","labels","length","mode","credential","kind","maxClaims","session","workspaceId","scope","registrationTokenId","toolCapabilities","ephemeralTokenId","sessionToken","runnerSessionId","id"],"mappings":"AAAA,SAAQA,uBAAuB,QAAO,oBAAoB;AAE1D,SAAQC,kBAAkB,QAAO,yBAAyB;AAC1D,SAAQC,0CAA0C,QAAO,uCAAuC;AAChG,SAAQC,mBAAmB,QAAO,yBAAyB;AAE3D,SAAQC,sBAAsB,QAAO,cAAc;AAwBnD,OAAO,eAAeC,sBAAsBC,MAI3C;IACC,MAAMC,SAAS;WAAIN,mBAAmBK,OAAOC,MAAM;KAAE;IACrD,IAAIA,OAAOC,MAAM,KAAK,GAAG,MAAM,IAAIJ;IAEnC,MAAMK,OAAOH,OAAOI,UAAU,CAACC,IAAI;IACnC,MAAMC,YAAYN,OAAOI,UAAU,CAACC,IAAI,KAAK,cAAc,IAAI;IAC/D,MAAME,UACJP,OAAOI,UAAU,CAACC,IAAI,KAAK,WACvB,MAAMR,oBAAoB;QACxBW,aAAaR,OAAOI,UAAU,CAACI,WAAW;QAC1CC,OAAO;QACPC,qBAAqBV,OAAOI,UAAU,CAACM,mBAAmB;QAC1DT;QACAU,kBAAkBX,OAAOW,gBAAgB,IAAI;IAC/C,KACA,MAAMf,2CAA2C;QAC/CgB,kBAAkBZ,OAAOI,UAAU,CAACQ,gBAAgB;QACpDJ,aAAaR,OAAOI,UAAU,CAACI,WAAW;QAC1CP;QACAU,kBAAkBX,OAAOW,gBAAgB,IAAI;QAC7CL,WAAW;IACb;IACN,MAAMO,eAAe,MAAMnB,wBAAwB;QACjDoB,iBAAiBP,QAAQQ,EAAE;QAC3BP,aAAaD,QAAQC,WAAW;QAChCC,OAAOF,QAAQE,KAAK;QACpBR,QAAQM,QAAQN,MAAM;QACtBK;IACF;IAEA,OAAO;QAACC;QAASM;QAAcV;QAAMG;IAAS;AAChD"}
@@ -0,0 +1,24 @@
1
+ import type { RunnerToolCapabilitiesDto } from '@shipfox/api-runners-dto';
2
+ type RunnerToolHarness = keyof RunnerToolCapabilitiesDto['harnesses'];
3
+ export declare const EMPTY_RUNNER_TOOL_CAPABILITIES: RunnerToolCapabilitiesDto;
4
+ export declare function effectiveRunnerToolCapabilities(params: {
5
+ toolCapabilities: RunnerToolCapabilitiesDto | null;
6
+ reportedAt: Date | null;
7
+ staleAfterSeconds: number;
8
+ now?: Date;
9
+ }): RunnerToolCapabilitiesDto;
10
+ export declare function unadvertisedRunnerTools(params: {
11
+ harness: RunnerToolHarness;
12
+ requestedTools: readonly string[];
13
+ capabilities: RunnerToolCapabilitiesDto;
14
+ }): string[];
15
+ export interface EffectiveRunnerToolCapabilitiesResult {
16
+ capabilities: RunnerToolCapabilitiesDto;
17
+ reportFresh: boolean;
18
+ harnessKnown(harness: RunnerToolHarness): boolean;
19
+ }
20
+ export declare function getEffectiveRunnerToolCapabilities(params: {
21
+ runnerSessionId: string;
22
+ }): Promise<EffectiveRunnerToolCapabilitiesResult>;
23
+ export {};
24
+ //# sourceMappingURL=runner-tool-capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner-tool-capabilities.d.ts","sourceRoot":"","sources":["../../src/core/runner-tool-capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,0BAA0B,CAAC;AAIxE,KAAK,iBAAiB,GAAG,MAAM,yBAAyB,CAAC,WAAW,CAAC,CAAC;AAEtE,eAAO,MAAM,8BAA8B,EAAE,yBAE5C,CAAC;AAEF,wBAAgB,+BAA+B,CAAC,MAAM,EAAE;IACtD,gBAAgB,EAAE,yBAAyB,GAAG,IAAI,CAAC;IACnD,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ,GAAG,yBAAyB,CAQ5B;AAeD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,OAAO,EAAE,iBAAiB,CAAC;IAC3B,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,YAAY,EAAE,yBAAyB,CAAC;CACzC,GAAG,MAAM,EAAE,CAGX;AAED,MAAM,WAAW,qCAAqC;IACpD,YAAY,EAAE,yBAAyB,CAAC;IACxC,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC;CACnD;AAED,wBAAsB,kCAAkC,CAAC,MAAM,EAAE;IAC/D,eAAe,EAAE,MAAM,CAAC;CACzB,GAAG,OAAO,CAAC,qCAAqC,CAAC,CAmBjD"}
@@ -0,0 +1,43 @@
1
+ import { config } from '#config.js';
2
+ import { getRunnerSessionById } from '#db/runner-sessions.js';
3
+ export const EMPTY_RUNNER_TOOL_CAPABILITIES = {
4
+ harnesses: {}
5
+ };
6
+ export function effectiveRunnerToolCapabilities(params) {
7
+ if (!params.toolCapabilities || !params.reportedAt) return EMPTY_RUNNER_TOOL_CAPABILITIES;
8
+ const now = params.now ?? new Date();
9
+ const ageMs = now.getTime() - params.reportedAt.getTime();
10
+ if (ageMs > params.staleAfterSeconds * 1000) return EMPTY_RUNNER_TOOL_CAPABILITIES;
11
+ return params.toolCapabilities;
12
+ }
13
+ function runnerToolCapabilityReportIsFresh(params) {
14
+ if (!params.toolCapabilities || !params.reportedAt) return false;
15
+ const now = params.now ?? new Date();
16
+ const ageMs = now.getTime() - params.reportedAt.getTime();
17
+ return ageMs <= params.staleAfterSeconds * 1000;
18
+ }
19
+ export function unadvertisedRunnerTools(params) {
20
+ const advertised = new Set(params.capabilities.harnesses[params.harness]?.tools ?? []);
21
+ return params.requestedTools.filter((tool)=>!advertised.has(tool));
22
+ }
23
+ export async function getEffectiveRunnerToolCapabilities(params) {
24
+ const runnerSession = await getRunnerSessionById(params.runnerSessionId);
25
+ const staleAfterSeconds = config.RUNNER_TOOL_CAPABILITIES_STALE_AFTER_SECONDS;
26
+ const capabilities = effectiveRunnerToolCapabilities({
27
+ toolCapabilities: runnerSession?.toolCapabilities ?? null,
28
+ reportedAt: runnerSession?.toolCapabilitiesReportedAt ?? null,
29
+ staleAfterSeconds
30
+ });
31
+ const reportFresh = runnerToolCapabilityReportIsFresh({
32
+ toolCapabilities: runnerSession?.toolCapabilities,
33
+ reportedAt: runnerSession?.toolCapabilitiesReportedAt,
34
+ staleAfterSeconds
35
+ });
36
+ return {
37
+ capabilities,
38
+ reportFresh,
39
+ harnessKnown: (harness)=>capabilities.harnesses[harness] !== undefined
40
+ };
41
+ }
42
+
43
+ //# sourceMappingURL=runner-tool-capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/runner-tool-capabilities.ts"],"sourcesContent":["import type {RunnerToolCapabilitiesDto} from '@shipfox/api-runners-dto';\nimport {config} from '#config.js';\nimport {getRunnerSessionById} from '#db/runner-sessions.js';\n\ntype RunnerToolHarness = keyof RunnerToolCapabilitiesDto['harnesses'];\n\nexport const EMPTY_RUNNER_TOOL_CAPABILITIES: RunnerToolCapabilitiesDto = {\n harnesses: {},\n};\n\nexport function effectiveRunnerToolCapabilities(params: {\n toolCapabilities: RunnerToolCapabilitiesDto | null;\n reportedAt: Date | null;\n staleAfterSeconds: number;\n now?: Date;\n}): RunnerToolCapabilitiesDto {\n if (!params.toolCapabilities || !params.reportedAt) return EMPTY_RUNNER_TOOL_CAPABILITIES;\n\n const now = params.now ?? new Date();\n const ageMs = now.getTime() - params.reportedAt.getTime();\n if (ageMs > params.staleAfterSeconds * 1000) return EMPTY_RUNNER_TOOL_CAPABILITIES;\n\n return params.toolCapabilities;\n}\n\nfunction runnerToolCapabilityReportIsFresh(params: {\n toolCapabilities: RunnerToolCapabilitiesDto | null | undefined;\n reportedAt: Date | null | undefined;\n staleAfterSeconds: number;\n now?: Date;\n}): boolean {\n if (!params.toolCapabilities || !params.reportedAt) return false;\n\n const now = params.now ?? new Date();\n const ageMs = now.getTime() - params.reportedAt.getTime();\n return ageMs <= params.staleAfterSeconds * 1000;\n}\n\nexport function unadvertisedRunnerTools(params: {\n harness: RunnerToolHarness;\n requestedTools: readonly string[];\n capabilities: RunnerToolCapabilitiesDto;\n}): string[] {\n const advertised = new Set(params.capabilities.harnesses[params.harness]?.tools ?? []);\n return params.requestedTools.filter((tool) => !advertised.has(tool));\n}\n\nexport interface EffectiveRunnerToolCapabilitiesResult {\n capabilities: RunnerToolCapabilitiesDto;\n reportFresh: boolean;\n harnessKnown(harness: RunnerToolHarness): boolean;\n}\n\nexport async function getEffectiveRunnerToolCapabilities(params: {\n runnerSessionId: string;\n}): Promise<EffectiveRunnerToolCapabilitiesResult> {\n const runnerSession = await getRunnerSessionById(params.runnerSessionId);\n const staleAfterSeconds = config.RUNNER_TOOL_CAPABILITIES_STALE_AFTER_SECONDS;\n const capabilities = effectiveRunnerToolCapabilities({\n toolCapabilities: runnerSession?.toolCapabilities ?? null,\n reportedAt: runnerSession?.toolCapabilitiesReportedAt ?? null,\n staleAfterSeconds,\n });\n const reportFresh = runnerToolCapabilityReportIsFresh({\n toolCapabilities: runnerSession?.toolCapabilities,\n reportedAt: runnerSession?.toolCapabilitiesReportedAt,\n staleAfterSeconds,\n });\n\n return {\n capabilities,\n reportFresh,\n harnessKnown: (harness) => capabilities.harnesses[harness] !== undefined,\n };\n}\n"],"names":["config","getRunnerSessionById","EMPTY_RUNNER_TOOL_CAPABILITIES","harnesses","effectiveRunnerToolCapabilities","params","toolCapabilities","reportedAt","now","Date","ageMs","getTime","staleAfterSeconds","runnerToolCapabilityReportIsFresh","unadvertisedRunnerTools","advertised","Set","capabilities","harness","tools","requestedTools","filter","tool","has","getEffectiveRunnerToolCapabilities","runnerSession","runnerSessionId","RUNNER_TOOL_CAPABILITIES_STALE_AFTER_SECONDS","toolCapabilitiesReportedAt","reportFresh","harnessKnown","undefined"],"mappings":"AACA,SAAQA,MAAM,QAAO,aAAa;AAClC,SAAQC,oBAAoB,QAAO,yBAAyB;AAI5D,OAAO,MAAMC,iCAA4D;IACvEC,WAAW,CAAC;AACd,EAAE;AAEF,OAAO,SAASC,gCAAgCC,MAK/C;IACC,IAAI,CAACA,OAAOC,gBAAgB,IAAI,CAACD,OAAOE,UAAU,EAAE,OAAOL;IAE3D,MAAMM,MAAMH,OAAOG,GAAG,IAAI,IAAIC;IAC9B,MAAMC,QAAQF,IAAIG,OAAO,KAAKN,OAAOE,UAAU,CAACI,OAAO;IACvD,IAAID,QAAQL,OAAOO,iBAAiB,GAAG,MAAM,OAAOV;IAEpD,OAAOG,OAAOC,gBAAgB;AAChC;AAEA,SAASO,kCAAkCR,MAK1C;IACC,IAAI,CAACA,OAAOC,gBAAgB,IAAI,CAACD,OAAOE,UAAU,EAAE,OAAO;IAE3D,MAAMC,MAAMH,OAAOG,GAAG,IAAI,IAAIC;IAC9B,MAAMC,QAAQF,IAAIG,OAAO,KAAKN,OAAOE,UAAU,CAACI,OAAO;IACvD,OAAOD,SAASL,OAAOO,iBAAiB,GAAG;AAC7C;AAEA,OAAO,SAASE,wBAAwBT,MAIvC;IACC,MAAMU,aAAa,IAAIC,IAAIX,OAAOY,YAAY,CAACd,SAAS,CAACE,OAAOa,OAAO,CAAC,EAAEC,SAAS,EAAE;IACrF,OAAOd,OAAOe,cAAc,CAACC,MAAM,CAAC,CAACC,OAAS,CAACP,WAAWQ,GAAG,CAACD;AAChE;AAQA,OAAO,eAAeE,mCAAmCnB,MAExD;IACC,MAAMoB,gBAAgB,MAAMxB,qBAAqBI,OAAOqB,eAAe;IACvE,MAAMd,oBAAoBZ,OAAO2B,4CAA4C;IAC7E,MAAMV,eAAeb,gCAAgC;QACnDE,kBAAkBmB,eAAenB,oBAAoB;QACrDC,YAAYkB,eAAeG,8BAA8B;QACzDhB;IACF;IACA,MAAMiB,cAAchB,kCAAkC;QACpDP,kBAAkBmB,eAAenB;QACjCC,YAAYkB,eAAeG;QAC3BhB;IACF;IAEA,OAAO;QACLK;QACAY;QACAC,cAAc,CAACZ,UAAYD,aAAad,SAAS,CAACe,QAAQ,KAAKa;IACjE;AACF"}