@shipfox/api-runners 10.1.0 → 10.2.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 (118) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/CHANGELOG.md +20 -0
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +8 -13
  5. package/dist/config.js.map +1 -1
  6. package/dist/core/admin-runner-instances.d.ts +34 -0
  7. package/dist/core/admin-runner-instances.d.ts.map +1 -0
  8. package/dist/core/admin-runner-instances.js +58 -0
  9. package/dist/core/admin-runner-instances.js.map +1 -0
  10. package/dist/core/errors.d.ts +6 -0
  11. package/dist/core/errors.d.ts.map +1 -1
  12. package/dist/core/errors.js +12 -0
  13. package/dist/core/errors.js.map +1 -1
  14. package/dist/core/index.d.ts +3 -2
  15. package/dist/core/index.d.ts.map +1 -1
  16. package/dist/core/index.js +3 -2
  17. package/dist/core/index.js.map +1 -1
  18. package/dist/core/provisioner-tokens.d.ts +33 -0
  19. package/dist/core/provisioner-tokens.d.ts.map +1 -1
  20. package/dist/core/provisioner-tokens.js +107 -2
  21. package/dist/core/provisioner-tokens.js.map +1 -1
  22. package/dist/db/admin-runner-instances.d.ts +34 -0
  23. package/dist/db/admin-runner-instances.d.ts.map +1 -0
  24. package/dist/db/admin-runner-instances.js +62 -0
  25. package/dist/db/admin-runner-instances.js.map +1 -0
  26. package/dist/db/db.d.ts +290 -0
  27. package/dist/db/db.d.ts.map +1 -1
  28. package/dist/db/db.js +2 -0
  29. package/dist/db/db.js.map +1 -1
  30. package/dist/db/index.d.ts +3 -1
  31. package/dist/db/index.d.ts.map +1 -1
  32. package/dist/db/index.js +2 -1
  33. package/dist/db/index.js.map +1 -1
  34. package/dist/db/job-executions.d.ts.map +1 -1
  35. package/dist/db/job-executions.js +11 -0
  36. package/dist/db/job-executions.js.map +1 -1
  37. package/dist/db/provisioner-tokens.d.ts +38 -0
  38. package/dist/db/provisioner-tokens.d.ts.map +1 -1
  39. package/dist/db/provisioner-tokens.js +157 -3
  40. package/dist/db/provisioner-tokens.js.map +1 -1
  41. package/dist/db/reservations.d.ts.map +1 -1
  42. package/dist/db/reservations.js +60 -8
  43. package/dist/db/reservations.js.map +1 -1
  44. package/dist/db/schema/admin-command-results.d.ts +134 -0
  45. package/dist/db/schema/admin-command-results.d.ts.map +1 -0
  46. package/dist/db/schema/admin-command-results.js +18 -0
  47. package/dist/db/schema/admin-command-results.js.map +1 -0
  48. package/dist/db/schema/runner-instances.d.ts +17 -0
  49. package/dist/db/schema/runner-instances.d.ts.map +1 -1
  50. package/dist/db/schema/runner-instances.js +3 -0
  51. package/dist/db/schema/runner-instances.js.map +1 -1
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +6 -1
  54. package/dist/index.js.map +1 -1
  55. package/dist/presentation/dto/admin-provisioner-token.d.ts +16 -0
  56. package/dist/presentation/dto/admin-provisioner-token.d.ts.map +1 -0
  57. package/dist/presentation/dto/admin-provisioner-token.js +22 -0
  58. package/dist/presentation/dto/admin-provisioner-token.js.map +1 -0
  59. package/dist/presentation/dto/admin-runner-instances.d.ts +23 -0
  60. package/dist/presentation/dto/admin-runner-instances.d.ts.map +1 -0
  61. package/dist/presentation/dto/admin-runner-instances.js +19 -0
  62. package/dist/presentation/dto/admin-runner-instances.js.map +1 -0
  63. package/dist/presentation/dto/index.d.ts +2 -0
  64. package/dist/presentation/dto/index.d.ts.map +1 -1
  65. package/dist/presentation/dto/index.js +2 -0
  66. package/dist/presentation/dto/index.js.map +1 -1
  67. package/dist/presentation/routes/admin-provisioner-tokens.d.ts +4 -0
  68. package/dist/presentation/routes/admin-provisioner-tokens.d.ts.map +1 -0
  69. package/dist/presentation/routes/admin-provisioner-tokens.js +167 -0
  70. package/dist/presentation/routes/admin-provisioner-tokens.js.map +1 -0
  71. package/dist/presentation/routes/admin-runner-instances.d.ts +3 -0
  72. package/dist/presentation/routes/admin-runner-instances.d.ts.map +1 -0
  73. package/dist/presentation/routes/admin-runner-instances.js +63 -0
  74. package/dist/presentation/routes/admin-runner-instances.js.map +1 -0
  75. package/dist/presentation/routes/index.d.ts.map +1 -1
  76. package/dist/presentation/routes/index.js +11 -1
  77. package/dist/presentation/routes/index.js.map +1 -1
  78. package/dist/presentation/routes/runner-enrollment.d.ts +1 -0
  79. package/dist/presentation/routes/runner-enrollment.d.ts.map +1 -1
  80. package/dist/presentation/routes/runner-enrollment.js +11 -4
  81. package/dist/presentation/routes/runner-enrollment.js.map +1 -1
  82. package/dist/tsconfig.test.tsbuildinfo +1 -1
  83. package/drizzle/0002_special_shadowcat.sql +1 -0
  84. package/drizzle/0003_flaky_sally_floyd.sql +11 -0
  85. package/drizzle/meta/0002_snapshot.json +2099 -0
  86. package/drizzle/meta/0003_snapshot.json +2178 -0
  87. package/drizzle/meta/_journal.json +14 -0
  88. package/package.json +8 -7
  89. package/src/config.test.ts +11 -0
  90. package/src/config.ts +19 -8
  91. package/src/core/admin-runner-instances.ts +125 -0
  92. package/src/core/errors.ts +14 -0
  93. package/src/core/index.ts +12 -0
  94. package/src/core/provisioner-tokens.ts +157 -1
  95. package/src/db/admin-runner-instances.ts +121 -0
  96. package/src/db/db.ts +2 -0
  97. package/src/db/index.ts +10 -0
  98. package/src/db/job-executions.test.ts +17 -0
  99. package/src/db/job-executions.ts +22 -0
  100. package/src/db/provisioner-tokens.ts +263 -9
  101. package/src/db/reservations.test.ts +253 -0
  102. package/src/db/reservations.ts +170 -15
  103. package/src/db/schema/admin-command-results.ts +29 -0
  104. package/src/db/schema/runner-instances.ts +1 -0
  105. package/src/index.test.ts +1 -1
  106. package/src/index.ts +6 -1
  107. package/src/presentation/dto/admin-provisioner-token.ts +23 -0
  108. package/src/presentation/dto/admin-runner-instances.ts +19 -0
  109. package/src/presentation/dto/index.ts +2 -0
  110. package/src/presentation/routes/admin-provisioner-tokens.test.ts +227 -0
  111. package/src/presentation/routes/admin-provisioner-tokens.ts +177 -0
  112. package/src/presentation/routes/admin-runner-instances.test.ts +671 -0
  113. package/src/presentation/routes/admin-runner-instances.ts +67 -0
  114. package/src/presentation/routes/index.ts +8 -0
  115. package/src/presentation/routes/runner-enrollment.test.ts +60 -2
  116. package/src/presentation/routes/runner-enrollment.ts +24 -4
  117. package/test/globalSetup.ts +1 -0
  118. package/tsconfig.build.tsbuildinfo +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/presentation/routes/admin-provisioner-tokens.ts"],"sourcesContent":["import {AUTH_USER, requireUserContext} from '@shipfox/api-auth-context';\nimport {\n type AuthInterModuleClient,\n authInterModuleContract,\n} from '@shipfox/api-auth-dto/inter-module';\nimport {\n createAdministratorProvisionerTokenBodySchema,\n createAdministratorProvisionerTokenResponseSchema,\n listAdministratorProvisionerTokensQuerySchema,\n listAdministratorProvisionerTokensResponseSchema,\n revokeAdministratorProvisionerTokenBodySchema,\n revokeAdministratorProvisionerTokenResponseSchema,\n} from '@shipfox/api-runners-dto';\nimport {isInterModuleKnownError} from '@shipfox/inter-module';\nimport {decodeTimestampIdCursor, encodeTimestampIdCursor} from '@shipfox/node-drizzle';\nimport {ClientError, defineRoute, type RouteGroup} from '@shipfox/node-fastify';\nimport {z} from 'zod';\nimport {\n createAdministratorInstallationProvisionerToken,\n listAdministratorInstallationProvisionerTokens,\n ProvisionerAdminIdempotencyKeyReuseError,\n ProvisionerAdminIdempotencyReplayUnavailableError,\n ProvisionerTokenNotFoundError,\n revokeAdministratorInstallationProvisionerToken,\n} from '#core/index.js';\nimport {toAdministratorProvisionerTokenDto} from '#presentation/dto/index.js';\n\nconst idempotencyKeyMaxLength = 256;\n\nfunction requireIdempotencyKey(request: {headers: Record<string, string | string[] | undefined>}) {\n const value = request.headers['idempotency-key'];\n const key = Array.isArray(value) ? value[0] : value;\n if (!key || key.trim().length === 0 || key.length > idempotencyKeyMaxLength) {\n throw new ClientError('Idempotency-Key header is required', 'idempotency-key-required', {\n status: 400,\n });\n }\n return key;\n}\n\nfunction translateAdministrationError(error: unknown): never {\n if (\n isInterModuleKnownError(authInterModuleContract.methods.requireAdminRole, error) &&\n error.code === 'admin-role-required'\n ) {\n throw new ClientError('Administrator role required', 'forbidden', {\n status: 403,\n details: {required_role: error.details.requiredRole},\n });\n }\n if (error instanceof ProvisionerAdminIdempotencyKeyReuseError) {\n throw new ClientError(\n 'Idempotency-Key was already used for a different provisioner token command',\n 'idempotency-key-reused',\n {status: 409},\n );\n }\n if (error instanceof ProvisionerAdminIdempotencyReplayUnavailableError) {\n throw new ClientError(\n 'Idempotency-Key replay cannot reproduce the original provisioner token',\n 'idempotency-replay-unavailable',\n {status: 409},\n );\n }\n if (error instanceof ProvisionerTokenNotFoundError) {\n throw new ClientError('Installation provisioner token not found', 'not-found', {\n status: 404,\n });\n }\n throw error;\n}\n\nexport function createAdminProvisionerTokenRoutes(\n auth: Pick<AuthInterModuleClient, 'requireAdminRole'>,\n): RouteGroup {\n const listRoute = defineRoute({\n method: 'GET',\n path: '/',\n auth: AUTH_USER,\n description: 'List bounded installation provisioner token metadata for administrators.',\n schema: {\n querystring: listAdministratorProvisionerTokensQuerySchema,\n response: {200: listAdministratorProvisionerTokensResponseSchema},\n },\n errorHandler: translateAdministrationError,\n handler: async (request) => {\n const actor = requireUserContext(request);\n await auth.requireAdminRole({userId: actor.userId, minimumRole: 'admin-observer'});\n const {status, limit, cursor} = request.query;\n const decodedCursor = decodeTimestampIdCursor(cursor);\n if (cursor !== undefined && !decodedCursor) {\n throw new ClientError('Invalid cursor', 'invalid-cursor', {status: 400});\n }\n const result = await listAdministratorInstallationProvisionerTokens({\n status,\n limit,\n ...(decodedCursor ? {cursor: decodedCursor} : {}),\n });\n return {\n tokens: result.tokens.map(toAdministratorProvisionerTokenDto),\n next_cursor: result.nextCursor ? encodeTimestampIdCursor(result.nextCursor) : null,\n };\n },\n });\n\n const createRoute = defineRoute({\n method: 'POST',\n path: '/',\n auth: AUTH_USER,\n description: 'Create an installation-wide provisioner token for administrators.',\n schema: {\n body: createAdministratorProvisionerTokenBodySchema,\n response: {201: createAdministratorProvisionerTokenResponseSchema},\n },\n errorHandler: translateAdministrationError,\n handler: async (request, reply) => {\n const actor = requireUserContext(request);\n const role = await auth.requireAdminRole({\n userId: actor.userId,\n minimumRole: 'admin-owner',\n });\n const result = await createAdministratorInstallationProvisionerToken({\n actorId: actor.userId,\n actorRole: role.role,\n idempotencyKey: requireIdempotencyKey(request),\n correlationId: request.id,\n reason: request.body.reason,\n name: request.body.name,\n ttlSeconds: request.body.ttl_seconds,\n });\n reply.code(201);\n return {\n ...toAdministratorProvisionerTokenDto(result.token),\n raw_token: result.rawToken,\n correlation_id: result.correlationId,\n };\n },\n });\n\n const revokeRoute = defineRoute({\n method: 'POST',\n path: '/:tokenId/revoke',\n auth: AUTH_USER,\n description: 'Revoke an installation provisioner token and its unclaimed descendants.',\n schema: {\n params: z.object({tokenId: z.string().uuid()}),\n body: revokeAdministratorProvisionerTokenBodySchema,\n response: {200: revokeAdministratorProvisionerTokenResponseSchema},\n },\n errorHandler: translateAdministrationError,\n handler: async (request) => {\n const actor = requireUserContext(request);\n const role = await auth.requireAdminRole({\n userId: actor.userId,\n minimumRole: 'admin-operator',\n });\n const result = await revokeAdministratorInstallationProvisionerToken({\n actorId: actor.userId,\n actorRole: role.role,\n tokenId: request.params.tokenId,\n idempotencyKey: requireIdempotencyKey(request),\n correlationId: request.id,\n reason: request.body.reason,\n });\n return {\n ...toAdministratorProvisionerTokenDto(result.token),\n correlation_id: result.correlationId,\n };\n },\n });\n\n return {\n prefix: '/admin/runners/provisioner-tokens',\n auth: AUTH_USER,\n routes: [listRoute, createRoute, revokeRoute],\n };\n}\n"],"names":["AUTH_USER","requireUserContext","authInterModuleContract","createAdministratorProvisionerTokenBodySchema","createAdministratorProvisionerTokenResponseSchema","listAdministratorProvisionerTokensQuerySchema","listAdministratorProvisionerTokensResponseSchema","revokeAdministratorProvisionerTokenBodySchema","revokeAdministratorProvisionerTokenResponseSchema","isInterModuleKnownError","decodeTimestampIdCursor","encodeTimestampIdCursor","ClientError","defineRoute","z","createAdministratorInstallationProvisionerToken","listAdministratorInstallationProvisionerTokens","ProvisionerAdminIdempotencyKeyReuseError","ProvisionerAdminIdempotencyReplayUnavailableError","ProvisionerTokenNotFoundError","revokeAdministratorInstallationProvisionerToken","toAdministratorProvisionerTokenDto","idempotencyKeyMaxLength","requireIdempotencyKey","request","value","headers","key","Array","isArray","trim","length","status","translateAdministrationError","error","methods","requireAdminRole","code","details","required_role","requiredRole","createAdminProvisionerTokenRoutes","auth","listRoute","method","path","description","schema","querystring","response","errorHandler","handler","actor","userId","minimumRole","limit","cursor","query","decodedCursor","undefined","result","tokens","map","next_cursor","nextCursor","createRoute","body","reply","role","actorId","actorRole","idempotencyKey","correlationId","id","reason","name","ttlSeconds","ttl_seconds","token","raw_token","rawToken","correlation_id","revokeRoute","params","object","tokenId","string","uuid","prefix","routes"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type AuthInterModuleClient } from '@shipfox/api-auth-dto/inter-module';
