deepline 0.3.128 → 0.3.130

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 (130) hide show
  1. package/dist/bundling-sources/sdk/src/client.ts +34 -9
  2. package/dist/bundling-sources/sdk/src/http.ts +22 -0
  3. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  4. package/dist/bundling-sources/shared_libs/play-data-plane/r2.ts +22 -0
  5. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +265 -2
  6. package/dist/bundling-sources/shared_libs/play-runtime/bounded-batch-function.ts +682 -0
  7. package/dist/bundling-sources/shared_libs/play-runtime/child-execution-strategy.ts +21 -5
  8. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +5390 -1732
  9. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +107 -1
  10. package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-janitor.ts +4 -1
  11. package/dist/bundling-sources/shared_libs/play-runtime/deployment/commands/roll-execution-relay.ts +7 -0
  12. package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-machines.ts +229 -7
  13. package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-registry.ts +25 -4
  14. package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-gateway-capacity.ts +71 -0
  15. package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-gateway-drain.ts +1 -1
  16. package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-topology.ts +4 -1
  17. package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +694 -28
  18. package/dist/bundling-sources/shared_libs/play-runtime/egress-bandwidth-probe.ts +167 -0
  19. package/dist/bundling-sources/shared_libs/play-runtime/execute-server-timing.ts +103 -0
  20. package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-receipt-output-reference.ts +34 -0
  21. package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-response-size.ts +27 -0
  22. package/dist/bundling-sources/shared_libs/play-runtime/gateway-postgres-admission.ts +66 -1
  23. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +425 -71
  24. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +210 -32
  25. package/dist/bundling-sources/shared_libs/play-runtime/governor/in-memory-rate-state-backend.ts +27 -13
  26. package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +19 -6
  27. package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +61 -2
  28. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/contracts.ts +33 -1
  29. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/job.ts +42 -1
  30. package/dist/bundling-sources/shared_libs/play-runtime/launch-source-policy.ts +11 -11
  31. package/dist/bundling-sources/shared_libs/play-runtime/ledger-safe-payload.ts +49 -16
  32. package/dist/bundling-sources/shared_libs/play-runtime/map-memory-limits.ts +1653 -98
  33. package/dist/bundling-sources/shared_libs/play-runtime/memory-ledger.ts +807 -0
  34. package/dist/bundling-sources/shared_libs/play-runtime/memory-pressure-signal.ts +138 -0
  35. package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +85 -3
  36. package/dist/bundling-sources/shared_libs/play-runtime/persistence-latch.ts +60 -2
  37. package/dist/bundling-sources/shared_libs/play-runtime/play-run-recovery-policy.ts +46 -1
  38. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/contracts.ts +2 -0
  39. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/job.ts +1 -0
  40. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/ports.ts +1 -0
  41. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/postgres-adapter.ts +1 -0
  42. package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-semantics.ts +70 -27
  43. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +56 -0
  44. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/adaptive-provider-capacity-controller.ts +192 -0
  45. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/epoch-aimd-rate-controller.ts +194 -0
  46. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/fixture-capacity-simulator.ts +220 -0
  47. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/gradient2-concurrency-controller.ts +214 -0
  48. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-capacity-policy.ts +43 -0
  49. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-concurrency-policy.ts +30 -0
  50. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-rate-policy.ts +95 -0
  51. package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-throttle-classifier.ts +40 -0
  52. package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +1535 -11
  53. package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +49 -2
  54. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +6 -1
  55. package/dist/bundling-sources/shared_libs/play-runtime/run-log-buffer.ts +55 -0
  56. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/egress-probe.ts +221 -0
  57. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +339 -29
  58. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-deadline.ts +28 -1
  59. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-progress-push.ts +192 -165
  60. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +6 -0
  61. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +90 -5
  62. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-runtime-watchdog.ts +281 -6
  63. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +27 -1
  64. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/local-process.ts +19 -0
  65. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/modal.ts +108 -0
  66. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runtime-sandbox-reconciliation.ts +40 -0
  67. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +11 -5
  68. package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +30 -0
  69. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api-compression.ts +276 -0
  70. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +723 -115
  71. package/dist/bundling-sources/shared_libs/play-runtime/runtime-capacity-policy.ts +114 -4
  72. package/dist/bundling-sources/shared_libs/play-runtime/runtime-contract.ts +3 -2
  73. package/dist/bundling-sources/shared_libs/play-runtime/runtime-environment.ts +41 -4
  74. package/dist/bundling-sources/shared_libs/play-runtime/runtime-flow.ts +448 -0
  75. package/dist/bundling-sources/shared_libs/play-runtime/runtime-map-row-feed.ts +215 -0
  76. package/dist/bundling-sources/shared_libs/play-runtime/runtime-operation-contract.ts +11 -0
  77. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-store-adapter.ts +161 -14
  78. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-value.ts +184 -0
  79. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-writer.ts +607 -121
  80. package/dist/bundling-sources/shared_libs/play-runtime/runtime-sandbox-placement-policy.ts +4 -0
  81. package/dist/bundling-sources/shared_libs/play-runtime/runtime-sheet-row-writer.ts +21 -0
  82. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/contract.ts +15 -2
  83. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +71 -14
  84. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-play-deploy-task.ts +2 -2
  85. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +288 -119
  86. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +8 -6
  87. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-required-env.ts +28 -3
  88. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd.ts +28 -8
  89. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/canonical-integration-operation-store.ts +179 -0
  90. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-heavy-request-admission.ts +80 -2
  91. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-progress-registry.ts +31 -2
  92. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-store-contract.ts +104 -0
  93. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-reference.ts +47 -0
  94. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-retirement.ts +193 -0
  95. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-storage.ts +420 -0
  96. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +146 -15
  97. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +134 -3
  98. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-rate-state.ts +1657 -95
  99. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +904 -77
  100. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-completion-coalescer.ts +452 -0
  101. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +601 -42
  102. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-terminal-transition.ts +1 -0
  103. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-receipt-value-storage.ts +371 -0
  104. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/worker-resource-metrics.ts +86 -7
  105. package/dist/bundling-sources/shared_libs/play-runtime/secret-redaction.ts +153 -22
  106. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/index.ts +1 -0
  107. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/receipt-cohort.ts +188 -38
  108. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/runtime-step-receipts-adapter.ts +28 -13
  109. package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +44 -1
  110. package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +56 -4
  111. package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +2 -0
  112. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +16 -10
  113. package/dist/bundling-sources/shared_libs/plays/dataset.ts +4 -1
  114. package/dist/cli/index.js +250 -38
  115. package/dist/cli/index.mjs +250 -38
  116. package/dist/{compiler-manifest-DfSnbCTW.d.mts → compiler-manifest-BIqRyj5m.d.mts} +1 -1
  117. package/dist/{compiler-manifest-DfSnbCTW.d.ts → compiler-manifest-BIqRyj5m.d.ts} +1 -1
  118. package/dist/index.d.mts +4 -2
  119. package/dist/index.d.ts +4 -2
  120. package/dist/index.js +231 -35
  121. package/dist/index.mjs +231 -35
  122. package/dist/install-integrity.json +31 -2
  123. package/dist/plays/bundle-play-file.d.mts +2 -2
  124. package/dist/plays/bundle-play-file.d.ts +2 -2
  125. package/dist/plays/bundle-play-file.mjs +65 -1
  126. package/dist/release.d.mts +1 -1
  127. package/dist/release.d.ts +1 -1
  128. package/dist/release.js +1 -1
  129. package/dist/release.mjs +1 -1
  130. package/package.json +1 -1
