@shipfox/api-runners 12.3.0 → 12.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/CHANGELOG.md +36 -0
  3. package/dist/config.d.ts +1 -0
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +9 -2
  6. package/dist/config.js.map +1 -1
  7. package/dist/core/demand.d.ts +4 -2
  8. package/dist/core/demand.d.ts.map +1 -1
  9. package/dist/core/demand.js +22 -6
  10. package/dist/core/demand.js.map +1 -1
  11. package/dist/core/entities/reservation.d.ts +1 -0
  12. package/dist/core/entities/reservation.d.ts.map +1 -1
  13. package/dist/core/entities/reservation.js.map +1 -1
  14. package/dist/core/entities/runner-instance.d.ts +3 -0
  15. package/dist/core/entities/runner-instance.d.ts.map +1 -1
  16. package/dist/core/entities/runner-instance.js.map +1 -1
  17. package/dist/core/errors.d.ts +5 -1
  18. package/dist/core/errors.d.ts.map +1 -1
  19. package/dist/core/errors.js +9 -2
  20. package/dist/core/errors.js.map +1 -1
  21. package/dist/core/runner-activation.d.ts +4 -1
  22. package/dist/core/runner-activation.d.ts.map +1 -1
  23. package/dist/core/runner-activation.js +32 -3
  24. package/dist/core/runner-activation.js.map +1 -1
  25. package/dist/core/runner-control-sessions.d.ts +8 -4
  26. package/dist/core/runner-control-sessions.d.ts.map +1 -1
  27. package/dist/core/runner-control-sessions.js +116 -20
  28. package/dist/core/runner-control-sessions.js.map +1 -1
  29. package/dist/core/runner-instances.d.ts +1 -0
  30. package/dist/core/runner-instances.d.ts.map +1 -1
  31. package/dist/core/runner-instances.js +1 -0
  32. package/dist/core/runner-instances.js.map +1 -1
  33. package/dist/db/db.d.ts +68 -0
  34. package/dist/db/db.d.ts.map +1 -1
  35. package/dist/db/ephemeral-registration-tokens.d.ts.map +1 -1
  36. package/dist/db/ephemeral-registration-tokens.js +1 -1
  37. package/dist/db/ephemeral-registration-tokens.js.map +1 -1
  38. package/dist/db/job-executions.d.ts.map +1 -1
  39. package/dist/db/job-executions.js +35 -4
  40. package/dist/db/job-executions.js.map +1 -1
  41. package/dist/db/reservation-locks.d.ts +6 -0
  42. package/dist/db/reservation-locks.d.ts.map +1 -0
  43. package/dist/db/reservation-locks.js +15 -0
  44. package/dist/db/reservation-locks.js.map +1 -0
  45. package/dist/db/reservations.d.ts +17 -3
  46. package/dist/db/reservations.d.ts.map +1 -1
  47. package/dist/db/reservations.js +246 -51
  48. package/dist/db/reservations.js.map +1 -1
  49. package/dist/db/runner-assignments.d.ts +25 -1
  50. package/dist/db/runner-assignments.d.ts.map +1 -1
  51. package/dist/db/runner-assignments.js +160 -18
  52. package/dist/db/runner-assignments.js.map +1 -1
  53. package/dist/db/runner-instances.d.ts +11 -2
  54. package/dist/db/runner-instances.d.ts.map +1 -1
  55. package/dist/db/runner-instances.js +167 -24
  56. package/dist/db/runner-instances.js.map +1 -1
  57. package/dist/db/runner-sessions.d.ts.map +1 -1
  58. package/dist/db/runner-sessions.js +14 -1
  59. package/dist/db/runner-sessions.js.map +1 -1
  60. package/dist/db/runner-states.d.ts +2 -0
  61. package/dist/db/runner-states.d.ts.map +1 -0
  62. package/dist/db/runner-states.js +7 -0
  63. package/dist/db/runner-states.js.map +1 -0
  64. package/dist/db/schema/reservations.d.ts +18 -0
  65. package/dist/db/schema/reservations.d.ts.map +1 -1
  66. package/dist/db/schema/reservations.js +7 -1
  67. package/dist/db/schema/reservations.js.map +1 -1
  68. package/dist/db/schema/runner-instances.d.ts +18 -0
  69. package/dist/db/schema/runner-instances.d.ts.map +1 -1
  70. package/dist/db/schema/runner-instances.js +8 -0
  71. package/dist/db/schema/runner-instances.js.map +1 -1
  72. package/dist/metrics/index.d.ts +2 -2
  73. package/dist/metrics/index.d.ts.map +1 -1
  74. package/dist/metrics/index.js +1 -1
  75. package/dist/metrics/index.js.map +1 -1
  76. package/dist/metrics/instance.d.ts +72 -2
  77. package/dist/metrics/instance.d.ts.map +1 -1
  78. package/dist/metrics/instance.js +161 -1
  79. package/dist/metrics/instance.js.map +1 -1
  80. package/dist/metrics/service.d.ts.map +1 -1
  81. package/dist/metrics/service.js +25 -4
  82. package/dist/metrics/service.js.map +1 -1
  83. package/dist/presentation/dto/poll-demand.d.ts.map +1 -1
  84. package/dist/presentation/dto/poll-demand.js +3 -0
  85. package/dist/presentation/dto/poll-demand.js.map +1 -1
  86. package/dist/presentation/dto/runner-instances.d.ts +4 -1
  87. package/dist/presentation/dto/runner-instances.d.ts.map +1 -1
  88. package/dist/presentation/dto/runner-instances.js +4 -1
  89. package/dist/presentation/dto/runner-instances.js.map +1 -1
  90. package/dist/presentation/routes/assign-runner-instances.d.ts.map +1 -1
  91. package/dist/presentation/routes/assign-runner-instances.js +10 -4
  92. package/dist/presentation/routes/assign-runner-instances.js.map +1 -1
  93. package/dist/presentation/routes/poll-demand.d.ts.map +1 -1
  94. package/dist/presentation/routes/poll-demand.js +1 -0
  95. package/dist/presentation/routes/poll-demand.js.map +1 -1
  96. package/dist/presentation/routes/reconcile-runner-instances.d.ts.map +1 -1
  97. package/dist/presentation/routes/reconcile-runner-instances.js +4 -2
  98. package/dist/presentation/routes/reconcile-runner-instances.js.map +1 -1
  99. package/dist/presentation/routes/runner-enrollment.d.ts +4 -1
  100. package/dist/presentation/routes/runner-enrollment.d.ts.map +1 -1
  101. package/dist/presentation/routes/runner-enrollment.js +11 -6
  102. package/dist/presentation/routes/runner-enrollment.js.map +1 -1
  103. package/dist/tsconfig.test.tsbuildinfo +1 -1
  104. package/drizzle/0005_previous_lenny_balinger.sql +5 -0
  105. package/drizzle/meta/0005_snapshot.json +2220 -0
  106. package/drizzle/meta/_journal.json +7 -0
  107. package/package.json +6 -6
  108. package/src/config.test.ts +22 -0
  109. package/src/config.ts +15 -2
  110. package/src/core/demand.test.ts +192 -3
  111. package/src/core/demand.ts +44 -4
  112. package/src/core/entities/reservation.ts +1 -0
  113. package/src/core/entities/runner-instance.ts +4 -0
  114. package/src/core/errors.ts +30 -1
  115. package/src/core/runner-activation.ts +48 -2
  116. package/src/core/runner-control-sessions.test.ts +135 -3
  117. package/src/core/runner-control-sessions.ts +141 -19
  118. package/src/core/runner-instances.test.ts +19 -0
  119. package/src/core/runner-instances.ts +2 -0
  120. package/src/core/runner-sessions.test.ts +121 -1
  121. package/src/db/ephemeral-registration-tokens.test.ts +20 -1
  122. package/src/db/ephemeral-registration-tokens.ts +1 -0
  123. package/src/db/job-executions.test.ts +98 -12
  124. package/src/db/job-executions.ts +52 -4
  125. package/src/db/reservation-locks.ts +22 -0
  126. package/src/db/reservations.test.ts +733 -22
  127. package/src/db/reservations.ts +408 -144
  128. package/src/db/runner-assignments.test.ts +105 -1
  129. package/src/db/runner-assignments.ts +245 -25
  130. package/src/db/runner-instances.test.ts +357 -2
  131. package/src/db/runner-instances.ts +289 -55
  132. package/src/db/runner-sessions.ts +19 -1
  133. package/src/db/runner-states.ts +7 -0
  134. package/src/db/schema/reservations.ts +5 -1
  135. package/src/db/schema/runner-instances.ts +9 -0
  136. package/src/metrics/index.ts +24 -1
  137. package/src/metrics/instance.test.ts +118 -0
  138. package/src/metrics/instance.ts +247 -3
  139. package/src/metrics/service.test.ts +46 -1
  140. package/src/metrics/service.ts +55 -8
  141. package/src/presentation/dto/poll-demand.ts +3 -0
  142. package/src/presentation/dto/runner-instances.ts +8 -1
  143. package/src/presentation/routes/assign-runner-instances.ts +14 -2
  144. package/src/presentation/routes/late-runner-enrollment.test.ts +219 -2
  145. package/src/presentation/routes/poll-demand.test.ts +56 -0
  146. package/src/presentation/routes/poll-demand.ts +1 -0
  147. package/src/presentation/routes/reconcile-runner-instances.test.ts +34 -2
  148. package/src/presentation/routes/reconcile-runner-instances.ts +7 -1
  149. package/src/presentation/routes/runner-enrollment.test.ts +316 -3
  150. package/src/presentation/routes/runner-enrollment.ts +8 -5
  151. package/test/factories/reservation.ts +2 -0
  152. package/test/factories/runner-instance.ts +6 -0
  153. package/tsconfig.build.tsbuildinfo +1 -1
@@ -18,6 +18,9 @@ export function toPollDemandResponseDto(result) {
18
18
  count: reservation.count,
19
19
  expires_at: reservation.expiresAt.toISOString()
20
20
  })),
21
+ ...result.newlyReservedCount !== undefined ? {
22
+ newly_reserved_count: result.newlyReservedCount
23
+ } : {},
21
24
  terminate_provider_runner_ids: result.terminateRunnerInstanceIds
22
25
  };
