sandbox0 0.10.4 → 0.10.6

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 (182) hide show
  1. package/README.md +134 -0
  2. package/dist/apispec/src/apis/FilesApi.d.ts +14 -10
  3. package/dist/apispec/src/apis/FilesApi.d.ts.map +1 -1
  4. package/dist/apispec/src/apis/FilesApi.js +14 -10
  5. package/dist/apispec/src/apis/SandboxRootfsApi.d.ts +96 -5
  6. package/dist/apispec/src/apis/SandboxRootfsApi.d.ts.map +1 -1
  7. package/dist/apispec/src/apis/SandboxRootfsApi.js +291 -5
  8. package/dist/apispec/src/apis/SandboxesApi.d.ts +345 -6
  9. package/dist/apispec/src/apis/SandboxesApi.d.ts.map +1 -1
  10. package/dist/apispec/src/apis/SandboxesApi.js +1017 -7
  11. package/dist/apispec/src/apis/SessionsApi.d.ts +51 -1
  12. package/dist/apispec/src/apis/SessionsApi.d.ts.map +1 -1
  13. package/dist/apispec/src/apis/SessionsApi.js +159 -1
  14. package/dist/apispec/src/models/CaptureSandboxRootFSSnapshotRequest.d.ts +51 -0
  15. package/dist/apispec/src/models/CaptureSandboxRootFSSnapshotRequest.d.ts.map +1 -0
  16. package/dist/apispec/src/models/CaptureSandboxRootFSSnapshotRequest.js +49 -0
  17. package/dist/apispec/src/models/ConditionalExecutionSessionRequest.d.ts +46 -0
  18. package/dist/apispec/src/models/ConditionalExecutionSessionRequest.d.ts.map +1 -0
  19. package/dist/apispec/src/models/ConditionalExecutionSessionRequest.js +52 -0
  20. package/dist/apispec/src/models/ForkSandboxConfig.d.ts +6 -0
  21. package/dist/apispec/src/models/ForkSandboxConfig.d.ts.map +1 -1
  22. package/dist/apispec/src/models/ForkSandboxConfig.js +2 -0
  23. package/dist/apispec/src/models/ForkSandboxRequest.d.ts +6 -0
  24. package/dist/apispec/src/models/ForkSandboxRequest.d.ts.map +1 -1
  25. package/dist/apispec/src/models/ForkSandboxRequest.js +2 -0
  26. package/dist/apispec/src/models/ManagedFileReadResponse.d.ts +64 -0
  27. package/dist/apispec/src/models/ManagedFileReadResponse.d.ts.map +1 -0
  28. package/dist/apispec/src/models/ManagedFileReadResponse.js +65 -0
  29. package/dist/apispec/src/models/ManagedFileWriteRequest.d.ts +39 -0
  30. package/dist/apispec/src/models/ManagedFileWriteRequest.d.ts.map +1 -0
  31. package/dist/apispec/src/models/ManagedFileWriteRequest.js +47 -0
  32. package/dist/apispec/src/models/ManagedFilesState.d.ts +58 -0
  33. package/dist/apispec/src/models/ManagedFilesState.d.ts.map +1 -0
  34. package/dist/apispec/src/models/ManagedFilesState.js +61 -0
  35. package/dist/apispec/src/models/PauseSandboxResponse.d.ts +12 -0
  36. package/dist/apispec/src/models/PauseSandboxResponse.d.ts.map +1 -1
  37. package/dist/apispec/src/models/PauseSandboxResponse.js +4 -0
  38. package/dist/apispec/src/models/QuotaDimension.d.ts +5 -1
  39. package/dist/apispec/src/models/QuotaDimension.d.ts.map +1 -1
  40. package/dist/apispec/src/models/QuotaDimension.js +5 -1
  41. package/dist/apispec/src/models/ResourceQuota.d.ts +1 -1
  42. package/dist/apispec/src/models/ResumeSandboxResponse.d.ts +25 -1
  43. package/dist/apispec/src/models/ResumeSandboxResponse.d.ts.map +1 -1
  44. package/dist/apispec/src/models/ResumeSandboxResponse.js +8 -0
  45. package/dist/apispec/src/models/SandboxExecutionStateRequest.d.ts +14 -2
  46. package/dist/apispec/src/models/SandboxExecutionStateRequest.d.ts.map +1 -1
  47. package/dist/apispec/src/models/SandboxExecutionStateRequest.js +4 -0
  48. package/dist/apispec/src/models/SandboxHealth.d.ts +99 -0
  49. package/dist/apispec/src/models/SandboxHealth.d.ts.map +1 -0
  50. package/dist/apispec/src/models/SandboxHealth.js +90 -0
  51. package/dist/apispec/src/models/SandboxHealthObservation.d.ts +111 -0
  52. package/dist/apispec/src/models/SandboxHealthObservation.d.ts.map +1 -0
  53. package/dist/apispec/src/models/SandboxHealthObservation.js +112 -0
  54. package/dist/apispec/src/models/SandboxMemoryOperation.d.ts +115 -0
  55. package/dist/apispec/src/models/SandboxMemoryOperation.d.ts.map +1 -0
  56. package/dist/apispec/src/models/SandboxMemoryOperation.js +100 -0
  57. package/dist/apispec/src/models/SandboxMemoryRestoration.d.ts +64 -0
  58. package/dist/apispec/src/models/SandboxMemoryRestoration.d.ts.map +1 -0
  59. package/dist/apispec/src/models/SandboxMemoryRestoration.js +64 -0
  60. package/dist/apispec/src/models/SandboxMemoryRestorationStep.d.ts +63 -0
  61. package/dist/apispec/src/models/SandboxMemoryRestorationStep.d.ts.map +1 -0
  62. package/dist/apispec/src/models/SandboxMemoryRestorationStep.js +63 -0
  63. package/dist/apispec/src/models/SandboxPauseRequest.d.ts +39 -0
  64. package/dist/apispec/src/models/SandboxPauseRequest.d.ts.map +1 -0
  65. package/dist/apispec/src/models/SandboxPauseRequest.js +43 -0
  66. package/dist/apispec/src/models/SandboxRestartFinalCapture.d.ts +79 -0
  67. package/dist/apispec/src/models/SandboxRestartFinalCapture.d.ts.map +1 -0
  68. package/dist/apispec/src/models/SandboxRestartFinalCapture.js +70 -0
  69. package/dist/apispec/src/models/SandboxRestartFinalCaptureAcknowledgement.d.ts +39 -0
  70. package/dist/apispec/src/models/SandboxRestartFinalCaptureAcknowledgement.d.ts.map +1 -0
  71. package/dist/apispec/src/models/SandboxRestartFinalCaptureAcknowledgement.js +47 -0
  72. package/dist/apispec/src/models/SandboxRestartFinalCaptureFile.d.ts +69 -0
  73. package/dist/apispec/src/models/SandboxRestartFinalCaptureFile.d.ts.map +1 -0
  74. package/dist/apispec/src/models/SandboxRestartFinalCaptureFile.js +67 -0
  75. package/dist/apispec/src/models/SandboxRestartOperation.d.ts +115 -0
  76. package/dist/apispec/src/models/SandboxRestartOperation.d.ts.map +1 -0
  77. package/dist/apispec/src/models/SandboxRestartOperation.js +95 -0
  78. package/dist/apispec/src/models/SandboxRestartRequest.d.ts +33 -0
  79. package/dist/apispec/src/models/SandboxRestartRequest.d.ts.map +1 -0
  80. package/dist/apispec/src/models/SandboxRestartRequest.js +43 -0
  81. package/dist/apispec/src/models/SandboxRestartRetryObservation.d.ts +83 -0
  82. package/dist/apispec/src/models/SandboxRestartRetryObservation.d.ts.map +1 -0
  83. package/dist/apispec/src/models/SandboxRestartRetryObservation.js +75 -0
  84. package/dist/apispec/src/models/SandboxRootFSForkLaunch.d.ts +123 -0
  85. package/dist/apispec/src/models/SandboxRootFSForkLaunch.d.ts.map +1 -0
  86. package/dist/apispec/src/models/SandboxRootFSForkLaunch.js +104 -0
  87. package/dist/apispec/src/models/SandboxRootFSForkLaunchRequest.d.ts +51 -0
  88. package/dist/apispec/src/models/SandboxRootFSForkLaunchRequest.d.ts.map +1 -0
  89. package/dist/apispec/src/models/SandboxRootFSForkLaunchRequest.js +55 -0
  90. package/dist/apispec/src/models/SandboxRootFSForkObservation.d.ts +129 -0
  91. package/dist/apispec/src/models/SandboxRootFSForkObservation.d.ts.map +1 -0
  92. package/dist/apispec/src/models/SandboxRootFSForkObservation.js +107 -0
  93. package/dist/apispec/src/models/SandboxRootFSIdentity.d.ts +138 -0
  94. package/dist/apispec/src/models/SandboxRootFSIdentity.d.ts.map +1 -0
  95. package/dist/apispec/src/models/SandboxRootFSIdentity.js +111 -0
  96. package/dist/apispec/src/models/SandboxRootFSSnapshot.d.ts +6 -0
  97. package/dist/apispec/src/models/SandboxRootFSSnapshot.d.ts.map +1 -1
  98. package/dist/apispec/src/models/SandboxRootFSSnapshot.js +2 -0
  99. package/dist/apispec/src/models/SandboxRuntimeHealth.d.ts +40 -0
  100. package/dist/apispec/src/models/SandboxRuntimeHealth.d.ts.map +1 -0
  101. package/dist/apispec/src/models/SandboxRuntimeHealth.js +48 -0
  102. package/dist/apispec/src/models/SandboxSnapshotRestoreOperation.d.ts +139 -0
  103. package/dist/apispec/src/models/SandboxSnapshotRestoreOperation.d.ts.map +1 -0
  104. package/dist/apispec/src/models/SandboxSnapshotRestoreOperation.js +109 -0
  105. package/dist/apispec/src/models/SandboxSnapshotRestoreRequest.d.ts +51 -0
  106. package/dist/apispec/src/models/SandboxSnapshotRestoreRequest.d.ts.map +1 -0
  107. package/dist/apispec/src/models/SandboxSnapshotRestoreRequest.js +55 -0
  108. package/dist/apispec/src/models/SandboxStorageHealth.d.ts +46 -0
  109. package/dist/apispec/src/models/SandboxStorageHealth.d.ts.map +1 -0
  110. package/dist/apispec/src/models/SandboxStorageHealth.js +52 -0
  111. package/dist/apispec/src/models/SuccessManagedFileReadResponse.d.ts +40 -0
  112. package/dist/apispec/src/models/SuccessManagedFileReadResponse.d.ts.map +1 -0
  113. package/dist/apispec/src/models/SuccessManagedFileReadResponse.js +48 -0
  114. package/dist/apispec/src/models/SuccessManagedFilesStateResponse.d.ts +40 -0
  115. package/dist/apispec/src/models/SuccessManagedFilesStateResponse.d.ts.map +1 -0
  116. package/dist/apispec/src/models/SuccessManagedFilesStateResponse.js +48 -0
  117. package/dist/apispec/src/models/SuccessSandboxHealthResponse.d.ts +40 -0
  118. package/dist/apispec/src/models/SuccessSandboxHealthResponse.d.ts.map +1 -0
  119. package/dist/apispec/src/models/SuccessSandboxHealthResponse.js +48 -0
  120. package/dist/apispec/src/models/SuccessSandboxMemoryOperationResponse.d.ts +40 -0
  121. package/dist/apispec/src/models/SuccessSandboxMemoryOperationResponse.d.ts.map +1 -0
  122. package/dist/apispec/src/models/SuccessSandboxMemoryOperationResponse.js +48 -0
  123. package/dist/apispec/src/models/SuccessSandboxMemoryRestorationResponse.d.ts +40 -0
  124. package/dist/apispec/src/models/SuccessSandboxMemoryRestorationResponse.d.ts.map +1 -0
  125. package/dist/apispec/src/models/SuccessSandboxMemoryRestorationResponse.js +48 -0
  126. package/dist/apispec/src/models/SuccessSandboxRestartFinalCaptureFileResponse.d.ts +40 -0
  127. package/dist/apispec/src/models/SuccessSandboxRestartFinalCaptureFileResponse.d.ts.map +1 -0
  128. package/dist/apispec/src/models/SuccessSandboxRestartFinalCaptureFileResponse.js +48 -0
  129. package/dist/apispec/src/models/SuccessSandboxRestartFinalCaptureResponse.d.ts +40 -0
  130. package/dist/apispec/src/models/SuccessSandboxRestartFinalCaptureResponse.d.ts.map +1 -0
  131. package/dist/apispec/src/models/SuccessSandboxRestartFinalCaptureResponse.js +48 -0
  132. package/dist/apispec/src/models/SuccessSandboxRestartOperationResponse.d.ts +40 -0
  133. package/dist/apispec/src/models/SuccessSandboxRestartOperationResponse.d.ts.map +1 -0
  134. package/dist/apispec/src/models/SuccessSandboxRestartOperationResponse.js +48 -0
  135. package/dist/apispec/src/models/SuccessSandboxRootFSForkLaunchResponse.d.ts +40 -0
  136. package/dist/apispec/src/models/SuccessSandboxRootFSForkLaunchResponse.d.ts.map +1 -0
  137. package/dist/apispec/src/models/SuccessSandboxRootFSForkLaunchResponse.js +48 -0
  138. package/dist/apispec/src/models/SuccessSandboxRootFSForkObservationResponse.d.ts +40 -0
  139. package/dist/apispec/src/models/SuccessSandboxRootFSForkObservationResponse.d.ts.map +1 -0
  140. package/dist/apispec/src/models/SuccessSandboxRootFSForkObservationResponse.js +48 -0
  141. package/dist/apispec/src/models/SuccessSandboxRootFSIdentityResponse.d.ts +40 -0
  142. package/dist/apispec/src/models/SuccessSandboxRootFSIdentityResponse.d.ts.map +1 -0
  143. package/dist/apispec/src/models/SuccessSandboxRootFSIdentityResponse.js +48 -0
  144. package/dist/apispec/src/models/SuccessSandboxSnapshotRestoreOperationResponse.d.ts +40 -0
  145. package/dist/apispec/src/models/SuccessSandboxSnapshotRestoreOperationResponse.d.ts.map +1 -0
  146. package/dist/apispec/src/models/SuccessSandboxSnapshotRestoreOperationResponse.js +48 -0
  147. package/dist/apispec/src/models/index.d.ts +37 -0
  148. package/dist/apispec/src/models/index.d.ts.map +1 -1
  149. package/dist/apispec/src/models/index.js +37 -0
  150. package/dist/fork_launch.d.ts +15 -0
  151. package/dist/fork_launch.d.ts.map +1 -0
  152. package/dist/fork_launch.js +38 -0
  153. package/dist/health.d.ts +4 -0
  154. package/dist/health.d.ts.map +1 -0
  155. package/dist/health.js +46 -0
  156. package/dist/index.d.ts +8 -0
  157. package/dist/index.d.ts.map +1 -1
  158. package/dist/index.js +1 -0
  159. package/dist/memory_operation.d.ts +12 -0
  160. package/dist/memory_operation.d.ts.map +1 -0
  161. package/dist/memory_operation.js +44 -0
  162. package/dist/memory_restoration.d.ts +5 -0
  163. package/dist/memory_restoration.d.ts.map +1 -0
  164. package/dist/memory_restoration.js +29 -0
  165. package/dist/models.d.ts +2 -0
  166. package/dist/models.d.ts.map +1 -1
  167. package/dist/resources/sandboxes.d.ts +73 -1
  168. package/dist/resources/sandboxes.d.ts.map +1 -1
  169. package/dist/resources/sandboxes.js +336 -3
  170. package/dist/restart_final_capture.d.ts +10 -0
  171. package/dist/restart_final_capture.d.ts.map +1 -0
  172. package/dist/restart_final_capture.js +52 -0
  173. package/dist/sandbox_managed_files.d.ts +34 -0
  174. package/dist/sandbox_managed_files.d.ts.map +1 -0
  175. package/dist/sandbox_managed_files.js +96 -0
  176. package/dist/sandbox_sessions.d.ts +5 -0
  177. package/dist/sandbox_sessions.d.ts.map +1 -1
  178. package/dist/sandbox_sessions.js +103 -1
  179. package/dist/ws_client.d.ts +8 -0
  180. package/dist/ws_client.d.ts.map +1 -1
  181. package/dist/ws_client.js +20 -2
  182. package/package.json +2 -2
