modal 0.3.15 → 0.3.17

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.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() {
@@ -38797,68 +38797,8 @@ function initializeClient(options) {
38797
38797
  client = createClient(mergedProfile);
38798
38798
  }
38799
38799
 
38800
- // src/image.ts
38801
- var Image2 = class {
38802
- imageId;
38803
- /** @ignore */
38804
- constructor(imageId) {
38805
- this.imageId = imageId;
38806
- }
38807
- };
38808
- async function fromRegistryInternal(appId, tag, imageRegistryConfig) {
38809
- const resp = await client.imageGetOrCreate({
38810
- appId,
38811
- image: {
38812
- dockerfileCommands: [`FROM ${tag}`],
38813
- imageRegistryConfig
38814
- },
38815
- builderVersion: imageBuilderVersion()
38816
- });
38817
- let result;
38818
- let metadata = void 0;
38819
- if (resp.result?.status) {
38820
- result = resp.result;
38821
- metadata = resp.metadata;
38822
- } else {
38823
- let lastEntryId = "";
38824
- let resultJoined = void 0;
38825
- while (!resultJoined) {
38826
- for await (const item of client.imageJoinStreaming({
38827
- imageId: resp.imageId,
38828
- timeout: 55,
38829
- lastEntryId
38830
- })) {
38831
- if (item.entryId) lastEntryId = item.entryId;
38832
- if (item.result?.status) {
38833
- resultJoined = item.result;
38834
- metadata = item.metadata;
38835
- break;
38836
- }
38837
- }
38838
- }
38839
- result = resultJoined;
38840
- }
38841
- void metadata;
38842
- if (result.status === 2 /* GENERIC_STATUS_FAILURE */) {
38843
- throw new Error(
38844
- `Image build for ${resp.imageId} failed with the exception:
38845
- ${result.exception}`
38846
- );
38847
- } else if (result.status === 3 /* GENERIC_STATUS_TERMINATED */) {
38848
- throw new Error(
38849
- `Image build for ${resp.imageId} terminated due to external shut-down. Please try again.`
38850
- );
38851
- } else if (result.status === 4 /* GENERIC_STATUS_TIMEOUT */) {
38852
- throw new Error(
38853
- `Image build for ${resp.imageId} timed out. Please try again with a larger timeout parameter.`
38854
- );
38855
- } else if (result.status !== 1 /* GENERIC_STATUS_SUCCESS */) {
38856
- throw new Error(
38857
- `Image build for ${resp.imageId} failed with unknown status: ${result.status}`
38858
- );
38859
- }
38860
- return new Image2(resp.imageId);
38861
- }
38800
+ // src/secret.ts
38801
+ import { ClientError as ClientError2, Status as Status2 } from "nice-grpc";
38862
38802
 
38863
38803
  // src/errors.ts
38864
38804
  var FunctionTimeoutError = class extends Error {
@@ -38916,6 +38856,200 @@ var SandboxTimeoutError = class extends Error {
38916
38856
  }
38917
38857
  };
38918
38858
 
38859
+ // src/secret.ts
38860
+ var Secret = class _Secret {
38861
+ secretId;
38862
+ name;
38863
+ /** @ignore */
38864
+ constructor(secretId, name) {
38865
+ this.secretId = secretId;
38866
+ this.name = name;
38867
+ }
38868
+ /** Reference a Secret by its name. */
38869
+ static async fromName(name, options) {
38870
+ try {
38871
+ const resp = await client.secretGetOrCreate({
38872
+ deploymentName: name,
38873
+ environmentName: environmentName(options?.environment),
38874
+ requiredKeys: options?.requiredKeys ?? []
38875
+ });
38876
+ return new _Secret(resp.secretId, name);
38877
+ } catch (err) {
38878
+ if (err instanceof ClientError2 && err.code === Status2.NOT_FOUND)
38879
+ throw new NotFoundError(err.details);
38880
+ if (err instanceof ClientError2 && err.code === Status2.FAILED_PRECONDITION && err.details.includes("Secret is missing key"))
38881
+ throw new NotFoundError(err.details);
38882
+ throw err;
38883
+ }
38884
+ }
38885
+ /** Create a Secret from a plain object of key-value pairs. */
38886
+ static async fromObject(entries, options) {
38887
+ for (const [, value] of Object.entries(entries)) {
38888
+ if (value == null || typeof value !== "string") {
38889
+ throw new InvalidError(
38890
+ "entries must be an object mapping string keys to string values, but got:\n" + JSON.stringify(entries)
38891
+ );
38892
+ }
38893
+ }
38894
+ try {
38895
+ const resp = await client.secretGetOrCreate({
38896
+ objectCreationType: 5 /* OBJECT_CREATION_TYPE_EPHEMERAL */,
38897
+ envDict: entries,
38898
+ environmentName: environmentName(options?.environment)
38899
+ });
38900
+ return new _Secret(resp.secretId);
38901
+ } catch (err) {
38902
+ if (err instanceof ClientError2 && (err.code === Status2.INVALID_ARGUMENT || err.code === Status2.FAILED_PRECONDITION))
38903
+ throw new InvalidError(err.details);
38904
+ throw err;
38905
+ }
38906
+ }
38907
+ };
38908
+
38909
+ // src/image.ts
38910
+ var Image2 = class _Image {
38911
+ #imageId;
38912
+ #tag;
38913
+ #imageRegistryConfig;
38914
+ /** @ignore */
38915
+ constructor(imageId, tag, imageRegistryConfig) {
38916
+ this.#imageId = imageId;
38917
+ this.#tag = tag;
38918
+ this.#imageRegistryConfig = imageRegistryConfig;
38919
+ }
38920
+ get imageId() {
38921
+ return this.#imageId;
38922
+ }
38923
+ /**
38924
+ * Creates an `Image` instance from a raw registry tag, optionally using a secret for authentication.
38925
+ *
38926
+ * @param tag - The registry tag for the image.
38927
+ * @param secret - Optional. A `Secret` instance containing credentials for registry authentication.
38928
+ */
38929
+ static fromRegistry(tag, secret) {
38930
+ let imageRegistryConfig;
38931
+ if (secret) {
38932
+ if (!(secret instanceof Secret)) {
38933
+ throw new TypeError(
38934
+ "secret must be a reference to an existing Secret, e.g. `await Secret.fromName('my_secret')`"
38935
+ );
38936
+ }
38937
+ imageRegistryConfig = {
38938
+ registryAuthType: 4 /* REGISTRY_AUTH_TYPE_STATIC_CREDS */,
38939
+ secretId: secret.secretId
38940
+ };
38941
+ }
38942
+ return new _Image("", tag, imageRegistryConfig);
38943
+ }
38944
+ /**
38945
+ * Creates an `Image` instance from a raw registry tag, optionally using a secret for authentication.
38946
+ *
38947
+ * @param tag - The registry tag for the image.
38948
+ * @param secret - A `Secret` instance containing credentials for registry authentication.
38949
+ */
38950
+ static fromAwsEcr(tag, secret) {
38951
+ let imageRegistryConfig;
38952
+ if (secret) {
38953
+ if (!(secret instanceof Secret)) {
38954
+ throw new TypeError(
38955
+ "secret must be a reference to an existing Secret, e.g. `await Secret.fromName('my_secret')`"
38956
+ );
38957
+ }
38958
+ imageRegistryConfig = {
38959
+ registryAuthType: 1 /* REGISTRY_AUTH_TYPE_AWS */,
38960
+ secretId: secret.secretId
38961
+ };
38962
+ }
38963
+ return new _Image("", tag, imageRegistryConfig);
38964
+ }
38965
+ /**
38966
+ * Creates an `Image` instance from a raw registry tag, optionally using a secret for authentication.
38967
+ *
38968
+ * @param tag - The registry tag for the image.
38969
+ * @param secret - A `Secret` instance containing credentials for registry authentication.
38970
+ */
38971
+ static fromGcpArtifactRegistry(tag, secret) {
38972
+ let imageRegistryConfig;
38973
+ if (secret) {
38974
+ if (!(secret instanceof Secret)) {
38975
+ throw new TypeError(
38976
+ "secret must be a reference to an existing Secret, e.g. `await Secret.fromName('my_secret')`"
38977
+ );
38978
+ }
38979
+ imageRegistryConfig = {
38980
+ registryAuthType: 2 /* REGISTRY_AUTH_TYPE_GCP */,
38981
+ secretId: secret.secretId
38982
+ };
38983
+ }
38984
+ return new _Image("", tag, imageRegistryConfig);
38985
+ }
38986
+ /**
38987
+ * @internal
38988
+ * Build image object
38989
+ */
38990
+ async _build(appId) {
38991
+ if (this.imageId !== "") {
38992
+ return this;
38993
+ }
38994
+ const resp = await client.imageGetOrCreate({
38995
+ appId,
38996
+ image: {
38997
+ dockerfileCommands: [`FROM ${this.#tag}`],
38998
+ imageRegistryConfig: this.#imageRegistryConfig
38999
+ },
39000
+ builderVersion: imageBuilderVersion()
39001
+ });
39002
+ let result;
39003
+ let metadata = void 0;
39004
+ if (resp.result?.status) {
39005
+ result = resp.result;
39006
+ metadata = resp.metadata;
39007
+ } else {
39008
+ let lastEntryId = "";
39009
+ let resultJoined = void 0;
39010
+ while (!resultJoined) {
39011
+ for await (const item of client.imageJoinStreaming({
39012
+ imageId: resp.imageId,
39013
+ timeout: 55,
39014
+ lastEntryId
39015
+ })) {
39016
+ if (item.entryId) lastEntryId = item.entryId;
39017
+ if (item.result?.status) {
39018
+ resultJoined = item.result;
39019
+ metadata = item.metadata;
39020
+ break;
39021
+ }
39022
+ }
39023
+ }
39024
+ result = resultJoined;
39025
+ }
39026
+ void metadata;
39027
+ if (result.status === 2 /* GENERIC_STATUS_FAILURE */) {
39028
+ throw new Error(
39029
+ `Image build for ${resp.imageId} failed with the exception:
39030
+ ${result.exception}`
39031
+ );
39032
+ } else if (result.status === 3 /* GENERIC_STATUS_TERMINATED */) {
39033
+ throw new Error(
39034
+ `Image build for ${resp.imageId} terminated due to external shut-down. Please try again.`
39035
+ );
39036
+ } else if (result.status === 4 /* GENERIC_STATUS_TIMEOUT */) {
39037
+ throw new Error(
39038
+ `Image build for ${resp.imageId} timed out. Please try again with a larger timeout parameter.`
39039
+ );
39040
+ } else if (result.status !== 1 /* GENERIC_STATUS_SUCCESS */) {
39041
+ throw new Error(
39042
+ `Image build for ${resp.imageId} failed with unknown status: ${result.status}`
39043
+ );
39044
+ }
39045
+ this.#imageId = resp.imageId;
39046
+ return this;
39047
+ }
39048
+ };
39049
+
39050
+ // src/sandbox.ts
39051
+ import { ClientError as ClientError3, Status as Status3 } from "nice-grpc";
39052
+
38919
39053
  // src/sandbox_filesystem.ts
38920
39054
  var SandboxFile = class {
38921
39055
  #fileDescriptor;
@@ -39179,6 +39313,42 @@ var Sandbox2 = class _Sandbox {
39179
39313
  ).pipeThrough(new TextDecoderStream())
39180
39314
  );
39181
39315
  }