23
26
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/dto/poll-demand.ts"],"sourcesContent":["import type {PollDemandResponseDto} from '@shipfox/api-runners-dto';\nimport type {PollDemandResult} from '#core/demand.js';\n\nexport function toPollDemandResponseDto(result: PollDemandResult): PollDemandResponseDto {\n return {\n stats: result.stats.map((stat) => ({\n ...(stat.workspaceId ? {workspace_id: stat.workspaceId} : {}),\n labels: stat.labels,\n queued: stat.queued,\n reserved: stat.reserved,\n oldest_queued_at: stat.oldestQueuedAt.toISOString(),\n })),\n reservations: result.reservations.map((reservation) => ({\n reservation_id: reservation.reservationId,\n ...(reservation.workspaceId ? {workspace_id: reservation.workspaceId} : {}),\n labels: reservation.labels,\n count: reservation.count,\n expires_at: reservation.expiresAt.toISOString(),\n })),\n terminate_provider_runner_ids: result.terminateRunnerInstanceIds,\n };\n}\n"],"names":["toPollDemandResponseDto","result","stats","map","stat","workspaceId","workspace_id","labels","queued","reserved","oldest_queued_at","oldestQueuedAt","toISOString","reservations","reservation","reservation_id","reservationId","count","expires_at","expiresAt","terminate_provider_runner_ids","terminateRunnerInstanceIds"],"mappings":"AAGA,OAAO,SAASA,wBAAwBC,MAAwB;IAC9D,OAAO;QACLC,OAAOD,OAAOC,KAAK,CAACC,GAAG,CAAC,CAACC,OAAU,CAAA;gBACjC,GAAIA,KAAKC,WAAW,GAAG;oBAACC,cAAcF,KAAKC,WAAW;gBAAA,IAAI,CAAC,CAAC;gBAC5DE,QAAQH,KAAKG,MAAM;gBACnBC,QAAQJ,KAAKI,MAAM;gBACnBC,UAAUL,KAAKK,QAAQ;gBACvBC,kBAAkBN,KAAKO,cAAc,CAACC,WAAW;YACnD,CAAA;QACAC,cAAcZ,OAAOY,YAAY,CAACV,GAAG,CAAC,CAACW,cAAiB,CAAA;gBACtDC,gBAAgBD,YAAYE,aAAa;gBACzC,GAAIF,YAAYT,WAAW,GAAG;oBAACC,cAAcQ,YAAYT,WAAW;gBAAA,IAAI,CAAC,CAAC;gBAC1EE,QAAQO,YAAYP,MAAM;gBAC1BU,OAAOH,YAAYG,KAAK;gBACxBC,YAAYJ,YAAYK,SAAS,CAACP,WAAW;YAC/C,CAAA;QACAQ,+BAA+BnB,OAAOoB,0BAA0B;IAClE;AACF"}
1
+ {"version":3,"sources":["../../../src/presentation/dto/poll-demand.ts"],"sourcesContent":["import type {PollDemandResponseDto} from '@shipfox/api-runners-dto';\nimport type {PollDemandResult} from '#core/demand.js';\n\nexport function toPollDemandResponseDto(result: PollDemandResult): PollDemandResponseDto {\n return {\n stats: result.stats.map((stat) => ({\n ...(stat.workspaceId ? {workspace_id: stat.workspaceId} : {}),\n labels: stat.labels,\n queued: stat.queued,\n reserved: stat.reserved,\n oldest_queued_at: stat.oldestQueuedAt.toISOString(),\n })),\n reservations: result.reservations.map((reservation) => ({\n reservation_id: reservation.reservationId,\n ...(reservation.workspaceId ? {workspace_id: reservation.workspaceId} : {}),\n labels: reservation.labels,\n count: reservation.count,\n expires_at: reservation.expiresAt.toISOString(),\n })),\n ...(result.newlyReservedCount !== undefined\n ? {newly_reserved_count: result.newlyReservedCount}\n : {}),\n terminate_provider_runner_ids: result.terminateRunnerInstanceIds,\n };\n}\n"],"names":["toPollDemandResponseDto","result","stats","map","stat","workspaceId","workspace_id","labels","queued","reserved","oldest_queued_at","oldestQueuedAt","toISOString","reservations","reservation","reservation_id","reservationId","count","expires_at","expiresAt","newlyReservedCount","undefined","newly_reserved_count","terminate_provider_runner_ids","terminateRunnerInstanceIds"],"mappings":"AAGA,OAAO,SAASA,wBAAwBC,MAAwB;IAC9D,OAAO;QACLC,OAAOD,OAAOC,KAAK,CAACC,GAAG,CAAC,CAACC,OAAU,CAAA;gBACjC,GAAIA,KAAKC,WAAW,GAAG;oBAACC,cAAcF,KAAKC,WAAW;gBAAA,IAAI,CAAC,CAAC;gBAC5DE,QAAQH,KAAKG,MAAM;gBACnBC,QAAQJ,KAAKI,MAAM;gBACnBC,UAAUL,KAAKK,QAAQ;gBACvBC,kBAAkBN,KAAKO,cAAc,CAACC,WAAW;YACnD,CAAA;QACAC,cAAcZ,OAAOY,YAAY,CAACV,GAAG,CAAC,CAACW,cAAiB,CAAA;gBACtDC,gBAAgBD,YAAYE,aAAa;gBACzC,GAAIF,YAAYT,WAAW,GAAG;oBAACC,cAAcQ,YAAYT,WAAW;gBAAA,IAAI,CAAC,CAAC;gBAC1EE,QAAQO,YAAYP,MAAM;gBAC1BU,OAAOH,YAAYG,KAAK;gBACxBC,YAAYJ,YAAYK,SAAS,CAACP,WAAW;YAC/C,CAAA;QACA,GAAIX,OAAOmB,kBAAkB,KAAKC,YAC9B;YAACC,sBAAsBrB,OAAOmB,kBAAkB;QAAA,IAChD,CAAC,CAAC;QACNG,+BAA+BtB,OAAOuB,0BAA0B;IAClE;AACF"}
@@ -3,10 +3,13 @@ export declare function toReportRunnerInstancesResponseDto(result: ReportRunnerI
3
3
  accepted: number;
4
4
  reservations_released: number;
5
5
  };
