modal 0.10.2-dev.5 → 0.10.2-dev.7

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
@@ -47974,6 +47974,108 @@ var SecretDeleteRequest = {
47974
47974
  return message;
47975
47975
  }
47976
47976
  };
47977
+ function createBaseSecretGetInfoRequest() {
47978
+ return { secretId: "" };
47979
+ }
47980
+ var SecretGetInfoRequest = {
47981
+ encode(message, writer = new BinaryWriter()) {
47982
+ if (message.secretId !== "") {
47983
+ writer.uint32(10).string(message.secretId);
47984
+ }
47985
+ return writer;
47986
+ },
47987
+ decode(input, length) {
47988
+ const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
47989
+ let end = length === void 0 ? reader.len : reader.pos + length;
47990
+ const message = createBaseSecretGetInfoRequest();
47991
+ while (reader.pos < end) {
47992
+ const tag = reader.uint32();
47993
+ switch (tag >>> 3) {
47994
+ case 1: {
47995
+ if (tag !== 10) {
47996
+ break;
47997
+ }
47998
+ message.secretId = reader.string();
47999
+ continue;
48000
+ }
48001
+ }
48002
+ if ((tag & 7) === 4 || tag === 0) {
48003
+ break;
48004
+ }
48005
+ reader.skip(tag & 7);
48006
+ }
48007
+ return message;
48008
+ },
48009
+ fromJSON(object) {
48010
+ return { secretId: isSet5(object.secretId) ? globalThis.String(object.secretId) : "" };
48011
+ },
48012
+ toJSON(message) {
48013
+ const obj = {};
48014
+ if (message.secretId !== "") {
48015
+ obj.secretId = message.secretId;
48016
+ }
48017
+ return obj;
48018
+ },
48019
+ create(base) {
48020
+ return SecretGetInfoRequest.fromPartial(base ?? {});
48021
+ },
48022
+ fromPartial(object) {
48023
+ const message = createBaseSecretGetInfoRequest();
48024
+ message.secretId = object.secretId ?? "";
48025
+ return message;
48026
+ }
48027
+ };
48028
+ function createBaseSecretGetInfoResponse() {
48029
+ return { metadata: void 0 };
48030
+ }
48031
+ var SecretGetInfoResponse = {
48032
+ encode(message, writer = new BinaryWriter()) {
48033
+ if (message.metadata !== void 0) {
48034
+ SecretMetadata.encode(message.metadata, writer.uint32(10).fork()).join();
48035
+ }
48036
+ return writer;
48037
+ },
48038
+ decode(input, length) {
48039
+ const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
48040
+ let end = length === void 0 ? reader.len : reader.pos + length;
48041
+ const message = createBaseSecretGetInfoResponse();
48042
+ while (reader.pos < end) {
48043
+ const tag = reader.uint32();
48044
+ switch (tag >>> 3) {
48045
+ case 1: {
48046
+ if (tag !== 10) {
48047
+ break;
48048
+ }
48049
+ message.metadata = SecretMetadata.decode(reader, reader.uint32());
48050
+ continue;
48051
+ }
48052
+ }
48053
+ if ((tag & 7) === 4 || tag === 0) {
48054
+ break;
48055
+ }
48056
+ reader.skip(tag & 7);
48057
+ }
48058
+ return message;
48059
+ },
48060
+ fromJSON(object) {
48061
+ return { metadata: isSet5(object.metadata) ? SecretMetadata.fromJSON(object.metadata) : void 0 };
48062
+ },
48063
+ toJSON(message) {
48064
+ const obj = {};
48065
+ if (message.metadata !== void 0) {
48066
+ obj.metadata = SecretMetadata.toJSON(message.metadata);
48067
+ }
48068
+ return obj;
48069
+ },
48070
+ create(base) {
48071
+ return SecretGetInfoResponse.fromPartial(base ?? {});
48072
+ },
48073
+ fromPartial(object) {
48074
+ const message = createBaseSecretGetInfoResponse();
48075
+ message.metadata = object.metadata !== void 0 && object.metadata !== null ? SecretMetadata.fromPartial(object.metadata) : void 0;
48076
+ return message;
48077
+ }
48078
+ };
47977
48079
  function createBaseSecretGetOrCreateRequest() {
47978
48080
  return { deploymentName: "", environmentName: "", objectCreationType: 0, envDict: {}, appId: "", requiredKeys: [] };
47979
48081
  }
