modal 0.5.0-dev.7 → 0.5.1

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
@@ -65,6 +65,7 @@ __export(index_exports, {
65
65
  SecretService: () => SecretService,
66
66
  Volume: () => Volume,
67
67
  VolumeService: () => VolumeService,
68
+ checkForRenamedParams: () => checkForRenamedParams,
68
69
  close: () => close,
69
70
  initializeClient: () => initializeClient
70
71
  });
@@ -43415,7 +43416,7 @@ function cborDecode(data) {
43415
43416
  }
43416
43417
 
43417
43418
  // src/invocation.ts
43418
- var outputsTimeout = 55 * 1e3;
43419
+ var outputsTimeoutMs = 55 * 1e3;
43419
43420
  var ControlPlaneInvocation = class _ControlPlaneInvocation {
43420
43421
  cpClient;
43421
43422
  functionCallId;
@@ -43451,19 +43452,18 @@ var ControlPlaneInvocation = class _ControlPlaneInvocation {
43451
43452
  static fromFunctionCallId(client2, functionCallId) {
43452
43453
  return new _ControlPlaneInvocation(client2.cpClient, functionCallId);
43453
43454
  }
43454
- async awaitOutput(timeout) {
43455
+ async awaitOutput(timeoutMs) {
43455
43456
  return await pollFunctionOutput(
43456
43457
  this.cpClient,
43457
- (timeoutMillis) => this.#getOutput(timeoutMillis),
43458
- timeout
43458
+ (timeoutMs2) => this.#getOutput(timeoutMs2),
43459
+ timeoutMs
43459
43460
  );
43460
43461
  }
43461
- async #getOutput(timeoutMillis) {
43462
+ async #getOutput(timeoutMs) {
43462
43463
  const response = await this.cpClient.functionGetOutputs({
43463
43464
  functionCallId: this.functionCallId,
43464
43465
  maxValues: 1,
43465
- timeout: timeoutMillis / 1e3,
43466
- // Backend needs seconds
43466
+ timeout: timeoutMs / 1e3,
43467
43467
  lastEntryId: "0-0",
43468
43468
  clearOnSuccess: true,
43469
43469
  requestedAt: timeNowSeconds()
@@ -43517,18 +43517,18 @@ var InputPlaneInvocation = class _InputPlaneInvocation {
43517
43517
  attemptStartResponse.attemptToken
43518
43518
  );
43519
43519
  }
43520
- async awaitOutput(timeout) {
43520
+ async awaitOutput(timeoutMs) {
43521
43521
  return await pollFunctionOutput(
43522
43522
  this.cpClient,
43523
- (timeoutMillis) => this.#getOutput(timeoutMillis),
43524
- timeout
43523
+ (timeoutMs2) => this.#getOutput(timeoutMs2),
43524
+ timeoutMs
43525
43525
  );
43526
43526
  }
43527
- async #getOutput(timeoutMillis) {
43527
+ async #getOutput(timeoutMs) {
43528
43528
  const response = await this.ipClient.attemptAwait({
43529
43529
  attemptToken: this.attemptToken,
43530
43530
  requestedAt: timeNowSeconds(),
43531
- timeoutSecs: timeoutMillis / 1e3
43531
+ timeoutSecs: timeoutMs / 1e3
43532
43532
  });
43533
43533
  return response.output;
43534
43534
  }
@@ -43544,24 +43544,24 @@ var InputPlaneInvocation = class _InputPlaneInvocation {
43544
43544
  function timeNowSeconds() {
43545
43545
  return Date.now() / 1e3;
43546
43546
  }
43547
- async function pollFunctionOutput(cpClient, getOutput, timeout) {
43547
+ async function pollFunctionOutput(cpClient, getOutput, timeoutMs) {
43548
43548
  const startTime = Date.now();
43549
- let pollTimeout = outputsTimeout;
43550
- if (timeout !== void 0) {
43551
- pollTimeout = Math.min(timeout, outputsTimeout);
43549
+ let pollTimeoutMs = outputsTimeoutMs;
43550
+ if (timeoutMs !== void 0) {
43551
+ pollTimeoutMs = Math.min(timeoutMs, outputsTimeoutMs);
43552
43552
  }
43553
43553
  while (true) {
43554
- const output = await getOutput(pollTimeout);
43554
+ const output = await getOutput(pollTimeoutMs);
43555
43555
  if (output) {
43556
43556
  return await processResult(cpClient, output.result, output.dataFormat);
43557
43557
  }
43558
- if (timeout !== void 0) {
43559
- const remainingTime = timeout - (Date.now() - startTime);
43560
- if (remainingTime <= 0) {
43561
- const message = `Timeout exceeded: ${(timeout / 1e3).toFixed(1)}s`;
43558
+ if (timeoutMs !== void 0) {
43559
+ const remainingMs = timeoutMs - (Date.now() - startTime);
43560
+ if (remainingMs <= 0) {
43561
+ const message = `Timeout exceeded: ${timeoutMs}ms`;
43562
43562
  throw new FunctionTimeoutError(message);
43563
43563
  }
43564
- pollTimeout = Math.min(outputsTimeout, remainingTime);
43564
+ pollTimeoutMs = Math.min(outputsTimeoutMs, remainingMs);
43565
43565
  }
43566
43566
  }
43567
43567
  }
@@ -43616,6 +43616,18 @@ function deserializeDataFormat(data, dataFormat) {
43616
43616
  }
43617
43617
  }
43618
43618
 
43619
+ // src/validation.ts
43620
+ function checkForRenamedParams(params, renames) {
43621
+ if (!params) return;
43622
+ for (const [oldName, newName] of Object.entries(renames)) {
43623
+ if (oldName in params) {
43624
+ throw new Error(
43625
+ `Parameter '${oldName}' has been renamed to '${newName}'.`
43626
+ );
43627
+ }
43628
+ }
43629
+ }
43630
+
43619
43631
  // src/function_call.ts
43620
43632
  var FunctionCallService = class {
43621
43633
  #client;
@@ -43645,12 +43657,12 @@ var FunctionCall = class _FunctionCall {
43645
43657
  }
43646
43658
  /** Get the result of a FunctionCall, optionally waiting with a timeout. */
43647
43659
  async get(params = {}) {
43648
- const timeout = params.timeout;
43660
+ checkForRenamedParams(params, { timeout: "timeoutMs" });
43649
43661
  const invocation = ControlPlaneInvocation.fromFunctionCallId(
43650
43662
  this.#client || getDefaultClient(),
43651
43663
  this.functionCallId
43652
43664
  );
43653
- return invocation.awaitOutput(timeout);
43665
+ return invocation.awaitOutput(params.timeoutMs);
43654
43666
  }
43655
43667
  /** Cancel a running FunctionCall. */
43656
43668
  async cancel(params = {}) {
@@ -43690,6 +43702,15 @@ var FunctionService = class {
43690
43702
  objectTag: name,
43691
43703
  environmentName: this.#client.environmentName(params.environment)
43692
43704
  });
43705
+ this.#client.logger.debug(
43706
+ "Retrieved Function",
43707
+ "function_id",
43708
+ resp.functionId,
43709
+ "app_name",
43710
+ appName,
43711
+ "function_name",
43712
+ name
43713
+ );
43693
43714
  return new Function_(
43694
43715
  this.#client,
43695
43716
  resp.functionId,
@@ -43721,16 +43742,42 @@ var Function_ = class {
43721
43742
  static async lookup(appName, name, params = {}) {
43722
43743
  return await getDefaultClient().functions.fromName(appName, name, params);
43723
43744
  }
43745
+ #checkNoWebUrl(fnName) {
43746
+ if (this.#handleMetadata?.webUrl) {
43747
+ throw new InvalidError(
43748
+ `A webhook Function cannot be invoked for remote execution with '.${fnName}'. Invoke this Function via its web url '${this.#handleMetadata.webUrl}' instead.`
43749
+ );
43750
+ }
43751
+ }
43724
43752
  // Execute a single input into a remote Function.
43725
43753
  async remote(args = [], kwargs = {}) {
43754
+ this.#client.logger.debug(
43755
+ "Executing function call",
43756
+ "function_id",
43757
+ this.functionId
43758
+ );
43759
+ this.#checkNoWebUrl("remote");
43726
43760
  const input = await this.#createInput(args, kwargs);
43727
43761
  const invocation = await this.#createRemoteInvocation(input);
43728
43762
  let retryCount = 0;
43729
43763
  while (true) {
43730
43764
  try {
43731
- return await invocation.awaitOutput();
43765
+ const result = await invocation.awaitOutput();
43766
+ this.#client.logger.debug(
43767
+ "Function call completed",
43768
+ "function_id",
43769
+ this.functionId
43770
+ );
43771
+ return result;
43732
43772
  } catch (err) {
43733
43773
  if (err instanceof InternalFailure && retryCount <= maxSystemRetries) {
43774
+ this.#client.logger.debug(
43775
+ "Retrying function call due to internal failure",
43776
+ "function_id",
43777
+ this.functionId,
43778
+ "retry_count",
43779
+ retryCount
43780
+ );
43734
43781
  await invocation.retry(retryCount);
43735
43782
  retryCount++;
43736
43783
  } else {
@@ -43757,6 +43804,12 @@ var Function_ = class {
43757
43804
  }
43758
43805
  // Spawn a single input into a remote Function.
43759
43806
  async spawn(args = [], kwargs = {}) {
43807
+ this.#client.logger.debug(
43808
+ "Spawning function call",
43809
+ "function_id",
43810
+ this.functionId
43811
+ );
43812
+ this.#checkNoWebUrl("spawn");
43760
43813
  const input = await this.#createInput(args, kwargs);
43761
43814
  const invocation = await ControlPlaneInvocation.create(
43762
43815
  this.#client,
@@ -43764,13 +43817,20 @@ var Function_ = class {
43764
43817
  input,
43765
43818
  3 /* FUNCTION_CALL_INVOCATION_TYPE_ASYNC */
43766
43819
  );
43820
+ this.#client.logger.debug(
43821
+ "Function call spawned",
43822
+ "function_id",
43823
+ this.functionId,
43824
+ "function_call_id",
43825
+ invocation.functionCallId
43826
+ );
43767
43827
  return new FunctionCall(this.#client, invocation.functionCallId);
43768
43828
  }
43769
43829
  // Returns statistics about the Function.
43770
43830
  async getCurrentStats() {
43771
43831
  const resp = await this.#client.cpClient.functionGetCurrentStats(
43772
43832
  { functionId: this.functionId },
43773
- { timeout: 1e4 }
43833
+ { timeoutMs: 1e4 }
43774
43834
  );
43775
43835
  return {
43776
43836
  backlog: resp.backlog,
@@ -43779,6 +43839,7 @@ var Function_ = class {
43779
43839
  }
43780
43840
  // Overrides the current autoscaler behavior for this Function.
43781
43841
  async updateAutoscaler(params) {
43842
+ checkForRenamedParams(params, { scaledownWindow: "scaledownWindowMs" });
43782
43843
  await this.#client.cpClient.functionUpdateSchedulingParams({
43783
43844
  functionId: this.functionId,
43784
43845
  warmPoolSizeOverride: 0,
@@ -43787,7 +43848,7 @@ var Function_ = class {
43787
43848
  minContainers: params.minContainers,
43788
43849
  maxContainers: params.maxContainers,
43789
43850
  bufferContainers: params.bufferContainers,
43790
- scaledownWindow: params.scaledownWindow
43851
+ scaledownWindow: params.scaledownWindowMs !== void 0 ? Math.trunc(params.scaledownWindowMs / 1e3) : void 0
43791
43852
  }
43792
43853
  });
43793
43854
  }
@@ -43802,7 +43863,7 @@ var Function_ = class {
43802
43863
  const supported_input_formats = this.#handleMetadata?.supportedInputFormats?.length ? this.#handleMetadata.supportedInputFormats : [1 /* DATA_FORMAT_PICKLE */];
43803
43864
  if (!supported_input_formats.includes(4 /* DATA_FORMAT_CBOR */)) {
43804
43865
  throw new InvalidError(
43805
- "the deployed Function does not support libmodal - please redeploy it using Modal Python SDK version >= 1.2"
43866
+ "cannot call Modal Function from JS SDK since it was deployed with an incompatible Python SDK version. Redeploy with Modal Python SDK >= 1.2"
43806
43867
  );
43807
43868
  }
43808
43869
  const payload = cborEncode([args, kwargs]);
@@ -43865,6 +43926,13 @@ var SecretService = class {
43865
43926
  environmentName: this.#client.environmentName(params?.environment),
43866
43927
  requiredKeys: params?.requiredKeys ?? []
43867
43928
  });
43929
+ this.#client.logger.debug(
43930
+ "Retrieved Secret",
43931
+ "secret_id",
43932
+ resp.secretId,
43933
+ "secret_name",
43934
+ name
43935
+ );
43868
43936
  return new Secret(resp.secretId, name);
43869
43937
  } catch (err) {
43870
43938
  if (err instanceof import_nice_grpc2.ClientError && err.code === import_nice_grpc2.Status.NOT_FOUND)
@@ -43889,6 +43957,11 @@ var SecretService = class {
43889
43957
  envDict: entries,
43890
43958
  environmentName: this.#client.environmentName(params?.environment)
43891
43959
  });
43960
+ this.#client.logger.debug(
43961
+ "Created ephemeral Secret",
43962
+ "secret_id",
43963
+ resp.secretId
43964
+ );
43892
43965
  return new Secret(resp.secretId);
43893
43966
  } catch (err) {
43894
43967
  if (err instanceof import_nice_grpc2.ClientError && (err.code === import_nice_grpc2.Status.INVALID_ARGUMENT || err.code === import_nice_grpc2.Status.FAILED_PRECONDITION))
@@ -44009,6 +44082,15 @@ var ClsService = class {
44009
44082
  `Unsupported parameter format: ${parameterInfo?.format}`
44010
44083
  );
44011
44084
  }
44085
+ this.#client.logger.debug(
44086
+ "Retrieved Cls",
44087
+ "function_id",
44088
+ serviceFunction.functionId,
44089
+ "app_name",
44090
+ appName,
44091
+ "cls_name",
44092
+ name
44093
+ );
44012
44094
  return new Cls(
44013
44095
  this.#client,
44014
44096
  serviceFunction.functionId,
@@ -44139,10 +44221,58 @@ function mergeServiceOptions(base, diff) {
44139
44221
  async function buildFunctionOptionsProto(options) {
44140
44222
  if (!options) return void 0;
44141
44223
  const o = options ?? {};
44224
+ checkForRenamedParams(o, {
44225
+ memory: "memoryMiB",
44226
+ memoryLimit: "memoryLimitMiB",
44227
+ scaledownWindow: "scaledownWindowMs",
44228
+ timeout: "timeoutMs"
44229
+ });
44142
44230
  const gpuConfig = parseGpuConfig(o.gpu);
44143
- const resources = o.cpu !== void 0 || o.memory !== void 0 || gpuConfig ? {
44144
- milliCpu: o.cpu !== void 0 ? Math.round(1e3 * o.cpu) : void 0,
44145
- memoryMb: o.memory,
44231
+ let milliCpu = void 0;
44232
+ let milliCpuMax = void 0;
44233
+ if (o.cpu === void 0 && o.cpuLimit !== void 0) {
44234
+ throw new Error("must also specify cpu when cpuLimit is specified");
44235
+ }
44236
+ if (o.cpu !== void 0) {
44237
+ if (o.cpu <= 0) {
44238
+ throw new Error(`cpu (${o.cpu}) must be a positive number`);
44239
+ }
44240
+ milliCpu = Math.trunc(1e3 * o.cpu);
44241
+ if (o.cpuLimit !== void 0) {
44242
+ if (o.cpuLimit < o.cpu) {
44243
+ throw new Error(
44244
+ `cpu (${o.cpu}) cannot be higher than cpuLimit (${o.cpuLimit})`
44245
+ );
44246
+ }
44247
+ milliCpuMax = Math.trunc(1e3 * o.cpuLimit);
44248
+ }
44249
+ }
44250
+ let memoryMb = void 0;
44251
+ let memoryMbMax = void 0;
44252
+ if (o.memoryMiB === void 0 && o.memoryLimitMiB !== void 0) {
44253
+ throw new Error(
44254
+ "must also specify memoryMiB when memoryLimitMiB is specified"
44255
+ );
44256
+ }
44257
+ if (o.memoryMiB !== void 0) {
44258
+ if (o.memoryMiB <= 0) {
44259
+ throw new Error(`memoryMiB (${o.memoryMiB}) must be a positive number`);
44260
+ }
44261
+ memoryMb = o.memoryMiB;
44262
+ if (o.memoryLimitMiB !== void 0) {
44263
+ if (o.memoryLimitMiB < o.memoryMiB) {
44264
+ throw new Error(
44265
+ `memoryMiB (${o.memoryMiB}) cannot be higher than memoryLimitMiB (${o.memoryLimitMiB})`
44266
+ );
44267
+ }
44268
+ memoryMbMax = o.memoryLimitMiB;
44269
+ }
44270
+ }
44271
+ const resources = milliCpu !== void 0 || milliCpuMax !== void 0 || memoryMb !== void 0 || memoryMbMax !== void 0 || gpuConfig ? {
44272
+ milliCpu,
44273
+ milliCpuMax,
44274
+ memoryMb,
44275
+ memoryMbMax,
44146
44276
  gpuConfig
44147
44277
  } : void 0;
44148
44278
  const secretIds = (o.secrets || []).map((s) => s.secretId);
@@ -44159,13 +44289,15 @@ async function buildFunctionOptionsProto(options) {
44159
44289
  initialDelayMs: parsedRetries.initialDelayMs,
44160
44290
  maxDelayMs: parsedRetries.maxDelayMs
44161
44291
  } : void 0;
44162
- if (o.scaledownWindow !== void 0 && o.scaledownWindow % 1e3 !== 0) {
44292
+ if (o.scaledownWindowMs !== void 0 && o.scaledownWindowMs % 1e3 !== 0) {
44163
44293
  throw new Error(
44164
- `scaledownWindow must be a multiple of 1000ms, got ${o.scaledownWindow}`
44294
+ `scaledownWindowMs must be a multiple of 1000ms, got ${o.scaledownWindowMs}`
44165
44295
  );
44166
44296
  }
44167
- if (o.timeout !== void 0 && o.timeout % 1e3 !== 0) {
44168
- throw new Error(`timeout must be a multiple of 1000ms, got ${o.timeout}`);
44297
+ if (o.timeoutMs !== void 0 && o.timeoutMs % 1e3 !== 0) {
44298
+ throw new Error(
44299
+ `timeoutMs must be a multiple of 1000ms, got ${o.timeoutMs}`
44300
+ );
44169
44301
  }
44170
44302
  const functionOptions = FunctionOptions.create({
44171
44303
  secretIds,
@@ -44176,8 +44308,8 @@ async function buildFunctionOptionsProto(options) {
44176
44308
  retryPolicy,
44177
44309
  concurrencyLimit: o.maxContainers,
44178
44310
  bufferContainers: o.bufferContainers,
44179
- taskIdleTimeoutSecs: o.scaledownWindow !== void 0 ? o.scaledownWindow / 1e3 : void 0,
44180
- timeoutSecs: o.timeout !== void 0 ? o.timeout / 1e3 : void 0,
44311
+ taskIdleTimeoutSecs: o.scaledownWindowMs !== void 0 ? o.scaledownWindowMs / 1e3 : void 0,
44312
+ timeoutSecs: o.timeoutMs !== void 0 ? o.timeoutMs / 1e3 : void 0,
44181
44313
  maxConcurrentInputs: o.maxConcurrentInputs,
44182
44314
  targetConcurrentInputs: o.targetConcurrentInputs,
44183
44315
  batchMaxSize: o.batchMaxSize,
@@ -44337,8 +44469,15 @@ var ImageService = class {
44337
44469
  * Delete an {@link Image} by ID. Warning: This removes an *entire Image*, and cannot be undone.
44338
44470
  */
44339
44471
  async delete(imageId, _ = {}) {
44340
- const image = await this.fromId(imageId);
44341
- await this.#client.cpClient.imageDelete({ imageId: image.imageId });
44472
+ try {
44473
+ await this.#client.cpClient.imageDelete({ imageId });
44474
+ } catch (err) {
44475
+ if (err instanceof import_nice_grpc4.ClientError && err.code === import_nice_grpc5.Status.NOT_FOUND)
44476
+ throw new NotFoundError(err.details);
44477
+ if (err instanceof import_nice_grpc4.ClientError && err.code === import_nice_grpc5.Status.FAILED_PRECONDITION && err.details.includes("Could not find image with ID"))
44478
+ throw new NotFoundError(err.details);
44479
+ throw err;
44480
+ }
44342
44481
  }
44343
44482
  };
44344
44483
  var Image2 = class _Image {
@@ -44436,6 +44575,7 @@ var Image2 = class _Image {
44436
44575
  if (this.imageId !== "") {
44437
44576
  return this;
44438
44577
  }
44578
+ this.#client.logger.debug("Building image", "app_id", app.appId);
44439
44579
  let baseImageId;
44440
44580
  for (let i = 0; i < this.#layers.length; i++) {
44441
44581
  const layer = this.#layers[i];
@@ -44510,6 +44650,7 @@ ${result.exception}`
44510
44650
  baseImageId = resp.imageId;
44511
44651
  }
44512
44652
  this.#imageId = baseImageId;
44653
+ this.#client.logger.debug("Image build completed", "image_id", baseImageId);
44513
44654
  return this;
44514
44655
  }
44515
44656
  /**
@@ -44957,8 +45098,8 @@ var EphemeralHeartbeatManager = class {
44957
45098
  };
44958
45099
 
44959
45100
  // src/queue.ts
44960
- var queueInitialPutBackoff = 100;
44961
- var queueDefaultPartitionTtl = 24 * 3600 * 1e3;
45101
+ var queueInitialPutBackoffMs = 100;
45102
+ var queueDefaultPartitionTtlMs = 24 * 3600 * 1e3;
44962
45103
  var QueueService = class {
44963
45104
  #client;
44964
45105
  constructor(client2) {
@@ -44973,6 +45114,11 @@ var QueueService = class {
44973
45114
  objectCreationType: 5 /* OBJECT_CREATION_TYPE_EPHEMERAL */,
44974
45115
  environmentName: this.#client.environmentName(params.environment)
44975
45116
  });
45117
+ this.#client.logger.debug(
45118
+ "Created ephemeral Queue",
45119
+ "queue_id",
45120
+ resp.queueId
45121
+ );
44976
45122
  const ephemeralHbManager = new EphemeralHeartbeatManager(
44977
45123
  () => this.#client.cpClient.queueHeartbeat({ queueId: resp.queueId })
44978
45124
  );
@@ -44987,6 +45133,13 @@ var QueueService = class {
44987
45133
  objectCreationType: params.createIfMissing ? 1 /* OBJECT_CREATION_TYPE_CREATE_IF_MISSING */ : void 0,
44988
45134
  environmentName: this.#client.environmentName(params.environment)
44989
45135
  });
45136
+ this.#client.logger.debug(
45137
+ "Retrieved Queue",
45138
+ "queue_id",
45139
+ resp.queueId,
45140
+ "queue_name",
45141
+ name
45142
+ );
44990
45143
  return new Queue(this.#client, resp.queueId, name);
44991
45144
  }
44992
45145
  /**
@@ -45062,30 +45215,30 @@ var Queue = class _Queue {
45062
45215
  allPartitions: params.all
45063
45216
  });
45064
45217
  }
45065
- async #get(n, partition, timeout) {
45218
+ async #get(n, partition, timeoutMs) {
45066
45219
  const partitionKey = _Queue.#validatePartitionKey(partition);
45067
45220
  const startTime = Date.now();
45068
- let pollTimeout = 5e4;
45069
- if (timeout !== void 0) {
45070
- pollTimeout = Math.min(pollTimeout, timeout);
45221
+ let pollTimeoutMs = 5e4;
45222
+ if (timeoutMs !== void 0) {
45223
+ pollTimeoutMs = Math.min(pollTimeoutMs, timeoutMs);
45071
45224
  }
45072
45225
  while (true) {
45073
45226
  const response = await this.#client.cpClient.queueGet({
45074
45227
  queueId: this.queueId,
45075
45228
  partitionKey,
45076
- timeout: pollTimeout / 1e3,
45229
+ timeout: pollTimeoutMs / 1e3,
45077
45230
  nValues: n
45078
45231
  });
45079
45232
  if (response.values && response.values.length > 0) {
45080
45233
  return response.values.map((value) => loads(value));
45081
45234
  }
45082
- if (timeout !== void 0) {
45083
- const remaining = timeout - (Date.now() - startTime);
45084
- if (remaining <= 0) {
45085
- const message = `Queue ${this.queueId} did not return values within ${timeout}ms.`;
45235
+ if (timeoutMs !== void 0) {
45236
+ const remainingMs = timeoutMs - (Date.now() - startTime);
45237
+ if (remainingMs <= 0) {
45238
+ const message = `Queue ${this.queueId} did not return values within ${timeoutMs}ms.`;
45086
45239
  throw new QueueEmptyError(message);
45087
45240
  }
45088
- pollTimeout = Math.min(pollTimeout, remaining);
45241
+ pollTimeoutMs = Math.min(pollTimeoutMs, remainingMs);
45089
45242
  }
45090
45243
  }
45091
45244
  }
@@ -45093,35 +45246,37 @@ var Queue = class _Queue {
45093
45246
  * Remove and return the next object from the Queue.
45094
45247
  *
45095
45248
  * By default, this will wait until at least one item is present in the Queue.
45096
- * If `timeout` is set, raises `QueueEmptyError` if no items are available
45249
+ * If `timeoutMs` is set, raises `QueueEmptyError` if no items are available
45097
45250
  * within that timeout in milliseconds.
45098
45251
  */
45099
45252
  async get(params = {}) {
45100
- const values = await this.#get(1, params.partition, params.timeout);
45253
+ checkForRenamedParams(params, { timeout: "timeoutMs" });
45254
+ const values = await this.#get(1, params.partition, params.timeoutMs);
45101
45255
  return values[0];
45102
45256
  }
45103
45257
  /**
45104
45258
  * Remove and return up to `n` objects from the Queue.
45105
45259
  *
45106
45260
  * By default, this will wait until at least one item is present in the Queue.
45107
- * If `timeout` is set, raises `QueueEmptyError` if no items are available
45261
+ * If `timeoutMs` is set, raises `QueueEmptyError` if no items are available
45108
45262
  * within that timeout in milliseconds.
45109
45263
  */
45110
45264
  async getMany(n, params = {}) {
45111
- return await this.#get(n, params.partition, params.timeout);
45265
+ checkForRenamedParams(params, { timeout: "timeoutMs" });
45266
+ return await this.#get(n, params.partition, params.timeoutMs);
45112
45267
  }
45113
- async #put(values, timeout, partition, partitionTtl) {
45268
+ async #put(values, timeoutMs, partition, partitionTtlMs) {
45114
45269
  const valuesEncoded = values.map((v) => dumps(v));
45115
45270
  const partitionKey = _Queue.#validatePartitionKey(partition);
45116
- let delay = queueInitialPutBackoff;
45117
- const deadline = timeout ? Date.now() + timeout : void 0;
45271
+ let delay = queueInitialPutBackoffMs;
45272
+ const deadline = timeoutMs ? Date.now() + timeoutMs : void 0;
45118
45273
  while (true) {
45119
45274
  try {
45120
45275
  await this.#client.cpClient.queuePut({
45121
45276
  queueId: this.queueId,
45122
45277
  values: valuesEncoded,
45123
45278
  partitionKey,
45124
- partitionTtlSeconds: (partitionTtl || queueDefaultPartitionTtl) / 1e3
45279
+ partitionTtlSeconds: (partitionTtlMs || queueDefaultPartitionTtlMs) / 1e3
45125
45280
  });
45126
45281
  break;
45127
45282
  } catch (e) {
@@ -45144,25 +45299,38 @@ var Queue = class _Queue {
45144
45299
  * Add an item to the end of the Queue.
45145
45300
  *
45146
45301
  * If the Queue is full, this will retry with exponential backoff until the
45147
- * provided `timeout` is reached, or indefinitely if `timeout` is not set.
45302
+ * provided `timeoutMs` is reached, or indefinitely if `timeoutMs` is not set.
45148
45303
  * Raises {@link QueueFullError} if the Queue is still full after the timeout.
45149
45304
  */
45150
45305
  async put(v, params = {}) {
45151
- await this.#put([v], params.timeout, params.partition, params.partitionTtl);
45306
+ checkForRenamedParams(params, {
45307
+ timeout: "timeoutMs",
45308
+ partitionTtl: "partitionTtlMs"
45309
+ });
45310
+ await this.#put(
45311
+ [v],
45312
+ params.timeoutMs,
45313
+ params.partition,
45314
+ params.partitionTtlMs
45315
+ );
45152
45316
  }
45153
45317
  /**
45154
45318
  * Add several items to the end of the Queue.
45155
45319
  *
45156
45320
  * If the Queue is full, this will retry with exponential backoff until the
45157
- * provided `timeout` is reached, or indefinitely if `timeout` is not set.
45321
+ * provided `timeoutMs` is reached, or indefinitely if `timeoutMs` is not set.
45158
45322
  * Raises {@link QueueFullError} if the Queue is still full after the timeout.
45159
45323
  */
45160
45324
  async putMany(values, params = {}) {
45325
+ checkForRenamedParams(params, {
45326
+ timeout: "timeoutMs",
45327
+ partitionTtl: "partitionTtlMs"
45328
+ });
45161
45329
  await this.#put(
45162
45330
  values,
45163
- params.timeout,
45331
+ params.timeoutMs,
45164
45332
  params.partition,
45165
- params.partitionTtl
45333
+ params.partitionTtlMs
45166
45334
  );
45167
45335
  }
45168
45336
  /** Return the number of objects in the Queue. */
@@ -45181,20 +45349,21 @@ var Queue = class _Queue {
45181
45349
  }
45182
45350
  /** Iterate through items in a Queue without mutation. */
45183
45351
  async *iterate(params = {}) {
45184
- const { partition, itemPollTimeout = 0 } = params;
45352
+ checkForRenamedParams(params, { itemPollTimeout: "itemPollTimeoutMs" });
45353
+ const { partition, itemPollTimeoutMs = 0 } = params;
45185
45354
  let lastEntryId = void 0;
45186
45355
  const validatedPartitionKey = _Queue.#validatePartitionKey(partition);
45187
- let fetchDeadline = Date.now() + itemPollTimeout;
45188
- const maxPollDuration = 3e4;
45356
+ let fetchDeadline = Date.now() + itemPollTimeoutMs;
45357
+ const maxPollDurationMs = 3e4;
45189
45358
  while (true) {
45190
- const pollDuration = Math.max(
45359
+ const pollDurationMs = Math.max(
45191
45360
  0,
45192
- Math.min(maxPollDuration, fetchDeadline - Date.now())
45361
+ Math.min(maxPollDurationMs, fetchDeadline - Date.now())
45193
45362
  );
45194
45363
  const request = {
45195
45364
  queueId: this.queueId,
45196
45365
  partitionKey: validatedPartitionKey,
45197
- itemPollTimeout: pollDuration / 1e3,
45366
+ itemPollTimeout: pollDurationMs / 1e3,
45198
45367
  lastEntryId: lastEntryId || ""
45199
45368
  };
45200
45369
  const response = await this.#client.cpClient.queueNextItems(request);
@@ -45203,7 +45372,7 @@ var Queue = class _Queue {
45203
45372
  yield loads(item.value);
45204
45373
  lastEntryId = item.entryId;
45205
45374
  }
45206
- fetchDeadline = Date.now() + itemPollTimeout;
45375
+ fetchDeadline = Date.now() + itemPollTimeoutMs;
45207
45376
  } else if (Date.now() > fetchDeadline) {
45208
45377
  break;
45209
45378
  }
@@ -45490,15 +45659,21 @@ function cloudBucketMountToProto(mount, mountPath) {
45490
45659
 
45491
45660
  // src/sandbox.ts
45492
45661
  async function buildSandboxCreateRequestProto(appId, imageId, params = {}) {
45662
+ checkForRenamedParams(params, {
45663
+ memory: "memoryMiB",
45664
+ memoryLimit: "memoryLimitMiB",
45665
+ timeout: "timeoutMs",
45666
+ idleTimeout: "idleTimeoutMs"
45667
+ });
45493
45668
  const gpuConfig = parseGpuConfig(params.gpu);
45494
- if (params.timeout && params.timeout % 1e3 !== 0) {
45669
+ if (params.timeoutMs && params.timeoutMs % 1e3 !== 0) {
45495
45670
  throw new Error(
45496
- `timeout must be a multiple of 1000ms, got ${params.timeout}`
45671
+ `timeoutMs must be a multiple of 1000ms, got ${params.timeoutMs}`
45497
45672
  );
45498
45673
  }
45499
- if (params.idleTimeout && params.idleTimeout % 1e3 !== 0) {
45674
+ if (params.idleTimeoutMs && params.idleTimeoutMs % 1e3 !== 0) {
45500
45675
  throw new Error(
45501
- `idleTimeout must be a multiple of 1000ms, got ${params.idleTimeout}`
45676
+ `idleTimeoutMs must be a multiple of 1000ms, got ${params.idleTimeoutMs}`
45502
45677
  );
45503
45678
  }
45504
45679
  if (params.workdir && !params.workdir.startsWith("/")) {
@@ -45569,20 +45744,63 @@ async function buildSandboxCreateRequestProto(appId, imageId, params = {}) {
45569
45744
  if (params.pty) {
45570
45745
  ptyInfo = defaultSandboxPTYInfo();
45571
45746
  }
45747
+ let milliCpu = void 0;
45748
+ let milliCpuMax = void 0;
45749
+ if (params.cpu === void 0 && params.cpuLimit !== void 0) {
45750
+ throw new Error("must also specify cpu when cpuLimit is specified");
45751
+ }
45752
+ if (params.cpu !== void 0) {
45753
+ if (params.cpu <= 0) {
45754
+ throw new Error(`cpu (${params.cpu}) must be a positive number`);
45755
+ }
45756
+ milliCpu = Math.trunc(1e3 * params.cpu);
45757
+ if (params.cpuLimit !== void 0) {
45758
+ if (params.cpuLimit < params.cpu) {
45759
+ throw new Error(
45760
+ `cpu (${params.cpu}) cannot be higher than cpuLimit (${params.cpuLimit})`
45761
+ );
45762
+ }
45763
+ milliCpuMax = Math.trunc(1e3 * params.cpuLimit);
45764
+ }
45765
+ }
45766
+ let memoryMb = void 0;
45767
+ let memoryMbMax = void 0;
45768
+ if (params.memoryMiB === void 0 && params.memoryLimitMiB !== void 0) {
45769
+ throw new Error(
45770
+ "must also specify memoryMiB when memoryLimitMiB is specified"
45771
+ );
45772
+ }
45773
+ if (params.memoryMiB !== void 0) {
45774
+ if (params.memoryMiB <= 0) {
45775
+ throw new Error(
45776
+ `the memoryMiB request (${params.memoryMiB}) must be a positive number`
45777
+ );
45778
+ }
45779
+ memoryMb = params.memoryMiB;
45780
+ if (params.memoryLimitMiB !== void 0) {
45781
+ if (params.memoryLimitMiB < params.memoryMiB) {
45782
+ throw new Error(
45783
+ `the memoryMiB request (${params.memoryMiB}) cannot be higher than memoryLimitMiB (${params.memoryLimitMiB})`
45784
+ );
45785
+ }
45786
+ memoryMbMax = params.memoryLimitMiB;
45787
+ }
45788
+ }
45572
45789
  return SandboxCreateRequest.create({
45573
45790
  appId,
45574
45791
  definition: {
45575
45792
  // Sleep default is implicit in image builder version <=2024.10
45576
45793
  entrypointArgs: params.command ?? ["sleep", "48h"],
45577
45794
  imageId,
45578
- timeoutSecs: params.timeout != void 0 ? params.timeout / 1e3 : 600,
45579
- idleTimeoutSecs: params.idleTimeout != void 0 ? params.idleTimeout / 1e3 : void 0,
45795
+ timeoutSecs: params.timeoutMs != void 0 ? params.timeoutMs / 1e3 : 600,
45796
+ idleTimeoutSecs: params.idleTimeoutMs != void 0 ? params.idleTimeoutMs / 1e3 : void 0,
45580
45797
  workdir: params.workdir ?? void 0,
45581
45798
  networkAccess,
45582
45799
  resources: {
45583
- // https://modal.com/docs/guide/resources
45584
- milliCpu: Math.round(1e3 * (params.cpu ?? 0.125)),
45585
- memoryMb: params.memory ?? 128,
45800
+ milliCpu,
45801
+ milliCpuMax,
45802
+ memoryMb,
45803
+ memoryMbMax,
45586
45804
  gpuConfig
45587
45805
  },
45588
45806
  volumeMounts,
@@ -45633,6 +45851,11 @@ var SandboxService = class {
45633
45851
  }
45634
45852
  throw err;
45635
45853
  }
45854
+ this.#client.logger.debug(
45855
+ "Created Sandbox",
45856
+ "sandbox_id",
45857
+ createResp.sandboxId
45858
+ );
45636
45859
  return new Sandbox2(this.#client, createResp.sandboxId);
45637
45860
  }
45638
45861
  /** Returns a running {@link Sandbox} object from an ID.
@@ -45757,6 +45980,7 @@ function defaultSandboxPTYInfo() {
45757
45980
  });
45758
45981
  }
45759
45982
  async function buildContainerExecRequestProto(taskId, command, params) {
45983
+ checkForRenamedParams(params, { timeout: "timeoutMs" });
45760
45984
  const secretIds = (params?.secrets || []).map((secret) => secret.secretId);
45761
45985
  let ptyInfo;
45762
45986
  if (params?.pty) {
@@ -45766,7 +45990,7 @@ async function buildContainerExecRequestProto(taskId, command, params) {
45766
45990
  taskId,
45767
45991
  command,
45768
45992
  workdir: params?.workdir,
45769
- timeoutSecs: params?.timeout ? params.timeout / 1e3 : 0,
45993
+ timeoutSecs: params?.timeoutMs ? params.timeoutMs / 1e3 : 0,
45770
45994
  secretIds,
45771
45995
  ptyInfo
45772
45996
  });
@@ -45892,6 +46116,15 @@ var Sandbox2 = class _Sandbox {
45892
46116
  mergedParams
45893
46117
  );
45894
46118
  const resp = await this.#client.cpClient.containerExec(req);
46119
+ this.#client.logger.debug(
46120
+ "Created ContainerProcess",
46121
+ "exec_id",
46122
+ resp.execId,
46123
+ "sandbox_id",
46124
+ this.sandboxId,
46125
+ "command",
46126
+ command
46127
+ );
45895
46128
  return new ContainerProcess(this.#client, resp.execId, params);
45896
46129
  }
45897
46130
  async #getTaskId() {
@@ -45924,7 +46157,17 @@ var Sandbox2 = class _Sandbox {
45924
46157
  timeout: 10
45925
46158
  });
45926
46159
  if (resp.result) {
45927
- return _Sandbox.#getReturnCode(resp.result);
46160
+ const returnCode = _Sandbox.#getReturnCode(resp.result);
46161
+ this.#client.logger.debug(
46162
+ "Sandbox wait completed",
46163
+ "sandbox_id",
46164
+ this.sandboxId,
46165
+ "status",
46166
+ resp.result.status,
46167
+ "return_code",
46168
+ returnCode
46169
+ );
46170
+ return returnCode;
45928
46171
  }
45929
46172
  }
45930
46173
  }
@@ -45934,14 +46177,13 @@ var Sandbox2 = class _Sandbox {
45934
46177
  *
45935
46178
  * @returns A dictionary of {@link Tunnel} objects which are keyed by the container port.
45936
46179
  */
45937
- async tunnels(timeout = 5e4) {
46180
+ async tunnels(timeoutMs = 5e4) {
45938
46181
  if (this.#tunnels) {
45939
46182
  return this.#tunnels;
45940
46183
  }
45941
46184
  const resp = await this.#client.cpClient.sandboxGetTunnels({
45942
46185
  sandboxId: this.sandboxId,
45943
- timeout: timeout / 1e3
45944
- // Convert to seconds
46186
+ timeout: timeoutMs / 1e3
45945
46187
  });
45946
46188
  if (resp.result?.status === 4 /* GENERIC_STATUS_TIMEOUT */) {
45947
46189
  throw new SandboxTimeoutError();
@@ -45962,13 +46204,13 @@ var Sandbox2 = class _Sandbox {
45962
46204
  *
45963
46205
  * Returns an {@link Image} object which can be used to spawn a new Sandbox with the same filesystem.
45964
46206
  *
45965
- * @param timeout - Timeout for the snapshot operation in milliseconds
46207
+ * @param timeoutMs - Timeout for the snapshot operation in milliseconds
45966
46208
  * @returns Promise that resolves to an {@link Image}
45967
46209
  */
45968
- async snapshotFilesystem(timeout = 55e3) {
46210
+ async snapshotFilesystem(timeoutMs = 55e3) {
45969
46211
  const resp = await this.#client.cpClient.sandboxSnapshotFs({
45970
46212
  sandboxId: this.sandboxId,
45971
- timeout: timeout / 1e3
46213
+ timeout: timeoutMs / 1e3
45972
46214
  });
45973
46215
  if (resp.result?.status !== 1 /* GENERIC_STATUS_SUCCESS */) {
45974
46216
  throw new Error(
@@ -46190,6 +46432,13 @@ var VolumeService = class {
46190
46432
  environmentName: this.#client.environmentName(params?.environment),
46191
46433
  objectCreationType: params?.createIfMissing ? 1 /* OBJECT_CREATION_TYPE_CREATE_IF_MISSING */ : 0 /* OBJECT_CREATION_TYPE_UNSPECIFIED */
46192
46434
  });
46435
+ this.#client.logger.debug(
46436
+ "Retrieved Volume",
46437
+ "volume_id",
46438
+ resp.volumeId,
46439
+ "volume_name",
46440
+ name
46441
+ );
46193
46442
  return new Volume(resp.volumeId, name);
46194
46443
  } catch (err) {
46195
46444
  if (err instanceof import_nice_grpc9.ClientError && err.code === import_nice_grpc9.Status.NOT_FOUND)
@@ -46206,6 +46455,11 @@ var VolumeService = class {
46206
46455
  objectCreationType: 5 /* OBJECT_CREATION_TYPE_EPHEMERAL */,
46207
46456
  environmentName: this.#client.environmentName(params.environment)
46208
46457
  });
46458
+ this.#client.logger.debug(
46459
+ "Created ephemeral Volume",
46460
+ "volume_id",
46461
+ resp.volumeId
46462
+ );
46209
46463
  const ephemeralHbManager = new EphemeralHeartbeatManager(
46210
46464
  () => this.#client.cpClient.volumeHeartbeat({ volumeId: resp.volumeId })
46211
46465
  );
@@ -46258,9 +46512,17 @@ var import_node_fs = require("fs");
46258
46512
  var import_node_os = require("os");
46259
46513
  var import_node_path = __toESM(require("path"), 1);
46260
46514
  var import_smol_toml = require("smol-toml");
46515
+ function configFilePath() {
46516
+ const configPath = process.env["MODAL_CONFIG_PATH"];
46517
+ if (configPath && configPath !== "") {
46518
+ return configPath;
46519
+ }
46520
+ return import_node_path.default.join((0, import_node_os.homedir)(), ".modal.toml");
46521
+ }
46261
46522
  function readConfigFile() {
46262
46523
  try {
46263
- const configContent = (0, import_node_fs.readFileSync)(import_node_path.default.join((0, import_node_os.homedir)(), ".modal.toml"), {
46524
+ const configPath = configFilePath();
46525
+ const configContent = (0, import_node_fs.readFileSync)(configPath, {
46264
46526
  encoding: "utf-8"
46265
46527
  });
46266
46528
  return (0, import_smol_toml.parse)(configContent);
@@ -46287,7 +46549,8 @@ function getProfile(profileName) {
46287
46549
  tokenId: process.env["MODAL_TOKEN_ID"] || profileData.token_id,
46288
46550
  tokenSecret: process.env["MODAL_TOKEN_SECRET"] || profileData.token_secret,
46289
46551
  environment: process.env["MODAL_ENVIRONMENT"] || profileData.environment,
46290
- imageBuilderVersion: process.env["MODAL_IMAGE_BUILDER_VERSION"] || profileData.imageBuilderVersion
46552
+ imageBuilderVersion: process.env["MODAL_IMAGE_BUILDER_VERSION"] || profileData.imageBuilderVersion,
46553
+ logLevel: process.env["MODAL_LOGLEVEL"] || profileData.loglevel
46291
46554
  };
46292
46555
  return profile;
46293
46556
  }
@@ -46297,13 +46560,15 @@ var REFRESH_WINDOW = 5 * 60;
46297
46560
  var DEFAULT_EXPIRY_OFFSET = 20 * 60;
46298
46561
  var AuthTokenManager = class {
46299
46562
  client;
46563
+ logger;
46300
46564
  currentToken = "";
46301
46565
  tokenExpiry = 0;
46302
46566
  stopped = false;
46303
46567
  timeoutId = null;
46304
46568
  initialTokenPromise = null;
46305
- constructor(client2) {
46569
+ constructor(client2, logger) {
46306
46570
  this.client = client2;
46571
+ this.logger = logger;
46307
46572
  }
46308
46573
  /**
46309
46574
  * Returns the current cached token.
@@ -46334,9 +46599,19 @@ var AuthTokenManager = class {
46334
46599
  if (exp > 0) {
46335
46600
  this.tokenExpiry = exp;
46336
46601
  } else {
46337
- console.warn("Failed to decode x-modal-auth-token exp field");
46602
+ this.logger.warn("x-modal-auth-token does not contain exp field");
46338
46603
  this.tokenExpiry = Math.floor(Date.now() / 1e3) + DEFAULT_EXPIRY_OFFSET;
46339
46604
  }
46605
+ const now = Math.floor(Date.now() / 1e3);
46606
+ const expiresIn = this.tokenExpiry - now;
46607
+ const refreshIn = this.tokenExpiry - now - REFRESH_WINDOW;
46608
+ this.logger.debug(
46609
+ "Fetched auth token",
46610
+ "expires_in",
46611
+ `${expiresIn}s`,
46612
+ "refresh_in",
46613
+ `${refreshIn}s`
46614
+ );
46340
46615
  }
46341
46616
  /**
46342
46617
  * Background loop that refreshes tokens REFRESH_WINDOW seconds before they expire.
@@ -46356,7 +46631,7 @@ var AuthTokenManager = class {
46356
46631
  try {
46357
46632
  await this.fetchToken();
46358
46633
  } catch (error) {
46359
- console.error("Failed to refresh auth token:", error);
46634
+ this.logger.error("Failed to refresh auth token", "error", error);
46360
46635
  await new Promise((resolve) => setTimeout(resolve, 5e3));
46361
46636
  }
46362
46637
  }
@@ -46420,7 +46695,113 @@ var AuthTokenManager = class {
46420
46695
 
46421
46696
  // src/version.ts
46422
46697
  function getSDKVersion() {
46423
- return true ? "0.5.0-dev.7" : "0.0.0";
46698
+ return true ? "0.5.1" : "0.0.0";
46699
+ }
46700
+
46701
+ // src/logger.ts
46702
+ var LOG_LEVELS = {
46703
+ debug: 0,
46704
+ info: 1,
46705
+ warn: 2,
46706
+ error: 3
46707
+ };
46708
+ function parseLogLevel(level) {
46709
+ if (!level) {
46710
+ return "warn";
46711
+ }
46712
+ const normalized = level.toLowerCase();
46713
+ if (normalized === "debug" || normalized === "info" || normalized === "warn" || normalized === "warning" || normalized === "error") {
46714
+ return normalized === "warning" ? "warn" : normalized;
46715
+ }
46716
+ throw new Error(
46717
+ `Invalid log level value: "${level}" (must be debug, info, warn, or error)`
46718
+ );
46719
+ }
46720
+ var DefaultLogger = class {
46721
+ levelValue;
46722
+ constructor(level = "warn") {
46723
+ this.levelValue = LOG_LEVELS[level];
46724
+ }
46725
+ debug(message, ...args) {
46726
+ if (this.levelValue <= LOG_LEVELS.debug) {
46727
+ console.log(this.formatMessage("DEBUG", message, args));
46728
+ }
46729
+ }
46730
+ info(message, ...args) {
46731
+ if (this.levelValue <= LOG_LEVELS.info) {
46732
+ console.log(this.formatMessage("INFO", message, args));
46733
+ }
46734
+ }
46735
+ warn(message, ...args) {
46736
+ if (this.levelValue <= LOG_LEVELS.warn) {
46737
+ console.warn(this.formatMessage("WARN", message, args));
46738
+ }
46739
+ }
46740
+ error(message, ...args) {
46741
+ if (this.levelValue <= LOG_LEVELS.error) {
46742
+ console.error(this.formatMessage("ERROR", message, args));
46743
+ }
46744
+ }
46745
+ formatMessage(level, message, args) {
46746
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
46747
+ let formatted = `time=${timestamp} level=${level} msg="${message}"`;
46748
+ if (args.length > 0) {
46749
+ for (let i = 0; i < args.length; i += 2) {
46750
+ if (i + 1 < args.length) {
46751
+ const key = args[i];
46752
+ const value = args[i + 1];
46753
+ formatted += ` ${key}=${this.formatValue(value)}`;
46754
+ }
46755
+ }
46756
+ }
46757
+ return formatted;
46758
+ }
46759
+ formatValue(value) {
46760
+ if (typeof value === "string") {
46761
+ return value.includes(" ") ? `"${value}"` : value;
46762
+ }
46763
+ if (value instanceof Error) {
46764
+ return `"${value.message}"`;
46765
+ }
46766
+ if (Array.isArray(value)) {
46767
+ return `[${value.join(",")}]`;
46768
+ }
46769
+ return String(value);
46770
+ }
46771
+ };
46772
+ var FilteredLogger = class {
46773
+ constructor(logger, level) {
46774
+ this.logger = logger;
46775
+ this.levelValue = LOG_LEVELS[level];
46776
+ }
46777
+ levelValue;
46778
+ debug(message, ...args) {
46779
+ if (this.levelValue <= LOG_LEVELS.debug) {
46780
+ this.logger.debug(message, ...args);
46781
+ }
46782
+ }
46783
+ info(message, ...args) {
46784
+ if (this.levelValue <= LOG_LEVELS.info) {
46785
+ this.logger.info(message, ...args);
46786
+ }
46787
+ }
46788
+ warn(message, ...args) {
46789
+ if (this.levelValue <= LOG_LEVELS.warn) {
46790
+ this.logger.warn(message, ...args);
46791
+ }
46792
+ }
46793
+ error(message, ...args) {
46794
+ if (this.levelValue <= LOG_LEVELS.error) {
46795
+ this.logger.error(message, ...args);
46796
+ }
46797
+ }
46798
+ };
46799
+ function createLogger(logger, logLevel = "") {
46800
+ const level = parseLogLevel(logLevel);
46801
+ if (logger) {
46802
+ return new FilteredLogger(logger, level);
46803
+ }
46804
+ return new DefaultLogger(level);
46424
46805
  }
46425
46806
 
46426
46807
  // src/client.ts
@@ -46438,9 +46819,11 @@ var ModalClient = class {
46438
46819
  /** @ignore */
46439
46820
  cpClient;
46440
46821
  profile;
46822
+ logger;
46441
46823
  ipClients;
46442
46824
  authTokenManager = null;
46443
46825
  constructor(params) {
46826
+ checkForRenamedParams(params, { timeout: "timeoutMs" });
46444
46827
  const baseProfile = getProfile(process.env["MODAL_PROFILE"]);
46445
46828
  this.profile = {
46446
46829
  ...baseProfile,
@@ -46448,8 +46831,18 @@ var ModalClient = class {
46448
46831
  ...params?.tokenSecret && { tokenSecret: params.tokenSecret },
46449
46832
  ...params?.environment && { environment: params.environment }
46450
46833
  };
46834
+ const logLevelValue = params?.logLevel || this.profile.logLevel || "";
46835
+ this.logger = createLogger(params?.logger, logLevelValue);
46836
+ this.logger.debug(
46837
+ "Initializing Modal client",
46838
+ "version",
46839
+ getSDKVersion(),
46840
+ "server_url",
46841
+ this.profile.serverUrl
46842
+ );
46451
46843
  this.ipClients = /* @__PURE__ */ new Map();
46452
46844
  this.cpClient = params?.cpClient ?? this.createClient(this.profile);
46845
+ this.logger.debug("Modal client initialized successfully");
46453
46846
  this.apps = new AppService(this);
46454
46847
  this.cls = new ClsService(this);
46455
46848
  this.functions = new FunctionService(this);
@@ -46473,16 +46866,19 @@ var ModalClient = class {
46473
46866
  if (existing) {
46474
46867
  return existing;
46475
46868
  }
46869
+ this.logger.debug("Creating input plane client", "server_url", serverUrl);
46476
46870
  const profile = { ...this.profile, serverUrl };
46477
46871
  const newClient = this.createClient(profile);
46478
46872
  this.ipClients.set(serverUrl, newClient);
46479
46873
  return newClient;
46480
46874
  }
46481
46875
  close() {
46876
+ this.logger.debug("Closing Modal client");
46482
46877
  if (this.authTokenManager) {
46483
46878
  this.authTokenManager.stop();
46484
46879
  this.authTokenManager = null;
46485
46880
  }
46881
+ this.logger.debug("Modal client closed");
46486
46882
  }
46487
46883
  version() {
46488
46884
  return getSDKVersion();
@@ -46493,12 +46889,97 @@ var ModalClient = class {
46493
46889
  "grpc.max_send_message_length": 100 * 1024 * 1024,
46494
46890
  "grpc-node.flow_control_window": 64 * 1024 * 1024
46495
46891
  });
46496
- return (0, import_nice_grpc10.createClientFactory)().use(this.authMiddleware(profile)).use(retryMiddleware).use(timeoutMiddleware).create(ModalClientDefinition, channel);
46892
+ return (0, import_nice_grpc10.createClientFactory)().use(this.authMiddleware(profile)).use(this.retryMiddleware()).use(timeoutMiddleware).create(ModalClientDefinition, channel);
46893
+ }
46894
+ /** Middleware to retry transient errors and timeouts for unary requests. */
46895
+ retryMiddleware() {
46896
+ const logger = this.logger;
46897
+ return async function* retryMiddleware(call, options) {
46898
+ const {
46899
+ retries = 3,
46900
+ baseDelay = 100,
46901
+ maxDelay = 1e3,
46902
+ delayFactor = 2,
46903
+ additionalStatusCodes = [],
46904
+ signal,
46905
+ ...restOptions
46906
+ } = options;
46907
+ if (call.requestStream || call.responseStream || !retries) {
46908
+ return yield* call.next(call.request, restOptions);
46909
+ }
46910
+ const retryableCodes = /* @__PURE__ */ new Set([
46911
+ ...retryableGrpcStatusCodes,
46912
+ ...additionalStatusCodes
46913
+ ]);
46914
+ const idempotencyKey = (0, import_uuid.v4)();
46915
+ const startTime = Date.now();
46916
+ let attempt = 0;
46917
+ let delayMs = baseDelay;
46918
+ logger.debug("Sending gRPC request", "method", call.method.path);
46919
+ while (true) {
46920
+ const metadata = new import_nice_grpc10.Metadata(restOptions.metadata ?? {});
46921
+ metadata.set("x-idempotency-key", idempotencyKey);
46922
+ metadata.set("x-retry-attempt", String(attempt));
46923
+ if (attempt > 0) {
46924
+ metadata.set(
46925
+ "x-retry-delay",
46926
+ ((Date.now() - startTime) / 1e3).toFixed(3)
46927
+ );
46928
+ }
46929
+ try {
46930
+ return yield* call.next(call.request, {
46931
+ ...restOptions,
46932
+ metadata,
46933
+ signal
46934
+ });
46935
+ } catch (err) {
46936
+ if (!(err instanceof import_nice_grpc10.ClientError) || !retryableCodes.has(err.code) || attempt >= retries) {
46937
+ if (attempt === retries && attempt > 0) {
46938
+ logger.debug(
46939
+ "Final retry attempt failed",
46940
+ "error",
46941
+ err,
46942
+ "retries",
46943
+ attempt,
46944
+ "delay",
46945
+ delayMs,
46946
+ "method",
46947
+ call.method.path,
46948
+ "idempotency_key",
46949
+ idempotencyKey.substring(0, 8)
46950
+ );
46951
+ }
46952
+ throw err;
46953
+ }
46954
+ if (attempt > 0) {
46955
+ logger.debug(
46956
+ "Retryable failure",
46957
+ "error",
46958
+ err,
46959
+ "retries",
46960
+ attempt,
46961
+ "delay",
46962
+ delayMs,
46963
+ "method",
46964
+ call.method.path,
46965
+ "idempotency_key",
46966
+ idempotencyKey.substring(0, 8)
46967
+ );
46968
+ }
46969
+ await sleep(delayMs, signal);
46970
+ delayMs = Math.min(delayMs * delayFactor, maxDelay);
46971
+ attempt += 1;
46972
+ }
46973
+ }
46974
+ };
46497
46975
  }
46498
46976
  authMiddleware(profile) {
46499
46977
  const getOrCreateAuthTokenManager = () => {
46500
46978
  if (!this.authTokenManager) {
46501
- this.authTokenManager = new AuthTokenManager(this.cpClient);
46979
+ this.authTokenManager = new AuthTokenManager(
46980
+ this.cpClient,
46981
+ this.logger
46982
+ );
46502
46983
  this.authTokenManager.start();
46503
46984
  }
46504
46985
  return this.authTokenManager;
@@ -46534,10 +47015,10 @@ var ModalClient = class {
46534
47015
  }
46535
47016
  };
46536
47017
  var timeoutMiddleware = async function* timeoutMiddleware2(call, options) {
46537
- if (!options.timeout || options.signal?.aborted) {
47018
+ if (!options.timeoutMs || options.signal?.aborted) {
46538
47019
  return yield* call.next(call.request, options);
46539
47020
  }
46540
- const { timeout, signal: origSignal, ...restOptions } = options;
47021
+ const { timeoutMs, signal: origSignal, ...restOptions } = options;
46541
47022
  const abortController = new AbortController();
46542
47023
  const abortListener = () => abortController.abort();
46543
47024
  origSignal?.addEventListener("abort", abortListener);
@@ -46545,7 +47026,7 @@ var timeoutMiddleware = async function* timeoutMiddleware2(call, options) {
46545
47026
  const timer = setTimeout(() => {
46546
47027
  timedOut = true;
46547
47028
  abortController.abort();
46548
- }, timeout);
47029
+ }, timeoutMs);
46549
47030
  try {
46550
47031
  return yield* call.next(call.request, {
46551
47032
  ...restOptions,
@@ -46558,7 +47039,7 @@ var timeoutMiddleware = async function* timeoutMiddleware2(call, options) {
46558
47039
  throw new import_nice_grpc10.ClientError(
46559
47040
  call.method.path,
46560
47041
  import_nice_grpc10.Status.DEADLINE_EXCEEDED,
46561
- `Timed out after ${timeout}ms`
47042
+ `Timed out after ${timeoutMs}ms`
46562
47043
  );
46563
47044
  }
46564
47045
  }
@@ -46588,53 +47069,6 @@ var sleep = (ms, signal) => new Promise((resolve, reject) => {
46588
47069
  { once: true }
46589
47070
  );
46590
47071
  });
46591
- var retryMiddleware = async function* retryMiddleware2(call, options) {
46592
- const {
46593
- retries = 3,
46594
- baseDelay = 100,
46595
- maxDelay = 1e3,
46596
- delayFactor = 2,
46597
- additionalStatusCodes = [],
46598
- signal,
46599
- ...restOptions
46600
- } = options;
46601
- if (call.requestStream || call.responseStream || !retries) {
46602
- return yield* call.next(call.request, restOptions);
46603
- }
46604
- const retryableCodes = /* @__PURE__ */ new Set([
46605
- ...retryableGrpcStatusCodes,
46606
- ...additionalStatusCodes
46607
- ]);
46608
- const idempotencyKey = (0, import_uuid.v4)();
46609
- const startTime = Date.now();
46610
- let attempt = 0;
46611
- let delayMs = baseDelay;
46612
- while (true) {
46613
- const metadata = new import_nice_grpc10.Metadata(restOptions.metadata ?? {});
46614
- metadata.set("x-idempotency-key", idempotencyKey);
46615
- metadata.set("x-retry-attempt", String(attempt));
46616
- if (attempt > 0) {
46617
- metadata.set(
46618
- "x-retry-delay",
46619
- ((Date.now() - startTime) / 1e3).toFixed(3)
46620
- );
46621
- }
46622
- try {
46623
- return yield* call.next(call.request, {
46624
- ...restOptions,
46625
- metadata,
46626
- signal
46627
- });
46628
- } catch (err) {
46629
- if (!(err instanceof import_nice_grpc10.ClientError) || !retryableCodes.has(err.code) || attempt >= retries) {
46630
- throw err;
46631
- }
46632
- await sleep(delayMs, signal);
46633
- delayMs = Math.min(delayMs * delayFactor, maxDelay);
46634
- attempt += 1;
46635
- }
46636
- }
46637
- };
46638
47072
  var defaultClient;
46639
47073
  var defaultClientOptions;
46640
47074
  function getDefaultClient() {
@@ -46678,6 +47112,13 @@ var AppService = class {
46678
47112
  environmentName: this.#client.environmentName(params.environment),
46679
47113
  objectCreationType: params.createIfMissing ? 1 /* OBJECT_CREATION_TYPE_CREATE_IF_MISSING */ : 0 /* OBJECT_CREATION_TYPE_UNSPECIFIED */
46680
47114
  });
47115
+ this.#client.logger.debug(
47116
+ "Retrieved App",
47117
+ "app_id",
47118
+ resp.appId,
47119
+ "app_name",
47120
+ name
47121
+ );
46681
47122
  return new App2(resp.appId, name);
46682
47123
  } catch (err) {
46683
47124
  if (err instanceof import_nice_grpc11.ClientError && err.code === import_nice_grpc11.Status.NOT_FOUND)
@@ -46785,6 +47226,7 @@ var App2 = class {
46785
47226
  SecretService,
46786
47227
  Volume,
46787
47228
  VolumeService,
47229
+ checkForRenamedParams,
46788
47230
  close,
46789
47231
  initializeClient
46790
47232
  });