39316
+ /** Set tags (key-value pairs) on the Sandbox. Tags can be used to filter results in `Sandbox.list`. */
39317
+ async setTags(tags) {
39318
+ const tagsList = Object.entries(tags).map(([tagName, tagValue]) => ({
39319
+ tagName,
39320
+ tagValue
39321
+ }));
39322
+ try {
39323
+ await client.sandboxTagsSet({
39324
+ environmentName: environmentName(),
39325
+ sandboxId: this.sandboxId,
39326
+ tags: tagsList
39327
+ });
39328
+ } catch (err) {
39329
+ if (err instanceof ClientError3 && err.code === Status3.INVALID_ARGUMENT) {
39330
+ throw new InvalidError(err.details || err.message);
39331
+ }
39332
+ throw err;
39333
+ }
39334
+ }
39335
+ /** Returns a running Sandbox object from an ID.
39336
+ *
39337
+ * @returns Sandbox with ID
39338
+ */
39339
+ static async fromId(sandboxId) {
39340
+ try {
39341
+ await client.sandboxWait({
39342
+ sandboxId,
39343
+ timeout: 0
39344
+ });
39345
+ } catch (err) {
39346
+ if (err instanceof ClientError3 && err.code === Status3.NOT_FOUND)
39347
+ throw new NotFoundError(`Sandbox with id: '${sandboxId}' not found`);
39348
+ throw err;
39349
+ }
39350
+ return new _Sandbox(sandboxId);
39351
+ }
39182
39352
  /**
39183
39353
  * Open a file in the sandbox filesystem.
39184
39354
  * @param path - Path to the file to open
@@ -39236,7 +39406,7 @@ var Sandbox2 = class _Sandbox {
39236
39406
  while (true) {
39237
39407
  const resp = await client.sandboxWait({
39238
39408
  sandboxId: this.sandboxId,
39239
- timeout: 55
39409
+ timeout: 10
39240
39410
  });
39241
39411
  if (resp.result) {
39242
39412
  return _Sandbox.#getReturnCode(resp.result);
@@ -39293,7 +39463,7 @@ var Sandbox2 = class _Sandbox {
39293
39463
  if (!resp.imageId) {
39294
39464
  throw new Error("Sandbox snapshot response missing image ID");
39295
39465
  }
39296
- return new Image2(resp.imageId);
39466
+ return new Image2(resp.imageId, "");
39297
39467
  }
39298
39468
  /**
39299
39469
  * Check if the Sandbox has finished running.
@@ -39307,6 +39477,41 @@ var Sandbox2 = class _Sandbox {
39307
39477
  });
39308
39478
  return _Sandbox.#getReturnCode(resp.result);
39309
39479
  }
39480
+ /**
39481
+ * List all Sandboxes for the current Environment or App ID (if specified).
39482
+ * If tags are specified, only Sandboxes that have at least those tags are returned.
39483
+ */
39484
+ static async *list(options = {}) {
39485
+ const env = environmentName(options.environment);
39486
+ const tagsList = options.tags ? Object.entries(options.tags).map(([tagName, tagValue]) => ({
39487
+ tagName,
39488
+ tagValue
39489
+ })) : [];
39490
+ let beforeTimestamp = void 0;
39491
+ while (true) {
39492
+ try {
39493
+ const resp = await client.sandboxList({
39494
+ appId: options.appId,
39495
+ beforeTimestamp,
39496
+ environmentName: env,
39497
+ includeFinished: false,
39498
+ tags: tagsList
39499
+ });
39500
+ if (!resp.sandboxes || resp.sandboxes.length === 0) {
39501
+ return;
39502
+ }
39503
+ for (const info of resp.sandboxes) {
39504
+ yield new _Sandbox(info.id);
39505
+ }
39506
+ beforeTimestamp = resp.sandboxes[resp.sandboxes.length - 1].createdAt;
39507
+ } catch (err) {
39508
+ if (err instanceof ClientError3 && err.code === Status3.INVALID_ARGUMENT) {
39509
+ throw new InvalidError(err.details || err.message);
39510
+ }
39511
+ throw err;
39512
+ }
39513
+ }
39514
+ }
39310
39515
  static #getReturnCode(result) {