@@ -48520,7 +48622,7 @@ var SecretListResponse = {
48520
48622
  }
48521
48623
  };
48522
48624
  function createBaseSecretMetadata() {
48523
- return { name: "", creationInfo: void 0, keys: [] };
48625
+ return { name: "", creationInfo: void 0, keys: [], environmentName: "" };
48524
48626
  }
48525
48627
  var SecretMetadata = {
48526
48628
  encode(message, writer = new BinaryWriter()) {
@@ -48533,6 +48635,9 @@ var SecretMetadata = {
48533
48635
  for (const v of message.keys) {
48534
48636
  writer.uint32(26).string(v);
48535
48637
  }
48638
+ if (message.environmentName !== "") {
48639
+ writer.uint32(34).string(message.environmentName);
48640
+ }
48536
48641
  return writer;
48537
48642
  },
48538
48643
  decode(input, length) {
@@ -48563,6 +48668,13 @@ var SecretMetadata = {
48563
48668
  message.keys.push(reader.string());
48564
48669
  continue;
48565
48670
  }
48671
+ case 4: {
48672
+ if (tag !== 34) {
48673
+ break;
48674
+ }
48675
+ message.environmentName = reader.string();
48676
+ continue;
48677
+ }
48566
48678
  }
48567
48679
  if ((tag & 7) === 4 || tag === 0) {
48568
48680
  break;
@@ -48575,7 +48687,8 @@ var SecretMetadata = {
48575
48687
  return {
48576
48688
  name: isSet5(object.name) ? globalThis.String(object.name) : "",
48577
48689
  creationInfo: isSet5(object.creationInfo) ? CreationInfo.fromJSON(object.creationInfo) : void 0,
48578
- keys: globalThis.Array.isArray(object?.keys) ? object.keys.map((e) => globalThis.String(e)) : []
48690
+ keys: globalThis.Array.isArray(object?.keys) ? object.keys.map((e) => globalThis.String(e)) : [],
48691
+ environmentName: isSet5(object.environmentName) ? globalThis.String(object.environmentName) : ""
48579
48692
  };
48580
48693
  },
48581
48694
  toJSON(message) {
@@ -48589,6 +48702,9 @@ var SecretMetadata = {
48589
48702
  if (message.keys?.length) {
48590
48703
  obj.keys = message.keys;
48591
48704
  }
48705
+ if (message.environmentName !== "") {
48706
+ obj.environmentName = message.environmentName;
48707
+ }
48592
48708
  return obj;
48593
48709
  },
48594
48710
  create(base) {
@@ -48599,6 +48715,7 @@ var SecretMetadata = {
48599
48715
  message.name = object.name ?? "";
48600
48716
  message.creationInfo = object.creationInfo !== void 0 && object.creationInfo !== null ? CreationInfo.fromPartial(object.creationInfo) : void 0;
48601
48717
  message.keys = object.keys?.map((e) => e) || [];
48718
+ message.environmentName = object.environmentName ?? "";
48602
48719
  return message;
48603
48720
  }
48604
48721
  };
@@ -61983,6 +62100,14 @@ var ModalClientDefinition = {
61983
62100
  responseStream: false,
61984
62101
  options: {}
61985
62102
  },
62103
+ secretGetInfo: {
62104
+ name: "SecretGetInfo",
62105
+ requestType: SecretGetInfoRequest,
62106
+ requestStream: false,
62107
+ responseType: SecretGetInfoResponse,
62108
+ responseStream: false,
62109
+ options: {}
62110
+ },
61986
62111
  secretGetOrCreate: {
61987
62112
  name: "SecretGetOrCreate",
61988
62113
  requestType: SecretGetOrCreateRequest,
@@ -70475,8 +70600,151 @@ var SandboxFilesystem = class {
70475
70600
  };
70476
70601
 
70477
70602
  // src/sandbox_sidecar.ts
70478
- import { ClientError as ClientError9, Status as Status9 } from "nice-grpc";
70603
+ import { ClientError as ClientError10, Status as Status10 } from "nice-grpc";
70479
70604
  import { v4 as uuidv4 } from "uuid";
70605
+
70606
+ // src/volume.ts
70607
+ import { ClientError as ClientError9, Status as Status9 } from "nice-grpc";
70608
+ var VolumeService = class {
70609
+ #client;
70610
+ constructor(client) {
70611
+ this.#client = client;
70612
+ }
70613
+ /**
70614
+ * Reference a {@link Volume} by its name.
70615
+ */
70616
+ async fromName(name, params) {
70617
+ try {
70618
+ const resp = await this.#client.cpClient.volumeGetOrCreate({
70619
+ deploymentName: name,
70620
+ environmentName: this.#client.environmentName(params?.environment),
70621
+ objectCreationType: params?.createIfMissing ? 1 /* OBJECT_CREATION_TYPE_CREATE_IF_MISSING */ : 0 /* OBJECT_CREATION_TYPE_UNSPECIFIED */
70622
+ });
70623
+ this.#client.logger.debug(
70624
+ "Retrieved Volume",
70625
+ "volume_id",
70626
+ resp.volumeId,
70627
+ "volume_name",
70628
+ name
70629
+ );
70630
+ return new Volume(resp.volumeId, name);
70631
+ } catch (err) {
70632
+ if (err instanceof ClientError9 && err.code === Status9.NOT_FOUND)
70633
+ throw new NotFoundError(err.details);
70634
+ throw err;
70635
+ }
70636
+ }
70637
+ /**
70638
+ * Create a nameless, temporary {@link Volume}.
70639
+ * It persists until closeEphemeral() is called, or the process exits.
70640
+ */
70641
+ async ephemeral(params = {}) {
70642
+ const resp = await this.#client.cpClient.volumeGetOrCreate({
70643
+ objectCreationType: 5 /* OBJECT_CREATION_TYPE_EPHEMERAL */,
70644
+ environmentName: this.#client.environmentName(params.environment)
70645
+ });
70646
+ this.#client.logger.debug(
70647
+ "Created ephemeral Volume",
70648
+ "volume_id",
70649
+ resp.volumeId
70650
+ );
70651
+ const ephemeralHbManager = new EphemeralHeartbeatManager(
70652
+ () => this.#client.cpClient.volumeHeartbeat({ volumeId: resp.volumeId })
70653
+ );
70654
+ return new Volume(resp.volumeId, void 0, void 0, ephemeralHbManager);
70655
+ }
70656
+ /**
70657
+ * Delete a named {@link Volume}.
70658
+ *
70659
+ * Warning: Deletion is irreversible and will affect any Apps currently using the Volume.
70660
+ */
70661
+ async delete(name, params) {
70662
+ try {
70663
+ const volume = await this.fromName(name, {
70664
+ environment: params?.environment,
70665
+ createIfMissing: false
70666
+ });
70667
+ await this.#client.cpClient.volumeDelete({
70668
+ volumeId: volume.volumeId
70669
+ });
70670
+ this.#client.logger.debug(
70671
+ "Deleted Volume",
70672
+ "volume_name",
70673
+ name,
70674
+ "volume_id",
70675
+ volume.volumeId
70676
+ );
70677
+ } catch (err) {
70678
+ const isNotFound = err instanceof NotFoundError || err instanceof ClientError9 && err.code === Status9.NOT_FOUND;
70679
+ if (isNotFound && params?.allowMissing) {
70680
+ return;
70681
+ }
70682
+ throw err;
70683
+ }
70684
+ }
70685
+ };
70686
+ var DEFAULT_MOUNT_OPTIONS = {
70687
+ readOnly: false,
70688
+ subPath: void 0
70689
+ };
70690
+ var Volume = class _Volume {
70691
+ volumeId;
70692
+ name;
70693
+ /**
70694
+ * @hidden
70695
+ * @internal
70696
+ */
70697
+ _mountOptions = DEFAULT_MOUNT_OPTIONS;
70698
+ #ephemeralHbManager;
70699
+ /** @ignore */
70700
+ constructor(volumeId, name, mountOptions, ephemeralHbManager) {
70701
+ this.volumeId = volumeId;
70702
+ this.name = name;
70703
+ if (mountOptions) {
70704
+ this._mountOptions = mountOptions;
70705
+ }
70706
+ this.#ephemeralHbManager = ephemeralHbManager;
70707
+ }
70708
+ /**
70709
+ * Configure options used when mounting this Volume. Fields left undefined preserve their value
70710
+ * from any previous withMountOptions call on the same Volume (stacking).
70711
+ */
70712
+ withMountOptions(params = {}) {
70713
+ let subPath = this._mountOptions.subPath;
70714
+ if (params.subPath !== void 0) {
70715
+ subPath = params.subPath === "/" ? void 0 : params.subPath;
70716
+ }
70717
+ return new _Volume(
70718
+ this.volumeId,
70719
+ this.name,
70720
+ {
70721
+ readOnly: params.readOnly ?? this._mountOptions.readOnly,
70722
+ subPath
70723
+ },
70724
+ this.#ephemeralHbManager
70725
+ );
70726
+ }
70727
+ /** Delete the ephemeral Volume. Only usable with emphemeral Volumes. */
70728
+ closeEphemeral() {
70729
+ if (this.#ephemeralHbManager) {
70730
+ this.#ephemeralHbManager.stop();
70731
+ } else {
70732
+ throw new InvalidError("Volume is not ephemeral.");
70733
+ }
70734
+ }
70735
+ };
70736
+ function volumeToMountProto(mountPath, volume) {
70737
+ const opts = volume._mountOptions ?? DEFAULT_MOUNT_OPTIONS;
70738
+ return {
70739
+ volumeId: volume.volumeId,
70740
+ mountPath,
70741
+ allowBackgroundCommits: true,
70742
+ readOnly: opts.readOnly,
70743
+ subPath: opts.subPath
70744
+ };
70745
+ }
70746
+
70747
+ // src/sandbox_sidecar.ts
70480
70748
  var MAIN_CONTAINER_NAME = "main";