@@ -1,3 +1,8 @@
1
+ import { validateMemoryRestorationTarget, validateMemoryRestoration } from "../memory_restoration.js";
2
+ import { validateForkLaunchInput, validateForkLaunchWire, validateForkLaunchReceipt } from "../fork_launch.js";
3
+ import { validateMemoryOperationLookup, validateMemoryOperation } from "../memory_operation.js";
4
+ import { validateCaptureTarget, validateCaptureName, validateCaptureReceipt, validateFinalCapture, decodeFinalCaptureFile } from "../restart_final_capture.js";
5
+ import { validateSandboxHealth, validateSandboxHealthWireTimes } from "../health.js";
1
6
  import { ensureData, ensureModel } from "../response.js";
2
7
  import { SandboxWaitTimeoutError, SandboxLifecycleFailedError, wrapApiCall } from "../errors.js";
3
8
  import { Sandbox as SandboxHandle } from "../sandbox.js";
@@ -122,13 +127,207 @@ export class Sandboxes {
122
127
  const response = await wrapApiCall(() => this.client.apispec.sandboxes.apiV1SandboxesIdStatusGet({ id: sandboxId }));
123
128
  return ensureData(response, "get sandbox status returned empty response");
124
129
  }
130
+ /** Explicitly restores one snapshot and discards processes. Retain every input after uncertainty. */
131
+ async restoreSnapshot(sandboxId, options) {
132
+ if (!Number.isSafeInteger(options.expectedRuntimeGeneration) || options.expectedRuntimeGeneration < 1 || options.expectedRuntimeGeneration >= Number.MAX_SAFE_INTEGER) {
133
+ throw new Error("expectedRuntimeGeneration must be nonnegative with a safe integer successor");
134
+ }
135
+ validateSnapshotRestoreIdentity(options.snapshotId);
136
+ validateSnapshotRestoreIdentity(options.snapshotGenerationId);
137
+ if (options.discardProcessState !== true)
138
+ throw new Error("explicit process-state discard required");
139
+ validateRestartKey(options.idempotencyKey);
140
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.restoreSandboxSnapshot({
141
+ id: sandboxId, idempotencyKey: options.idempotencyKey,
142
+ sandboxSnapshotRestoreRequest: { expectedRuntimeGeneration: options.expectedRuntimeGeneration, snapshotId: options.snapshotId, snapshotGenerationId: options.snapshotGenerationId, discardProcessState: options.discardProcessState },
143
+ }));
144
+ const operation = validateSnapshotRestoreReceipt(ensureData(response, "snapshot restore returned empty response"), sandboxId);
145
+ if (operation.requestKey !== options.idempotencyKey || operation.fromRuntimeGeneration !== options.expectedRuntimeGeneration || operation.snapshotId !== options.snapshotId || operation.snapshotGenerationId !== options.snapshotGenerationId) {
146
+ throw new Error("snapshot restore receipt does not match request");
147
+ }
148
+ return operation;
149
+ }
150
+ /** Historical operation status; this does not report current application health. */
151
+ async getSnapshotRestoreOperation(sandboxId, operationId) {
152
+ if (!restartOperationIDPattern.test(operationId))
153
+ throw new Error("invalid snapshot restore operation ID");
154
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.getSandboxSnapshotRestoreOperation({ id: sandboxId, operationId }));
155
+ const operation = validateSnapshotRestoreReceipt(ensureData(response, "snapshot restore lookup returned empty response"), sandboxId);
156
+ if (operation.id !== operationId)
157
+ throw new Error("snapshot restore receipt does not match operation");
158
+ return operation;
159
+ }
160
+ /** Recovers a lost acknowledgement without submitting or retrying a mutation. */
161
+ async findSnapshotRestoreOperation(sandboxId, requestKey) {
162
+ validateRestartKey(requestKey);
163
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.findSandboxSnapshotRestoreOperation({ id: sandboxId, requestKey }));
164
+ const operation = validateSnapshotRestoreReceipt(ensureData(response, "snapshot restore lookup returned empty response"), sandboxId);
165
+ if (operation.requestKey !== requestKey)
166
+ throw new Error("snapshot restore receipt does not match request key");
167
+ return operation;
168
+ }
169
+ /** Explicitly discards process state. Retain both inputs after an uncertain reply. */
170
+ async restart(sandboxId, options) {
171
+ if (!Number.isSafeInteger(options.expectedRuntimeGeneration) || options.expectedRuntimeGeneration < 0 || options.expectedRuntimeGeneration >= Number.MAX_SAFE_INTEGER) {
172
+ throw new Error("expectedRuntimeGeneration must be nonnegative with a safe integer successor");
173
+ }
174
+ validateRestartKey(options.idempotencyKey);
175
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.restartSandbox({
176
+ id: sandboxId, idempotencyKey: options.idempotencyKey,
177
+ sandboxRestartRequest: { expectedRuntimeGeneration: options.expectedRuntimeGeneration },
178
+ }));
179
+ const operation = validateRestartReceipt(ensureData(response, "restart returned empty response"), sandboxId);
180
+ if (operation.requestKey !== options.idempotencyKey || operation.fromRuntimeGeneration !== options.expectedRuntimeGeneration) {
181
+ throw new Error("restart receipt does not match request");
182
+ }
183
+ return operation;
184
+ }
185
+ /** Historical operation status; this does not report current application health. */
186
+ async getRestartOperation(sandboxId, operationId) {
187
+ if (!restartOperationIDPattern.test(operationId))
188
+ throw new Error("invalid restart operation ID");
189
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.getSandboxRestartOperation({ id: sandboxId, operationId }));
190
+ const operation = validateRestartReceipt(ensureData(response, "restart lookup returned empty response"), sandboxId);
191
+ if (operation.id !== operationId)
192
+ throw new Error("restart receipt does not match operation");
193
+ return operation;
194
+ }
195
+ /** Recovers a lost acknowledgement without submitting or retrying a mutation. */
196
+ async findRestartOperation(sandboxId, requestKey) {
197
+ validateRestartKey(requestKey);
198
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.findSandboxRestartOperation({ id: sandboxId, requestKey }));
199
+ const operation = validateRestartReceipt(ensureData(response, "restart lookup returned empty response"), sandboxId);
200
+ if (operation.requestKey !== requestKey)
201
+ throw new Error("restart receipt does not match request key");
202
+ return operation;
203
+ }
204
+ /** Durable stopped-source metadata, independent of guest execution. */
205
+ async getSnapshotRestoreFinalCapture(sandboxId, operationId) {
206
+ validateCaptureTarget(sandboxId, operationId);
207
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.getSandboxSnapshotRestoreFinalCapture({ id: sandboxId, operationId }));
208
+ return validateFinalCapture(ensureData(response, "final capture status missing"), sandboxId, operationId);
209
+ }
210
+ /** Only found=false attests absence. Errors never become logout or trigger fallback. */
211
+ async readSnapshotRestoreFinalCaptureFile(sandboxId, operationId, captureId, namespace, name) {
212
+ validateCaptureTarget(sandboxId, operationId, captureId);
213
+ validateCaptureName(namespace);
214
+ validateCaptureName(name);
215
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.readSandboxSnapshotRestoreFinalCaptureFile({ id: sandboxId, operationId, captureId, namespace, name }));
216
+ return decodeFinalCaptureFile(ensureData(response, "final capture file response missing"), operationId, captureId);
217
+ }
218
+ /** Call only after durable owner commit. Retry the identical receipt after uncertainty. */
219
+ async acknowledgeSnapshotRestoreFinalCapture(sandboxId, operationId, captureId, receiptId) {
220
+ validateCaptureTarget(sandboxId, operationId, captureId);
221
+ validateCaptureReceipt(receiptId);
222
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.acknowledgeSandboxSnapshotRestoreFinalCapture({ id: sandboxId, operationId, sandboxRestartFinalCaptureAcknowledgement: { captureId, receiptId } }));
223
+ const result = validateFinalCapture(ensureData(response, "final capture acknowledgement missing"), sandboxId, operationId);
224
+ if (result.captureId !== captureId || result.receiptId !== receiptId || !["acknowledged", "released"].includes(result.state))
225
+ throw new Error("final capture acknowledgement changed receipt");
226
+ return result;
227
+ }
228
+ /** Independent observations. Guest evidence is advisory; never resumes or restarts. */
229
+ /** Durable stopped-source metadata, independent of guest execution. */
230
+ async getRestartFinalCapture(sandboxId, operationId) {
231
+ validateCaptureTarget(sandboxId, operationId);
232
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.getSandboxRestartFinalCapture({ id: sandboxId, operationId }));
233
+ return validateFinalCapture(ensureData(response, "final capture status missing"), sandboxId, operationId);
234
+ }
235
+ /** Only found=false attests absence. Errors never become logout or trigger fallback. */
236
+ async readRestartFinalCaptureFile(sandboxId, operationId, captureId, namespace, name) {
237
+ validateCaptureTarget(sandboxId, operationId, captureId);
238
+ validateCaptureName(namespace);
239
+ validateCaptureName(name);
240
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.readSandboxRestartFinalCaptureFile({ id: sandboxId, operationId, captureId, namespace, name }));
241
+ return decodeFinalCaptureFile(ensureData(response, "final capture file response missing"), operationId, captureId);
242
+ }
243
+ /** Call only after durable owner commit. Retry the identical receipt after uncertainty. */
244
+ async acknowledgeRestartFinalCapture(sandboxId, operationId, captureId, receiptId) {
245
+ validateCaptureTarget(sandboxId, operationId, captureId);
246
+ validateCaptureReceipt(receiptId);
247
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.acknowledgeSandboxRestartFinalCapture({ id: sandboxId, operationId, sandboxRestartFinalCaptureAcknowledgement: { captureId, receiptId } }));
248
+ const result = validateFinalCapture(ensureData(response, "final capture acknowledgement missing"), sandboxId, operationId);
249
+ if (result.captureId !== captureId || result.receiptId !== receiptId || !["acknowledged", "released"].includes(result.state))
250
+ throw new Error("final capture acknowledgement changed receipt");
251
+ return result;
252
+ }
253
+ /** Independent observations. Guest evidence is advisory; never resumes or restarts. */
254
+ async getHealth(sandboxId, options) {
255
+ if (typeof sandboxId !== "string" || !sandboxId || sandboxId.trim() !== sandboxId)
256
+ throw new Error("invalid sandbox identity");
257
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.getSandboxHealthRaw({ id: sandboxId }, options?.signal ? { signal: options.signal } : undefined));
258
+ // The generated Date decoder normalizes missing/null and numeric dates.
259
+ // Inspect only their wire representation before the typed conversion.
260
+ validateSandboxHealthWireTimes(await response.raw.clone().json());
261
+ const health = ensureData(await response.value(), "health returned empty response");
262
+ return validateSandboxHealth(health, sandboxId);
263
+ }
264
+ /** Committed memory lineage; bind to owned history before adopting a restored session. */
265
+ async getMemoryRestoration(sandboxId, runtimeGeneration) {
266
+ validateMemoryRestorationTarget(sandboxId, runtimeGeneration);
267
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.getSandboxMemoryRestorationRaw({ id: sandboxId, runtimeGeneration }));
268
+ const wire = await response.raw.clone().json();
269
+ if (typeof wire?.data?.observed_at !== "string" || !/^\d{4}-\d{2}-\d{2}T.*(?:Z|[+-]\d{2}:\d{2})$/.test(wire.data.observed_at))
270
+ throw new Error("invalid memory restoration observation time");
271
+ return validateMemoryRestoration(ensureData(await response.value(), "memory restoration returned empty response"), sandboxId, runtimeGeneration);
272
+ }
273
+ /** Read the original request without dispatching it. current is a snapshot, never a lease. */
274
+ async lookupMemoryOperation(sandboxId, options) {
275
+ validateMemoryOperationLookup(sandboxId, options);
276
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.lookupSandboxMemoryOperationRaw({
277
+ id: sandboxId, action: options.action, expectedRuntimeGeneration: options.expectedRuntimeGeneration,
278
+ idempotencyKey: options.idempotencyKey, checkpointId: options.checkpointId,
279
+ }));
280
+ // Optional nulls are normalized away by the generated decoder; they are not
281
+ // valid absent evidence in this contract.
282
+ const wire = await response.raw.clone().json();
283
+ if (wire?.data?.reason === null || wire?.data?.result_runtime_generation === null)
284
+ throw new Error("invalid memory operation observation");
285
+ return validateMemoryOperation(ensureData(await response.value(), "memory operation lookup returned empty response"), sandboxId, options);
286
+ }
287
+ /** External provenance only; never a credential-clean or storage-liveness attestation. */
288
+ async getRootFSIdentity(sandboxId) {
289
+ if (typeof sandboxId !== "string" || !sandboxId || sandboxId.trim() !== sandboxId)
290
+ throw new Error("invalid sandbox identity");
291
+ const response = await wrapApiCall(() => this.client.apispec.sandboxRootfs.getSandboxRootFSIdentity({ id: sandboxId }));
292
+ const identity = ensureData(response, "RootFS identity returned empty response");
293
+ if (identity.sandboxId !== sandboxId ||
294
+ [identity.runtimeGeneration, identity.lifecycleEpoch, identity.writerEpoch, identity.managedFilesSizeBytes].some(value => !Number.isSafeInteger(value) || value < 0) ||
295
+ [identity.filesystemId, identity.headGenerationId, identity.baseArtifactDigest, identity.sourceOciDigest].some(value => typeof value !== "string" || !value) ||
296
+ [identity.observedAt, identity.sandboxCreatedAt, identity.filesystemCreatedAt].some(value => !(value instanceof Date) || !Number.isFinite(value.getTime())) ||
297
+ typeof identity.hasImportedFilesystem !== "boolean" || typeof identity.activeLifecycle !== "boolean" ||
298
+ !["active", "paused", "terminated"].includes(identity.desiredState))
299
+ throw new Error("invalid external RootFS identity");
300
+ for (const digest of [identity.runtimeCompatibilityDigest, identity.retainedRuntimeCompatibilityDigest]) {
301
+ if (digest !== undefined && (typeof digest !== "string" || !/^sha256:[a-f0-9]{64}$/.test(digest) ||
302
+ identity.desiredState !== "active" || identity.activeLifecycle || identity.runtimeGeneration <= 0))
303
+ throw new Error("invalid external runtime compatibility");
304
+ }
305
+ return identity;
306
+ }
125
307
  async pause(sandboxId, options) {
126
308
  const response = await wrapApiCall(() => this.client.apispec.sandboxes.apiV1SandboxesIdPausePost({
127
309
  id: sandboxId,
128
- sandboxExecutionStateRequest: options === undefined ? undefined : { memory: options.memory ?? false },
310
+ sandboxPauseRequest: options === undefined ? undefined : { memory: options.memory ?? false },
129
311
  }));
130
312
  return ensureData(response, "pause sandbox returned empty response");
131
313
  }
