@tokenfactory/acc-runner 0.44.8 → 0.44.10

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 (183) hide show
  1. package/README.md +38 -0
  2. package/dist/attachments/codex-stage.d.ts +11 -0
  3. package/dist/attachments/codex-stage.d.ts.map +1 -0
  4. package/dist/attachments/codex-stage.js +82 -0
  5. package/dist/attachments/codex-stage.js.map +1 -0
  6. package/dist/attachments/fetch-attachment.d.ts +17 -0
  7. package/dist/attachments/fetch-attachment.d.ts.map +1 -1
  8. package/dist/attachments/fetch-attachment.js +134 -6
  9. package/dist/attachments/fetch-attachment.js.map +1 -1
  10. package/dist/attachments/index.d.ts +2 -1
  11. package/dist/attachments/index.d.ts.map +1 -1
  12. package/dist/attachments/index.js +2 -1
  13. package/dist/attachments/index.js.map +1 -1
  14. package/dist/build-info.generated.d.ts +1 -1
  15. package/dist/build-info.generated.js +2 -2
  16. package/dist/commit-sha.d.ts +31 -0
  17. package/dist/commit-sha.d.ts.map +1 -0
  18. package/dist/commit-sha.js +31 -0
  19. package/dist/commit-sha.js.map +1 -0
  20. package/dist/companion-run.d.ts.map +1 -1
  21. package/dist/companion-run.js +14 -1
  22. package/dist/companion-run.js.map +1 -1
  23. package/dist/device-refusal.d.ts +70 -0
  24. package/dist/device-refusal.d.ts.map +1 -0
  25. package/dist/device-refusal.js +97 -0
  26. package/dist/device-refusal.js.map +1 -0
  27. package/dist/doctor.d.ts +16 -0
  28. package/dist/doctor.d.ts.map +1 -1
  29. package/dist/doctor.js +107 -0
  30. package/dist/doctor.js.map +1 -1
  31. package/dist/engines/codex-chat.d.ts +10 -1
  32. package/dist/engines/codex-chat.d.ts.map +1 -1
  33. package/dist/engines/codex-chat.js +32 -2
  34. package/dist/engines/codex-chat.js.map +1 -1
  35. package/dist/login.d.ts.map +1 -1
  36. package/dist/login.js +32 -3
  37. package/dist/login.js.map +1 -1
  38. package/dist/machine-console/index.d.ts +6 -10
  39. package/dist/machine-console/index.d.ts.map +1 -1
  40. package/dist/machine-console/index.js +61 -54
  41. package/dist/machine-console/index.js.map +1 -1
  42. package/dist/machine-console/redact.d.ts.map +1 -1
  43. package/dist/machine-console/redact.js +10 -1
  44. package/dist/machine-console/redact.js.map +1 -1
  45. package/dist/machine-console/transport.d.ts +57 -0
  46. package/dist/machine-console/transport.d.ts.map +1 -0
  47. package/dist/machine-console/transport.js +170 -0
  48. package/dist/machine-console/transport.js.map +1 -0
  49. package/dist/preview-environments/control-plane.d.ts +11 -0
  50. package/dist/preview-environments/control-plane.d.ts.map +1 -0
  51. package/dist/preview-environments/control-plane.js +49 -0
  52. package/dist/preview-environments/control-plane.js.map +1 -0
  53. package/dist/preview-environments/http-provider.d.ts +13 -0
  54. package/dist/preview-environments/http-provider.d.ts.map +1 -0
  55. package/dist/preview-environments/http-provider.js +64 -0
  56. package/dist/preview-environments/http-provider.js.map +1 -0
  57. package/dist/preview-environments/profiles.d.ts +6 -0
  58. package/dist/preview-environments/profiles.d.ts.map +1 -0
  59. package/dist/preview-environments/profiles.js +34 -0
  60. package/dist/preview-environments/profiles.js.map +1 -0
  61. package/dist/preview-environments/safety.d.ts +7 -0
  62. package/dist/preview-environments/safety.d.ts.map +1 -0
  63. package/dist/preview-environments/safety.js +47 -0
  64. package/dist/preview-environments/safety.js.map +1 -0
  65. package/dist/preview-environments/service.d.ts +36 -0
  66. package/dist/preview-environments/service.d.ts.map +1 -0
  67. package/dist/preview-environments/service.js +149 -0
  68. package/dist/preview-environments/service.js.map +1 -0
  69. package/dist/preview-environments/types.d.ts +60 -0
  70. package/dist/preview-environments/types.d.ts.map +1 -0
  71. package/dist/preview-environments/types.js +2 -0
  72. package/dist/preview-environments/types.js.map +1 -0
  73. package/dist/production-migrations/command.d.ts +3 -0
  74. package/dist/production-migrations/command.d.ts.map +1 -0
  75. package/dist/production-migrations/command.js +21 -0
  76. package/dist/production-migrations/command.js.map +1 -0
  77. package/dist/production-migrations/executor.d.ts +59 -0
  78. package/dist/production-migrations/executor.d.ts.map +1 -0
  79. package/dist/production-migrations/executor.js +161 -0
  80. package/dist/production-migrations/executor.js.map +1 -0
  81. package/dist/production-migrations/pg-target.d.ts +22 -0
  82. package/dist/production-migrations/pg-target.d.ts.map +1 -0
  83. package/dist/production-migrations/pg-target.js +87 -0
  84. package/dist/production-migrations/pg-target.js.map +1 -0
  85. package/dist/production-migrations/profiles.d.ts +5 -0
  86. package/dist/production-migrations/profiles.d.ts.map +1 -0
  87. package/dist/production-migrations/profiles.js +39 -0
  88. package/dist/production-migrations/profiles.js.map +1 -0
  89. package/dist/production-migrations/service.d.ts +39 -0
  90. package/dist/production-migrations/service.d.ts.map +1 -0
  91. package/dist/production-migrations/service.js +166 -0
  92. package/dist/production-migrations/service.js.map +1 -0
  93. package/dist/program.d.ts.map +1 -1
  94. package/dist/program.js +17 -0
  95. package/dist/program.js.map +1 -1
  96. package/dist/runtime/worktree.d.ts.map +1 -1
  97. package/dist/runtime/worktree.js +23 -1
  98. package/dist/runtime/worktree.js.map +1 -1
  99. package/dist/secure-execution/auto-lease.d.ts +57 -0
  100. package/dist/secure-execution/auto-lease.d.ts.map +1 -0
  101. package/dist/secure-execution/auto-lease.js +116 -0
  102. package/dist/secure-execution/auto-lease.js.map +1 -0
  103. package/dist/secure-execution/command-policy.d.ts +5 -0
  104. package/dist/secure-execution/command-policy.d.ts.map +1 -0
  105. package/dist/secure-execution/command-policy.js +95 -0
  106. package/dist/secure-execution/command-policy.js.map +1 -0
  107. package/dist/secure-execution/confinement.d.ts +3 -0
  108. package/dist/secure-execution/confinement.d.ts.map +1 -0
  109. package/dist/secure-execution/confinement.js +18 -0
  110. package/dist/secure-execution/confinement.js.map +1 -0
  111. package/dist/secure-execution/engine.d.ts +24 -0
  112. package/dist/secure-execution/engine.d.ts.map +1 -0
  113. package/dist/secure-execution/engine.js +272 -0
  114. package/dist/secure-execution/engine.js.map +1 -0
  115. package/dist/secure-execution/index.d.ts +7 -0
  116. package/dist/secure-execution/index.d.ts.map +1 -0
  117. package/dist/secure-execution/index.js +6 -0
  118. package/dist/secure-execution/index.js.map +1 -0
  119. package/dist/secure-execution/node-pty.d.ts +11 -0
  120. package/dist/secure-execution/node-pty.d.ts.map +1 -0
  121. package/dist/secure-execution/node-pty.js +27 -0
  122. package/dist/secure-execution/node-pty.js.map +1 -0
  123. package/dist/secure-execution/types.d.ts +176 -0
  124. package/dist/secure-execution/types.d.ts.map +1 -0
  125. package/dist/secure-execution/types.js +2 -0
  126. package/dist/secure-execution/types.js.map +1 -0
  127. package/dist/staging-migrations/command.d.ts +2 -0
  128. package/dist/staging-migrations/command.d.ts.map +1 -0
  129. package/dist/staging-migrations/command.js +58 -0
  130. package/dist/staging-migrations/command.js.map +1 -0
  131. package/dist/staging-migrations/executor.d.ts +49 -0
  132. package/dist/staging-migrations/executor.d.ts.map +1 -0
  133. package/dist/staging-migrations/executor.js +125 -0
  134. package/dist/staging-migrations/executor.js.map +1 -0
  135. package/dist/staging-migrations/pg-target.d.ts +20 -0
  136. package/dist/staging-migrations/pg-target.d.ts.map +1 -0
  137. package/dist/staging-migrations/pg-target.js +63 -0
  138. package/dist/staging-migrations/pg-target.js.map +1 -0
  139. package/dist/staging-migrations/profiles.d.ts +5 -0
  140. package/dist/staging-migrations/profiles.d.ts.map +1 -0
  141. package/dist/staging-migrations/profiles.js +31 -0
  142. package/dist/staging-migrations/profiles.js.map +1 -0
  143. package/dist/staging-migrations/service.d.ts +40 -0
  144. package/dist/staging-migrations/service.d.ts.map +1 -0
  145. package/dist/staging-migrations/service.js +157 -0
  146. package/dist/staging-migrations/service.js.map +1 -0
  147. package/dist/supervisor.d.ts +15 -0
  148. package/dist/supervisor.d.ts.map +1 -0
  149. package/dist/supervisor.js +54 -0
  150. package/dist/supervisor.js.map +1 -0
  151. package/dist/terminal/http-carrier.d.ts +17 -0
  152. package/dist/terminal/http-carrier.d.ts.map +1 -0
  153. package/dist/terminal/http-carrier.js +39 -0
  154. package/dist/terminal/http-carrier.js.map +1 -0
  155. package/dist/terminal/pty-adapter.d.ts +88 -0
  156. package/dist/terminal/pty-adapter.d.ts.map +1 -0
  157. package/dist/terminal/pty-adapter.js +252 -0
  158. package/dist/terminal/pty-adapter.js.map +1 -0
  159. package/dist/terminal/transport-contract.d.ts +115 -0
  160. package/dist/terminal/transport-contract.d.ts.map +1 -0
  161. package/dist/terminal/transport-contract.js +2 -0
  162. package/dist/terminal/transport-contract.js.map +1 -0
  163. package/dist/terminal/transport.d.ts +32 -0
  164. package/dist/terminal/transport.d.ts.map +1 -0
  165. package/dist/terminal/transport.js +208 -0
  166. package/dist/terminal/transport.js.map +1 -0
  167. package/dist/types.d.ts +22 -0
  168. package/dist/types.d.ts.map +1 -1
  169. package/dist/watch-chat/wire.d.ts.map +1 -1
  170. package/dist/watch-chat/wire.js +14 -1
  171. package/dist/watch-chat/wire.js.map +1 -1
  172. package/dist/watch.d.ts.map +1 -1
  173. package/dist/watch.js +32 -0
  174. package/dist/watch.js.map +1 -1
  175. package/package.json +6 -1
  176. package/scripts/com.tokenfactory.acc-runner-dedicated.plist +64 -0
  177. package/scripts/com.tokenfactory.acc-runner.plist +90 -0
  178. package/scripts/gen-build-info.d.mts +3 -0
  179. package/scripts/gen-build-info.mjs +72 -0
  180. package/scripts/install-launchd.sh +235 -0
  181. package/scripts/setup-dedicated-runner-darwin.sh +75 -0
  182. package/scripts/setup-dedicated-runner-linux.sh +173 -0
  183. package/scripts/uninstall-launchd.sh +67 -0
