modal 0.3.14 → 0.3.16

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/dist/index.cjs CHANGED
@@ -55,7 +55,7 @@ __export(index_exports, {
55
55
  module.exports = __toCommonJS(index_exports);
56
56
 
57
57
  // src/app.ts
58
- var import_nice_grpc3 = require("nice-grpc");
58
+ var import_nice_grpc4 = require("nice-grpc");
59
59
 
60
60
  // node_modules/@bufbuild/protobuf/dist/esm/wire/varint.js
61
61
  function varint64read() {
@@ -18869,7 +18869,8 @@ function createBaseFunctionHandleMetadata() {
18869
18869
  methodHandleMetadata: {},
18870
18870
  functionSchema: void 0,
18871
18871
  inputPlaneUrl: void 0,
18872
- inputPlaneRegion: void 0
18872
+ inputPlaneRegion: void 0,
18873
+ maxObjectSizeBytes: void 0
18873
18874
  };
18874
18875
  }
18875
18876
  var FunctionHandleMetadata = {
@@ -18910,6 +18911,9 @@ var FunctionHandleMetadata = {
18910
18911
  if (message.inputPlaneRegion !== void 0) {
18911
18912
  writer.uint32(378).string(message.inputPlaneRegion);
18912
18913
  }
18914
+ if (message.maxObjectSizeBytes !== void 0) {
18915
+ writer.uint32(384).uint64(message.maxObjectSizeBytes);
18916
+ }
18913
18917
  return writer;
18914
18918
  },
18915
18919
  decode(input, length) {
@@ -19006,6 +19010,13 @@ var FunctionHandleMetadata = {
19006
19010
  message.inputPlaneRegion = reader.string();
19007
19011
  continue;
19008
19012
  }
19013
+ case 48: {
19014
+ if (tag !== 384) {
19015
+ break;
19016
+ }
19017
+ message.maxObjectSizeBytes = longToNumber(reader.uint64());
19018
+ continue;
19019
+ }
19009
19020
  }
19010
19021
  if ((tag & 7) === 4 || tag === 0) {
19011
19022
  break;
@@ -19033,7 +19044,8 @@ var FunctionHandleMetadata = {
19033
19044
  ) : {},
19034
19045
  functionSchema: isSet3(object.functionSchema) ? FunctionSchema.fromJSON(object.functionSchema) : void 0,
19035
19046
  inputPlaneUrl: isSet3(object.inputPlaneUrl) ? globalThis.String(object.inputPlaneUrl) : void 0,
19036
- inputPlaneRegion: isSet3(object.inputPlaneRegion) ? globalThis.String(object.inputPlaneRegion) : void 0
19047
+ inputPlaneRegion: isSet3(object.inputPlaneRegion) ? globalThis.String(object.inputPlaneRegion) : void 0,
19048
+ maxObjectSizeBytes: isSet3(object.maxObjectSizeBytes) ? globalThis.Number(object.maxObjectSizeBytes) : void 0
19037
19049
  };
19038
19050
  },
19039
19051
  toJSON(message) {
@@ -19080,6 +19092,9 @@ var FunctionHandleMetadata = {
19080
19092
  if (message.inputPlaneRegion !== void 0) {
19081
19093
  obj.inputPlaneRegion = message.inputPlaneRegion;
19082
19094
  }
19095
+ if (message.maxObjectSizeBytes !== void 0) {
19096
+ obj.maxObjectSizeBytes = Math.round(message.maxObjectSizeBytes);
19097
+ }
19083
19098
  return obj;
19084
19099
  },
19085
19100
  create(base) {
@@ -19104,6 +19119,7 @@ var FunctionHandleMetadata = {
19104
19119
  message.functionSchema = object.functionSchema !== void 0 && object.functionSchema !== null ? FunctionSchema.fromPartial(object.functionSchema) : void 0;
19105
19120
  message.inputPlaneUrl = object.inputPlaneUrl ?? void 0;
19106
19121
  message.inputPlaneRegion = object.inputPlaneRegion ?? void 0;
19122
+ message.maxObjectSizeBytes = object.maxObjectSizeBytes ?? void 0;
19107
19123
  return message;
19108
19124
  }
19109
19125
  };
@@ -38670,7 +38686,7 @@ function authMiddleware(profile) {
38670
38686
  options.metadata ??= new import_nice_grpc.Metadata();
38671
38687
  options.metadata.set(
38672
38688
  "x-modal-client-type",
38673
- String(7 /* CLIENT_TYPE_LIBMODAL */)
38689
+ String(8 /* CLIENT_TYPE_LIBMODAL_JS */)
38674
38690
  );
38675
38691
  options.metadata.set("x-modal-client-version", "1.0.0");
38676
38692
  options.metadata.set("x-modal-token-id", tokenId);
@@ -38894,6 +38910,9 @@ ${result.exception}`
38894
38910
  return new Image2(resp.imageId);
38895
38911
  }
38896
38912
 
38913
+ // src/sandbox.ts
38914
+ var import_nice_grpc2 = require("nice-grpc");
38915
+
38897
38916
  // src/errors.ts
38898
38917
  var FunctionTimeoutError = class extends Error {
38899
38918
  constructor(message) {
@@ -39191,7 +39210,7 @@ var Tunnel = class {
39191
39210
  return [this.unencryptedHost, this.unencryptedPort];
39192
39211
  }
39193
39212
  };
39194
- var Sandbox2 = class {
39213
+ var Sandbox2 = class _Sandbox {
39195
39214
  sandboxId;
39196
39215
  stdin;
39197
39216
  stdout;
@@ -39213,6 +39232,23 @@ var Sandbox2 = class {
39213
39232
  ).pipeThrough(new TextDecoderStream())
39214
39233
  );
39215
39234
  }
39235
+ /** Returns a running Sandbox object from an ID.
39236
+ *
39237
+ * @returns Sandbox with ID
39238
+ */
39239
+ static async fromId(sandboxId) {
39240
+ try {
39241
+ await client.sandboxWait({
39242
+ sandboxId,
39243
+ timeout: 0
39244
+ });
39245
+ } catch (err) {
39246
+ if (err instanceof import_nice_grpc2.ClientError && err.code === import_nice_grpc2.Status.NOT_FOUND)
39247
+ throw new NotFoundError(`Sandbox with id: '${sandboxId}' not found`);
39248
+ throw err;
39249
+ }
39250
+ return new _Sandbox(sandboxId);
39251
+ }
39216
39252
  /**
39217
39253
  * Open a file in the sandbox filesystem.
39218
39254
  * @param path - Path to the file to open
@@ -39233,11 +39269,13 @@ var Sandbox2 = class {
39233
39269
  }
39234
39270
  async exec(command, options) {
39235
39271
  const taskId = await this.#getTaskId();
39272
+ const secretIds = options?.secrets ? options.secrets.map((secret) => secret.secretId) : [];
39236
39273
  const resp = await client.containerExec({
39237
39274
  taskId,
39238
39275
  command,
39239
39276
  workdir: options?.workdir,
39240
- timeoutSecs: options?.timeout ? options.timeout / 1e3 : 0
39277
+ timeoutSecs: options?.timeout ? options.timeout / 1e3 : 0,
39278
+ secretIds
39241
39279
  });
39242
39280
  return new ContainerProcess(resp.execId, options);
39243
39281
  }
@@ -39271,7 +39309,7 @@ var Sandbox2 = class {
39271
39309
  timeout: 55
39272
39310
  });
39273
39311
  if (resp.result) {
39274
- return resp.result.exitcode;
39312
+ return _Sandbox.#getReturnCode(resp.result);
39275
39313
  }
39276
39314
  }
39277
39315
  }
@@ -39304,6 +39342,53 @@ var Sandbox2 = class {
39304
39342
  }
39305
39343
  return this.#tunnels;
39306
39344
  }
39345
+ /**
39346
+ * Snapshot the filesystem of the Sandbox.
39347
+ *
39348
+ * Returns an `Image` object which can be used to spawn a new Sandbox with the same filesystem.
39349
+ *
39350
+ * @param timeout - Timeout for the snapshot operation in milliseconds
39351
+ * @returns Promise that resolves to an Image
39352
+ */
39353
+ async snapshotFilesystem(timeout = 55e3) {
39354
+ const resp = await client.sandboxSnapshotFs({
39355
+ sandboxId: this.sandboxId,
39356
+ timeout: timeout / 1e3
39357
+ });
39358
+ if (resp.result?.status !== 1 /* GENERIC_STATUS_SUCCESS */) {
39359
+ throw new Error(
39360
+ `Sandbox snapshot failed: ${resp.result?.exception || "Unknown error"}`
39361
+ );
39362
+ }
39363
+ if (!resp.imageId) {
39364
+ throw new Error("Sandbox snapshot response missing image ID");
39365
+ }
39366
+ return new Image2(resp.imageId);
39367
+ }
39368
+ /**
39369
+ * Check if the Sandbox has finished running.
39370
+ *
39371
+ * Returns `null` if the Sandbox is still running, else returns the exit code.
39372
+ */
39373
+ async poll() {
39374
+ const resp = await client.sandboxWait({
39375
+ sandboxId: this.sandboxId,
39376
+ timeout: 0
39377
+ });
39378
+ return _Sandbox.#getReturnCode(resp.result);
39379
+ }
39380
+ static #getReturnCode(result) {
39381
+ if (result === void 0 || result.status === 0 /* GENERIC_STATUS_UNSPECIFIED */) {
39382
+ return null;
39383
+ }
39384
+ if (result.status === 4 /* GENERIC_STATUS_TIMEOUT */) {
39385
+ return 124;
39386
+ } else if (result.status === 3 /* GENERIC_STATUS_TERMINATED */) {
39387
+ return 137;
39388
+ } else {
39389
+ return result.exitcode;
39390
+ }
39391
+ }
39307
39392
  };
39308
39393
  var ContainerProcess = class {
39309
39394
  stdin;
@@ -39458,7 +39543,7 @@ function encodeIfString(chunk) {
39458
39543
  }
39459
39544
 
39460
39545
  // src/secret.ts
39461
- var import_nice_grpc2 = require("nice-grpc");
39546
+ var import_nice_grpc3 = require("nice-grpc");
39462
39547
  var Secret = class _Secret {
39463
39548
  secretId;
39464
39549
  /** @ignore */
@@ -39475,9 +39560,9 @@ var Secret = class _Secret {
39475
39560
  });
39476
39561
  return new _Secret(resp.secretId);
39477
39562
  } catch (err) {
39478
- if (err instanceof import_nice_grpc2.ClientError && err.code === import_nice_grpc2.Status.NOT_FOUND)
39563
+ if (err instanceof import_nice_grpc3.ClientError && err.code === import_nice_grpc3.Status.NOT_FOUND)
39479
39564
  throw new NotFoundError(err.details);
39480
- if (err instanceof import_nice_grpc2.ClientError && err.code === import_nice_grpc2.Status.FAILED_PRECONDITION && err.details.includes("Secret is missing key"))
39565
+ if (err instanceof import_nice_grpc3.ClientError && err.code === import_nice_grpc3.Status.FAILED_PRECONDITION && err.details.includes("Secret is missing key"))
39481
39566
  throw new NotFoundError(err.details);
39482
39567
  throw err;
39483
39568
  }
@@ -39501,7 +39586,7 @@ var App = class _App {
39501
39586
  });
39502
39587
  return new _App(resp.appId);
39503
39588
  } catch (err) {
39504
- if (err instanceof import_nice_grpc3.ClientError && err.code === import_nice_grpc3.Status.NOT_FOUND)
39589
+ if (err instanceof import_nice_grpc4.ClientError && err.code === import_nice_grpc4.Status.NOT_FOUND)
39505
39590
  throw new NotFoundError(`App '${name}' not found`);
39506
39591
  throw err;
39507
39592
  }
@@ -39544,6 +39629,7 @@ var App = class _App {
39544
39629
  }))
39545
39630
  );
39546
39631
  }
39632
+ const secretIds = options.secrets ? options.secrets.map((secret) => secret.secretId) : [];
39547
39633
  const createResp = await client.sandboxCreate({
39548
39634
  appId: this.appId,
39549
39635
  definition: {
@@ -39560,6 +39646,7 @@ var App = class _App {
39560
39646
  memoryMb: options.memory ?? 128
39561
39647
  },
39562
39648
  volumeMounts,
39649
+ secretIds,
39563
39650
  openPorts: openPorts.length > 0 ? { ports: openPorts } : void 0
39564
39651
  }
39565
39652
  });
@@ -39607,7 +39694,7 @@ var App = class _App {
39607
39694
  };
39608
39695
 
39609
39696
  // src/cls.ts
39610
- var import_nice_grpc5 = require("nice-grpc");
39697
+ var import_nice_grpc6 = require("nice-grpc");
39611
39698
 
39612
39699
  // src/function.ts
39613
39700
  var import_node_crypto = require("crypto");
@@ -40180,7 +40267,7 @@ var FunctionCall = class _FunctionCall {
40180
40267
  };
40181
40268
 
40182
40269
  // src/function.ts
40183
- var import_nice_grpc4 = require("nice-grpc");
40270
+ var import_nice_grpc5 = require("nice-grpc");
40184
40271
  var maxObjectSizeBytes = 2 * 1024 * 1024;
40185
40272
  var maxSystemRetries = 8;
40186
40273
  var Function_ = class _Function_ {
@@ -40206,7 +40293,7 @@ var Function_ = class _Function_ {
40206
40293
  resp.handleMetadata?.inputPlaneUrl
40207
40294
  );
40208
40295
  } catch (err) {
40209
- if (err instanceof import_nice_grpc4.ClientError && err.code === import_nice_grpc4.Status.NOT_FOUND)
40296
+ if (err instanceof import_nice_grpc5.ClientError && err.code === import_nice_grpc5.Status.NOT_FOUND)
40210
40297
  throw new NotFoundError(`Function '${appName}/${name}' not found`);
40211
40298
  throw err;
40212
40299
  }
@@ -40344,7 +40431,7 @@ var Cls = class _Cls {
40344
40431
  serviceFunction.handleMetadata?.inputPlaneUrl
40345
40432
  );
40346
40433
  } catch (err) {
40347
- if (err instanceof import_nice_grpc5.ClientError && err.code === import_nice_grpc5.Status.NOT_FOUND)
40434
+ if (err instanceof import_nice_grpc6.ClientError && err.code === import_nice_grpc6.Status.NOT_FOUND)
40348
40435
  throw new NotFoundError(`Class '${appName}/${name}' not found`);
40349
40436
  throw err;
40350
40437
  }
@@ -40443,7 +40530,7 @@ var ClsInstance = class {
40443
40530
  };
40444
40531
 
40445
40532
  // src/queue.ts
40446
- var import_nice_grpc6 = require("nice-grpc");
40533
+ var import_nice_grpc7 = require("nice-grpc");
40447
40534
  var ephemeralObjectHeartbeatSleep = 3e5;
40448
40535
  var queueInitialPutBackoff = 100;
40449
40536
  var queueDefaultPartitionTtl = 24 * 3600 * 1e3;
@@ -40597,7 +40684,7 @@ var Queue = class _Queue {
40597
40684
  });
40598
40685
  break;
40599
40686
  } catch (e) {
40600
- if (e instanceof import_nice_grpc6.ClientError && e.code === import_nice_grpc6.Status.RESOURCE_EXHAUSTED) {
40687
+ if (e instanceof import_nice_grpc7.ClientError && e.code === import_nice_grpc7.Status.RESOURCE_EXHAUSTED) {
40601
40688
  delay = Math.min(delay * 2, 3e4);
40602
40689
  if (deadline !== void 0) {
40603
40690
  const remaining = deadline - Date.now();
@@ -40689,7 +40776,7 @@ var Queue = class _Queue {
40689
40776
  };
40690
40777
 
40691
40778
  // src/volume.ts
40692
- var import_nice_grpc7 = require("nice-grpc");
40779
+ var import_nice_grpc8 = require("nice-grpc");
40693
40780
  var Volume = class _Volume {
40694
40781
  volumeId;
40695
40782
  /** @ignore */
@@ -40705,7 +40792,7 @@ var Volume = class _Volume {
40705
40792
  });
40706
40793
  return new _Volume(resp.volumeId);
40707
40794
  } catch (err) {
40708
- if (err instanceof import_nice_grpc7.ClientError && err.code === import_nice_grpc7.Status.NOT_FOUND)
40795
+ if (err instanceof import_nice_grpc8.ClientError && err.code === import_nice_grpc8.Status.NOT_FOUND)
40709
40796
  throw new NotFoundError(err.details);
40710
40797
  throw err;
40711
40798
  }
package/dist/index.d.cts CHANGED
@@ -124,6 +124,20 @@ interface ModalWriteStream<R = any> extends WritableStream<R> {
124
124
  writeBytes(bytes: Uint8Array): Promise<void>;
125
125
  }
126
126
 
127
+ /** Options for `Secret.fromName()`. */
128
+ type SecretFromNameOptions = {
129
+ environment?: string;
130
+ requiredKeys?: string[];
131
+ };
132
+ /** Secrets provide a dictionary of environment variables for images. */
133
+ declare class Secret {
134
+ readonly secretId: string;
135
+ /** @ignore */
136
+ constructor(secretId: string);
137
+ /** Reference a Secret by its name. */
138
+ static fromName(name: string, options?: SecretFromNameOptions): Promise<Secret>;
139
+ }
140
+
127
141
  /**
128
142
  * Stdin is always present, but this option allow you to drop stdout or stderr
129
143
  * if you don't need them. The default is "pipe", matching Node.js behavior.
@@ -149,6 +163,8 @@ type ExecOptions = {
149
163
  workdir?: string;
150
164
  /** Timeout for the process in milliseconds. Defaults to 0 (no timeout). */
151
165
  timeout?: number;
166
+ /** Secrets with environment variables for the command. */
167
+ secrets?: [Secret];
152
168
  };
153
169
  /** A port forwarded from within a running Modal sandbox. */
154
170
  declare class Tunnel {
@@ -174,6 +190,11 @@ declare class Sandbox {
174
190
  stderr: ModalReadStream<string>;
175
191
  /** @ignore */
176
192
  constructor(sandboxId: string);
193
+ /** Returns a running Sandbox object from an ID.
194
+ *
195
+ * @returns Sandbox with ID
196
+ */
197
+ static fromId(sandboxId: string): Promise<Sandbox>;
177
198
  /**
178
199
  * Open a file in the sandbox filesystem.
179
200
  * @param path - Path to the file to open
@@ -196,6 +217,21 @@ declare class Sandbox {
196
217
  * @returns A dictionary of Tunnel objects which are keyed by the container port.
197
218
  */
198
219
  tunnels(timeout?: number): Promise<Record<number, Tunnel>>;
220
+ /**
221
+ * Snapshot the filesystem of the Sandbox.
222
+ *
223
+ * Returns an `Image` object which can be used to spawn a new Sandbox with the same filesystem.
224
+ *
225
+ * @param timeout - Timeout for the snapshot operation in milliseconds
226
+ * @returns Promise that resolves to an Image
227
+ */
228
+ snapshotFilesystem(timeout?: number): Promise<Image>;
229
+ /**
230
+ * Check if the Sandbox has finished running.
231
+ *
232
+ * Returns `null` if the Sandbox is still running, else returns the exit code.
233
+ */
234
+ poll(): Promise<number | null>;
199
235
  }
200
236
  declare class ContainerProcess<R extends string | Uint8Array = any> {
201
237
  #private;
@@ -208,20 +244,6 @@ declare class ContainerProcess<R extends string | Uint8Array = any> {
208
244
  wait(): Promise<number>;
209
245
  }
210
246
 
211
- /** Options for `Secret.fromName()`. */
212
- type SecretFromNameOptions = {
213
- environment?: string;
214
- requiredKeys?: string[];
215
- };
216
- /** Secrets provide a dictionary of environment variables for images. */
217
- declare class Secret {
218
- readonly secretId: string;
219
- /** @ignore */
220
- constructor(secretId: string);
221
- /** Reference a Secret by its name. */
222
- static fromName(name: string, options?: SecretFromNameOptions): Promise<Secret>;
223
- }
224
-
225
247
  /** Options for `Volume.fromName()`. */
226
248
  type VolumeFromNameOptions = {
227
249
  environment?: string;
@@ -261,6 +283,8 @@ type SandboxCreateOptions = {
261
283
  * Default behavior is to sleep indefinitely until timeout or termination.
262
284
  */
263
285
  command?: string[];
286
+ /** Secrets to inject into the sandbox. */
287
+ secrets?: Secret[];
264
288
  /** Mount points for Modal Volumes. */
265
289
  volumes?: Record<string, Volume>;
266
290
  /** List of ports to tunnel into the sandbox. Encrypted ports are tunneled with TLS. */
package/dist/index.d.ts CHANGED
@@ -124,6 +124,20 @@ interface ModalWriteStream<R = any> extends WritableStream<R> {
124
124
  writeBytes(bytes: Uint8Array): Promise<void>;
125
125
  }
126
126
 
127
+ /** Options for `Secret.fromName()`. */
128
+ type SecretFromNameOptions = {
129
+ environment?: string;
130
+ requiredKeys?: string[];
131
+ };
132
+ /** Secrets provide a dictionary of environment variables for images. */
133
+ declare class Secret {
134
+ readonly secretId: string;
135
+ /** @ignore */
136
+ constructor(secretId: string);
137
+ /** Reference a Secret by its name. */
138
+ static fromName(name: string, options?: SecretFromNameOptions): Promise<Secret>;
139
+ }
140
+
127
141
  /**
128
142
  * Stdin is always present, but this option allow you to drop stdout or stderr
129
143
  * if you don't need them. The default is "pipe", matching Node.js behavior.
@@ -149,6 +163,8 @@ type ExecOptions = {
149
163
  workdir?: string;
150
164
  /** Timeout for the process in milliseconds. Defaults to 0 (no timeout). */
151
165
  timeout?: number;
166
+ /** Secrets with environment variables for the command. */
167
+ secrets?: [Secret];
152
168
  };
153
169
  /** A port forwarded from within a running Modal sandbox. */
154
170
  declare class Tunnel {
@@ -174,6 +190,11 @@ declare class Sandbox {
174
190
  stderr: ModalReadStream<string>;
175
191
  /** @ignore */
176
192
  constructor(sandboxId: string);
193
+ /** Returns a running Sandbox object from an ID.
194
+ *
195
+ * @returns Sandbox with ID
196
+ */
197
+ static fromId(sandboxId: string): Promise<Sandbox>;
177
198
  /**
178
199
  * Open a file in the sandbox filesystem.
179
200
  * @param path - Path to the file to open
@@ -196,6 +217,21 @@ declare class Sandbox {
196
217
  * @returns A dictionary of Tunnel objects which are keyed by the container port.
197
218
  */
198
219
  tunnels(timeout?: number): Promise<Record<number, Tunnel>>;
220
+ /**
221
+ * Snapshot the filesystem of the Sandbox.
222
+ *
223
+ * Returns an `Image` object which can be used to spawn a new Sandbox with the same filesystem.
224
+ *
225
+ * @param timeout - Timeout for the snapshot operation in milliseconds
226
+ * @returns Promise that resolves to an Image
227
+ */
228
+ snapshotFilesystem(timeout?: number): Promise<Image>;
229
+ /**
230
+ * Check if the Sandbox has finished running.
231
+ *
232
+ * Returns `null` if the Sandbox is still running, else returns the exit code.
233
+ */
234
+ poll(): Promise<number | null>;
199
235
  }
200
236
  declare class ContainerProcess<R extends string | Uint8Array = any> {
201
237
  #private;
@@ -208,20 +244,6 @@ declare class ContainerProcess<R extends string | Uint8Array = any> {
208
244
  wait(): Promise<number>;
209
245
  }
210
246
 
211
- /** Options for `Secret.fromName()`. */
212
- type SecretFromNameOptions = {
213
- environment?: string;
214
- requiredKeys?: string[];
215
- };
216
- /** Secrets provide a dictionary of environment variables for images. */
217
- declare class Secret {
218
- readonly secretId: string;
219
- /** @ignore */
220
- constructor(secretId: string);
221
- /** Reference a Secret by its name. */
222
- static fromName(name: string, options?: SecretFromNameOptions): Promise<Secret>;
223
- }
224
-
225
247
  /** Options for `Volume.fromName()`. */
226
248
  type VolumeFromNameOptions = {
227
249
  environment?: string;
@@ -261,6 +283,8 @@ type SandboxCreateOptions = {
261
283
  * Default behavior is to sleep indefinitely until timeout or termination.
262
284
  */
263
285
  command?: string[];
286
+ /** Secrets to inject into the sandbox. */
287
+ secrets?: Secret[];
264
288
  /** Mount points for Modal Volumes. */
265
289
  volumes?: Record<string, Volume>;
266
290
  /** List of ports to tunnel into the sandbox. Encrypted ports are tunneled with TLS. */
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/app.ts
2
- import { ClientError as ClientError3, Status as Status3 } from "nice-grpc";
2
+ import { ClientError as ClientError4, Status as Status4 } from "nice-grpc";
3
3
 
4
4
  // node_modules/@bufbuild/protobuf/dist/esm/wire/varint.js
5
5
  function varint64read() {
@@ -18813,7 +18813,8 @@ function createBaseFunctionHandleMetadata() {
18813
18813
  methodHandleMetadata: {},
18814
18814
  functionSchema: void 0,
18815
18815
  inputPlaneUrl: void 0,
18816
- inputPlaneRegion: void 0
18816
+ inputPlaneRegion: void 0,
18817
+ maxObjectSizeBytes: void 0
18817
18818
  };
18818
18819
  }
18819
18820
  var FunctionHandleMetadata = {
@@ -18854,6 +18855,9 @@ var FunctionHandleMetadata = {
18854
18855
  if (message.inputPlaneRegion !== void 0) {
18855
18856
  writer.uint32(378).string(message.inputPlaneRegion);
18856
18857
  }
18858
+ if (message.maxObjectSizeBytes !== void 0) {
18859
+ writer.uint32(384).uint64(message.maxObjectSizeBytes);
18860
+ }
18857
18861
  return writer;
18858
18862
  },
18859
18863
  decode(input, length) {
@@ -18950,6 +18954,13 @@ var FunctionHandleMetadata = {
18950
18954
  message.inputPlaneRegion = reader.string();
18951
18955
  continue;
18952
18956
  }
18957
+ case 48: {
18958
+ if (tag !== 384) {
18959
+ break;
18960
+ }
18961
+ message.maxObjectSizeBytes = longToNumber(reader.uint64());
18962
+ continue;
18963
+ }
18953
18964
  }
18954
18965
  if ((tag & 7) === 4 || tag === 0) {
18955
18966
  break;
@@ -18977,7 +18988,8 @@ var FunctionHandleMetadata = {
18977
18988
  ) : {},
18978
18989
  functionSchema: isSet3(object.functionSchema) ? FunctionSchema.fromJSON(object.functionSchema) : void 0,
18979
18990
  inputPlaneUrl: isSet3(object.inputPlaneUrl) ? globalThis.String(object.inputPlaneUrl) : void 0,
18980
- inputPlaneRegion: isSet3(object.inputPlaneRegion) ? globalThis.String(object.inputPlaneRegion) : void 0
18991
+ inputPlaneRegion: isSet3(object.inputPlaneRegion) ? globalThis.String(object.inputPlaneRegion) : void 0,
18992
+ maxObjectSizeBytes: isSet3(object.maxObjectSizeBytes) ? globalThis.Number(object.maxObjectSizeBytes) : void 0
18981
18993
  };
18982
18994
  },
18983
18995
  toJSON(message) {
@@ -19024,6 +19036,9 @@ var FunctionHandleMetadata = {
19024
19036
  if (message.inputPlaneRegion !== void 0) {
19025
19037
  obj.inputPlaneRegion = message.inputPlaneRegion;
19026
19038
  }
19039
+ if (message.maxObjectSizeBytes !== void 0) {
19040
+ obj.maxObjectSizeBytes = Math.round(message.maxObjectSizeBytes);
19041
+ }
19027
19042
  return obj;
19028
19043
  },
19029
19044
  create(base) {
@@ -19048,6 +19063,7 @@ var FunctionHandleMetadata = {
19048
19063
  message.functionSchema = object.functionSchema !== void 0 && object.functionSchema !== null ? FunctionSchema.fromPartial(object.functionSchema) : void 0;
19049
19064
  message.inputPlaneUrl = object.inputPlaneUrl ?? void 0;
19050
19065
  message.inputPlaneRegion = object.inputPlaneRegion ?? void 0;
19066
+ message.maxObjectSizeBytes = object.maxObjectSizeBytes ?? void 0;
19051
19067
  return message;
19052
19068
  }
19053
19069
  };
@@ -38620,7 +38636,7 @@ function authMiddleware(profile) {
38620
38636
  options.metadata ??= new Metadata();
38621
38637
  options.metadata.set(
38622
38638
  "x-modal-client-type",
38623
- String(7 /* CLIENT_TYPE_LIBMODAL */)
38639
+ String(8 /* CLIENT_TYPE_LIBMODAL_JS */)
38624
38640
  );
38625
38641
  options.metadata.set("x-modal-client-version", "1.0.0");
38626
38642
  options.metadata.set("x-modal-token-id", tokenId);
@@ -38844,6 +38860,9 @@ ${result.exception}`
38844
38860
  return new Image2(resp.imageId);
38845
38861
  }
38846
38862
 
38863
+ // src/sandbox.ts
38864
+ import { ClientError as ClientError2, Status as Status2 } from "nice-grpc";
38865
+
38847
38866
  // src/errors.ts
38848
38867
  var FunctionTimeoutError = class extends Error {
38849
38868
  constructor(message) {
@@ -39141,7 +39160,7 @@ var Tunnel = class {
39141
39160
  return [this.unencryptedHost, this.unencryptedPort];
39142
39161
  }
39143
39162
  };
39144
- var Sandbox2 = class {
39163
+ var Sandbox2 = class _Sandbox {
39145
39164
  sandboxId;
39146
39165
  stdin;
39147
39166
  stdout;
@@ -39163,6 +39182,23 @@ var Sandbox2 = class {
39163
39182
  ).pipeThrough(new TextDecoderStream())
39164
39183
  );
39165
39184
  }
39185
+ /** Returns a running Sandbox object from an ID.
39186
+ *
39187
+ * @returns Sandbox with ID
39188
+ */
39189
+ static async fromId(sandboxId) {
39190
+ try {
39191
+ await client.sandboxWait({
39192
+ sandboxId,
39193
+ timeout: 0
39194
+ });
39195
+ } catch (err) {
39196
+ if (err instanceof ClientError2 && err.code === Status2.NOT_FOUND)
39197
+ throw new NotFoundError(`Sandbox with id: '${sandboxId}' not found`);
39198
+ throw err;
39199
+ }
39200
+ return new _Sandbox(sandboxId);
39201
+ }
39166
39202
  /**
39167
39203
  * Open a file in the sandbox filesystem.
39168
39204
  * @param path - Path to the file to open
@@ -39183,11 +39219,13 @@ var Sandbox2 = class {
39183
39219
  }
39184
39220
  async exec(command, options) {
39185
39221
  const taskId = await this.#getTaskId();
39222
+ const secretIds = options?.secrets ? options.secrets.map((secret) => secret.secretId) : [];
39186
39223
  const resp = await client.containerExec({
39187
39224
  taskId,
39188
39225
  command,
39189
39226
  workdir: options?.workdir,
39190
- timeoutSecs: options?.timeout ? options.timeout / 1e3 : 0
39227
+ timeoutSecs: options?.timeout ? options.timeout / 1e3 : 0,
39228
+ secretIds
39191
39229
  });
39192
39230
  return new ContainerProcess(resp.execId, options);
39193
39231
  }
@@ -39221,7 +39259,7 @@ var Sandbox2 = class {
39221
39259
  timeout: 55
39222
39260
  });
39223
39261
  if (resp.result) {
39224
- return resp.result.exitcode;
39262
+ return _Sandbox.#getReturnCode(resp.result);
39225
39263
  }
39226
39264
  }
39227
39265
  }
@@ -39254,6 +39292,53 @@ var Sandbox2 = class {
39254
39292
  }
39255
39293
  return this.#tunnels;
39256
39294
  }
39295
+ /**
39296
+ * Snapshot the filesystem of the Sandbox.
39297
+ *
39298
+ * Returns an `Image` object which can be used to spawn a new Sandbox with the same filesystem.
39299
+ *
39300
+ * @param timeout - Timeout for the snapshot operation in milliseconds
39301
+ * @returns Promise that resolves to an Image
39302
+ */
39303
+ async snapshotFilesystem(timeout = 55e3) {
39304
+ const resp = await client.sandboxSnapshotFs({
39305
+ sandboxId: this.sandboxId,
39306
+ timeout: timeout / 1e3
39307
+ });
39308
+ if (resp.result?.status !== 1 /* GENERIC_STATUS_SUCCESS */) {
39309
+ throw new Error(
39310
+ `Sandbox snapshot failed: ${resp.result?.exception || "Unknown error"}`
39311
+ );
39312
+ }
39313
+ if (!resp.imageId) {
39314
+ throw new Error("Sandbox snapshot response missing image ID");
39315
+ }
39316
+ return new Image2(resp.imageId);
39317
+ }
39318
+ /**
39319
+ * Check if the Sandbox has finished running.
39320
+ *
39321
+ * Returns `null` if the Sandbox is still running, else returns the exit code.
39322
+ */
39323
+ async poll() {
39324
+ const resp = await client.sandboxWait({
39325
+ sandboxId: this.sandboxId,
39326
+ timeout: 0
39327
+ });
39328
+ return _Sandbox.#getReturnCode(resp.result);
39329
+ }
39330
+ static #getReturnCode(result) {
39331
+ if (result === void 0 || result.status === 0 /* GENERIC_STATUS_UNSPECIFIED */) {
39332
+ return null;
39333
+ }
39334
+ if (result.status === 4 /* GENERIC_STATUS_TIMEOUT */) {
39335
+ return 124;
39336
+ } else if (result.status === 3 /* GENERIC_STATUS_TERMINATED */) {
39337
+ return 137;
39338
+ } else {
39339
+ return result.exitcode;
39340
+ }
39341
+ }
39257
39342
  };
39258
39343
  var ContainerProcess = class {
39259
39344
  stdin;
@@ -39408,7 +39493,7 @@ function encodeIfString(chunk) {
39408
39493
  }
39409
39494
 
39410
39495
  // src/secret.ts
39411
- import { ClientError as ClientError2, Status as Status2 } from "nice-grpc";
39496
+ import { ClientError as ClientError3, Status as Status3 } from "nice-grpc";
39412
39497
  var Secret = class _Secret {
39413
39498
  secretId;
39414
39499
  /** @ignore */
@@ -39425,9 +39510,9 @@ var Secret = class _Secret {
39425
39510
  });
39426
39511
  return new _Secret(resp.secretId);
39427
39512
  } catch (err) {
39428
- if (err instanceof ClientError2 && err.code === Status2.NOT_FOUND)
39513
+ if (err instanceof ClientError3 && err.code === Status3.NOT_FOUND)
39429
39514
  throw new NotFoundError(err.details);
39430
- if (err instanceof ClientError2 && err.code === Status2.FAILED_PRECONDITION && err.details.includes("Secret is missing key"))
39515
+ if (err instanceof ClientError3 && err.code === Status3.FAILED_PRECONDITION && err.details.includes("Secret is missing key"))
39431
39516
  throw new NotFoundError(err.details);
39432
39517
  throw err;
39433
39518
  }
@@ -39451,7 +39536,7 @@ var App = class _App {
39451
39536
  });
39452
39537
  return new _App(resp.appId);
39453
39538
  } catch (err) {
39454
- if (err instanceof ClientError3 && err.code === Status3.NOT_FOUND)
39539
+ if (err instanceof ClientError4 && err.code === Status4.NOT_FOUND)
39455
39540
  throw new NotFoundError(`App '${name}' not found`);
39456
39541
  throw err;
39457
39542
  }