314
+ /** Bind memory pause to one source generation. Retry with the same inputs after an uncertain reply. */
315
+ async pauseMemoryForOperation(sandboxId, options) {
316
+ if (!Number.isSafeInteger(options.expectedRuntimeGeneration) || options.expectedRuntimeGeneration <= 0 ||
317
+ typeof options.idempotencyKey !== "string" || !/^[A-Za-z0-9._:-]{1,255}$/.test(options.idempotencyKey)) {
318
+ throw new Error("invalid conditional memory pause generation or idempotency key");
319
+ }
320
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.apiV1SandboxesIdPausePost({
321
+ id: sandboxId, idempotencyKey: options.idempotencyKey,
322
+ sandboxPauseRequest: { memory: true, expectedRuntimeGeneration: options.expectedRuntimeGeneration },
323
+ }));
324
+ const result = ensureData(response, "conditional memory pause returned empty response");
325
+ if (result.sandboxId !== sandboxId || result.runtimeGeneration !== options.expectedRuntimeGeneration ||
326
+ typeof result.operationId !== "string" || !/^idem-[a-f0-9]{64}$/.test(result.operationId) || typeof result.paused !== "boolean") {
327
+ throw new Error("conditional memory pause response does not match request");
328
+ }
329
+ return result;
330
+ }
132
331
  /** Requests a pause and waits for its durable checkpoint to commit. */