6
- export declare function toReconcileRunnerInstancesResponseDto(result: ReconcileRunnerInstancesResult): {
6
+ export declare function toReconcileRunnerInstancesResponseDto(result: ReconcileRunnerInstancesResult, options: {
7
+ includeIntendedReservationId: boolean;
8
+ }): {
7
9
  runners: Array<{
8
10
  provider_runner_id: string;
9
11
  state: ReconcileRunnerInstancesResult['runners'][number]['state'];
12
+ intended_reservation_id?: string | null;
10
13
  reservation_id: string | null;
11
14
  runner_session_id: string | null;
12
15
  bound_job: {
@@ -1 +1 @@
1
- {"version":3,"file":"runner-instances.d.ts","sourceRoot":"","sources":["../../../src/presentation/dto/runner-instances.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,8BAA8B,EAC9B,2BAA2B,EAC5B,MAAM,2BAA2B,CAAC;AAEnC,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,2BAA2B,GAAG;IACvF,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,EAAE,MAAM,CAAC;CAC/B,CAKA;AAED,wBAAgB,qCAAqC,CAAC,MAAM,EAAE,8BAA8B,GAAG;IAC7F,OAAO,EAAE,KAAK,CAAC;QACb,kBAAkB,EAAE,MAAM,CAAC;QAC3B,KAAK,EAAE,8BAA8B,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC;QAClE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,SAAS,EAAE;YACT,MAAM,EAAE,MAAM,CAAC;YACf,uBAAuB,EAAE,MAAM,CAAC;YAChC,iBAAiB,EAAE,MAAM,CAAC;YAC1B,yBAAyB,EAAE,MAAM,GAAG,IAAI,CAAC;SAC1C,GAAG,IAAI,CAAC;QACT,cAAc,EAAE,8BAA8B,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC;KACpF,CAAC,CAAC;IACH,qCAAqC,EAAE,MAAM,EAAE,CAAC;CACjD,CAoBA;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG;IACnE,OAAO,EAAE,KAAK,CAAC;QACb,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;QAClC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;QAC7B,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;QACvC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CAAC,CAAC;CACJ,CAiBA"}
1
+ {"version":3,"file":"runner-instances.d.ts","sourceRoot":"","sources":["../../../src/presentation/dto/runner-instances.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,8BAA8B,EAC9B,2BAA2B,EAC5B,MAAM,2BAA2B,CAAC;AAEnC,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,2BAA2B,GAAG;IACvF,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,EAAE,MAAM,CAAC;CAC/B,CAKA;AAED,wBAAgB,qCAAqC,CACnD,MAAM,EAAE,8BAA8B,EACtC,OAAO,EAAE;IAAC,4BAA4B,EAAE,OAAO,CAAA;CAAC,GAC/C;IACD,OAAO,EAAE,KAAK,CAAC;QACb,kBAAkB,EAAE,MAAM,CAAC;QAC3B,KAAK,EAAE,8BAA8B,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC;QAClE,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACxC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,SAAS,EAAE;YACT,MAAM,EAAE,MAAM,CAAC;YACf,uBAAuB,EAAE,MAAM,CAAC;YAChC,iBAAiB,EAAE,MAAM,CAAC;YAC1B,yBAAyB,EAAE,MAAM,GAAG,IAAI,CAAC;SAC1C,GAAG,IAAI,CAAC;QACT,cAAc,EAAE,8BAA8B,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC;KACpF,CAAC,CAAC;IACH,qCAAqC,EAAE,MAAM,EAAE,CAAC;CACjD,CAuBA;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG;IACnE,OAAO,EAAE,KAAK,CAAC;QACb,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;QAClC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;QAC7B,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;QACvC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CAAC,CAAC;CACJ,CAiBA"}
@@ -4,11 +4,14 @@ export function toReportRunnerInstancesResponseDto(result) {
4
4
  reservations_released: result.reservationsReleased
5
5
  };
6
6
  }
7
- export function toReconcileRunnerInstancesResponseDto(result) {
7
+ export function toReconcileRunnerInstancesResponseDto(result, options) {
8
8
  return {
9
9
  runners: result.runners.map((runner)=>({
10
10
  provider_runner_id: runner.providerRunnerId,
11
11
  state: runner.state,
12
+ ...options.includeIntendedReservationId ? {
13
+ intended_reservation_id: runner.intendedReservationId
14
+ } : {},
12
15
  reservation_id: runner.reservationId,
13
16
  runner_session_id: runner.runnerSessionId,
14
17
  bound_job: runner.boundJobExecution ? {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/dto/runner-instances.ts"],"sourcesContent":["import type {\n ActiveRunner,\n ReconcileRunnerInstancesResult,\n ReportRunnerInstancesResult,\n} from '#core/runner-instances.js';\n\nexport function toReportRunnerInstancesResponseDto(result: ReportRunnerInstancesResult): {\n accepted: number;\n reservations_released: number;\n} {\n return {\n accepted: result.accepted,\n reservations_released: result.reservationsReleased,\n };\n}\n\nexport function toReconcileRunnerInstancesResponseDto(result: ReconcileRunnerInstancesResult): {\n runners: Array<{\n provider_runner_id: string;\n state: ReconcileRunnerInstancesResult['runners'][number]['state'];\n reservation_id: string | null;\n runner_session_id: string | null;\n bound_job: {\n job_id: string;\n workflow_run_attempt_id: string;\n last_heartbeat_at: string;\n cancellation_requested_at: string | null;\n } | null;\n desired_intent: ReconcileRunnerInstancesResult['runners'][number]['desiredIntent'];\n }>;\n terminated_absent_provider_runner_ids: string[];\n} {\n return {\n runners: result.runners.map((runner) => ({\n provider_runner_id: runner.providerRunnerId,\n state: runner.state,\n reservation_id: runner.reservationId,\n runner_session_id: runner.runnerSessionId,\n bound_job: runner.boundJobExecution\n ? {\n job_id: runner.boundJobExecution.jobId,\n workflow_run_attempt_id: runner.boundJobExecution.workflowRunAttemptId,\n last_heartbeat_at: runner.boundJobExecution.lastHeartbeatAt.toISOString(),\n cancellation_requested_at:\n runner.boundJobExecution.cancellationRequestedAt?.toISOString() ?? null,\n }\n : null,\n desired_intent: runner.desiredIntent,\n })),\n terminated_absent_provider_runner_ids: result.terminatedAbsentRunnerInstanceIds,\n };\n}\n\nexport function toActiveRunnersResponseDto(runners: ActiveRunner[]): {\n runners: Array<{\n runner_session_id: string | null;\n provider_runner_id: string | null;\n provisioner_id: string | null;\n state: ActiveRunner['state'];\n labels: string[];\n template_key: string | null;\n provider_kind: string | null;\n job_id: string | null;\n workflow_run_attempt_id: string | null;\n project_id: string | null;\n reported_at: string | null;\n last_heartbeat_at: string | null;\n }>;\n} {\n return {\n runners: runners.map((runner) => ({\n runner_session_id: runner.runnerSessionId,\n provider_runner_id: runner.providerRunnerId,\n provisioner_id: runner.provisionerId,\n state: runner.state,\n labels: runner.labels,\n template_key: runner.templateKey,\n provider_kind: runner.providerKind,\n job_id: runner.jobId,\n workflow_run_attempt_id: runner.workflowRunAttemptId,\n project_id: runner.projectId,\n reported_at: runner.reportedAt?.toISOString() ?? null,\n last_heartbeat_at: runner.lastHeartbeatAt?.toISOString() ?? null,\n })),\n };\n}\n"],"names":["toReportRunnerInstancesResponseDto","result","accepted","reservations_released","reservationsReleased","toReconcileRunnerInstancesResponseDto","runners","map","runner","provider_runner_id","providerRunnerId","state","reservation_id","reservationId","runner_session_id","runnerSessionId","bound_job","boundJobExecution","job_id","jobId","workflow_run_attempt_id","workflowRunAttemptId","last_heartbeat_at","lastHeartbeatAt","toISOString","cancellation_requested_at","cancellationRequestedAt","desired_intent","desiredIntent","terminated_absent_provider_runner_ids","terminatedAbsentRunnerInstanceIds","toActiveRunnersResponseDto","provisioner_id","provisionerId","labels","template_key","templateKey","provider_kind","providerKind","project_id","projectId","reported_at","reportedAt"],"mappings":"AAMA,OAAO,SAASA,mCAAmCC,MAAmC;IAIpF,OAAO;QACLC,UAAUD,OAAOC,QAAQ;QACzBC,uBAAuBF,OAAOG,oBAAoB;IACpD;AACF;AAEA,OAAO,SAASC,sCAAsCJ,MAAsC;IAgB1F,OAAO;QACLK,SAASL,OAAOK,OAAO,CAACC,GAAG,CAAC,CAACC,SAAY,CAAA;gBACvCC,oBAAoBD,OAAOE,gBAAgB;gBAC3CC,OAAOH,OAAOG,KAAK;gBACnBC,gBAAgBJ,OAAOK,aAAa;gBACpCC,mBAAmBN,OAAOO,eAAe;gBACzCC,WAAWR,OAAOS,iBAAiB,GAC/B;oBACEC,QAAQV,OAAOS,iBAAiB,CAACE,KAAK;oBACtCC,yBAAyBZ,OAAOS,iBAAiB,CAACI,oBAAoB;oBACtEC,mBAAmBd,OAAOS,iBAAiB,CAACM,eAAe,CAACC,WAAW;oBACvEC,2BACEjB,OAAOS,iBAAiB,CAACS,uBAAuB,EAAEF,iBAAiB;gBACvE,IACA;gBACJG,gBAAgBnB,OAAOoB,aAAa;YACtC,CAAA;QACAC,uCAAuC5B,OAAO6B,iCAAiC;IACjF;AACF;AAEA,OAAO,SAASC,2BAA2BzB,OAAuB;IAgBhE,OAAO;QACLA,SAASA,QAAQC,GAAG,CAAC,CAACC,SAAY,CAAA;gBAChCM,mBAAmBN,OAAOO,eAAe;gBACzCN,oBAAoBD,OAAOE,gBAAgB;gBAC3CsB,gBAAgBxB,OAAOyB,aAAa;gBACpCtB,OAAOH,OAAOG,KAAK;gBACnBuB,QAAQ1B,OAAO0B,MAAM;gBACrBC,cAAc3B,OAAO4B,WAAW;gBAChCC,eAAe7B,OAAO8B,YAAY;gBAClCpB,QAAQV,OAAOW,KAAK;gBACpBC,yBAAyBZ,OAAOa,oBAAoB;gBACpDkB,YAAY/B,OAAOgC,SAAS;gBAC5BC,aAAajC,OAAOkC,UAAU,EAAElB,iBAAiB;gBACjDF,mBAAmBd,OAAOe,eAAe,EAAEC,iBAAiB;YAC9D,CAAA;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/presentation/dto/runner-instances.ts"],"sourcesContent":["import type {\n ActiveRunner,\n ReconcileRunnerInstancesResult,\n ReportRunnerInstancesResult,\n} from '#core/runner-instances.js';\n\nexport function toReportRunnerInstancesResponseDto(result: ReportRunnerInstancesResult): {\n accepted: number;\n reservations_released: number;\n} {\n return {\n accepted: result.accepted,\n reservations_released: result.reservationsReleased,\n };\n}\n\nexport function toReconcileRunnerInstancesResponseDto(\n result: ReconcileRunnerInstancesResult,\n options: {includeIntendedReservationId: boolean},\n): {\n runners: Array<{\n provider_runner_id: string;\n state: ReconcileRunnerInstancesResult['runners'][number]['state'];\n intended_reservation_id?: string | null;\n reservation_id: string | null;\n runner_session_id: string | null;\n bound_job: {\n job_id: string;\n workflow_run_attempt_id: string;\n last_heartbeat_at: string;\n cancellation_requested_at: string | null;\n } | null;\n desired_intent: ReconcileRunnerInstancesResult['runners'][number]['desiredIntent'];\n }>;\n terminated_absent_provider_runner_ids: string[];\n} {\n return {\n runners: result.runners.map((runner) => ({\n provider_runner_id: runner.providerRunnerId,\n state: runner.state,\n ...(options.includeIntendedReservationId\n ? {intended_reservation_id: runner.intendedReservationId}\n : {}),\n reservation_id: runner.reservationId,\n runner_session_id: runner.runnerSessionId,\n bound_job: runner.boundJobExecution\n ? {\n job_id: runner.boundJobExecution.jobId,\n workflow_run_attempt_id: runner.boundJobExecution.workflowRunAttemptId,\n last_heartbeat_at: runner.boundJobExecution.lastHeartbeatAt.toISOString(),\n cancellation_requested_at:\n runner.boundJobExecution.cancellationRequestedAt?.toISOString() ?? null,\n }\n : null,\n desired_intent: runner.desiredIntent,\n })),\n terminated_absent_provider_runner_ids: result.terminatedAbsentRunnerInstanceIds,\n };\n}\n\nexport function toActiveRunnersResponseDto(runners: ActiveRunner[]): {\n runners: Array<{\n runner_session_id: string | null;\n provider_runner_id: string | null;\n provisioner_id: string | null;\n state: ActiveRunner['state'];\n labels: string[];\n template_key: string | null;\n provider_kind: string | null;\n job_id: string | null;\n workflow_run_attempt_id: string | null;\n project_id: string | null;\n reported_at: string | null;\n last_heartbeat_at: string | null;\n }>;\n} {\n return {\n runners: runners.map((runner) => ({\n runner_session_id: runner.runnerSessionId,\n provider_runner_id: runner.providerRunnerId,\n provisioner_id: runner.provisionerId,\n state: runner.state,\n labels: runner.labels,\n template_key: runner.templateKey,\n provider_kind: runner.providerKind,\n job_id: runner.jobId,\n workflow_run_attempt_id: runner.workflowRunAttemptId,\n project_id: runner.projectId,\n reported_at: runner.reportedAt?.toISOString() ?? null,\n last_heartbeat_at: runner.lastHeartbeatAt?.toISOString() ?? null,\n })),\n };\n}\n"],"names":["toReportRunnerInstancesResponseDto","result","accepted","reservations_released","reservationsReleased","toReconcileRunnerInstancesResponseDto","options","runners","map","runner","provider_runner_id","providerRunnerId","state","includeIntendedReservationId","intended_reservation_id","intendedReservationId","reservation_id","reservationId","runner_session_id","runnerSessionId","bound_job","boundJobExecution","job_id","jobId","workflow_run_attempt_id","workflowRunAttemptId","last_heartbeat_at","lastHeartbeatAt","toISOString","cancellation_requested_at","cancellationRequestedAt","desired_intent","desiredIntent","terminated_absent_provider_runner_ids","terminatedAbsentRunnerInstanceIds","toActiveRunnersResponseDto","provisioner_id","provisionerId","labels","template_key","templateKey","provider_kind","providerKind","project_id","projectId","reported_at","reportedAt"],"mappings":"AAMA,OAAO,SAASA,mCAAmCC,MAAmC;IAIpF,OAAO;QACLC,UAAUD,OAAOC,QAAQ;QACzBC,uBAAuBF,OAAOG,oBAAoB;IACpD;AACF;AAEA,OAAO,SAASC,sCACdJ,MAAsC,EACtCK,OAAgD;IAkBhD,OAAO;QACLC,SAASN,OAAOM,OAAO,CAACC,GAAG,CAAC,CAACC,SAAY,CAAA;gBACvCC,oBAAoBD,OAAOE,gBAAgB;gBAC3CC,OAAOH,OAAOG,KAAK;gBACnB,GAAIN,QAAQO,4BAA4B,GACpC;oBAACC,yBAAyBL,OAAOM,qBAAqB;gBAAA,IACtD,CAAC,CAAC;gBACNC,gBAAgBP,OAAOQ,aAAa;gBACpCC,mBAAmBT,OAAOU,eAAe;gBACzCC,WAAWX,OAAOY,iBAAiB,GAC/B;oBACEC,QAAQb,OAAOY,iBAAiB,CAACE,KAAK;oBACtCC,yBAAyBf,OAAOY,iBAAiB,CAACI,oBAAoB;oBACtEC,mBAAmBjB,OAAOY,iBAAiB,CAACM,eAAe,CAACC,WAAW;oBACvEC,2BACEpB,OAAOY,iBAAiB,CAACS,uBAAuB,EAAEF,iBAAiB;gBACvE,IACA;gBACJG,gBAAgBtB,OAAOuB,aAAa;YACtC,CAAA;QACAC,uCAAuChC,OAAOiC,iCAAiC;IACjF;AACF;AAEA,OAAO,SAASC,2BAA2B5B,OAAuB;IAgBhE,OAAO;QACLA,SAASA,QAAQC,GAAG,CAAC,CAACC,SAAY,CAAA;gBAChCS,mBAAmBT,OAAOU,eAAe;gBACzCT,oBAAoBD,OAAOE,gBAAgB;gBAC3CyB,gBAAgB3B,OAAO4B,aAAa;gBACpCzB,OAAOH,OAAOG,KAAK;gBACnB0B,QAAQ7B,OAAO6B,MAAM;gBACrBC,cAAc9B,OAAO+B,WAAW;gBAChCC,eAAehC,OAAOiC,YAAY;gBAClCpB,QAAQb,OAAOc,KAAK;gBACpBC,yBAAyBf,OAAOgB,oBAAoB;gBACpDkB,YAAYlC,OAAOmC,SAAS;gBAC5BC,aAAapC,OAAOqC,UAAU,EAAElB,iBAAiB;gBACjDF,mBAAmBjB,OAAOkB,eAAe,EAAEC,iBAAiB;YAC9D,CAAA;IACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"assign-runner-instances.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/assign-runner-instances.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,0BAA0B,iDAkCrC,CAAC"}
1
+ {"version":3,"file":"assign-runner-instances.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/assign-runner-instances.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,0BAA0B,iDA0CrC,CAAC"}
@@ -1,8 +1,9 @@
1
1
  import { requireProvisionerContext } from '@shipfox/api-auth-context';
2
- import { assignRunnerInstancesBodySchema, assignRunnerInstancesResponseSchema } from '@shipfox/api-runners-dto';
2
+ import { assignRunnerInstancesBodySchema, assignRunnerInstancesResponseSchema, RESERVATION_EXPIRED_ERROR_CODE, RUNNER_INSTANCE_NOT_ASSIGNABLE_ERROR_CODE } from '@shipfox/api-runners-dto';
3
3
  import { ClientError, defineRoute } from '@shipfox/node-fastify';
4
- import { ReservationExpiredError, ReservationNotFoundError, RunnerInstanceAlreadyAssignedError, RunnerInstanceNotAssignableError } from '#core/errors.js';
4
+ import { getRunnerAssignmentRejectionReason, ReservationExpiredError, ReservationNotFoundError, RunnerInstanceAlreadyAssignedError, RunnerInstanceNotAssignableError } from '#core/errors.js';
5
5
  import { assignRunnerInstances } from '#core/runner-assignments.js';
6
+ import { recordProviderRunnerAssignmentRejected } from '#metrics/instance.js';
6
7
  export const assignRunnerInstancesRoute = defineRoute({
7
8
  method: 'POST',
8
9
  path: '/runner-instances/assignments',
@@ -14,13 +15,18 @@ export const assignRunnerInstancesRoute = defineRoute({
14
15
  }
15
16
  },
16
17
  errorHandler: (error)=>{
18
+ const rejectionReason = getRunnerAssignmentRejectionReason(error);
19
+ if (rejectionReason) recordProviderRunnerAssignmentRejected({
20
+ reason: rejectionReason,
21
+ surface: 'provisioner'
22
+ });
17
23
  if (error instanceof ReservationNotFoundError) throw new ClientError('Reservation not found', 'reservation-not-found', {
18
24
  status: 404
19
25
  });
20
- if (error instanceof ReservationExpiredError) throw new ClientError('Reservation has expired', 'reservation-expired', {
26
+ if (error instanceof ReservationExpiredError) throw new ClientError('Reservation has expired', RESERVATION_EXPIRED_ERROR_CODE, {
21
27
  status: 409
22
28
  });
23
- if (error instanceof RunnerInstanceAlreadyAssignedError || error instanceof RunnerInstanceNotAssignableError) throw new ClientError('Runner instance cannot be assigned', 'runner-instance-not-assignable', {
29
+ if (error instanceof RunnerInstanceAlreadyAssignedError || error instanceof RunnerInstanceNotAssignableError) throw new ClientError('Runner instance cannot be assigned', RUNNER_INSTANCE_NOT_ASSIGNABLE_ERROR_CODE, {
24
30
  status: 409
25
31
  });
26
32
  throw error;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/routes/assign-runner-instances.ts"],"sourcesContent":["import {requireProvisionerContext} from '@shipfox/api-auth-context';\nimport {\n assignRunnerInstancesBodySchema,\n assignRunnerInstancesResponseSchema,\n} from '@shipfox/api-runners-dto';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {\n ReservationExpiredError,\n ReservationNotFoundError,\n RunnerInstanceAlreadyAssignedError,\n RunnerInstanceNotAssignableError,\n} from '#core/errors.js';\nimport {assignRunnerInstances} from '#core/runner-assignments.js';\n\nexport const assignRunnerInstancesRoute = defineRoute({\n method: 'POST',\n path: '/runner-instances/assignments',\n description: 'Assign enrolled runner instances to an owned demand reservation',\n schema: {\n body: assignRunnerInstancesBodySchema,\n response: {200: assignRunnerInstancesResponseSchema},\n },\n errorHandler: (error) => {\n if (error instanceof ReservationNotFoundError)\n throw new ClientError('Reservation not found', 'reservation-not-found', {status: 404});\n if (error instanceof ReservationExpiredError)\n throw new ClientError('Reservation has expired', 'reservation-expired', {status: 409});\n if (\n error instanceof RunnerInstanceAlreadyAssignedError ||\n error instanceof RunnerInstanceNotAssignableError\n )\n throw new ClientError(\n 'Runner instance cannot be assigned',\n 'runner-instance-not-assignable',\n {status: 409},\n );\n throw error;\n },\n handler: async (request) => {\n const {provisionerTokenId} = requireProvisionerContext(request);\n return {\n runner_instance_ids: await assignRunnerInstances({\n provisionerId: provisionerTokenId,\n reservationId: request.body.reservation_id,\n runnerInstanceIds: request.body.runner_instance_ids,\n }),\n };\n },\n});\n"],"names":["requireProvisionerContext","assignRunnerInstancesBodySchema","assignRunnerInstancesResponseSchema","ClientError","defineRoute","ReservationExpiredError","ReservationNotFoundError","RunnerInstanceAlreadyAssignedError","RunnerInstanceNotAssignableError","assignRunnerInstances","assignRunnerInstancesRoute","method","path","description","schema","body","response","errorHandler","error","status","handler","request","provisionerTokenId","runner_instance_ids","provisionerId","reservationId","reservation_id","runnerInstanceIds"],"mappings":"AAAA,SAAQA,yBAAyB,QAAO,4BAA4B;AACpE,SACEC,+BAA+B,EAC/BC,mCAAmC,QAC9B,2BAA2B;AAClC,SAAQC,WAAW,EAAEC,WAAW,QAAO,wBAAwB;AAC/D,SACEC,uBAAuB,EACvBC,wBAAwB,EACxBC,kCAAkC,EAClCC,gCAAgC,QAC3B,kBAAkB;AACzB,SAAQC,qBAAqB,QAAO,8BAA8B;AAElE,OAAO,MAAMC,6BAA6BN,YAAY;IACpDO,QAAQ;IACRC,MAAM;IACNC,aAAa;IACbC,QAAQ;QACNC,MAAMd;QACNe,UAAU;YAAC,KAAKd;QAAmC;IACrD;IACAe,cAAc,CAACC;QACb,IAAIA,iBAAiBZ,0BACnB,MAAM,IAAIH,YAAY,yBAAyB,yBAAyB;YAACgB,QAAQ;QAAG;QACtF,IAAID,iBAAiBb,yBACnB,MAAM,IAAIF,YAAY,2BAA2B,uBAAuB;YAACgB,QAAQ;QAAG;QACtF,IACED,iBAAiBX,sCACjBW,iBAAiBV,kCAEjB,MAAM,IAAIL,YACR,sCACA,kCACA;YAACgB,QAAQ;QAAG;QAEhB,MAAMD;IACR;IACAE,SAAS,OAAOC;QACd,MAAM,EAACC,kBAAkB,EAAC,GAAGtB,0BAA0BqB;QACvD,OAAO;YACLE,qBAAqB,MAAMd,sBAAsB;gBAC/Ce,eAAeF;gBACfG,eAAeJ,QAAQN,IAAI,CAACW,cAAc;gBAC1CC,mBAAmBN,QAAQN,IAAI,CAACQ,mBAAmB;YACrD;QACF;IACF;AACF,GAAG"}
1
+ {"version":3,"sources":["../../../src/presentation/routes/assign-runner-instances.ts"],"sourcesContent":["import {requireProvisionerContext} from '@shipfox/api-auth-context';\nimport {\n assignRunnerInstancesBodySchema,\n assignRunnerInstancesResponseSchema,\n RESERVATION_EXPIRED_ERROR_CODE,\n RUNNER_INSTANCE_NOT_ASSIGNABLE_ERROR_CODE,\n} from '@shipfox/api-runners-dto';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {\n getRunnerAssignmentRejectionReason,\n ReservationExpiredError,\n ReservationNotFoundError,\n RunnerInstanceAlreadyAssignedError,\n RunnerInstanceNotAssignableError,\n} from '#core/errors.js';\nimport {assignRunnerInstances} from '#core/runner-assignments.js';\nimport {recordProviderRunnerAssignmentRejected} from '#metrics/instance.js';\n\nexport const assignRunnerInstancesRoute = defineRoute({\n method: 'POST',\n path: '/runner-instances/assignments',\n description: 'Assign enrolled runner instances to an owned demand reservation',\n schema: {\n body: assignRunnerInstancesBodySchema,\n response: {200: assignRunnerInstancesResponseSchema},\n },\n errorHandler: (error) => {\n const rejectionReason = getRunnerAssignmentRejectionReason(error);\n if (rejectionReason)\n recordProviderRunnerAssignmentRejected({\n reason: rejectionReason,\n surface: 'provisioner',\n });\n if (error instanceof ReservationNotFoundError)\n throw new ClientError('Reservation not found', 'reservation-not-found', {status: 404});\n if (error instanceof ReservationExpiredError)\n throw new ClientError('Reservation has expired', RESERVATION_EXPIRED_ERROR_CODE, {\n status: 409,\n });\n if (\n error instanceof RunnerInstanceAlreadyAssignedError ||\n error instanceof RunnerInstanceNotAssignableError\n )\n throw new ClientError(\n 'Runner instance cannot be assigned',\n RUNNER_INSTANCE_NOT_ASSIGNABLE_ERROR_CODE,\n {status: 409},\n );\n throw error;\n },\n handler: async (request) => {\n const {provisionerTokenId} = requireProvisionerContext(request);\n return {\n runner_instance_ids: await assignRunnerInstances({\n provisionerId: provisionerTokenId,\n reservationId: request.body.reservation_id,\n runnerInstanceIds: request.body.runner_instance_ids,\n }),\n };\n },\n});\n"],"names":["requireProvisionerContext","assignRunnerInstancesBodySchema","assignRunnerInstancesResponseSchema","RESERVATION_EXPIRED_ERROR_CODE","RUNNER_INSTANCE_NOT_ASSIGNABLE_ERROR_CODE","ClientError","defineRoute","getRunnerAssignmentRejectionReason","ReservationExpiredError","ReservationNotFoundError","RunnerInstanceAlreadyAssignedError","RunnerInstanceNotAssignableError","assignRunnerInstances","recordProviderRunnerAssignmentRejected","assignRunnerInstancesRoute","method","path","description","schema","body","response","errorHandler","error","rejectionReason","reason","surface","status","handler","request","provisionerTokenId","runner_instance_ids","provisionerId","reservationId","reservation_id","runnerInstanceIds"],"mappings":"AAAA,SAAQA,yBAAyB,QAAO,4BAA4B;AACpE,SACEC,+BAA+B,EAC/BC,mCAAmC,EACnCC,8BAA8B,EAC9BC,yCAAyC,QACpC,2BAA2B;AAClC,SAAQC,WAAW,EAAEC,WAAW,QAAO,wBAAwB;AAC/D,SACEC,kCAAkC,EAClCC,uBAAuB,EACvBC,wBAAwB,EACxBC,kCAAkC,EAClCC,gCAAgC,QAC3B,kBAAkB;AACzB,SAAQC,qBAAqB,QAAO,8BAA8B;AAClE,SAAQC,sCAAsC,QAAO,uBAAuB;AAE5E,OAAO,MAAMC,6BAA6BR,YAAY;IACpDS,QAAQ;IACRC,MAAM;IACNC,aAAa;IACbC,QAAQ;QACNC,MAAMlB;QACNmB,UAAU;YAAC,KAAKlB;QAAmC;IACrD;IACAmB,cAAc,CAACC;QACb,MAAMC,kBAAkBhB,mCAAmCe;QAC3D,IAAIC,iBACFV,uCAAuC;YACrCW,QAAQD;YACRE,SAAS;QACX;QACF,IAAIH,iBAAiBb,0BACnB,MAAM,IAAIJ,YAAY,yBAAyB,yBAAyB;YAACqB,QAAQ;QAAG;QACtF,IAAIJ,iBAAiBd,yBACnB,MAAM,IAAIH,YAAY,2BAA2BF,gCAAgC;YAC/EuB,QAAQ;QACV;QACF,IACEJ,iBAAiBZ,sCACjBY,iBAAiBX,kCAEjB,MAAM,IAAIN,YACR,sCACAD,2CACA;YAACsB,QAAQ;QAAG;QAEhB,MAAMJ;IACR;IACAK,SAAS,OAAOC;QACd,MAAM,EAACC,kBAAkB,EAAC,GAAG7B,0BAA0B4B;QACvD,OAAO;YACLE,qBAAqB,MAAMlB,sBAAsB;gBAC/CmB,eAAeF;gBACfG,eAAeJ,QAAQT,IAAI,CAACc,cAAc;gBAC1CC,mBAAmBN,QAAQT,IAAI,CAACW,mBAAmB;YACrD;QACF;IACF;AACF,GAAG"}
@@ -1 +1 @@
1
- {"version":3,"file":"poll-demand.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/poll-demand.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAC,0BAA0B,EAAC,MAAM,+BAA+B,CAAC;AAsB9E,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,0BAA+B,mDAgG7E;AAED,eAAO,MAAM,eAAe,iDAA0B,CAAC"}
1
+ {"version":3,"file":"poll-demand.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/poll-demand.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAC,0BAA0B,EAAC,MAAM,+BAA+B,CAAC;AAsB9E,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,0BAA+B,mDAiG7E;AAED,eAAO,MAAM,eAAe,iDAA0B,CAAC"}
@@ -74,6 +74,7 @@ export function createPollDemandRoute(options = {}) {
74
74
  provisionerId: provisionerContext.provisionerTokenId,
75
75
  maxReservations: request.body.max_reservations,
76
76
  ttlSeconds,
77
+ activationGraceSeconds: config.RESERVATION_TTL_SECONDS,
77
78
  templates,
78
79
  capabilityWindowSeconds: config.PROVISIONER_ACTIVE_WINDOW_SECONDS,
79
80
  eligibleWorkspaceIds,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/routes/poll-demand.ts"],"sourcesContent":["import {\n requireProvisionerContext,\n requireWorkspaceProvisionerContext,\n} from '@shipfox/api-auth-context';\nimport type {PollDemandTemplateDto} from '@shipfox/api-runners-dto';\nimport {pollDemandBodySchema, pollDemandResponseSchema} from '@shipfox/api-runners-dto';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {config} from '#config.js';\nimport {pollDemand, releaseReservationGrants} from '#core/demand.js';\nimport {sanitizeRunnerLabels} from '#core/runner-labels.js';\nimport {publishWorkspaceProvisionerCapabilitySnapshot} from '#db/provisioner-capability-snapshots.js';\nimport {\n listQueuedDemandWorkspaceIds,\n pollInstallationDemandAndReserve,\n type ReservationGrant,\n type ReservationTemplate,\n} from '#db/reservations.js';\nimport type {CreateRunnersModuleOptions} from '#installation-provisioning.js';\nimport {toPollDemandResponseDto} from '#presentation/dto/index.js';\n\nconst TERMINATE_INTENT_LIMIT = 1000;\n\nfunction toReservationTemplates(\n templates: PollDemandTemplateDto[],\n scope: 'installation' | 'workspace',\n): ReservationTemplate[] {\n return templates.map((template) => ({\n templateKey: template.template_key,\n labels: sanitizeRunnerLabels(template.labels, {\n scope,\n logLevel: 'debug',\n source: 'provisioner template advertisement',\n }),\n availableSlots: template.available_slots,\n starting: template.starting,\n running: template.running,\n }));\n}\n\nexport function createPollDemandRoute(options: CreateRunnersModuleOptions = {}) {\n return defineRoute({\n method: 'POST',\n path: '/demand/poll',\n description: 'Poll aggregate runner demand and reserve capacity for a provisioner',\n schema: {\n body: pollDemandBodySchema,\n response: {\n 200: pollDemandResponseSchema,\n },\n },\n handler: async (request, reply) => {\n const abortController = new AbortController();\n let responseFinished = false;\n let responseReservations: ReservationGrant[] = [];\n reply.raw.on('finish', () => {\n responseFinished = true;\n });\n reply.raw.on('close', () => {\n if (!responseFinished) {\n abortController.abort();\n void releaseReservationGrants(responseReservations).catch((error) => {\n logger().error(\n {err: error, reservationCount: responseReservations.length},\n 'Failed to release reservations after provisioner disconnect',\n );\n reportError(error, {\n boundary: 'runners.cleanup',\n operation: 'release-disconnected-reservations',\n extra: {reservationCount: responseReservations.length},\n });\n });\n }\n });\n const provisionerContext = requireProvisionerContext(request);\n const ttlSeconds = Math.min(\n request.body.reservation_ttl_seconds ?? config.RESERVATION_TTL_SECONDS,\n config.RESERVATION_TTL_MAX_SECONDS,\n );\n if (provisionerContext.scope === 'installation') {\n if (!options.installationProvisioning) {\n throw new ClientError(\n 'Installation provisioner credentials are not accepted on this host',\n 'forbidden',\n {\n status: 403,\n },\n );\n }\n const candidateWorkspaceIds = await listQueuedDemandWorkspaceIds();\n const eligibleWorkspaceIds =\n await options.installationProvisioning.policy.filterEligibleWorkspaceIds(\n candidateWorkspaceIds,\n );\n const templates = toReservationTemplates(request.body.templates, 'installation');\n const result = await pollInstallationDemandAndReserve({\n provisionerId: provisionerContext.provisionerTokenId,\n maxReservations: request.body.max_reservations,\n ttlSeconds,\n templates,\n capabilityWindowSeconds: config.PROVISIONER_ACTIVE_WINDOW_SECONDS,\n eligibleWorkspaceIds,\n signal: abortController.signal,\n onReservations: (reservations) => {\n responseReservations.push(...reservations);\n },\n });\n return toPollDemandResponseDto({\n ...result,\n terminateRunnerInstanceIds: [],\n });\n }\n const {provisionerTokenId, workspaceId} = requireWorkspaceProvisionerContext(request);\n\n const templates = toReservationTemplates(request.body.templates, 'workspace');\n await publishWorkspaceProvisionerCapabilitySnapshot({\n workspaceId,\n provisionerId: provisionerTokenId,\n templates,\n });\n\n const result = await pollDemand({\n workspaceId,\n provisionerId: provisionerTokenId,\n maxReservations: request.body.max_reservations,\n waitSeconds: request.body.wait_seconds,\n ttlSeconds,\n terminateIntentLimit: TERMINATE_INTENT_LIMIT,\n templates,\n signal: abortController.signal,\n });\n responseReservations = result.reservations;\n\n return toPollDemandResponseDto(result);\n },\n });\n}\n\nexport const pollDemandRoute = createPollDemandRoute();\n"],"names":["requireProvisionerContext","requireWorkspaceProvisionerContext","pollDemandBodySchema","pollDemandResponseSchema","reportError","ClientError","defineRoute","logger","config","pollDemand","releaseReservationGrants","sanitizeRunnerLabels","publishWorkspaceProvisionerCapabilitySnapshot","listQueuedDemandWorkspaceIds","pollInstallationDemandAndReserve","toPollDemandResponseDto","TERMINATE_INTENT_LIMIT","toReservationTemplates","templates","scope","map","template","templateKey","template_key","labels","logLevel","source","availableSlots","available_slots","starting","running","createPollDemandRoute","options","method","path","description","schema","body","response","handler","request","reply","abortController","AbortController","responseFinished","responseReservations","raw","on","abort","catch","error","err","reservationCount","length","boundary","operation","extra","provisionerContext","ttlSeconds","Math","min","reservation_ttl_seconds","RESERVATION_TTL_SECONDS","RESERVATION_TTL_MAX_SECONDS","installationProvisioning","status","candidateWorkspaceIds","eligibleWorkspaceIds","policy","filterEligibleWorkspaceIds","result","provisionerId","provisionerTokenId","maxReservations","max_reservations","capabilityWindowSeconds","PROVISIONER_ACTIVE_WINDOW_SECONDS","signal","onReservations","reservations","push","terminateRunnerInstanceIds","workspaceId","waitSeconds","wait_seconds","terminateIntentLimit","pollDemandRoute"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/presentation/routes/poll-demand.ts"],"sourcesContent":["import {\n requireProvisionerContext,\n requireWorkspaceProvisionerContext,\n} from '@shipfox/api-auth-context';\nimport type {PollDemandTemplateDto} from '@shipfox/api-runners-dto';\nimport {pollDemandBodySchema, pollDemandResponseSchema} from '@shipfox/api-runners-dto';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {config} from '#config.js';\nimport {pollDemand, releaseReservationGrants} from '#core/demand.js';\nimport {sanitizeRunnerLabels} from '#core/runner-labels.js';\nimport {publishWorkspaceProvisionerCapabilitySnapshot} from '#db/provisioner-capability-snapshots.js';\nimport {\n listQueuedDemandWorkspaceIds,\n pollInstallationDemandAndReserve,\n type ReservationGrant,\n type ReservationTemplate,\n} from '#db/reservations.js';\nimport type {CreateRunnersModuleOptions} from '#installation-provisioning.js';\nimport {toPollDemandResponseDto} from '#presentation/dto/index.js';\n\nconst TERMINATE_INTENT_LIMIT = 1000;\n\nfunction toReservationTemplates(\n templates: PollDemandTemplateDto[],\n scope: 'installation' | 'workspace',\n): ReservationTemplate[] {\n return templates.map((template) => ({\n templateKey: template.template_key,\n labels: sanitizeRunnerLabels(template.labels, {\n scope,\n logLevel: 'debug',\n source: 'provisioner template advertisement',\n }),\n availableSlots: template.available_slots,\n starting: template.starting,\n running: template.running,\n }));\n}\n\nexport function createPollDemandRoute(options: CreateRunnersModuleOptions = {}) {\n return defineRoute({\n method: 'POST',\n path: '/demand/poll',\n description: 'Poll aggregate runner demand and reserve capacity for a provisioner',\n schema: {\n body: pollDemandBodySchema,\n response: {\n 200: pollDemandResponseSchema,\n },\n },\n handler: async (request, reply) => {\n const abortController = new AbortController();\n let responseFinished = false;\n let responseReservations: ReservationGrant[] = [];\n reply.raw.on('finish', () => {\n responseFinished = true;\n });\n reply.raw.on('close', () => {\n if (!responseFinished) {\n abortController.abort();\n void releaseReservationGrants(responseReservations).catch((error) => {\n logger().error(\n {err: error, reservationCount: responseReservations.length},\n 'Failed to release reservations after provisioner disconnect',\n );\n reportError(error, {\n boundary: 'runners.cleanup',\n operation: 'release-disconnected-reservations',\n extra: {reservationCount: responseReservations.length},\n });\n });\n }\n });\n const provisionerContext = requireProvisionerContext(request);\n const ttlSeconds = Math.min(\n request.body.reservation_ttl_seconds ?? config.RESERVATION_TTL_SECONDS,\n config.RESERVATION_TTL_MAX_SECONDS,\n );\n if (provisionerContext.scope === 'installation') {\n if (!options.installationProvisioning) {\n throw new ClientError(\n 'Installation provisioner credentials are not accepted on this host',\n 'forbidden',\n {\n status: 403,\n },\n );\n }\n const candidateWorkspaceIds = await listQueuedDemandWorkspaceIds();\n const eligibleWorkspaceIds =\n await options.installationProvisioning.policy.filterEligibleWorkspaceIds(\n candidateWorkspaceIds,\n );\n const templates = toReservationTemplates(request.body.templates, 'installation');\n const result = await pollInstallationDemandAndReserve({\n provisionerId: provisionerContext.provisionerTokenId,\n maxReservations: request.body.max_reservations,\n ttlSeconds,\n activationGraceSeconds: config.RESERVATION_TTL_SECONDS,\n templates,\n capabilityWindowSeconds: config.PROVISIONER_ACTIVE_WINDOW_SECONDS,\n eligibleWorkspaceIds,\n signal: abortController.signal,\n onReservations: (reservations) => {\n responseReservations.push(...reservations);\n },\n });\n return toPollDemandResponseDto({\n ...result,\n terminateRunnerInstanceIds: [],\n });\n }\n const {provisionerTokenId, workspaceId} = requireWorkspaceProvisionerContext(request);\n\n const templates = toReservationTemplates(request.body.templates, 'workspace');\n await publishWorkspaceProvisionerCapabilitySnapshot({\n workspaceId,\n provisionerId: provisionerTokenId,\n templates,\n });\n\n const result = await pollDemand({\n workspaceId,\n provisionerId: provisionerTokenId,\n maxReservations: request.body.max_reservations,\n waitSeconds: request.body.wait_seconds,\n ttlSeconds,\n terminateIntentLimit: TERMINATE_INTENT_LIMIT,\n templates,\n signal: abortController.signal,\n });\n responseReservations = result.reservations;\n\n return toPollDemandResponseDto(result);\n },\n });\n}\n\nexport const pollDemandRoute = createPollDemandRoute();\n"],"names":["requireProvisionerContext","requireWorkspaceProvisionerContext","pollDemandBodySchema","pollDemandResponseSchema","reportError","ClientError","defineRoute","logger","config","pollDemand","releaseReservationGrants","sanitizeRunnerLabels","publishWorkspaceProvisionerCapabilitySnapshot","listQueuedDemandWorkspaceIds","pollInstallationDemandAndReserve","toPollDemandResponseDto","TERMINATE_INTENT_LIMIT","toReservationTemplates","templates","scope","map","template","templateKey","template_key","labels","logLevel","source","availableSlots","available_slots","starting","running","createPollDemandRoute","options","method","path","description","schema","body","response","handler","request","reply","abortController","AbortController","responseFinished","responseReservations","raw","on","abort","catch","error","err","reservationCount","length","boundary","operation","extra","provisionerContext","ttlSeconds","Math","min","reservation_ttl_seconds","RESERVATION_TTL_SECONDS","RESERVATION_TTL_MAX_SECONDS","installationProvisioning","status","candidateWorkspaceIds","eligibleWorkspaceIds","policy","filterEligibleWorkspaceIds","result","provisionerId","provisionerTokenId","maxReservations","max_reservations","activationGraceSeconds","capabilityWindowSeconds","PROVISIONER_ACTIVE_WINDOW_SECONDS","signal","onReservations","reservations","push","terminateRunnerInstanceIds","workspaceId","waitSeconds","wait_seconds","terminateIntentLimit","pollDemandRoute"],"mappings":"AAAA,SACEA,yBAAyB,EACzBC,kCAAkC,QAC7B,4BAA4B;AAEnC,SAAQC,oBAAoB,EAAEC,wBAAwB,QAAO,2BAA2B;AACxF,SAAQC,WAAW,QAAO,iCAAiC;AAC3D,SAAQC,WAAW,EAAEC,WAAW,QAAO,wBAAwB;AAC/D,SAAQC,MAAM,QAAO,8BAA8B;AACnD,SAAQC,MAAM,QAAO,aAAa;AAClC,SAAQC,UAAU,EAAEC,wBAAwB,QAAO,kBAAkB;AACrE,SAAQC,oBAAoB,QAAO,yBAAyB;AAC5D,SAAQC,6CAA6C,QAAO,0CAA0C;AACtG,SACEC,4BAA4B,EAC5BC,gCAAgC,QAG3B,sBAAsB;AAE7B,SAAQC,uBAAuB,QAAO,6BAA6B;AAEnE,MAAMC,yBAAyB;AAE/B,SAASC,uBACPC,SAAkC,EAClCC,KAAmC;IAEnC,OAAOD,UAAUE,GAAG,CAAC,CAACC,WAAc,CAAA;YAClCC,aAAaD,SAASE,YAAY;YAClCC,QAAQb,qBAAqBU,SAASG,MAAM,EAAE;gBAC5CL;gBACAM,UAAU;gBACVC,QAAQ;YACV;YACAC,gBAAgBN,SAASO,eAAe;YACxCC,UAAUR,SAASQ,QAAQ;YAC3BC,SAAST,SAASS,OAAO;QAC3B,CAAA;AACF;AAEA,OAAO,SAASC,sBAAsBC,UAAsC,CAAC,CAAC;IAC5E,OAAO1B,YAAY;QACjB2B,QAAQ;QACRC,MAAM;QACNC,aAAa;QACbC,QAAQ;YACNC,MAAMnC;YACNoC,UAAU;gBACR,KAAKnC;YACP;QACF;QACAoC,SAAS,OAAOC,SAASC;YACvB,MAAMC,kBAAkB,IAAIC;YAC5B,IAAIC,mBAAmB;YACvB,IAAIC,uBAA2C,EAAE;YACjDJ,MAAMK,GAAG,CAACC,EAAE,CAAC,UAAU;gBACrBH,mBAAmB;YACrB;YACAH,MAAMK,GAAG,CAACC,EAAE,CAAC,SAAS;gBACpB,IAAI,CAACH,kBAAkB;oBACrBF,gBAAgBM,KAAK;oBACrB,KAAKtC,yBAAyBmC,sBAAsBI,KAAK,CAAC,CAACC;wBACzD3C,SAAS2C,KAAK,CACZ;4BAACC,KAAKD;4BAAOE,kBAAkBP,qBAAqBQ,MAAM;wBAAA,GAC1D;wBAEFjD,YAAY8C,OAAO;4BACjBI,UAAU;4BACVC,WAAW;4BACXC,OAAO;gCAACJ,kBAAkBP,qBAAqBQ,MAAM;4BAAA;wBACvD;oBACF;gBACF;YACF;YACA,MAAMI,qBAAqBzD,0BAA0BwC;YACrD,MAAMkB,aAAaC,KAAKC,GAAG,CACzBpB,QAAQH,IAAI,CAACwB,uBAAuB,IAAIrD,OAAOsD,uBAAuB,EACtEtD,OAAOuD,2BAA2B;YAEpC,IAAIN,mBAAmBtC,KAAK,KAAK,gBAAgB;gBAC/C,IAAI,CAACa,QAAQgC,wBAAwB,EAAE;oBACrC,MAAM,IAAI3D,YACR,sEACA,aACA;wBACE4D,QAAQ;oBACV;gBAEJ;gBACA,MAAMC,wBAAwB,MAAMrD;gBACpC,MAAMsD,uBACJ,MAAMnC,QAAQgC,wBAAwB,CAACI,MAAM,CAACC,0BAA0B,CACtEH;gBAEJ,MAAMhD,YAAYD,uBAAuBuB,QAAQH,IAAI,CAACnB,SAAS,EAAE;gBACjE,MAAMoD,SAAS,MAAMxD,iCAAiC;oBACpDyD,eAAed,mBAAmBe,kBAAkB;oBACpDC,iBAAiBjC,QAAQH,IAAI,CAACqC,gBAAgB;oBAC9ChB;oBACAiB,wBAAwBnE,OAAOsD,uBAAuB;oBACtD5C;oBACA0D,yBAAyBpE,OAAOqE,iCAAiC;oBACjEV;oBACAW,QAAQpC,gBAAgBoC,MAAM;oBAC9BC,gBAAgB,CAACC;wBACfnC,qBAAqBoC,IAAI,IAAID;oBAC/B;gBACF;gBACA,OAAOjE,wBAAwB;oBAC7B,GAAGuD,MAAM;oBACTY,4BAA4B,EAAE;gBAChC;YACF;YACA,MAAM,EAACV,kBAAkB,EAAEW,WAAW,EAAC,GAAGlF,mCAAmCuC;YAE7E,MAAMtB,YAAYD,uBAAuBuB,QAAQH,IAAI,CAACnB,SAAS,EAAE;YACjE,MAAMN,8CAA8C;gBAClDuE;gBACAZ,eAAeC;gBACftD;YACF;YAEA,MAAMoD,SAAS,MAAM7D,WAAW;gBAC9B0E;gBACAZ,eAAeC;gBACfC,iBAAiBjC,QAAQH,IAAI,CAACqC,gBAAgB;gBAC9CU,aAAa5C,QAAQH,IAAI,CAACgD,YAAY;gBACtC3B;gBACA4B,sBAAsBtE;gBACtBE;gBACA4D,QAAQpC,gBAAgBoC,MAAM;YAChC;YACAjC,uBAAuByB,OAAOU,YAAY;YAE1C,OAAOjE,wBAAwBuD;QACjC;IACF;AACF;AAEA,OAAO,MAAMiB,kBAAkBxD,wBAAwB"}
@@ -1 +1 @@
1
- {"version":3,"file":"reconcile-runner-instances.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/reconcile-runner-instances.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,6BAA6B,iDAoBxC,CAAC"}
1
+ {"version":3,"file":"reconcile-runner-instances.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/reconcile-runner-instances.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,6BAA6B,iDAwBxC,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { requireProvisionerContext } from '@shipfox/api-auth-context';
2
- import { reconcileRunnerInstancesBodySchema, reconcileRunnerInstancesResponseSchema } from '@shipfox/api-runners-dto';
2
+ import { RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER, RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER_VALUE, reconcileRunnerInstancesBodySchema, reconcileRunnerInstancesResponseSchema } from '@shipfox/api-runners-dto';
3
3
  import { defineRoute } from '@shipfox/node-fastify';
4
4
  import { reconcileRunnerInstances } from '#core/index.js';
5
5
  import { toReconcileRunnerInstancesResponseDto } from '#presentation/dto/index.js';
@@ -20,7 +20,9 @@ export const reconcileRunnerInstancesRoute = defineRoute({
20
20
  provisionerId: context.provisionerTokenId,
21
21
  observedRunnerInstanceIds: request.body.observed_provider_runner_ids
22
22
  });
23
- return toReconcileRunnerInstancesResponseDto(result);
23
+ return toReconcileRunnerInstancesResponseDto(result, {
24
+ includeIntendedReservationId: request.headers[RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER] === RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER_VALUE
25
+ });
24
26
  }
25
27
  });
26
28
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/routes/reconcile-runner-instances.ts"],"sourcesContent":["import {requireProvisionerContext} from '@shipfox/api-auth-context';\nimport {\n reconcileRunnerInstancesBodySchema,\n reconcileRunnerInstancesResponseSchema,\n} from '@shipfox/api-runners-dto';\nimport {defineRoute} from '@shipfox/node-fastify';\nimport {reconcileRunnerInstances} from '#core/index.js';\nimport {toReconcileRunnerInstancesResponseDto} from '#presentation/dto/index.js';\n\nexport const reconcileRunnerInstancesRoute = defineRoute({\n method: 'POST',\n path: '/runner-instances/reconcile',\n description: 'Reconcile provisioned runner state for a provisioner',\n schema: {\n body: reconcileRunnerInstancesBodySchema,\n response: {\n 200: reconcileRunnerInstancesResponseSchema,\n },\n },\n handler: async (request) => {\n const context = requireProvisionerContext(request);\n const result = await reconcileRunnerInstances({\n workspaceId: context.scope === 'workspace' ? context.workspaceId : null,\n provisionerId: context.provisionerTokenId,\n observedRunnerInstanceIds: request.body.observed_provider_runner_ids,\n });\n\n return toReconcileRunnerInstancesResponseDto(result);\n },\n});\n"],"names":["requireProvisionerContext","reconcileRunnerInstancesBodySchema","reconcileRunnerInstancesResponseSchema","defineRoute","reconcileRunnerInstances","toReconcileRunnerInstancesResponseDto","reconcileRunnerInstancesRoute","method","path","description","schema","body","response","handler","request","context","result","workspaceId","scope","provisionerId","provisionerTokenId","observedRunnerInstanceIds","observed_provider_runner_ids"],"mappings":"AAAA,SAAQA,yBAAyB,QAAO,4BAA4B;AACpE,SACEC,kCAAkC,EAClCC,sCAAsC,QACjC,2BAA2B;AAClC,SAAQC,WAAW,QAAO,wBAAwB;AAClD,SAAQC,wBAAwB,QAAO,iBAAiB;AACxD,SAAQC,qCAAqC,QAAO,6BAA6B;AAEjF,OAAO,MAAMC,gCAAgCH,YAAY;IACvDI,QAAQ;IACRC,MAAM;IACNC,aAAa;IACbC,QAAQ;QACNC,MAAMV;QACNW,UAAU;YACR,KAAKV;QACP;IACF;IACAW,SAAS,OAAOC;QACd,MAAMC,UAAUf,0BAA0Bc;QAC1C,MAAME,SAAS,MAAMZ,yBAAyB;YAC5Ca,aAAaF,QAAQG,KAAK,KAAK,cAAcH,QAAQE,WAAW,GAAG;YACnEE,eAAeJ,QAAQK,kBAAkB;YACzCC,2BAA2BP,QAAQH,IAAI,CAACW,4BAA4B;QACtE;QAEA,OAAOjB,sCAAsCW;IAC/C;AACF,GAAG"}
1
+ {"version":3,"sources":["../../../src/presentation/routes/reconcile-runner-instances.ts"],"sourcesContent":["import {requireProvisionerContext} from '@shipfox/api-auth-context';\nimport {\n RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER,\n RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER_VALUE,\n reconcileRunnerInstancesBodySchema,\n reconcileRunnerInstancesResponseSchema,\n} from '@shipfox/api-runners-dto';\nimport {defineRoute} from '@shipfox/node-fastify';\nimport {reconcileRunnerInstances} from '#core/index.js';\nimport {toReconcileRunnerInstancesResponseDto} from '#presentation/dto/index.js';\n\nexport const reconcileRunnerInstancesRoute = defineRoute({\n method: 'POST',\n path: '/runner-instances/reconcile',\n description: 'Reconcile provisioned runner state for a provisioner',\n schema: {\n body: reconcileRunnerInstancesBodySchema,\n response: {\n 200: reconcileRunnerInstancesResponseSchema,\n },\n },\n handler: async (request) => {\n const context = requireProvisionerContext(request);\n const result = await reconcileRunnerInstances({\n workspaceId: context.scope === 'workspace' ? context.workspaceId : null,\n provisionerId: context.provisionerTokenId,\n observedRunnerInstanceIds: request.body.observed_provider_runner_ids,\n });\n\n return toReconcileRunnerInstancesResponseDto(result, {\n includeIntendedReservationId:\n request.headers[RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER] ===\n RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER_VALUE,\n });\n },\n});\n"],"names":["requireProvisionerContext","RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER","RECONCILE_RUNNER_INSTANCES_INTENDED_RESERVATION_HEADER_VALUE","reconcileRunnerInstancesBodySchema","reconcileRunnerInstancesResponseSchema","defineRoute","reconcileRunnerInstances","toReconcileRunnerInstancesResponseDto","reconcileRunnerInstancesRoute","method","path","description","schema","body","response","handler","request","context","result","workspaceId","scope","provisionerId","provisionerTokenId","observedRunnerInstanceIds","observed_provider_runner_ids","includeIntendedReservationId","headers"],"mappings":"AAAA,SAAQA,yBAAyB,QAAO,4BAA4B;AACpE,SACEC,sDAAsD,EACtDC,4DAA4D,EAC5DC,kCAAkC,EAClCC,sCAAsC,QACjC,2BAA2B;AAClC,SAAQC,WAAW,QAAO,wBAAwB;AAClD,SAAQC,wBAAwB,QAAO,iBAAiB;AACxD,SAAQC,qCAAqC,QAAO,6BAA6B;AAEjF,OAAO,MAAMC,gCAAgCH,YAAY;IACvDI,QAAQ;IACRC,MAAM;IACNC,aAAa;IACbC,QAAQ;QACNC,MAAMV;QACNW,UAAU;YACR,KAAKV;QACP;IACF;IACAW,SAAS,OAAOC;QACd,MAAMC,UAAUjB,0BAA0BgB;QAC1C,MAAME,SAAS,MAAMZ,yBAAyB;YAC5Ca,aAAaF,QAAQG,KAAK,KAAK,cAAcH,QAAQE,WAAW,GAAG;YACnEE,eAAeJ,QAAQK,kBAAkB;YACzCC,2BAA2BP,QAAQH,IAAI,CAACW,4BAA4B;QACtE;QAEA,OAAOjB,sCAAsCW,QAAQ;YACnDO,8BACET,QAAQU,OAAO,CAACzB,uDAAuD,KACvEC;QACJ;IACF;AACF,GAAG"}
@@ -8,7 +8,10 @@ type RunnerAssignmentPollParams = {
8
8
  deadline: number;
9
9
  intervalMs: number;
10
10
  signal: AbortSignal;
11
- getAssignment: () => Promise<unknown | null>;
11
+ getAssignment: () => Promise<{
12
+ workspaceId: string | null;
13
+ runnerSessionId: string | null;
14
+ } | null>;
12
15
  issueActivationToken: () => Promise<string | null>;
13
16
  };
14
17
  export declare function resolveRunnerAssignmentPollWaitSeconds(requestedWaitSeconds: number | undefined): number;
@@ -1 +1 @@
1
- {"version":3,"file":"runner-enrollment.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/runner-enrollment.ts"],"names":[],"mappings":"AAiCA,eAAO,MAAM,0BAA0B,iDA2BrC,CAAC;AAEH,eAAO,MAAM,mCAAmC,iDAmB9C,CAAC;AAEH,eAAO,MAAM,4BAA4B,iDA2BvC,CAAC;AAEH,eAAO,MAAM,iBAAiB,iDAuB5B,CAAC;AAEH,eAAO,MAAM,kCAAkC,iDAkB7C,CAAC;AAEH,eAAO,MAAM,2BAA2B,iDAYtC,CAAC;AAEH,KAAK,0BAA0B,GAAG;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,WAAW,CAAC;IACpB,aAAa,EAAE,MAAM,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC7C,oBAAoB,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACpD,CAAC;AAEF,wBAAgB,sCAAsC,CACpD,oBAAoB,EAAE,MAAM,GAAG,SAAS,GACvC,MAAM,CAQR;AAED,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAaxB;AACD,eAAO,MAAM,yBAAyB,iDA4BpC,CAAC"}
1
+ {"version":3,"file":"runner-enrollment.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/runner-enrollment.ts"],"names":[],"mappings":"AAiCA,eAAO,MAAM,0BAA0B,iDA6BrC,CAAC;AAEH,eAAO,MAAM,mCAAmC,iDAmB9C,CAAC;AAEH,eAAO,MAAM,4BAA4B,iDA2BvC,CAAC;AAEH,eAAO,MAAM,iBAAiB,iDAuB5B,CAAC;AAEH,eAAO,MAAM,kCAAkC,iDAkB7C,CAAC;AAEH,eAAO,MAAM,2BAA2B,iDAYtC,CAAC;AAEH,KAAK,0BAA0B,GAAG;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,WAAW,CAAC;IACpB,aAAa,EAAE,MAAM,OAAO,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;KAAC,GAAG,IAAI,CAAC,CAAC;IAClG,oBAAoB,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACpD,CAAC;AAEF,wBAAgB,sCAAsC,CACpD,oBAAoB,EAAE,MAAM,GAAG,SAAS,GACvC,MAAM,CAQR;AAED,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAaxB;AACD,eAAO,MAAM,yBAAyB,iDA6BpC,CAAC"}
@@ -20,7 +20,7 @@ export const createRunnerInstancesRoute = defineRoute({
20
20
  },
21
21
  handler: async (request)=>{
22
22
  const { provisionerTokenId } = requireProvisionerContext(request);
23
- const results = await createRunnerInstancesWithBootstrapTokens({
23
+ const result = await createRunnerInstancesWithBootstrapTokens({
24
24
  provisionerId: provisionerTokenId,
25
25
  ...request.body.provider_kind ? {
26
26
  providerKind: request.body.provider_kind
@@ -36,10 +36,14 @@ export const createRunnerInstancesRoute = defineRoute({
36
36
  ttlSeconds: config.RUNNER_BOOTSTRAP_TOKEN_TTL_SECONDS
37
37
  });
38
38
  return {
39
- runner_instances: results.map((result)=>({
40
- runner_instance_id: result.runnerInstanceId,
41
- bootstrap_token: result.bootstrapToken
42
- }))
39
+ runner_instances: result.runnerInstances.map((runnerInstance)=>({
40
+ runner_instance_id: runnerInstance.runnerInstanceId,
41
+ bootstrap_token: runnerInstance.bootstrapToken,
42
+ request_index: runnerInstance.requestIndex
43
+ })),
44
+ ...result.reservationUnavailable ? {
45
+ reservation_unavailable: true
46
+ } : {}
43
47
  };
44
48
  }
45
49
  });
@@ -220,7 +224,8 @@ export const runnerAssignmentPollRoute = defineRoute({
220
224
  getAssignment: ()=>getRunnerAssignment(session),
221
225
  issueActivationToken: ()=>issueRunnerActivationToken({
222
226
  ...session,
223
- ttlSeconds: config.RUNNER_ACTIVATION_TOKEN_TTL_SECONDS
227
+ ttlSeconds: config.RUNNER_ACTIVATION_TOKEN_TTL_SECONDS,
228
+ surface: 'poll'
224
229
  })
225
230
  });
226
231
  return {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/routes/runner-enrollment.ts"],"sourcesContent":["import {\n requireProvisionerContext,\n requireRunnerControlSessionContext,\n} from '@shipfox/api-auth-context';\nimport {\n attachRunnerControlProviderIdBodySchema,\n createRunnerInstancesBodySchema,\n createRunnerInstancesResponseSchema,\n runnerAssignmentPollQuerySchema,\n runnerAssignmentPollResponseSchema,\n runnerBootstrapExchangeBodySchema,\n runnerBootstrapExchangeResponseSchema,\n runnerControlHeartbeatResponseSchema,\n runnerEnrollmentBodySchema,\n runnerEnrollmentResponseSchema,\n} from '@shipfox/api-runners-dto';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {z} from 'zod';\nimport {config} from '#config.js';\nimport {getRunnerAssignment, issueRunnerActivationToken} from '#core/runner-activation.js';\nimport {\n attachRunnerControlProviderId,\n createRunnerInstancesWithBootstrapTokens,\n enrollRunnerControlSession,\n exchangeRunnerBootstrapToken,\n RunnerBootstrapTokenInvalidError,\n RunnerControlSessionInvalidError,\n touchRunnerControlSession,\n} from '#core/runner-control-sessions.js';\nimport {attachRunnerInstanceProviderId} from '#core/runner-instances.js';\nimport {runnerBootstrapExchangeCount, runnerControlHeartbeatCount} from '#metrics/instance.js';\nimport {authenticateRunnerControlSession} from '#presentation/auth/index.js';\n\nexport const createRunnerInstancesRoute = defineRoute({\n method: 'POST',\n path: '/runner-instances/batch',\n description:\n 'Create provisioner-owned runner instances and one-use bootstrap tokens before launch',\n schema: {\n body: createRunnerInstancesBodySchema,\n response: {200: createRunnerInstancesResponseSchema},\n },\n handler: async (request) => {\n const {provisionerTokenId} = requireProvisionerContext(request);\n const results = await createRunnerInstancesWithBootstrapTokens({\n provisionerId: provisionerTokenId,\n ...(request.body.provider_kind ? {providerKind: request.body.provider_kind} : {}),\n runnerInstances: request.body.runner_instances.map((runner) => ({\n ...(runner.template_key ? {templateKey: runner.template_key} : {}),\n ...(runner.reservation_id ? {reservationId: runner.reservation_id} : {}),\n })),\n ttlSeconds: config.RUNNER_BOOTSTRAP_TOKEN_TTL_SECONDS,\n });\n return {\n runner_instances: results.map((result) => ({\n runner_instance_id: result.runnerInstanceId,\n bootstrap_token: result.bootstrapToken,\n })),\n };\n },\n});\n\nexport const attachRunnerInstanceProviderIdRoute = defineRoute({\n method: 'POST',\n path: '/runner-instances/:runnerInstanceId/provider-runner',\n description: 'Attach the provider identity after the provisioner launches a runner instance',\n schema: {\n params: z.object({runnerInstanceId: z.string().uuid()}),\n body: attachRunnerControlProviderIdBodySchema,\n response: {200: z.object({attached: z.boolean()})},\n },\n handler: async (request) => {\n const {provisionerTokenId} = requireProvisionerContext(request);\n return {\n attached: await attachRunnerInstanceProviderId({\n runnerInstanceId: request.params.runnerInstanceId,\n provisionerId: provisionerTokenId,\n providerRunnerId: request.body.provider_runner_id,\n }),\n };\n },\n});\n\nexport const exchangeRunnerBootstrapRoute = defineRoute({\n method: 'POST',\n path: '/exchange',\n description: 'Exchange a one-use runner bootstrap token for a workspace-neutral control session',\n schema: {\n body: runnerBootstrapExchangeBodySchema,\n response: {200: runnerBootstrapExchangeResponseSchema},\n },\n errorHandler: (error) => {\n if (error instanceof RunnerBootstrapTokenInvalidError)\n runnerBootstrapExchangeCount.add(1, {outcome: 'rejected'});\n if (error instanceof RunnerBootstrapTokenInvalidError)\n throw new ClientError(error.message, 'runner-bootstrap-token-invalid', {status: 401});\n throw error;\n },\n handler: async (request) => {\n const result = await exchangeRunnerBootstrapToken({\n rawToken: request.body.bootstrap_token,\n ttlSeconds: config.RUNNER_CONTROL_SESSION_TTL_SECONDS,\n });\n runnerBootstrapExchangeCount.add(1, {outcome: 'accepted'});\n return {\n runner_instance_id: result.runnerInstanceId,\n control_session_token: result.controlSessionToken,\n expires_at: result.expiresAt.toISOString(),\n };\n },\n});\n\nexport const enrollRunnerRoute = defineRoute({\n method: 'POST',\n path: '/enrollment',\n description: 'Declare the authenticated runner instance labels and protocol capabilities',\n schema: {body: runnerEnrollmentBodySchema, response: {200: runnerEnrollmentResponseSchema}},\n preHandler: authenticateRunnerControlSession,\n errorHandler: (error) => {\n if (error instanceof RunnerControlSessionInvalidError)\n throw new ClientError(error.message, 'runner-control-session-invalid', {status: 409});\n throw error;\n },\n handler: async (request) => {\n const session = requireRunnerControlSessionContext(request);\n const activationToken = await enrollRunnerControlSession({\n runnerInstanceId: session.runnerInstanceId,\n provisionerId: session.provisionerId,\n labels: request.body.labels,\n ...(request.body.capabilities ? {capabilities: request.body.capabilities} : {}),\n providerKind: request.body.provider_kind,\n protocolVersion: request.body.protocol_version,\n });\n return {activation_token: activationToken};\n },\n});\n\nexport const attachRunnerControlProviderIdRoute = defineRoute({\n method: 'POST',\n path: '/provider-runner',\n description: 'Attach the authenticated runner instance provider identity once',\n schema: {\n body: attachRunnerControlProviderIdBodySchema,\n response: {200: z.object({attached: z.boolean()})},\n },\n preHandler: authenticateRunnerControlSession,\n handler: async (request) => {\n const session = requireRunnerControlSessionContext(request);\n return {\n attached: await attachRunnerControlProviderId({\n ...session,\n providerRunnerId: request.body.provider_runner_id,\n }),\n };\n },\n});\n\nexport const runnerControlHeartbeatRoute = defineRoute({\n method: 'POST',\n path: '/heartbeat',\n description: 'Record liveness for only the authenticated runner instance',\n schema: {response: {200: runnerControlHeartbeatResponseSchema}},\n preHandler: authenticateRunnerControlSession,\n handler: async (request) => {\n const session = requireRunnerControlSessionContext(request);\n await touchRunnerControlSession(session.runnerInstanceId, session.provisionerId);\n runnerControlHeartbeatCount.add(1);\n return {ok: true};\n },\n});\n\ntype RunnerAssignmentPollParams = {\n deadline: number;\n intervalMs: number;\n signal: AbortSignal;\n getAssignment: () => Promise<unknown | null>;\n issueActivationToken: () => Promise<string | null>;\n};\n\nexport function resolveRunnerAssignmentPollWaitSeconds(\n requestedWaitSeconds: number | undefined,\n): number {\n return Math.max(\n 1,\n Math.min(\n requestedWaitSeconds ?? config.RUNNER_ASSIGNMENT_POLL_MAX_WAIT_SECONDS,\n config.RUNNER_ASSIGNMENT_POLL_MAX_WAIT_SECONDS,\n ),\n );\n}\n\nexport async function pollForRunnerActivationToken(\n params: RunnerAssignmentPollParams,\n): Promise<string | null> {\n while (Date.now() < params.deadline) {\n if (params.signal.aborted) return null;\n const assignment = await params.getAssignment();\n if (assignment) {\n const activationToken = await params.issueActivationToken();\n if (activationToken) return activationToken;\n }\n const remainingMs = params.deadline - Date.now();\n if (remainingMs <= 0 || params.signal.aborted) return null;\n await new Promise((resolve) => setTimeout(resolve, Math.min(params.intervalMs, remainingMs)));\n }\n return null;\n}\nexport const runnerAssignmentPollRoute = defineRoute({\n method: 'GET',\n path: '/assignment',\n description: 'Wait for only the authenticated runner instance assignment',\n schema: {\n querystring: runnerAssignmentPollQuerySchema,\n response: {200: runnerAssignmentPollResponseSchema},\n },\n preHandler: authenticateRunnerControlSession,\n handler: async (request, reply) => {\n const session = requireRunnerControlSessionContext(request);\n const waitSeconds = resolveRunnerAssignmentPollWaitSeconds(request.query.wait_seconds);\n const deadline = Date.now() + waitSeconds * 1000;\n const abortController = new AbortController();\n reply.raw.on('close', () => abortController.abort());\n const activationToken = await pollForRunnerActivationToken({\n deadline,\n intervalMs: config.RUNNER_ASSIGNMENT_POLL_INTERVAL_MS,\n signal: abortController.signal,\n getAssignment: () => getRunnerAssignment(session),\n issueActivationToken: () =>\n issueRunnerActivationToken({\n ...session,\n ttlSeconds: config.RUNNER_ACTIVATION_TOKEN_TTL_SECONDS,\n }),\n });\n return {activation_token: activationToken};\n },\n});\n"],"names":["requireProvisionerContext","requireRunnerControlSessionContext","attachRunnerControlProviderIdBodySchema","createRunnerInstancesBodySchema","createRunnerInstancesResponseSchema","runnerAssignmentPollQuerySchema","runnerAssignmentPollResponseSchema","runnerBootstrapExchangeBodySchema","runnerBootstrapExchangeResponseSchema","runnerControlHeartbeatResponseSchema","runnerEnrollmentBodySchema","runnerEnrollmentResponseSchema","ClientError","defineRoute","z","config","getRunnerAssignment","issueRunnerActivationToken","attachRunnerControlProviderId","createRunnerInstancesWithBootstrapTokens","enrollRunnerControlSession","exchangeRunnerBootstrapToken","RunnerBootstrapTokenInvalidError","RunnerControlSessionInvalidError","touchRunnerControlSession","attachRunnerInstanceProviderId","runnerBootstrapExchangeCount","runnerControlHeartbeatCount","authenticateRunnerControlSession","createRunnerInstancesRoute","method","path","description","schema","body","response","handler","request","provisionerTokenId","results","provisionerId","provider_kind","providerKind","runnerInstances","runner_instances","map","runner","template_key","templateKey","reservation_id","reservationId","ttlSeconds","RUNNER_BOOTSTRAP_TOKEN_TTL_SECONDS","result","runner_instance_id","runnerInstanceId","bootstrap_token","bootstrapToken","attachRunnerInstanceProviderIdRoute","params","object","string","uuid","attached","boolean","providerRunnerId","provider_runner_id","exchangeRunnerBootstrapRoute","errorHandler","error","add","outcome","message","status","rawToken","RUNNER_CONTROL_SESSION_TTL_SECONDS","control_session_token","controlSessionToken","expires_at","expiresAt","toISOString","enrollRunnerRoute","preHandler","session","activationToken","labels","capabilities","protocolVersion","protocol_version","activation_token","attachRunnerControlProviderIdRoute","runnerControlHeartbeatRoute","ok","resolveRunnerAssignmentPollWaitSeconds","requestedWaitSeconds","Math","max","min","RUNNER_ASSIGNMENT_POLL_MAX_WAIT_SECONDS","pollForRunnerActivationToken","Date","now","deadline","signal","aborted","assignment","getAssignment","issueActivationToken","remainingMs","Promise","resolve","setTimeout","intervalMs","runnerAssignmentPollRoute","querystring","reply","waitSeconds","query","wait_seconds","abortController","AbortController","raw","on","abort","RUNNER_ASSIGNMENT_POLL_INTERVAL_MS","RUNNER_ACTIVATION_TOKEN_TTL_SECONDS"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/presentation/routes/runner-enrollment.ts"],"sourcesContent":["import {\n requireProvisionerContext,\n requireRunnerControlSessionContext,\n} from '@shipfox/api-auth-context';\nimport {\n attachRunnerControlProviderIdBodySchema,\n createRunnerInstancesBodySchema,\n createRunnerInstancesResponseSchema,\n runnerAssignmentPollQuerySchema,\n runnerAssignmentPollResponseSchema,\n runnerBootstrapExchangeBodySchema,\n runnerBootstrapExchangeResponseSchema,\n runnerControlHeartbeatResponseSchema,\n runnerEnrollmentBodySchema,\n runnerEnrollmentResponseSchema,\n} from '@shipfox/api-runners-dto';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {z} from 'zod';\nimport {config} from '#config.js';\nimport {getRunnerAssignment, issueRunnerActivationToken} from '#core/runner-activation.js';\nimport {\n attachRunnerControlProviderId,\n createRunnerInstancesWithBootstrapTokens,\n enrollRunnerControlSession,\n exchangeRunnerBootstrapToken,\n RunnerBootstrapTokenInvalidError,\n RunnerControlSessionInvalidError,\n touchRunnerControlSession,\n} from '#core/runner-control-sessions.js';\nimport {attachRunnerInstanceProviderId} from '#core/runner-instances.js';\nimport {runnerBootstrapExchangeCount, runnerControlHeartbeatCount} from '#metrics/instance.js';\nimport {authenticateRunnerControlSession} from '#presentation/auth/index.js';\n\nexport const createRunnerInstancesRoute = defineRoute({\n method: 'POST',\n path: '/runner-instances/batch',\n description:\n 'Create provisioner-owned runner instances and one-use bootstrap tokens before launch',\n schema: {\n body: createRunnerInstancesBodySchema,\n response: {200: createRunnerInstancesResponseSchema},\n },\n handler: async (request) => {\n const {provisionerTokenId} = requireProvisionerContext(request);\n const result = await createRunnerInstancesWithBootstrapTokens({\n provisionerId: provisionerTokenId,\n ...(request.body.provider_kind ? {providerKind: request.body.provider_kind} : {}),\n runnerInstances: request.body.runner_instances.map((runner) => ({\n ...(runner.template_key ? {templateKey: runner.template_key} : {}),\n ...(runner.reservation_id ? {reservationId: runner.reservation_id} : {}),\n })),\n ttlSeconds: config.RUNNER_BOOTSTRAP_TOKEN_TTL_SECONDS,\n });\n return {\n runner_instances: result.runnerInstances.map((runnerInstance) => ({\n runner_instance_id: runnerInstance.runnerInstanceId,\n bootstrap_token: runnerInstance.bootstrapToken,\n request_index: runnerInstance.requestIndex,\n })),\n ...(result.reservationUnavailable ? {reservation_unavailable: true as const} : {}),\n };\n },\n});\n\nexport const attachRunnerInstanceProviderIdRoute = defineRoute({\n method: 'POST',\n path: '/runner-instances/:runnerInstanceId/provider-runner',\n description: 'Attach the provider identity after the provisioner launches a runner instance',\n schema: {\n params: z.object({runnerInstanceId: z.string().uuid()}),\n body: attachRunnerControlProviderIdBodySchema,\n response: {200: z.object({attached: z.boolean()})},\n },\n handler: async (request) => {\n const {provisionerTokenId} = requireProvisionerContext(request);\n return {\n attached: await attachRunnerInstanceProviderId({\n runnerInstanceId: request.params.runnerInstanceId,\n provisionerId: provisionerTokenId,\n providerRunnerId: request.body.provider_runner_id,\n }),\n };\n },\n});\n\nexport const exchangeRunnerBootstrapRoute = defineRoute({\n method: 'POST',\n path: '/exchange',\n description: 'Exchange a one-use runner bootstrap token for a workspace-neutral control session',\n schema: {\n body: runnerBootstrapExchangeBodySchema,\n response: {200: runnerBootstrapExchangeResponseSchema},\n },\n errorHandler: (error) => {\n if (error instanceof RunnerBootstrapTokenInvalidError)\n runnerBootstrapExchangeCount.add(1, {outcome: 'rejected'});\n if (error instanceof RunnerBootstrapTokenInvalidError)\n throw new ClientError(error.message, 'runner-bootstrap-token-invalid', {status: 401});\n throw error;\n },\n handler: async (request) => {\n const result = await exchangeRunnerBootstrapToken({\n rawToken: request.body.bootstrap_token,\n ttlSeconds: config.RUNNER_CONTROL_SESSION_TTL_SECONDS,\n });\n runnerBootstrapExchangeCount.add(1, {outcome: 'accepted'});\n return {\n runner_instance_id: result.runnerInstanceId,\n control_session_token: result.controlSessionToken,\n expires_at: result.expiresAt.toISOString(),\n };\n },\n});\n\nexport const enrollRunnerRoute = defineRoute({\n method: 'POST',\n path: '/enrollment',\n description: 'Declare the authenticated runner instance labels and protocol capabilities',\n schema: {body: runnerEnrollmentBodySchema, response: {200: runnerEnrollmentResponseSchema}},\n preHandler: authenticateRunnerControlSession,\n errorHandler: (error) => {\n if (error instanceof RunnerControlSessionInvalidError)\n throw new ClientError(error.message, 'runner-control-session-invalid', {status: 409});\n throw error;\n },\n handler: async (request) => {\n const session = requireRunnerControlSessionContext(request);\n const activationToken = await enrollRunnerControlSession({\n runnerInstanceId: session.runnerInstanceId,\n provisionerId: session.provisionerId,\n labels: request.body.labels,\n ...(request.body.capabilities ? {capabilities: request.body.capabilities} : {}),\n providerKind: request.body.provider_kind,\n protocolVersion: request.body.protocol_version,\n });\n return {activation_token: activationToken};\n },\n});\n\nexport const attachRunnerControlProviderIdRoute = defineRoute({\n method: 'POST',\n path: '/provider-runner',\n description: 'Attach the authenticated runner instance provider identity once',\n schema: {\n body: attachRunnerControlProviderIdBodySchema,\n response: {200: z.object({attached: z.boolean()})},\n },\n preHandler: authenticateRunnerControlSession,\n handler: async (request) => {\n const session = requireRunnerControlSessionContext(request);\n return {\n attached: await attachRunnerControlProviderId({\n ...session,\n providerRunnerId: request.body.provider_runner_id,\n }),\n };\n },\n});\n\nexport const runnerControlHeartbeatRoute = defineRoute({\n method: 'POST',\n path: '/heartbeat',\n description: 'Record liveness for only the authenticated runner instance',\n schema: {response: {200: runnerControlHeartbeatResponseSchema}},\n preHandler: authenticateRunnerControlSession,\n handler: async (request) => {\n const session = requireRunnerControlSessionContext(request);\n await touchRunnerControlSession(session.runnerInstanceId, session.provisionerId);\n runnerControlHeartbeatCount.add(1);\n return {ok: true};\n },\n});\n\ntype RunnerAssignmentPollParams = {\n deadline: number;\n intervalMs: number;\n signal: AbortSignal;\n getAssignment: () => Promise<{workspaceId: string | null; runnerSessionId: string | null} | null>;\n issueActivationToken: () => Promise<string | null>;\n};\n\nexport function resolveRunnerAssignmentPollWaitSeconds(\n requestedWaitSeconds: number | undefined,\n): number {\n return Math.max(\n 1,\n Math.min(\n requestedWaitSeconds ?? config.RUNNER_ASSIGNMENT_POLL_MAX_WAIT_SECONDS,\n config.RUNNER_ASSIGNMENT_POLL_MAX_WAIT_SECONDS,\n ),\n );\n}\n\nexport async function pollForRunnerActivationToken(\n params: RunnerAssignmentPollParams,\n): Promise<string | null> {\n while (Date.now() < params.deadline) {\n if (params.signal.aborted) return null;\n const assignment = await params.getAssignment();\n if (assignment) {\n const activationToken = await params.issueActivationToken();\n if (activationToken) return activationToken;\n }\n const remainingMs = params.deadline - Date.now();\n if (remainingMs <= 0 || params.signal.aborted) return null;\n await new Promise((resolve) => setTimeout(resolve, Math.min(params.intervalMs, remainingMs)));\n }\n return null;\n}\nexport const runnerAssignmentPollRoute = defineRoute({\n method: 'GET',\n path: '/assignment',\n description: 'Wait for only the authenticated runner instance assignment',\n schema: {\n querystring: runnerAssignmentPollQuerySchema,\n response: {200: runnerAssignmentPollResponseSchema},\n },\n preHandler: authenticateRunnerControlSession,\n handler: async (request, reply) => {\n const session = requireRunnerControlSessionContext(request);\n const waitSeconds = resolveRunnerAssignmentPollWaitSeconds(request.query.wait_seconds);\n const deadline = Date.now() + waitSeconds * 1000;\n const abortController = new AbortController();\n reply.raw.on('close', () => abortController.abort());\n const activationToken = await pollForRunnerActivationToken({\n deadline,\n intervalMs: config.RUNNER_ASSIGNMENT_POLL_INTERVAL_MS,\n signal: abortController.signal,\n getAssignment: () => getRunnerAssignment(session),\n issueActivationToken: () =>\n issueRunnerActivationToken({\n ...session,\n ttlSeconds: config.RUNNER_ACTIVATION_TOKEN_TTL_SECONDS,\n surface: 'poll',\n }),\n });\n return {activation_token: activationToken};\n },\n});\n"],"names":["requireProvisionerContext","requireRunnerControlSessionContext","attachRunnerControlProviderIdBodySchema","createRunnerInstancesBodySchema","createRunnerInstancesResponseSchema","runnerAssignmentPollQuerySchema","runnerAssignmentPollResponseSchema","runnerBootstrapExchangeBodySchema","runnerBootstrapExchangeResponseSchema","runnerControlHeartbeatResponseSchema","runnerEnrollmentBodySchema","runnerEnrollmentResponseSchema","ClientError","defineRoute","z","config","getRunnerAssignment","issueRunnerActivationToken","attachRunnerControlProviderId","createRunnerInstancesWithBootstrapTokens","enrollRunnerControlSession","exchangeRunnerBootstrapToken","RunnerBootstrapTokenInvalidError","RunnerControlSessionInvalidError","touchRunnerControlSession","attachRunnerInstanceProviderId","runnerBootstrapExchangeCount","runnerControlHeartbeatCount","authenticateRunnerControlSession","createRunnerInstancesRoute","method","path","description","schema","body","response","handler","request","provisionerTokenId","result","provisionerId","provider_kind","providerKind","runnerInstances","runner_instances","map","runner","template_key","templateKey","reservation_id","reservationId","ttlSeconds","RUNNER_BOOTSTRAP_TOKEN_TTL_SECONDS","runnerInstance","runner_instance_id","runnerInstanceId","bootstrap_token","bootstrapToken","request_index","requestIndex","reservationUnavailable","reservation_unavailable","attachRunnerInstanceProviderIdRoute","params","object","string","uuid","attached","boolean","providerRunnerId","provider_runner_id","exchangeRunnerBootstrapRoute","errorHandler","error","add","outcome","message","status","rawToken","RUNNER_CONTROL_SESSION_TTL_SECONDS","control_session_token","controlSessionToken","expires_at","expiresAt","toISOString","enrollRunnerRoute","preHandler","session","activationToken","labels","capabilities","protocolVersion","protocol_version","activation_token","attachRunnerControlProviderIdRoute","runnerControlHeartbeatRoute","ok","resolveRunnerAssignmentPollWaitSeconds","requestedWaitSeconds","Math","max","min","RUNNER_ASSIGNMENT_POLL_MAX_WAIT_SECONDS","pollForRunnerActivationToken","Date","now","deadline","signal","aborted","assignment","getAssignment","issueActivationToken","remainingMs","Promise","resolve","setTimeout","intervalMs","runnerAssignmentPollRoute","querystring","reply","waitSeconds","query","wait_seconds","abortController","AbortController","raw","on","abort","RUNNER_ASSIGNMENT_POLL_INTERVAL_MS","RUNNER_ACTIVATION_TOKEN_TTL_SECONDS","surface"],"mappings":"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"}