@@ -39494,6 +39579,7 @@ var App = class _App {
39494
39579
  }))
39495
39580
  );
39496
39581
  }
39582
+ const secretIds = options.secrets ? options.secrets.map((secret) => secret.secretId) : [];
39497
39583
  const createResp = await client.sandboxCreate({
39498
39584
  appId: this.appId,
39499
39585
  definition: {
@@ -39510,6 +39596,7 @@ var App = class _App {
39510
39596
  memoryMb: options.memory ?? 128
39511
39597
  },
39512
39598
  volumeMounts,
39599
+ secretIds,
39513
39600
  openPorts: openPorts.length > 0 ? { ports: openPorts } : void 0
39514
39601
  }
39515
39602
  });
@@ -39557,7 +39644,7 @@ var App = class _App {
39557
39644
  };
39558
39645
 
39559
39646
  // src/cls.ts
39560
- import { ClientError as ClientError5, Status as Status5 } from "nice-grpc";
39647
+ import { ClientError as ClientError6, Status as Status6 } from "nice-grpc";
39561
39648
 
39562
39649
  // src/function.ts
39563
39650
  import { createHash } from "node:crypto";
@@ -40130,7 +40217,7 @@ var FunctionCall = class _FunctionCall {
40130
40217
  };
40131
40218
 
