freestyle-sandboxes 0.1.40 → 0.1.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.cjs CHANGED
@@ -5648,6 +5648,7 @@ function composeCreateVmOptions(arr) {
5648
5648
  result.activityThresholdBytes = options.activityThresholdBytes;
5649
5649
  if (options.discriminator !== void 0)
5650
5650
  result.discriminator = options.discriminator;
5651
+ if (options.skipCache !== void 0) result.skipCache = options.skipCache;
5651
5652
  if (options.persistence !== void 0)
5652
5653
  result.persistence = options.persistence;
5653
5654
  if (options.ports !== void 0) {
@@ -5795,6 +5796,7 @@ function composeCreateVmOptions(arr) {
5795
5796
  aptDeps: newTemplate.aptDeps ?? baseTemplate.aptDeps,
5796
5797
  vcpuCount: newTemplate.vcpuCount !== void 0 ? newTemplate.vcpuCount : baseTemplate.vcpuCount,
5797
5798
  discriminator: newTemplate.discriminator ?? baseTemplate.discriminator,
5799
+ skipCache: newTemplate.skipCache ?? baseTemplate.skipCache,
5798
5800
  workdir: newTemplate.workdir !== void 0 ? newTemplate.workdir : baseTemplate.workdir,
5799
5801
  idleTimeoutSeconds: newTemplate.idleTimeoutSeconds !== void 0 ? newTemplate.idleTimeoutSeconds : baseTemplate.idleTimeoutSeconds,
5800
5802
  waitForReadySignal: newTemplate.waitForReadySignal !== void 0 ? newTemplate.waitForReadySignal : baseTemplate.waitForReadySignal,
@@ -6545,7 +6547,10 @@ class VmSpec {
6545
6547
  }
6546
6548
  ensureSnapshot() {
6547
6549
  if (!isVmSpecLike$1(this.raw.snapshot)) {
6548
- this.raw.snapshot = this.raw.discriminator !== void 0 ? new VmSpec({ discriminator: this.raw.discriminator }) : new VmSpec();
6550
+ this.raw.snapshot = new VmSpec({
6551
+ discriminator: this.raw.discriminator,
6552
+ skipCache: this.raw.skipCache
6553
+ });
6549
6554
  }
6550
6555
  return this.raw.snapshot;
6551
6556
  }
@@ -6574,6 +6579,9 @@ class VmSpec {
6574
6579
  discriminator(value) {
6575
6580
  return this.mergeRaw({ discriminator: value });
6576
6581
  }
6582
+ skipCache() {
6583
+ return this.mergeRaw({ skipCache: true });
6584
+ }
6577
6585
  workdir(path) {
6578
6586
  return this.mergeRaw({ workdir: path });
6579
6587
  }
@@ -6695,6 +6703,73 @@ function isVmSpecLike$1(value) {
6695
6703
  function isVmTemplateLike$1(value) {
6696
6704
  return !!value && typeof value === "object" && "raw" in value && "with" in value;
6697
6705
  }
6706
+ function cloneVmSpecTree(spec) {
6707
+ const clonedRaw = cloneVmSpecRaw$1(spec.raw);
6708
+ return new VmSpec({
6709
+ ...clonedRaw,
6710
+ with: { ...spec.builders },
6711
+ __withDiscriminators: spec.getBuilderDiscriminators()
6712
+ });
6713
+ }
6714
+ function isVmSpecInstance(value) {
6715
+ return value instanceof VmSpec;
6716
+ }
6717
+ function isVmTemplateInstance(value) {
6718
+ return value instanceof VmTemplate;
6719
+ }
6720
+ function cloneVmTemplateTree(template) {
6721
+ const clonedRaw = cloneVmTemplateRaw$1(template.raw);
6722
+ return new VmTemplate({
6723
+ ...clonedRaw,
6724
+ with: { ...template.with }
6725
+ });
6726
+ }
6727
+ function cloneVmSpecRaw$1(raw) {
6728
+ const cloned = cloneVmTemplateRaw$1(raw);
6729
+ if (isVmSpecInstance(raw.snapshot)) {
6730
+ cloned.snapshot = cloneVmSpecTree(raw.snapshot);
6731
+ } else if (raw.snapshot !== void 0) {
6732
+ cloned.snapshot = cloneVmValue(raw.snapshot);
6733
+ }
6734
+ return cloned;
6735
+ }
6736
+ function cloneVmTemplateRaw$1(raw) {
6737
+ const cloned = cloneVmPlainObject(raw);
6738
+ if (isVmTemplateInstance(raw.template)) {
6739
+ cloned.template = cloneVmTemplateTree(raw.template);
6740
+ } else if (raw.template !== void 0) {
6741
+ cloned.template = cloneVmValue(raw.template);
6742
+ }
6743
+ return cloned;
6744
+ }
6745
+ function cloneVmPlainObject(value) {
6746
+ if (!value || typeof value !== "object") {
6747
+ return value;
6748
+ }
6749
+ const cloned = {};
6750
+ for (const [key, entry] of Object.entries(value)) {
6751
+ cloned[key] = cloneVmValue(entry);
6752
+ }
6753
+ return cloned;
6754
+ }
6755
+ function cloneVmValue(value) {
6756
+ if (value instanceof VmBaseImage) {
6757
+ return new VmBaseImage(value.toRaw());
6758
+ }
6759
+ if (isVmSpecInstance(value)) {
6760
+ return cloneVmSpecTree(value);
6761
+ }
6762
+ if (isVmTemplateInstance(value)) {
6763
+ return cloneVmTemplateTree(value);
6764
+ }
6765
+ if (Array.isArray(value)) {
6766
+ return value.map((entry) => cloneVmValue(entry));
6767
+ }
6768
+ if (value && typeof value === "object") {
6769
+ return cloneVmPlainObject(value);
6770
+ }
6771
+ return value;
6772
+ }
6698
6773
  async function convertSpecSnapshotsToTemplates(spec, processBuilders = true) {
6699
6774
  if (!isVmSpecLike$1(spec.raw.snapshot)) {
6700
6775
  return void 0;
@@ -6733,7 +6808,10 @@ async function processOuterSpecBuilders(spec) {
6733
6808
  snapshotSpec = spec.raw.snapshot;
6734
6809
  } else {
6735
6810
  const inheritedDiscriminator = spec.getBuilderDiscriminator(key) ?? spec.raw.discriminator;
6736
- snapshotSpec = inheritedDiscriminator !== void 0 ? new VmSpec({ discriminator: inheritedDiscriminator }) : new VmSpec({});
6811
+ snapshotSpec = new VmSpec({
6812
+ discriminator: inheritedDiscriminator,
6813
+ skipCache: spec.raw.skipCache
6814
+ });
6737
6815
  spec.raw.snapshot = snapshotSpec;
6738
6816
  }
6739
6817
  spec.raw.snapshot = await builder.configureSnapshotSpec(snapshotSpec);
@@ -6760,7 +6838,10 @@ async function processSpecTree(spec) {
6760
6838
  snapshotSpec = spec.raw.snapshot;
6761
6839
  } else {
6762
6840
  const inheritedDiscriminator = spec.getBuilderDiscriminator(key) ?? spec.raw.discriminator;
6763
- snapshotSpec = inheritedDiscriminator !== void 0 ? new VmSpec({ discriminator: inheritedDiscriminator }) : new VmSpec({});
6841
+ snapshotSpec = new VmSpec({
6842
+ discriminator: inheritedDiscriminator,
6843
+ skipCache: spec.raw.skipCache
6844
+ });
6764
6845
  spec.raw.snapshot = snapshotSpec;
6765
6846
  }
6766
6847
  spec.raw.snapshot = await builder.configureSnapshotSpec(snapshotSpec);
@@ -6806,7 +6887,17 @@ class VmsNamespace {
6806
6887
  snapshots;
6807
6888
  async create(options = {}) {
6808
6889
  if (isVmSpecLike$1(options)) {
6809
- options = { spec: options };
6890
+ options = { spec: cloneVmSpecTree(options) };
6891
+ } else {
6892
+ if (isVmSpecLike$1(options.spec)) {
6893
+ options.spec = cloneVmSpecTree(options.spec);
6894
+ }
6895
+ if (isVmSpecLike$1(options.snapshot)) {
6896
+ options.snapshot = cloneVmSpecTree(options.snapshot);
6897
+ }
6898
+ if (isVmTemplateLike$1(options.template)) {
6899
+ options.template = cloneVmTemplateTree(options.template);
6900
+ }
6810
6901
  }
6811
6902
  if (isVmSpecLike$1(options.snapshot)) {
6812
6903
  if (isVmSpecLike$1(options.spec)) {
@@ -6918,6 +7009,12 @@ class VmsNamespace {
6918
7009
  template: _template,
6919
7010
  ...requestConfig
6920
7011
  } = config;
7012
+ let slowPathTimeout;
7013
+ slowPathTimeout = setTimeout(() => {
7014
+ console.log(
7015
+ "VM creation is taking longer than expected. This usually happens when there's a cache miss on your vm's base snapshot. Subsequent vm creations with this configuration will likely be much faster."
7016
+ );
7017
+ }, 5e3);
6921
7018
  const response = await this.freestyle._apiClient.post("/v1/vms", {
6922
7019
  body: {
6923
7020
  ...requestConfig,
@@ -6928,9 +7025,11 @@ class VmsNamespace {
6928
7025
  git: normalizeGitOptions(config.git)
6929
7026
  }
6930
7027
  }).catch((e) => {
7028
+ if (slowPathTimeout) clearTimeout(slowPathTimeout);
6931
7029
  enhanceError(e);
6932
7030
  throw e;
6933
7031
  });
7032
+ if (slowPathTimeout) clearTimeout(slowPathTimeout);
6934
7033
  const vmId = response.id;
6935
7034
  const vm = new Vm({ vmId, freestyle: this.freestyle });
6936
7035
  for (const key in builders) {
@@ -7083,7 +7182,12 @@ class VmSnapshotsNamespace {
7083
7182
  this.apiClient = apiClient;
7084
7183
  }
7085
7184
  async ensure(options) {
7086
- let requestOptions = options;
7185
+ let requestOptions = {
7186
+ ...options,
7187
+ spec: isVmSpecLike$1(options.spec) ? cloneVmSpecTree(options.spec) : void 0,
7188
+ snapshot: isVmSpecLike$1(options.snapshot) ? cloneVmSpecTree(options.snapshot) : void 0,
7189
+ template: isVmTemplateLike$1(options.template) ? cloneVmTemplateTree(options.template) : options.template
7190
+ };
7087
7191
  if (isVmSpecLike$1(requestOptions.snapshot)) {
7088
7192
  if (isVmSpecLike$1(requestOptions.spec)) {
7089
7193
  if (!requestOptions.spec.raw.snapshot) {
@@ -7129,6 +7233,7 @@ class VmSnapshotsNamespace {
7129
7233
  "snapshots.ensure requires a template or spec to build a snapshot"
7130
7234
  );
7131
7235
  }
7236
+ const startTime = Date.now();
7132
7237
  return this.apiClient.post("/v1/vms/snapshots", {
7133
7238
  body: {
7134
7239
  ...requestOptions,
@@ -7136,6 +7241,14 @@ class VmSnapshotsNamespace {
7136
7241
  isVmTemplateLike$1(requestOptions.template) ? requestOptions.template.raw : requestOptions.template
7137
7242
  )
7138
7243
  }
7244
+ }).then((response) => {
7245
+ const elapsedTime = Date.now() - startTime;
7246
+ if (elapsedTime > 5e3) {
7247
+ console.log(
7248
+ "Snapshot creation took longer than expected (> 5 seconds). This is slower because caches weren't available, but subsequent operations will be much faster."
7249
+ );
7250
+ }
7251
+ return response;
7139
7252
  }).catch((e) => {
7140
7253
  enhanceError(e);
7141
7254
  throw e;
package/index.d.cts CHANGED
@@ -4467,6 +4467,12 @@ interface PostV1VmsRequestBody {
4467
4467
  * These packages will be installed using `apt-get install` on VM startup.
4468
4468
  */
4469
4469
  aptDeps?: string[] | null;
4470
+ /**
4471
+ * When true, bypasses the snapshot cache and always creates a new snapshot.
4472
+ * The new snapshot still stores the template hash, so it becomes the updated
4473
+ * cache entry for future requests that do not set skipCache.
4474
+ */
4475
+ skipCache?: boolean | null;
4470
4476
  };
4471
4477
  /**
4472
4478
  * @deprecated
@@ -4883,6 +4889,12 @@ interface PostV1VmsSnapshotsRequestBody {
4883
4889
  * These packages will be installed using `apt-get install` on VM startup.
4884
4890
  */
4885
4891
  aptDeps?: string[] | null;
4892
+ /**
4893
+ * When true, bypasses the snapshot cache and always creates a new snapshot.
4894
+ * The new snapshot still stores the template hash, so it becomes the updated
4895
+ * cache entry for future requests that do not set skipCache.
4896
+ */
4897
+ skipCache?: boolean | null;
4886
4898
  };
4887
4899
  persistence?: null | ({
4888
4900
  priority?: number | null;
@@ -11909,6 +11921,12 @@ interface CreateSnapshotRequest {
11909
11921
  * These packages will be installed using `apt-get install` on VM startup.
11910
11922
  */
11911
11923
  aptDeps?: string[] | null;
11924
+ /**
11925
+ * When true, bypasses the snapshot cache and always creates a new snapshot.
11926
+ * The new snapshot still stores the template hash, so it becomes the updated
11927
+ * cache entry for future requests that do not set skipCache.
11928
+ */
11929
+ skipCache?: boolean | null;
11912
11930
  };
11913
11931
  persistence?: null | ({
11914
11932
  priority?: number | null;
@@ -12496,6 +12514,7 @@ declare class VmSpec<T extends Record<string, VmWithLike> = {}> {
12496
12514
  readySignalTimeoutSeconds(value: number): this;
12497
12515
  waitForReadySignal(value: boolean): this;
12498
12516
  discriminator(value: string): this;
12517
+ skipCache(): this;
12499
12518
  workdir(path: string): this;
12500
12519
  aptDeps(...deps: string[]): this;
12501
12520
  users(users: NonNullable<CreateVmOptions["users"]>): this;
@@ -12595,6 +12614,7 @@ type CreateVmOptions = Omit<PostV1VmsRequestBody, "template" | "systemd" | "git"
12595
12614
  };
12596
12615
  git?: null | GitOptions;
12597
12616
  discriminator?: CreateSnapshotRequest["template"]["discriminator"];
12617
+ skipCache?: CreateSnapshotRequest["template"]["skipCache"];
12598
12618
  };
12599
12619
 
12600
12620
  type CronSchedule = {
package/index.d.mts CHANGED
@@ -4467,6 +4467,12 @@ interface PostV1VmsRequestBody {
4467
4467
  * These packages will be installed using `apt-get install` on VM startup.
4468
4468
  */
4469
4469
  aptDeps?: string[] | null;
4470
+ /**
4471
+ * When true, bypasses the snapshot cache and always creates a new snapshot.
4472
+ * The new snapshot still stores the template hash, so it becomes the updated
4473
+ * cache entry for future requests that do not set skipCache.
4474
+ */
4475
+ skipCache?: boolean | null;
4470
4476
  };
4471
4477
  /**
4472
4478
  * @deprecated
@@ -4883,6 +4889,12 @@ interface PostV1VmsSnapshotsRequestBody {
4883
4889
  * These packages will be installed using `apt-get install` on VM startup.
4884
4890
  */
4885
4891
  aptDeps?: string[] | null;
4892
+ /**
4893
+ * When true, bypasses the snapshot cache and always creates a new snapshot.
4894
+ * The new snapshot still stores the template hash, so it becomes the updated
4895
+ * cache entry for future requests that do not set skipCache.
4896
+ */
4897
+ skipCache?: boolean | null;
4886
4898
  };
4887
4899
  persistence?: null | ({
4888
4900
  priority?: number | null;
@@ -11909,6 +11921,12 @@ interface CreateSnapshotRequest {
11909
11921
  * These packages will be installed using `apt-get install` on VM startup.
11910
11922
  */
11911
11923
  aptDeps?: string[] | null;
11924
+ /**
11925
+ * When true, bypasses the snapshot cache and always creates a new snapshot.
11926
+ * The new snapshot still stores the template hash, so it becomes the updated
11927
+ * cache entry for future requests that do not set skipCache.
11928
+ */
11929
+ skipCache?: boolean | null;
11912
11930
  };
11913
11931
  persistence?: null | ({
11914
11932
  priority?: number | null;
@@ -12496,6 +12514,7 @@ declare class VmSpec<T extends Record<string, VmWithLike> = {}> {
12496
12514
  readySignalTimeoutSeconds(value: number): this;
12497
12515
  waitForReadySignal(value: boolean): this;
12498
12516
  discriminator(value: string): this;
12517
+ skipCache(): this;
12499
12518
  workdir(path: string): this;
12500
12519
  aptDeps(...deps: string[]): this;
12501
12520
  users(users: NonNullable<CreateVmOptions["users"]>): this;
@@ -12595,6 +12614,7 @@ type CreateVmOptions = Omit<PostV1VmsRequestBody, "template" | "systemd" | "git"
12595
12614
  };
12596
12615
  git?: null | GitOptions;
12597
12616
  discriminator?: CreateSnapshotRequest["template"]["discriminator"];
12617
+ skipCache?: CreateSnapshotRequest["template"]["skipCache"];
12598
12618
  };
12599
12619
 
12600
12620
  type CronSchedule = {
package/index.mjs CHANGED
@@ -5646,6 +5646,7 @@ function composeCreateVmOptions(arr) {
5646
5646
  result.activityThresholdBytes = options.activityThresholdBytes;
5647
5647
  if (options.discriminator !== void 0)
5648
5648
  result.discriminator = options.discriminator;
5649
+ if (options.skipCache !== void 0) result.skipCache = options.skipCache;
5649
5650
  if (options.persistence !== void 0)
5650
5651
  result.persistence = options.persistence;
5651
5652
  if (options.ports !== void 0) {
@@ -5793,6 +5794,7 @@ function composeCreateVmOptions(arr) {
5793
5794
  aptDeps: newTemplate.aptDeps ?? baseTemplate.aptDeps,
5794
5795
  vcpuCount: newTemplate.vcpuCount !== void 0 ? newTemplate.vcpuCount : baseTemplate.vcpuCount,
5795
5796
  discriminator: newTemplate.discriminator ?? baseTemplate.discriminator,
5797
+ skipCache: newTemplate.skipCache ?? baseTemplate.skipCache,
5796
5798
  workdir: newTemplate.workdir !== void 0 ? newTemplate.workdir : baseTemplate.workdir,
5797
5799
  idleTimeoutSeconds: newTemplate.idleTimeoutSeconds !== void 0 ? newTemplate.idleTimeoutSeconds : baseTemplate.idleTimeoutSeconds,
5798
5800
  waitForReadySignal: newTemplate.waitForReadySignal !== void 0 ? newTemplate.waitForReadySignal : baseTemplate.waitForReadySignal,
@@ -6543,7 +6545,10 @@ class VmSpec {
6543
6545
  }
6544
6546
  ensureSnapshot() {
6545
6547
  if (!isVmSpecLike$1(this.raw.snapshot)) {
6546
- this.raw.snapshot = this.raw.discriminator !== void 0 ? new VmSpec({ discriminator: this.raw.discriminator }) : new VmSpec();
6548
+ this.raw.snapshot = new VmSpec({
6549
+ discriminator: this.raw.discriminator,
6550
+ skipCache: this.raw.skipCache
6551
+ });
6547
6552
  }
6548
6553
  return this.raw.snapshot;
6549
6554
  }
@@ -6572,6 +6577,9 @@ class VmSpec {
6572
6577
  discriminator(value) {
6573
6578
  return this.mergeRaw({ discriminator: value });
6574
6579
  }
6580
+ skipCache() {
6581
+ return this.mergeRaw({ skipCache: true });
6582
+ }
6575
6583
  workdir(path) {
6576
6584
  return this.mergeRaw({ workdir: path });
6577
6585
  }
@@ -6693,6 +6701,73 @@ function isVmSpecLike$1(value) {
6693
6701
  function isVmTemplateLike$1(value) {
6694
6702
  return !!value && typeof value === "object" && "raw" in value && "with" in value;
6695
6703
  }
6704
+ function cloneVmSpecTree(spec) {
6705
+ const clonedRaw = cloneVmSpecRaw$1(spec.raw);
6706
+ return new VmSpec({
6707
+ ...clonedRaw,
6708
+ with: { ...spec.builders },
6709
+ __withDiscriminators: spec.getBuilderDiscriminators()
6710
+ });
6711
+ }
6712
+ function isVmSpecInstance(value) {
6713
+ return value instanceof VmSpec;
6714
+ }
6715
+ function isVmTemplateInstance(value) {
6716
+ return value instanceof VmTemplate;
6717
+ }
6718
+ function cloneVmTemplateTree(template) {
6719
+ const clonedRaw = cloneVmTemplateRaw$1(template.raw);
6720
+ return new VmTemplate({
6721
+ ...clonedRaw,
6722
+ with: { ...template.with }
6723
+ });
6724
+ }
6725
+ function cloneVmSpecRaw$1(raw) {
6726
+ const cloned = cloneVmTemplateRaw$1(raw);
6727
+ if (isVmSpecInstance(raw.snapshot)) {
6728
+ cloned.snapshot = cloneVmSpecTree(raw.snapshot);
6729
+ } else if (raw.snapshot !== void 0) {
6730
+ cloned.snapshot = cloneVmValue(raw.snapshot);
6731
+ }
6732
+ return cloned;
6733
+ }
6734
+ function cloneVmTemplateRaw$1(raw) {
6735
+ const cloned = cloneVmPlainObject(raw);
6736
+ if (isVmTemplateInstance(raw.template)) {
6737
+ cloned.template = cloneVmTemplateTree(raw.template);
6738
+ } else if (raw.template !== void 0) {
6739
+ cloned.template = cloneVmValue(raw.template);
6740
+ }
6741
+ return cloned;
6742
+ }
6743
+ function cloneVmPlainObject(value) {
6744
+ if (!value || typeof value !== "object") {
6745
+ return value;
6746
+ }
6747
+ const cloned = {};
6748
+ for (const [key, entry] of Object.entries(value)) {
6749
+ cloned[key] = cloneVmValue(entry);
6750
+ }
6751
+ return cloned;
6752
+ }
6753
+ function cloneVmValue(value) {
6754
+ if (value instanceof VmBaseImage) {
6755
+ return new VmBaseImage(value.toRaw());
6756
+ }
6757
+ if (isVmSpecInstance(value)) {
6758
+ return cloneVmSpecTree(value);
6759
+ }
6760
+ if (isVmTemplateInstance(value)) {
6761
+ return cloneVmTemplateTree(value);
6762
+ }
6763
+ if (Array.isArray(value)) {
6764
+ return value.map((entry) => cloneVmValue(entry));
6765
+ }
6766
+ if (value && typeof value === "object") {
6767
+ return cloneVmPlainObject(value);
6768
+ }
6769
+ return value;
6770
+ }
6696
6771
  async function convertSpecSnapshotsToTemplates(spec, processBuilders = true) {
6697
6772
  if (!isVmSpecLike$1(spec.raw.snapshot)) {
6698
6773
  return void 0;
@@ -6731,7 +6806,10 @@ async function processOuterSpecBuilders(spec) {
6731
6806
  snapshotSpec = spec.raw.snapshot;
6732
6807
  } else {
6733
6808
  const inheritedDiscriminator = spec.getBuilderDiscriminator(key) ?? spec.raw.discriminator;
6734
- snapshotSpec = inheritedDiscriminator !== void 0 ? new VmSpec({ discriminator: inheritedDiscriminator }) : new VmSpec({});
6809
+ snapshotSpec = new VmSpec({
6810
+ discriminator: inheritedDiscriminator,
6811
+ skipCache: spec.raw.skipCache
6812
+ });
6735
6813
  spec.raw.snapshot = snapshotSpec;
6736
6814
  }
6737
6815
  spec.raw.snapshot = await builder.configureSnapshotSpec(snapshotSpec);
@@ -6758,7 +6836,10 @@ async function processSpecTree(spec) {
6758
6836
  snapshotSpec = spec.raw.snapshot;
6759
6837
  } else {
6760
6838
  const inheritedDiscriminator = spec.getBuilderDiscriminator(key) ?? spec.raw.discriminator;
6761
- snapshotSpec = inheritedDiscriminator !== void 0 ? new VmSpec({ discriminator: inheritedDiscriminator }) : new VmSpec({});
6839
+ snapshotSpec = new VmSpec({
6840
+ discriminator: inheritedDiscriminator,
6841
+ skipCache: spec.raw.skipCache
6842
+ });
6762
6843
  spec.raw.snapshot = snapshotSpec;
6763
6844
  }
6764
6845
  spec.raw.snapshot = await builder.configureSnapshotSpec(snapshotSpec);
@@ -6804,7 +6885,17 @@ class VmsNamespace {
6804
6885
  snapshots;
6805
6886
  async create(options = {}) {
6806
6887
  if (isVmSpecLike$1(options)) {
6807
- options = { spec: options };
6888
+ options = { spec: cloneVmSpecTree(options) };
6889
+ } else {
6890
+ if (isVmSpecLike$1(options.spec)) {
6891
+ options.spec = cloneVmSpecTree(options.spec);
6892
+ }
6893
+ if (isVmSpecLike$1(options.snapshot)) {
6894
+ options.snapshot = cloneVmSpecTree(options.snapshot);
6895
+ }
6896
+ if (isVmTemplateLike$1(options.template)) {
6897
+ options.template = cloneVmTemplateTree(options.template);
6898
+ }
6808
6899
  }
6809
6900
  if (isVmSpecLike$1(options.snapshot)) {
6810
6901
  if (isVmSpecLike$1(options.spec)) {
@@ -6916,6 +7007,12 @@ class VmsNamespace {
6916
7007
  template: _template,
6917
7008
  ...requestConfig
6918
7009
  } = config;
7010
+ let slowPathTimeout;
7011
+ slowPathTimeout = setTimeout(() => {
7012
+ console.log(
7013
+ "VM creation is taking longer than expected. This usually happens when there's a cache miss on your vm's base snapshot. Subsequent vm creations with this configuration will likely be much faster."
7014
+ );
7015
+ }, 5e3);
6919
7016
  const response = await this.freestyle._apiClient.post("/v1/vms", {
6920
7017
  body: {
6921
7018
  ...requestConfig,
@@ -6926,9 +7023,11 @@ class VmsNamespace {
6926
7023
  git: normalizeGitOptions(config.git)
6927
7024
  }
6928
7025
  }).catch((e) => {
7026
+ if (slowPathTimeout) clearTimeout(slowPathTimeout);
6929
7027
  enhanceError(e);
6930
7028
  throw e;
6931
7029
  });
7030
+ if (slowPathTimeout) clearTimeout(slowPathTimeout);
6932
7031
  const vmId = response.id;
6933
7032
  const vm = new Vm({ vmId, freestyle: this.freestyle });
6934
7033
  for (const key in builders) {
@@ -7081,7 +7180,12 @@ class VmSnapshotsNamespace {
7081
7180
  this.apiClient = apiClient;
7082
7181
  }
7083
7182
  async ensure(options) {
7084
- let requestOptions = options;
7183
+ let requestOptions = {
7184
+ ...options,
7185
+ spec: isVmSpecLike$1(options.spec) ? cloneVmSpecTree(options.spec) : void 0,
7186
+ snapshot: isVmSpecLike$1(options.snapshot) ? cloneVmSpecTree(options.snapshot) : void 0,
7187
+ template: isVmTemplateLike$1(options.template) ? cloneVmTemplateTree(options.template) : options.template
7188
+ };
7085
7189
  if (isVmSpecLike$1(requestOptions.snapshot)) {
7086
7190
  if (isVmSpecLike$1(requestOptions.spec)) {
7087
7191
  if (!requestOptions.spec.raw.snapshot) {
@@ -7127,6 +7231,7 @@ class VmSnapshotsNamespace {
7127
7231
  "snapshots.ensure requires a template or spec to build a snapshot"
7128
7232
  );
7129
7233
  }
7234
+ const startTime = Date.now();
7130
7235
  return this.apiClient.post("/v1/vms/snapshots", {
7131
7236
  body: {
7132
7237
  ...requestOptions,
@@ -7134,6 +7239,14 @@ class VmSnapshotsNamespace {
7134
7239
  isVmTemplateLike$1(requestOptions.template) ? requestOptions.template.raw : requestOptions.template
7135
7240
  )
7136
7241
  }
7242
+ }).then((response) => {
7243
+ const elapsedTime = Date.now() - startTime;
7244
+ if (elapsedTime > 5e3) {
7245
+ console.log(
7246
+ "Snapshot creation took longer than expected (> 5 seconds). This is slower because caches weren't available, but subsequent operations will be much faster."
7247
+ );
7248
+ }
7249
+ return response;
7137
7250
  }).catch((e) => {
7138
7251
  enhanceError(e);
7139
7252
  throw e;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "freestyle-sandboxes",
3
- "version": "0.1.40",
3
+ "version": "0.1.42",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "require": {