70481
70749
  var CONTAINER_WAIT_POLL_TIMEOUT_SECONDS = 10;
70482
70750
  var CONTROL_PLANE_SIDECAR_CREATE_ENV_VAR = "MODAL_USE_CONTROL_PLANE_SIDECAR_CREATE";
@@ -70493,6 +70761,29 @@ function validateSidecarName(name) {
70493
70761
  );
70494
70762
  }
70495
70763
  }
70764
+ function buildSidecarVolumeMounts(volumes) {
70765
+ const mountPathsByVolumeId = /* @__PURE__ */ new Map();
70766
+ const volumeMounts = [];
70767
+ for (const [mountPath, volume] of Object.entries(volumes ?? {})) {
70768
+ if (!volume) {
70769
+ throw new InvalidError(
70770
+ `Volume mounted at "${mountPath}" must not be null or undefined`
70771
+ );
70772
+ }
70773
+ const mountPaths = mountPathsByVolumeId.get(volume.volumeId) ?? [];
70774
+ mountPaths.push(mountPath);
70775
+ mountPathsByVolumeId.set(volume.volumeId, mountPaths);
70776
+ volumeMounts.push(volumeToMountProto(mountPath, volume));
70777
+ }
70778
+ for (const mountPaths of mountPathsByVolumeId.values()) {
70779
+ if (mountPaths.length > 1) {
70780
+ throw new InvalidError(
70781
+ "The same Volume cannot be mounted at multiple paths in a sidecar: " + mountPaths.sort().join(", ")
70782
+ );
70783
+ }
70784
+ }
70785
+ return volumeMounts;
70786
+ }
70496
70787
  function sidecarContainerFromProto(access, info) {
70497
70788
  return new SidecarContainer(
70498
70789
  access,
@@ -70530,6 +70821,7 @@ var SidecarService = class {
70530
70821
  Object.assign(envDict, params?.env ?? {});
70531
70822
  await hydrateSecrets(this.#access.client, resolvableSecrets);
70532
70823
  const secretIds = collectSecretIds(resolvableSecrets);
70824
+ const volumeMounts = buildSidecarVolumeMounts(params?.volumes);
70533
70825
  const ptyInfo = params?.pty ? defaultSandboxPTYInfo() : void 0;
70534
70826
  const networkAccess = buildOutboundNetworkAccess(
70535
70827
  false,
@@ -70549,6 +70841,7 @@ var SidecarService = class {
70549
70841
  entrypointArgs: command,
70550
70842
  workdir: params?.workdir ?? void 0,
70551
70843
  secretIds,
70844
+ volumeMounts,
70552
70845
  networkAccess,
70553
70846
  ptyInfo
70554
70847
  }),
@@ -70566,17 +70859,18 @@ var SidecarService = class {
70566
70859
  env: envDict,
70567
70860
  workdir: params?.workdir ?? "",
70568
70861
  secretIds,
70862
+ volumeMounts,
70569
70863
  networkAccess,
70570
70864
  ptyInfo
70571
70865
  })
70572
70866
  );
70573
70867
  }
70574
70868
  } catch (err) {
70575
- if (err instanceof ClientError9) {
70576
- if (err.code === Status9.ALREADY_EXISTS) {
70869
+ if (err instanceof ClientError10) {
70870
+ if (err.code === Status10.ALREADY_EXISTS) {
70577
70871
  throw new AlreadyExistsError(err.details || err.message);
70578
70872
  }
70579
- if (err.code === Status9.INVALID_ARGUMENT) {
70873
+ if (err.code === Status10.INVALID_ARGUMENT) {
70580
70874
  throw new InvalidError(err.details || err.message);
70581
70875
  }
70582
70876
  }
@@ -70602,7 +70896,7 @@ var SidecarService = class {
70602
70896
  })
70603
70897
  );
70604
70898
  } catch (err) {
70605
- if (err instanceof ClientError9 && err.code === Status9.NOT_FOUND) {
70899
+ if (err instanceof ClientError10 && err.code === Status10.NOT_FOUND) {
70606
70900
  throw new NotFoundError(`Sidecar container "${name}" not found`);
70607
70901
  }
70608
70902
  throw err;
@@ -70973,151 +71267,11 @@ var SandboxSnapshotService = class {
70973
71267
  }
70974
71268
  };
70975
71269
 
70976
- // src/volume.ts
70977
- import { ClientError as ClientError10, Status as Status10 } from "nice-grpc";
70978
- var VolumeService = class {
70979
- #client;
70980
- constructor(client) {
70981
- this.#client = client;
70982
- }
70983
- /**
70984
- * Reference a {@link Volume} by its name.
70985
- */
70986
- async fromName(name, params) {
70987
- try {
70988
- const resp = await this.#client.cpClient.volumeGetOrCreate({
70989
- deploymentName: name,
70990
- environmentName: this.#client.environmentName(params?.environment),
70991
- objectCreationType: params?.createIfMissing ? 1 /* OBJECT_CREATION_TYPE_CREATE_IF_MISSING */ : 0 /* OBJECT_CREATION_TYPE_UNSPECIFIED */
70992
- });
70993
- this.#client.logger.debug(
70994
- "Retrieved Volume",
70995
- "volume_id",
70996
- resp.volumeId,
70997
- "volume_name",
70998
- name
70999
- );
71000
- return new Volume(resp.volumeId, name);
71001
- } catch (err) {
71002
- if (err instanceof ClientError10 && err.code === Status10.NOT_FOUND)
71003
- throw new NotFoundError(err.details);
71004
- throw err;
71005
- }
71006
- }
71007
- /**
71008
- * Create a nameless, temporary {@link Volume}.
71009
- * It persists until closeEphemeral() is called, or the process exits.
71010
- */
71011
- async ephemeral(params = {}) {
71012
- const resp = await this.#client.cpClient.volumeGetOrCreate({
71013
- objectCreationType: 5 /* OBJECT_CREATION_TYPE_EPHEMERAL */,
71014
- environmentName: this.#client.environmentName(params.environment)
71015
- });
71016
- this.#client.logger.debug(
71017
- "Created ephemeral Volume",
71018
- "volume_id",
71019
- resp.volumeId
71020
- );
71021
- const ephemeralHbManager = new EphemeralHeartbeatManager(
71022
- () => this.#client.cpClient.volumeHeartbeat({ volumeId: resp.volumeId })
71023
- );
71024
- return new Volume(resp.volumeId, void 0, void 0, ephemeralHbManager);
71025
- }
71026
- /**
71027
- * Delete a named {@link Volume}.
71028
- *
71029
- * Warning: Deletion is irreversible and will affect any Apps currently using the Volume.
71030
- */
71031
- async delete(name, params) {
71032
- try {
71033
- const volume = await this.fromName(name, {
71034
- environment: params?.environment,
71035
- createIfMissing: false
71036
- });
71037
- await this.#client.cpClient.volumeDelete({
71038
- volumeId: volume.volumeId
71039
- });
71040
- this.#client.logger.debug(
71041
- "Deleted Volume",
71042
- "volume_name",
71043
- name,
71044
- "volume_id",
71045
- volume.volumeId
71046
- );
71047
- } catch (err) {
71048
- const isNotFound = err instanceof NotFoundError || err instanceof ClientError10 && err.code === Status10.NOT_FOUND;
71049
- if (isNotFound && params?.allowMissing) {
71050
- return;
71051
- }
71052
- throw err;
71053
- }
71054
- }
71055
- };
71056
- var DEFAULT_MOUNT_OPTIONS = {
71057
- readOnly: false,
71058
- subPath: void 0
71059
- };
71060
- var Volume = class _Volume {
71061
- volumeId;
71062
- name;
71063
- /**
71064
- * @hidden
71065
- * @internal
71066
- */
71067
- _mountOptions = DEFAULT_MOUNT_OPTIONS;
71068
- #ephemeralHbManager;
71069
- /** @ignore */
71070
- constructor(volumeId, name, mountOptions, ephemeralHbManager) {
71071
- this.volumeId = volumeId;
71072
- this.name = name;
71073
- if (mountOptions) {
71074
- this._mountOptions = mountOptions;
71075
- }
71076
- this.#ephemeralHbManager = ephemeralHbManager;
71077
- }
71078
- /**
71079
- * Configure options used when mounting this Volume. Fields left undefined preserve their value
71080
- * from any previous withMountOptions call on the same Volume (stacking).
71081
- */
71082
- withMountOptions(params = {}) {
71083
- let subPath = this._mountOptions.subPath;
71084
- if (params.subPath !== void 0) {
71085
- subPath = params.subPath === "/" ? void 0 : params.subPath;
71086
- }
71087
- return new _Volume(
71088
- this.volumeId,
71089
- this.name,
71090
- {
71091
- readOnly: params.readOnly ?? this._mountOptions.readOnly,
71092
- subPath
71093
- },
71094
- this.#ephemeralHbManager
71095
- );
71096
- }
71097
- /** Delete the ephemeral Volume. Only usable with emphemeral Volumes. */
71098
- closeEphemeral() {
71099
- if (this.#ephemeralHbManager) {
71100
- this.#ephemeralHbManager.stop();
71101
- } else {
71102
- throw new InvalidError("Volume is not ephemeral.");
71103
- }
71104
- }
71105
- };
71106
- function volumeToMountProto(mountPath, volume) {
71107
- const opts = volume._mountOptions ?? DEFAULT_MOUNT_OPTIONS;
71108
- return {
71109
- volumeId: volume.volumeId,
71110
- mountPath,
71111
- allowBackgroundCommits: true,
71112
- readOnly: opts.readOnly,
71113
- subPath: opts.subPath
71114
- };
71115
- }
71116
-
71117
71270
  // src/sandbox.ts