2
+ export declare function createAdminRunnerInstancesRoute(auth: Pick<AuthInterModuleClient, 'requireAdminRole'>): import("@shipfox/node-fastify").RouteDefinition;
3
+ //# sourceMappingURL=admin-runner-instances.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-runner-instances.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/admin-runner-instances.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,qBAAqB,EAE3B,MAAM,oCAAoC,CAAC;AAyB5C,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,IAAI,CAAC,qBAAqB,EAAE,kBAAkB,CAAC,mDAoCtD"}
@@ -0,0 +1,63 @@
1
+ import { AUTH_USER, requireUserContext } from '@shipfox/api-auth-context';
2
+ import { authInterModuleContract } from '@shipfox/api-auth-dto/inter-module';
3
+ import { listRunnerAdministratorInstancesQuerySchema, listRunnerAdministratorInstancesResponseSchema } from '@shipfox/api-runners-dto';
4
+ import { isInterModuleKnownError } from '@shipfox/inter-module';
5
+ import { decodeTimestampIdCursor, encodeTimestampIdCursor } from '@shipfox/node-drizzle';
6
+ import { ClientError, defineRoute } from '@shipfox/node-fastify';
7
+ import { listRunnerAdministratorInstances } from '#core/admin-runner-instances.js';
8
+ import { toRunnerAdministratorInstanceDto } from '#presentation/dto/admin-runner-instances.js';
9
+ function translateAdminRunnerInstancesRouteError(error) {
10
+ if (isInterModuleKnownError(authInterModuleContract.methods.requireAdminRole, error) && error.code === 'admin-role-required') {
11
+ throw new ClientError('Administrator observer role required', 'forbidden', {
12
+ status: 403,
13
+ details: {
14
+ required_role: error.details.requiredRole
15
+ }
16
+ });
17
+ }
18
+ throw error;
19
+ }
20
+ export function createAdminRunnerInstancesRoute(auth) {
21
+ return defineRoute({
22
+ method: 'GET',
23
+ path: '/',
24
+ auth: AUTH_USER,
25
+ description: 'List bounded safe installation-managed runner instances for administrators.',
26
+ schema: {
27
+ querystring: listRunnerAdministratorInstancesQuerySchema,
28
+ response: {
29
+ 200: listRunnerAdministratorInstancesResponseSchema
30
+ }
31
+ },
32
+ errorHandler: translateAdminRunnerInstancesRouteError,
33
+ handler: async (request)=>{
34
+ const actor = requireUserContext(request);
35
+ await auth.requireAdminRole({
36
+ userId: actor.userId,
37
+ minimumRole: 'admin-observer'
38
+ });
39
+ const { state, assignment, label, limit, cursor } = request.query;
40
+ const decodedCursor = decodeTimestampIdCursor(cursor);
41
+ if (cursor !== undefined && !decodedCursor) {
42
+ throw new ClientError('Invalid cursor', 'invalid-cursor', {
43
+ status: 400
44
+ });
45
+ }
46
+ const result = await listRunnerAdministratorInstances({
47
+ state,
48
+ assignment,
49
+ label,
50
+ limit,
51
+ ...decodedCursor ? {
52
+ cursor: decodedCursor
53
+ } : {}
54
+ });
55
+ return {
56
+ runners: result.runners.map(toRunnerAdministratorInstanceDto),
57
+ next_cursor: result.nextCursor ? encodeTimestampIdCursor(result.nextCursor) : null
58
+ };
59
+ }
60
+ });
61
+ }
62
+
63
+ //# sourceMappingURL=admin-runner-instances.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/presentation/routes/admin-runner-instances.ts"],"sourcesContent":["import {AUTH_USER, requireUserContext} from '@shipfox/api-auth-context';\nimport {\n type AuthInterModuleClient,\n authInterModuleContract,\n} from '@shipfox/api-auth-dto/inter-module';\nimport {\n listRunnerAdministratorInstancesQuerySchema,\n listRunnerAdministratorInstancesResponseSchema,\n} from '@shipfox/api-runners-dto';\nimport {isInterModuleKnownError} from '@shipfox/inter-module';\nimport {decodeTimestampIdCursor, encodeTimestampIdCursor} from '@shipfox/node-drizzle';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {listRunnerAdministratorInstances} from '#core/admin-runner-instances.js';\nimport {toRunnerAdministratorInstanceDto} from '#presentation/dto/admin-runner-instances.js';\n\nfunction translateAdminRunnerInstancesRouteError(error: unknown): never {\n if (\n isInterModuleKnownError(authInterModuleContract.methods.requireAdminRole, error) &&\n error.code === 'admin-role-required'\n ) {\n throw new ClientError('Administrator observer role required', 'forbidden', {\n status: 403,\n details: {required_role: error.details.requiredRole},\n });\n }\n\n throw error;\n}\n\nexport function createAdminRunnerInstancesRoute(\n auth: Pick<AuthInterModuleClient, 'requireAdminRole'>,\n) {\n return defineRoute({\n method: 'GET',\n path: '/',\n auth: AUTH_USER,\n description: 'List bounded safe installation-managed runner instances for administrators.',\n schema: {\n querystring: listRunnerAdministratorInstancesQuerySchema,\n response: {200: listRunnerAdministratorInstancesResponseSchema},\n },\n errorHandler: translateAdminRunnerInstancesRouteError,\n handler: async (request) => {\n const actor = requireUserContext(request);\n await auth.requireAdminRole({userId: actor.userId, minimumRole: 'admin-observer'});\n\n const {state, assignment, label, limit, cursor} = request.query;\n const decodedCursor = decodeTimestampIdCursor(cursor);\n if (cursor !== undefined && !decodedCursor) {\n throw new ClientError('Invalid cursor', 'invalid-cursor', {status: 400});\n }\n\n const result = await listRunnerAdministratorInstances({\n state,\n assignment,\n label,\n limit,\n ...(decodedCursor ? {cursor: decodedCursor} : {}),\n });\n\n return {\n runners: result.runners.map(toRunnerAdministratorInstanceDto),\n next_cursor: result.nextCursor ? encodeTimestampIdCursor(result.nextCursor) : null,\n };\n },\n });\n}\n"],"names":["AUTH_USER","requireUserContext","authInterModuleContract","listRunnerAdministratorInstancesQuerySchema","listRunnerAdministratorInstancesResponseSchema","isInterModuleKnownError","decodeTimestampIdCursor","encodeTimestampIdCursor","ClientError","defineRoute","listRunnerAdministratorInstances","toRunnerAdministratorInstanceDto","translateAdminRunnerInstancesRouteError","error","methods","requireAdminRole","code","status","details","required_role","requiredRole","createAdminRunnerInstancesRoute","auth","method","path","description","schema","querystring","response","errorHandler","handler","request","actor","userId","minimumRole","state","assignment","label","limit","cursor","query","decodedCursor","undefined","result","runners","map","next_cursor","nextCursor"],"mappings":"AAAA,SAAQA,SAAS,EAAEC,kBAAkB,QAAO,4BAA4B;AACxE,SAEEC,uBAAuB,QAClB,qCAAqC;AAC5C,SACEC,2CAA2C,EAC3CC,8CAA8C,QACzC,2BAA2B;AAClC,SAAQC,uBAAuB,QAAO,wBAAwB;AAC9D,SAAQC,uBAAuB,EAAEC,uBAAuB,QAAO,wBAAwB;AACvF,SAAQC,WAAW,EAAEC,WAAW,QAAO,wBAAwB;AAC/D,SAAQC,gCAAgC,QAAO,kCAAkC;AACjF,SAAQC,gCAAgC,QAAO,8CAA8C;AAE7F,SAASC,wCAAwCC,KAAc;IAC7D,IACER,wBAAwBH,wBAAwBY,OAAO,CAACC,gBAAgB,EAAEF,UAC1EA,MAAMG,IAAI,KAAK,uBACf;QACA,MAAM,IAAIR,YAAY,wCAAwC,aAAa;YACzES,QAAQ;YACRC,SAAS;gBAACC,eAAeN,MAAMK,OAAO,CAACE,YAAY;YAAA;QACrD;IACF;IAEA,MAAMP;AACR;AAEA,OAAO,SAASQ,gCACdC,IAAqD;IAErD,OAAOb,YAAY;QACjBc,QAAQ;QACRC,MAAM;QACNF,MAAMtB;QACNyB,aAAa;QACbC,QAAQ;YACNC,aAAaxB;YACbyB,UAAU;gBAAC,KAAKxB;YAA8C;QAChE;QACAyB,cAAcjB;QACdkB,SAAS,OAAOC;YACd,MAAMC,QAAQ/B,mBAAmB8B;YACjC,MAAMT,KAAKP,gBAAgB,CAAC;gBAACkB,QAAQD,MAAMC,MAAM;gBAAEC,aAAa;YAAgB;YAEhF,MAAM,EAACC,KAAK,EAAEC,UAAU,EAAEC,KAAK,EAAEC,KAAK,EAAEC,MAAM,EAAC,GAAGR,QAAQS,KAAK;YAC/D,MAAMC,gBAAgBnC,wBAAwBiC;YAC9C,IAAIA,WAAWG,aAAa,CAACD,eAAe;gBAC1C,MAAM,IAAIjC,YAAY,kBAAkB,kBAAkB;oBAACS,QAAQ;gBAAG;YACxE;YAEA,MAAM0B,SAAS,MAAMjC,iCAAiC;gBACpDyB;gBACAC;gBACAC;gBACAC;gBACA,GAAIG,gBAAgB;oBAACF,QAAQE;gBAAa,IAAI,CAAC,CAAC;YAClD;YAEA,OAAO;gBACLG,SAASD,OAAOC,OAAO,CAACC,GAAG,CAAClC;gBAC5BmC,aAAaH,OAAOI,UAAU,GAAGxC,wBAAwBoC,OAAOI,UAAU,IAAI;YAChF;QACF;IACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,oCAAoC,CAAC;AAC9E,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAC,0BAA0B,EAAC,MAAM,+BAA+B,CAAC;AAsF9E,eAAO,MAAM,iBAAiB,EAAE,UAAU,EAgBzC,CAAC;AAEF,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,qBAAqB,EAC3B,OAAO,GAAE,0BAA+B,GACvC,UAAU,EAAE,CAgBd"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,oCAAoC,CAAC;AAC9E,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAC,0BAA0B,EAAC,MAAM,+BAA+B,CAAC;AA8F9E,eAAO,MAAM,iBAAiB,EAAE,UAAU,EAgBzC,CAAC;AAEF,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,qBAAqB,EAC3B,OAAO,GAAE,0BAA+B,GACvC,UAAU,EAAE,CAgBd"}
@@ -1,4 +1,6 @@
1
1
  import { AUTH_LEASED_JOB, AUTH_PROVISIONER_TOKEN, AUTH_RUNNER_REGISTRATION_TOKEN, AUTH_RUNNER_SESSION, AUTH_USER } from '@shipfox/api-auth-context';