39311
39516
  if (result === void 0 || result.status === 0 /* GENERIC_STATUS_UNSPECIFIED */) {
39312
39517
  return null;
@@ -39472,39 +39677,99 @@ function encodeIfString(chunk) {
39472
39677
  return typeof chunk === "string" ? new TextEncoder().encode(chunk) : chunk;
39473
39678
  }
39474
39679
 
39475
- // src/secret.ts
39476
- import { ClientError as ClientError2, Status as Status2 } from "nice-grpc";
39477
- var Secret = class _Secret {
39478
- secretId;
39479
- /** @ignore */
39480
- constructor(secretId) {
39481
- this.secretId = secretId;
39482
- }
39483
- /** Reference a Secret by its name. */
39484
- static async fromName(name, options) {
39485
- try {
39486
- const resp = await client.secretGetOrCreate({
39487
- deploymentName: name,
39488
- environmentName: environmentName(options?.environment),
39489
- requiredKeys: options?.requiredKeys ?? []
39490
- });
39491
- return new _Secret(resp.secretId);
39492
- } catch (err) {
39493
- if (err instanceof ClientError2 && err.code === Status2.NOT_FOUND)
39494
- throw new NotFoundError(err.details);
39495
- if (err instanceof ClientError2 && err.code === Status2.FAILED_PRECONDITION && err.details.includes("Secret is missing key"))
39496
- throw new NotFoundError(err.details);
39497
- throw err;
39680
+ // src/cloud_bucket_mount.ts
39681
+ var CloudBucketMount2 = class {
39682
+ bucketName;
39683
+ secret;
39684
+ readOnly;
39685
+ requesterPays;
39686
+ bucketEndpointUrl;
39687
+ keyPrefix;
39688
+ oidcAuthRoleArn;
39689
+ constructor(bucketName, options = {}) {
39690
+ this.bucketName = bucketName;
39691
+ this.secret = options.secret;
39692
+ this.readOnly = options.readOnly ?? false;
39693
+ this.requesterPays = options.requesterPays ?? false;
39694
+ this.bucketEndpointUrl = options.bucketEndpointUrl;
39695
+ this.keyPrefix = options.keyPrefix;
39696
+ this.oidcAuthRoleArn = options.oidcAuthRoleArn;
39697
+ if (this.bucketEndpointUrl) {
39698
+ const url = new URL(this.bucketEndpointUrl);
39699
+ if (!url.hostname.endsWith("r2.cloudflarestorage.com") && !url.hostname.endsWith("storage.googleapis.com")) {
39700
+ console.warn(
39701
+ "CloudBucketMount received unrecognized bucket endpoint URL. Assuming AWS S3 configuration as fallback."
39702
+ );
39703
+ }
39704
+ }
39705
+ if (this.requesterPays && !this.secret) {
39706
+ throw new Error("Credentials required in order to use Requester Pays.");
39707
+ }
39708
+ if (this.keyPrefix && !this.keyPrefix.endsWith("/")) {
39709
+ throw new Error(
39710
+ "keyPrefix will be prefixed to all object paths, so it must end in a '/'"
39711
+ );
39498
39712
  }
39499
39713
  }
39500
39714
  };
39715
+ function endpointUrlToBucketType(bucketEndpointUrl) {
39716
+ if (!bucketEndpointUrl) {
39717
+ return 1 /* S3 */;
39718
+ }
39719
+ const url = new URL(bucketEndpointUrl);
39720
+ if (url.hostname.endsWith("r2.cloudflarestorage.com")) {
39721
+ return 2 /* R2 */;
39722
+ } else if (url.hostname.endsWith("storage.googleapis.com")) {
39723
+ return 3 /* GCP */;
39724
+ } else {
39725
+ return 1 /* S3 */;
39726
+ }
39727
+ }
39728
+ function cloudBucketMountToProto(mount, mountPath) {
39729
+ return {
39730
+ bucketName: mount.bucketName,
39731
+ mountPath,
39732
+ credentialsSecretId: mount.secret?.secretId ?? "",
39733
+ readOnly: mount.readOnly,
39734
+ bucketType: endpointUrlToBucketType(mount.bucketEndpointUrl),
39735
+ requesterPays: mount.requesterPays,
39736
+ bucketEndpointUrl: mount.bucketEndpointUrl,
39737
+ keyPrefix: mount.keyPrefix,
39738
+ oidcAuthRoleArn: mount.oidcAuthRoleArn
39739
+ };
39740
+ }
39501
39741
 
39502
39742
  // src/app.ts
39743
+ function parseGpuConfig(gpu) {
39744
+ if (!gpu) {
39745
+ return void 0;
39746
+ }
39747
+ let gpuType = gpu;
39748
+ let count = 1;
39749
+ if (gpu.includes(":")) {
39750
+ const [type, countStr] = gpu.split(":", 2);
39751
+ gpuType = type;
39752
+ count = parseInt(countStr, 10);
39753
+ if (isNaN(count) || count < 1) {
39754
+ throw new Error(
39755
+ `Invalid GPU count: ${countStr}. Value must be a positive integer.`
39756
+ );
39757
+ }
39758
+ }
39759
+ return {
39760
+ type: 0,
39761
+ // Deprecated field, but required by proto
39762
+ count,
39763
+ gpuType: gpuType.toUpperCase()
39764
+ };
39765
+ }
39503
39766
  var App = class _App {
39504
39767
  appId;
39768
+ name;
39505
39769
  /** @ignore */
39506
- constructor(appId) {
39770
+ constructor(appId, name) {
39507
39771
  this.appId = appId;
39772
+ this.name = name;
39508
39773
  }
39509
39774
  /** Lookup a deployed app by name, or create if it does not exist. */
39510
39775
  static async lookup(name, options = {}) {
@@ -39514,25 +39779,35 @@ var App = class _App {
39514
39779
  environmentName: environmentName(options.environment),
39515
39780
  objectCreationType: options.createIfMissing ? 1 /* OBJECT_CREATION_TYPE_CREATE_IF_MISSING */ : 0 /* OBJECT_CREATION_TYPE_UNSPECIFIED */
39516
39781
  });
39517
- return new _App(resp.appId);
39782
+ return new _App(resp.appId, name);
39518
39783
  } catch (err) {
39519
- if (err instanceof ClientError3 && err.code === Status3.NOT_FOUND)
39784
+ if (err instanceof ClientError4 && err.code === Status4.NOT_FOUND)
39520
39785
  throw new NotFoundError(`App '${name}' not found`);
39521
39786
  throw err;
39522
39787
  }
39523
39788
  }
39524
39789
  async createSandbox(image, options = {}) {
39790
+ const gpuConfig = parseGpuConfig(options.gpu);
39525
39791
  if (options.timeout && options.timeout % 1e3 !== 0) {
39526
39792
  throw new Error(
39527
39793
  `Timeout must be a multiple of 1000ms, got ${options.timeout}`
39528
39794
  );
39529
39795
  }
39796
+ await image._build(this.appId);
39797
+ if (options.workdir && !options.workdir.startsWith("/")) {
39798
+ throw new Error(
39799
+ `workdir must be an absolute path, got: ${options.workdir}`
39800
+ );
39801
+ }
39530
39802
  const volumeMounts = options.volumes ? Object.entries(options.volumes).map(([mountPath, volume]) => ({
39531
39803
  volumeId: volume.volumeId,
39532
39804
  mountPath,
39533
39805
  allowBackgroundCommits: true,
39534
- readOnly: false
39806
+ readOnly: volume.isReadOnly
39535
39807
  })) : [];
39808
+ const cloudBucketMounts = options.cloudBucketMounts ? Object.entries(options.cloudBucketMounts).map(
39809
+ ([mountPath, mount]) => cloudBucketMountToProto(mount, mountPath)
39810
+ ) : [];
39536
39811
  const openPorts = [];
39537
39812
  if (options.encryptedPorts) {
39538
39813
  openPorts.push(
@@ -39560,6 +39835,31 @@ var App = class _App {
39560
39835
  );
39561
39836
  }
39562
39837
  const secretIds = options.secrets ? options.secrets.map((secret) => secret.secretId) : [];
39838
+ let networkAccess;
39839
+ if (options.blockNetwork) {
39840
+ if (options.cidrAllowlist) {
39841
+ throw new Error(
39842
+ "cidrAllowlist cannot be used when blockNetwork is enabled"
39843
+ );
39844
+ }
39845
+ networkAccess = {
39846
+ networkAccessType: 2 /* BLOCKED */,
39847
+ allowedCidrs: []
39848
+ };
39849
+ } else if (options.cidrAllowlist) {
39850
+ networkAccess = {
39851
+ networkAccessType: 3 /* ALLOWLIST */,
39852
+ allowedCidrs: options.cidrAllowlist
39853
+ };
39854
+ } else {
39855
+ networkAccess = {
39856
+ networkAccessType: 1 /* OPEN */,
39857
+ allowedCidrs: []
39858
+ };
39859
+ }
39860
+ const schedulerPlacement = SchedulerPlacement.create({
39861
+ regions: options.regions ?? []
39862
+ });
39563
39863
  const createResp = await client.sandboxCreate({
39564
39864
  appId: this.appId,
39565
39865
  definition: {
@@ -39567,64 +39867,48 @@ var App = class _App {
39567
39867
  entrypointArgs: options.command ?? ["sleep", "48h"],
39568
39868
  imageId: image.imageId,
39569
39869
  timeoutSecs: options.timeout != void 0 ? options.timeout / 1e3 : 600,
39570
- networkAccess: {
39571
- networkAccessType: 1 /* OPEN */
39572
- },
39870
+ workdir: options.workdir ?? void 0,
39871
+ networkAccess,
39573
39872
  resources: {
39574
39873
  // https://modal.com/docs/guide/resources
39575
39874
  milliCpu: Math.round(1e3 * (options.cpu ?? 0.125)),
39576
- memoryMb: options.memory ?? 128
39875
+ memoryMb: options.memory ?? 128,
39876
+ gpuConfig
39577
39877
  },
39578
39878
  volumeMounts,
39879
+ cloudBucketMounts,
39579
39880
  secretIds,
39580
- openPorts: openPorts.length > 0 ? { ports: openPorts } : void 0
39881
+ openPorts: openPorts.length > 0 ? { ports: openPorts } : void 0,
39882
+ cloudProviderStr: options.cloud ?? "",
39883
+ schedulerPlacement,
39884
+ verbose: options.verbose ?? false,
39885
+ proxyId: options.proxy?.proxyId
39581
39886
  }
39582
39887
  });
39583
39888
  return new Sandbox2(createResp.sandboxId);
39584
39889
  }
39890
+ /**
39891
+ * @deprecated Use `Image.fromRegistry` instead.
39892
+ */
39585
39893
  async imageFromRegistry(tag, secret) {
39586
- let imageRegistryConfig;
39587
- if (secret) {
39588
- if (!(secret instanceof Secret)) {
39589
- throw new TypeError(
39590
- "secret must be a reference to an existing Secret, e.g. `await Secret.fromName('my_secret')`"
39591
- );
39592
- }
39593
- imageRegistryConfig = {
39594
- registryAuthType: 4 /* REGISTRY_AUTH_TYPE_STATIC_CREDS */,
39595
- secretId: secret.secretId
39596
- };
39597
- }
39598
- return await fromRegistryInternal(this.appId, tag, imageRegistryConfig);
39894
+ return await Image2.fromRegistry(tag, secret)._build(this.appId);
39599
39895
  }
39896
+ /**
39897
+ * @deprecated Use `Image.fromAwsEcr` instead.
39898
+ */
39600
39899
  async imageFromAwsEcr(tag, secret) {
39601
- if (!(secret instanceof Secret)) {
39602
- throw new TypeError(
39603
- "secret must be a reference to an existing Secret, e.g. `await Secret.fromName('my_secret')`"
39604
- );
39605
- }
39606
- const imageRegistryConfig = {
39607
- registryAuthType: 1 /* REGISTRY_AUTH_TYPE_AWS */,
39608
- secretId: secret.secretId
39609
- };
39610
- return await fromRegistryInternal(this.appId, tag, imageRegistryConfig);
39900
+ return await Image2.fromAwsEcr(tag, secret)._build(this.appId);
39611
39901
  }
39902
+ /**
39903
+ * @deprecated Use `Image.fromGcpArtifactRegistry` instead.
39904
+ */
39612
39905
  async imageFromGcpArtifactRegistry(tag, secret) {
39613
- if (!(secret instanceof Secret)) {
39614
- throw new TypeError(
39615
- "secret must be a reference to an existing Secret, e.g. `await Secret.fromName('my_secret')`"
39616
- );
39617
- }
39618
- const imageRegistryConfig = {
39619
- registryAuthType: 2 /* REGISTRY_AUTH_TYPE_GCP */,
39620
- secretId: secret.secretId
39621
- };
39622
- return await fromRegistryInternal(this.appId, tag, imageRegistryConfig);
39906
+ return await Image2.fromGcpArtifactRegistry(tag, secret)._build(this.appId);
39623
39907
  }
39624
39908
  };
39625
39909
 
39626
39910
  // src/cls.ts
39627
- import { ClientError as ClientError5, Status as Status5 } from "nice-grpc";
39911
+ import { ClientError as ClientError6, Status as Status6 } from "nice-grpc";
39628
39912
 
39629
39913
  // src/function.ts
39630
39914
  import { createHash } from "node:crypto";
@@ -40197,18 +40481,20 @@ var FunctionCall = class _FunctionCall {
40197
40481
  };
40198
40482
 
40199
40483
  // src/function.ts
40200
- import { ClientError as ClientError4, Status as Status4 } from "nice-grpc";
40484
+ import { ClientError as ClientError5, Status as Status5 } from "nice-grpc";
40201
40485
  var maxObjectSizeBytes = 2 * 1024 * 1024;
40202
40486
  var maxSystemRetries = 8;
40203
40487
  var Function_ = class _Function_ {
40204
40488
  functionId;
40205
40489
  methodName;
40206
40490
  #inputPlaneUrl;
40491
+ #webUrl;
40207
40492
  /** @ignore */
40208
- constructor(functionId, methodName, inputPlaneUrl) {
40493
+ constructor(functionId, methodName, inputPlaneUrl, webUrl) {
40209
40494
  this.functionId = functionId;
40210
40495
  this.methodName = methodName;
40211
40496
  this.#inputPlaneUrl = inputPlaneUrl;
40497
+ this.#webUrl = webUrl;
40212
40498
  }
40213
40499
  static async lookup(appName, name, options = {}) {
40214
40500
  try {
@@ -40220,10 +40506,11 @@ var Function_ = class _Function_ {
40220
40506
  return new _Function_(
40221
40507
  resp.functionId,
40222
40508
  void 0,
40223
- resp.handleMetadata?.inputPlaneUrl
40509
+ resp.handleMetadata?.inputPlaneUrl,
40510
+ resp.handleMetadata?.webUrl
40224
40511
  );
40225
40512
  } catch (err) {
40226
- if (err instanceof ClientError4 && err.code === Status4.NOT_FOUND)
40513
+ if (err instanceof ClientError5 && err.code === Status5.NOT_FOUND)
40227
40514
  throw new NotFoundError(`Function '${appName}/${name}' not found`);
40228
40515
  throw err;
40229
40516
  }
@@ -40270,6 +40557,38 @@ var Function_ = class _Function_ {
40270
40557
  );
40271
40558
  return new FunctionCall(invocation.functionCallId);
40272
40559
  }
40560
+ // Returns statistics about the Function.
40561
+ async getCurrentStats() {
40562
+ const resp = await client.functionGetCurrentStats(
40563
+ { functionId: this.functionId },
40564
+ { timeout: 1e4 }
40565
+ );
40566
+ return {
40567
+ backlog: resp.backlog,
40568
+ numTotalRunners: resp.numTotalTasks
40569
+ };
40570
+ }
40571
+ // Overrides the current autoscaler behavior for this Function.
40572
+ async updateAutoscaler(options) {
40573
+ await client.functionUpdateSchedulingParams({
40574
+ functionId: this.functionId,
40575
+ warmPoolSizeOverride: 0,
40576
+ // Deprecated field, always set to 0
40577
+ settings: {
40578
+ minContainers: options.minContainers,
40579
+ maxContainers: options.maxContainers,
40580
+ bufferContainers: options.bufferContainers,
40581
+ scaledownWindow: options.scaledownWindow
40582
+ }
40583
+ });
40584
+ }
40585
+ /**
40586
+ * URL of a Function running as a web endpoint.
40587
+ * @returns The web URL if this function is a web endpoint, otherwise undefined
40588
+ */
40589
+ async getWebUrl() {
40590
+ return this.#webUrl || void 0;
40591
+ }
40273
40592
  async #createInput(args = [], kwargs = {}) {
40274
40593
  const payload = dumps([args, kwargs]);
40275
40594
  let argsBlobId = void 0;
@@ -40361,7 +40680,7 @@ var Cls = class _Cls {
40361
40680
  serviceFunction.handleMetadata?.inputPlaneUrl
40362
40681
  );
40363
40682
  } catch (err) {
40364
- if (err instanceof ClientError5 && err.code === Status5.NOT_FOUND)
40683
+ if (err instanceof ClientError6 && err.code === Status6.NOT_FOUND)
40365
40684
  throw new NotFoundError(`Class '${appName}/${name}' not found`);
40366
40685
  throw err;
40367
40686
  }
@@ -40460,17 +40779,19 @@ var ClsInstance = class {
40460
40779
  };
40461
40780
 
40462
40781
  // src/queue.ts
40463
- import { ClientError as ClientError6, Status as Status6 } from "nice-grpc";
40782
+ import { ClientError as ClientError7, Status as Status7 } from "nice-grpc";
40464
40783
  var ephemeralObjectHeartbeatSleep = 3e5;
40465
40784
  var queueInitialPutBackoff = 100;
40466
40785
  var queueDefaultPartitionTtl = 24 * 3600 * 1e3;
40467
40786
  var Queue = class _Queue {
40468
40787
  queueId;
40788
+ name;
40469
40789
  #ephemeral;
40470
40790
  #abortController;
40471
40791
  /** @ignore */
40472
- constructor(queueId, ephemeral = false) {
40792
+ constructor(queueId, name, ephemeral = false) {
40473
40793
  this.queueId = queueId;
40794
+ this.name = name;
40474
40795
  this.#ephemeral = ephemeral;
40475
40796
  this.#abortController = ephemeral ? new AbortController() : void 0;
40476
40797
  }
@@ -40495,7 +40816,7 @@ var Queue = class _Queue {
40495
40816
  objectCreationType: 5 /* OBJECT_CREATION_TYPE_EPHEMERAL */,
40496
40817
  environmentName: environmentName(options.environment)
40497
40818
  });
40498
- const queue = new _Queue(resp.queueId, true);
40819
+ const queue = new _Queue(resp.queueId, void 0, true);
40499
40820
  const signal = queue.#abortController.signal;
40500
40821
  (async () => {
40501
40822
  while (true) {
@@ -40529,7 +40850,7 @@ var Queue = class _Queue {
40529
40850
  objectCreationType: options.createIfMissing ? 1 /* OBJECT_CREATION_TYPE_CREATE_IF_MISSING */ : void 0,
40530
40851
  environmentName: environmentName(options.environment)
40531
40852
  });
40532
- return new _Queue(resp.queueId);
40853
+ return new _Queue(resp.queueId, name);
40533
40854
  }
40534
40855
  /** Delete a queue by name. */
40535
40856
  static async delete(name, options = {}) {
@@ -40614,7 +40935,7 @@ var Queue = class _Queue {
40614
40935
  });
40615
40936
  break;
40616
40937
  } catch (e) {
40617
- if (e instanceof ClientError6 && e.code === Status6.RESOURCE_EXHAUSTED) {
40938
+ if (e instanceof ClientError7 && e.code === Status7.RESOURCE_EXHAUSTED) {
40618
40939
  delay = Math.min(delay * 2, 3e4);
40619
40940
  if (deadline !== void 0) {
40620
40941
  const remaining = deadline - Date.now();
@@ -40706,12 +41027,16 @@ var Queue = class _Queue {
40706
41027
  };
40707
41028
 
40708
41029
  // src/volume.ts
40709
- import { ClientError as ClientError7, Status as Status7 } from "nice-grpc";
41030
+ import { ClientError as ClientError8, Status as Status8 } from "nice-grpc";
40710
41031
  var Volume = class _Volume {
40711
41032
  volumeId;
41033
+ name;
41034
+ _readOnly = false;
40712
41035
  /** @ignore */
40713
- constructor(volumeId) {
41036
+ constructor(volumeId, name, readOnly = false) {
40714
41037
  this.volumeId = volumeId;
41038
+ this.name = name;
41039
+ this._readOnly = readOnly;
40715
41040
  }
40716
41041
  static async fromName(name, options) {
40717
41042
  try {
@@ -40720,16 +41045,51 @@ var Volume = class _Volume {
40720
41045
  environmentName: environmentName(options?.environment),
40721
41046
  objectCreationType: options?.createIfMissing ? 1 /* OBJECT_CREATION_TYPE_CREATE_IF_MISSING */ : 0 /* OBJECT_CREATION_TYPE_UNSPECIFIED */
40722
41047
  });
40723
- return new _Volume(resp.volumeId);
41048
+ return new _Volume(resp.volumeId, name);
40724
41049
  } catch (err) {
40725
- if (err instanceof ClientError7 && err.code === Status7.NOT_FOUND)
41050
+ if (err instanceof ClientError8 && err.code === Status8.NOT_FOUND)
40726
41051
  throw new NotFoundError(err.details);
40727
41052
  throw err;
40728
41053
  }
40729
41054
  }
41055
+ /** Configure Volume to mount as read-only. */
41056
+ readOnly() {
41057
+ return new _Volume(this.volumeId, this.name, true);
41058
+ }
41059
+ get isReadOnly() {
41060
+ return this._readOnly;
41061
+ }
41062
+ };
41063
+
41064
+ // src/proxy.ts
41065
+ import { ClientError as ClientError9, Status as Status9 } from "nice-grpc";
41066
+ var Proxy2 = class _Proxy {
41067
+ proxyId;
41068
+ /** @ignore */
41069
+ constructor(proxyId) {
41070
+ this.proxyId = proxyId;
41071
+ }
41072
+ /** Reference a Proxy by its name. */
41073
+ static async fromName(name, options) {
41074
+ try {
41075
+ const resp = await client.proxyGet({
41076
+ name,
41077
+ environmentName: environmentName(options?.environment)
41078
+ });
41079
+ if (!resp.proxy?.proxyId) {
41080
+ throw new NotFoundError(`Proxy '${name}' not found`);
41081
+ }
41082
+ return new _Proxy(resp.proxy.proxyId);
41083
+ } catch (err) {
41084
+ if (err instanceof ClientError9 && err.code === Status9.NOT_FOUND)
41085
+ throw new NotFoundError(`Proxy '${name}' not found`);
41086
+ throw err;
41087
+ }
41088
+ }
40730
41089
  };
40731
41090
  export {
40732
41091
  App,
41092
+ CloudBucketMount2 as CloudBucketMount,
40733
41093
  Cls,
40734
41094
  ClsInstance,
40735
41095
  ContainerProcess,
@@ -40740,6 +41100,7 @@ export {
40740
41100
  InternalFailure,
40741
41101
  InvalidError,
40742
41102
  NotFoundError,
41103
+ Proxy2 as Proxy,
40743
41104
  Queue,
40744
41105
  QueueEmptyError,
40745
41106
  QueueFullError,