71118
71271
  var SB_LOGS_INITIAL_DELAY_MS = 10;
71119
71272
  var SB_LOGS_DELAY_FACTOR = 2;
71120
71273
  var SB_LOGS_MAX_RETRIES = 10;
71274
+ var SB_LOGS_TASK_ID_TIMEOUT_SECONDS = 0.5;
71121
71275
  var TTL_NO_EXPIRY_SENTINEL = -1;
71122
71276
  var CUSTOMER_SUPPLIED_ENCRYPTION_KEY_MIN_LENGTH = 16;
71123
71277
  var CUSTOMER_SUPPLIED_ENCRYPTION_KEY_MAX_LENGTH = 512;
@@ -71975,6 +72129,7 @@ function buildTaskSnapshotDirectoryRequestProto(taskId, path2, snapshotId, ttlSe
71975
72129
  var Sandbox2 = class _Sandbox {
71976
72130
  #client;
71977
72131
  sandboxId;
72132
+ #appId;
71978
72133
  #stdin;
71979
72134
  #stdout;
71980
72135
  #stderr;
@@ -72021,6 +72176,25 @@ var Sandbox2 = class _Sandbox {
72021
72176
  }
72022
72177
  return this.#stderr;
72023
72178
  }
72179
+ /**
72180
+ * Access persisted entrypoint logs emitted by this Sandbox.
72181
+ *
72182
+ * Use {@link SandboxLogsManager#fetch fetch()} to read logs from a UTC time
72183
+ * range and {@link SandboxLogsManager#tail tail()} to read the most recent
72184
+ * logs.
72185
+ *
72186
+ * This is separate from {@link Sandbox#stdout stdout} and
72187
+ * {@link Sandbox#stderr stderr}, which expose the Sandbox's live output
72188
+ * streams.
72189
+ */
72190
+ get logs() {
72191
+ return new SandboxLogsManager(
72192
+ this.#client,
72193
+ this.sandboxId,
72194
+ () => this.#getAppId(),
72195
+ () => this.#resolveTaskIdForLogs()
72196
+ );
72197
+ }
72024
72198
  #outputStream(fileDescriptor) {
72025
72199
  if (this.#isV2) {
72026
72200
  this.#ensureAttached();
@@ -72253,8 +72427,11 @@ var Sandbox2 = class _Sandbox {
72253
72427
  }
72254
72428
  return this.#client.cpClient.sandboxWait(req);
72255
72429
  }
72256
- #sandboxGetTaskId(signal) {
72257
- const req = { sandboxId: this.sandboxId };
72430
+ #sandboxGetTaskId(signal, timeout) {
72431
+ const req = SandboxGetTaskIdRequest.create({
72432
+ sandboxId: this.sandboxId,
72433
+ timeout
72434
+ });
72258
72435
  if (this.#isV2) {
72259
72436
  return this.#client.cpClient.sandboxGetTaskIdV2(req, { signal });
72260
72437
  }
@@ -72284,6 +72461,42 @@ var Sandbox2 = class _Sandbox {
72284
72461
  }
72285
72462
  static #maxGetTaskIdAttempts = 600;
72286
72463
  // 5 minutes at 500ms intervals
72464
+ async #getAppId() {
72465
+ if (this.#appId !== void 0) {
72466
+ return this.#appId;
72467
+ }
72468
+ const resp = await this.#sandboxWait(0);
72469
+ const appId = resp.metadata?.appId;
72470
+ if (!appId) {
72471
+ throw new ExecutionError(
72472
+ "Sandbox app ID should have been set during hydration"
72473
+ );
72474
+ }
72475
+ this.#appId = appId;
72476
+ return appId;
72477
+ }
72478
+ async #resolveTaskIdForLogs() {
72479
+ if (this.#taskId !== void 0) {
72480
+ return this.#taskId;
72481
+ }
72482
+ let resp;
72483
+ try {
72484
+ resp = await this.#sandboxGetTaskId(
72485
+ void 0,
72486
+ SB_LOGS_TASK_ID_TIMEOUT_SECONDS
72487
+ );
72488
+ } catch (error) {
72489
+ if (error instanceof ClientError11 && error.code === Status11.DEADLINE_EXCEEDED) {
72490
+ throw new ExecutionError("Sandbox task ID is not available yet.");
72491
+ }
72492
+ throw error;
72493
+ }
72494
+ if (!resp.taskId) {
72495
+ throw new ExecutionError("Sandbox task ID is not available.");
72496
+ }
72497
+ this.#taskId = resp.taskId;
72498
+ return this.#taskId;
72499
+ }
72287
72500
  async #getTaskId(signal) {
