@shipfox/api-runners 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -0
- package/.turbo/turbo-type$colon$emit.log +1 -0
- package/.turbo/turbo-type.log +1 -0
- package/CHANGELOG.md +187 -0
- package/LICENSE +21 -0
- package/dist/config.d.ts +30 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +208 -0
- package/dist/config.js.map +1 -0
- package/dist/core/demand.d.ts +33 -0
- package/dist/core/demand.d.ts.map +1 -0
- package/dist/core/demand.js +169 -0
- package/dist/core/demand.js.map +1 -0
- package/dist/core/entities/ephemeral-registration-token.d.ts +14 -0
- package/dist/core/entities/ephemeral-registration-token.d.ts.map +1 -0
- package/dist/core/entities/ephemeral-registration-token.js +3 -0
- package/dist/core/entities/ephemeral-registration-token.js.map +1 -0
- package/dist/core/entities/manual-registration-token.d.ts +12 -0
- package/dist/core/entities/manual-registration-token.d.ts.map +1 -0
- package/dist/core/entities/manual-registration-token.js +3 -0
- package/dist/core/entities/manual-registration-token.js.map +1 -0
- package/dist/core/entities/provisioned-runner.d.ts +24 -0
- package/dist/core/entities/provisioned-runner.d.ts.map +1 -0
- package/dist/core/entities/provisioned-runner.js +3 -0
- package/dist/core/entities/provisioned-runner.js.map +1 -0
- package/dist/core/entities/provisioner-token.d.ts +18 -0
- package/dist/core/entities/provisioner-token.d.ts.map +1 -0
- package/dist/core/entities/provisioner-token.js +3 -0
- package/dist/core/entities/provisioner-token.js.map +1 -0
- package/dist/core/entities/reservation.d.ts +10 -0
- package/dist/core/entities/reservation.d.ts.map +1 -0
- package/dist/core/entities/reservation.js +3 -0
- package/dist/core/entities/reservation.js.map +1 -0
- package/dist/core/entities/runner-session.d.ts +18 -0
- package/dist/core/entities/runner-session.d.ts.map +1 -0
- package/dist/core/entities/runner-session.js +3 -0
- package/dist/core/entities/runner-session.js.map +1 -0
- package/dist/core/ephemeral-registration-tokens.d.ts +31 -0
- package/dist/core/ephemeral-registration-tokens.d.ts.map +1 -0
- package/dist/core/ephemeral-registration-tokens.js +61 -0
- package/dist/core/ephemeral-registration-tokens.js.map +1 -0
- package/dist/core/errors.d.ts +62 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +92 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/index.d.ts +14 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +10 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/job-executions.d.ts +14 -0
- package/dist/core/job-executions.d.ts.map +1 -0
- package/dist/core/job-executions.js +37 -0
- package/dist/core/job-executions.js.map +1 -0
- package/dist/core/maintenance-policy.d.ts +2 -0
- package/dist/core/maintenance-policy.d.ts.map +1 -0
- package/dist/core/maintenance-policy.js +3 -0
- package/dist/core/maintenance-policy.js.map +1 -0
- package/dist/core/maintenance.d.ts +33 -0
- package/dist/core/maintenance.d.ts.map +1 -0
- package/dist/core/maintenance.js +55 -0
- package/dist/core/maintenance.js.map +1 -0
- package/dist/core/manual-registration-tokens.d.ts +17 -0
- package/dist/core/manual-registration-tokens.d.ts.map +1 -0
- package/dist/core/manual-registration-tokens.js +28 -0
- package/dist/core/manual-registration-tokens.js.map +1 -0
- package/dist/core/provisioned-runners.d.ts +67 -0
- package/dist/core/provisioned-runners.d.ts.map +1 -0
- package/dist/core/provisioned-runners.js +162 -0
- package/dist/core/provisioned-runners.js.map +1 -0
- package/dist/core/provisioner-tokens.d.ts +20 -0
- package/dist/core/provisioner-tokens.d.ts.map +1 -0
- package/dist/core/provisioner-tokens.js +36 -0
- package/dist/core/provisioner-tokens.js.map +1 -0
- package/dist/core/rate-limit.d.ts +35 -0
- package/dist/core/rate-limit.d.ts.map +1 -0
- package/dist/core/rate-limit.js +74 -0
- package/dist/core/rate-limit.js.map +1 -0
- package/dist/core/runner-sessions.d.ts +26 -0
- package/dist/core/runner-sessions.d.ts.map +1 -0
- package/dist/core/runner-sessions.js +41 -0
- package/dist/core/runner-sessions.js.map +1 -0
- package/dist/core/runner-tool-capabilities.d.ts +24 -0
- package/dist/core/runner-tool-capabilities.d.ts.map +1 -0
- package/dist/core/runner-tool-capabilities.js +43 -0
- package/dist/core/runner-tool-capabilities.js.map +1 -0
- package/dist/db/db.d.ts +4478 -0
- package/dist/db/db.d.ts.map +1 -0
- package/dist/db/db.js +36 -0
- package/dist/db/db.js.map +1 -0
- package/dist/db/ephemeral-registration-tokens.d.ts +47 -0
- package/dist/db/ephemeral-registration-tokens.d.ts.map +1 -0
- package/dist/db/ephemeral-registration-tokens.js +170 -0
- package/dist/db/ephemeral-registration-tokens.js.map +1 -0
- package/dist/db/index.d.ts +19 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +15 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/job-executions.d.ts +128 -0
- package/dist/db/job-executions.d.ts.map +1 -0
- package/dist/db/job-executions.js +354 -0
- package/dist/db/job-executions.js.map +1 -0
- package/dist/db/manual-registration-tokens.d.ts +16 -0
- package/dist/db/manual-registration-tokens.d.ts.map +1 -0
- package/dist/db/manual-registration-tokens.js +37 -0
- package/dist/db/manual-registration-tokens.js.map +1 -0
- package/dist/db/provisioned-runners.d.ts +79 -0
- package/dist/db/provisioned-runners.d.ts.map +1 -0
- package/dist/db/provisioned-runners.js +466 -0
- package/dist/db/provisioned-runners.js.map +1 -0
- package/dist/db/provisioner-tokens.d.ts +26 -0
- package/dist/db/provisioner-tokens.d.ts.map +1 -0
- package/dist/db/provisioner-tokens.js +54 -0
- package/dist/db/provisioner-tokens.js.map +1 -0
- package/dist/db/rate-limits.d.ts +18 -0
- package/dist/db/rate-limits.d.ts.map +1 -0
- package/dist/db/rate-limits.js +44 -0
- package/dist/db/rate-limits.js.map +1 -0
- package/dist/db/reservations.d.ts +48 -0
- package/dist/db/reservations.d.ts.map +1 -0
- package/dist/db/reservations.js +162 -0
- package/dist/db/reservations.js.map +1 -0
- package/dist/db/runner-sessions.d.ts +18 -0
- package/dist/db/runner-sessions.d.ts.map +1 -0
- package/dist/db/runner-sessions.js +38 -0
- package/dist/db/runner-sessions.js.map +1 -0
- package/dist/db/schema/common.d.ts +2 -0
- package/dist/db/schema/common.d.ts.map +1 -0
- package/dist/db/schema/common.js +4 -0
- package/dist/db/schema/common.js.map +1 -0
- package/dist/db/schema/ephemeral-registration-tokens.d.ts +199 -0
- package/dist/db/schema/ephemeral-registration-tokens.d.ts.map +1 -0
- package/dist/db/schema/ephemeral-registration-tokens.js +45 -0
- package/dist/db/schema/ephemeral-registration-tokens.js.map +1 -0
- package/dist/db/schema/manual-registration-tokens.d.ts +165 -0
- package/dist/db/schema/manual-registration-tokens.d.ts.map +1 -0
- package/dist/db/schema/manual-registration-tokens.js +40 -0
- package/dist/db/schema/manual-registration-tokens.js.map +1 -0
- package/dist/db/schema/outbox.d.ts +195 -0
- package/dist/db/schema/outbox.d.ts.map +1 -0
- package/dist/db/schema/outbox.js +5 -0
- package/dist/db/schema/outbox.js.map +1 -0
- package/dist/db/schema/pending-job-executions.d.ts +189 -0
- package/dist/db/schema/pending-job-executions.d.ts.map +1 -0
- package/dist/db/schema/pending-job-executions.js +21 -0
- package/dist/db/schema/pending-job-executions.js.map +1 -0
- package/dist/db/schema/provisioned-runners.d.ts +379 -0
- package/dist/db/schema/provisioned-runners.d.ts.map +1 -0
- package/dist/db/schema/provisioned-runners.js +83 -0
- package/dist/db/schema/provisioned-runners.js.map +1 -0
- package/dist/db/schema/provisioner-tokens.d.ts +216 -0
- package/dist/db/schema/provisioner-tokens.d.ts.map +1 -0
- package/dist/db/schema/provisioner-tokens.js +48 -0
- package/dist/db/schema/provisioner-tokens.js.map +1 -0
- package/dist/db/schema/rate-limits.d.ts +145 -0
- package/dist/db/schema/rate-limits.d.ts.map +1 -0
- package/dist/db/schema/rate-limits.js +25 -0
- package/dist/db/schema/rate-limits.js.map +1 -0
- package/dist/db/schema/reservations.d.ts +157 -0
- package/dist/db/schema/reservations.d.ts.map +1 -0
- package/dist/db/schema/reservations.js +34 -0
- package/dist/db/schema/reservations.js.map +1 -0
- package/dist/db/schema/runner-sessions.d.ts +298 -0
- package/dist/db/schema/runner-sessions.d.ts.map +1 -0
- package/dist/db/schema/runner-sessions.js +61 -0
- package/dist/db/schema/runner-sessions.js.map +1 -0
- package/dist/db/schema/running-job-executions.d.ts +334 -0
- package/dist/db/schema/running-job-executions.d.ts.map +1 -0
- package/dist/db/schema/running-job-executions.js +41 -0
- package/dist/db/schema/running-job-executions.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/metrics/index.d.ts +3 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +4 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/metrics/instance.d.ts +34 -0
- package/dist/metrics/instance.d.ts.map +1 -0
- package/dist/metrics/instance.js +60 -0
- package/dist/metrics/instance.js.map +1 -0
- package/dist/metrics/service.d.ts +2 -0
- package/dist/metrics/service.d.ts.map +1 -0
- package/dist/metrics/service.js +21 -0
- package/dist/metrics/service.js.map +1 -0
- package/dist/presentation/auth/index.d.ts +3 -0
- package/dist/presentation/auth/index.d.ts.map +1 -0
- package/dist/presentation/auth/index.js +4 -0
- package/dist/presentation/auth/index.js.map +1 -0
- package/dist/presentation/auth/provisioner-token-auth.d.ts +3 -0
- package/dist/presentation/auth/provisioner-token-auth.d.ts.map +1 -0
- package/dist/presentation/auth/provisioner-token-auth.js +81 -0
- package/dist/presentation/auth/provisioner-token-auth.js.map +1 -0
- package/dist/presentation/auth/runner-registration-token-auth.d.ts +17 -0
- package/dist/presentation/auth/runner-registration-token-auth.d.ts.map +1 -0
- package/dist/presentation/auth/runner-registration-token-auth.js +77 -0
- package/dist/presentation/auth/runner-registration-token-auth.js.map +1 -0
- package/dist/presentation/dto/active-provisioner.d.ts +8 -0
- package/dist/presentation/dto/active-provisioner.d.ts.map +1 -0
- package/dist/presentation/dto/active-provisioner.js +10 -0
- package/dist/presentation/dto/active-provisioner.js.map +1 -0
- package/dist/presentation/dto/index.d.ts +7 -0
- package/dist/presentation/dto/index.d.ts.map +1 -0
- package/dist/presentation/dto/index.js +8 -0
- package/dist/presentation/dto/index.js.map +1 -0
- package/dist/presentation/dto/manual-registration-token.d.ts +12 -0
- package/dist/presentation/dto/manual-registration-token.d.ts.map +1 -0
- package/dist/presentation/dto/manual-registration-token.js +14 -0
- package/dist/presentation/dto/manual-registration-token.js.map +1 -0
- package/dist/presentation/dto/mint-registration-tokens.d.ts +5 -0
- package/dist/presentation/dto/mint-registration-tokens.d.ts.map +1 -0
- package/dist/presentation/dto/mint-registration-tokens.js +19 -0
- package/dist/presentation/dto/mint-registration-tokens.js.map +1 -0
- package/dist/presentation/dto/poll-demand.d.ts +4 -0
- package/dist/presentation/dto/poll-demand.d.ts.map +1 -0
- package/dist/presentation/dto/poll-demand.js +19 -0
- package/dist/presentation/dto/poll-demand.js.map +1 -0
- package/dist/presentation/dto/provisioned-runners.d.ts +38 -0
- package/dist/presentation/dto/provisioned-runners.d.ts.map +1 -0
- package/dist/presentation/dto/provisioned-runners.js +44 -0
- package/dist/presentation/dto/provisioned-runners.js.map +1 -0
- package/dist/presentation/dto/provisioner-token.d.ts +15 -0
- package/dist/presentation/dto/provisioner-token.d.ts.map +1 -0
- package/dist/presentation/dto/provisioner-token.js +17 -0
- package/dist/presentation/dto/provisioner-token.js.map +1 -0
- package/dist/presentation/index.d.ts +4 -0
- package/dist/presentation/index.d.ts.map +1 -0
- package/dist/presentation/index.js +5 -0
- package/dist/presentation/index.js.map +1 -0
- package/dist/presentation/routes/create-manual-registration-token.d.ts +2 -0
- package/dist/presentation/routes/create-manual-registration-token.d.ts.map +1 -0
- package/dist/presentation/routes/create-manual-registration-token.js +44 -0
- package/dist/presentation/routes/create-manual-registration-token.js.map +1 -0
- package/dist/presentation/routes/create-provisioner-token.d.ts +2 -0
- package/dist/presentation/routes/create-provisioner-token.d.ts.map +1 -0
- package/dist/presentation/routes/create-provisioner-token.js +42 -0
- package/dist/presentation/routes/create-provisioner-token.js.map +1 -0
- package/dist/presentation/routes/get-provisioner-me.d.ts +2 -0
- package/dist/presentation/routes/get-provisioner-me.d.ts.map +1 -0
- package/dist/presentation/routes/get-provisioner-me.js +22 -0
- package/dist/presentation/routes/get-provisioner-me.js.map +1 -0
- package/dist/presentation/routes/heartbeat.d.ts +2 -0
- package/dist/presentation/routes/heartbeat.d.ts.map +1 -0
- package/dist/presentation/routes/heartbeat.js +64 -0
- package/dist/presentation/routes/heartbeat.js.map +1 -0
- package/dist/presentation/routes/index.d.ts +4 -0
- package/dist/presentation/routes/index.d.ts.map +1 -0
- package/dist/presentation/routes/index.js +97 -0
- package/dist/presentation/routes/index.js.map +1 -0
- package/dist/presentation/routes/list-active-provisioners.d.ts +2 -0
- package/dist/presentation/routes/list-active-provisioners.d.ts.map +1 -0
- package/dist/presentation/routes/list-active-provisioners.js +32 -0
- package/dist/presentation/routes/list-active-provisioners.js.map +1 -0
- package/dist/presentation/routes/list-active-runners.d.ts +2 -0
- package/dist/presentation/routes/list-active-runners.d.ts.map +1 -0
- package/dist/presentation/routes/list-active-runners.js +32 -0
- package/dist/presentation/routes/list-active-runners.js.map +1 -0
- package/dist/presentation/routes/list-manual-registration-tokens.d.ts +2 -0
- package/dist/presentation/routes/list-manual-registration-tokens.d.ts.map +1 -0
- package/dist/presentation/routes/list-manual-registration-tokens.js +32 -0
- package/dist/presentation/routes/list-manual-registration-tokens.js.map +1 -0
- package/dist/presentation/routes/list-provisioner-tokens.d.ts +2 -0
- package/dist/presentation/routes/list-provisioner-tokens.d.ts.map +1 -0
- package/dist/presentation/routes/list-provisioner-tokens.js +32 -0
- package/dist/presentation/routes/list-provisioner-tokens.js.map +1 -0
- package/dist/presentation/routes/mint-registration-tokens.d.ts +2 -0
- package/dist/presentation/routes/mint-registration-tokens.d.ts.map +1 -0
- package/dist/presentation/routes/mint-registration-tokens.js +74 -0
- package/dist/presentation/routes/mint-registration-tokens.js.map +1 -0
- package/dist/presentation/routes/poll-demand.d.ts +2 -0
- package/dist/presentation/routes/poll-demand.d.ts.map +1 -0
- package/dist/presentation/routes/poll-demand.js +53 -0
- package/dist/presentation/routes/poll-demand.js.map +1 -0
- package/dist/presentation/routes/rate-limit.d.ts +4 -0
- package/dist/presentation/routes/rate-limit.d.ts.map +1 -0
- package/dist/presentation/routes/rate-limit.js +94 -0
- package/dist/presentation/routes/rate-limit.js.map +1 -0
- package/dist/presentation/routes/reconcile-provisioned-runners.d.ts +2 -0
- package/dist/presentation/routes/reconcile-provisioned-runners.d.ts.map +1 -0
- package/dist/presentation/routes/reconcile-provisioned-runners.js +27 -0
- package/dist/presentation/routes/reconcile-provisioned-runners.js.map +1 -0
- package/dist/presentation/routes/register.d.ts +2 -0
- package/dist/presentation/routes/register.d.ts.map +1 -0
- package/dist/presentation/routes/register.js +63 -0
- package/dist/presentation/routes/register.js.map +1 -0
- package/dist/presentation/routes/report-provisioned-runners.d.ts +2 -0
- package/dist/presentation/routes/report-provisioned-runners.d.ts.map +1 -0
- package/dist/presentation/routes/report-provisioned-runners.js +37 -0
- package/dist/presentation/routes/report-provisioned-runners.js.map +1 -0
- package/dist/presentation/routes/request-job.d.ts +2 -0
- package/dist/presentation/routes/request-job.d.ts.map +1 -0
- package/dist/presentation/routes/request-job.js +45 -0
- package/dist/presentation/routes/request-job.js.map +1 -0
- package/dist/presentation/routes/revoke-manual-registration-token.d.ts +2 -0
- package/dist/presentation/routes/revoke-manual-registration-token.d.ts.map +1 -0
- package/dist/presentation/routes/revoke-manual-registration-token.js +42 -0
- package/dist/presentation/routes/revoke-manual-registration-token.js.map +1 -0
- package/dist/presentation/routes/revoke-provisioner-token.d.ts +2 -0
- package/dist/presentation/routes/revoke-provisioner-token.d.ts.map +1 -0
- package/dist/presentation/routes/revoke-provisioner-token.js +44 -0
- package/dist/presentation/routes/revoke-provisioner-token.js.map +1 -0
- package/dist/presentation/routes/workspace-membership.d.ts +6 -0
- package/dist/presentation/routes/workspace-membership.d.ts.map +1 -0
- package/dist/presentation/routes/workspace-membership.js +6 -0
- package/dist/presentation/routes/workspace-membership.js.map +1 -0
- package/dist/presentation/subscribers/on-workflows-job-execution-timed-out.d.ts +3 -0
- package/dist/presentation/subscribers/on-workflows-job-execution-timed-out.d.ts.map +1 -0
- package/dist/presentation/subscribers/on-workflows-job-execution-timed-out.js +14 -0
- package/dist/presentation/subscribers/on-workflows-job-execution-timed-out.js.map +1 -0
- package/dist/temporal/activities/index.d.ts +9 -0
- package/dist/temporal/activities/index.d.ts.map +1 -0
- package/dist/temporal/activities/index.js +12 -0
- package/dist/temporal/activities/index.js.map +1 -0
- package/dist/temporal/activities/maintenance-activities.d.ts +31 -0
- package/dist/temporal/activities/maintenance-activities.d.ts.map +1 -0
- package/dist/temporal/activities/maintenance-activities.js +18 -0
- package/dist/temporal/activities/maintenance-activities.js.map +1 -0
- package/dist/temporal/constants.d.ts +2 -0
- package/dist/temporal/constants.d.ts.map +1 -0
- package/dist/temporal/constants.js +3 -0
- package/dist/temporal/constants.js.map +1 -0
- package/dist/temporal/workflows/index.d.ts +2 -0
- package/dist/temporal/workflows/index.d.ts.map +1 -0
- package/dist/temporal/workflows/index.js +3 -0
- package/dist/temporal/workflows/index.js.map +1 -0
- package/dist/temporal/workflows/stuck-job-detector.d.ts +2 -0
- package/dist/temporal/workflows/stuck-job-detector.d.ts.map +1 -0
- package/dist/temporal/workflows/stuck-job-detector.js +61 -0
- package/dist/temporal/workflows/stuck-job-detector.js.map +1 -0
- package/dist/tsconfig.test.tsbuildinfo +1 -0
- package/drizzle/0000_initial.sql +185 -0
- package/drizzle/meta/0000_snapshot.json +1582 -0
- package/drizzle/meta/_journal.json +13 -0
- package/drizzle.config.ts +7 -0
- package/package.json +82 -0
- package/src/config.test.ts +374 -0
- package/src/config.ts +330 -0
- package/src/core/demand.test.ts +301 -0
- package/src/core/demand.ts +239 -0
- package/src/core/entities/ephemeral-registration-token.ts +13 -0
- package/src/core/entities/manual-registration-token.ts +11 -0
- package/src/core/entities/provisioned-runner.ts +30 -0
- package/src/core/entities/provisioner-token.ts +16 -0
- package/src/core/entities/reservation.ts +9 -0
- package/src/core/entities/runner-session.ts +18 -0
- package/src/core/ephemeral-registration-tokens.test.ts +108 -0
- package/src/core/ephemeral-registration-tokens.ts +112 -0
- package/src/core/errors.ts +128 -0
- package/src/core/index.ts +56 -0
- package/src/core/job-executions.ts +47 -0
- package/src/core/maintenance-policy.ts +1 -0
- package/src/core/maintenance.test.ts +251 -0
- package/src/core/maintenance.ts +74 -0
- package/src/core/manual-registration-tokens.test.ts +44 -0
- package/src/core/manual-registration-tokens.ts +51 -0
- package/src/core/provisioned-runners.test.ts +101 -0
- package/src/core/provisioned-runners.ts +301 -0
- package/src/core/provisioner-tokens.test.ts +61 -0
- package/src/core/provisioner-tokens.ts +61 -0
- package/src/core/rate-limit.test.ts +158 -0
- package/src/core/rate-limit.ts +121 -0
- package/src/core/runner-sessions.test.ts +209 -0
- package/src/core/runner-sessions.ts +66 -0
- package/src/core/runner-tool-capabilities.test.ts +141 -0
- package/src/core/runner-tool-capabilities.ts +75 -0
- package/src/db/db.ts +38 -0
- package/src/db/ephemeral-registration-tokens.test.ts +332 -0
- package/src/db/ephemeral-registration-tokens.ts +348 -0
- package/src/db/index.ts +90 -0
- package/src/db/job-executions.test.ts +1500 -0
- package/src/db/job-executions.ts +647 -0
- package/src/db/manual-registration-tokens.test.ts +99 -0
- package/src/db/manual-registration-tokens.ts +87 -0
- package/src/db/provisioned-runners.test.ts +1812 -0
- package/src/db/provisioned-runners.ts +886 -0
- package/src/db/provisioner-tokens.test.ts +133 -0
- package/src/db/provisioner-tokens.ts +142 -0
- package/src/db/rate-limits.test.ts +74 -0
- package/src/db/rate-limits.ts +69 -0
- package/src/db/reservations.test.ts +399 -0
- package/src/db/reservations.ts +296 -0
- package/src/db/runner-sessions.test.ts +153 -0
- package/src/db/runner-sessions.ts +97 -0
- package/src/db/schema/common.ts +3 -0
- package/src/db/schema/ephemeral-registration-tokens.ts +58 -0
- package/src/db/schema/manual-registration-tokens.ts +40 -0
- package/src/db/schema/outbox.ts +4 -0
- package/src/db/schema/pending-job-executions.ts +25 -0
- package/src/db/schema/provisioned-runners.ts +89 -0
- package/src/db/schema/provisioner-tokens.ts +50 -0
- package/src/db/schema/rate-limits.ts +27 -0
- package/src/db/schema/reservations.ts +38 -0
- package/src/db/schema/runner-sessions.ts +77 -0
- package/src/db/schema/running-job-executions.ts +50 -0
- package/src/index.ts +63 -0
- package/src/metrics/index.ts +13 -0
- package/src/metrics/instance.ts +115 -0
- package/src/metrics/service.ts +22 -0
- package/src/presentation/auth/index.ts +6 -0
- package/src/presentation/auth/provisioner-token-auth.ts +76 -0
- package/src/presentation/auth/runner-registration-token-auth.ts +105 -0
- package/src/presentation/dto/active-provisioner.ts +15 -0
- package/src/presentation/dto/index.ts +13 -0
- package/src/presentation/dto/manual-registration-token.ts +23 -0
- package/src/presentation/dto/mint-registration-tokens.ts +35 -0
- package/src/presentation/dto/poll-demand.ts +20 -0
- package/src/presentation/dto/provisioned-runners.ts +88 -0
- package/src/presentation/dto/provisioner-token.ts +29 -0
- package/src/presentation/index.ts +6 -0
- package/src/presentation/routes/create-manual-registration-token.ts +43 -0
- package/src/presentation/routes/create-provisioner-token.ts +41 -0
- package/src/presentation/routes/get-provisioner-me.ts +22 -0
- package/src/presentation/routes/heartbeat.test.ts +325 -0
- package/src/presentation/routes/heartbeat.ts +80 -0
- package/src/presentation/routes/index.ts +86 -0
- package/src/presentation/routes/list-active-provisioners.ts +25 -0
- package/src/presentation/routes/list-active-runners.test.ts +366 -0
- package/src/presentation/routes/list-active-runners.ts +25 -0
- package/src/presentation/routes/list-manual-registration-tokens.ts +25 -0
- package/src/presentation/routes/list-provisioner-tokens.ts +25 -0
- package/src/presentation/routes/manual-registration-tokens.test.ts +213 -0
- package/src/presentation/routes/mint-registration-tokens.test.ts +453 -0
- package/src/presentation/routes/mint-registration-tokens.ts +82 -0
- package/src/presentation/routes/poll-demand-release.test.ts +80 -0
- package/src/presentation/routes/poll-demand.test.ts +323 -0
- package/src/presentation/routes/poll-demand.ts +56 -0
- package/src/presentation/routes/provisioner-me.test.ts +172 -0
- package/src/presentation/routes/provisioner-tokens.test.ts +219 -0
- package/src/presentation/routes/rate-limit.ts +115 -0
- package/src/presentation/routes/reconcile-provisioned-runners.test.ts +380 -0
- package/src/presentation/routes/reconcile-provisioned-runners.ts +30 -0
- package/src/presentation/routes/register.test.ts +453 -0
- package/src/presentation/routes/register.ts +75 -0
- package/src/presentation/routes/report-provisioned-runners.test.ts +249 -0
- package/src/presentation/routes/report-provisioned-runners.ts +40 -0
- package/src/presentation/routes/request-job.test.ts +222 -0
- package/src/presentation/routes/request-job.ts +47 -0
- package/src/presentation/routes/revoke-manual-registration-token.ts +35 -0
- package/src/presentation/routes/revoke-provisioner-token.ts +37 -0
- package/src/presentation/routes/workspace-membership.ts +9 -0
- package/src/presentation/subscribers/on-workflows-job-execution-timed-out.test.ts +147 -0
- package/src/presentation/subscribers/on-workflows-job-execution-timed-out.ts +17 -0
- package/src/temporal/activities/index.ts +17 -0
- package/src/temporal/activities/maintenance-activities.test.ts +104 -0
- package/src/temporal/activities/maintenance-activities.ts +41 -0
- package/src/temporal/constants.ts +1 -0
- package/src/temporal/workflows/index.ts +1 -0
- package/src/temporal/workflows/stuck-job-detector.test.ts +93 -0
- package/src/temporal/workflows/stuck-job-detector.ts +67 -0
- package/test/env.ts +11 -0
- package/test/factories/ephemeral-registration-token.ts +41 -0
- package/test/factories/manual-registration-token.ts +37 -0
- package/test/factories/pending-job.ts +44 -0
- package/test/factories/provisioned-runner.ts +78 -0
- package/test/factories/provisioner-token.ts +41 -0
- package/test/factories/reservation.ts +33 -0
- package/test/factories/runner-session.ts +32 -0
- package/test/globalSetup.ts +23 -0
- package/test/index.ts +16 -0
- package/test/setup.ts +17 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +3 -0
- package/tsconfig.test.json +8 -0
- package/vitest.config.ts +14 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { isTerminalState, listActiveProvisionedRunners, listActiveRunningJobExecutions, reconcileProvisionedRunners as reconcileProvisionedRunnersDb, reportProvisionedRunners as reportProvisionedRunnersDb } from '#db/index.js';
|
|
2
|
+
import { provisionedRunnerAbsentTerminatedCount, provisionedRunnerReconcileCallCount, provisionedRunnerReportCount, provisionedRunnerTerminateIntentHonoredCount, provisionedRunnerTerminateIntentIssuedCount, reservationReleasedCount } from '#metrics/instance.js';
|
|
3
|
+
import { config } from '../config.js';
|
|
4
|
+
export async function reportProvisionedRunners(params) {
|
|
5
|
+
const result = await reportProvisionedRunnersDb(params);
|
|
6
|
+
for (const event of params.events){
|
|
7
|
+
provisionedRunnerReportCount.add(1, {
|
|
8
|
+
state: event.state
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
for (const intent of result.terminateIntentsHonored){
|
|
12
|
+
provisionedRunnerTerminateIntentHonoredCount.add(1, {
|
|
13
|
+
reason: intent.reason
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
if (result.reservationsReleased > 0) reservationReleasedCount.add(result.reservationsReleased);
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
export async function reconcileProvisionedRunners(params) {
|
|
20
|
+
const result = await reconcileProvisionedRunnersDb({
|
|
21
|
+
...params,
|
|
22
|
+
terminateGraceSeconds: config.RUNNER_RECONCILE_TERMINATE_GRACE_SECONDS
|
|
23
|
+
});
|
|
24
|
+
if (result.reservationsReleased > 0) reservationReleasedCount.add(result.reservationsReleased);
|
|
25
|
+
provisionedRunnerReconcileCallCount.add(1);
|
|
26
|
+
if (result.absentIds.length > 0) provisionedRunnerAbsentTerminatedCount.add(result.absentIds.length);
|
|
27
|
+
const runners = reconcileProvisionedRunnersFromDbResult({
|
|
28
|
+
observedProvisionedRunnerIds: params.observedProvisionedRunnerIds,
|
|
29
|
+
observedRows: result.observedRows,
|
|
30
|
+
boundJobExecutionsByProvisionedRunnerId: result.boundJobExecutionsByProvisionedRunnerId
|
|
31
|
+
});
|
|
32
|
+
for (const runner of runners){
|
|
33
|
+
if (runner.desiredIntentReason) {
|
|
34
|
+
provisionedRunnerTerminateIntentIssuedCount.add(1, {
|
|
35
|
+
surface: 'reconcile',
|
|
36
|
+
reason: runner.desiredIntentReason
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
runners,
|
|
42
|
+
terminatedAbsentProvisionedRunnerIds: result.absentIds
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function reconcileProvisionedRunnersFromDbResult(params) {
|
|
46
|
+
const rowsByProvisionedRunnerId = new Map(params.observedRows.map((row)=>[
|
|
47
|
+
row.provisionedRunnerId,
|
|
48
|
+
row
|
|
49
|
+
]));
|
|
50
|
+
return params.observedProvisionedRunnerIds.map((provisionedRunnerId)=>{
|
|
51
|
+
const row = rowsByProvisionedRunnerId.get(provisionedRunnerId);
|
|
52
|
+
const boundJobExecution = params.boundJobExecutionsByProvisionedRunnerId.get(provisionedRunnerId);
|
|
53
|
+
const desiredIntentReason = getDesiredIntentReason(row, boundJobExecution);
|
|
54
|
+
return {
|
|
55
|
+
provisionedRunnerId,
|
|
56
|
+
state: row?.state ?? null,
|
|
57
|
+
reservationId: row?.reservationId ?? null,
|
|
58
|
+
runnerSessionId: row?.runnerSessionId ?? null,
|
|
59
|
+
boundJobExecution: boundJobExecution ? toReconciledBoundJobExecution(boundJobExecution) : null,
|
|
60
|
+
desiredIntent: desiredIntentReason ? 'terminate' : 'keep',
|
|
61
|
+
desiredIntentReason
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
export async function listActiveRunners(params) {
|
|
66
|
+
const [provisionedRunnerRows, jobExecutionRows] = await Promise.all([
|
|
67
|
+
listActiveProvisionedRunners({
|
|
68
|
+
workspaceId: params.workspaceId,
|
|
69
|
+
windowSeconds: config.RUNNER_ACTIVE_WINDOW_SECONDS
|
|
70
|
+
}),
|
|
71
|
+
listActiveRunningJobExecutions({
|
|
72
|
+
workspaceId: params.workspaceId,
|
|
73
|
+
windowSeconds: config.RUNNER_ACTIVE_WINDOW_SECONDS
|
|
74
|
+
})
|
|
75
|
+
]);
|
|
76
|
+
return mergeActiveRunners(provisionedRunnerRows, jobExecutionRows);
|
|
77
|
+
}
|
|
78
|
+
function toReconciledBoundJobExecution(jobExecution) {
|
|
79
|
+
return {
|
|
80
|
+
jobId: jobExecution.jobId,
|
|
81
|
+
jobExecutionId: jobExecution.jobExecutionId,
|
|
82
|
+
workflowRunAttemptId: jobExecution.workflowRunAttemptId,
|
|
83
|
+
lastHeartbeatAt: jobExecution.lastHeartbeatAt,
|
|
84
|
+
cancellationRequestedAt: jobExecution.cancellationRequestedAt
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export function desiredIntent(row, boundJobExecution) {
|
|
88
|
+
return getDesiredIntentReason(row, boundJobExecution) ? 'terminate' : 'keep';
|
|
89
|
+
}
|
|
90
|
+
function getDesiredIntentReason(row, boundJobExecution) {
|
|
91
|
+
if (!row) return null;
|
|
92
|
+
if (isTerminalState(row.state)) return 'terminal-state';
|
|
93
|
+
if (boundJobExecution?.cancellationRequestedAt) return 'job-cancelled';
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
function mergeActiveRunners(provisionedRunners, jobExecutions) {
|
|
97
|
+
const jobExecutionsByRunnerSessionId = new Map();
|
|
98
|
+
const jobExecutionsByProvisionedRunnerId = new Map();
|
|
99
|
+
for (const jobExecution of jobExecutions){
|
|
100
|
+
const runnerJobExecutions = jobExecutionsByRunnerSessionId.get(jobExecution.runnerSessionId) ?? [];
|
|
101
|
+
runnerJobExecutions.push(jobExecution);
|
|
102
|
+
jobExecutionsByRunnerSessionId.set(jobExecution.runnerSessionId, runnerJobExecutions);
|
|
103
|
+
if (jobExecution.provisionerId && jobExecution.provisionedRunnerId) {
|
|
104
|
+
const key = provisionedRunnerKey(jobExecution.provisionerId, jobExecution.provisionedRunnerId);
|
|
105
|
+
const provisionedRunnerJobExecutions = jobExecutionsByProvisionedRunnerId.get(key) ?? [];
|
|
106
|
+
provisionedRunnerJobExecutions.push(jobExecution);
|
|
107
|
+
jobExecutionsByProvisionedRunnerId.set(key, provisionedRunnerJobExecutions);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const merged = [];
|
|
111
|
+
const usedJobExecutionIds = new Set();
|
|
112
|
+
for (const provisionedRunner of provisionedRunners){
|
|
113
|
+
const provisionedRunnerJobExecutions = jobExecutionsByProvisionedRunnerId.get(provisionedRunnerKey(provisionedRunner.provisionerId, provisionedRunner.provisionedRunnerId)) ?? (provisionedRunner.runnerSessionId ? jobExecutionsByRunnerSessionId.get(provisionedRunner.runnerSessionId) : undefined);
|
|
114
|
+
if (!provisionedRunnerJobExecutions || provisionedRunnerJobExecutions.length === 0) {
|
|
115
|
+
merged.push(toActiveRunner(provisionedRunner, undefined));
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
let emitted = false;
|
|
119
|
+
for (const jobExecution of provisionedRunnerJobExecutions){
|
|
120
|
+
if (usedJobExecutionIds.has(jobExecution.jobExecutionId)) continue;
|
|
121
|
+
usedJobExecutionIds.add(jobExecution.jobExecutionId);
|
|
122
|
+
merged.push(toActiveRunner(provisionedRunner, jobExecution));
|
|
123
|
+
emitted = true;
|
|
124
|
+
}
|
|
125
|
+
if (!emitted) merged.push(toActiveRunner(provisionedRunner, undefined));
|
|
126
|
+
}
|
|
127
|
+
for (const jobExecution of jobExecutions){
|
|
128
|
+
if (usedJobExecutionIds.has(jobExecution.jobExecutionId)) continue;
|
|
129
|
+
merged.push(toActiveRunner(undefined, jobExecution));
|
|
130
|
+
}
|
|
131
|
+
return merged.sort(compareActiveRunners);
|
|
132
|
+
}
|
|
133
|
+
function provisionedRunnerKey(provisionerId, provisionedRunnerId) {
|
|
134
|
+
return `${provisionerId}:${provisionedRunnerId}`;
|
|
135
|
+
}
|
|
136
|
+
function toActiveRunner(provisionedRunner, jobExecution) {
|
|
137
|
+
return {
|
|
138
|
+
runnerSessionId: provisionedRunner?.runnerSessionId ?? jobExecution?.runnerSessionId ?? null,
|
|
139
|
+
provisionedRunnerId: provisionedRunner?.provisionedRunnerId ?? jobExecution?.provisionedRunnerId ?? null,
|
|
140
|
+
provisionerId: provisionedRunner?.provisionerId ?? jobExecution?.provisionerId ?? null,
|
|
141
|
+
state: jobExecution ? 'busy' : toActiveRunnerState(provisionedRunner?.state ?? 'running'),
|
|
142
|
+
labels: provisionedRunner?.labels ?? jobExecution?.runnerLabels ?? [],
|
|
143
|
+
templateKey: provisionedRunner?.templateKey ?? null,
|
|
144
|
+
providerKind: provisionedRunner?.providerKind ?? null,
|
|
145
|
+
jobId: jobExecution?.jobId ?? null,
|
|
146
|
+
workflowRunAttemptId: jobExecution?.workflowRunAttemptId ?? null,
|
|
147
|
+
projectId: jobExecution?.projectId ?? null,
|
|
148
|
+
reportedAt: provisionedRunner?.reportedAt ?? null,
|
|
149
|
+
lastHeartbeatAt: jobExecution?.lastHeartbeatAt ?? null
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function toActiveRunnerState(state) {
|
|
153
|
+
if (state === 'starting' || state === 'stopping') return state;
|
|
154
|
+
return 'running';
|
|
155
|
+
}
|
|
156
|
+
function compareActiveRunners(a, b) {
|
|
157
|
+
const aTime = Math.max(a.lastHeartbeatAt?.getTime() ?? 0, a.reportedAt?.getTime() ?? 0);
|
|
158
|
+
const bTime = Math.max(b.lastHeartbeatAt?.getTime() ?? 0, b.reportedAt?.getTime() ?? 0);
|
|
159
|
+
return bTime - aTime;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
//# sourceMappingURL=provisioned-runners.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/provisioned-runners.ts"],"sourcesContent":["import type {ProvisionedRunner, ProvisionedRunnerState} from '#core/entities/provisioned-runner.js';\nimport {\n isTerminalState,\n listActiveProvisionedRunners,\n listActiveRunningJobExecutions,\n type ProvisionedRunnerReportEvent,\n reconcileProvisionedRunners as reconcileProvisionedRunnersDb,\n reportProvisionedRunners as reportProvisionedRunnersDb,\n} from '#db/index.js';\nimport type {\n ActiveRunningJobExecution,\n ProvisionedRunnerBoundJobExecution,\n} from '#db/job-executions.js';\nimport {\n provisionedRunnerAbsentTerminatedCount,\n provisionedRunnerReconcileCallCount,\n provisionedRunnerReportCount,\n provisionedRunnerTerminateIntentHonoredCount,\n provisionedRunnerTerminateIntentIssuedCount,\n reservationReleasedCount,\n} from '#metrics/instance.js';\nimport {config} from '../config.js';\n\nexport interface ReportProvisionedRunnersParams {\n workspaceId: string;\n provisionerId: string;\n events: ProvisionedRunnerReportEvent[];\n}\n\nexport interface ReportProvisionedRunnersResult {\n accepted: number;\n reservationsReleased: number;\n}\n\nexport interface ReconcileProvisionedRunnersParams {\n workspaceId: string;\n provisionerId: string;\n observedProvisionedRunnerIds: string[];\n}\n\nexport type ReconcileDesiredIntent = 'keep' | 'terminate';\ntype ReconcileDesiredIntentReason = 'job-cancelled' | 'terminal-state';\n\nexport interface ReconciledBoundJobExecution {\n jobId: string;\n jobExecutionId: string;\n workflowRunAttemptId: string;\n lastHeartbeatAt: Date;\n cancellationRequestedAt: Date | null;\n}\n\nexport interface ReconciledProvisionedRunner {\n provisionedRunnerId: string;\n state: ProvisionedRunnerState | null;\n reservationId: string | null;\n runnerSessionId: string | null;\n boundJobExecution: ReconciledBoundJobExecution | null;\n desiredIntent: ReconcileDesiredIntent;\n desiredIntentReason: ReconcileDesiredIntentReason | null;\n}\n\nexport interface ReconcileProvisionedRunnersResult {\n runners: ReconciledProvisionedRunner[];\n terminatedAbsentProvisionedRunnerIds: string[];\n}\n\nexport type ActiveRunnerState = 'starting' | 'running' | 'stopping' | 'busy';\n\nexport interface ActiveRunner {\n runnerSessionId: string | null;\n provisionedRunnerId: string | null;\n provisionerId: string | null;\n state: ActiveRunnerState;\n labels: string[];\n templateKey: string | null;\n providerKind: string | null;\n jobId: string | null;\n workflowRunAttemptId: string | null;\n projectId: string | null;\n reportedAt: Date | null;\n lastHeartbeatAt: Date | null;\n}\n\nexport async function reportProvisionedRunners(\n params: ReportProvisionedRunnersParams,\n): Promise<ReportProvisionedRunnersResult> {\n const result = await reportProvisionedRunnersDb(params);\n\n for (const event of params.events) {\n provisionedRunnerReportCount.add(1, {state: event.state});\n }\n for (const intent of result.terminateIntentsHonored) {\n provisionedRunnerTerminateIntentHonoredCount.add(1, {reason: intent.reason});\n }\n if (result.reservationsReleased > 0) reservationReleasedCount.add(result.reservationsReleased);\n\n return result;\n}\n\nexport async function reconcileProvisionedRunners(\n params: ReconcileProvisionedRunnersParams,\n): Promise<ReconcileProvisionedRunnersResult> {\n const result = await reconcileProvisionedRunnersDb({\n ...params,\n terminateGraceSeconds: config.RUNNER_RECONCILE_TERMINATE_GRACE_SECONDS,\n });\n\n if (result.reservationsReleased > 0) reservationReleasedCount.add(result.reservationsReleased);\n provisionedRunnerReconcileCallCount.add(1);\n if (result.absentIds.length > 0)\n provisionedRunnerAbsentTerminatedCount.add(result.absentIds.length);\n\n const runners = reconcileProvisionedRunnersFromDbResult({\n observedProvisionedRunnerIds: params.observedProvisionedRunnerIds,\n observedRows: result.observedRows,\n boundJobExecutionsByProvisionedRunnerId: result.boundJobExecutionsByProvisionedRunnerId,\n });\n for (const runner of runners) {\n if (runner.desiredIntentReason) {\n provisionedRunnerTerminateIntentIssuedCount.add(1, {\n surface: 'reconcile',\n reason: runner.desiredIntentReason,\n });\n }\n }\n\n return {\n runners,\n terminatedAbsentProvisionedRunnerIds: result.absentIds,\n };\n}\n\nexport function reconcileProvisionedRunnersFromDbResult(params: {\n observedProvisionedRunnerIds: string[];\n observedRows: ProvisionedRunner[];\n boundJobExecutionsByProvisionedRunnerId: Map<string, ProvisionedRunnerBoundJobExecution>;\n}): ReconciledProvisionedRunner[] {\n const rowsByProvisionedRunnerId = new Map(\n params.observedRows.map((row) => [row.provisionedRunnerId, row]),\n );\n\n return params.observedProvisionedRunnerIds.map((provisionedRunnerId) => {\n const row = rowsByProvisionedRunnerId.get(provisionedRunnerId);\n const boundJobExecution =\n params.boundJobExecutionsByProvisionedRunnerId.get(provisionedRunnerId);\n\n const desiredIntentReason = getDesiredIntentReason(row, boundJobExecution);\n\n return {\n provisionedRunnerId,\n state: row?.state ?? null,\n reservationId: row?.reservationId ?? null,\n runnerSessionId: row?.runnerSessionId ?? null,\n boundJobExecution: boundJobExecution\n ? toReconciledBoundJobExecution(boundJobExecution)\n : null,\n desiredIntent: desiredIntentReason ? 'terminate' : 'keep',\n desiredIntentReason,\n };\n });\n}\n\nexport async function listActiveRunners(params: {workspaceId: string}): Promise<ActiveRunner[]> {\n const [provisionedRunnerRows, jobExecutionRows] = await Promise.all([\n listActiveProvisionedRunners({\n workspaceId: params.workspaceId,\n windowSeconds: config.RUNNER_ACTIVE_WINDOW_SECONDS,\n }),\n listActiveRunningJobExecutions({\n workspaceId: params.workspaceId,\n windowSeconds: config.RUNNER_ACTIVE_WINDOW_SECONDS,\n }),\n ]);\n\n return mergeActiveRunners(provisionedRunnerRows, jobExecutionRows);\n}\n\nfunction toReconciledBoundJobExecution(\n jobExecution: ProvisionedRunnerBoundJobExecution,\n): ReconciledBoundJobExecution {\n return {\n jobId: jobExecution.jobId,\n jobExecutionId: jobExecution.jobExecutionId,\n workflowRunAttemptId: jobExecution.workflowRunAttemptId,\n lastHeartbeatAt: jobExecution.lastHeartbeatAt,\n cancellationRequestedAt: jobExecution.cancellationRequestedAt,\n };\n}\n\nexport function desiredIntent(\n row: ProvisionedRunner | undefined,\n boundJobExecution: ProvisionedRunnerBoundJobExecution | undefined,\n): ReconcileDesiredIntent {\n return getDesiredIntentReason(row, boundJobExecution) ? 'terminate' : 'keep';\n}\n\nfunction getDesiredIntentReason(\n row: ProvisionedRunner | undefined,\n boundJobExecution: ProvisionedRunnerBoundJobExecution | undefined,\n): ReconcileDesiredIntentReason | null {\n if (!row) return null;\n if (isTerminalState(row.state)) return 'terminal-state';\n if (boundJobExecution?.cancellationRequestedAt) return 'job-cancelled';\n return null;\n}\n\nfunction mergeActiveRunners(\n provisionedRunners: ProvisionedRunner[],\n jobExecutions: ActiveRunningJobExecution[],\n): ActiveRunner[] {\n const jobExecutionsByRunnerSessionId = new Map<string, ActiveRunningJobExecution[]>();\n const jobExecutionsByProvisionedRunnerId = new Map<string, ActiveRunningJobExecution[]>();\n for (const jobExecution of jobExecutions) {\n const runnerJobExecutions =\n jobExecutionsByRunnerSessionId.get(jobExecution.runnerSessionId) ?? [];\n runnerJobExecutions.push(jobExecution);\n jobExecutionsByRunnerSessionId.set(jobExecution.runnerSessionId, runnerJobExecutions);\n\n if (jobExecution.provisionerId && jobExecution.provisionedRunnerId) {\n const key = provisionedRunnerKey(\n jobExecution.provisionerId,\n jobExecution.provisionedRunnerId,\n );\n const provisionedRunnerJobExecutions = jobExecutionsByProvisionedRunnerId.get(key) ?? [];\n provisionedRunnerJobExecutions.push(jobExecution);\n jobExecutionsByProvisionedRunnerId.set(key, provisionedRunnerJobExecutions);\n }\n }\n\n const merged: ActiveRunner[] = [];\n const usedJobExecutionIds = new Set<string>();\n\n for (const provisionedRunner of provisionedRunners) {\n const provisionedRunnerJobExecutions =\n jobExecutionsByProvisionedRunnerId.get(\n provisionedRunnerKey(\n provisionedRunner.provisionerId,\n provisionedRunner.provisionedRunnerId,\n ),\n ) ??\n (provisionedRunner.runnerSessionId\n ? jobExecutionsByRunnerSessionId.get(provisionedRunner.runnerSessionId)\n : undefined);\n if (!provisionedRunnerJobExecutions || provisionedRunnerJobExecutions.length === 0) {\n merged.push(toActiveRunner(provisionedRunner, undefined));\n continue;\n }\n\n let emitted = false;\n for (const jobExecution of provisionedRunnerJobExecutions) {\n if (usedJobExecutionIds.has(jobExecution.jobExecutionId)) continue;\n usedJobExecutionIds.add(jobExecution.jobExecutionId);\n merged.push(toActiveRunner(provisionedRunner, jobExecution));\n emitted = true;\n }\n if (!emitted) merged.push(toActiveRunner(provisionedRunner, undefined));\n }\n\n for (const jobExecution of jobExecutions) {\n if (usedJobExecutionIds.has(jobExecution.jobExecutionId)) continue;\n merged.push(toActiveRunner(undefined, jobExecution));\n }\n\n return merged.sort(compareActiveRunners);\n}\n\nfunction provisionedRunnerKey(provisionerId: string, provisionedRunnerId: string): string {\n return `${provisionerId}:${provisionedRunnerId}`;\n}\n\nfunction toActiveRunner(\n provisionedRunner: ProvisionedRunner | undefined,\n jobExecution: ActiveRunningJobExecution | undefined,\n): ActiveRunner {\n return {\n runnerSessionId: provisionedRunner?.runnerSessionId ?? jobExecution?.runnerSessionId ?? null,\n provisionedRunnerId:\n provisionedRunner?.provisionedRunnerId ?? jobExecution?.provisionedRunnerId ?? null,\n provisionerId: provisionedRunner?.provisionerId ?? jobExecution?.provisionerId ?? null,\n state: jobExecution ? 'busy' : toActiveRunnerState(provisionedRunner?.state ?? 'running'),\n labels: provisionedRunner?.labels ?? jobExecution?.runnerLabels ?? [],\n templateKey: provisionedRunner?.templateKey ?? null,\n providerKind: provisionedRunner?.providerKind ?? null,\n jobId: jobExecution?.jobId ?? null,\n workflowRunAttemptId: jobExecution?.workflowRunAttemptId ?? null,\n projectId: jobExecution?.projectId ?? null,\n reportedAt: provisionedRunner?.reportedAt ?? null,\n lastHeartbeatAt: jobExecution?.lastHeartbeatAt ?? null,\n };\n}\n\nfunction toActiveRunnerState(state: ProvisionedRunnerState): ActiveRunnerState {\n if (state === 'starting' || state === 'stopping') return state;\n return 'running';\n}\n\nfunction compareActiveRunners(a: ActiveRunner, b: ActiveRunner): number {\n const aTime = Math.max(a.lastHeartbeatAt?.getTime() ?? 0, a.reportedAt?.getTime() ?? 0);\n const bTime = Math.max(b.lastHeartbeatAt?.getTime() ?? 0, b.reportedAt?.getTime() ?? 0);\n return bTime - aTime;\n}\n"],"names":["isTerminalState","listActiveProvisionedRunners","listActiveRunningJobExecutions","reconcileProvisionedRunners","reconcileProvisionedRunnersDb","reportProvisionedRunners","reportProvisionedRunnersDb","provisionedRunnerAbsentTerminatedCount","provisionedRunnerReconcileCallCount","provisionedRunnerReportCount","provisionedRunnerTerminateIntentHonoredCount","provisionedRunnerTerminateIntentIssuedCount","reservationReleasedCount","config","params","result","event","events","add","state","intent","terminateIntentsHonored","reason","reservationsReleased","terminateGraceSeconds","RUNNER_RECONCILE_TERMINATE_GRACE_SECONDS","absentIds","length","runners","reconcileProvisionedRunnersFromDbResult","observedProvisionedRunnerIds","observedRows","boundJobExecutionsByProvisionedRunnerId","runner","desiredIntentReason","surface","terminatedAbsentProvisionedRunnerIds","rowsByProvisionedRunnerId","Map","map","row","provisionedRunnerId","get","boundJobExecution","getDesiredIntentReason","reservationId","runnerSessionId","toReconciledBoundJobExecution","desiredIntent","listActiveRunners","provisionedRunnerRows","jobExecutionRows","Promise","all","workspaceId","windowSeconds","RUNNER_ACTIVE_WINDOW_SECONDS","mergeActiveRunners","jobExecution","jobId","jobExecutionId","workflowRunAttemptId","lastHeartbeatAt","cancellationRequestedAt","provisionedRunners","jobExecutions","jobExecutionsByRunnerSessionId","jobExecutionsByProvisionedRunnerId","runnerJobExecutions","push","set","provisionerId","key","provisionedRunnerKey","provisionedRunnerJobExecutions","merged","usedJobExecutionIds","Set","provisionedRunner","undefined","toActiveRunner","emitted","has","sort","compareActiveRunners","toActiveRunnerState","labels","runnerLabels","templateKey","providerKind","projectId","reportedAt","a","b","aTime","Math","max","getTime","bTime"],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ActiveProvisionerToken, ProvisionerToken } from './entities/provisioner-token.js';
|
|
2
|
+
export interface CreateWorkspaceProvisionerTokenParams {
|
|
3
|
+
workspaceId: string;
|
|
4
|
+
createdByUserId: string;
|
|
5
|
+
name?: string | undefined;
|
|
6
|
+
ttlSeconds?: number | undefined;
|
|
7
|
+
}
|
|
8
|
+
export interface CreateWorkspaceProvisionerTokenResult {
|
|
9
|
+
token: ProvisionerToken;
|
|
10
|
+
rawToken: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function createWorkspaceProvisionerToken(params: CreateWorkspaceProvisionerTokenParams): Promise<CreateWorkspaceProvisionerTokenResult>;
|
|
13
|
+
export declare function listUsableProvisionerTokens(workspaceId: string): Promise<ProvisionerToken[]>;
|
|
14
|
+
export declare function listActiveProvisioners(workspaceId: string): Promise<ActiveProvisionerToken[]>;
|
|
15
|
+
export declare function revokeWorkspaceProvisionerToken(params: {
|
|
16
|
+
tokenId: string;
|
|
17
|
+
workspaceId: string;
|
|
18
|
+
revokedByUserId: string;
|
|
19
|
+
}): Promise<ProvisionerToken>;
|
|
20
|
+
//# sourceMappingURL=provisioner-tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provisioner-tokens.d.ts","sourceRoot":"","sources":["../../src/core/provisioner-tokens.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,sBAAsB,EAAE,gBAAgB,EAAC,MAAM,iCAAiC,CAAC;AAG9F,MAAM,WAAW,qCAAqC;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAED,MAAM,WAAW,qCAAqC;IACpD,KAAK,EAAE,gBAAgB,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,+BAA+B,CACnD,MAAM,EAAE,qCAAqC,GAC5C,OAAO,CAAC,qCAAqC,CAAC,CAchD;AAED,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAE5F;AAED,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAK7F;AAED,wBAAsB,+BAA+B,CAAC,MAAM,EAAE;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAI5B"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { extractDisplayPrefix, generateOpaqueToken, hashOpaqueToken } from '@shipfox/node-tokens';
|
|
2
|
+
import { createProvisionerToken, listActiveProvisionerTokens, listUsableProvisionerTokensByWorkspaceId, revokeProvisionerToken } from '#db/provisioner-tokens.js';
|
|
3
|
+
import { config } from '../config.js';
|
|
4
|
+
import { ProvisionerTokenNotFoundError } from './errors.js';
|
|
5
|
+
export async function createWorkspaceProvisionerToken(params) {
|
|
6
|
+
const rawToken = generateOpaqueToken('provisionerToken');
|
|
7
|
+
const expiresAt = params.ttlSeconds ? new Date(Date.now() + params.ttlSeconds * 1000) : undefined;
|
|
8
|
+
const token = await createProvisionerToken({
|
|
9
|
+
workspaceId: params.workspaceId,
|
|
10
|
+
hashedToken: hashOpaqueToken(rawToken),
|
|
11
|
+
prefix: extractDisplayPrefix(rawToken),
|
|
12
|
+
name: params.name,
|
|
13
|
+
createdByUserId: params.createdByUserId,
|
|
14
|
+
expiresAt
|
|
15
|
+
});
|
|
16
|
+
return {
|
|
17
|
+
token,
|
|
18
|
+
rawToken
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function listUsableProvisionerTokens(workspaceId) {
|
|
22
|
+
return listUsableProvisionerTokensByWorkspaceId(workspaceId);
|
|
23
|
+
}
|
|
24
|
+
export function listActiveProvisioners(workspaceId) {
|
|
25
|
+
return listActiveProvisionerTokens({
|
|
26
|
+
workspaceId,
|
|
27
|
+
windowSeconds: config.PROVISIONER_ACTIVE_WINDOW_SECONDS
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
export async function revokeWorkspaceProvisionerToken(params) {
|
|
31
|
+
const token = await revokeProvisionerToken(params);
|
|
32
|
+
if (!token) throw new ProvisionerTokenNotFoundError(params.tokenId);
|
|
33
|
+
return token;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=provisioner-tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/provisioner-tokens.ts"],"sourcesContent":["import {extractDisplayPrefix, generateOpaqueToken, hashOpaqueToken} from '@shipfox/node-tokens';\nimport {\n createProvisionerToken,\n listActiveProvisionerTokens,\n listUsableProvisionerTokensByWorkspaceId,\n revokeProvisionerToken,\n} from '#db/provisioner-tokens.js';\nimport {config} from '../config.js';\nimport type {ActiveProvisionerToken, ProvisionerToken} from './entities/provisioner-token.js';\nimport {ProvisionerTokenNotFoundError} from './errors.js';\n\nexport interface CreateWorkspaceProvisionerTokenParams {\n workspaceId: string;\n createdByUserId: string;\n name?: string | undefined;\n ttlSeconds?: number | undefined;\n}\n\nexport interface CreateWorkspaceProvisionerTokenResult {\n token: ProvisionerToken;\n rawToken: string;\n}\n\nexport async function createWorkspaceProvisionerToken(\n params: CreateWorkspaceProvisionerTokenParams,\n): Promise<CreateWorkspaceProvisionerTokenResult> {\n const rawToken = generateOpaqueToken('provisionerToken');\n const expiresAt = params.ttlSeconds ? new Date(Date.now() + params.ttlSeconds * 1000) : undefined;\n\n const token = await createProvisionerToken({\n workspaceId: params.workspaceId,\n hashedToken: hashOpaqueToken(rawToken),\n prefix: extractDisplayPrefix(rawToken),\n name: params.name,\n createdByUserId: params.createdByUserId,\n expiresAt,\n });\n\n return {token, rawToken};\n}\n\nexport function listUsableProvisionerTokens(workspaceId: string): Promise<ProvisionerToken[]> {\n return listUsableProvisionerTokensByWorkspaceId(workspaceId);\n}\n\nexport function listActiveProvisioners(workspaceId: string): Promise<ActiveProvisionerToken[]> {\n return listActiveProvisionerTokens({\n workspaceId,\n windowSeconds: config.PROVISIONER_ACTIVE_WINDOW_SECONDS,\n });\n}\n\nexport async function revokeWorkspaceProvisionerToken(params: {\n tokenId: string;\n workspaceId: string;\n revokedByUserId: string;\n}): Promise<ProvisionerToken> {\n const token = await revokeProvisionerToken(params);\n if (!token) throw new ProvisionerTokenNotFoundError(params.tokenId);\n return token;\n}\n"],"names":["extractDisplayPrefix","generateOpaqueToken","hashOpaqueToken","createProvisionerToken","listActiveProvisionerTokens","listUsableProvisionerTokensByWorkspaceId","revokeProvisionerToken","config","ProvisionerTokenNotFoundError","createWorkspaceProvisionerToken","params","rawToken","expiresAt","ttlSeconds","Date","now","undefined","token","workspaceId","hashedToken","prefix","name","createdByUserId","listUsableProvisionerTokens","listActiveProvisioners","windowSeconds","PROVISIONER_ACTIVE_WINDOW_SECONDS","revokeWorkspaceProvisionerToken","tokenId"],"mappings":"AAAA,SAAQA,oBAAoB,EAAEC,mBAAmB,EAAEC,eAAe,QAAO,uBAAuB;AAChG,SACEC,sBAAsB,EACtBC,2BAA2B,EAC3BC,wCAAwC,EACxCC,sBAAsB,QACjB,4BAA4B;AACnC,SAAQC,MAAM,QAAO,eAAe;AAEpC,SAAQC,6BAA6B,QAAO,cAAc;AAc1D,OAAO,eAAeC,gCACpBC,MAA6C;IAE7C,MAAMC,WAAWV,oBAAoB;IACrC,MAAMW,YAAYF,OAAOG,UAAU,GAAG,IAAIC,KAAKA,KAAKC,GAAG,KAAKL,OAAOG,UAAU,GAAG,QAAQG;IAExF,MAAMC,QAAQ,MAAMd,uBAAuB;QACzCe,aAAaR,OAAOQ,WAAW;QAC/BC,aAAajB,gBAAgBS;QAC7BS,QAAQpB,qBAAqBW;QAC7BU,MAAMX,OAAOW,IAAI;QACjBC,iBAAiBZ,OAAOY,eAAe;QACvCV;IACF;IAEA,OAAO;QAACK;QAAON;IAAQ;AACzB;AAEA,OAAO,SAASY,4BAA4BL,WAAmB;IAC7D,OAAOb,yCAAyCa;AAClD;AAEA,OAAO,SAASM,uBAAuBN,WAAmB;IACxD,OAAOd,4BAA4B;QACjCc;QACAO,eAAelB,OAAOmB,iCAAiC;IACzD;AACF;AAEA,OAAO,eAAeC,gCAAgCjB,MAIrD;IACC,MAAMO,QAAQ,MAAMX,uBAAuBI;IAC3C,IAAI,CAACO,OAAO,MAAM,IAAIT,8BAA8BE,OAAOkB,OAAO;IAClE,OAAOX;AACT"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { RateLimitExceededError, type RateLimitOutcome, type RateLimitPolicy, RateLimitUnavailableError } from '@shipfox/node-rate-limit';
|
|
2
|
+
export type RunnersRateLimitAction = 'provisioner-mint' | 'ephemeral-register';
|
|
3
|
+
export type RunnersRateLimitScope = 'provisioner' | 'ephemeral-token';
|
|
4
|
+
export type RunnersRateLimitOutcome = RateLimitOutcome;
|
|
5
|
+
export type RunnersRateLimitPolicy = RateLimitPolicy;
|
|
6
|
+
export interface CheckRunnersRateLimitParams extends RunnersRateLimitPolicy {
|
|
7
|
+
action: RunnersRateLimitAction;
|
|
8
|
+
scope: RunnersRateLimitScope;
|
|
9
|
+
identifier: string;
|
|
10
|
+
now?: Date | undefined;
|
|
11
|
+
timeoutMs?: number | undefined;
|
|
12
|
+
}
|
|
13
|
+
export declare class RunnersRateLimitExceededError extends RateLimitExceededError<RunnersRateLimitAction, RunnersRateLimitScope> {
|
|
14
|
+
constructor(params: {
|
|
15
|
+
action: RunnersRateLimitAction;
|
|
16
|
+
scope: RunnersRateLimitScope;
|
|
17
|
+
retryAfterSeconds: number;
|
|
18
|
+
identifierHmacPrefix: string;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export declare class RunnersRateLimitUnavailableError extends RateLimitUnavailableError<RunnersRateLimitAction, RunnersRateLimitScope> {
|
|
22
|
+
constructor(params: {
|
|
23
|
+
action: RunnersRateLimitAction;
|
|
24
|
+
scope: RunnersRateLimitScope;
|
|
25
|
+
identifierHmacPrefix: string;
|
|
26
|
+
cause: unknown;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export declare function hashRunnersRateLimitIdentifier(params: {
|
|
30
|
+
action: RunnersRateLimitAction;
|
|
31
|
+
scope: RunnersRateLimitScope;
|
|
32
|
+
identifier: string;
|
|
33
|
+
}): string;
|
|
34
|
+
export declare function checkRunnersRateLimit(params: CheckRunnersRateLimitParams): Promise<void>;
|
|
35
|
+
//# sourceMappingURL=rate-limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/core/rate-limit.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,yBAAyB,EAC1B,MAAM,0BAA0B,CAAC;AAKlC,MAAM,MAAM,sBAAsB,GAAG,kBAAkB,GAAG,oBAAoB,CAAC;AAC/E,MAAM,MAAM,qBAAqB,GAAG,aAAa,GAAG,iBAAiB,CAAC;AACtE,MAAM,MAAM,uBAAuB,GAAG,gBAAgB,CAAC;AACvD,MAAM,MAAM,sBAAsB,GAAG,eAAe,CAAC;AAErD,MAAM,WAAW,2BAA4B,SAAQ,sBAAsB;IACzE,MAAM,EAAE,sBAAsB,CAAC;IAC/B,KAAK,EAAE,qBAAqB,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,qBAAa,6BAA8B,SAAQ,sBAAsB,CACvE,sBAAsB,EACtB,qBAAqB,CACtB;gBACa,MAAM,EAAE;QAClB,MAAM,EAAE,sBAAsB,CAAC;QAC/B,KAAK,EAAE,qBAAqB,CAAC;QAC7B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,oBAAoB,EAAE,MAAM,CAAC;KAC9B;CAIF;AAED,qBAAa,gCAAiC,SAAQ,yBAAyB,CAC7E,sBAAsB,EACtB,qBAAqB,CACtB;gBACa,MAAM,EAAE;QAClB,MAAM,EAAE,sBAAsB,CAAC;QAC/B,KAAK,EAAE,qBAAqB,CAAC;QAC7B,oBAAoB,EAAE,MAAM,CAAC;QAC7B,KAAK,EAAE,OAAO,CAAC;KAChB;CAIF;AAKD,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,MAAM,EAAE,sBAAsB,CAAC;IAC/B,KAAK,EAAE,qBAAqB,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CAQT;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAoC9F"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { createHmac } from 'node:crypto';
|
|
2
|
+
import { config as authConfig } from '@shipfox/api-auth/config';
|
|
3
|
+
import { checkRateLimit, hashRateLimitIdentifier, RateLimitExceededError, RateLimitUnavailableError } from '@shipfox/node-rate-limit';
|
|
4
|
+
import { config } from '#config.js';
|
|
5
|
+
import { consumeRunnersRateLimit, pruneExpiredRunnersRateLimits } from '#db/rate-limits.js';
|
|
6
|
+
import { recordRunnersRateLimitCheck, recordRunnersRateLimitPruneFailure } from '#metrics/index.js';
|
|
7
|
+
export class RunnersRateLimitExceededError extends RateLimitExceededError {
|
|
8
|
+
constructor(params){
|
|
9
|
+
super(params);
|
|
10
|
+
this.name = 'RunnersRateLimitExceededError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class RunnersRateLimitUnavailableError extends RateLimitUnavailableError {
|
|
14
|
+
constructor(params){
|
|
15
|
+
super(params);
|
|
16
|
+
this.name = 'RunnersRateLimitUnavailableError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const IDENTIFIER_HASH_DOMAIN = 'shipfox.runners.rate-limit.identifier.v1';
|
|
20
|
+
const IDENTIFIER_SECRET_DERIVATION_DOMAIN = 'shipfox.runners.rate-limit.identifier-secret.v1';
|
|
21
|
+
export function hashRunnersRateLimitIdentifier(params) {
|
|
22
|
+
return hashRateLimitIdentifier({
|
|
23
|
+
action: params.action,
|
|
24
|
+
scope: params.scope,
|
|
25
|
+
identifier: params.identifier,
|
|
26
|
+
secret: effectiveIdentifierSecret(),
|
|
27
|
+
domain: IDENTIFIER_HASH_DOMAIN
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
export async function checkRunnersRateLimit(params) {
|
|
31
|
+
try {
|
|
32
|
+
await checkRateLimit({
|
|
33
|
+
action: params.action,
|
|
34
|
+
scope: params.scope,
|
|
35
|
+
identifier: params.identifier,
|
|
36
|
+
limit: params.limit,
|
|
37
|
+
windowSeconds: params.windowSeconds,
|
|
38
|
+
identifierSecret: effectiveIdentifierSecret(),
|
|
39
|
+
identifierHashDomain: IDENTIFIER_HASH_DOMAIN,
|
|
40
|
+
consume: consumeRunnersRateLimit,
|
|
41
|
+
prune: pruneExpiredRunnersRateLimits,
|
|
42
|
+
onCheck: recordRunnersRateLimitCheck,
|
|
43
|
+
onPruneFailure: recordRunnersRateLimitPruneFailure,
|
|
44
|
+
now: params.now,
|
|
45
|
+
timeoutMs: params.timeoutMs ?? config.RUNNERS_RATE_LIMIT_TIMEOUT_MS
|
|
46
|
+
});
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (error instanceof RateLimitExceededError) {
|
|
49
|
+
throw new RunnersRateLimitExceededError({
|
|
50
|
+
action: error.action,
|
|
51
|
+
scope: error.scope,
|
|
52
|
+
retryAfterSeconds: error.retryAfterSeconds,
|
|
53
|
+
identifierHmacPrefix: error.identifierHmacPrefix
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
if (error instanceof RateLimitUnavailableError) {
|
|
57
|
+
throw new RunnersRateLimitUnavailableError({
|
|
58
|
+
action: error.action,
|
|
59
|
+
scope: error.scope,
|
|
60
|
+
identifierHmacPrefix: error.identifierHmacPrefix,
|
|
61
|
+
cause: error.cause
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function effectiveIdentifierSecret() {
|
|
68
|
+
if (config.RATE_LIMIT_IDENTIFIER_SECRET) {
|
|
69
|
+
return config.RATE_LIMIT_IDENTIFIER_SECRET;
|
|
70
|
+
}
|
|
71
|
+
return createHmac('sha256', authConfig.AUTH_JWT_SECRET).update(IDENTIFIER_SECRET_DERIVATION_DOMAIN).digest();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
//# sourceMappingURL=rate-limit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/rate-limit.ts"],"sourcesContent":["import {createHmac} from 'node:crypto';\nimport {config as authConfig} from '@shipfox/api-auth/config';\nimport {\n checkRateLimit,\n hashRateLimitIdentifier,\n RateLimitExceededError,\n type RateLimitOutcome,\n type RateLimitPolicy,\n RateLimitUnavailableError,\n} from '@shipfox/node-rate-limit';\nimport {config} from '#config.js';\nimport {consumeRunnersRateLimit, pruneExpiredRunnersRateLimits} from '#db/rate-limits.js';\nimport {recordRunnersRateLimitCheck, recordRunnersRateLimitPruneFailure} from '#metrics/index.js';\n\nexport type RunnersRateLimitAction = 'provisioner-mint' | 'ephemeral-register';\nexport type RunnersRateLimitScope = 'provisioner' | 'ephemeral-token';\nexport type RunnersRateLimitOutcome = RateLimitOutcome;\nexport type RunnersRateLimitPolicy = RateLimitPolicy;\n\nexport interface CheckRunnersRateLimitParams extends RunnersRateLimitPolicy {\n action: RunnersRateLimitAction;\n scope: RunnersRateLimitScope;\n identifier: string;\n now?: Date | undefined;\n timeoutMs?: number | undefined;\n}\n\nexport class RunnersRateLimitExceededError extends RateLimitExceededError<\n RunnersRateLimitAction,\n RunnersRateLimitScope\n> {\n constructor(params: {\n action: RunnersRateLimitAction;\n scope: RunnersRateLimitScope;\n retryAfterSeconds: number;\n identifierHmacPrefix: string;\n }) {\n super(params);\n this.name = 'RunnersRateLimitExceededError';\n }\n}\n\nexport class RunnersRateLimitUnavailableError extends RateLimitUnavailableError<\n RunnersRateLimitAction,\n RunnersRateLimitScope\n> {\n constructor(params: {\n action: RunnersRateLimitAction;\n scope: RunnersRateLimitScope;\n identifierHmacPrefix: string;\n cause: unknown;\n }) {\n super(params);\n this.name = 'RunnersRateLimitUnavailableError';\n }\n}\n\nconst IDENTIFIER_HASH_DOMAIN = 'shipfox.runners.rate-limit.identifier.v1';\nconst IDENTIFIER_SECRET_DERIVATION_DOMAIN = 'shipfox.runners.rate-limit.identifier-secret.v1';\n\nexport function hashRunnersRateLimitIdentifier(params: {\n action: RunnersRateLimitAction;\n scope: RunnersRateLimitScope;\n identifier: string;\n}): string {\n return hashRateLimitIdentifier({\n action: params.action,\n scope: params.scope,\n identifier: params.identifier,\n secret: effectiveIdentifierSecret(),\n domain: IDENTIFIER_HASH_DOMAIN,\n });\n}\n\nexport async function checkRunnersRateLimit(params: CheckRunnersRateLimitParams): Promise<void> {\n try {\n await checkRateLimit({\n action: params.action,\n scope: params.scope,\n identifier: params.identifier,\n limit: params.limit,\n windowSeconds: params.windowSeconds,\n identifierSecret: effectiveIdentifierSecret(),\n identifierHashDomain: IDENTIFIER_HASH_DOMAIN,\n consume: consumeRunnersRateLimit,\n prune: pruneExpiredRunnersRateLimits,\n onCheck: recordRunnersRateLimitCheck,\n onPruneFailure: recordRunnersRateLimitPruneFailure,\n now: params.now,\n timeoutMs: params.timeoutMs ?? config.RUNNERS_RATE_LIMIT_TIMEOUT_MS,\n });\n } catch (error) {\n if (error instanceof RateLimitExceededError) {\n throw new RunnersRateLimitExceededError({\n action: error.action,\n scope: error.scope,\n retryAfterSeconds: error.retryAfterSeconds,\n identifierHmacPrefix: error.identifierHmacPrefix,\n });\n }\n if (error instanceof RateLimitUnavailableError) {\n throw new RunnersRateLimitUnavailableError({\n action: error.action,\n scope: error.scope,\n identifierHmacPrefix: error.identifierHmacPrefix,\n cause: error.cause,\n });\n }\n throw error;\n }\n}\n\nfunction effectiveIdentifierSecret(): Buffer | string {\n if (config.RATE_LIMIT_IDENTIFIER_SECRET) {\n return config.RATE_LIMIT_IDENTIFIER_SECRET;\n }\n\n return createHmac('sha256', authConfig.AUTH_JWT_SECRET)\n .update(IDENTIFIER_SECRET_DERIVATION_DOMAIN)\n .digest();\n}\n"],"names":["createHmac","config","authConfig","checkRateLimit","hashRateLimitIdentifier","RateLimitExceededError","RateLimitUnavailableError","consumeRunnersRateLimit","pruneExpiredRunnersRateLimits","recordRunnersRateLimitCheck","recordRunnersRateLimitPruneFailure","RunnersRateLimitExceededError","params","name","RunnersRateLimitUnavailableError","IDENTIFIER_HASH_DOMAIN","IDENTIFIER_SECRET_DERIVATION_DOMAIN","hashRunnersRateLimitIdentifier","action","scope","identifier","secret","effectiveIdentifierSecret","domain","checkRunnersRateLimit","limit","windowSeconds","identifierSecret","identifierHashDomain","consume","prune","onCheck","onPruneFailure","now","timeoutMs","RUNNERS_RATE_LIMIT_TIMEOUT_MS","error","retryAfterSeconds","identifierHmacPrefix","cause","RATE_LIMIT_IDENTIFIER_SECRET","AUTH_JWT_SECRET","update","digest"],"mappings":"AAAA,SAAQA,UAAU,QAAO,cAAc;AACvC,SAAQC,UAAUC,UAAU,QAAO,2BAA2B;AAC9D,SACEC,cAAc,EACdC,uBAAuB,EACvBC,sBAAsB,EAGtBC,yBAAyB,QACpB,2BAA2B;AAClC,SAAQL,MAAM,QAAO,aAAa;AAClC,SAAQM,uBAAuB,EAAEC,6BAA6B,QAAO,qBAAqB;AAC1F,SAAQC,2BAA2B,EAAEC,kCAAkC,QAAO,oBAAoB;AAelG,OAAO,MAAMC,sCAAsCN;IAIjD,YAAYO,MAKX,CAAE;QACD,KAAK,CAACA;QACN,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMC,yCAAyCR;IAIpD,YAAYM,MAKX,CAAE;QACD,KAAK,CAACA;QACN,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,MAAME,yBAAyB;AAC/B,MAAMC,sCAAsC;AAE5C,OAAO,SAASC,+BAA+BL,MAI9C;IACC,OAAOR,wBAAwB;QAC7Bc,QAAQN,OAAOM,MAAM;QACrBC,OAAOP,OAAOO,KAAK;QACnBC,YAAYR,OAAOQ,UAAU;QAC7BC,QAAQC;QACRC,QAAQR;IACV;AACF;AAEA,OAAO,eAAeS,sBAAsBZ,MAAmC;IAC7E,IAAI;QACF,MAAMT,eAAe;YACnBe,QAAQN,OAAOM,MAAM;YACrBC,OAAOP,OAAOO,KAAK;YACnBC,YAAYR,OAAOQ,UAAU;YAC7BK,OAAOb,OAAOa,KAAK;YACnBC,eAAed,OAAOc,aAAa;YACnCC,kBAAkBL;YAClBM,sBAAsBb;YACtBc,SAAStB;YACTuB,OAAOtB;YACPuB,SAAStB;YACTuB,gBAAgBtB;YAChBuB,KAAKrB,OAAOqB,GAAG;YACfC,WAAWtB,OAAOsB,SAAS,IAAIjC,OAAOkC,6BAA6B;QACrE;IACF,EAAE,OAAOC,OAAO;QACd,IAAIA,iBAAiB/B,wBAAwB;YAC3C,MAAM,IAAIM,8BAA8B;gBACtCO,QAAQkB,MAAMlB,MAAM;gBACpBC,OAAOiB,MAAMjB,KAAK;gBAClBkB,mBAAmBD,MAAMC,iBAAiB;gBAC1CC,sBAAsBF,MAAME,oBAAoB;YAClD;QACF;QACA,IAAIF,iBAAiB9B,2BAA2B;YAC9C,MAAM,IAAIQ,iCAAiC;gBACzCI,QAAQkB,MAAMlB,MAAM;gBACpBC,OAAOiB,MAAMjB,KAAK;gBAClBmB,sBAAsBF,MAAME,oBAAoB;gBAChDC,OAAOH,MAAMG,KAAK;YACpB;QACF;QACA,MAAMH;IACR;AACF;AAEA,SAASd;IACP,IAAIrB,OAAOuC,4BAA4B,EAAE;QACvC,OAAOvC,OAAOuC,4BAA4B;IAC5C;IAEA,OAAOxC,WAAW,UAAUE,WAAWuC,eAAe,EACnDC,MAAM,CAAC1B,qCACP2B,MAAM;AACX"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { RunnerToolCapabilitiesDto } from '@shipfox/api-runners-dto';
|
|
2
|
+
import type { RunnerSession } from './entities/runner-session.js';
|
|
3
|
+
export interface RegisterRunnerSessionResult {
|
|
4
|
+
session: RunnerSession;
|
|
5
|
+
sessionToken: string;
|
|
6
|
+
mode: 'manual' | 'ephemeral';
|
|
7
|
+
maxClaims: number | null;
|
|
8
|
+
}
|
|
9
|
+
export type RunnerRegistrationCredential = {
|
|
10
|
+
kind: 'manual';
|
|
11
|
+
registrationTokenId: string;
|
|
12
|
+
workspaceId: string;
|
|
13
|
+
} | {
|
|
14
|
+
kind: 'ephemeral';
|
|
15
|
+
ephemeralTokenId: string;
|
|
16
|
+
workspaceId: string;
|
|
17
|
+
provisionerId: string;
|
|
18
|
+
reservationId: string | null;
|
|
19
|
+
provisionedRunnerId: string;
|
|
20
|
+
};
|
|
21
|
+
export declare function registerRunnerSession(params: {
|
|
22
|
+
credential: RunnerRegistrationCredential;
|
|
23
|
+
labels: string[];
|
|
24
|
+
toolCapabilities?: RunnerToolCapabilitiesDto | null;
|
|
25
|
+
}): Promise<RegisterRunnerSessionResult>;
|
|
26
|
+
//# sourceMappingURL=runner-sessions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner-sessions.d.ts","sourceRoot":"","sources":["../../src/core/runner-sessions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,0BAA0B,CAAC;AAIxE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,8BAA8B,CAAC;AAGhE,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,aAAa,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,QAAQ,GAAG,WAAW,CAAC;IAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,MAAM,4BAA4B,GACpC;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;CACrB,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEN,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,UAAU,EAAE,4BAA4B,CAAC;IACzC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,gBAAgB,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;CACrD,GAAG,OAAO,CAAC,2BAA2B,CAAC,CA+BvC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { issueRunnerSessionToken } from '@shipfox/api-auth';
|
|
2
|
+
import { canonicalizeLabels } from '@shipfox/runner-labels';
|
|
3
|
+
import { createRunnerSessionConsumingEphemeralToken } from '#db/ephemeral-registration-tokens.js';
|
|
4
|
+
import { createRunnerSession } from '#db/runner-sessions.js';
|
|
5
|
+
import { EmptyRunnerLabelsError } from './errors.js';
|
|
6
|
+
export async function registerRunnerSession(params) {
|
|
7
|
+
const labels = [
|
|
8
|
+
...canonicalizeLabels(params.labels)
|
|
9
|
+
];
|
|
10
|
+
if (labels.length === 0) throw new EmptyRunnerLabelsError();
|
|
11
|
+
const mode = params.credential.kind;
|
|
12
|
+
const maxClaims = params.credential.kind === 'ephemeral' ? 1 : null;
|
|
13
|
+
const session = params.credential.kind === 'manual' ? await createRunnerSession({
|
|
14
|
+
workspaceId: params.credential.workspaceId,
|
|
15
|
+
scope: 'workspace',
|
|
16
|
+
registrationTokenId: params.credential.registrationTokenId,
|
|
17
|
+
labels,
|
|
18
|
+
toolCapabilities: params.toolCapabilities ?? null
|
|
19
|
+
}) : await createRunnerSessionConsumingEphemeralToken({
|
|
20
|
+
ephemeralTokenId: params.credential.ephemeralTokenId,
|
|
21
|
+
workspaceId: params.credential.workspaceId,
|
|
22
|
+
labels,
|
|
23
|
+
toolCapabilities: params.toolCapabilities ?? null,
|
|
24
|
+
maxClaims: 1
|
|
25
|
+
});
|
|
26
|
+
const sessionToken = await issueRunnerSessionToken({
|
|
27
|
+
runnerSessionId: session.id,
|
|
28
|
+
workspaceId: session.workspaceId,
|
|
29
|
+
scope: session.scope,
|
|
30
|
+
labels: session.labels,
|
|
31
|
+
maxClaims
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
session,
|
|
35
|
+
sessionToken,
|
|
36
|
+
mode,
|
|
37
|
+
maxClaims
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=runner-sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/runner-sessions.ts"],"sourcesContent":["import {issueRunnerSessionToken} from '@shipfox/api-auth';\nimport type {RunnerToolCapabilitiesDto} from '@shipfox/api-runners-dto';\nimport {canonicalizeLabels} from '@shipfox/runner-labels';\nimport {createRunnerSessionConsumingEphemeralToken} from '#db/ephemeral-registration-tokens.js';\nimport {createRunnerSession} from '#db/runner-sessions.js';\nimport type {RunnerSession} from './entities/runner-session.js';\nimport {EmptyRunnerLabelsError} from './errors.js';\n\nexport interface RegisterRunnerSessionResult {\n session: RunnerSession;\n sessionToken: string;\n mode: 'manual' | 'ephemeral';\n maxClaims: number | null;\n}\n\nexport type RunnerRegistrationCredential =\n | {\n kind: 'manual';\n registrationTokenId: string;\n workspaceId: string;\n }\n | {\n kind: 'ephemeral';\n ephemeralTokenId: string;\n workspaceId: string;\n provisionerId: string;\n reservationId: string | null;\n provisionedRunnerId: string;\n };\n\nexport async function registerRunnerSession(params: {\n credential: RunnerRegistrationCredential;\n labels: string[];\n toolCapabilities?: RunnerToolCapabilitiesDto | null;\n}): Promise<RegisterRunnerSessionResult> {\n const labels = [...canonicalizeLabels(params.labels)];\n if (labels.length === 0) throw new EmptyRunnerLabelsError();\n\n const mode = params.credential.kind;\n const maxClaims = params.credential.kind === 'ephemeral' ? 1 : null;\n const session =\n params.credential.kind === 'manual'\n ? await createRunnerSession({\n workspaceId: params.credential.workspaceId,\n scope: 'workspace',\n registrationTokenId: params.credential.registrationTokenId,\n labels,\n toolCapabilities: params.toolCapabilities ?? null,\n })\n : await createRunnerSessionConsumingEphemeralToken({\n ephemeralTokenId: params.credential.ephemeralTokenId,\n workspaceId: params.credential.workspaceId,\n labels,\n toolCapabilities: params.toolCapabilities ?? null,\n maxClaims: 1,\n });\n const sessionToken = await issueRunnerSessionToken({\n runnerSessionId: session.id,\n workspaceId: session.workspaceId,\n scope: session.scope,\n labels: session.labels,\n maxClaims,\n });\n\n return {session, sessionToken, mode, maxClaims};\n}\n"],"names":["issueRunnerSessionToken","canonicalizeLabels","createRunnerSessionConsumingEphemeralToken","createRunnerSession","EmptyRunnerLabelsError","registerRunnerSession","params","labels","length","mode","credential","kind","maxClaims","session","workspaceId","scope","registrationTokenId","toolCapabilities","ephemeralTokenId","sessionToken","runnerSessionId","id"],"mappings":"AAAA,SAAQA,uBAAuB,QAAO,oBAAoB;AAE1D,SAAQC,kBAAkB,QAAO,yBAAyB;AAC1D,SAAQC,0CAA0C,QAAO,uCAAuC;AAChG,SAAQC,mBAAmB,QAAO,yBAAyB;AAE3D,SAAQC,sBAAsB,QAAO,cAAc;AAwBnD,OAAO,eAAeC,sBAAsBC,MAI3C;IACC,MAAMC,SAAS;WAAIN,mBAAmBK,OAAOC,MAAM;KAAE;IACrD,IAAIA,OAAOC,MAAM,KAAK,GAAG,MAAM,IAAIJ;IAEnC,MAAMK,OAAOH,OAAOI,UAAU,CAACC,IAAI;IACnC,MAAMC,YAAYN,OAAOI,UAAU,CAACC,IAAI,KAAK,cAAc,IAAI;IAC/D,MAAME,UACJP,OAAOI,UAAU,CAACC,IAAI,KAAK,WACvB,MAAMR,oBAAoB;QACxBW,aAAaR,OAAOI,UAAU,CAACI,WAAW;QAC1CC,OAAO;QACPC,qBAAqBV,OAAOI,UAAU,CAACM,mBAAmB;QAC1DT;QACAU,kBAAkBX,OAAOW,gBAAgB,IAAI;IAC/C,KACA,MAAMf,2CAA2C;QAC/CgB,kBAAkBZ,OAAOI,UAAU,CAACQ,gBAAgB;QACpDJ,aAAaR,OAAOI,UAAU,CAACI,WAAW;QAC1CP;QACAU,kBAAkBX,OAAOW,gBAAgB,IAAI;QAC7CL,WAAW;IACb;IACN,MAAMO,eAAe,MAAMnB,wBAAwB;QACjDoB,iBAAiBP,QAAQQ,EAAE;QAC3BP,aAAaD,QAAQC,WAAW;QAChCC,OAAOF,QAAQE,KAAK;QACpBR,QAAQM,QAAQN,MAAM;QACtBK;IACF;IAEA,OAAO;QAACC;QAASM;QAAcV;QAAMG;IAAS;AAChD"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RunnerToolCapabilitiesDto } from '@shipfox/api-runners-dto';
|
|
2
|
+
type RunnerToolHarness = keyof RunnerToolCapabilitiesDto['harnesses'];
|
|
3
|
+
export declare const EMPTY_RUNNER_TOOL_CAPABILITIES: RunnerToolCapabilitiesDto;
|
|
4
|
+
export declare function effectiveRunnerToolCapabilities(params: {
|
|
5
|
+
toolCapabilities: RunnerToolCapabilitiesDto | null;
|
|
6
|
+
reportedAt: Date | null;
|
|
7
|
+
staleAfterSeconds: number;
|
|
8
|
+
now?: Date;
|
|
9
|
+
}): RunnerToolCapabilitiesDto;
|
|
10
|
+
export declare function unadvertisedRunnerTools(params: {
|
|
11
|
+
harness: RunnerToolHarness;
|
|
12
|
+
requestedTools: readonly string[];
|
|
13
|
+
capabilities: RunnerToolCapabilitiesDto;
|
|
14
|
+
}): string[];
|
|
15
|
+
export interface EffectiveRunnerToolCapabilitiesResult {
|
|
16
|
+
capabilities: RunnerToolCapabilitiesDto;
|
|
17
|
+
reportFresh: boolean;
|
|
18
|
+
harnessKnown(harness: RunnerToolHarness): boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function getEffectiveRunnerToolCapabilities(params: {
|
|
21
|
+
runnerSessionId: string;
|
|
22
|
+
}): Promise<EffectiveRunnerToolCapabilitiesResult>;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=runner-tool-capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner-tool-capabilities.d.ts","sourceRoot":"","sources":["../../src/core/runner-tool-capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,0BAA0B,CAAC;AAIxE,KAAK,iBAAiB,GAAG,MAAM,yBAAyB,CAAC,WAAW,CAAC,CAAC;AAEtE,eAAO,MAAM,8BAA8B,EAAE,yBAE5C,CAAC;AAEF,wBAAgB,+BAA+B,CAAC,MAAM,EAAE;IACtD,gBAAgB,EAAE,yBAAyB,GAAG,IAAI,CAAC;IACnD,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ,GAAG,yBAAyB,CAQ5B;AAeD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,OAAO,EAAE,iBAAiB,CAAC;IAC3B,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,YAAY,EAAE,yBAAyB,CAAC;CACzC,GAAG,MAAM,EAAE,CAGX;AAED,MAAM,WAAW,qCAAqC;IACpD,YAAY,EAAE,yBAAyB,CAAC;IACxC,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC;CACnD;AAED,wBAAsB,kCAAkC,CAAC,MAAM,EAAE;IAC/D,eAAe,EAAE,MAAM,CAAC;CACzB,GAAG,OAAO,CAAC,qCAAqC,CAAC,CAmBjD"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { config } from '#config.js';
|
|
2
|
+
import { getRunnerSessionById } from '#db/runner-sessions.js';
|
|
3
|
+
export const EMPTY_RUNNER_TOOL_CAPABILITIES = {
|
|
4
|
+
harnesses: {}
|
|
5
|
+
};
|
|
6
|
+
export function effectiveRunnerToolCapabilities(params) {
|
|
7
|
+
if (!params.toolCapabilities || !params.reportedAt) return EMPTY_RUNNER_TOOL_CAPABILITIES;
|
|
8
|
+
const now = params.now ?? new Date();
|
|
9
|
+
const ageMs = now.getTime() - params.reportedAt.getTime();
|
|
10
|
+
if (ageMs > params.staleAfterSeconds * 1000) return EMPTY_RUNNER_TOOL_CAPABILITIES;
|
|
11
|
+
return params.toolCapabilities;
|
|
12
|
+
}
|
|
13
|
+
function runnerToolCapabilityReportIsFresh(params) {
|
|
14
|
+
if (!params.toolCapabilities || !params.reportedAt) return false;
|
|
15
|
+
const now = params.now ?? new Date();
|
|
16
|
+
const ageMs = now.getTime() - params.reportedAt.getTime();
|
|
17
|
+
return ageMs <= params.staleAfterSeconds * 1000;
|
|
18
|
+
}
|
|
19
|
+
export function unadvertisedRunnerTools(params) {
|
|
20
|
+
const advertised = new Set(params.capabilities.harnesses[params.harness]?.tools ?? []);
|
|
21
|
+
return params.requestedTools.filter((tool)=>!advertised.has(tool));
|
|
22
|
+
}
|
|
23
|
+
export async function getEffectiveRunnerToolCapabilities(params) {
|
|
24
|
+
const runnerSession = await getRunnerSessionById(params.runnerSessionId);
|
|
25
|
+
const staleAfterSeconds = config.RUNNER_TOOL_CAPABILITIES_STALE_AFTER_SECONDS;
|
|
26
|
+
const capabilities = effectiveRunnerToolCapabilities({
|
|
27
|
+
toolCapabilities: runnerSession?.toolCapabilities ?? null,
|
|
28
|
+
reportedAt: runnerSession?.toolCapabilitiesReportedAt ?? null,
|
|
29
|
+
staleAfterSeconds
|
|
30
|
+
});
|
|
31
|
+
const reportFresh = runnerToolCapabilityReportIsFresh({
|
|
32
|
+
toolCapabilities: runnerSession?.toolCapabilities,
|
|
33
|
+
reportedAt: runnerSession?.toolCapabilitiesReportedAt,
|
|
34
|
+
staleAfterSeconds
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
capabilities,
|
|
38
|
+
reportFresh,
|
|
39
|
+
harnessKnown: (harness)=>capabilities.harnesses[harness] !== undefined
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//# sourceMappingURL=runner-tool-capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/runner-tool-capabilities.ts"],"sourcesContent":["import type {RunnerToolCapabilitiesDto} from '@shipfox/api-runners-dto';\nimport {config} from '#config.js';\nimport {getRunnerSessionById} from '#db/runner-sessions.js';\n\ntype RunnerToolHarness = keyof RunnerToolCapabilitiesDto['harnesses'];\n\nexport const EMPTY_RUNNER_TOOL_CAPABILITIES: RunnerToolCapabilitiesDto = {\n harnesses: {},\n};\n\nexport function effectiveRunnerToolCapabilities(params: {\n toolCapabilities: RunnerToolCapabilitiesDto | null;\n reportedAt: Date | null;\n staleAfterSeconds: number;\n now?: Date;\n}): RunnerToolCapabilitiesDto {\n if (!params.toolCapabilities || !params.reportedAt) return EMPTY_RUNNER_TOOL_CAPABILITIES;\n\n const now = params.now ?? new Date();\n const ageMs = now.getTime() - params.reportedAt.getTime();\n if (ageMs > params.staleAfterSeconds * 1000) return EMPTY_RUNNER_TOOL_CAPABILITIES;\n\n return params.toolCapabilities;\n}\n\nfunction runnerToolCapabilityReportIsFresh(params: {\n toolCapabilities: RunnerToolCapabilitiesDto | null | undefined;\n reportedAt: Date | null | undefined;\n staleAfterSeconds: number;\n now?: Date;\n}): boolean {\n if (!params.toolCapabilities || !params.reportedAt) return false;\n\n const now = params.now ?? new Date();\n const ageMs = now.getTime() - params.reportedAt.getTime();\n return ageMs <= params.staleAfterSeconds * 1000;\n}\n\nexport function unadvertisedRunnerTools(params: {\n harness: RunnerToolHarness;\n requestedTools: readonly string[];\n capabilities: RunnerToolCapabilitiesDto;\n}): string[] {\n const advertised = new Set(params.capabilities.harnesses[params.harness]?.tools ?? []);\n return params.requestedTools.filter((tool) => !advertised.has(tool));\n}\n\nexport interface EffectiveRunnerToolCapabilitiesResult {\n capabilities: RunnerToolCapabilitiesDto;\n reportFresh: boolean;\n harnessKnown(harness: RunnerToolHarness): boolean;\n}\n\nexport async function getEffectiveRunnerToolCapabilities(params: {\n runnerSessionId: string;\n}): Promise<EffectiveRunnerToolCapabilitiesResult> {\n const runnerSession = await getRunnerSessionById(params.runnerSessionId);\n const staleAfterSeconds = config.RUNNER_TOOL_CAPABILITIES_STALE_AFTER_SECONDS;\n const capabilities = effectiveRunnerToolCapabilities({\n toolCapabilities: runnerSession?.toolCapabilities ?? null,\n reportedAt: runnerSession?.toolCapabilitiesReportedAt ?? null,\n staleAfterSeconds,\n });\n const reportFresh = runnerToolCapabilityReportIsFresh({\n toolCapabilities: runnerSession?.toolCapabilities,\n reportedAt: runnerSession?.toolCapabilitiesReportedAt,\n staleAfterSeconds,\n });\n\n return {\n capabilities,\n reportFresh,\n harnessKnown: (harness) => capabilities.harnesses[harness] !== undefined,\n };\n}\n"],"names":["config","getRunnerSessionById","EMPTY_RUNNER_TOOL_CAPABILITIES","harnesses","effectiveRunnerToolCapabilities","params","toolCapabilities","reportedAt","now","Date","ageMs","getTime","staleAfterSeconds","runnerToolCapabilityReportIsFresh","unadvertisedRunnerTools","advertised","Set","capabilities","harness","tools","requestedTools","filter","tool","has","getEffectiveRunnerToolCapabilities","runnerSession","runnerSessionId","RUNNER_TOOL_CAPABILITIES_STALE_AFTER_SECONDS","toolCapabilitiesReportedAt","reportFresh","harnessKnown","undefined"],"mappings":"AACA,SAAQA,MAAM,QAAO,aAAa;AAClC,SAAQC,oBAAoB,QAAO,yBAAyB;AAI5D,OAAO,MAAMC,iCAA4D;IACvEC,WAAW,CAAC;AACd,EAAE;AAEF,OAAO,SAASC,gCAAgCC,MAK/C;IACC,IAAI,CAACA,OAAOC,gBAAgB,IAAI,CAACD,OAAOE,UAAU,EAAE,OAAOL;IAE3D,MAAMM,MAAMH,OAAOG,GAAG,IAAI,IAAIC;IAC9B,MAAMC,QAAQF,IAAIG,OAAO,KAAKN,OAAOE,UAAU,CAACI,OAAO;IACvD,IAAID,QAAQL,OAAOO,iBAAiB,GAAG,MAAM,OAAOV;IAEpD,OAAOG,OAAOC,gBAAgB;AAChC;AAEA,SAASO,kCAAkCR,MAK1C;IACC,IAAI,CAACA,OAAOC,gBAAgB,IAAI,CAACD,OAAOE,UAAU,EAAE,OAAO;IAE3D,MAAMC,MAAMH,OAAOG,GAAG,IAAI,IAAIC;IAC9B,MAAMC,QAAQF,IAAIG,OAAO,KAAKN,OAAOE,UAAU,CAACI,OAAO;IACvD,OAAOD,SAASL,OAAOO,iBAAiB,GAAG;AAC7C;AAEA,OAAO,SAASE,wBAAwBT,MAIvC;IACC,MAAMU,aAAa,IAAIC,IAAIX,OAAOY,YAAY,CAACd,SAAS,CAACE,OAAOa,OAAO,CAAC,EAAEC,SAAS,EAAE;IACrF,OAAOd,OAAOe,cAAc,CAACC,MAAM,CAAC,CAACC,OAAS,CAACP,WAAWQ,GAAG,CAACD;AAChE;AAQA,OAAO,eAAeE,mCAAmCnB,MAExD;IACC,MAAMoB,gBAAgB,MAAMxB,qBAAqBI,OAAOqB,eAAe;IACvE,MAAMd,oBAAoBZ,OAAO2B,4CAA4C;IAC7E,MAAMV,eAAeb,gCAAgC;QACnDE,kBAAkBmB,eAAenB,oBAAoB;QACrDC,YAAYkB,eAAeG,8BAA8B;QACzDhB;IACF;IACA,MAAMiB,cAAchB,kCAAkC;QACpDP,kBAAkBmB,eAAenB;QACjCC,YAAYkB,eAAeG;QAC3BhB;IACF;IAEA,OAAO;QACLK;QACAY;QACAC,cAAc,CAACZ,UAAYD,aAAad,SAAS,CAACe,QAAQ,KAAKa;IACjE;AACF"}
|