@blaxel/core 0.3.13 → 0.3.18-dev.283

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 (45) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/client/sdk.gen.js +105 -3
  3. package/dist/cjs/common/settings.js +28 -3
  4. package/dist/cjs/common/settings.test.js +50 -0
  5. package/dist/cjs/common/shell.js +18 -0
  6. package/dist/cjs/sandbox/filesystem/filesystem.js +31 -11
  7. package/dist/cjs/sandbox/filesystem/filesystem.test.js +207 -2
  8. package/dist/cjs/sandbox/sandbox.js +124 -0
  9. package/dist/cjs/types/client/sdk.gen.d.ts +31 -1
  10. package/dist/cjs/types/client/types.gen.d.ts +368 -7
  11. package/dist/cjs/types/common/settings.d.ts +15 -0
  12. package/dist/cjs/types/common/shell.d.ts +13 -0
  13. package/dist/cjs/types/sandbox/sandbox.d.ts +56 -1
  14. package/dist/cjs/types/sandbox/schedule.d.ts +2 -2
  15. package/dist/cjs-browser/.tsbuildinfo +1 -1
  16. package/dist/cjs-browser/client/sdk.gen.js +105 -3
  17. package/dist/cjs-browser/common/settings.js +28 -3
  18. package/dist/cjs-browser/common/settings.test.js +50 -0
  19. package/dist/cjs-browser/common/shell.js +18 -0
  20. package/dist/cjs-browser/sandbox/filesystem/filesystem.js +31 -11
  21. package/dist/cjs-browser/sandbox/filesystem/filesystem.test.js +207 -2
  22. package/dist/cjs-browser/sandbox/sandbox.js +124 -0
  23. package/dist/cjs-browser/types/client/sdk.gen.d.ts +31 -1
  24. package/dist/cjs-browser/types/client/types.gen.d.ts +368 -7
  25. package/dist/cjs-browser/types/common/settings.d.ts +15 -0
  26. package/dist/cjs-browser/types/common/shell.d.ts +13 -0
  27. package/dist/cjs-browser/types/sandbox/sandbox.d.ts +56 -1
  28. package/dist/cjs-browser/types/sandbox/schedule.d.ts +2 -2
  29. package/dist/esm/.tsbuildinfo +1 -1
  30. package/dist/esm/client/sdk.gen.js +96 -0
  31. package/dist/esm/common/settings.js +28 -3
  32. package/dist/esm/common/settings.test.js +50 -0
  33. package/dist/esm/common/shell.js +15 -0
  34. package/dist/esm/sandbox/filesystem/filesystem.js +31 -11
  35. package/dist/esm/sandbox/filesystem/filesystem.test.js +208 -3
  36. package/dist/esm/sandbox/sandbox.js +125 -1
  37. package/dist/esm-browser/.tsbuildinfo +1 -1
  38. package/dist/esm-browser/client/sdk.gen.js +96 -0
  39. package/dist/esm-browser/common/settings.js +28 -3
  40. package/dist/esm-browser/common/settings.test.js +50 -0
  41. package/dist/esm-browser/common/shell.js +15 -0
  42. package/dist/esm-browser/sandbox/filesystem/filesystem.js +31 -11
  43. package/dist/esm-browser/sandbox/filesystem/filesystem.test.js +208 -3
  44. package/dist/esm-browser/sandbox/sandbox.js +125 -1
  45. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { createSandbox, createSandboxSnapshot, deleteSandbox, deleteSandboxSnapshot, forkSandbox, getSandbox, getSandboxByExternalId, listSandboxes, listSandboxSnapshots, updateSandbox } from "../client/index.js";
1
+ import { archiveSandbox, createSandbox, createSandboxSnapshot, deleteSandbox, deleteSandboxSnapshot, forkSandbox, getSandbox, getSandboxByExternalId, listSandboxes, listSandboxSnapshots, restoreSandboxSnapshot, unarchiveSandbox, updateSandbox } from "../client/index.js";
2
2
  import { logger } from "../common/logger.js";