40132
40219
  // src/function.ts
40133
- import { ClientError as ClientError4, Status as Status4 } from "nice-grpc";
40220
+ import { ClientError as ClientError5, Status as Status5 } from "nice-grpc";
40134
40221
  var maxObjectSizeBytes = 2 * 1024 * 1024;
40135
40222
  var maxSystemRetries = 8;
40136
40223
  var Function_ = class _Function_ {
@@ -40156,7 +40243,7 @@ var Function_ = class _Function_ {
40156
40243
  resp.handleMetadata?.inputPlaneUrl
40157
40244
  );
40158
40245
  } catch (err) {
40159
- if (err instanceof ClientError4 && err.code === Status4.NOT_FOUND)
40246
+ if (err instanceof ClientError5 && err.code === Status5.NOT_FOUND)
40160
40247
  throw new NotFoundError(`Function '${appName}/${name}' not found`);
40161
40248
  throw err;
40162
40249
  }
@@ -40294,7 +40381,7 @@ var Cls = class _Cls {
40294
40381
  serviceFunction.handleMetadata?.inputPlaneUrl
40295
40382
  );
40296
40383
  } catch (err) {
40297
- if (err instanceof ClientError5 && err.code === Status5.NOT_FOUND)
40384
+ if (err instanceof ClientError6 && err.code === Status6.NOT_FOUND)
40298
40385
  throw new NotFoundError(`Class '${appName}/${name}' not found`);
40299
40386
  throw err;
40300
40387
  }