@@ -7,19 +7,41 @@
7
7
  * and tests cannot independently invent concurrency or timeout budgets.
8
8
  */
9
9
  export const RUNTIME_CAPACITY_POLICY = {
10
+ runtimePostgres: {
11
+ /** One process-local scheduler pool budget for every control-plane lane. */
12
+ schedulerPoolMaxClients: 2,
13
+ },
10
14
  absurd: {
11
15
  /** Warm floor for availability and deploy rollovers. */
12
16
  activeLaneMachines: 2,
13
- /** 32 Machines x 8 claim slots permits 256 concurrent launch/resume legs. */
14
- maxActiveLaneMachines: 32,
17
+ /** Keep worker pools and direct wake listeners below the shared DB budget. */
18
+ maxActiveLaneMachines: 8,
15
19
  workerSlotsPerMachine: 8,
16
- /** Queue age is an escape hatch for small-but-stuck backlogs. */
17
- scaleUpQueueAgeMs: 10_000,
20
+ /** React within one control interval when a due backlog is not draining. */
21
+ scaleUpQueueAgeMs: 1_000,
18
22
  /** Bound one Fly reconciliation without turning backlog into a stampede. */
19
23
  maxScaleUpMachinesPerReconcile: 4,
20
24
  /** Do not tear down burst capacity on the first empty observation. */
21
25
  scaleDownQuietMs: 120_000,
22
26
  },
27
+ executionRelay: {
28
+ /** Keep two relay Machines available for deploys and one-machine faults. */
29
+ minimumMachines: 2,
30
+ /** Bound relay spend and the blast radius of a bad demand signal. */
31
+ maxMachines: 16,
32
+ /** The local admission gate's per-Machine upstream permit ceiling. */
33
+ upstreamSlotsPerMachine: 192,
34
+ /** Grow before the local queue reaches its hard shed boundary. */
35
+ scaleUpUtilization: 0.75,
36
+ /** Retain a larger safety margin before removing burst capacity. */
37
+ scaleDownUtilization: 0.35,
38
+ /** One observation may add only a small bounded number of Machines. */
39
+ maxScaleUpMachinesPerReconcile: 2,
40
+ /** Reclaim burst capacity gradually after a long quiet window. */
41
+ maxScaleDownMachinesPerReconcile: 2,
42
+ /** Empty relay capacity must be quiet before it is reclaimed. */
43
+ scaleDownQuietMs: 120_000,
44
+ },
23
45
  receiptGateway: {
24
46
  admissionTimeoutMs: 10_000,
25
47
  /** End identical receipt-row work before the caller can overlap a retry. */
@@ -33,6 +55,9 @@ export const RUNTIME_CAPACITY_POLICY = {
33
55
  * once started, all eight execution slots may run concurrently.
34
56
  */
35
57
  daytonaConcurrentStartsPerProcess: 1,
58
+ /** Fleet-wide AIMD start pacing, separate from execution-slot scaling. */
59
+ daytonaInitialStartsPerMinute: 120,
60
+ daytonaMaximumStartsPerMinute: 600,
36
61
  },
37
62
  } as const;
38
63
 
@@ -95,6 +120,55 @@ export function desiredAbsurdLaneMachines(input: {
95
120
  return desired;
96
121
  }
97
122
 
123
+ /**
124
+ * Execution-relay demand is the exact upstream admission state, not request
125
+ * count. Active permits consume capacity and waiting requests are an early
126
+ * backpressure signal. Scale up before the local gate begins shedding, but
127
+ * only by a bounded amount per controller observation. Scale down only after
128
+ * the aggregate relay is empty for the quiet window; the controller applies
129
+ * its own per-pass stop bound when it materializes this target.
130
+ */
131
+ export function desiredExecutionRelayMachines(input: {
132
+ currentMachines?: number;
133
+ inFlight: number;
134
+ waiting: number;
135
+ idleForMs?: number;
136
+ }): number {
137
+ const policy = RUNTIME_CAPACITY_POLICY.executionRelay;
138
+ const currentMachines = Math.max(
139
+ policy.minimumMachines,
140
+ nonNegativeInteger(input.currentMachines ?? policy.minimumMachines),
141
+ );
142
+ const inFlight = nonNegativeInteger(input.inFlight);
143
+ const waiting = nonNegativeInteger(input.waiting);
144
+ const targetSlots =
145
+ policy.upstreamSlotsPerMachine * policy.scaleUpUtilization;
146
+ let desired = Math.max(
147
+ policy.minimumMachines,
148
+ Math.ceil((inFlight + waiting) / targetSlots),
149
+ );
150
+
151
+ // A waiter means at least one Machine is already at its local admission
152
+ // boundary. Aggregate active work may still look below the fleet target
153
+ // when the other Machine(s) are quiet, so give the queue one extra slot.
154
+ if (waiting > 0) desired = Math.max(desired, currentMachines + 1);
155
+
156
+ desired = Math.min(
157
+ desired,
158
+ currentMachines + policy.maxScaleUpMachinesPerReconcile,
159
+ policy.maxMachines,
160
+ );
161
+
162
+ if (
163
+ inFlight === 0 &&
164
+ waiting === 0 &&
165
+ nonNegativeNumber(input.idleForMs ?? 0) < policy.scaleDownQuietMs
166
+ ) {
167
+ desired = Math.max(desired, currentMachines);
168
+ }
169
+ return desired;
170
+ }
171
+
98
172
  function nonNegativeInteger(value: number): number {
99
173
  return Math.max(0, Math.floor(nonNegativeNumber(value)));
100
174
  }
@@ -104,6 +178,16 @@ function nonNegativeNumber(value: number): number {
104
178
  }
105
179
 
106
180
  export function assertRuntimeCapacityPolicy(): void {
181
+ if (
182
+ !Number.isInteger(
183
+ RUNTIME_CAPACITY_POLICY.runtimePostgres.schedulerPoolMaxClients,
184
+ ) ||
185
+ RUNTIME_CAPACITY_POLICY.runtimePostgres.schedulerPoolMaxClients < 1
186
+ ) {
187
+ throw new Error(
188
+ 'Runtime scheduler pool client cap must be a positive integer.',
189
+ );
190
+ }
107
191
  if (
108
192
  !Number.isInteger(
109
193
  RUNTIME_CAPACITY_POLICY.sandboxAcquisition
@@ -116,6 +200,19 @@ export function assertRuntimeCapacityPolicy(): void {
116
200
  'Daytona sandbox-start concurrency must be a positive integer.',
117
201
  );
118
202
  }
203
+ const sandboxAcquisition = RUNTIME_CAPACITY_POLICY.sandboxAcquisition;
204
+ if (
205
+ !Number.isInteger(sandboxAcquisition.daytonaInitialStartsPerMinute) ||
206
+ !Number.isInteger(sandboxAcquisition.daytonaMaximumStartsPerMinute) ||
207
+ sandboxAcquisition.daytonaInitialStartsPerMinute <= 0 ||
208
+ sandboxAcquisition.daytonaInitialStartsPerMinute >
209
+ sandboxAcquisition.daytonaMaximumStartsPerMinute ||
210
+ sandboxAcquisition.daytonaMaximumStartsPerMinute > 600
211
+ ) {
212
+ throw new Error(
213
+ 'Daytona sandbox-start AIMD rates must be positive integers with initial <= maximum <= 600/minute.',
214
+ );
215
+ }
119
216
  if (
120
217
  RUNTIME_CAPACITY_POLICY.receiptGateway.requestTimeoutMs <=
121
218
  RUNTIME_CAPACITY_POLICY.receiptGateway.admissionTimeoutMs
@@ -140,6 +237,19 @@ export function assertRuntimeCapacityPolicy(): void {
140
237
  'Active-lane minimum Machines cannot exceed the active-lane maximum.',
141
238
  );
142
239
  }
240
+ const relay = RUNTIME_CAPACITY_POLICY.executionRelay;
241
+ if (
242
+ relay.minimumMachines > relay.maxMachines ||
243
+ relay.upstreamSlotsPerMachine <= 0 ||
244
+ relay.scaleUpUtilization <= 0 ||
245
+ relay.scaleUpUtilization > 1 ||
246
+ relay.scaleDownUtilization <= 0 ||
247
+ relay.scaleDownUtilization > relay.scaleUpUtilization
248
+ ) {
249
+ throw new Error(
250
+ 'Execution-relay capacity policy has invalid floor, ceiling, or utilization bounds.',
251
+ );
252
+ }
143
253
  }
144
254
 
145
255
  assertRuntimeCapacityPolicy();
@@ -58,10 +58,11 @@ export function resolveLegacyRuntimeReceiptWireFormat(
58
58
  }
59
59
 
60
60
  export function runtimeReceiptCompletionResponse<
61
- T extends { output?: unknown },
61
+ T extends { output?: unknown; outputRef?: unknown },
62
62
  >(wireFormat: LegacyRuntimeReceiptWireFormat, receipt: T | null): T | null {
63
63
  if (!receipt || wireFormat < 3) return receipt;
64
- const { output, ...ack } = receipt;
64
+ const { output, outputRef, ...ack } = receipt;
65
65
  void output;
66
+ void outputRef;
66
67
  return ack as T;
67
68
  }
@@ -10,9 +10,13 @@ export type PlayRuntimeSelection = {
10
10
  namespace: string;
11
11
  /** Explicit managed-sandbox executor. Omission preserves Daytona compatibility. */
12
12
  backend?: Extract<PlayRuntimeBackendId, 'daytona' | 'modal'>;
13
+ /** Durable placement contract for the selected Preview worker lane. */
14
+ sandboxPlacementPolicy?: string;
13
15
  };
14
16
 
15
17
  const PLAY_RUNTIME_NAMESPACE_PATTERN = /^[a-z][a-z0-9-]{0,30}$/;
18
+ const PLAY_RUNTIME_SANDBOX_PLACEMENT_POLICY_PATTERN =
19
+ /^[a-z][a-z0-9_]*@[1-9][0-9]*$/;
16
20
 
17
21
  export function normalizePlayRuntimeNamespace(value: unknown): string | null {
18
22
  if (typeof value !== 'string') return null;
@@ -20,6 +24,21 @@ export function normalizePlayRuntimeNamespace(value: unknown): string | null {
20
24
  return PLAY_RUNTIME_NAMESPACE_PATTERN.test(normalized) ? normalized : null;
21
25
  }
22
26
 
27
+ /**
28
+ * Policy membership is owned by the server-side policy catalogue. The shared
29
+ * selector only accepts a stable versioned id shape, so unknown policies fail
30
+ * loudly at the authority that knows which worker releases support them.
31
+ */
32
+ export function normalizePlayRuntimeSandboxPlacementPolicy(
33
+ value: unknown,
34
+ ): string | null {
35
+ if (typeof value !== 'string') return null;
36
+ const normalized = value.trim();
37
+ return PLAY_RUNTIME_SANDBOX_PLACEMENT_POLICY_PATTERN.test(normalized)
38
+ ? normalized
39
+ : null;
40
+ }
41
+
23
42
  /** Validate the selector as one value so the SDK and server cannot drift. */
24
43
  export function normalizePlayRuntimeSelection(
25
44
  value: unknown,
@@ -29,7 +48,10 @@ export function normalizePlayRuntimeSelection(
29
48
  if (
30
49
  Object.keys(record).some(
31
50
  (key) =>
32
- key !== 'environment' && key !== 'namespace' && key !== 'backend',
51
+ key !== 'environment' &&
52
+ key !== 'namespace' &&
53
+ key !== 'backend' &&
54
+ key !== 'sandboxPlacementPolicy',
33
55
  ) ||
34
56
  record.environment !== 'preview'
35
57
  ) {
@@ -37,16 +59,31 @@ export function normalizePlayRuntimeSelection(
37
59
  }
38
60
  const namespace = normalizePlayRuntimeNamespace(record.namespace);
39
61
  if (!namespace) return null;
40
- if (record.backend === undefined) {
41
- return { environment: 'preview', namespace };
62
+ const sandboxPlacementPolicy =
63
+ record.sandboxPlacementPolicy === undefined
64
+ ? undefined
65
+ : normalizePlayRuntimeSandboxPlacementPolicy(
66
+ record.sandboxPlacementPolicy,
67
+ );
68
+ if (
69
+ record.sandboxPlacementPolicy !== undefined &&
70
+ sandboxPlacementPolicy === null
71
+ ) {
72
+ return null;
42
73
  }
43
74
  if (
75
+ record.backend !== undefined &&
44
76
  record.backend !== PLAY_RUNTIME_BACKENDS.daytona &&
45
77
  record.backend !== PLAY_RUNTIME_BACKENDS.modal
46
78
  ) {
47
79
  return null;
48
80
  }
49
- return { environment: 'preview', namespace, backend: record.backend };
81
+ return {
82
+ environment: 'preview',
83
+ namespace,
84
+ ...(record.backend === undefined ? {} : { backend: record.backend }),
85
+ ...(sandboxPlacementPolicy ? { sandboxPlacementPolicy } : {}),
86
+ };
50
87
  }
51
88
 
52
89
  export function normalizePlayRuntimeEnvironment(