3
3
  import { backoffDelayMs } from "../common/transient-retry.js";
4
4
  import { createPaginatedList } from "../common/pagination.js";
@@ -31,6 +31,23 @@ const TRANSIENT_SANDBOX_STATUSES = new Set([
31
31
  ]);
32
32
  const TRANSIENT_STATUS_MAX_WAIT_MS = 30_000;
33
33
  const TRANSIENT_STATUS_POLL_MS = 500;
34
+ // Archiving a filesystem, and restoring it, take as long as that filesystem is
35
+ // big — minutes for a few gigabytes.
36
+ const ARCHIVE_MAX_WAIT_MS = 1_800_000;
37
+ const ARCHIVE_WAIT_POLL_MS = 2_000;
38
+ // An archive is done when the sandbox is ARCHIVED; it is still under way while
39
+ // the record holds one of these.
40
+ const ARCHIVING_STATUSES = new Set(["ARCHIVING"]);
41
+ // A restore is done when the sandbox is DEPLOYED again; the instance is recreated
42
+ // before the archived filesystem is written back over its image.
43
+ const UNARCHIVING_STATUSES = new Set(["UNARCHIVING", "DEPLOYING", "BUILDING", "UPLOADING"]);
44
+ // The status the sandbox holds before the operation moves it, tolerated only
45
+ // while the operation is starting: an archive that fails hands the sandbox back
46
+ // as DEPLOYED and a restore that fails leaves it ARCHIVED, so reading the entry
47
+ // status once the operation has begun means it is over, not still running.
48
+ const ARCHIVE_ENTRY_STATUS = "DEPLOYED";
49
+ const UNARCHIVE_ENTRY_STATUS = "ARCHIVED";
50
+ const ARCHIVE_ENTRY_MAX_WAIT_MS = 30_000;
34
51
  // A create that outlives the edge's 60s origin-read timeout gets a 504 from
35
52
  // CloudFront while the control plane keeps deploying the sandbox for up to
36
53
  // 300s (ENG-3662 timeout ladder inversion). The 504 body is edge HTML with no
@@ -170,6 +187,24 @@ export class SandboxInstance {
170
187
  throwOnError: true,
171
188
  });
172
189
  }