2
+ import { createAdminProvisionerTokenRoutes } from './admin-provisioner-tokens.js';
3
+ import { createAdminRunnerInstancesRoute } from './admin-runner-instances.js';
2
4
  import { assignRunnerInstancesRoute } from './assign-runner-instances.js';
3
5
  import { createManualRegistrationTokenRoute } from './create-manual-registration-token.js';
4
6
  import { createProvisionerTokenRoute } from './create-provisioner-token.js';
@@ -66,7 +68,15 @@ function createRunnerOnlyRoutes(auth) {
66
68
  reportRunnerInstancesRoute,
67
69
  reconcileRunnerInstancesRoute
68
70
  ]
69
- }
71
+ },
72
+ {
73
+ prefix: '/admin/runners/instances',
74
+ auth: AUTH_USER,
75
+ routes: [
76
+ createAdminRunnerInstancesRoute(auth)
77
+ ]
78
+ },
79
+ createAdminProvisionerTokenRoutes(auth)
70
80
  ];
71
81
  }
72
82
  const runnerControlRoutes = [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/routes/index.ts"],"sourcesContent":["import {\n AUTH_LEASED_JOB,\n AUTH_PROVISIONER_TOKEN,\n AUTH_RUNNER_REGISTRATION_TOKEN,\n AUTH_RUNNER_SESSION,\n AUTH_USER,\n} from '@shipfox/api-auth-context';\nimport type {AuthInterModuleClient} from '@shipfox/api-auth-dto/inter-module';\nimport type {RouteGroup} from '@shipfox/node-fastify';\nimport type {CreateRunnersModuleOptions} from '#installation-provisioning.js';\nimport {assignRunnerInstancesRoute} from './assign-runner-instances.js';\nimport {createManualRegistrationTokenRoute} from './create-manual-registration-token.js';\nimport {createProvisionerTokenRoute} from './create-provisioner-token.js';\nimport {getProvisionerMeRoute} from './get-provisioner-me.js';\nimport {createHeartbeatRoute} from './heartbeat.js';\nimport {listActiveProvisionersRoute} from './list-active-provisioners.js';\nimport {listActiveRunnersRoute} from './list-active-runners.js';\nimport {listManualRegistrationTokensRoute} from './list-manual-registration-tokens.js';\nimport {listProvisionerTokensRoute} from './list-provisioner-tokens.js';\nimport {createPollDemandRoute, pollDemandRoute} from './poll-demand.js';\nimport {reconcileRunnerInstancesRoute} from './reconcile-runner-instances.js';\nimport {createRegisterRoute} from './register.js';\nimport {reportRunnerInstancesRoute} from './report-runner-instances.js';\nimport {createRequestJobRoute} from './request-job.js';\nimport {revokeManualRegistrationTokenRoute} from './revoke-manual-registration-token.js';\nimport {revokeProvisionerTokenRoute} from './revoke-provisioner-token.js';\nimport {\n attachRunnerControlProviderIdRoute,\n attachRunnerInstanceProviderIdRoute,\n createRunnerInstancesRoute,\n enrollRunnerRoute,\n exchangeRunnerBootstrapRoute,\n runnerAssignmentPollRoute,\n runnerControlHeartbeatRoute,\n} from './runner-enrollment.js';\n\nfunction createRunnerOnlyRoutes(auth: AuthInterModuleClient): RouteGroup[] {\n return [\n {\n prefix: '/workspaces/:workspaceId/runners/manual-registration-tokens',\n auth: AUTH_USER,\n routes: [\n listManualRegistrationTokensRoute,\n createManualRegistrationTokenRoute,\n revokeManualRegistrationTokenRoute,\n ],\n },\n {\n prefix: '/workspaces/:workspaceId/runners/active',\n auth: AUTH_USER,\n routes: [listActiveRunnersRoute],\n },\n {\n prefix: '/runners',\n auth: AUTH_RUNNER_REGISTRATION_TOKEN,\n routes: [createRegisterRoute(auth)],\n },\n {\n prefix: '/runners/jobs',\n auth: AUTH_RUNNER_SESSION,\n routes: [createRequestJobRoute(auth)],\n },\n {\n prefix: '/runners/jobs',\n auth: AUTH_LEASED_JOB,\n routes: [createHeartbeatRoute(auth)],\n },\n {\n prefix: '/provisioners',\n auth: AUTH_PROVISIONER_TOKEN,\n routes: [\n pollDemandRoute,\n createRunnerInstancesRoute,\n attachRunnerInstanceProviderIdRoute,\n assignRunnerInstancesRoute,\n reportRunnerInstancesRoute,\n reconcileRunnerInstancesRoute,\n ],\n },\n ];\n}\n\nconst runnerControlRoutes: RouteGroup[] = [\n {prefix: '/runner-enrollment', routes: [exchangeRunnerBootstrapRoute]},\n {\n prefix: '/runner-control',\n routes: [\n enrollRunnerRoute,\n attachRunnerControlProviderIdRoute,\n runnerControlHeartbeatRoute,\n runnerAssignmentPollRoute,\n ],\n },\n];\n\nexport const provisionerRoutes: RouteGroup[] = [\n {\n prefix: '/workspaces/:workspaceId/provisioners/tokens',\n auth: AUTH_USER,\n routes: [listProvisionerTokensRoute, createProvisionerTokenRoute, revokeProvisionerTokenRoute],\n },\n {\n prefix: '/workspaces/:workspaceId/provisioners/active',\n auth: AUTH_USER,\n routes: [listActiveProvisionersRoute],\n },\n {\n prefix: '/provisioners',\n auth: AUTH_PROVISIONER_TOKEN,\n routes: [getProvisionerMeRoute],\n },\n];\n\nexport function createRunnerRoutes(\n auth: AuthInterModuleClient,\n options: CreateRunnersModuleOptions = {},\n): RouteGroup[] {\n const runnerOnlyRoutes = createRunnerOnlyRoutes(auth);\n return [\n ...runnerOnlyRoutes.map((route) =>\n route.routes.includes(pollDemandRoute)\n ? {\n ...route,\n routes: route.routes.map((r) =>\n r === pollDemandRoute ? createPollDemandRoute(options) : r,\n ),\n }\n : route,\n ),\n ...runnerControlRoutes,\n ...provisionerRoutes,\n ];\n}\n"],"names":["AUTH_LEASED_JOB","AUTH_PROVISIONER_TOKEN","AUTH_RUNNER_REGISTRATION_TOKEN","AUTH_RUNNER_SESSION","AUTH_USER","assignRunnerInstancesRoute","createManualRegistrationTokenRoute","createProvisionerTokenRoute","getProvisionerMeRoute","createHeartbeatRoute","listActiveProvisionersRoute","listActiveRunnersRoute","listManualRegistrationTokensRoute","listProvisionerTokensRoute","createPollDemandRoute","pollDemandRoute","reconcileRunnerInstancesRoute","createRegisterRoute","reportRunnerInstancesRoute","createRequestJobRoute","revokeManualRegistrationTokenRoute","revokeProvisionerTokenRoute","attachRunnerControlProviderIdRoute","attachRunnerInstanceProviderIdRoute","createRunnerInstancesRoute","enrollRunnerRoute","exchangeRunnerBootstrapRoute","runnerAssignmentPollRoute","runnerControlHeartbeatRoute","createRunnerOnlyRoutes","auth","prefix","routes","runnerControlRoutes","provisionerRoutes","createRunnerRoutes","options","runnerOnlyRoutes","map","route","includes","r"],"mappings":"AAAA,SACEA,eAAe,EACfC,sBAAsB,EACtBC,8BAA8B,EAC9BC,mBAAmB,EACnBC,SAAS,QACJ,4BAA4B;AAInC,SAAQC,0BAA0B,QAAO,+BAA+B;AACxE,SAAQC,kCAAkC,QAAO,wCAAwC;AACzF,SAAQC,2BAA2B,QAAO,gCAAgC;AAC1E,SAAQC,qBAAqB,QAAO,0BAA0B;AAC9D,SAAQC,oBAAoB,QAAO,iBAAiB;AACpD,SAAQC,2BAA2B,QAAO,gCAAgC;AAC1E,SAAQC,sBAAsB,QAAO,2BAA2B;AAChE,SAAQC,iCAAiC,QAAO,uCAAuC;AACvF,SAAQC,0BAA0B,QAAO,+BAA+B;AACxE,SAAQC,qBAAqB,EAAEC,eAAe,QAAO,mBAAmB;AACxE,SAAQC,6BAA6B,QAAO,kCAAkC;AAC9E,SAAQC,mBAAmB,QAAO,gBAAgB;AAClD,SAAQC,0BAA0B,QAAO,+BAA+B;AACxE,SAAQC,qBAAqB,QAAO,mBAAmB;AACvD,SAAQC,kCAAkC,QAAO,wCAAwC;AACzF,SAAQC,2BAA2B,QAAO,gCAAgC;AAC1E,SACEC,kCAAkC,EAClCC,mCAAmC,EACnCC,0BAA0B,EAC1BC,iBAAiB,EACjBC,4BAA4B,EAC5BC,yBAAyB,EACzBC,2BAA2B,QACtB,yBAAyB;AAEhC,SAASC,uBAAuBC,IAA2B;IACzD,OAAO;QACL;YACEC,QAAQ;YACRD,MAAM1B;YACN4B,QAAQ;gBACNpB;gBACAN;gBACAc;aACD;QACH;QACA;YACEW,QAAQ;YACRD,MAAM1B;YACN4B,QAAQ;gBAACrB;aAAuB;QAClC;QACA;YACEoB,QAAQ;YACRD,MAAM5B;YACN8B,QAAQ;gBAACf,oBAAoBa;aAAM;QACrC;QACA;YACEC,QAAQ;YACRD,MAAM3B;YACN6B,QAAQ;gBAACb,sBAAsBW;aAAM;QACvC;QACA;YACEC,QAAQ;YACRD,MAAM9B;YACNgC,QAAQ;gBAACvB,qBAAqBqB;aAAM;QACtC;QACA;YACEC,QAAQ;YACRD,MAAM7B;YACN+B,QAAQ;gBACNjB;gBACAS;gBACAD;gBACAlB;gBACAa;gBACAF;aACD;QACH;KACD;AACH;AAEA,MAAMiB,sBAAoC;IACxC;QAACF,QAAQ;QAAsBC,QAAQ;YAACN;SAA6B;IAAA;IACrE;QACEK,QAAQ;QACRC,QAAQ;YACNP;YACAH;YACAM;YACAD;SACD;IACH;CACD;AAED,OAAO,MAAMO,oBAAkC;IAC7C;QACEH,QAAQ;QACRD,MAAM1B;QACN4B,QAAQ;YAACnB;YAA4BN;YAA6Bc;SAA4B;IAChG;IACA;QACEU,QAAQ;QACRD,MAAM1B;QACN4B,QAAQ;YAACtB;SAA4B;IACvC;IACA;QACEqB,QAAQ;QACRD,MAAM7B;QACN+B,QAAQ;YAACxB;SAAsB;IACjC;CACD,CAAC;AAEF,OAAO,SAAS2B,mBACdL,IAA2B,EAC3BM,UAAsC,CAAC,CAAC;IAExC,MAAMC,mBAAmBR,uBAAuBC;IAChD,OAAO;WACFO,iBAAiBC,GAAG,CAAC,CAACC,QACvBA,MAAMP,MAAM,CAACQ,QAAQ,CAACzB,mBAClB;gBACE,GAAGwB,KAAK;gBACRP,QAAQO,MAAMP,MAAM,CAACM,GAAG,CAAC,CAACG,IACxBA,MAAM1B,kBAAkBD,sBAAsBsB,WAAWK;YAE7D,IACAF;WAEHN;WACAC;KACJ;AACH"}
1
+ {"version":3,"sources":["../../../src/presentation/routes/index.ts"],"sourcesContent":["import {\n AUTH_LEASED_JOB,\n AUTH_PROVISIONER_TOKEN,\n AUTH_RUNNER_REGISTRATION_TOKEN,\n AUTH_RUNNER_SESSION,\n AUTH_USER,\n} from '@shipfox/api-auth-context';\nimport type {AuthInterModuleClient} from '@shipfox/api-auth-dto/inter-module';\nimport type {RouteGroup} from '@shipfox/node-fastify';\nimport type {CreateRunnersModuleOptions} from '#installation-provisioning.js';\nimport {createAdminProvisionerTokenRoutes} from './admin-provisioner-tokens.js';\nimport {createAdminRunnerInstancesRoute} from './admin-runner-instances.js';\nimport {assignRunnerInstancesRoute} from './assign-runner-instances.js';\nimport {createManualRegistrationTokenRoute} from './create-manual-registration-token.js';\nimport {createProvisionerTokenRoute} from './create-provisioner-token.js';\nimport {getProvisionerMeRoute} from './get-provisioner-me.js';\nimport {createHeartbeatRoute} from './heartbeat.js';\nimport {listActiveProvisionersRoute} from './list-active-provisioners.js';\nimport {listActiveRunnersRoute} from './list-active-runners.js';\nimport {listManualRegistrationTokensRoute} from './list-manual-registration-tokens.js';\nimport {listProvisionerTokensRoute} from './list-provisioner-tokens.js';\nimport {createPollDemandRoute, pollDemandRoute} from './poll-demand.js';\nimport {reconcileRunnerInstancesRoute} from './reconcile-runner-instances.js';\nimport {createRegisterRoute} from './register.js';\nimport {reportRunnerInstancesRoute} from './report-runner-instances.js';\nimport {createRequestJobRoute} from './request-job.js';\nimport {revokeManualRegistrationTokenRoute} from './revoke-manual-registration-token.js';\nimport {revokeProvisionerTokenRoute} from './revoke-provisioner-token.js';\nimport {\n attachRunnerControlProviderIdRoute,\n attachRunnerInstanceProviderIdRoute,\n createRunnerInstancesRoute,\n enrollRunnerRoute,\n exchangeRunnerBootstrapRoute,\n runnerAssignmentPollRoute,\n runnerControlHeartbeatRoute,\n} from './runner-enrollment.js';\n\nfunction createRunnerOnlyRoutes(auth: AuthInterModuleClient): RouteGroup[] {\n return [\n {\n prefix: '/workspaces/:workspaceId/runners/manual-registration-tokens',\n auth: AUTH_USER,\n routes: [\n listManualRegistrationTokensRoute,\n createManualRegistrationTokenRoute,\n revokeManualRegistrationTokenRoute,\n ],\n },\n {\n prefix: '/workspaces/:workspaceId/runners/active',\n auth: AUTH_USER,\n routes: [listActiveRunnersRoute],\n },\n {\n prefix: '/runners',\n auth: AUTH_RUNNER_REGISTRATION_TOKEN,\n routes: [createRegisterRoute(auth)],\n },\n {\n prefix: '/runners/jobs',\n auth: AUTH_RUNNER_SESSION,\n routes: [createRequestJobRoute(auth)],\n },\n {\n prefix: '/runners/jobs',\n auth: AUTH_LEASED_JOB,\n routes: [createHeartbeatRoute(auth)],\n },\n {\n prefix: '/provisioners',\n auth: AUTH_PROVISIONER_TOKEN,\n routes: [\n pollDemandRoute,\n createRunnerInstancesRoute,\n attachRunnerInstanceProviderIdRoute,\n assignRunnerInstancesRoute,\n reportRunnerInstancesRoute,\n reconcileRunnerInstancesRoute,\n ],\n },\n {\n prefix: '/admin/runners/instances',\n auth: AUTH_USER,\n routes: [createAdminRunnerInstancesRoute(auth)],\n },\n createAdminProvisionerTokenRoutes(auth),\n ];\n}\n\nconst runnerControlRoutes: RouteGroup[] = [\n {prefix: '/runner-enrollment', routes: [exchangeRunnerBootstrapRoute]},\n {\n prefix: '/runner-control',\n routes: [\n enrollRunnerRoute,\n attachRunnerControlProviderIdRoute,\n runnerControlHeartbeatRoute,\n runnerAssignmentPollRoute,\n ],\n },\n];\n\nexport const provisionerRoutes: RouteGroup[] = [\n {\n prefix: '/workspaces/:workspaceId/provisioners/tokens',\n auth: AUTH_USER,\n routes: [listProvisionerTokensRoute, createProvisionerTokenRoute, revokeProvisionerTokenRoute],\n },\n {\n prefix: '/workspaces/:workspaceId/provisioners/active',\n auth: AUTH_USER,\n routes: [listActiveProvisionersRoute],\n },\n {\n prefix: '/provisioners',\n auth: AUTH_PROVISIONER_TOKEN,\n routes: [getProvisionerMeRoute],\n },\n];\n\nexport function createRunnerRoutes(\n auth: AuthInterModuleClient,\n options: CreateRunnersModuleOptions = {},\n): RouteGroup[] {\n const runnerOnlyRoutes = createRunnerOnlyRoutes(auth);\n return [\n ...runnerOnlyRoutes.map((route) =>\n route.routes.includes(pollDemandRoute)\n ? {\n ...route,\n routes: route.routes.map((r) =>\n r === pollDemandRoute ? createPollDemandRoute(options) : r,\n ),\n }\n : route,\n ),\n ...runnerControlRoutes,\n ...provisionerRoutes,\n ];\n}\n"],"names":["AUTH_LEASED_JOB","AUTH_PROVISIONER_TOKEN","AUTH_RUNNER_REGISTRATION_TOKEN","AUTH_RUNNER_SESSION","AUTH_USER","createAdminProvisionerTokenRoutes","createAdminRunnerInstancesRoute","assignRunnerInstancesRoute","createManualRegistrationTokenRoute","createProvisionerTokenRoute","getProvisionerMeRoute","createHeartbeatRoute","listActiveProvisionersRoute","listActiveRunnersRoute","listManualRegistrationTokensRoute","listProvisionerTokensRoute","createPollDemandRoute","pollDemandRoute","reconcileRunnerInstancesRoute","createRegisterRoute","reportRunnerInstancesRoute","createRequestJobRoute","revokeManualRegistrationTokenRoute","revokeProvisionerTokenRoute","attachRunnerControlProviderIdRoute","attachRunnerInstanceProviderIdRoute","createRunnerInstancesRoute","enrollRunnerRoute","exchangeRunnerBootstrapRoute","runnerAssignmentPollRoute","runnerControlHeartbeatRoute","createRunnerOnlyRoutes","auth","prefix","routes","runnerControlRoutes","provisionerRoutes","createRunnerRoutes","options","runnerOnlyRoutes","map","route","includes","r"],"mappings":"AAAA,SACEA,eAAe,EACfC,sBAAsB,EACtBC,8BAA8B,EAC9BC,mBAAmB,EACnBC,SAAS,QACJ,4BAA4B;AAInC,SAAQC,iCAAiC,QAAO,gCAAgC;AAChF,SAAQC,+BAA+B,QAAO,8BAA8B;AAC5E,SAAQC,0BAA0B,QAAO,+BAA+B;AACxE,SAAQC,kCAAkC,QAAO,wCAAwC;AACzF,SAAQC,2BAA2B,QAAO,gCAAgC;AAC1E,SAAQC,qBAAqB,QAAO,0BAA0B;AAC9D,SAAQC,oBAAoB,QAAO,iBAAiB;AACpD,SAAQC,2BAA2B,QAAO,gCAAgC;AAC1E,SAAQC,sBAAsB,QAAO,2BAA2B;AAChE,SAAQC,iCAAiC,QAAO,uCAAuC;AACvF,SAAQC,0BAA0B,QAAO,+BAA+B;AACxE,SAAQC,qBAAqB,EAAEC,eAAe,QAAO,mBAAmB;AACxE,SAAQC,6BAA6B,QAAO,kCAAkC;AAC9E,SAAQC,mBAAmB,QAAO,gBAAgB;AAClD,SAAQC,0BAA0B,QAAO,+BAA+B;AACxE,SAAQC,qBAAqB,QAAO,mBAAmB;AACvD,SAAQC,kCAAkC,QAAO,wCAAwC;AACzF,SAAQC,2BAA2B,QAAO,gCAAgC;AAC1E,SACEC,kCAAkC,EAClCC,mCAAmC,EACnCC,0BAA0B,EAC1BC,iBAAiB,EACjBC,4BAA4B,EAC5BC,yBAAyB,EACzBC,2BAA2B,QACtB,yBAAyB;AAEhC,SAASC,uBAAuBC,IAA2B;IACzD,OAAO;QACL;YACEC,QAAQ;YACRD,MAAM5B;YACN8B,QAAQ;gBACNpB;gBACAN;gBACAc;aACD;QACH;QACA;YACEW,QAAQ;YACRD,MAAM5B;YACN8B,QAAQ;gBAACrB;aAAuB;QAClC;QACA;YACEoB,QAAQ;YACRD,MAAM9B;YACNgC,QAAQ;gBAACf,oBAAoBa;aAAM;QACrC;QACA;YACEC,QAAQ;YACRD,MAAM7B;YACN+B,QAAQ;gBAACb,sBAAsBW;aAAM;QACvC;QACA;YACEC,QAAQ;YACRD,MAAMhC;YACNkC,QAAQ;gBAACvB,qBAAqBqB;aAAM;QACtC;QACA;YACEC,QAAQ;YACRD,MAAM/B;YACNiC,QAAQ;gBACNjB;gBACAS;gBACAD;gBACAlB;gBACAa;gBACAF;aACD;QACH;QACA;YACEe,QAAQ;YACRD,MAAM5B;YACN8B,QAAQ;gBAAC5B,gCAAgC0B;aAAM;QACjD;QACA3B,kCAAkC2B;KACnC;AACH;AAEA,MAAMG,sBAAoC;IACxC;QAACF,QAAQ;QAAsBC,QAAQ;YAACN;SAA6B;IAAA;IACrE;QACEK,QAAQ;QACRC,QAAQ;YACNP;YACAH;YACAM;YACAD;SACD;IACH;CACD;AAED,OAAO,MAAMO,oBAAkC;IAC7C;QACEH,QAAQ;QACRD,MAAM5B;QACN8B,QAAQ;YAACnB;YAA4BN;YAA6Bc;SAA4B;IAChG;IACA;QACEU,QAAQ;QACRD,MAAM5B;QACN8B,QAAQ;YAACtB;SAA4B;IACvC;IACA;QACEqB,QAAQ;QACRD,MAAM/B;QACNiC,QAAQ;YAACxB;SAAsB;IACjC;CACD,CAAC;AAEF,OAAO,SAAS2B,mBACdL,IAA2B,EAC3BM,UAAsC,CAAC,CAAC;IAExC,MAAMC,mBAAmBR,uBAAuBC;IAChD,OAAO;WACFO,iBAAiBC,GAAG,CAAC,CAACC,QACvBA,MAAMP,MAAM,CAACQ,QAAQ,CAACzB,mBAClB;gBACE,GAAGwB,KAAK;gBACRP,QAAQO,MAAMP,MAAM,CAACM,GAAG,CAAC,CAACG,IACxBA,MAAM1B,kBAAkBD,sBAAsBsB,WAAWK;YAE7D,IACAF;WAEHN;WACAC;KACJ;AACH"}
@@ -11,6 +11,7 @@ type RunnerAssignmentPollParams = {
11
11
  getAssignment: () => Promise<unknown | null>;
12
12
  issueActivationToken: () => Promise<string | null>;
13
13
  };
14
+ export declare function resolveRunnerAssignmentPollWaitSeconds(requestedWaitSeconds: number | undefined): number;
14
15
  export declare function pollForRunnerActivationToken(params: RunnerAssignmentPollParams): Promise<string | null>;
15
16
  export declare const runnerAssignmentPollRoute: import("@shipfox/node-fastify").RouteDefinition;
16
17
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"runner-enrollment.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/runner-enrollment.ts"],"names":[],"mappings":"AAgCA,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;AACF,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAWxB;AACD,eAAO,MAAM,yBAAyB,iDAwBpC,CAAC"}
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,5 +1,5 @@
1
1
  import { requireProvisionerContext, requireRunnerControlSessionContext } from '@shipfox/api-auth-context';