72288
72501
  if (this.#taskId !== void 0) {
72289
72502
  return this.#taskId;
@@ -73292,7 +73505,7 @@ var AuthTokenManager = class {
73292
73505
  };
73293
73506
 
73294
73507
  // src/version.ts
73295
- var SDK_VERSION = "0.10.2-dev.5";
73508
+ var SDK_VERSION = "0.10.2-dev.7";
73296
73509
  function getSDKVersion() {
73297
73510
  return SDK_VERSION;
73298
73511
  }
@@ -74038,6 +74251,8 @@ function contextIds(batch, item, ObjectId) {
74038
74251
  item.inputId || batch.inputId,
74039
74252
  item.containerId || batch.taskId
74040
74253
  ].filter((id) => id);
74254
+ case "sb":
74255
+ return [item.containerId || batch.taskId].filter((id) => id);
74041
74256
  default:
74042
74257
  return [];
74043
74258
  }
@@ -74858,6 +75073,97 @@ var FunctionCallLogsManager = class extends LogsManager {
74858
75073
  );
74859
75074
  }
74860
75075
  };
75076
+ var SandboxLogsManager = class {
75077
+ /** @ignore */
75078
+ constructor(client, sandboxId, getAppId, getTaskId) {
75079
+ this.client = client;
75080
+ this.sandboxId = sandboxId;
75081
+ this.getAppId = getAppId;
75082
+ this.getTaskId = getTaskId;
75083
+ }
75084
+ /**
75085
+ * Fetch Sandbox entrypoint logs corresponding to a UTC time range and
75086
+ * optional filters.
75087
+ *
75088
+ * Entries are returned in chronological order.
75089
+ *
75090
+ * @returns An async iterable of {@link LogEntry} objects.
75091
+ *
75092
+ * @example
75093
+ * ```typescript
75094
+ * import { ModalClient } from "modal";
75095
+ *
75096
+ * const modal = new ModalClient();
75097
+ * const sandbox = await modal.sandboxes.fromId("sb-...");
75098
+ *
75099
+ * for await (const entry of sandbox.logs.fetch({
75100
+ * since: new Date(Date.now() - 60 * 60 * 1_000),
75101
+ * source: "stdout",
75102
+ * })) {
75103
+ * process.stdout.write(entry.message);
75104
+ * }
75105
+ * ```
75106
+ */
75107
+ async *fetch(params) {
75108
+ const [appId, taskId] = await Promise.all([
75109
+ this.getAppId(),
75110
+ this.getTaskId()
75111
+ ]);
75112
+ if (!taskId) {
75113
+ throw new ExecutionError(
75114
+ "Cannot resolve Sandbox metadata needed for fetching logs. Wait for the Sandbox to be scheduled."
75115
+ );
75116
+ }
75117
+ yield* fetchLogs(
75118
+ this.client,
75119
+ {
75120
+ appId,
75121
+ objectId: this.sandboxId,
75122
+ taskId,
75123
+ source: sourceToFileDescriptor(params.source),
75124
+ searchText: params.searchText
75125
+ },
75126
+ params.since,
75127
+ params.until
75128
+ );
75129
+ }
75130
+ /**
75131
+ * Fetch the most recent Sandbox entrypoint logs.
75132
+ *
75133
+ * Entries are returned in chronological order.
75134
+ *
75135
+ * @returns An async iterable of {@link LogEntry} objects.
75136
+ *
75137
+ * @example
75138
+ * ```typescript
75139
+ * import { ModalClient } from "modal";
75140
+ *
75141
+ * const modal = new ModalClient();
75142
+ * const sandbox = await modal.sandboxes.fromId("sb-...");
75143
+ *
75144
+ * for await (const entry of sandbox.logs.tail({ entries: 20 })) {
75145
+ * process.stdout.write(entry.message);
75146
+ * }
75147
+ * ```
75148
+ */
75149
+ async *tail(params = {}) {
75150
+ const [appId, taskId] = await Promise.all([
75151
+ this.getAppId(),
75152
+ this.getTaskId()
75153
+ ]);
75154
+ if (!taskId) {
75155
+ throw new ExecutionError(
75156
+ "Sandbox task ID cannot be empty when fetching logs. Wait for the Sandbox to be scheduled."
75157
+ );
75158
+ }
75159
+ yield* tailLogs(this.client, params.entries ?? 100, {
75160
+ appId,
75161
+ objectId: this.sandboxId,
75162
+ taskId,
75163
+ source: sourceToFileDescriptor(params.source)
75164
+ });
75165
+ }
75166
+ };
74861
75167
 
74862
75168
  // src/function_call.ts
74863
75169
  var FunctionCallService = class {
@@ -75794,6 +76100,7 @@ export {
75794
76100
  SandboxFilesystemNotFoundError,
75795
76101
  SandboxFilesystemPathAlreadyExistsError,
75796
76102
  SandboxFilesystemPermissionError,
76103
+ SandboxLogsManager,
75797
76104
  SandboxService,
75798
76105
  SandboxSnapshot,
75799
76106
  SandboxSnapshotService,