133
332
  async pauseAndWait(sandboxId, options) {
134
333
  throwIfAborted(options?.signal, "sandbox lifecycle wait was aborted");
@@ -147,6 +346,25 @@ export class Sandboxes {
147
346
  }));
148
347
  return ensureData(response, "resume sandbox returned empty response");
149
348
  }
349
+ /** Restore one retained checkpoint. Retain all inputs after an uncertain reply. */
350
+ async resumeMemoryForOperation(sandboxId, options) {
351
+ if (!Number.isSafeInteger(options.expectedRuntimeGeneration) || options.expectedRuntimeGeneration < 0 || options.expectedRuntimeGeneration >= Number.MAX_SAFE_INTEGER ||
352
+ typeof options.checkpointId !== "string" || !/^[!-~]{1,256}$/.test(options.checkpointId) ||
353
+ typeof options.idempotencyKey !== "string" || !/^[A-Za-z0-9._:-]{1,255}$/.test(options.idempotencyKey)) {
354
+ throw new Error("invalid conditional memory resume generation, checkpoint or idempotency key");
355
+ }
356
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.apiV1SandboxesIdResumePost({
357
+ id: sandboxId, idempotencyKey: options.idempotencyKey,
358
+ sandboxExecutionStateRequest: { memory: true, expectedRuntimeGeneration: options.expectedRuntimeGeneration, checkpointId: options.checkpointId },
359
+ }));
360
+ const result = ensureData(response, "conditional memory resume returned empty response");
361
+ if (result.sandboxId !== sandboxId || result.resumed !== true || result.checkpointId !== options.checkpointId ||
362
+ result.fromRuntimeGeneration !== options.expectedRuntimeGeneration || result.runtimeGeneration !== options.expectedRuntimeGeneration + 1 ||
363
+ typeof result.operationId !== "string" || !/^idem-[a-f0-9]{64}$/.test(result.operationId)) {
364
+ throw new Error("conditional memory resume response does not match request");
365
+ }
366
+ return result;
367
+ }
150
368
  /** Requests a resume and waits for the committed running generation. */
