@shipfox/api-runners-dto 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/.turbo/turbo-build.log +2 -0
  2. package/.turbo/turbo-type$colon$emit.log +1 -0
  3. package/.turbo/turbo-type.log +1 -0
  4. package/CHANGELOG.md +59 -0
  5. package/LICENSE +21 -0
  6. package/dist/events.d.ts +55 -0
  7. package/dist/events.d.ts.map +1 -0
  8. package/dist/events.js +33 -0
  9. package/dist/events.js.map +1 -0
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +4 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/schemas/claim-job.d.ts +11 -0
  15. package/dist/schemas/claim-job.d.ts.map +1 -0
  16. package/dist/schemas/claim-job.js +11 -0
  17. package/dist/schemas/claim-job.js.map +1 -0
  18. package/dist/schemas/heartbeat.d.ts +20 -0
  19. package/dist/schemas/heartbeat.d.ts.map +1 -0
  20. package/dist/schemas/heartbeat.js +11 -0
  21. package/dist/schemas/heartbeat.js.map +1 -0
  22. package/dist/schemas/index.d.ts +12 -0
  23. package/dist/schemas/index.d.ts.map +1 -0
  24. package/dist/schemas/index.js +13 -0
  25. package/dist/schemas/index.js.map +1 -0
  26. package/dist/schemas/list-active-provisioners.d.ts +18 -0
  27. package/dist/schemas/list-active-provisioners.d.ts.map +1 -0
  28. package/dist/schemas/list-active-provisioners.js +12 -0
  29. package/dist/schemas/list-active-provisioners.js.map +1 -0
  30. package/dist/schemas/manual-registration-token.d.ts +53 -0
  31. package/dist/schemas/manual-registration-token.d.ts.map +1 -0
  32. package/dist/schemas/manual-registration-token.js +31 -0
  33. package/dist/schemas/manual-registration-token.js.map +1 -0
  34. package/dist/schemas/mint-registration-tokens.d.ts +28 -0
  35. package/dist/schemas/mint-registration-tokens.d.ts.map +1 -0
  36. package/dist/schemas/mint-registration-tokens.js +24 -0
  37. package/dist/schemas/mint-registration-tokens.js.map +1 -0
  38. package/dist/schemas/poll-demand.d.ts +52 -0
  39. package/dist/schemas/poll-demand.d.ts.map +1 -0
  40. package/dist/schemas/poll-demand.js +34 -0
  41. package/dist/schemas/poll-demand.js.map +1 -0
  42. package/dist/schemas/provisioner-token.d.ts +72 -0
  43. package/dist/schemas/provisioner-token.d.ts.map +1 -0
  44. package/dist/schemas/provisioner-token.js +43 -0
  45. package/dist/schemas/provisioner-token.js.map +1 -0
  46. package/dist/schemas/reconcile-provisioned-runners.d.ts +71 -0
  47. package/dist/schemas/reconcile-provisioned-runners.d.ts.map +1 -0
  48. package/dist/schemas/reconcile-provisioned-runners.js +36 -0
  49. package/dist/schemas/reconcile-provisioned-runners.js.map +1 -0
  50. package/dist/schemas/register.d.ts +27 -0
  51. package/dist/schemas/register.d.ts.map +1 -0
  52. package/dist/schemas/register.js +19 -0
  53. package/dist/schemas/register.js.map +1 -0
  54. package/dist/schemas/report-provisioned-runners.d.ts +109 -0
  55. package/dist/schemas/report-provisioned-runners.d.ts.map +1 -0
  56. package/dist/schemas/report-provisioned-runners.js +58 -0
  57. package/dist/schemas/report-provisioned-runners.js.map +1 -0
  58. package/dist/schemas/tool-capabilities.d.ts +17 -0
  59. package/dist/schemas/tool-capabilities.d.ts.map +1 -0
  60. package/dist/schemas/tool-capabilities.js +27 -0
  61. package/dist/schemas/tool-capabilities.js.map +1 -0
  62. package/dist/tsconfig.test.tsbuildinfo +1 -0
  63. package/package.json +56 -0
  64. package/src/events.ts +46 -0
  65. package/src/index.ts +107 -0
  66. package/src/schemas/claim-job.test.ts +53 -0
  67. package/src/schemas/claim-job.ts +13 -0
  68. package/src/schemas/heartbeat.ts +16 -0
  69. package/src/schemas/index.ts +115 -0
  70. package/src/schemas/list-active-provisioners.ts +17 -0
  71. package/src/schemas/manual-registration-token.test.ts +36 -0
  72. package/src/schemas/manual-registration-token.ts +58 -0
  73. package/src/schemas/mint-registration-tokens.test.ts +28 -0
  74. package/src/schemas/mint-registration-tokens.ts +46 -0
  75. package/src/schemas/poll-demand.test.ts +27 -0
  76. package/src/schemas/poll-demand.ts +49 -0
  77. package/src/schemas/provisioner-token.test.ts +38 -0
  78. package/src/schemas/provisioner-token.ts +64 -0
  79. package/src/schemas/reconcile-provisioned-runners.test.ts +85 -0
  80. package/src/schemas/reconcile-provisioned-runners.ts +61 -0
  81. package/src/schemas/register.ts +28 -0
  82. package/src/schemas/report-provisioned-runners.test.ts +61 -0
  83. package/src/schemas/report-provisioned-runners.ts +75 -0
  84. package/src/schemas/tool-capabilities.test.ts +64 -0
  85. package/src/schemas/tool-capabilities.ts +35 -0
  86. package/tsconfig.build.json +9 -0
  87. package/tsconfig.build.tsbuildinfo +1 -0
  88. package/tsconfig.json +3 -0
  89. package/tsconfig.test.json +8 -0
  90. package/vitest.config.ts +3 -0
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@shipfox/api-runners-dto",
3
+ "license": "MIT",
4
+ "version": "2.0.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/ShipfoxHQ/shipfox.git",
8
+ "directory": "libs/api/runners-dto"
9
+ },
10
+ "private": false,
11
+ "type": "module",
12
+ "main": "dist/index.js",
13
+ "types": "dist/index.d.ts",
14
+ "imports": {
15
+ "#test/*": "./test/*",
16
+ "#*": {
17
+ "workspace-source": "./src/*",
18
+ "development": "./src/*",
19
+ "default": "./dist/*"
20
+ }
21
+ },
22
+ "exports": {
23
+ ".": {
24
+ "development": {
25
+ "types": "./src/index.ts",
26
+ "default": "./src/index.ts"
27
+ },
28
+ "default": {
29
+ "types": "./dist/index.d.ts",
30
+ "default": "./dist/index.js"
31
+ }
32
+ }
33
+ },
34
+ "dependencies": {
35
+ "zod": "^4.4.3",
36
+ "@shipfox/runner-labels": "0.1.0"
37
+ },
38
+ "devDependencies": {
39
+ "@shipfox/depcruise": "1.0.1",
40
+ "@shipfox/biome": "1.8.1",
41
+ "@shipfox/typescript": "1.1.6",
42
+ "@shipfox/ts-config": "1.3.8",
43
+ "@shipfox/vitest": "1.2.2",
44
+ "@shipfox/swc": "1.2.5"
45
+ },
46
+ "scripts": {
47
+ "build": "shipfox-swc",
48
+ "check": "shipfox-biome-check",
49
+ "check:fix": "shipfox-biome-check --write",
50
+ "depcruise": "shipfox-depcruise",
51
+ "test": "shipfox-vitest-run",
52
+ "test:watch": "shipfox-vitest-watch",
53
+ "type": "shipfox-tsc-check",
54
+ "type:emit": "shipfox-tsc-emit"
55
+ }
56
+ }
package/src/events.ts ADDED
@@ -0,0 +1,46 @@
1
+ import {z} from 'zod';
2
+
3
+ const nonEmptyStringSchema = z.string().nonempty();
4
+ const isoDateTimeSchema = z.string().datetime();
5
+
6
+ export const RUNNER_JOB_LEASE_EXPIRED = 'runners.job.lease_expired' as const;
7
+ export const RUNNER_JOB_QUEUED = 'runners.job.queued' as const;
8
+ export const RUNNER_JOB_CLAIMED = 'runners.job.claimed' as const;
9
+
10
+ export const runnerJobLeaseExpiredEventSchema = z.object({
11
+ workflowRunId: nonEmptyStringSchema,
12
+ workflowRunAttemptId: nonEmptyStringSchema,
13
+ jobId: nonEmptyStringSchema,
14
+ jobExecutionId: nonEmptyStringSchema,
15
+ });
16
+ export type RunnerJobLeaseExpiredEvent = z.infer<typeof runnerJobLeaseExpiredEventSchema>;
17
+
18
+ export const runnerJobQueuedEventSchema = z.object({
19
+ workflowRunId: nonEmptyStringSchema,
20
+ workflowRunAttemptId: nonEmptyStringSchema,
21
+ jobId: nonEmptyStringSchema,
22
+ jobExecutionId: nonEmptyStringSchema,
23
+ queuedAt: isoDateTimeSchema,
24
+ });
25
+ export type RunnerJobQueuedEvent = z.infer<typeof runnerJobQueuedEventSchema>;
26
+
27
+ export const runnerJobClaimedEventSchema = z.object({
28
+ workflowRunId: nonEmptyStringSchema,
29
+ workflowRunAttemptId: nonEmptyStringSchema,
30
+ jobId: nonEmptyStringSchema,
31
+ jobExecutionId: nonEmptyStringSchema,
32
+ claimedAt: isoDateTimeSchema,
33
+ });
34
+ export type RunnerJobClaimedEvent = z.infer<typeof runnerJobClaimedEventSchema>;
35
+
36
+ export interface RunnersEventMap {
37
+ [RUNNER_JOB_LEASE_EXPIRED]: RunnerJobLeaseExpiredEvent;
38
+ [RUNNER_JOB_QUEUED]: RunnerJobQueuedEvent;
39
+ [RUNNER_JOB_CLAIMED]: RunnerJobClaimedEvent;
40
+ }
41
+
42
+ export const runnersEventSchemas = {
43
+ [RUNNER_JOB_LEASE_EXPIRED]: runnerJobLeaseExpiredEventSchema,
44
+ [RUNNER_JOB_QUEUED]: runnerJobQueuedEventSchema,
45
+ [RUNNER_JOB_CLAIMED]: runnerJobClaimedEventSchema,
46
+ } satisfies Record<keyof RunnersEventMap, z.ZodType>;
package/src/index.ts ADDED
@@ -0,0 +1,107 @@
1
+ export {
2
+ type ActiveProvisionerDto,
3
+ type ActiveRunnerDto,
4
+ type ActiveRunnerStateDto,
5
+ type ActiveRunnersResponseDto,
6
+ activeProvisionerDtoSchema,
7
+ activeRunnerDtoSchema,
8
+ activeRunnerStateSchema,
9
+ activeRunnersResponseSchema,
10
+ type ClaimedJobResponseDto,
11
+ type CreateManualRegistrationTokenBodyDto,
12
+ type CreateManualRegistrationTokenResponseDto,
13
+ type CreateProvisionerTokenBodyDto,
14
+ type CreateProvisionerTokenResponseDto,
15
+ claimedJobResponseSchema,
16
+ createManualRegistrationTokenBodySchema,
17
+ createManualRegistrationTokenResponseSchema,
18
+ createProvisionerTokenBodySchema,
19
+ createProvisionerTokenResponseSchema,
20
+ type DemandStatDto,
21
+ demandStatSchema,
22
+ type HeartbeatBodyDto,
23
+ type HeartbeatResponseDto,
24
+ heartbeatBodySchema,
25
+ heartbeatResponseSchema,
26
+ type ListActiveProvisionersResponseDto,
27
+ type ListManualRegistrationTokensResponseDto,
28
+ type ListProvisionerTokensResponseDto,
29
+ listActiveProvisionersResponseSchema,
30
+ listManualRegistrationTokensResponseSchema,
31
+ listProvisionerTokensResponseSchema,
32
+ MAX_MANUAL_REGISTRATION_TOKEN_TTL_SECONDS,
33
+ MAX_OBSERVED_PROVISIONED_RUNNER_ID_LENGTH,
34
+ MAX_PROVIDER_KIND_LENGTH,
35
+ MAX_PROVISIONED_RUNNER_REASON_LENGTH,
36
+ MAX_PROVISIONED_RUNNER_REPORT_EVENTS,
37
+ MAX_PROVISIONER_TOKEN_TTL_SECONDS,
38
+ MAX_RECONCILE_OBSERVED_RUNNERS,
39
+ type ManualRegistrationTokenDto,
40
+ type MintedRegistrationTokenDto,
41
+ type MintRegistrationTokensBatchBodyDto,
42
+ type MintRegistrationTokensBatchResponseDto,
43
+ type MintRegistrationTokensProvisionedRunnerDto,
44
+ manualRegistrationTokenDtoSchema,
45
+ mintedRegistrationTokenSchema,
46
+ mintRegistrationTokensBatchBodySchema,
47
+ mintRegistrationTokensBatchResponseSchema,
48
+ mintRegistrationTokensProvisionedRunnerSchema,
49
+ type PollDemandBodyDto,
50
+ type PollDemandResponseDto,
51
+ type PollDemandTemplateDto,
52
+ type ProvisionedRunnerReportEventDto,
53
+ type ProvisionedRunnerStateDto,
54
+ type ProvisionerIdentityResponseDto,
55
+ type ProvisionerTokenDto,
56
+ pollDemandBodySchema,
57
+ pollDemandResponseSchema,
58
+ pollDemandTemplateSchema,
59
+ providerKindSchema,
60
+ provisionedRunnerReportEventSchema,
61
+ provisionedRunnerStateSchema,
62
+ provisionerIdentityResponseSchema,
63
+ provisionerTokenDtoSchema,
64
+ REGISTRATION_TOKEN_BATCH_HARD_MAX,
65
+ type ReconcileDesiredIntentDto,
66
+ type ReconciledBoundJobDto,
67
+ type ReconciledProvisionedRunnerDto,
68
+ type ReconcileProvisionedRunnersBodyDto,
69
+ type ReconcileProvisionedRunnersResponseDto,
70
+ type RegisterRunnerBodyDto,
71
+ type RegisterRunnerResponseDto,
72
+ type ReportProvisionedRunnersBodyDto,
73
+ type ReportProvisionedRunnersResponseDto,
74
+ type ReservationGrantDto,
75
+ type RevokeManualRegistrationTokenResponseDto,
76
+ type RevokeProvisionerTokenResponseDto,
77
+ RUNNER_SESSION_EXHAUSTED_CODE,
78
+ type RunnerHarnessToolCapabilitiesDto,
79
+ type RunnerToolCapabilitiesDto,
80
+ reconcileDesiredIntentSchema,
81
+ reconciledBoundJobSchema,
82
+ reconciledProvisionedRunnerSchema,
83
+ reconcileProvisionedRunnersBodySchema,
84
+ reconcileProvisionedRunnersResponseSchema,
85
+ registerRunnerBodySchema,
86
+ registerRunnerResponseSchema,
87
+ reportProvisionedRunnersBodySchema,
88
+ reportProvisionedRunnersResponseSchema,
89
+ reservationGrantSchema,
90
+ revokeManualRegistrationTokenResponseSchema,
91
+ revokeProvisionerTokenResponseSchema,
92
+ runnerHarnessToolCapabilitiesSchema,
93
+ runnerToolCapabilitiesSchema,
94
+ } from '#schemas/index.js';
95
+ export {
96
+ RUNNER_JOB_CLAIMED,
97
+ RUNNER_JOB_LEASE_EXPIRED,
98
+ RUNNER_JOB_QUEUED,
99
+ type RunnerJobClaimedEvent,
100
+ type RunnerJobLeaseExpiredEvent,
101
+ type RunnerJobQueuedEvent,
102
+ type RunnersEventMap,
103
+ runnerJobClaimedEventSchema,
104
+ runnerJobLeaseExpiredEventSchema,
105
+ runnerJobQueuedEventSchema,
106
+ runnersEventSchemas,
107
+ } from './events.js';
@@ -0,0 +1,53 @@
1
+ import {claimedJobResponseSchema} from './claim-job.js';
2
+
3
+ describe('claimedJobResponseSchema', () => {
4
+ it('parses a step-less claim response', () => {
5
+ const parsed = claimedJobResponseSchema.parse({
6
+ job_id: crypto.randomUUID(),
7
+ job_execution_id: crypto.randomUUID(),
8
+ workflow_run_id: crypto.randomUUID(),
9
+ workflow_run_attempt_id: crypto.randomUUID(),
10
+ lease_token: 'lease-abc',
11
+ });
12
+
13
+ expect(parsed.lease_token).toBe('lease-abc');
14
+ });
15
+
16
+ it('rejects a missing lease token', () => {
17
+ const parse = () =>
18
+ claimedJobResponseSchema.parse({
19
+ job_id: crypto.randomUUID(),
20
+ job_execution_id: crypto.randomUUID(),
21
+ workflow_run_id: crypto.randomUUID(),
22
+ workflow_run_attempt_id: crypto.randomUUID(),
23
+ });
24
+
25
+ expect(parse).toThrow();
26
+ });
27
+
28
+ it('rejects an empty lease token', () => {
29
+ const parse = () =>
30
+ claimedJobResponseSchema.parse({
31
+ job_id: crypto.randomUUID(),
32
+ job_execution_id: crypto.randomUUID(),
33
+ workflow_run_id: crypto.randomUUID(),
34
+ workflow_run_attempt_id: crypto.randomUUID(),
35
+ lease_token: '',
36
+ });
37
+
38
+ expect(parse).toThrow();
39
+ });
40
+
41
+ it('rejects a non-uuid job id', () => {
42
+ const parse = () =>
43
+ claimedJobResponseSchema.parse({
44
+ job_id: 'not-a-uuid',
45
+ job_execution_id: crypto.randomUUID(),
46
+ workflow_run_id: crypto.randomUUID(),
47
+ workflow_run_attempt_id: crypto.randomUUID(),
48
+ lease_token: 'lease-abc',
49
+ });
50
+
51
+ expect(parse).toThrow();
52
+ });
53
+ });
@@ -0,0 +1,13 @@
1
+ import {z} from 'zod';
2
+
3
+ export const RUNNER_SESSION_EXHAUSTED_CODE = 'runner-session-exhausted' as const;
4
+
5
+ export const claimedJobResponseSchema = z.object({
6
+ workflow_run_id: z.string().uuid(),
7
+ workflow_run_attempt_id: z.string().uuid(),
8
+ job_id: z.string().uuid(),
9
+ job_execution_id: z.string().uuid(),
10
+ lease_token: z.string().min(1),
11
+ });
12
+
13
+ export type ClaimedJobResponseDto = z.infer<typeof claimedJobResponseSchema>;
@@ -0,0 +1,16 @@
1
+ import {z} from 'zod';
2
+ import {runnerToolCapabilitiesSchema} from './tool-capabilities.js';
3
+
4
+ export const heartbeatBodySchema = z
5
+ .object({
6
+ capabilities: runnerToolCapabilitiesSchema.optional(),
7
+ })
8
+ .strict();
9
+
10
+ export const heartbeatResponseSchema = z.object({
11
+ cancel: z.boolean(),
12
+ lease_token: z.string().min(1),
13
+ });
14
+
15
+ export type HeartbeatBodyDto = z.infer<typeof heartbeatBodySchema>;
16
+ export type HeartbeatResponseDto = z.infer<typeof heartbeatResponseSchema>;
@@ -0,0 +1,115 @@
1
+ export {
2
+ type ClaimedJobResponseDto,
3
+ claimedJobResponseSchema,
4
+ RUNNER_SESSION_EXHAUSTED_CODE,
5
+ } from './claim-job.js';
6
+ export {
7
+ type HeartbeatBodyDto,
8
+ type HeartbeatResponseDto,
9
+ heartbeatBodySchema,
10
+ heartbeatResponseSchema,
11
+ } from './heartbeat.js';
12
+ export {
13
+ type ActiveProvisionerDto,
14
+ activeProvisionerDtoSchema,
15
+ type ListActiveProvisionersResponseDto,
16
+ listActiveProvisionersResponseSchema,
17
+ } from './list-active-provisioners.js';
18
+ export {
19
+ type CreateManualRegistrationTokenBodyDto,
20
+ type CreateManualRegistrationTokenResponseDto,
21
+ createManualRegistrationTokenBodySchema,
22
+ createManualRegistrationTokenResponseSchema,
23
+ type ListManualRegistrationTokensResponseDto,
24
+ listManualRegistrationTokensResponseSchema,
25
+ MAX_MANUAL_REGISTRATION_TOKEN_TTL_SECONDS,
26
+ type ManualRegistrationTokenDto,
27
+ manualRegistrationTokenDtoSchema,
28
+ type RevokeManualRegistrationTokenResponseDto,
29
+ revokeManualRegistrationTokenResponseSchema,
30
+ } from './manual-registration-token.js';
31
+ export {
32
+ type MintedRegistrationTokenDto,
33
+ type MintRegistrationTokensBatchBodyDto,
34
+ type MintRegistrationTokensBatchResponseDto,
35
+ type MintRegistrationTokensProvisionedRunnerDto,
36
+ mintedRegistrationTokenSchema,
37
+ mintRegistrationTokensBatchBodySchema,
38
+ mintRegistrationTokensBatchResponseSchema,
39
+ mintRegistrationTokensProvisionedRunnerSchema,
40
+ REGISTRATION_TOKEN_BATCH_HARD_MAX,
41
+ } from './mint-registration-tokens.js';
42
+ export {
43
+ type DemandStatDto,
44
+ demandStatSchema,
45
+ type PollDemandBodyDto,
46
+ type PollDemandResponseDto,
47
+ type PollDemandTemplateDto,
48
+ pollDemandBodySchema,
49
+ pollDemandResponseSchema,
50
+ pollDemandTemplateSchema,
51
+ type ReservationGrantDto,
52
+ reservationGrantSchema,
53
+ } from './poll-demand.js';
54
+ export {
55
+ type CreateProvisionerTokenBodyDto,
56
+ type CreateProvisionerTokenResponseDto,
57
+ createProvisionerTokenBodySchema,
58
+ createProvisionerTokenResponseSchema,
59
+ type ListProvisionerTokensResponseDto,
60
+ listProvisionerTokensResponseSchema,
61
+ MAX_PROVISIONER_TOKEN_TTL_SECONDS,
62
+ type ProvisionerIdentityResponseDto,
63
+ type ProvisionerTokenDto,
64
+ provisionerIdentityResponseSchema,
65
+ provisionerTokenDtoSchema,
66
+ type RevokeProvisionerTokenResponseDto,
67
+ revokeProvisionerTokenResponseSchema,
68
+ } from './provisioner-token.js';
69
+ export {
70
+ MAX_OBSERVED_PROVISIONED_RUNNER_ID_LENGTH,
71
+ MAX_RECONCILE_OBSERVED_RUNNERS,
72
+ type ReconcileDesiredIntentDto,
73
+ type ReconciledBoundJobDto,
74
+ type ReconciledProvisionedRunnerDto,
75
+ type ReconcileProvisionedRunnersBodyDto,
76
+ type ReconcileProvisionedRunnersResponseDto,
77
+ reconcileDesiredIntentSchema,
78
+ reconciledBoundJobSchema,
79
+ reconciledProvisionedRunnerSchema,
80
+ reconcileProvisionedRunnersBodySchema,
81
+ reconcileProvisionedRunnersResponseSchema,
82
+ } from './reconcile-provisioned-runners.js';
83
+ export {
84
+ type RegisterRunnerBodyDto,
85
+ type RegisterRunnerResponseDto,
86
+ registerRunnerBodySchema,
87
+ registerRunnerResponseSchema,
88
+ runnerLabelSchema,
89
+ } from './register.js';
90
+ export {
91
+ type ActiveRunnerDto,
92
+ type ActiveRunnerStateDto,
93
+ type ActiveRunnersResponseDto,
94
+ activeRunnerDtoSchema,
95
+ activeRunnerStateSchema,
96
+ activeRunnersResponseSchema,
97
+ MAX_PROVIDER_KIND_LENGTH,
98
+ MAX_PROVISIONED_RUNNER_REASON_LENGTH,
99
+ MAX_PROVISIONED_RUNNER_REPORT_EVENTS,
100
+ type ProvisionedRunnerReportEventDto,
101
+ type ProvisionedRunnerStateDto,
102
+ providerKindSchema,
103
+ provisionedRunnerReportEventSchema,
104
+ provisionedRunnerStateSchema,
105
+ type ReportProvisionedRunnersBodyDto,
106
+ type ReportProvisionedRunnersResponseDto,
107
+ reportProvisionedRunnersBodySchema,
108
+ reportProvisionedRunnersResponseSchema,
109
+ } from './report-provisioned-runners.js';
110
+ export {
111
+ type RunnerHarnessToolCapabilitiesDto,
112
+ type RunnerToolCapabilitiesDto,
113
+ runnerHarnessToolCapabilitiesSchema,
114
+ runnerToolCapabilitiesSchema,
115
+ } from './tool-capabilities.js';
@@ -0,0 +1,17 @@
1
+ import {z} from 'zod';
2
+
3
+ export const activeProvisionerDtoSchema = z.object({
4
+ id: z.string().uuid(),
5
+ name: z.string().nullable(),
6
+ prefix: z.string(),
7
+ last_seen_at: z.string(),
8
+ });
9
+
10
+ export const listActiveProvisionersResponseSchema = z.object({
11
+ provisioners: z.array(activeProvisionerDtoSchema),
12
+ });
13
+
14
+ export type ActiveProvisionerDto = z.infer<typeof activeProvisionerDtoSchema>;
15
+ export type ListActiveProvisionersResponseDto = z.infer<
16
+ typeof listActiveProvisionersResponseSchema
17
+ >;
@@ -0,0 +1,36 @@
1
+ import {
2
+ createManualRegistrationTokenBodySchema,
3
+ MAX_MANUAL_REGISTRATION_TOKEN_TTL_SECONDS,
4
+ } from './manual-registration-token.js';
5
+
6
+ describe('manual registration token schemas', () => {
7
+ it('accepts a valid create body', () => {
8
+ const result = createManualRegistrationTokenBodySchema.parse({
9
+ name: 'builder',
10
+ ttl_seconds: MAX_MANUAL_REGISTRATION_TOKEN_TTL_SECONDS,
11
+ });
12
+
13
+ expect(result).toEqual({
14
+ name: 'builder',
15
+ ttl_seconds: MAX_MANUAL_REGISTRATION_TOKEN_TTL_SECONDS,
16
+ });
17
+ });
18
+
19
+ it('accepts omitted TTL for never-expiring tokens', () => {
20
+ const result = createManualRegistrationTokenBodySchema.parse({
21
+ name: 'builder',
22
+ });
23
+
24
+ expect(result).toEqual({
25
+ name: 'builder',
26
+ });
27
+ });
28
+
29
+ it('rejects token TTLs above one year', () => {
30
+ const result = createManualRegistrationTokenBodySchema.safeParse({
31
+ ttl_seconds: MAX_MANUAL_REGISTRATION_TOKEN_TTL_SECONDS + 1,
32
+ });
33
+
34
+ expect(result.success).toBe(false);
35
+ });
36
+ });
@@ -0,0 +1,58 @@
1
+ import {z} from 'zod';
2
+
3
+ export const MAX_MANUAL_REGISTRATION_TOKEN_TTL_SECONDS = 31_536_000;
4
+
5
+ export const createManualRegistrationTokenBodySchema = z.object({
6
+ name: z.string().min(1).optional(),
7
+ ttl_seconds: z
8
+ .number()
9
+ .int()
10
+ .positive()
11
+ .max(MAX_MANUAL_REGISTRATION_TOKEN_TTL_SECONDS)
12
+ .optional(),
13
+ });
14
+
15
+ export type CreateManualRegistrationTokenBodyDto = z.infer<
16
+ typeof createManualRegistrationTokenBodySchema
17
+ >;
18
+
19
+ export const createManualRegistrationTokenResponseSchema = z.object({
20
+ id: z.string().uuid(),
21
+ raw_token: z.string(),
22
+ prefix: z.string(),
23
+ name: z.string().nullable(),
24
+ workspace_id: z.string().uuid(),
25
+ expires_at: z.string().nullable(),
26
+ created_at: z.string(),
27
+ });
28
+
29
+ export type CreateManualRegistrationTokenResponseDto = z.infer<
30
+ typeof createManualRegistrationTokenResponseSchema
31
+ >;
32
+
33
+ export const manualRegistrationTokenDtoSchema = z.object({
34
+ id: z.string().uuid(),
35
+ workspace_id: z.string().uuid(),
36
+ prefix: z.string(),
37
+ name: z.string().nullable(),
38
+ expires_at: z.string().nullable(),
39
+ revoked_at: z.string().nullable(),
40
+ created_at: z.string(),
41
+ updated_at: z.string(),
42
+ });
43
+
44
+ export type ManualRegistrationTokenDto = z.infer<typeof manualRegistrationTokenDtoSchema>;
45
+
46
+ export const listManualRegistrationTokensResponseSchema = z.object({
47
+ manual_registration_tokens: z.array(manualRegistrationTokenDtoSchema),
48
+ });
49
+
50
+ export type ListManualRegistrationTokensResponseDto = z.infer<
51
+ typeof listManualRegistrationTokensResponseSchema
52
+ >;
53
+
54
+ export const revokeManualRegistrationTokenResponseSchema = manualRegistrationTokenDtoSchema;
55
+
56
+ export type RevokeManualRegistrationTokenResponseDto = z.infer<
57
+ typeof revokeManualRegistrationTokenResponseSchema
58
+ >;
@@ -0,0 +1,28 @@
1
+ import {
2
+ mintRegistrationTokensBatchBodySchema,
3
+ mintRegistrationTokensProvisionedRunnerSchema,
4
+ } from './mint-registration-tokens.js';
5
+
6
+ describe('mintRegistrationTokensProvisionedRunnerSchema', () => {
7
+ it('accepts provisioned runner ids up to the lifecycle report limit', () => {
8
+ const result = mintRegistrationTokensProvisionedRunnerSchema.safeParse({
9
+ provisioned_runner_id: 'a'.repeat(255),
10
+ });
11
+
12
+ expect(result.success).toBe(true);
13
+ });
14
+ });
15
+
16
+ describe('mintRegistrationTokensBatchBodySchema', () => {
17
+ it('rejects duplicate provisioned runner ids', () => {
18
+ const result = mintRegistrationTokensBatchBodySchema.safeParse({
19
+ reservation_id: crypto.randomUUID(),
20
+ provisioned_runners: [
21
+ {provisioned_runner_id: 'provisioned-runner-1'},
22
+ {provisioned_runner_id: 'provisioned-runner-1'},
23
+ ],
24
+ });
25
+
26
+ expect(result.success).toBe(false);
27
+ });
28
+ });
@@ -0,0 +1,46 @@
1
+ import {z} from 'zod';
2
+
3
+ export const REGISTRATION_TOKEN_BATCH_HARD_MAX = 1000;
4
+
5
+ export const mintRegistrationTokensProvisionedRunnerSchema = z.object({
6
+ provisioned_runner_id: z.string().min(1).max(255),
7
+ });
8
+
9
+ export const mintRegistrationTokensBatchBodySchema = z
10
+ .object({
11
+ reservation_id: z.string().uuid(),
12
+ provisioned_runners: z
13
+ .array(mintRegistrationTokensProvisionedRunnerSchema)
14
+ .min(1)
15
+ .max(REGISTRATION_TOKEN_BATCH_HARD_MAX),
16
+ })
17
+ .refine(
18
+ (body) =>
19
+ new Set(
20
+ body.provisioned_runners.map(
21
+ (provisionedRunner) => provisionedRunner.provisioned_runner_id,
22
+ ),
23
+ ).size === body.provisioned_runners.length,
24
+ {message: 'provisioned_runner_id values must be unique', path: ['provisioned_runners']},
25
+ );
26
+
27
+ export const mintedRegistrationTokenSchema = z.object({
28
+ provisioned_runner_id: z.string(),
29
+ registration_token: z.string(),
30
+ expires_at: z.string().datetime(),
31
+ });
32
+
33
+ export const mintRegistrationTokensBatchResponseSchema = z.object({
34
+ tokens: z.array(mintedRegistrationTokenSchema),
35
+ });
36
+
37
+ export type MintRegistrationTokensProvisionedRunnerDto = z.infer<
38
+ typeof mintRegistrationTokensProvisionedRunnerSchema
39
+ >;
40
+ export type MintRegistrationTokensBatchBodyDto = z.infer<
41
+ typeof mintRegistrationTokensBatchBodySchema
42
+ >;
43
+ export type MintedRegistrationTokenDto = z.infer<typeof mintedRegistrationTokenSchema>;
44
+ export type MintRegistrationTokensBatchResponseDto = z.infer<
45
+ typeof mintRegistrationTokensBatchResponseSchema
46
+ >;
@@ -0,0 +1,27 @@
1
+ import {pollDemandResponseSchema} from './poll-demand.js';
2
+
3
+ describe('pollDemandResponseSchema', () => {
4
+ it('requires datetime response fields to be ISO datetimes', () => {
5
+ const result = pollDemandResponseSchema.safeParse({
6
+ stats: [
7
+ {
8
+ labels: ['linux'],
9
+ queued: 1,
10
+ reserved: 1,
11
+ oldest_queued_at: 'not-a-date',
12
+ },
13
+ ],
14
+ reservations: [
15
+ {
16
+ reservation_id: crypto.randomUUID(),
17
+ labels: ['linux'],
18
+ count: 1,
19
+ expires_at: 'not-a-date',
20
+ },
21
+ ],
22
+ terminate_provisioned_runner_ids: [],
23
+ });
24
+
25
+ expect(result.success).toBe(false);
26
+ });
27
+ });
@@ -0,0 +1,49 @@
1
+ import {MAX_RUNNER_LABELS} from '@shipfox/runner-labels';
2
+ import {z} from 'zod';
3
+ import {runnerLabelSchema} from './register.js';
4
+
5
+ export const pollDemandTemplateSchema = z.object({
6
+ template_key: z.string().min(1),
7
+ labels: z.array(runnerLabelSchema).min(1).max(MAX_RUNNER_LABELS),
8
+ available_slots: z.number().int().min(0).max(100_000),
9
+ starting: z.number().int().min(0).max(100_000),
10
+ running: z.number().int().min(0).max(100_000),
11
+ });
12
+
13
+ export const pollDemandBodySchema = z.object({
14
+ wait_seconds: z.number().int().min(0).optional(),
15
+ max_reservations: z.number().int().min(0).max(1000),
16
+ templates: z.array(pollDemandTemplateSchema).min(1).max(100),
17
+ });
18
+
19
+ export const demandStatSchema = z.object({
20
+ labels: z.array(z.string()),
21
+ queued: z.number().int().min(0),
22
+ reserved: z
23
+ .number()
24
+ .int()
25
+ .min(0)
26
+ .describe(
27
+ 'Active reservations for this label set; advisory, may exceed `queued` during heavy claiming.',
28
+ ),
29
+ oldest_queued_at: z.string().datetime(),
30
+ });
31
+
32
+ export const reservationGrantSchema = z.object({
33
+ reservation_id: z.string().uuid(),
34
+ labels: z.array(z.string()),
35
+ count: z.number().int().positive(),
36
+ expires_at: z.string().datetime(),
37
+ });
38
+
39
+ export const pollDemandResponseSchema = z.object({
40
+ stats: z.array(demandStatSchema),
41
+ reservations: z.array(reservationGrantSchema),
42
+ terminate_provisioned_runner_ids: z.array(z.string()),
43
+ });
44
+
45
+ export type PollDemandTemplateDto = z.infer<typeof pollDemandTemplateSchema>;
46
+ export type PollDemandBodyDto = z.infer<typeof pollDemandBodySchema>;
47
+ export type DemandStatDto = z.infer<typeof demandStatSchema>;
48
+ export type ReservationGrantDto = z.infer<typeof reservationGrantSchema>;
49
+ export type PollDemandResponseDto = z.infer<typeof pollDemandResponseSchema>;