@@ -0,0 +1,149 @@
1
+ import { SupabasePreviewControlPlane } from "./control-plane.js";
2
+ import { providerForProfile } from "./profiles.js";
3
+ import { desiredAction, deterministicUuid, receiptSha, safePreviewCode, validateLease, } from "./safety.js";
4
+ export class PreviewEnvironmentService {
5
+ runnerId;
6
+ options;
7
+ timer = null;
8
+ active = false;
9
+ stopping = false;
10
+ env;
11
+ logger;
12
+ pollMs;
13
+ timeoutMs;
14
+ staleAfterMs;
15
+ batchSize;
16
+ controlPlane;
17
+ constructor(cfg, runnerId, options = {}) {
18
+ this.runnerId = runnerId;
19
+ this.options = options;
20
+ this.env = options.env ?? process.env;
21
+ this.logger = options.logger ?? console;
22
+ this.pollMs = bounded(options.pollMs ?? Number(this.env.ACC_PREVIEW_POLL_MS ?? 30_000), 5_000, 300_000);
23
+ this.timeoutMs = bounded(options.timeoutMs ?? Number(this.env.ACC_PREVIEW_ACTION_TIMEOUT_MS ?? 120_000), 5_000, 600_000);
24
+ this.staleAfterMs = Math.max(this.timeoutMs * 2, 180_000);
25
+ this.batchSize = bounded(options.batchSize ?? Number(this.env.ACC_PREVIEW_BATCH_SIZE ?? 10), 1, 50);
26
+ this.controlPlane = options.controlPlane ?? new SupabasePreviewControlPlane(cfg.supabaseUrl, this.env.ACC_PREVIEW_CONTROL_PLANE_SERVICE_ROLE_KEY ?? "");
27
+ }
28
+ start() {
29
+ if (this.timer)
30
+ return;
31
+ this.stopping = false;
32
+ void this.pollOnce();
33
+ this.timer = setInterval(() => void this.pollOnce(), this.pollMs);
34
+ this.timer.unref?.();
35
+ }
36
+ async stop() {
37
+ this.stopping = true;
38
+ if (this.timer)
39
+ clearInterval(this.timer);
40
+ this.timer = null;
41
+ const deadline = Date.now() + this.timeoutMs;
42
+ while (this.active && Date.now() < deadline)
43
+ await new Promise((resolve) => setTimeout(resolve, 25));
44
+ }
45
+ async pollOnce() {
46
+ if (this.active || this.stopping)
47
+ return;
48
+ this.active = true;
49
+ try {
50
+ const rows = await this.controlPlane.listCandidates(this.batchSize);
51
+ for (const row of rows) {
52
+ if (this.stopping)
53
+ break;
54
+ await this.process(row);
55
+ }
56
+ }
57
+ catch (error) {
58
+ this.logger.error(`[acc-runner] preview environment service: ${safePreviewCode(error)}`);
59
+ }
60
+ finally {
61
+ this.active = false;
62
+ }
63
+ }
64
+ async process(row) {
65
+ const action = desiredAction(row, Date.now(), this.staleAfterMs);
66
+ if (!action)
67
+ return "skipped";
68
+ try {
69
+ validateLease(row);
70
+ if (action !== "stop" && action !== "archive" && Date.parse(row.lease_expires_at) <= Date.now())
71
+ throw new Error("preview_lease_expired");
72
+ const providerDeploymentId = row.provider_deployment_id ?? row.deployment_identity_sha;
73
+ const recovering = row.observed_state === "provisioning";
74
+ const claimReceipt = { action, runner_id: this.runnerId, generation: row.generation, recovering };
75
+ const claim = await this.controlPlane.recordObservation({
76
+ environmentId: row.id,
77
+ generation: row.generation,
78
+ observedState: "provisioning",
79
+ providerDeploymentId,
80
+ providerReceiptSha: receiptSha(claimReceipt),
81
+ idempotencyKey: deterministicUuid(row.id, row.generation, action, recovering ? `recover:${row.updated_at}` : "claim"),
82
+ });
83
+ if (claim.idempotent_replay)
84
+ return "skipped";
85
+ const controller = new AbortController();
86
+ const timeout = setTimeout(() => controller.abort(new Error("preview_provider_timeout")), this.timeoutMs);
87
+ try {
88
+ const adapter = this.options.providerFactory?.(row.provider, row.provider_credential_profile_ref) ??
89
+ providerForProfile(row.provider, row.provider_credential_profile_ref, this.env);
90
+ const result = await adapter.execute({
91
+ action,
92
+ environmentId: row.id,
93
+ orgId: row.org_id,
94
+ projectId: row.project_id,
95
+ repo: row.repo,
96
+ pullRequestNumber: row.pull_request_number,
97
+ headSha: row.head_sha,
98
+ generation: row.generation,
99
+ deploymentIdentity: row.deployment_identity_sha,
100
+ providerDeploymentId,
101
+ leaseExpiresAt: row.lease_expires_at,
102
+ signal: controller.signal,
103
+ });
104
+ const providerReceiptSha = receiptSha(result.receipt);
105
+ await this.controlPlane.recordObservation({
106
+ environmentId: row.id,
107
+ generation: row.generation,
108
+ observedState: result.observedState,
109
+ providerDeploymentId: result.providerDeploymentId,
110
+ previewUrl: result.previewUrl,
111
+ providerReceiptSha,
112
+ idempotencyKey: deterministicUuid(row.id, row.generation, action, "complete"),
113
+ });
114
+ await this.controlPlane.audit("preview.environment_runner_completed", row.id, {
115
+ runner_id: this.runnerId,
116
+ action,
117
+ generation: row.generation,
118
+ provider_receipt_sha: providerReceiptSha,
119
+ }).catch((error) => {
120
+ this.logger.error(`[acc-runner] preview audit: ${safePreviewCode(error)}`);
121
+ });
122
+ return "succeeded";
123
+ }
124
+ finally {
125
+ clearTimeout(timeout);
126
+ }
127
+ }
128
+ catch (error) {
129
+ const failureCode = safePreviewCode(error);
130
+ const providerDeploymentId = row.provider_deployment_id ?? row.deployment_identity_sha;
131
+ await this.controlPlane.recordObservation({
132
+ environmentId: row.id,
133
+ generation: row.generation,
134
+ observedState: "failed",
135
+ providerDeploymentId,
136
+ providerReceiptSha: receiptSha({ failureCode }),
137
+ failureCode,
138
+ idempotencyKey: deterministicUuid(row.id, row.generation, action, "failed"),
139
+ }).catch(() => undefined);
140
+ this.logger.error(`[acc-runner] preview environment ${row.id}: ${failureCode}`);
141
+ return "failed";
142
+ }
143
+ }
144
+ }
145
+ function bounded(value, min, max) {
146
+ return Number.isFinite(value) ? Math.max(min, Math.min(max, Math.floor(value))) : min;
147
+ }
148
+ export { previewEnvironmentCaps, previewEnvironmentServiceEnabled } from "./profiles.js";
149
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/preview-environments/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ export type PreviewDesiredState = "active" | "promoted" | "stopped" | "archived";
2
+ export type PreviewObservedState = "pending" | "provisioning" | "ready" | "failed" | "stopped" | "archived";
3
+ export type PreviewAction = "create" | "refresh" | "promote" | "stop" | "archive";
4
+ export interface PreviewEnvironmentLease {
5
+ id: string;
6
+ org_id: string;
7
+ project_id: string;
8
+ repo: string;
9
+ pull_request_number: number;
10
+ head_sha: string;
11
+ provider: string;
12
+ provider_credential_profile_ref: string;
13
+ deployment_identity_sha: string;
14
+ provider_deployment_id: string | null;
15
+ desired_state: PreviewDesiredState;
16
+ observed_state: PreviewObservedState;
17
+ generation: number;
18
+ lease_expires_at: string;
19
+ updated_at: string;
20
+ }
21
+ export interface PreviewProviderRequest {
22
+ action: PreviewAction;
23
+ environmentId: string;
24
+ orgId: string;
25
+ projectId: string;
26
+ repo: string;
27
+ pullRequestNumber: number;
28
+ headSha: string;
29
+ generation: number;
30
+ deploymentIdentity: string;
31
+ providerDeploymentId: string;
32
+ leaseExpiresAt: string;
33
+ signal: AbortSignal;
34
+ }
35
+ export interface PreviewProviderResult {
36
+ providerDeploymentId: string;
37
+ observedState: Exclude<PreviewObservedState, "pending" | "provisioning">;
38
+ previewUrl?: string | null;
39
+ receipt: Record<string, unknown>;
40
+ }
41
+ export interface PreviewProviderAdapter {
42
+ execute(request: PreviewProviderRequest): Promise<PreviewProviderResult>;
43
+ }
44
+ export interface PreviewControlPlane {
45
+ listCandidates(limit: number): Promise<PreviewEnvironmentLease[]>;
46
+ recordObservation(input: {
47
+ environmentId: string;
48
+ generation: number;
49
+ observedState: Exclude<PreviewObservedState, "pending">;
50
+ providerDeploymentId: string;
51
+ previewUrl?: string | null;
52
+ providerReceiptSha: string;
53
+ failureCode?: string | null;
54
+ idempotencyKey: string;
55
+ }): Promise<{
56
+ idempotent_replay?: boolean;
57
+ }>;
58
+ audit(verb: string, environmentId: string, payload: Record<string, unknown>): Promise<void>;
59
+ }
60
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/preview-environments/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC;AACjF,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;AAC5G,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAElF,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,+BAA+B,EAAE,MAAM,CAAC;IACxC,uBAAuB,EAAE,MAAM,CAAC;IAChC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,aAAa,EAAE,mBAAmB,CAAC;IACnC,cAAc,EAAE,oBAAoB,CAAC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC,oBAAoB,EAAE,SAAS,GAAG,cAAc,CAAC,CAAC;IACzE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CAC1E;AAED,MAAM,WAAW,mBAAmB;IAClC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAAC;IAClE,iBAAiB,CAAC,KAAK,EAAE;QACvB,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;QACnB,aAAa,EAAE,OAAO,CAAC,oBAAoB,EAAE,SAAS,CAAC,CAAC;QACxD,oBAAoB,EAAE,MAAM,CAAC;QAC7B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,cAAc,EAAE,MAAM,CAAC;KACxB,GAAG,OAAO,CAAC;QAAE,iBAAiB,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC7C,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7F"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/preview-environments/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ /** Explicit single-promotion entrypoint; the claim RPC is always the authority. */
2
+ export declare function applyApprovedProductionMigrationCommand(promotionId: string): Promise<void>;
3
+ //# sourceMappingURL=command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/production-migrations/command.ts"],"names":[],"mappings":"AAKA,mFAAmF;AACnF,wBAAsB,uCAAuC,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWhG"}
@@ -0,0 +1,21 @@
1
+ import { loadConfig } from "../config.js";
2
+ import { getTokenProvider } from "../token-provider.js";
3
+ import { createRunnerClient } from "../supabase.js";
4
+ import { ProductionMigrationService } from "./service.js";
5
+ /** Explicit single-promotion entrypoint; the claim RPC is always the authority. */
6
+ export async function applyApprovedProductionMigrationCommand(promotionId) {
7
+ if (!/^[0-9a-f-]{36}$/i.test(promotionId))
8
+ throw new Error("invalid production promotion id");
9
+ const cfg = loadConfig();
10
+ const session = await getTokenProvider().load();
11
+ if (!session?.runner_id)
12
+ throw new Error("runner login required");
13
+ const sb = createRunnerClient(cfg, session.access_token, session.realtime_config);
14
+ const service = new ProductionMigrationService(sb, cfg, session.runner_id, {
15
+ env: { ...process.env, ACC_PRODUCTION_MIGRATION_PROMOTION_IDS: promotionId },
16
+ });
17
+ const outcome = await service.claimAndRun(promotionId);
18
+ if (outcome !== "succeeded")
19
+ throw new Error(`production migration ${outcome}`);
20
+ }
21
+ //# sourceMappingURL=command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/production-migrations/command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAE1D,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,uCAAuC,CAAC,WAAmB;IAC/E,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IAC9F,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,MAAM,OAAO,GAAG,MAAM,gBAAgB,EAAE,CAAC,IAAI,EAAE,CAAC;IAChD,IAAI,CAAC,OAAO,EAAE,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAClE,MAAM,EAAE,GAAG,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAClF,MAAM,OAAO,GAAG,IAAI,0BAA0B,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,SAAS,EAAE;QACzE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,sCAAsC,EAAE,WAAW,EAAE;KAC7E,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;IACvD,IAAI,OAAO,KAAK,WAAW;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,OAAO,EAAE,CAAC,CAAC;AAClF,CAAC"}
@@ -0,0 +1,59 @@
1
+ export declare const PRODUCTION_PROJECT_REF = "ctknjrtevjrzwpuojghx";
2
+ export interface ProductionMigrationItem {
3
+ ordinal: number;
4
+ seq: string;
5
+ slug: string;
6
+ path: string;
7
+ sha: string;
8
+ staging_status: "applied" | "skipped";
9
+ status: "pending" | "skipped" | "applied" | "failed";
10
+ }
11
+ export interface ProductionMigrationPromotion {
12
+ id: string;
13
+ repo: string;
14
+ commit_sha: string;
15
+ plan_hash: string;
16
+ production_project_ref: string;
17
+ production_credential_profile_ref: string;
18
+ staging_ledger_snapshot_sha: string;
19
+ analyzer_classification: "safe" | "review_required" | "blocked";
20
+ items: ProductionMigrationItem[];
21
+ }
22
+ export interface ProductionTarget {
23
+ projectRef(): Promise<string>;
24
+ tryAdvisoryLock(key: string): Promise<boolean>;
25
+ unlockAdvisory(key: string): Promise<void>;
26
+ ledgerHead(): Promise<string | null>;
27
+ ledger(seq: string): Promise<{
28
+ slug: string;
29
+ sha: string;
30
+ } | null>;
31
+ applyFile(file: string, signal: AbortSignal): Promise<void>;
32
+ }
33
+ export interface SignedReceipt {
34
+ receiptId: string;
35
+ digest: string;
36
+ signature: string;
37
+ keyId: string;
38
+ }
39
+ export interface ProductionReceiptSink {
40
+ item(ordinal: number, status: "skipped" | "applied" | "failed", errorCode?: string): Promise<{
41
+ receipt_id: string;
42
+ }>;
43
+ complete(succeeded: boolean, failureCode?: string): Promise<{
44
+ receipt_id: string;
45
+ }>;
46
+ signed(receipt: SignedReceipt): Promise<void>;
47
+ }
48
+ export interface ProductionExecutionOptions {
49
+ timeoutMs?: number;
50
+ cancelled?: () => Promise<boolean>;
51
+ receiptKey: string;
52
+ receiptKeyId: string;
53
+ }
54
+ export declare function productionLedgerSnapshot(items: ProductionMigrationItem[]): string;
55
+ export declare function signReceipt(promotionId: string, action: string, receiptId: string, key: string, keyId: string): SignedReceipt;
56
+ export declare function verifySignedReceipt(receipt: SignedReceipt, key: string): boolean;
57
+ /** Exact-file, fail-closed production executor. Applied ledger rows make crash recovery idempotent. */
58
+ export declare function executeProductionPromotion(promotion: ProductionMigrationPromotion, repoRoot: string, target: ProductionTarget, receipts: ProductionReceiptSink, options: ProductionExecutionOptions): Promise<void>;
59
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/production-migrations/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,161 @@
1
+ import { createHash, createHmac, timingSafeEqual } from "node:crypto";
2
+ import { readFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { isCommitSha, isSha256Digest } from "../commit-sha.js";
5
+ export const PRODUCTION_PROJECT_REF = "ctknjrtevjrzwpuojghx";
6
+ export function productionLedgerSnapshot(items) {
7
+ const value = items
8
+ .map((item) => `${item.ordinal}:${item.seq}:${item.slug}:${item.sha}:${item.staging_status}`)
9
+ .join("|");
10
+ return createHash("sha256").update(value).digest("hex");
11
+ }
12
+ export function signReceipt(promotionId, action, receiptId, key, keyId) {
13
+ if (key.length < 32 || !keyId)
14
+ throw new Error("production_receipt_signing_key_required");
15
+ const digest = createHash("sha256").update(`${promotionId}:${action}:${receiptId}`).digest("hex");
16
+ return {
17
+ receiptId,
18
+ digest,
19
+ signature: createHmac("sha256", key).update(digest).digest("hex"),
20
+ keyId,
21
+ };
22
+ }
23
+ export function verifySignedReceipt(receipt, key) {
24
+ const actual = Buffer.from(receipt.signature, "hex");
25
+ const expected = Buffer.from(createHmac("sha256", key).update(receipt.digest).digest("hex"), "hex");
26
+ return actual.length === expected.length && timingSafeEqual(actual, expected);
27
+ }
28
+ function assertPromotion(promotion) {
29
+ if (promotion.production_project_ref !== PRODUCTION_PROJECT_REF)
30
+ throw new Error("production_project_pin_invalid");
31
+ if (promotion.analyzer_classification !== "safe")
32
+ throw new Error("production_analyzer_not_safe");
33
+ if (!isCommitSha(promotion.commit_sha))
34
+ throw new Error("production_commit_invalid");
35
+ if (!isSha256Digest(promotion.plan_hash))
36
+ throw new Error("production_plan_hash_invalid");
37
+ if (promotion.items.length === 0)
38
+ throw new Error("production_plan_empty");
39
+ if (productionLedgerSnapshot(promotion.items) !== promotion.staging_ledger_snapshot_sha)
40
+ throw new Error("production_staging_snapshot_mismatch");
41
+ let previous = null;
42
+ for (const [index, item] of promotion.items.entries()) {
43
+ if (item.ordinal !== index ||
44
+ item.path !== `supabase/migrations/${item.seq}_${item.slug}.sql` ||
45
+ !/^[0-9]{4}$/.test(item.seq) ||
46
+ !isSha256Digest(item.sha))
47
+ throw new Error("production_plan_item_invalid");
48
+ if (previous !== null && Number(item.seq) !== previous + 1)
49
+ throw new Error("production_plan_not_contiguous");
50
+ previous = Number(item.seq);
51
+ }
52
+ }
53
+ function insideRepo(repoRoot, migrationPath) {
54
+ const root = path.resolve(repoRoot);
55
+ const resolved = path.resolve(root, migrationPath);
56
+ if (!resolved.startsWith(`${root}${path.sep}`))
57
+ throw new Error("production_migration_path_escape");
58
+ return resolved;
59
+ }
60
+ function failureCode(error) {
61
+ const raw = error instanceof Error ? error.message : "production_migration_failed";
62
+ return raw
63
+ .replace(/postgres(?:ql)?:\/\/[^\s]+/gi, "[REDACTED_DB_URL]")
64
+ .replace(/(password|token|secret)=?[^\s]*/gi, "$1=[REDACTED]")
65
+ .replace(/[^a-zA-Z0-9_.:[\] -]/g, "_")
66
+ .slice(0, 200);
67
+ }
68
+ async function signed(promotion, action, result, receipts, options) {
69
+ if (!/^[0-9a-f-]{36}$/i.test(result.receipt_id))
70
+ throw new Error("production_receipt_invalid");
71
+ await receipts.signed(signReceipt(promotion.id, action, result.receipt_id, options.receiptKey, options.receiptKeyId));
72
+ }
73
+ /** Exact-file, fail-closed production executor. Applied ledger rows make crash recovery idempotent. */
74
+ export async function executeProductionPromotion(promotion, repoRoot, target, receipts, options) {
75
+ const lockKey = `acc:production-migrations:${PRODUCTION_PROJECT_REF}`;
76
+ const timeoutMs = Math.max(5_000, Math.min(options.timeoutMs ?? 300_000, 900_000));
77
+ let locked = false;
78
+ try {
79
+ assertPromotion(promotion);
80
+ if ((await target.projectRef()) !== PRODUCTION_PROJECT_REF)
81
+ throw new Error("production_project_pin_mismatch");
82
+ if (!(await target.tryAdvisoryLock(lockKey)))
83
+ throw new Error("production_migration_lock_busy");
84
+ locked = true;
85
+ const head = await target.ledgerHead();
86
+ const acceptable = new Set([
87
+ String(Number(promotion.items[0].seq) - 1).padStart(4, "0"),
88
+ ...promotion.items.map((item) => item.seq),
89
+ ]);
90
+ if (!head || !acceptable.has(head))
91
+ throw new Error("production_ledger_head_mismatch");
92
+ for (const item of promotion.items) {
93
+ if (await options.cancelled?.())
94
+ throw new Error("production_migration_cancelled");
95
+ if (item.status === "applied" || item.status === "skipped")
96
+ continue;
97
+ const existing = await target.ledger(item.seq);
98
+ if (existing) {
99
+ if (existing.slug !== item.slug || existing.sha !== item.sha)
100
+ throw new Error(`production_ledger_drift_${item.seq}`);
101
+ const result = await receipts.item(item.ordinal, "skipped");
102
+ await signed(promotion, `item:${item.ordinal}:skipped`, result, receipts, options);
103
+ continue;
104
+ }
105
+ const file = insideRepo(repoRoot, item.path);
106
+ const sql = await readFile(file);
107
+ if (createHash("sha256").update(sql).digest("hex") !== item.sha)
108
+ throw new Error(`production_file_hash_mismatch_${item.seq}`);
109
+ const controller = new AbortController();
110
+ let cancelled = false;
111
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
112
+ const cancelPoll = options.cancelled
113
+ ? setInterval(() => {
114
+ void options.cancelled?.().then((value) => {
115
+ if (value) {
116
+ cancelled = true;
117
+ controller.abort();
118
+ }
119
+ });
120
+ }, 250)
121
+ : null;
122
+ cancelPoll?.unref?.();
123
+ try {
124
+ await target.applyFile(file, controller.signal);
125
+ const recorded = await target.ledger(item.seq);
126
+ if (!recorded || recorded.slug !== item.slug || recorded.sha !== item.sha)
127
+ throw new Error(`production_ledger_receipt_missing_${item.seq}`);
128
+ const result = await receipts.item(item.ordinal, "applied");
129
+ await signed(promotion, `item:${item.ordinal}:applied`, result, receipts, options);
130
+ }
131
+ catch (error) {
132
+ const code = cancelled
133
+ ? "production_migration_cancelled"
134
+ : controller.signal.aborted
135
+ ? "production_migration_timeout"
136
+ : failureCode(error);
137
+ const result = await receipts.item(item.ordinal, "failed", code);
138
+ await signed(promotion, `item:${item.ordinal}:failed`, result, receipts, options);
139
+ throw new Error(code);
140
+ }
141
+ finally {
142
+ clearTimeout(timer);
143
+ if (cancelPoll)
144
+ clearInterval(cancelPoll);
145
+ }
146
+ }
147
+ const result = await receipts.complete(true);
148
+ await signed(promotion, "complete:succeeded", result, receipts, options);
149
+ }
150
+ catch (error) {
151
+ const result = await receipts.complete(false, failureCode(error)).catch(() => null);
152
+ if (result)
153
+ await signed(promotion, "complete:failed", result, receipts, options).catch(() => undefined);
154
+ throw error;
155
+ }
156
+ finally {
157
+ if (locked)
158
+ await target.unlockAdvisory(lockKey).catch(() => undefined);
159
+ }
160
+ }
161
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/production-migrations/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { type ProductionTarget } from "./executor.js";
2
+ export declare function productionCredentialEnvName(profile: string): string;
3
+ export declare function projectRefFromProductionUrl(value: string): string;
4
+ export declare class PgProductionTarget implements ProductionTarget {
5
+ private readonly env;
6
+ private readonly client;
7
+ private readonly connectionString;
8
+ private readonly pinnedRef;
9
+ constructor(profile: string, env?: NodeJS.ProcessEnv);
10
+ connect(): Promise<void>;
11
+ close(): Promise<void>;
12
+ projectRef(): Promise<string>;
13
+ tryAdvisoryLock(key: string): Promise<boolean>;
14
+ unlockAdvisory(key: string): Promise<void>;
15
+ ledger(seq: string): Promise<{
16
+ slug: string;
17
+ sha: string;
18
+ } | null>;
19
+ ledgerHead(): Promise<string | null>;
20
+ applyFile(file: string, signal: AbortSignal): Promise<void>;
21
+ }
22
+ //# sourceMappingURL=pg-target.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pg-target.d.ts","sourceRoot":"","sources":["../../src/production-migrations/pg-target.ts"],"names":[],"mappings":"AAGA,OAAO,EAA0B,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAI9E,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAInE;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUjE;AAED,qBAAa,kBAAmB,YAAW,gBAAgB;IAOvD,OAAO,CAAC,QAAQ,CAAC,GAAG;IANtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAGjC,OAAO,EAAE,MAAM,EACE,GAAG,GAAE,MAAM,CAAC,UAAwB;IAcjD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAGxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAGtB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAG7B,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAO9C,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAG1C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAOlE,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAMpC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAmBlE"}
@@ -0,0 +1,87 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { Client } from "pg";
4
+ import { PRODUCTION_PROJECT_REF } from "./executor.js";
5
+ const execFileAsync = promisify(execFile);
6
+ export function productionCredentialEnvName(profile) {
7
+ if (!/^[A-Za-z0-9_.-]{1,80}$/.test(profile))
8
+ throw new Error("production_credential_profile_invalid");
9
+ return `ACC_DB_PROFILE_${profile.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_URL`;
10
+ }
11
+ export function projectRefFromProductionUrl(value) {
12
+ let parsed;
13
+ try {
14
+ parsed = new URL(value);
15
+ }
16
+ catch {
17
+ throw new Error("production_credential_url_invalid");
18
+ }
19
+ const ref = `${parsed.hostname}${parsed.pathname}`.match(/\b([a-z0-9]{20})\b/)?.[1];
20
+ if (!ref)
21
+ throw new Error("production_credential_project_ref_missing");
22
+ return ref;
23
+ }
24
+ export class PgProductionTarget {
25
+ env;
26
+ client;
27
+ connectionString;
28
+ pinnedRef;
29
+ constructor(profile, env = process.env) {
30
+ this.env = env;
31
+ const value = env[productionCredentialEnvName(profile)];
32
+ if (!value)
33
+ throw new Error("production_credential_profile_not_configured");
34
+ this.pinnedRef = projectRefFromProductionUrl(value);
35
+ if (this.pinnedRef !== PRODUCTION_PROJECT_REF)
36
+ throw new Error("non_production_target_forbidden");
37
+ this.connectionString = value;
38
+ this.client = new Client({
39
+ connectionString: value,
40
+ application_name: "acc-production-migration-executor",
41
+ });
42
+ }
43
+ async connect() {
44
+ await this.client.connect();
45
+ }
46
+ async close() {
47
+ await this.client.end();
48
+ }
49
+ async projectRef() {
50
+ return this.pinnedRef;
51
+ }
52
+ async tryAdvisoryLock(key) {
53
+ const result = await this.client.query("select pg_try_advisory_lock(hashtextextended($1, 0)) as locked", [key]);
54
+ return result.rows[0]?.locked === true;
55
+ }
56
+ async unlockAdvisory(key) {
57
+ await this.client.query("select pg_advisory_unlock(hashtextextended($1, 0))", [key]);
58
+ }
59
+ async ledger(seq) {
60
+ const result = await this.client.query("select slug, sha from acc.applied_migrations where seq = $1", [seq]);
61
+ return result.rows[0] ?? null;
62
+ }
63
+ async ledgerHead() {
64
+ const result = await this.client.query("select seq from acc.applied_migrations order by seq::integer desc limit 1");
65
+ return result.rows[0]?.seq ?? null;
66
+ }
67
+ async applyFile(file, signal) {
68
+ // Do not leak the runner/token/signing environment into psql. The opaque
69
+ // profile resolves locally and only the minimum process environment crosses
70
+ // the child boundary; the connection string is never placed in argv.
71
+ const childEnv = {
72
+ PATH: this.env.PATH,
73
+ HOME: this.env.HOME,
74
+ LANG: this.env.LANG,
75
+ LC_ALL: this.env.LC_ALL,
76
+ SSL_CERT_FILE: this.env.SSL_CERT_FILE,
77
+ PGCONNECT_TIMEOUT: this.env.PGCONNECT_TIMEOUT ?? "10",
78
+ PGDATABASE: this.connectionString,
79
+ };
80
+ await execFileAsync("psql", ["-X", "--set", "ON_ERROR_STOP=1", "--file", file], {
81
+ env: childEnv,
82
+ signal,
83
+ maxBuffer: 256 * 1024,
84
+ });
85
+ }
86
+ }
87
+ //# sourceMappingURL=pg-target.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pg-target.js","sourceRoot":"","sources":["../../src/production-migrations/pg-target.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function configuredProductionMigrationProfiles(env?: NodeJS.ProcessEnv): string[];
2
+ export declare function configuredProductionPromotionIds(env?: NodeJS.ProcessEnv): string[];
3
+ export declare function productionMigrationServiceEnabled(env?: NodeJS.ProcessEnv): boolean;
4
+ export declare function productionMigrationCaps(env?: NodeJS.ProcessEnv): Record<string, unknown>;
5
+ //# sourceMappingURL=profiles.d.ts.map