2
- import { attachRunnerControlProviderIdBodySchema, createRunnerInstancesBodySchema, createRunnerInstancesResponseSchema, runnerAssignmentPollResponseSchema, runnerBootstrapExchangeBodySchema, runnerBootstrapExchangeResponseSchema, runnerControlHeartbeatResponseSchema, runnerEnrollmentBodySchema, runnerEnrollmentResponseSchema } from '@shipfox/api-runners-dto';
2
+ import { attachRunnerControlProviderIdBodySchema, createRunnerInstancesBodySchema, createRunnerInstancesResponseSchema, runnerAssignmentPollQuerySchema, runnerAssignmentPollResponseSchema, runnerBootstrapExchangeBodySchema, runnerBootstrapExchangeResponseSchema, runnerControlHeartbeatResponseSchema, runnerEnrollmentBodySchema, runnerEnrollmentResponseSchema } from '@shipfox/api-runners-dto';
3
3
  import { ClientError, defineRoute } from '@shipfox/node-fastify';
4
4
  import { z } from 'zod';
5
5
  import { config } from '#config.js';
@@ -179,15 +179,20 @@ export const runnerControlHeartbeatRoute = defineRoute({
179
179
  };
180
180
  }
181
181
  });
182
+ export function resolveRunnerAssignmentPollWaitSeconds(requestedWaitSeconds) {
183
+ return Math.max(1, Math.min(requestedWaitSeconds ?? config.RUNNER_ASSIGNMENT_POLL_MAX_WAIT_SECONDS, config.RUNNER_ASSIGNMENT_POLL_MAX_WAIT_SECONDS));
184
+ }
182
185
  export async function pollForRunnerActivationToken(params) {
183
- while(Date.now() <= params.deadline){
186
+ while(Date.now() < params.deadline){
184
187
  if (params.signal.aborted) return null;
185
188
  const assignment = await params.getAssignment();
186
189
  if (assignment) {
187
190
  const activationToken = await params.issueActivationToken();
188
191
  if (activationToken) return activationToken;
189
192
  }
190
- await new Promise((resolve)=>setTimeout(resolve, params.intervalMs));
193
+ const remainingMs = params.deadline - Date.now();
194
+ if (remainingMs <= 0 || params.signal.aborted) return null;
195
+ await new Promise((resolve)=>setTimeout(resolve, Math.min(params.intervalMs, remainingMs)));
191
196
  }
192
197
  return null;
193
198
  }
@@ -196,6 +201,7 @@ export const runnerAssignmentPollRoute = defineRoute({
196
201
  path: '/assignment',
197
202
  description: 'Wait for only the authenticated runner instance assignment',
198
203
  schema: {
204
+ querystring: runnerAssignmentPollQuerySchema,
199
205
  response: {
200
206
  200: runnerAssignmentPollResponseSchema
201
207
  }
@@ -203,7 +209,8 @@ export const runnerAssignmentPollRoute = defineRoute({
203
209
  preHandler: authenticateRunnerControlSession,
204
210
  handler: async (request, reply)=>{
205
211
  const session = requireRunnerControlSessionContext(request);
206
- const deadline = Date.now() + config.RUNNER_ASSIGNMENT_POLL_MAX_WAIT_SECONDS * 1000;
212
+ const waitSeconds = resolveRunnerAssignmentPollWaitSeconds(request.query.wait_seconds);
213
+ const deadline = Date.now() + waitSeconds * 1000;
207
214
  const abortController = new AbortController();
208
215
  reply.raw.on('close', ()=>abortController.abort());
209
216
  const activationToken = await pollForRunnerActivationToken({
@@ -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 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};\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 await new Promise((resolve) => setTimeout(resolve, params.intervalMs));\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: {response: {200: runnerAssignmentPollResponseSchema}},\n preHandler: authenticateRunnerControlSession,\n handler: async (request, reply) => {\n const session = requireRunnerControlSessionContext(request);\n const deadline = Date.now() + config.RUNNER_ASSIGNMENT_POLL_MAX_WAIT_SECONDS * 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","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","pollForRunnerActivationToken","Date","now","deadline","signal","aborted","assignment","getAssignment","issueActivationToken","Promise","resolve","setTimeout","intervalMs","runnerAssignmentPollRoute","reply","RUNNER_ASSIGNMENT_POLL_MAX_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 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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"}