190
+ /**
191
+ * Restore this sandbox to one of its own snapshots. The sandbox keeps its
192
+ * name, its URLs and its previews: the running instance is torn down and
193
+ * rebuilt from the snapshot, so everything written since it was taken is
194
+ * lost unless it was snapshotted too.
195
+ *
196
+ * The restore is asked for without waiting on the guest, the same way a fork
197
+ * is: connections to a sandbox still resuming are retried by the gateway.
198
+ *
199
+ * @param snapshotId - ID of the snapshot to restore this sandbox to.
200
+ */
201
+ async restore(snapshotId) {
202
+ const { data } = await restoreSandboxSnapshot({
203
+ path: { sandboxName: this.metadata.name, snapshotId },
204
+ throwOnError: true,
205
+ });
206
+ return data;
207
+ }
173
208
  /**
174
209
  * Fork this sandbox into a new sandbox or application.
175
210
  *
@@ -318,6 +353,95 @@ export class SandboxInstance {
318
353
  }
319
354
  return instance;
320
355
  }
356
+ /**
357
+ * Archive a sandbox: keep its filesystem, stop the sandbox.
358
+ *
359
+ * The filesystem changes made over the image are exported to the archive store
360
+ * and the sandbox is shut down; memory and running processes are lost, and the
361
+ * saved processes start again from their configuration when the sandbox is
362
+ * unarchived. The export runs in the background: this waits until the sandbox
363
+ * is ARCHIVED, pass `{ wait: false }` to return as soon as it is launched.
364
+ */
365
+ static async archive(sandboxName, options = {}) {
366
+ const { data } = await archiveSandbox({
367
+ path: { sandboxName },
368
+ throwOnError: true,
369
+ });
370
+ return SandboxInstance.waitForArchiveStatus(sandboxName, data, "ARCHIVED", ARCHIVING_STATUSES, ARCHIVE_ENTRY_STATUS, "archive", options);
371
+ }
372
+ /**
373
+ * Archive this sandbox: keep its filesystem, stop the sandbox.
374
+ *
375
+ * @see SandboxInstance.archive
376
+ */
377
+ async archive(options = {}) {
378
+ const instance = await SandboxInstance.archive(this.metadata.name, options);
379
+ this.refreshFrom(instance);
380
+ return this;
381
+ }
382
+ /**
383
+ * Recreate an archived sandbox from its archive.
384
+ *
385
+ * The sandbox is started again from its image, and the archived filesystem is
386
+ * written back over it. The sandbox answers, and its terminal is reachable, while the archived
387
+ * filesystem is written back over its image. This waits until the restore is
388
+ * done and the saved processes are running again; pass `{ wait: false }` to
389
+ * return while the sandbox is still UNARCHIVING.
390
+ */
391
+ static async unarchive(sandboxName, options = {}) {
392
+ const { data } = await unarchiveSandbox({
393
+ path: { sandboxName },
394
+ throwOnError: true,
395
+ });
396
+ return SandboxInstance.waitForArchiveStatus(sandboxName, data, "DEPLOYED", UNARCHIVING_STATUSES, UNARCHIVE_ENTRY_STATUS, "unarchive", options);
397
+ }
398
+ /**
399
+ * Recreate this sandbox from its archive.
400
+ *
401
+ * @see SandboxInstance.unarchive
402
+ */
403
+ async unarchive(options = {}) {
404
+ const instance = await SandboxInstance.unarchive(this.metadata.name, options);
405
+ this.refreshFrom(instance);
406
+ return this;
407
+ }
408
+ // The subsystems (fs, process, previews, ...) hold the configuration object
409
+ // this instance was built with, so a refresh writes into it rather than
410
+ // replacing it. Anything the read did not carry, the forced URL of a session
411
+ // above all, is kept.
412
+ refreshFrom(instance) {
413
+ Object.assign(this.sandbox, instance.sandbox);
414
+ }
415
+ static async waitForArchiveStatus(sandboxName, launched, target, pending, entry, action, { wait = true, maxWait = ARCHIVE_MAX_WAIT_MS, interval = ARCHIVE_WAIT_POLL_MS }) {
416
+ if (!wait || launched.status === target) {
417
+ return SandboxInstance.attachH2Session(new SandboxInstance(launched));
418
+ }
419
+ const deadline = Date.now() + maxWait;
420
+ // The status the sandbox is given back at is tolerated while the operation
421
+ // turns into a status change, but never past the wait the caller asked for.
422
+ const entryDeadline = Date.now() + Math.min(ARCHIVE_ENTRY_MAX_WAIT_MS, maxWait);
423
+ let started = false;
424
+ for (;;) {
425
+ await new Promise((resolve) => setTimeout(resolve, interval));
426
+ const instance = await SandboxInstance.get(sandboxName);
427
+ const status = instance.status;
428
+ if (status === target) {
429
+ return instance;
430
+ }
431
+ if (pending.has(status ?? "")) {
432
+ started = true;
433
+ }
434
+ else if (status === entry && !started && Date.now() < entryDeadline) {
435
+ continue;
436
+ }
437
+ if (!pending.has(status ?? "")) {
438
+ throw new Error(`Sandbox ${sandboxName} is ${status} while it should ${action}`);
439
+ }
440
+ if (Date.now() >= deadline) {
441
+ throw new Error(`Sandbox ${sandboxName} is still ${status} after waiting ${Math.round(maxWait / 1000)}s for it to ${action}`);
442
+ }
443
+ }
444
+ }
321
445
  static async get(sandboxName) {
322
446
  const { data } = await getSandbox({
323
447
  path: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blaxel/core",
3
- "version": "0.3.13",
3
+ "version": "0.3.18-dev.283",
4
4
  "description": "Blaxel Core SDK for TypeScript",
5
5
  "license": "MIT",
6
6
  "author": "Blaxel, INC (https://blaxel.ai)",