@shipfox/api-runners 4.0.0 → 6.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 (414) hide show
  1. package/.turbo/turbo-build.log +6 -6
  2. package/CHANGELOG.md +83 -0
  3. package/dist/config.d.ts +5 -1
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +53 -6
  6. package/dist/config.js.map +1 -1
  7. package/dist/core/capacity-assignments.d.ts +7 -0
  8. package/dist/core/capacity-assignments.d.ts.map +1 -0
  9. package/dist/core/capacity-assignments.js +6 -0
  10. package/dist/core/capacity-assignments.js.map +1 -0
  11. package/dist/core/demand.d.ts +6 -6
  12. package/dist/core/demand.d.ts.map +1 -1
  13. package/dist/core/demand.js +10 -10
  14. package/dist/core/demand.js.map +1 -1
  15. package/dist/core/entities/capacity-assignment.d.ts +9 -0
  16. package/dist/core/entities/capacity-assignment.d.ts.map +1 -0
  17. package/dist/core/entities/capacity-assignment.js +3 -0
  18. package/dist/core/entities/capacity-assignment.js.map +1 -0
  19. package/dist/core/entities/ephemeral-registration-token.d.ts +1 -1
  20. package/dist/core/entities/ephemeral-registration-token.d.ts.map +1 -1
  21. package/dist/core/entities/ephemeral-registration-token.js.map +1 -1
  22. package/dist/core/entities/provisioner-capability-snapshot.d.ts +13 -0
  23. package/dist/core/entities/provisioner-capability-snapshot.d.ts.map +1 -0
  24. package/dist/core/entities/provisioner-capability-snapshot.js +3 -0
  25. package/dist/core/entities/provisioner-capability-snapshot.js.map +1 -0
  26. package/dist/core/entities/provisioner-token.d.ts +10 -2
  27. package/dist/core/entities/provisioner-token.d.ts.map +1 -1
  28. package/dist/core/entities/provisioner-token.js.map +1 -1
  29. package/dist/core/entities/{provisioned-runner.d.ts → runner-instance.d.ts} +6 -6
  30. package/dist/core/entities/runner-instance.d.ts.map +1 -0
  31. package/dist/core/entities/runner-instance.js +3 -0
  32. package/dist/core/entities/runner-instance.js.map +1 -0
  33. package/dist/core/entities/runner-session.d.ts +4 -2
  34. package/dist/core/entities/runner-session.d.ts.map +1 -1
  35. package/dist/core/entities/runner-session.js.map +1 -1
  36. package/dist/core/ephemeral-registration-tokens.d.ts +5 -5
  37. package/dist/core/ephemeral-registration-tokens.d.ts.map +1 -1
  38. package/dist/core/ephemeral-registration-tokens.js +12 -12
  39. package/dist/core/ephemeral-registration-tokens.js.map +1 -1
  40. package/dist/core/errors.d.ts +16 -4
  41. package/dist/core/errors.d.ts.map +1 -1
  42. package/dist/core/errors.js +22 -4
  43. package/dist/core/errors.js.map +1 -1
  44. package/dist/core/index.d.ts +10 -4
  45. package/dist/core/index.d.ts.map +1 -1
  46. package/dist/core/index.js +6 -2
  47. package/dist/core/index.js.map +1 -1
  48. package/dist/core/job-executions.d.ts +2 -0
  49. package/dist/core/job-executions.d.ts.map +1 -1
  50. package/dist/core/job-executions.js +1 -2
  51. package/dist/core/job-executions.js.map +1 -1
  52. package/dist/core/maintenance.d.ts +1 -1
  53. package/dist/core/maintenance.d.ts.map +1 -1
  54. package/dist/core/maintenance.js +5 -5
  55. package/dist/core/maintenance.js.map +1 -1
  56. package/dist/core/provisioner-capability-snapshots.d.ts +5 -0
  57. package/dist/core/provisioner-capability-snapshots.d.ts.map +1 -0
  58. package/dist/core/provisioner-capability-snapshots.js +10 -0
  59. package/dist/core/provisioner-capability-snapshots.js.map +1 -0
  60. package/dist/core/provisioner-tokens.d.ts +10 -0
  61. package/dist/core/provisioner-tokens.d.ts.map +1 -1
  62. package/dist/core/provisioner-tokens.js +23 -1
  63. package/dist/core/provisioner-tokens.js.map +1 -1
  64. package/dist/core/rate-limit.d.ts.map +1 -1
  65. package/dist/core/rate-limit.js +2 -7
  66. package/dist/core/rate-limit.js.map +1 -1
  67. package/dist/core/runner-activation.d.ts +13 -0
  68. package/dist/core/runner-activation.d.ts.map +1 -0
  69. package/dist/core/runner-activation.js +36 -0
  70. package/dist/core/runner-activation.js.map +1 -0
  71. package/dist/core/runner-control-sessions.d.ts +46 -0
  72. package/dist/core/runner-control-sessions.d.ts.map +1 -0
  73. package/dist/core/runner-control-sessions.js +121 -0
  74. package/dist/core/runner-control-sessions.js.map +1 -0
  75. package/dist/core/runner-instances.d.ts +79 -0
  76. package/dist/core/runner-instances.d.ts.map +1 -0
  77. package/dist/core/runner-instances.js +168 -0
  78. package/dist/core/runner-instances.js.map +1 -0
  79. package/dist/core/runner-sessions.d.ts +8 -2
  80. package/dist/core/runner-sessions.d.ts.map +1 -1
  81. package/dist/core/runner-sessions.js +8 -5
  82. package/dist/core/runner-sessions.js.map +1 -1
  83. package/dist/db/capacity-assignments.d.ts +7 -0
  84. package/dist/db/capacity-assignments.d.ts.map +1 -0
  85. package/dist/db/capacity-assignments.js +72 -0
  86. package/dist/db/capacity-assignments.js.map +1 -0
  87. package/dist/db/db.d.ts +2837 -1009
  88. package/dist/db/db.d.ts.map +1 -1
  89. package/dist/db/db.js +11 -2
  90. package/dist/db/db.js.map +1 -1
  91. package/dist/db/ephemeral-registration-tokens.d.ts +2 -2
  92. package/dist/db/ephemeral-registration-tokens.d.ts.map +1 -1
  93. package/dist/db/ephemeral-registration-tokens.js +21 -21
  94. package/dist/db/ephemeral-registration-tokens.js.map +1 -1
  95. package/dist/db/index.d.ts +7 -4
  96. package/dist/db/index.d.ts.map +1 -1
  97. package/dist/db/index.js +5 -2
  98. package/dist/db/index.js.map +1 -1
  99. package/dist/db/job-executions.d.ts +6 -6
  100. package/dist/db/job-executions.d.ts.map +1 -1
  101. package/dist/db/job-executions.js +20 -19
  102. package/dist/db/job-executions.js.map +1 -1
  103. package/dist/db/provisioner-capability-snapshots.d.ts +21 -0
  104. package/dist/db/provisioner-capability-snapshots.d.ts.map +1 -0
  105. package/dist/db/provisioner-capability-snapshots.js +57 -0
  106. package/dist/db/provisioner-capability-snapshots.js.map +1 -0
  107. package/dist/db/provisioner-tokens.d.ts +7 -2
  108. package/dist/db/provisioner-tokens.d.ts.map +1 -1
  109. package/dist/db/provisioner-tokens.js +59 -10
  110. package/dist/db/provisioner-tokens.js.map +1 -1
  111. package/dist/db/reservations.d.ts +18 -0
  112. package/dist/db/reservations.d.ts.map +1 -1
  113. package/dist/db/reservations.js +88 -1
  114. package/dist/db/reservations.js.map +1 -1
  115. package/dist/db/runner-instances.d.ts +91 -0
  116. package/dist/db/runner-instances.d.ts.map +1 -0
  117. package/dist/db/runner-instances.js +511 -0
  118. package/dist/db/runner-instances.js.map +1 -0
  119. package/dist/db/runner-sessions.d.ts +5 -0
  120. package/dist/db/runner-sessions.d.ts.map +1 -1
  121. package/dist/db/runner-sessions.js +48 -2
  122. package/dist/db/runner-sessions.js.map +1 -1
  123. package/dist/db/schema/capacity-assignments.d.ts +113 -0
  124. package/dist/db/schema/capacity-assignments.d.ts.map +1 -0
  125. package/dist/db/schema/capacity-assignments.js +29 -0
  126. package/dist/db/schema/capacity-assignments.js.map +1 -0
  127. package/dist/db/schema/ephemeral-registration-tokens.d.ts +2 -2
  128. package/dist/db/schema/ephemeral-registration-tokens.js +3 -3
  129. package/dist/db/schema/ephemeral-registration-tokens.js.map +1 -1
  130. package/dist/db/schema/provisioner-capability-snapshots.d.ts +207 -0
  131. package/dist/db/schema/provisioner-capability-snapshots.d.ts.map +1 -0
  132. package/dist/db/schema/provisioner-capability-snapshots.js +38 -0
  133. package/dist/db/schema/provisioner-capability-snapshots.js.map +1 -0
  134. package/dist/db/schema/provisioner-tokens.d.ts +19 -1
  135. package/dist/db/schema/provisioner-tokens.d.ts.map +1 -1
  136. package/dist/db/schema/provisioner-tokens.js +29 -3
  137. package/dist/db/schema/provisioner-tokens.js.map +1 -1
  138. package/dist/db/schema/runner-activation-tokens.d.ts +161 -0
  139. package/dist/db/schema/runner-activation-tokens.d.ts.map +1 -0
  140. package/dist/db/schema/runner-activation-tokens.js +27 -0
  141. package/dist/db/schema/runner-activation-tokens.js.map +1 -0
  142. package/dist/db/schema/runner-control-sessions.d.ts +338 -0
  143. package/dist/db/schema/runner-control-sessions.d.ts.map +1 -0
  144. package/dist/db/schema/runner-control-sessions.js +52 -0
  145. package/dist/db/schema/runner-control-sessions.js.map +1 -0
  146. package/dist/db/schema/{provisioned-runners.d.ts → runner-instances.d.ts} +88 -34
  147. package/dist/db/schema/runner-instances.d.ts.map +1 -0
  148. package/dist/db/schema/{provisioned-runners.js → runner-instances.js} +19 -14
  149. package/dist/db/schema/runner-instances.js.map +1 -0
  150. package/dist/db/schema/runner-sessions.d.ts +39 -5
  151. package/dist/db/schema/runner-sessions.d.ts.map +1 -1
  152. package/dist/db/schema/runner-sessions.js +13 -6
  153. package/dist/db/schema/runner-sessions.js.map +1 -1
  154. package/dist/db/schema/running-job-executions.d.ts +2 -2
  155. package/dist/db/schema/running-job-executions.js +4 -4
  156. package/dist/db/schema/running-job-executions.js.map +1 -1
  157. package/dist/index.d.ts +7 -2
  158. package/dist/index.d.ts.map +1 -1
  159. package/dist/index.js +45 -38
  160. package/dist/index.js.map +1 -1
  161. package/dist/installation-provisioning.d.ts +14 -0
  162. package/dist/installation-provisioning.d.ts.map +1 -0
  163. package/dist/installation-provisioning.js +7 -0
  164. package/dist/installation-provisioning.js.map +1 -0
  165. package/dist/metrics/index.d.ts +1 -1
  166. package/dist/metrics/index.d.ts.map +1 -1
  167. package/dist/metrics/index.js +1 -1
  168. package/dist/metrics/index.js.map +1 -1
  169. package/dist/metrics/instance.d.ts +11 -7
  170. package/dist/metrics/instance.d.ts.map +1 -1
  171. package/dist/metrics/instance.js +13 -7
  172. package/dist/metrics/instance.js.map +1 -1
  173. package/dist/presentation/auth/index.d.ts +1 -0
  174. package/dist/presentation/auth/index.d.ts.map +1 -1
  175. package/dist/presentation/auth/index.js +1 -0
  176. package/dist/presentation/auth/index.js.map +1 -1
  177. package/dist/presentation/auth/provisioner-token-auth.d.ts.map +1 -1
  178. package/dist/presentation/auth/provisioner-token-auth.js +5 -1
  179. package/dist/presentation/auth/provisioner-token-auth.js.map +1 -1
  180. package/dist/presentation/auth/runner-control-session-auth.d.ts +4 -0
  181. package/dist/presentation/auth/runner-control-session-auth.d.ts.map +1 -0
  182. package/dist/presentation/auth/runner-control-session-auth.js +29 -0
  183. package/dist/presentation/auth/runner-control-session-auth.js.map +1 -0
  184. package/dist/presentation/auth/runner-registration-token-auth.d.ts +5 -1
  185. package/dist/presentation/auth/runner-registration-token-auth.d.ts.map +1 -1
  186. package/dist/presentation/auth/runner-registration-token-auth.js +21 -1
  187. package/dist/presentation/auth/runner-registration-token-auth.js.map +1 -1
  188. package/dist/presentation/dto/index.d.ts +2 -2
  189. package/dist/presentation/dto/index.d.ts.map +1 -1
  190. package/dist/presentation/dto/index.js +2 -2
  191. package/dist/presentation/dto/index.js.map +1 -1
  192. package/dist/presentation/dto/mint-registration-tokens.d.ts +5 -3
  193. package/dist/presentation/dto/mint-registration-tokens.d.ts.map +1 -1
  194. package/dist/presentation/dto/mint-registration-tokens.js +4 -4
  195. package/dist/presentation/dto/mint-registration-tokens.js.map +1 -1
  196. package/dist/presentation/dto/poll-demand.d.ts.map +1 -1
  197. package/dist/presentation/dto/poll-demand.js +7 -1
  198. package/dist/presentation/dto/poll-demand.js.map +1 -1
  199. package/dist/presentation/dto/provisioner-token.d.ts +1 -0
  200. package/dist/presentation/dto/provisioner-token.d.ts.map +1 -1
  201. package/dist/presentation/dto/provisioner-token.js +5 -1
  202. package/dist/presentation/dto/provisioner-token.js.map +1 -1
  203. package/dist/presentation/dto/{provisioned-runners.d.ts → runner-instances.d.ts} +9 -9
  204. package/dist/presentation/dto/runner-instances.d.ts.map +1 -0
  205. package/dist/presentation/dto/{provisioned-runners.js → runner-instances.js} +6 -6
  206. package/dist/presentation/dto/runner-instances.js.map +1 -0
  207. package/dist/presentation/index.d.ts +2 -2
  208. package/dist/presentation/index.d.ts.map +1 -1
  209. package/dist/presentation/index.js +2 -2
  210. package/dist/presentation/index.js.map +1 -1
  211. package/dist/presentation/inter-module.d.ts +5 -0
  212. package/dist/presentation/inter-module.d.ts.map +1 -0
  213. package/dist/presentation/inter-module.js +43 -0
  214. package/dist/presentation/inter-module.js.map +1 -0
  215. package/dist/presentation/routes/assign-capacity.d.ts +2 -0
  216. package/dist/presentation/routes/assign-capacity.d.ts.map +1 -0
  217. package/dist/presentation/routes/assign-capacity.js +44 -0
  218. package/dist/presentation/routes/assign-capacity.js.map +1 -0
  219. package/dist/presentation/routes/get-provisioner-me.d.ts.map +1 -1
  220. package/dist/presentation/routes/get-provisioner-me.js +5 -1
  221. package/dist/presentation/routes/get-provisioner-me.js.map +1 -1
  222. package/dist/presentation/routes/heartbeat.d.ts +2 -1
  223. package/dist/presentation/routes/heartbeat.d.ts.map +1 -1
  224. package/dist/presentation/routes/heartbeat.js +60 -50
  225. package/dist/presentation/routes/heartbeat.js.map +1 -1
  226. package/dist/presentation/routes/index.d.ts +3 -1
  227. package/dist/presentation/routes/index.d.ts.map +1 -1
  228. package/dist/presentation/routes/index.js +83 -50
  229. package/dist/presentation/routes/index.js.map +1 -1
  230. package/dist/presentation/routes/mint-registration-tokens.d.ts.map +1 -1
  231. package/dist/presentation/routes/mint-registration-tokens.js +5 -5
  232. package/dist/presentation/routes/mint-registration-tokens.js.map +1 -1
  233. package/dist/presentation/routes/planned-capacity.d.ts +3 -0
  234. package/dist/presentation/routes/planned-capacity.d.ts.map +1 -0
  235. package/dist/presentation/routes/planned-capacity.js +54 -0
  236. package/dist/presentation/routes/planned-capacity.js.map +1 -0
  237. package/dist/presentation/routes/poll-demand.d.ts +2 -0
  238. package/dist/presentation/routes/poll-demand.d.ts.map +1 -1
  239. package/dist/presentation/routes/poll-demand.js +86 -45
  240. package/dist/presentation/routes/poll-demand.js.map +1 -1
  241. package/dist/presentation/routes/reconcile-runner-instances.d.ts +2 -0
  242. package/dist/presentation/routes/reconcile-runner-instances.d.ts.map +1 -0
  243. package/dist/presentation/routes/reconcile-runner-instances.js +27 -0
  244. package/dist/presentation/routes/reconcile-runner-instances.js.map +1 -0
  245. package/dist/presentation/routes/register.d.ts +2 -1
  246. package/dist/presentation/routes/register.d.ts.map +1 -1
  247. package/dist/presentation/routes/register.js +55 -52
  248. package/dist/presentation/routes/register.js.map +1 -1
  249. package/dist/presentation/routes/report-runner-instances.d.ts +2 -0
  250. package/dist/presentation/routes/report-runner-instances.d.ts.map +1 -0
  251. package/dist/presentation/routes/report-runner-instances.js +37 -0
  252. package/dist/presentation/routes/report-runner-instances.js.map +1 -0
  253. package/dist/presentation/routes/request-job.d.ts +2 -1
  254. package/dist/presentation/routes/request-job.d.ts.map +1 -1
  255. package/dist/presentation/routes/request-job.js +39 -36
  256. package/dist/presentation/routes/request-job.js.map +1 -1
  257. package/dist/presentation/routes/runner-enrollment.d.ts +7 -0
  258. package/dist/presentation/routes/runner-enrollment.d.ts.map +1 -0
  259. package/dist/presentation/routes/runner-enrollment.js +185 -0
  260. package/dist/presentation/routes/runner-enrollment.js.map +1 -0
  261. package/dist/temporal/activities/index.d.ts +2 -2
  262. package/dist/temporal/activities/index.d.ts.map +1 -1
  263. package/dist/temporal/activities/index.js +2 -2
  264. package/dist/temporal/activities/index.js.map +1 -1
  265. package/dist/temporal/activities/maintenance-activities.d.ts +1 -1
  266. package/dist/temporal/activities/maintenance-activities.d.ts.map +1 -1
  267. package/dist/temporal/activities/maintenance-activities.js +3 -3
  268. package/dist/temporal/activities/maintenance-activities.js.map +1 -1
  269. package/dist/temporal/workflows/index.bundle.js +3 -3
  270. package/dist/temporal/workflows/stuck-job-detector.js +2 -2
  271. package/dist/temporal/workflows/stuck-job-detector.js.map +1 -1
  272. package/dist/tsconfig.test.tsbuildinfo +1 -1
  273. package/drizzle/0000_initial.sql +102 -24
  274. package/drizzle/meta/0000_snapshot.json +483 -63
  275. package/package.json +31 -36
  276. package/src/config.test.ts +0 -26
  277. package/src/config.ts +47 -6
  278. package/src/core/capacity-assignments.ts +10 -0
  279. package/src/core/demand.test.ts +29 -29
  280. package/src/core/demand.ts +22 -22
  281. package/src/core/entities/capacity-assignment.ts +8 -0
  282. package/src/core/entities/ephemeral-registration-token.ts +1 -1
  283. package/src/core/entities/provisioner-capability-snapshot.ts +12 -0
  284. package/src/core/entities/provisioner-token.ts +8 -2
  285. package/src/core/entities/{provisioned-runner.ts → runner-instance.ts} +5 -5
  286. package/src/core/entities/runner-session.ts +4 -2
  287. package/src/core/ephemeral-registration-tokens.test.ts +11 -11
  288. package/src/core/ephemeral-registration-tokens.ts +18 -20
  289. package/src/core/errors.ts +23 -4
  290. package/src/core/index.ts +39 -17
  291. package/src/core/job-executions.ts +3 -2
  292. package/src/core/maintenance.test.ts +13 -17
  293. package/src/core/maintenance.ts +5 -5
  294. package/src/core/provisioner-capability-snapshots.test.ts +35 -0
  295. package/src/core/provisioner-capability-snapshots.ts +12 -0
  296. package/src/core/provisioner-tokens.test.ts +20 -0
  297. package/src/core/provisioner-tokens.ts +33 -0
  298. package/src/core/rate-limit.test.ts +11 -27
  299. package/src/core/rate-limit.ts +3 -11
  300. package/src/core/runner-activation.ts +72 -0
  301. package/src/core/runner-control-sessions.ts +190 -0
  302. package/src/core/{provisioned-runners.test.ts → runner-instances.test.ts} +24 -24
  303. package/src/core/runner-instances.ts +310 -0
  304. package/src/core/runner-sessions.test.ts +112 -22
  305. package/src/core/runner-sessions.ts +25 -14
  306. package/src/db/capacity-assignments.test.ts +159 -0
  307. package/src/db/capacity-assignments.ts +116 -0
  308. package/src/db/db.ts +11 -2
  309. package/src/db/ephemeral-registration-tokens.test.ts +9 -9
  310. package/src/db/ephemeral-registration-tokens.ts +26 -26
  311. package/src/db/index.ts +31 -21
  312. package/src/db/job-executions.test.ts +13 -11
  313. package/src/db/job-executions.ts +33 -27
  314. package/src/db/provisioner-capability-snapshots.test.ts +175 -0
  315. package/src/db/provisioner-capability-snapshots.ts +130 -0
  316. package/src/db/provisioner-tokens.test.ts +139 -2
  317. package/src/db/provisioner-tokens.ts +123 -15
  318. package/src/db/reservations.test.ts +49 -0
  319. package/src/db/reservations.ts +146 -1
  320. package/src/db/{provisioned-runners.test.ts → runner-instances.test.ts} +429 -353
  321. package/src/db/runner-instances.ts +942 -0
  322. package/src/db/runner-sessions.test.ts +19 -6
  323. package/src/db/runner-sessions.ts +78 -2
  324. package/src/db/schema/capacity-assignments.ts +34 -0
  325. package/src/db/schema/ephemeral-registration-tokens.ts +4 -4
  326. package/src/db/schema/provisioner-capability-snapshots.ts +46 -0
  327. package/src/db/schema/provisioner-tokens.ts +33 -2
  328. package/src/db/schema/runner-activation-tokens.ts +22 -0
  329. package/src/db/schema/runner-control-sessions.ts +46 -0
  330. package/src/db/schema/{provisioned-runners.ts → runner-instances.ts} +26 -27
  331. package/src/db/schema/runner-sessions.ts +11 -7
  332. package/src/db/schema/running-job-executions.ts +5 -5
  333. package/src/index.test.ts +26 -0
  334. package/src/index.ts +39 -19
  335. package/src/installation-provisioning.ts +14 -0
  336. package/src/metrics/index.ts +5 -5
  337. package/src/metrics/instance.ts +25 -14
  338. package/src/presentation/auth/index.ts +4 -0
  339. package/src/presentation/auth/provisioner-token-auth.ts +8 -4
  340. package/src/presentation/auth/runner-control-session-auth.ts +31 -0
  341. package/src/presentation/auth/runner-registration-token-auth.ts +39 -3
  342. package/src/presentation/dto/index.ts +5 -5
  343. package/src/presentation/dto/mint-registration-tokens.ts +8 -15
  344. package/src/presentation/dto/poll-demand.ts +3 -1
  345. package/src/presentation/dto/provisioner-token.ts +5 -0
  346. package/src/presentation/dto/{provisioned-runners.ts → runner-instances.ts} +13 -15
  347. package/src/presentation/index.ts +2 -1
  348. package/src/presentation/inter-module.test.ts +15 -0
  349. package/src/presentation/inter-module.ts +53 -0
  350. package/src/presentation/routes/assign-capacity.ts +48 -0
  351. package/src/presentation/routes/get-provisioner-me.ts +3 -4
  352. package/src/presentation/routes/heartbeat.test.ts +4 -3
  353. package/src/presentation/routes/heartbeat.ts +67 -64
  354. package/src/presentation/routes/index.ts +93 -43
  355. package/src/presentation/routes/list-active-runners.test.ts +23 -23
  356. package/src/presentation/routes/manual-registration-tokens.test.ts +4 -3
  357. package/src/presentation/routes/mint-registration-tokens.test.ts +12 -12
  358. package/src/presentation/routes/mint-registration-tokens.ts +5 -7
  359. package/src/presentation/routes/planned-capacity.ts +49 -0
  360. package/src/presentation/routes/poll-demand-release.test.ts +4 -4
  361. package/src/presentation/routes/poll-demand.test.ts +161 -22
  362. package/src/presentation/routes/poll-demand.ts +105 -45
  363. package/src/presentation/routes/provisioner-me.test.ts +37 -3
  364. package/src/presentation/routes/{reconcile-provisioned-runners.test.ts → reconcile-runner-instances.test.ts} +66 -61
  365. package/src/presentation/routes/reconcile-runner-instances.ts +30 -0
  366. package/src/presentation/routes/register.test.ts +9 -5
  367. package/src/presentation/routes/register.ts +61 -57
  368. package/src/presentation/routes/{report-provisioned-runners.test.ts → report-runner-instances.test.ts} +28 -28
  369. package/src/presentation/routes/{report-provisioned-runners.ts → report-runner-instances.ts} +14 -14
  370. package/src/presentation/routes/request-job.test.ts +5 -3
  371. package/src/presentation/routes/request-job.ts +41 -37
  372. package/src/presentation/routes/runner-enrollment.test.ts +259 -0
  373. package/src/presentation/routes/runner-enrollment.ts +174 -0
  374. package/src/temporal/activities/index.ts +2 -2
  375. package/src/temporal/activities/maintenance-activities.test.ts +7 -7
  376. package/src/temporal/activities/maintenance-activities.ts +3 -3
  377. package/src/temporal/workflows/stuck-job-detector.test.ts +3 -3
  378. package/src/temporal/workflows/stuck-job-detector.ts +2 -2
  379. package/test/env.ts +1 -3
  380. package/test/factories/ephemeral-registration-token.ts +2 -2
  381. package/test/factories/provisioner-token.ts +3 -1
  382. package/test/factories/runner-instance.ts +57 -0
  383. package/test/factories/runner-session.ts +3 -1
  384. package/test/fixtures/auth-inter-module.ts +30 -0
  385. package/test/globalSetup.ts +5 -1
  386. package/test/index.ts +2 -1
  387. package/tsconfig.build.tsbuildinfo +1 -1
  388. package/dist/core/entities/provisioned-runner.d.ts.map +0 -1
  389. package/dist/core/entities/provisioned-runner.js +0 -3
  390. package/dist/core/entities/provisioned-runner.js.map +0 -1
  391. package/dist/core/provisioned-runners.d.ts +0 -67
  392. package/dist/core/provisioned-runners.d.ts.map +0 -1
  393. package/dist/core/provisioned-runners.js +0 -162
  394. package/dist/core/provisioned-runners.js.map +0 -1
  395. package/dist/db/provisioned-runners.d.ts +0 -79
  396. package/dist/db/provisioned-runners.d.ts.map +0 -1
  397. package/dist/db/provisioned-runners.js +0 -466
  398. package/dist/db/provisioned-runners.js.map +0 -1
  399. package/dist/db/schema/provisioned-runners.d.ts.map +0 -1
  400. package/dist/db/schema/provisioned-runners.js.map +0 -1
  401. package/dist/presentation/dto/provisioned-runners.d.ts.map +0 -1
  402. package/dist/presentation/dto/provisioned-runners.js.map +0 -1
  403. package/dist/presentation/routes/reconcile-provisioned-runners.d.ts +0 -2
  404. package/dist/presentation/routes/reconcile-provisioned-runners.d.ts.map +0 -1
  405. package/dist/presentation/routes/reconcile-provisioned-runners.js +0 -27
  406. package/dist/presentation/routes/reconcile-provisioned-runners.js.map +0 -1
  407. package/dist/presentation/routes/report-provisioned-runners.d.ts +0 -2
  408. package/dist/presentation/routes/report-provisioned-runners.d.ts.map +0 -1
  409. package/dist/presentation/routes/report-provisioned-runners.js +0 -37
  410. package/dist/presentation/routes/report-provisioned-runners.js.map +0 -1
  411. package/src/core/provisioned-runners.ts +0 -301
  412. package/src/db/provisioned-runners.ts +0 -886
  413. package/src/presentation/routes/reconcile-provisioned-runners.ts +0 -30
  414. package/test/factories/provisioned-runner.ts +0 -78
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import {dirname, resolve} from 'node:path';
2
2
  import {fileURLToPath} from 'node:url';