@@ -40393,7 +40480,7 @@ var ClsInstance = class {
40393
40480
  };
40394
40481
 
40395
40482
  // src/queue.ts
40396
- import { ClientError as ClientError6, Status as Status6 } from "nice-grpc";
40483
+ import { ClientError as ClientError7, Status as Status7 } from "nice-grpc";
40397
40484
  var ephemeralObjectHeartbeatSleep = 3e5;
40398
40485
  var queueInitialPutBackoff = 100;
40399
40486
  var queueDefaultPartitionTtl = 24 * 3600 * 1e3;
@@ -40547,7 +40634,7 @@ var Queue = class _Queue {
40547
40634
  });
40548
40635
  break;
40549
40636
  } catch (e) {
40550
- if (e instanceof ClientError6 && e.code === Status6.RESOURCE_EXHAUSTED) {
40637
+ if (e instanceof ClientError7 && e.code === Status7.RESOURCE_EXHAUSTED) {
40551
40638
  delay = Math.min(delay * 2, 3e4);
40552
40639
  if (deadline !== void 0) {
40553
40640
  const remaining = deadline - Date.now();
@@ -40639,7 +40726,7 @@ var Queue = class _Queue {
40639
40726
  };
40640
40727
 
40641
40728
  // src/volume.ts
40642
- import { ClientError as ClientError7, Status as Status7 } from "nice-grpc";
40729
+ import { ClientError as ClientError8, Status as Status8 } from "nice-grpc";
40643
40730
  var Volume = class _Volume {
40644
40731
  volumeId;
40645
40732
  /** @ignore */
@@ -40655,7 +40742,7 @@ var Volume = class _Volume {
40655
40742
  });
40656
40743
  return new _Volume(resp.volumeId);
40657
40744
  } catch (err) {
40658
- if (err instanceof ClientError7 && err.code === Status7.NOT_FOUND)
40745
+ if (err instanceof ClientError8 && err.code === Status8.NOT_FOUND)
40659
40746
  throw new NotFoundError(err.details);
40660
40747
  throw err;
40661
40748
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "modal",
3
- "version": "0.3.14",
3
+ "version": "0.3.16",
4
4
  "description": "Modal client library for JavaScript",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://modal.com/docs",