151
369
  async resumeAndWait(sandboxId, options) {
152
370
  throwIfAborted(options?.signal, "sandbox lifecycle wait was aborted");
@@ -178,6 +396,80 @@ export class Sandboxes {
178
396
  }));
179
397
  return ensureData(response, "create sandbox rootfs snapshot returned empty response");
180
398
  }
399
+ /** One conditional capture. Retry uncertainty with the same key and metadata. */
400
+ async captureRootFSSnapshot(sandboxId, options) {
401
+ const { idempotencyKey, ...request } = options;
402
+ if (!sandboxId || !Number.isSafeInteger(request.expectedRuntimeGeneration) || request.expectedRuntimeGeneration <= 0 ||
403
+ !/^[A-Za-z0-9._:-]{1,255}$/.test(idempotencyKey))
404
+ throw new Error("conditional snapshot requires a source, positive safe generation and canonical key");
405
+ const response = await wrapApiCall(() => this.client.apispec.sandboxRootfs.captureSandboxRootFSSnapshot({
406
+ id: sandboxId, idempotencyKey, captureSandboxRootFSSnapshotRequest: request,
407
+ }));
408
+ const snapshot = ensureData(response, "conditional snapshot returned no receipt");
409
+ if (!snapshot.id || snapshot.sandboxId !== sandboxId || !Number.isFinite(snapshot.createdAt.getTime())) {
410
+ throw new Error("conditional snapshot returned mismatched identity");
411
+ }
412
+ return snapshot;
413
+ }
414
+ /** Read only the original capture. Missing/pending results remain errors and never authorize a replacement. */
415
+ async getCapturedRootFSSnapshot(sandboxId, options) {
416
+ if (!sandboxId || !Number.isSafeInteger(options.expectedRuntimeGeneration) || options.expectedRuntimeGeneration <= 0 ||
417
+ !/^[A-Za-z0-9._:-]{1,255}$/.test(options.idempotencyKey))
418
+ throw new Error("snapshot observation requires a source, positive safe generation and canonical key");
419
+ const response = await wrapApiCall(() => this.client.apispec.sandboxRootfs.getCapturedSandboxRootFSSnapshot({ id: sandboxId, ...options }));
420
+ const snapshot = ensureData(response, "snapshot observation returned no receipt");
421
+ if (!snapshot.id || snapshot.sandboxId !== sandboxId || !Number.isFinite(snapshot.createdAt.getTime())) {
422
+ throw new Error("snapshot observation returned mismatched identity");
423
+ }
424
+ return snapshot;
425
+ }
426
+ /** Reads original fork provenance without retrying or submitting work. Not a state reservation or credential-safety attestation. */
427
+ async getRootFSFork(sandboxId, options) {
428
+ if (!sandboxId || !Number.isSafeInteger(options.expectedRuntimeGeneration) || options.expectedRuntimeGeneration < 0 ||
429
+ typeof options.idempotencyKey !== "string" || !/^[A-Za-z0-9._:-]{1,255}$/.test(options.idempotencyKey)) {
430
+ throw new Error("fork observation requires a source, nonnegative safe generation and canonical key");
431
+ }
432
+ const response = await wrapApiCall(() => this.client.apispec.sandboxRootfs.getSandboxRootFSFork({ id: sandboxId, ...options }));
433
+ const r = ensureData(response, "fork observation returned no receipt");
434
+ if (r.sourceSandboxId !== sandboxId || r.sourceRuntimeGeneration !== options.expectedRuntimeGeneration || r.targetSandboxId === sandboxId ||
435
+ r.targetFilesystemId !== r.targetSandboxId ||
436
+ [r.operationId, r.targetSandboxId, r.sourceFilesystemId, r.sourceHeadGenerationId, r.targetHeadGenerationId, r.baseArtifactDigest, r.sourceOciDigest].some(v => typeof v !== "string" || !v) ||
437
+ !Number.isSafeInteger(r.writerEpoch) || r.writerEpoch <= 0 || !Number.isSafeInteger(r.managedFilesSizeBytes) || r.managedFilesSizeBytes < 0 ||
438
+ typeof r.autoResume !== "boolean" || typeof r.automaticRoutes !== "boolean" ||
439
+ [r.sandboxCreatedAt, r.filesystemCreatedAt, r.observedAt].some(v => !(v instanceof Date) || !Number.isFinite(v.getTime()))) {
440
+ throw new Error("fork observation returned mismatched identity");
441
+ }
442
+ return r;
443
+ }
444
+ /** Exactly one conditional first launch; no waiting, retry or ordinary resume fallback. */
445
+ async launchRootFSFork(sandboxId, options) {
446
+ const q = { ...options };
447
+ validateForkLaunchInput(sandboxId, q);
448
+ const response = await wrapApiCall(() => this.client.apispec.sandboxRootfs.launchSandboxRootFSForkRaw({
449
+ id: sandboxId, idempotencyKey: q.idempotencyKey,
450
+ sandboxRootFSForkLaunchRequest: { forkOperationId: q.forkOperationId, filesystemId: q.filesystemId, headGenerationId: q.headGenerationId, writerEpoch: q.writerEpoch },
451
+ }));
452
+ if (![200, 202].includes(response.raw.status))
453
+ throw new Error("unexpected fork launch response status");
454
+ validateForkLaunchWire(await response.raw.clone().json());
455
+ const r = validateForkLaunchReceipt(ensureData(await response.value(), "fork launch returned no receipt"), sandboxId, q);
456
+ if (response.raw.status === 202 && r.state !== "pending")
457
+ throw new Error("accepted fork launch returned terminal evidence");
458
+ return r;
459
+ }
460
+ /** Original-condition lookup, including completed history with current=false. Never submits work. */
461
+ async getRootFSForkLaunch(sandboxId, options) {
462
+ const q = { ...options };
463
+ validateForkLaunchInput(sandboxId, q);
464
+ const response = await wrapApiCall(() => this.client.apispec.sandboxRootfs.getSandboxRootFSForkLaunchRaw({
465
+ id: sandboxId, idempotencyKey: q.idempotencyKey, forkOperationId: q.forkOperationId,
466
+ filesystemId: q.filesystemId, headGenerationId: q.headGenerationId, writerEpoch: q.writerEpoch,
467
+ }));
468
+ if (response.raw.status !== 200)
469
+ throw new Error("unexpected fork launch lookup status");
470
+ validateForkLaunchWire(await response.raw.clone().json());
471
+ return validateForkLaunchReceipt(ensureData(await response.value(), "fork launch lookup returned no receipt"), sandboxId, q);
472
+ }
181
473
  async listRootFSSnapshots(sandboxId) {
182
474
  const response = await wrapApiCall(() => this.client.apispec.sandboxRootfs.apiV1SandboxesIdSnapshotsGet({ id: sandboxId }));
183
475
  const data = ensureData(response, "list sandbox rootfs snapshots returned empty response");
@@ -210,8 +502,12 @@ export class Sandboxes {
210
502
  return ensureData(response, "rebase sandbox rootfs returned empty response");
211
503
  }
212
504
  async fork(sandboxId, request, options = {}) {
213
- if (request?.memory && (!options.idempotencyKey?.trim() || new TextEncoder().encode(options.idempotencyKey).length > 255)) {
214
- throw new Error("memory fork requires a stable idempotencyKey of at most 255 bytes");
505
+ const generation = request?.expectedRuntimeGeneration;
506
+ if (generation !== undefined && (!Number.isSafeInteger(generation) || generation < 0 || (request?.memory && generation === Number.MAX_SAFE_INTEGER))) {
507
+ throw new Error("invalid expected runtime generation for fork");
508
+ }
509
+ if ((request?.memory || generation !== undefined) && (!options.idempotencyKey?.trim() || new TextEncoder().encode(options.idempotencyKey).length > 255)) {
510
+ throw new Error("conditional or memory fork requires a stable idempotencyKey of at most 255 bytes");
215
511
  }
216
512
  const response = await wrapApiCall(() => this.client.apispec.sandboxRootfs.apiV1SandboxesIdForkPost({
217
513
  id: sandboxId,
@@ -224,3 +520,40 @@ export class Sandboxes {
224
520
  return new SandboxHandle({ id: sandboxId, client: this.client });
225
521
  }
226
522
  }
523
+ const restartOperationIDPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
524
+ function validateRestartKey(key) {
525
+ if (typeof key !== "string" || !/^[A-Za-z0-9._:-]{1,255}$/.test(key))
526
+ throw new Error("invalid restart request key");
527
+ }
528
+ function validateRestartReceipt(operation, sandboxId) {
529
+ validateRestartKey(operation.requestKey);
530
+ if (operation.sandboxId !== sandboxId || !restartOperationIDPattern.test(operation.id) ||
531
+ !Number.isSafeInteger(operation.fromRuntimeGeneration) || operation.fromRuntimeGeneration < 0 || operation.fromRuntimeGeneration >= Number.MAX_SAFE_INTEGER ||
532
+ !["pausing", "paused", "resuming", "succeeded", "failed", "superseded"].includes(operation.state)) {
533
+ throw new Error("invalid restart receipt");
534
+ }
535
+ if (operation.state === "succeeded") {
536
+ if (!Number.isSafeInteger(operation.resultRuntimeGeneration) || operation.resultRuntimeGeneration !== operation.fromRuntimeGeneration + 1) {
537
+ throw new Error("invalid restart result generation");
538
+ }
539
+ }
540
+ else if (operation.resultRuntimeGeneration !== undefined)
541
+ throw new Error("uncommitted restart result generation");
542
+ return operation;
543
+ }
544
+ function validateSnapshotRestoreIdentity(value) {
545
+ if (typeof value !== "string" || !value || value.trim() !== value || new TextEncoder().encode(value).length > 512 || value.includes("\0"))
546
+ throw new Error("invalid snapshot identity");
547
+ }
548
+ function validateSnapshotRestoreReceipt(operation, sandboxId) {
549
+ validateRestartReceipt(operation, sandboxId);
550
+ validateSnapshotRestoreIdentity(operation.snapshotId);
551
+ validateSnapshotRestoreIdentity(operation.snapshotGenerationId);
552
+ if (operation.discardProcessState !== true || operation.fromRuntimeGeneration < 1)
553
+ throw new Error("invalid snapshot restore receipt");
554
+ if (operation.restoredRootfsGenerationId !== undefined)
555
+ validateSnapshotRestoreIdentity(operation.restoredRootfsGenerationId);
556
+ if (["resuming", "succeeded"].includes(operation.state) && !operation.restoredRootfsGenerationId)
557
+ throw new Error("restored head receipt missing");
558
+ return operation;
559
+ }
@@ -0,0 +1,10 @@
1
+ import type { SandboxRestartFinalCapture, SandboxRestartFinalCaptureFile } from "./apispec/src/models/index.js";
2
+ export type RestartFinalCaptureFile = Omit<SandboxRestartFinalCaptureFile, "content"> & {
3
+ content: Uint8Array;
4
+ };
5
+ export declare function validateCaptureTarget(sandbox: string, operation: string, capture?: string): void;
6
+ export declare function validateCaptureName(name: string): void;
7
+ export declare function validateCaptureReceipt(receipt: string): void;
8
+ export declare function validateFinalCapture(value: SandboxRestartFinalCapture, sandbox: string, operation: string): SandboxRestartFinalCapture;
9
+ export declare function decodeFinalCaptureFile(value: SandboxRestartFinalCaptureFile, operation: string, capture: string): RestartFinalCaptureFile;
10
+ //# sourceMappingURL=restart_final_capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restart_final_capture.d.ts","sourceRoot":"","sources":["../src/restart_final_capture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,8BAA8B,EAAE,MAAM,4BAA4B,CAAC;AAI7G,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,8BAA8B,EAAE,SAAS,CAAC,GAAG;IAAE,OAAO,EAAE,UAAU,CAAA;CAAE,CAAC;AAEhH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAGhG;AACD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEtD;AACD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE5D;AACD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,0BAA0B,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,0BAA0B,CAYtI;AACD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,8BAA8B,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,uBAAuB,CAUzI"}
@@ -0,0 +1,52 @@
1
+ const operationPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
2
+ const capturePattern = /^[a-f0-9]{64}$/;
3
+ export function validateCaptureTarget(sandbox, operation, capture) {
4
+ if (typeof sandbox !== "string" || !sandbox || sandbox.trim() !== sandbox || sandbox === "." || sandbox === ".." || typeof operation !== "string" || !operationPattern.test(operation) ||
5
+ (arguments.length >= 3 && (typeof capture !== "string" || !capturePattern.test(capture))))
6
+ throw new Error("invalid restart final capture identity");
7
+ }
8
+ export function validateCaptureName(name) {
9
+ if (typeof name !== "string" || !/^[A-Za-z0-9._-]{1,128}$/.test(name) || name === "." || name === ".." || name.startsWith(".s0-write-"))
10
+ throw new Error("invalid final capture file name or namespace");
11
+ }
12
+ export function validateCaptureReceipt(receipt) {
13
+ if (typeof receipt !== "string" || !/^[A-Za-z0-9._:-]{1,255}$/.test(receipt))
14
+ throw new Error("invalid final capture receipt");
15
+ }
16
+ export function validateFinalCapture(value, sandbox, operation) {
17
+ if (value.sandboxId !== sandbox || value.operationId !== operation || !Number.isSafeInteger(value.fromRuntimeGeneration) || value.fromRuntimeGeneration < 1 ||
18
+ !["pending", "stopped", "acknowledged", "released"].includes(value.state))
19
+ throw new Error("invalid final capture status");
20
+ if (value.state === "pending") {
21
+ if (value.captureId !== undefined || value.stoppedAt !== undefined || value.receiptId !== undefined)
22
+ throw new Error("pending final capture has a receipt");
23
+ }
24
+ else {
25
+ if (typeof value.captureId !== "string" || !capturePattern.test(value.captureId) || !(value.stoppedAt instanceof Date) || !Number.isFinite(value.stoppedAt.getTime()))
26
+ throw new Error("invalid stopped capture identity");
27
+ if (value.state === "stopped") {
28
+ if (value.receiptId !== undefined)
29
+ throw new Error("unacknowledged capture has a receipt");
30
+ }
31
+ else
32
+ validateCaptureReceipt(value.receiptId);
33
+ }
34
+ return value;
35
+ }
36
+ export function decodeFinalCaptureFile(value, operation, capture) {
37
+ if (value.operationId !== operation || value.captureId !== capture || !Number.isSafeInteger(value.runtimeGeneration) || value.runtimeGeneration < 1 ||
38
+ typeof value.found !== "boolean" || !Number.isSafeInteger(value.sizeBytes) || value.sizeBytes < 1048576 || value.sizeBytes > 67108864 ||
39
+ typeof value.mutationSequence !== "string" || !/^(0|[1-9][0-9]{0,19})$/.test(value.mutationSequence) || BigInt(value.mutationSequence) > 18446744073709551615n)
40
+ throw new Error("invalid final capture file authority");
41
+ try {
42
+ if (typeof value.content !== "string" || value.content.length > 4 * Math.ceil(4194304 / 3))
43
+ throw new Error();
44
+ const binary = atob(value.content);
45
+ if (binary.length > 4194304 || btoa(binary) !== value.content || (!value.found && binary.length !== 0))
46
+ throw new Error();
47
+ return { ...value, content: Uint8Array.from(binary, c => c.charCodeAt(0)) };
48
+ }
49
+ catch {
50
+ throw new Error("invalid final capture file content");
51
+ }
52
+ }
@@ -0,0 +1,34 @@
1
+ import type { ManagedFileReadResponse, ManagedFilesState } from "./apispec/src/models/index.js";
2
+ import type { Client } from "./client.js";
3
+ export interface ManagedFilesOptions {
4
+ runtimeGeneration: number;
5
+ /** Omit to use the projection root. */
6
+ namespace?: string;
7
+ }
8
+ export type ManagedFileRead = Omit<ManagedFileReadResponse, "content"> & {
9
+ content: Uint8Array;
10
+ };
11
+ /** Fixed-generation access to node-owned files, independent of guest execution.
12
+ * No automatic resume, generation discovery, fallback or write retry is performed.
13
+ * Sequences are shared across namespaces and do not track native guest refreshes.
14
+ */
15
+ export declare class ManagedFiles {
16
+ private readonly client;
17
+ private readonly id;
18
+ private readonly generation;
19
+ private readonly namespace?;
20
+ constructor(client: Client, id: string, options: ManagedFilesOptions);
21
+ private state;
22
+ /** Describes projection state; does not attest historical RootFS credential safety. */
23
+ inspect(): Promise<ManagedFilesState>;
24
+ read(name: string): Promise<ManagedFileRead>;
25
+ /** On an ambiguous error, inspect/read to reconcile; never blindly fetch a new sequence and repeat. */
26
+ write(name: string, content: Uint8Array, expectedMutationSequence: string): Promise<ManagedFilesState>;
27
+ delete(name: string, expectedMutationSequence: string): Promise<ManagedFilesState>;
28
+ }
29
+ declare module "./sandbox.js" {
30
+ interface Sandbox {
31
+ managedFiles(options: ManagedFilesOptions): ManagedFiles;
32
+ }
33
+ }
34
+ //# sourceMappingURL=sandbox_managed_files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox_managed_files.d.ts","sourceRoot":"","sources":["../src/sandbox_managed_files.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC7F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAKvC,MAAM,WAAW,mBAAmB;IAClC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,uBAAuB,EAAE,SAAS,CAAC,GAAG;IAAE,OAAO,EAAE,UAAU,CAAA;CAAE,CAAC;AA2BjG;;;GAGG;AACH,qBAAa,YAAY;IAIX,OAAO,CAAC,QAAQ,CAAC,MAAM;IAAU,OAAO,CAAC,QAAQ,CAAC,EAAE;IAHhE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAS;gBAEP,MAAM,EAAE,MAAM,EAAmB,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB;IAOtG,OAAO,CAAC,KAAK;IAMb,uFAAuF;IACjF,OAAO,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAKrC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAUlD,uGAAuG;IACjG,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,wBAAwB,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAUtG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,wBAAwB,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;CASzF;AAED,OAAO,QAAQ,WAAW,CAAC;IAAE,UAAU,OAAO;QAAG,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAAC;KAAE;CAAE"}
@@ -0,0 +1,96 @@
1
+ import { wrapApiCall } from "./errors.js";
2
+ import { ensureData } from "./response.js";
3
+ import { Sandbox } from "./sandbox.js";
4
+ function validateName(name) {
5
+ if (!/^[A-Za-z0-9._-]{1,128}$/.test(name) || name === "." || name === ".." || name.startsWith(".s0-write-")) {
6
+ throw new Error("invalid managed file name or namespace");
7
+ }
8
+ }
9
+ function validateSequence(value) {
10
+ if (typeof value !== "string" || !/^(0|[1-9][0-9]{0,19})$/.test(value) || BigInt(value) > 18446744073709551615n) {
11
+ throw new Error("invalid managed file mutation sequence");
12
+ }
13
+ }
14
+ function encode(content) {
15
+ if (!(content instanceof Uint8Array) || content.byteLength > 4 * 1024 * 1024)
16
+ throw new Error("invalid managed file content size or type");
17
+ let binary = "";
18
+ for (let i = 0; i < content.length; i += 8192)
19
+ binary += String.fromCharCode(...content.subarray(i, i + 8192));
20
+ return btoa(binary);
21
+ }
22
+ function decode(content) {
23
+ try {
24
+ if (typeof content !== "string" || content.length > 4 * Math.ceil((4 * 1024 * 1024) / 3))
25
+ throw new Error();
26
+ const binary = atob(content);
27
+ if (binary.length > 4 * 1024 * 1024 || btoa(binary) !== content)
28
+ throw new Error();
29
+ return Uint8Array.from(binary, c => c.charCodeAt(0));
30
+ }
31
+ catch {
32
+ throw new Error("invalid managed file response content");
33
+ }
34
+ }
35
+ /** Fixed-generation access to node-owned files, independent of guest execution.
36
+ * No automatic resume, generation discovery, fallback or write retry is performed.
37
+ * Sequences are shared across namespaces and do not track native guest refreshes.
38
+ */
39
+ export class ManagedFiles {
40
+ client;
41
+ id;
42
+ generation;
43
+ namespace;
44
+ constructor(client, id, options) {
45
+ this.client = client;
46
+ this.id = id;
47
+ if (!Number.isSafeInteger(options.runtimeGeneration) || options.runtimeGeneration <= 0)
48
+ throw new Error("invalid managed file runtime generation");
49
+ if (options.namespace !== undefined)
50
+ validateName(options.namespace);
51
+ this.generation = options.runtimeGeneration;
52
+ this.namespace = options.namespace;
53
+ }
54
+ state(value) {
55
+ if (value.runtimeGeneration !== this.generation)
56
+ throw new Error("managed file response generation changed");
57
+ validateSequence(value.mutationSequence);
58
+ return value;
59
+ }
60
+ /** Describes projection state; does not attest historical RootFS credential safety. */
61
+ async inspect() {
62
+ const response = await wrapApiCall(() => this.client.apispec.sandboxes.inspectSandboxManagedFiles({ id: this.id, runtimeGeneration: this.generation }));
63
+ return this.state(ensureData(response, "managed file response missing"));
64
+ }
65
+ async read(name) {
66
+ validateName(name);
67
+ const params = { id: this.id, runtimeGeneration: this.generation, name };
68
+ const response = await wrapApiCall(() => this.namespace === undefined
69
+ ? this.client.apispec.sandboxes.readSandboxManagedFile(params)
70
+ : this.client.apispec.sandboxes.readSandboxNamespacedManagedFile({ ...params, namespace: this.namespace }));
71
+ const value = this.state(ensureData(response, "managed file response missing"));
72
+ return { ...value, content: decode(value.content) };
73
+ }
74
+ /** On an ambiguous error, inspect/read to reconcile; never blindly fetch a new sequence and repeat. */
75
+ async write(name, content, expectedMutationSequence) {
76
+ validateName(name);
77
+ validateSequence(expectedMutationSequence);
78
+ const params = { id: this.id, runtimeGeneration: this.generation, name, managedFileWriteRequest: { content: encode(content), expectedMutationSequence } };
79
+ const response = await wrapApiCall(() => this.namespace === undefined
80
+ ? this.client.apispec.sandboxes.writeSandboxManagedFile(params)
81
+ : this.client.apispec.sandboxes.writeSandboxNamespacedManagedFile({ ...params, namespace: this.namespace }));
82
+ return this.state(ensureData(response, "managed file response missing"));
83
+ }
84
+ async delete(name, expectedMutationSequence) {
85
+ validateName(name);
86
+ validateSequence(expectedMutationSequence);
87
+ const params = { id: this.id, runtimeGeneration: this.generation, name, expectedMutationSequence };
88
+ const response = await wrapApiCall(() => this.namespace === undefined
89
+ ? this.client.apispec.sandboxes.deleteSandboxManagedFile(params)
90
+ : this.client.apispec.sandboxes.deleteSandboxNamespacedManagedFile({ ...params, namespace: this.namespace }));
91
+ return this.state(ensureData(response, "managed file response missing"));
92
+ }
93
+ }
94
+ Sandbox.prototype.managedFiles = function (options) {
95
+ return new ManagedFiles(this.client, this.id, options);
96
+ };
@@ -5,6 +5,10 @@ declare module "./sandbox.js" {
5
5
  interface Sandbox {
6
6
  listSessions(): Promise<ExecutionSession[]>;
7
7
  createSession(spec: ExecutionSessionSpec, options?: SessionCreateOptions): Promise<ExecutionSession>;
8
+ /** Read-only original creation receipt; never auto-resumes or creates. */
9
+ findConditionalSession(creationKey: string, runtimeGeneration: number): Promise<ExecutionSession>;
10
+ findRestoredConditionalSession(creationKey: string, runtimeGeneration: number, creationRuntimeGeneration: number): Promise<ExecutionSession>;
11
+ connectRestoredConditionalSession(sessionId: string, creationKey: string, runtimeGeneration: number, creationRuntimeGeneration: number, attemptId: string, options?: SessionWebSocketOptions): Promise<ExecutionSessionConnection>;
8
12
  getSession(sessionId: string): Promise<ExecutionSession>;
9
13
  updateSession(sessionId: string, spec: ExecutionSessionSpec): Promise<ExecutionSession>;
10
14
  deleteSession(sessionId: string): Promise<SuccessDeletedResponse>;
@@ -15,6 +19,7 @@ declare module "./sandbox.js" {
15
19
  resizeSessionTerminal(sessionId: string, request: ExecutionSessionTerminalResizeRequest): Promise<SuccessResizedResponse>;
16
20
  listSessionEvents(sessionId: string, options?: SessionEventOptions): Promise<ExecutionSessionEventPage>;
17
21
  watchSessionEvents(sessionId: string, options?: SessionEventStreamOptions): Promise<SessionEventStream>;
22
+ connectConditionalSession(sessionId: string, creationKey: string, runtimeGeneration: number, attemptId: string, options?: SessionWebSocketOptions): Promise<ExecutionSessionConnection>;
18
23
  connectSession(sessionId: string, options?: SessionWebSocketOptions): Promise<ExecutionSessionConnection>;
19
24
  }
20
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sandbox_sessions.d.ts","sourceRoot":"","sources":["../src/sandbox_sessions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sandbox_sessions.d.ts","sourceRoot":"","sources":["../src/sandbox_sessions.ts"],"names":[],"mappings":"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"}