3
+ import type {AuthInterModuleClient} from '@shipfox/api-auth-dto/inter-module';
3
4
  import {runnersEventSchemas} from '@shipfox/api-runners-dto';
4
5
  import {
5
6
  WORKFLOWS_JOB_EXECUTION_TIMED_OUT,
@@ -7,13 +8,16 @@ import {
7
8
  } from '@shipfox/api-workflows-dto';
8
9
  import {type ShipfoxModule, subscriberFactory} from '@shipfox/node-module';
9
10
  import {db, migrationsPath, runnersOutbox} from '#db/index.js';
11
+ import type {CreateRunnersModuleOptions} from '#installation-provisioning.js';
10
12
  import {registerRunnersServiceMetrics} from '#metrics/index.js';
11
13
  import {
12
14
  createProvisionerTokenAuthMethod,
15
+ createRunnerControlSessionAuthMethod,
13
16
  createRunnerRegistrationTokenAuthMethod,
17
+ createRunnerRoutes,
14
18
  onWorkflowsJobExecutionTimedOut,
15
- routes,
16
19
  } from '#presentation/index.js';
20
+ import {createRunnersInterModulePresentation} from '#presentation/inter-module.js';
17
21
  import {createRunnersMaintenanceActivities} from '#temporal/activities/index.js';
18
22
  import {RUNNERS_MAINTENANCE_TASK_QUEUE} from '#temporal/constants.js';
19
23
 
@@ -21,8 +25,8 @@ export {
21
25
  type MintEphemeralRegistrationTokenParams,
22
26
  type MintEphemeralRegistrationTokenResult,
23
27
  type MintEphemeralRegistrationTokensBatchParams,
24
- type MintEphemeralRegistrationTokensBatchProvisionedRunner,
25
28
  type MintEphemeralRegistrationTokensBatchResult,
29
+ type MintEphemeralRegistrationTokensBatchRunnerInstance,
26
30
  mintEphemeralRegistrationToken,
27
31
  mintEphemeralRegistrationTokensBatch,
28
32
  } from '#core/ephemeral-registration-tokens.js';
@@ -38,26 +42,42 @@ export {
38
42
  isJobLeaseActive,
39
43
  releaseJobExecution,
40
44
  } from '#db/index.js';
45
+ export type {
46
+ CreateRunnersModuleOptions,
47
+ InstallationProvisioningPolicy,
48
+ } from '#installation-provisioning.js';
41
49
 
42
50
  const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
43
51
  const workflowsPath = resolve(packageRoot, 'dist/temporal/workflows/index.js');
44
52
 
45
53
  const subscriber = subscriberFactory<WorkflowsEventMapDto>();
46
54
 
47
- export const runnersModule: ShipfoxModule = {
48
- name: 'runners',
49
- database: {db, migrationsPath},
50
- auth: [createRunnerRegistrationTokenAuthMethod(), createProvisionerTokenAuthMethod()],
51
- routes,
52
- metrics: registerRunnersServiceMetrics,
53
- publishers: [{name: 'runners', table: runnersOutbox, db, eventSchemas: runnersEventSchemas}],
54
- subscribers: [subscriber(WORKFLOWS_JOB_EXECUTION_TIMED_OUT, onWorkflowsJobExecutionTimedOut)],
55
- workers: [
56
- {
57
- taskQueue: RUNNERS_MAINTENANCE_TASK_QUEUE,
58
- workflowsPath,
59
- activities: createRunnersMaintenanceActivities,
60
- workflows: [{name: 'stuckJobDetector', id: 'stuck-job-detector', cronSchedule: '* * * * *'}],
61
- },
62
- ],
63
- };
55
+ export function createRunnersModule({
56
+ auth,
57
+ ...options
58
+ }: CreateRunnersModuleOptions & {auth: AuthInterModuleClient}): ShipfoxModule {
59
+ return {
60
+ name: 'runners',
61
+ database: {db, migrationsPath},
62
+ auth: [
63
+ createRunnerRegistrationTokenAuthMethod(),
64
+ createRunnerControlSessionAuthMethod(),
65
+ createProvisionerTokenAuthMethod(),
66
+ ],
67
+ routes: createRunnerRoutes(auth, options),
68
+ metrics: registerRunnersServiceMetrics,
69
+ publishers: [{name: 'runners', table: runnersOutbox, db, eventSchemas: runnersEventSchemas}],
70
+ subscribers: [subscriber(WORKFLOWS_JOB_EXECUTION_TIMED_OUT, onWorkflowsJobExecutionTimedOut)],
71
+ workers: [
72
+ {
73
+ taskQueue: RUNNERS_MAINTENANCE_TASK_QUEUE,
74
+ workflowsPath,
75
+ activities: createRunnersMaintenanceActivities,
76
+ workflows: [
77
+ {name: 'stuckJobDetector', id: 'stuck-job-detector', cronSchedule: '* * * * *'},
78
+ ],
79
+ },
80
+ ],
81
+ interModulePresentations: [createRunnersInterModulePresentation()],
82
+ };
83
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Lets an application host choose which workspaces may receive installation-provisioned capacity.
3
+ * The runners module passes candidate IDs in batches so host policy can apply its own entitlement
4
+ * or tenancy rules without exposing those rules from this package.
5
+ */
6
+ export interface InstallationProvisioningPolicy {
7
+ filterEligibleWorkspaceIds(workspaceIds: readonly string[]): Promise<ReadonlySet<string>>;
8
+ }
9
+
10
+ export interface CreateRunnersModuleOptions {
11
+ installationProvisioning?: {
12
+ policy: InstallationProvisioningPolicy;
13
+ };
14
+ }
@@ -2,11 +2,11 @@ export {
2
2
  jobExecutionClaimedCount,
3
3
  jobExecutionEnqueuedCount,
4
4
  jobExecutionLeaseExpiredCount,
5
- provisionedRunnerAbsentTerminatedCount,
6
- provisionedRunnerCountDivergenceCount,
7
- provisionedRunnerReconcileCallCount,
8
- provisionedRunnerTerminateIntentHonoredCount,
9
- provisionedRunnerTerminateIntentIssuedCount,
5
+ providerRunnerAbsentTerminatedCount,
6
+ providerRunnerCountDivergenceCount,
7
+ providerRunnerReconcileCallCount,
8
+ providerRunnerTerminateIntentHonoredCount,
9
+ providerRunnerTerminateIntentIssuedCount,
10
10
  recordRunnersRateLimitCheck,
11
11
  recordRunnersRateLimitPruneFailure,
12
12
  } from './instance.js';
@@ -19,51 +19,62 @@ export const jobExecutionLeaseExpiredCount = meter.createCounter<Record<string,
19
19
  {description: 'Job execution leases reaped after passing the heartbeat threshold'},
20
20
  );
21
21
 
22
- export const provisionedRunnerReportCount = meter.createCounter<{
22
+ export const providerRunnerReportCount = meter.createCounter<{
23
23
  state: 'starting' | 'running' | 'stopping' | 'stopped' | 'failed' | 'terminated';
24
- }>('runners_provisioned_runner_reported', {
24
+ }>('runners_provider_runner_reported', {
25
25
  description: 'Provisioned runner lifecycle reports accepted by state',
26
26
  });
27
27
 
28
- export const provisionedRunnerReapedCount = meter.createCounter<Record<string, never>>(
29
- 'runners_provisioned_runner_reaped',
28
+ export const runnerBootstrapExchangeCount = meter.createCounter<{
29
+ outcome: 'accepted' | 'rejected';
30
+ }>('runners_runner_bootstrap_exchange', {
31
+ description: 'Runner bootstrap-token exchanges by outcome',
32
+ });
33
+
34
+ export const runnerControlHeartbeatCount = meter.createCounter<Record<string, never>>(
35
+ 'runners_runner_control_heartbeat',
36
+ {description: 'Pre-workspace runner-control heartbeats accepted'},
37
+ );
38
+
39
+ export const providerRunnerReapedCount = meter.createCounter<Record<string, never>>(
40
+ 'runners_provider_runner_reaped',
30
41
  {
31
42
  description: 'Stale provisioned runners marked failed by backend maintenance',
32
43
  },
33
44
  );
34
45
 
35
- export const provisionedRunnerCountDivergenceCount = meter.createCounter<{
46
+ export const providerRunnerCountDivergenceCount = meter.createCounter<{
36
47
  template_key?: string;
37
48
  state: 'starting' | 'running';
38
49
  direction: 'backend-higher' | 'advertised-higher';
39
- }>('runners_provisioned_runner_count_divergence', {
50
+ }>('runners_provider_runner_count_divergence', {
40
51
  description:
41
52
  'Absolute difference between provisioner-advertised and backend-observed provisioned runner counts',
42
53
  });
43
54
 
44
- export const provisionedRunnerReconcileCallCount = meter.createCounter<Record<string, never>>(
45
- 'runners_provisioned_runner_reconcile_called',
55
+ export const providerRunnerReconcileCallCount = meter.createCounter<Record<string, never>>(
56
+ 'runners_provider_runner_reconcile_called',
46
57
  {description: 'Provisioned runner reconcile calls completed successfully'},
47
58
  );
48
59
 
49
- export const provisionedRunnerAbsentTerminatedCount = meter.createCounter<Record<string, never>>(
50
- 'runners_provisioned_runner_absent_terminated',
60
+ export const providerRunnerAbsentTerminatedCount = meter.createCounter<Record<string, never>>(
61
+ 'runners_provider_runner_absent_terminated',
51
62
  {
52
63
  description:
53
64
  'Owned provisioned runners marked terminated because they were absent from reconcile',
54
65
  },
55
66
  );
56
67
 
57
- export const provisionedRunnerTerminateIntentIssuedCount = meter.createCounter<{
68
+ export const providerRunnerTerminateIntentIssuedCount = meter.createCounter<{
58
69
  surface: 'poll-demand' | 'reconcile';
59
70
  reason: 'job-cancelled' | 'terminal-state';
60
- }>('runners_provisioned_runner_terminate_intent_issued', {
71
+ }>('runners_provider_runner_terminate_intent_issued', {
61
72
  description: 'Provisioned runner terminate intents returned to provisioners',
62
73
  });
63
74
 
64
- export const provisionedRunnerTerminateIntentHonoredCount = meter.createCounter<{
75
+ export const providerRunnerTerminateIntentHonoredCount = meter.createCounter<{
65
76
  reason: 'job-cancelled';
66
- }>('runners_provisioned_runner_terminate_intent_honored', {
77
+ }>('runners_provider_runner_terminate_intent_honored', {
67
78
  description: 'Provisioned runner terminate intents honored by first transition to terminated',
68
79
  });
69
80
 
@@ -1,4 +1,8 @@
1
1
  export {createProvisionerTokenAuthMethod} from './provisioner-token-auth.js';
2
+ export {
3
+ authenticateRunnerControlSession,
4
+ createRunnerControlSessionAuthMethod,
5
+ } from './runner-control-session-auth.js';
2
6
  export {
3
7
  createRunnerRegistrationTokenAuthMethod,
4
8
  getRunnerContext,
@@ -48,10 +48,14 @@ export function createProvisionerTokenAuthMethod(): AuthMethod {
48
48
  });
49
49
  }
50
50
 
51
- const context: ProvisionerContext = {
52
- provisionerTokenId: provisionerToken.id,
53
- workspaceId: provisionerToken.workspaceId,
54
- };
51
+ const context: ProvisionerContext =
52
+ provisionerToken.scope === 'installation'
53
+ ? {provisionerTokenId: provisionerToken.id, scope: 'installation'}
54
+ : {
55
+ provisionerTokenId: provisionerToken.id,
56
+ scope: 'workspace',
57
+ workspaceId: provisionerToken.workspaceId,
58
+ };
55
59
 
56
60
  await touchProvisionerLastSeen({
57
61
  tokenId: provisionerToken.id,
@@ -0,0 +1,31 @@
1
+ import {
2
+ AUTH_RUNNER_CONTROL_SESSION,
3
+ setRunnerControlSessionContext,
4
+ } from '@shipfox/api-auth-context';
5
+ import {type AuthMethod, ClientError, extractBearerToken} from '@shipfox/node-fastify';
6
+ import {getTokenType} from '@shipfox/node-tokens';
7
+ import {resolveRunnerControlSession} from '#core/runner-control-sessions.js';
8
+
9
+ export function createRunnerControlSessionAuthMethod(): AuthMethod {
10
+ return {
11
+ name: AUTH_RUNNER_CONTROL_SESSION,
12
+ authenticate: authenticateRunnerControlSession,
13
+ };
14
+ }
15
+
16
+ export async function authenticateRunnerControlSession(
17
+ request: Parameters<AuthMethod['authenticate']>[0],
18
+ ) {
19
+ const rawToken = extractBearerToken(request.headers.authorization);
20
+ if (!rawToken || getTokenType(rawToken) !== 'runnerControlSession') {
21
+ throw new ClientError('Invalid runner control session', 'unauthorized', {status: 401});
22
+ }
23
+ const session = await resolveRunnerControlSession(rawToken);
24
+ if (!session)
25
+ throw new ClientError('Invalid runner control session', 'unauthorized', {status: 401});
26
+ setRunnerControlSessionContext(request, {
27
+ runnerControlSessionId: session.id,
28
+ runnerInstanceId: session.runnerInstanceId,
29
+ provisionerId: session.provisionerId,
30
+ });
31
+ }
@@ -1,9 +1,14 @@
1
1
  import {AUTH_RUNNER_REGISTRATION_TOKEN} from '@shipfox/api-auth-context';
2
2
  import {type AuthMethod, ClientError, extractBearerToken} from '@shipfox/node-fastify';
3
3
  import {getTokenType, hashOpaqueToken} from '@shipfox/node-tokens';
4
+ import {and, eq, gt, isNull, or, sql} from 'drizzle-orm';
4
5
  import type {FastifyRequest} from 'fastify';
6
+ import {db} from '#db/db.js';
5
7
  import {resolveEphemeralRegistrationTokenByHash} from '#db/ephemeral-registration-tokens.js';
6
8
  import {resolveManualRegistrationTokenByHash} from '#db/manual-registration-tokens.js';
9
+ import {provisionerTokens} from '#db/schema/provisioner-tokens.js';
10
+ import {runnerActivationTokens} from '#db/schema/runner-activation-tokens.js';
11
+ import {providerRunners} from '#db/schema/runner-instances.js';
7
12
 
8
13
  const RUNNER_CONTEXT_KEY = 'runner';
9
14
 
@@ -19,8 +24,9 @@ export type RunnerRegistrationContext =
19
24
  workspaceId: string;
20
25
  provisionerId: string;
21
26
  reservationId: string | null;
22
- provisionedRunnerId: string;
23
- };
27
+ providerRunnerId: string;
28
+ }
29
+ | {kind: 'activation'; activationTokenId: string; workspaceId: string};
24
30
 
25
31
  export function getRunnerContext(request: FastifyRequest): RunnerRegistrationContext {
26
32
  const context = (request as unknown as Record<string, unknown>)[RUNNER_CONTEXT_KEY] as
@@ -45,6 +51,36 @@ export function createRunnerRegistrationTokenAuthMethod(): AuthMethod {
45
51
 
46
52
  const tokenType = getTokenType(rawToken);
47
53
 
54
+ if (tokenType === 'runnerActivationToken') {
55
+ const [activation] = await db()
56
+ .select({id: runnerActivationTokens.id, workspaceId: providerRunners.workspaceId})
57
+ .from(runnerActivationTokens)
58
+ .innerJoin(
59
+ providerRunners,
60
+ eq(providerRunners.id, runnerActivationTokens.runnerInstanceId),
61
+ )
62
+ .leftJoin(provisionerTokens, eq(provisionerTokens.id, providerRunners.provisionerId))
63
+ .where(
64
+ and(
65
+ eq(runnerActivationTokens.hashedToken, hashOpaqueToken(rawToken)),
66
+ isNull(runnerActivationTokens.consumedAt),
67
+ isNull(runnerActivationTokens.revokedAt),
68
+ gt(runnerActivationTokens.expiresAt, sql`now()`),
69
+ or(isNull(provisionerTokens.id), isNull(provisionerTokens.revokedAt)),
70
+ isNull(providerRunners.runnerSessionId),
71
+ ),
72
+ )
73
+ .limit(1);
74
+ if (!activation?.workspaceId)
75
+ throw new ClientError('Invalid runner registration token', 'unauthorized', {status: 401});
76
+ (request as unknown as Record<string, unknown>)[RUNNER_CONTEXT_KEY] = {
77
+ kind: 'activation',
78
+ activationTokenId: activation.id,
79
+ workspaceId: activation.workspaceId,
80
+ } satisfies RunnerRegistrationContext;
81
+ return;
82
+ }
83
+
48
84
  if (tokenType === 'ephemeralRegistrationToken') {
49
85
  const ephemeralToken = await resolveEphemeralRegistrationTokenByHash(
50
86
  hashOpaqueToken(rawToken),
@@ -68,7 +104,7 @@ export function createRunnerRegistrationTokenAuthMethod(): AuthMethod {
68
104
  workspaceId: ephemeralToken.workspaceId,
69
105
  provisionerId: ephemeralToken.provisionerId,
70
106
  reservationId: ephemeralToken.reservationId,
71
- provisionedRunnerId: ephemeralToken.provisionedRunnerId,
107
+ providerRunnerId: ephemeralToken.providerRunnerId,
72
108
  } satisfies RunnerRegistrationContext;
73
109
  return;
74
110
  }
@@ -1,13 +1,13 @@
1
1
  export {toActiveProvisionerDto} from './active-provisioner.js';
2
2
  export {toManualRegistrationTokenDto} from './manual-registration-token.js';
3
3
  export {
4
- toMintRegistrationTokensProvisionedRunners,
5
4
  toMintRegistrationTokensResponseDto,
5
+ toMintRegistrationTokensRunnerInstances,
6
6
  } from './mint-registration-tokens.js';
7
7
  export {toPollDemandResponseDto} from './poll-demand.js';
8
+ export {toProvisionerTokenDto} from './provisioner-token.js';
8
9
  export {
9
10
  toActiveRunnersResponseDto,
10
- toReconcileProvisionedRunnersResponseDto,
11
- toReportProvisionedRunnersResponseDto,
12
- } from './provisioned-runners.js';
13
- export {toProvisionerTokenDto} from './provisioner-token.js';
11
+ toReconcileRunnerInstancesResponseDto,
12
+ toReportRunnerInstancesResponseDto,
13
+ } from './runner-instances.js';
@@ -1,34 +1,27 @@
1
1
  import type {
2
2
  MintedRegistrationTokenDto,
3
3
  MintRegistrationTokensBatchResponseDto,
4
- MintRegistrationTokensProvisionedRunnerDto,
4
+ MintRegistrationTokensRunnerInstanceDto,
5
5
  } from '@shipfox/api-runners-dto';
6
- import type {
7
- MintEphemeralRegistrationTokensBatchProvisionedRunner,
8
- MintEphemeralRegistrationTokensBatchResult,
9
- } from '#core/ephemeral-registration-tokens.js';
6
+ import type {MintEphemeralRegistrationTokensBatchResult} from '#core/ephemeral-registration-tokens.js';
10
7
 
11
- export function toMintRegistrationTokensProvisionedRunners(
12
- provisionedRunners: MintRegistrationTokensProvisionedRunnerDto[],
13
- ): MintEphemeralRegistrationTokensBatchProvisionedRunner[] {
14
- return provisionedRunners.map((provisionedRunner) => ({
15
- provisionedRunnerId: provisionedRunner.provisioned_runner_id,
16
- }));
8
+ export function toMintRegistrationTokensRunnerInstances(
9
+ providerRunners: MintRegistrationTokensRunnerInstanceDto[],
10
+ ) {
11
+ return providerRunners.map((runner) => ({providerRunnerId: runner.provider_runner_id}));
17
12
  }
18
13
 
19
14
  export function toMintRegistrationTokensResponseDto(
20
15
  result: MintEphemeralRegistrationTokensBatchResult[],
21
16
  ): MintRegistrationTokensBatchResponseDto {
22
- return {
23
- tokens: result.map(toMintedRegistrationTokenDto),
24
- };
17
+ return {tokens: result.map(toMintedRegistrationTokenDto)};
25
18
  }
26
19
 
27
20
  function toMintedRegistrationTokenDto(
28
21
  result: MintEphemeralRegistrationTokensBatchResult,
29
22
  ): MintedRegistrationTokenDto {
30
23
  return {
31
- provisioned_runner_id: result.provisionedRunnerId,
24
+ provider_runner_id: result.providerRunnerId,
32
25
  registration_token: result.rawToken,
33
26
  expires_at: result.token.expiresAt.toISOString(),
34
27
  };
@@ -4,6 +4,7 @@ import type {PollDemandResult} from '#core/demand.js';
4
4
  export function toPollDemandResponseDto(result: PollDemandResult): PollDemandResponseDto {
5
5
  return {
6
6
  stats: result.stats.map((stat) => ({
7
+ ...(stat.workspaceId ? {workspace_id: stat.workspaceId} : {}),
7
8
  labels: stat.labels,
8
9
  queued: stat.queued,
9
10
  reserved: stat.reserved,
@@ -11,10 +12,11 @@ export function toPollDemandResponseDto(result: PollDemandResult): PollDemandRes
11
12
  })),
12
13
  reservations: result.reservations.map((reservation) => ({
13
14
  reservation_id: reservation.reservationId,
15
+ ...(reservation.workspaceId ? {workspace_id: reservation.workspaceId} : {}),
14
16
  labels: reservation.labels,
15
17
  count: reservation.count,
16
18
  expires_at: reservation.expiresAt.toISOString(),
17
19
  })),
18
- terminate_provisioned_runner_ids: result.terminateProvisionedRunnerIds,
20
+ terminate_provider_runner_ids: result.terminateRunnerInstanceIds,
19
21
  };
20
22
  }
@@ -3,6 +3,7 @@ import type {ProvisionerToken} from '#core/entities/provisioner-token.js';
3
3
  export function toProvisionerTokenDto(token: ProvisionerToken): {
4
4
  id: string;
5
5
  workspace_id: string;
6
+ scope: 'workspace';
6
7
  prefix: string;
7
8
  name: string | null;
8
9
  created_by_user_id: string;
@@ -13,6 +14,9 @@ export function toProvisionerTokenDto(token: ProvisionerToken): {
13
14
  created_at: string;
14
15
  updated_at: string;
15
16
  } {
17
+ if (token.scope !== 'workspace') {
18
+ throw new Error('Installation provisioner tokens cannot be returned from workspace routes');
19
+ }
16
20
  return {
17
21
  id: token.id,
18
22
  workspace_id: token.workspaceId,
@@ -25,5 +29,6 @@ export function toProvisionerTokenDto(token: ProvisionerToken): {
25
29
  last_seen_at: token.lastSeenAt?.toISOString() ?? null,
26
30
  created_at: token.createdAt.toISOString(),
27
31
  updated_at: token.updatedAt.toISOString(),
32
+ scope: 'workspace',
28
33
  };
29
34
  }
@@ -1,10 +1,10 @@
1
1
  import type {
2
2
  ActiveRunner,
3
- ReconcileProvisionedRunnersResult,
4
- ReportProvisionedRunnersResult,
5
- } from '#core/provisioned-runners.js';
3
+ ReconcileRunnerInstancesResult,
4
+ ReportRunnerInstancesResult,
5
+ } from '#core/runner-instances.js';
6
6
 
7
- export function toReportProvisionedRunnersResponseDto(result: ReportProvisionedRunnersResult): {
7
+ export function toReportRunnerInstancesResponseDto(result: ReportRunnerInstancesResult): {
8
8
  accepted: number;
9
9
  reservations_released: number;
10
10
  } {
@@ -14,12 +14,10 @@ export function toReportProvisionedRunnersResponseDto(result: ReportProvisionedR
14
14
  };
15
15
  }
16
16
 
17
- export function toReconcileProvisionedRunnersResponseDto(
18
- result: ReconcileProvisionedRunnersResult,
19
- ): {
17
+ export function toReconcileRunnerInstancesResponseDto(result: ReconcileRunnerInstancesResult): {
20
18
  runners: Array<{
21
- provisioned_runner_id: string;
22
- state: ReconcileProvisionedRunnersResult['runners'][number]['state'];
19
+ provider_runner_id: string;
20
+ state: ReconcileRunnerInstancesResult['runners'][number]['state'];
23
21
  reservation_id: string | null;
24
22
  runner_session_id: string | null;
25
23
  bound_job: {
@@ -28,13 +26,13 @@ export function toReconcileProvisionedRunnersResponseDto(
28
26
  last_heartbeat_at: string;
29
27
  cancellation_requested_at: string | null;
30
28
  } | null;
31
- desired_intent: ReconcileProvisionedRunnersResult['runners'][number]['desiredIntent'];
29
+ desired_intent: ReconcileRunnerInstancesResult['runners'][number]['desiredIntent'];
32
30
  }>;
33
- terminated_absent_provisioned_runner_ids: string[];
31
+ terminated_absent_provider_runner_ids: string[];
34
32
  } {
35
33
  return {
36
34
  runners: result.runners.map((runner) => ({
37
- provisioned_runner_id: runner.provisionedRunnerId,
35
+ provider_runner_id: runner.providerRunnerId,
38
36
  state: runner.state,
39
37
  reservation_id: runner.reservationId,
40
38
  runner_session_id: runner.runnerSessionId,
@@ -49,14 +47,14 @@ export function toReconcileProvisionedRunnersResponseDto(
49
47
  : null,
50
48
  desired_intent: runner.desiredIntent,
51
49
  })),
52
- terminated_absent_provisioned_runner_ids: result.terminatedAbsentProvisionedRunnerIds,
50
+ terminated_absent_provider_runner_ids: result.terminatedAbsentRunnerInstanceIds,
53
51
  };
54
52
  }
55
53
 
56
54
  export function toActiveRunnersResponseDto(runners: ActiveRunner[]): {
57
55
  runners: Array<{
58
56
  runner_session_id: string | null;
59
- provisioned_runner_id: string | null;
57
+ provider_runner_id: string | null;
60
58
  provisioner_id: string | null;
61
59
  state: ActiveRunner['state'];
62
60
  labels: string[];
@@ -72,7 +70,7 @@ export function toActiveRunnersResponseDto(runners: ActiveRunner[]): {
72
70
  return {
73
71
  runners: runners.map((runner) => ({
74
72
  runner_session_id: runner.runnerSessionId,
75
- provisioned_runner_id: runner.provisionedRunnerId,
73
+ provider_runner_id: runner.providerRunnerId,
76
74
  provisioner_id: runner.provisionerId,
77
75
  state: runner.state,
78
76
  labels: runner.labels,
@@ -1,6 +1,7 @@
1
1
  export {
2
2
  createProvisionerTokenAuthMethod,
3
+ createRunnerControlSessionAuthMethod,
3
4
  createRunnerRegistrationTokenAuthMethod,
4
5
  } from './auth/index.js';
5
- export {runnerRoutes as routes} from './routes/index.js';
6
+ export {createRunnerRoutes, createRunnerRoutes as routes} from './routes/index.js';
6
7
  export {onWorkflowsJobExecutionTimedOut} from './subscribers/on-workflows-job-execution-timed-out.js';
@@ -0,0 +1,15 @@
1
+ import {runnersInterModuleContract} from '@shipfox/api-runners-dto/inter-module';
2
+ import {isInterModuleKnownError} from '@shipfox/inter-module';
3
+ import {EmptyRequiredLabelsError} from '#core/errors.js';
4
+ import {toEnqueueJobExecutionKnownError} from './inter-module.js';
5
+
6
+ describe('Runners inter-module presentation', () => {
7
+ test('maps empty scheduling labels to the published contract error', () => {
8
+ const result = toEnqueueJobExecutionKnownError(new EmptyRequiredLabelsError());
9
+
10
+ expect(
11
+ isInterModuleKnownError(runnersInterModuleContract.methods.enqueueJobExecution, result) &&
12
+ result.code,
13
+ ).toBe('empty-required-labels');
14
+ });
15
+ });
@@ -0,0 +1,53 @@
1
+ import {runnersInterModuleContract} from '@shipfox/api-runners-dto/inter-module';
2
+ import {
3
+ createInterModuleKnownError,
4
+ defineInterModulePresentation,
5
+ type InterModulePresentation,
6
+ } from '@shipfox/inter-module';
7
+ import {EmptyRequiredLabelsError} from '#core/errors.js';
8
+ import {getEffectiveRunnerToolCapabilities} from '#core/runner-tool-capabilities.js';
9
+ import {
10
+ cancelRunnerJobs,
11
+ enqueueJobExecution,
12
+ isJobLeaseActive,
13
+ releaseJobExecution,
14
+ } from '#db/job-executions.js';
15
+
16
+ export function createRunnersInterModulePresentation(): InterModulePresentation<
17
+ typeof runnersInterModuleContract
18
+ > {
19
+ return defineInterModulePresentation(runnersInterModuleContract, {
20
+ enqueueJobExecution: async (input) => {
21
+ try {
22
+ await enqueueJobExecution(input);
23
+ return {};
24
+ } catch (error) {
25
+ throw toEnqueueJobExecutionKnownError(error);
26
+ }
27
+ },
28
+ releaseJobExecution: async (input) => {
29
+ await releaseJobExecution(input);
30
+ return {};
31
+ },
32
+ cancelJobs: async (input) => {
33
+ await cancelRunnerJobs(input);
34
+ return {};
35
+ },
36
+ getLeaseState: async (input) => ({active: await isJobLeaseActive(input)}),
37
+ getEffectiveRunnerToolCapabilities: async (input) => {
38
+ const result = await getEffectiveRunnerToolCapabilities(input);
39
+ return {capabilities: result.capabilities, reportFresh: result.reportFresh};
40
+ },
41
+ });
42
+ }
43
+
44
+ export function toEnqueueJobExecutionKnownError(error: unknown): unknown {
45
+ if (error instanceof EmptyRequiredLabelsError) {
46
+ return createInterModuleKnownError(
47
+ runnersInterModuleContract.methods.enqueueJobExecution,
48
+ 'empty-required-labels',
49
+ {},
50
+ );
51
+ }
52
+ return error;
53
+ }
@@ -0,0 +1,48 @@
1
+ import {requireProvisionerContext} from '@shipfox/api-auth-context';
2
+ import {
3
+ assignCapacityBatchBodySchema,
4
+ assignCapacityBatchResponseSchema,
5
+ } from '@shipfox/api-runners-dto';
6
+ import {ClientError, defineRoute} from '@shipfox/node-fastify';
7
+ import {assignCapacityBatch} from '#core/capacity-assignments.js';
8
+ import {
9
+ CapacityAlreadyAssignedError,
10
+ CapacityNotAssignableError,
11
+ ReservationExpiredError,
12
+ ReservationNotFoundError,
13
+ } from '#core/errors.js';
14
+
15
+ export const assignCapacityRoute = defineRoute({
16
+ method: 'POST',
17
+ path: '/capacity/assignments',
18
+ description: 'Atomically assign provisioner capacity to a live reservation',
19
+ schema: {body: assignCapacityBatchBodySchema, response: {200: assignCapacityBatchResponseSchema}},
20
+ errorHandler: (error) => {
21
+ if (error instanceof ReservationNotFoundError)
22
+ throw new ClientError('Reservation not found', 'reservation-not-found', {status: 404});
23
+ if (error instanceof ReservationExpiredError)
24
+ throw new ClientError('Reservation has expired', 'reservation-expired', {status: 409});
25
+ if (
26
+ error instanceof CapacityAlreadyAssignedError ||
27
+ error instanceof CapacityNotAssignableError
28
+ )
29
+ throw new ClientError('Capacity cannot be assigned', 'capacity-not-assignable', {
30
+ status: 409,
31
+ });
32
+ throw error;
33
+ },
34
+ handler: async (request) => {
35
+ const {provisionerTokenId} = requireProvisionerContext(request);
36
+ const assignments = await assignCapacityBatch({
37
+ provisionerId: provisionerTokenId,
38
+ reservationId: request.body.reservation_id,
39
+ capacityIds: request.body.capacity_ids,
40
+ });
41
+ return {
42
+ assignments: assignments.map((assignment) => ({
43
+ capacity_id: assignment.capacityId,
44
+ assignment_id: assignment.id,
45
+ })),
46
+ };
47
+ },
48
+ });