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.js CHANGED
@@ -43349,7 +43349,7 @@ function cborDecode(data) {
43349
43349
  }
43350
43350
 
43351
43351
  // src/invocation.ts
43352
- var outputsTimeout = 55 * 1e3;
43352
+ var outputsTimeoutMs = 55 * 1e3;
43353
43353
  var ControlPlaneInvocation = class _ControlPlaneInvocation {
43354
43354
  cpClient;
43355
43355
  functionCallId;
@@ -43385,19 +43385,18 @@ var ControlPlaneInvocation = class _ControlPlaneInvocation {
43385
43385
  static fromFunctionCallId(client2, functionCallId) {
43386
43386
  return new _ControlPlaneInvocation(client2.cpClient, functionCallId);
43387
43387
  }
43388
- async awaitOutput(timeout) {
43388
+ async awaitOutput(timeoutMs) {
43389
43389
  return await pollFunctionOutput(
43390
43390
  this.cpClient,
43391
- (timeoutMillis) => this.#getOutput(timeoutMillis),
43392
- timeout
43391
+ (timeoutMs2) => this.#getOutput(timeoutMs2),
43392
+ timeoutMs
43393
43393
  );
43394
43394
  }
43395
- async #getOutput(timeoutMillis) {
43395
+ async #getOutput(timeoutMs) {
43396
43396
  const response = await this.cpClient.functionGetOutputs({
43397
43397
  functionCallId: this.functionCallId,
43398
43398
  maxValues: 1,
43399
- timeout: timeoutMillis / 1e3,
43400
- // Backend needs seconds
43399
+ timeout: timeoutMs / 1e3,
43401
43400
  lastEntryId: "0-0",
43402
43401
  clearOnSuccess: true,
43403
43402
  requestedAt: timeNowSeconds()
@@ -43451,18 +43450,18 @@ var InputPlaneInvocation = class _InputPlaneInvocation {
43451
43450
  attemptStartResponse.attemptToken
43452
43451
  );
43453
43452
  }
43454
- async awaitOutput(timeout) {
43453
+ async awaitOutput(timeoutMs) {
43455
43454
  return await pollFunctionOutput(
43456
43455
  this.cpClient,
43457
- (timeoutMillis) => this.#getOutput(timeoutMillis),
43458
- timeout
43456
+ (timeoutMs2) => this.#getOutput(timeoutMs2),
43457
+ timeoutMs
43459
43458
  );
43460
43459
  }
43461
- async #getOutput(timeoutMillis) {
43460
+ async #getOutput(timeoutMs) {
43462
43461
  const response = await this.ipClient.attemptAwait({
43463
43462
  attemptToken: this.attemptToken,
43464
43463
  requestedAt: timeNowSeconds(),
43465
- timeoutSecs: timeoutMillis / 1e3
43464
+ timeoutSecs: timeoutMs / 1e3
43466
43465
  });
43467
43466
  return response.output;
43468
43467
  }
@@ -43478,24 +43477,24 @@ var InputPlaneInvocation = class _InputPlaneInvocation {
43478
43477
  function timeNowSeconds() {
43479
43478
  return Date.now() / 1e3;
43480
43479
  }
43481
- async function pollFunctionOutput(cpClient, getOutput, timeout) {
43480
+ async function pollFunctionOutput(cpClient, getOutput, timeoutMs) {
43482
43481
  const startTime = Date.now();
43483
- let pollTimeout = outputsTimeout;
43484
- if (timeout !== void 0) {
43485
- pollTimeout = Math.min(timeout, outputsTimeout);
43482
+ let pollTimeoutMs = outputsTimeoutMs;
43483
+ if (timeoutMs !== void 0) {
43484
+ pollTimeoutMs = Math.min(timeoutMs, outputsTimeoutMs);
43486
43485
  }
43487
43486
  while (true) {
43488
- const output = await getOutput(pollTimeout);
43487
+ const output = await getOutput(pollTimeoutMs);
43489
43488
  if (output) {
43490
43489
  return await processResult(cpClient, output.result, output.dataFormat);
43491
43490
  }
43492
- if (timeout !== void 0) {
43493
- const remainingTime = timeout - (Date.now() - startTime);
43494
- if (remainingTime <= 0) {
43495
- const message = `Timeout exceeded: ${(timeout / 1e3).toFixed(1)}s`;
43491
+ if (timeoutMs !== void 0) {
43492
+ const remainingMs = timeoutMs - (Date.now() - startTime);
43493
+ if (remainingMs <= 0) {
43494
+ const message = `Timeout exceeded: ${timeoutMs}ms`;
43496
43495
  throw new FunctionTimeoutError(message);
43497
43496
  }
43498
- pollTimeout = Math.min(outputsTimeout, remainingTime);
43497
+ pollTimeoutMs = Math.min(outputsTimeoutMs, remainingMs);
43499
43498
  }
43500
43499
  }
43501
43500
  }
@@ -43550,6 +43549,18 @@ function deserializeDataFormat(data, dataFormat) {
43550
43549
  }
43551
43550
  }
43552
43551
 
43552
+ // src/validation.ts
43553
+ function checkForRenamedParams(params, renames) {
43554
+ if (!params) return;
43555
+ for (const [oldName, newName] of Object.entries(renames)) {
43556
+ if (oldName in params) {
43557
+ throw new Error(
43558
+ `Parameter '${oldName}' has been renamed to '${newName}'.`
43559
+ );
43560
+ }
43561
+ }
43562
+ }
43563
+
43553
43564
  // src/function_call.ts
43554
43565
  var FunctionCallService = class {
43555
43566
  #client;
@@ -43579,12 +43590,12 @@ var FunctionCall = class _FunctionCall {
43579
43590
  }
43580
43591
  /** Get the result of a FunctionCall, optionally waiting with a timeout. */
43581
43592
  async get(params = {}) {
43582
- const timeout = params.timeout;
43593
+ checkForRenamedParams(params, { timeout: "timeoutMs" });
43583
43594
  const invocation = ControlPlaneInvocation.fromFunctionCallId(
43584
43595
  this.#client || getDefaultClient(),
43585
43596
  this.functionCallId
43586
43597
  );
43587
- return invocation.awaitOutput(timeout);
43598
+ return invocation.awaitOutput(params.timeoutMs);
43588
43599
  }
43589
43600
  /** Cancel a running FunctionCall. */
43590
43601
  async cancel(params = {}) {
@@ -43624,6 +43635,15 @@ var FunctionService = class {
43624
43635
  objectTag: name,
43625
43636
  environmentName: this.#client.environmentName(params.environment)
43626
43637
  });
43638
+ this.#client.logger.debug(
43639
+ "Retrieved Function",
43640
+ "function_id",
43641
+ resp.functionId,
43642
+ "app_name",
43643
+ appName,
43644
+ "function_name",
43645
+ name
43646
+ );
43627
43647
  return new Function_(
43628
43648
  this.#client,
43629
43649
  resp.functionId,
@@ -43655,16 +43675,42 @@ var Function_ = class {
43655
43675
  static async lookup(appName, name, params = {}) {
43656
43676
  return await getDefaultClient().functions.fromName(appName, name, params);
43657
43677
  }
43678
+ #checkNoWebUrl(fnName) {
43679
+ if (this.#handleMetadata?.webUrl) {
43680
+ throw new InvalidError(
43681
+ `A webhook Function cannot be invoked for remote execution with '.${fnName}'. Invoke this Function via its web url '${this.#handleMetadata.webUrl}' instead.`
43682
+ );
43683
+ }
43684
+ }
43658
43685
  // Execute a single input into a remote Function.
43659
43686
  async remote(args = [], kwargs = {}) {
43687
+ this.#client.logger.debug(
43688
+ "Executing function call",
43689
+ "function_id",
43690
+ this.functionId
43691
+ );
43692
+ this.#checkNoWebUrl("remote");
43660
43693
  const input = await this.#createInput(args, kwargs);
43661
43694
  const invocation = await this.#createRemoteInvocation(input);
43662
43695
  let retryCount = 0;
43663
43696
  while (true) {
43664
43697
  try {
43665
- return await invocation.awaitOutput();
43698
+ const result = await invocation.awaitOutput();
43699
+ this.#client.logger.debug(
43700
+ "Function call completed",
43701
+ "function_id",
43702
+ this.functionId
43703
+ );
43704
+ return result;
43666
43705
  } catch (err) {
43667
43706
  if (err instanceof InternalFailure && retryCount <= maxSystemRetries) {
43707
+ this.#client.logger.debug(
43708
+ "Retrying function call due to internal failure",
43709
+ "function_id",
43710
+ this.functionId,
43711
+ "retry_count",
43712
+ retryCount
43713
+ );
43668
43714
  await invocation.retry(retryCount);
43669
43715
  retryCount++;
43670
43716
  } else {
@@ -43691,6 +43737,12 @@ var Function_ = class {
43691
43737
  }
43692
43738
  // Spawn a single input into a remote Function.
43693
43739
  async spawn(args = [], kwargs = {}) {
43740
+ this.#client.logger.debug(
43741
+ "Spawning function call",
43742
+ "function_id",
43743
+ this.functionId
43744
+ );
43745
+ this.#checkNoWebUrl("spawn");
43694
43746
  const input = await this.#createInput(args, kwargs);
43695
43747
  const invocation = await ControlPlaneInvocation.create(
43696
43748
  this.#client,
@@ -43698,13 +43750,20 @@ var Function_ = class {
43698
43750
  input,
43699
43751
  3 /* FUNCTION_CALL_INVOCATION_TYPE_ASYNC */
43700
43752
  );
43753
+ this.#client.logger.debug(
43754
+ "Function call spawned",
43755
+ "function_id",
43756
+ this.functionId,
43757
+ "function_call_id",
43758
+ invocation.functionCallId
43759
+ );
43701
43760
  return new FunctionCall(this.#client, invocation.functionCallId);
43702
43761
  }
43703
43762
  // Returns statistics about the Function.
43704
43763
  async getCurrentStats() {
43705
43764
  const resp = await this.#client.cpClient.functionGetCurrentStats(
43706
43765
  { functionId: this.functionId },
43707
- { timeout: 1e4 }
43766
+ { timeoutMs: 1e4 }
43708
43767
  );
43709
43768
  return {
43710
43769
  backlog: resp.backlog,
@@ -43713,6 +43772,7 @@ var Function_ = class {
43713
43772
  }
43714
43773
  // Overrides the current autoscaler behavior for this Function.
43715
43774
  async updateAutoscaler(params) {
43775
+ checkForRenamedParams(params, { scaledownWindow: "scaledownWindowMs" });
43716
43776
  await this.#client.cpClient.functionUpdateSchedulingParams({
43717
43777
  functionId: this.functionId,
43718
43778
  warmPoolSizeOverride: 0,
@@ -43721,7 +43781,7 @@ var Function_ = class {
43721
43781
  minContainers: params.minContainers,
43722
43782
  maxContainers: params.maxContainers,
43723
43783
  bufferContainers: params.bufferContainers,
43724
- scaledownWindow: params.scaledownWindow
43784
+ scaledownWindow: params.scaledownWindowMs !== void 0 ? Math.trunc(params.scaledownWindowMs / 1e3) : void 0
43725
43785
  }
43726
43786
  });
43727
43787
  }
@@ -43736,7 +43796,7 @@ var Function_ = class {
43736
43796
  const supported_input_formats = this.#handleMetadata?.supportedInputFormats?.length ? this.#handleMetadata.supportedInputFormats : [1 /* DATA_FORMAT_PICKLE */];
43737
43797
  if (!supported_input_formats.includes(4 /* DATA_FORMAT_CBOR */)) {
43738
43798
  throw new InvalidError(
43739
- "the deployed Function does not support libmodal - please redeploy it using Modal Python SDK version >= 1.2"
43799
+ "cannot call Modal Function from JS SDK since it was deployed with an incompatible Python SDK version. Redeploy with Modal Python SDK >= 1.2"
43740
43800
  );
43741
43801
  }
43742
43802
  const payload = cborEncode([args, kwargs]);
@@ -43799,6 +43859,13 @@ var SecretService = class {
43799
43859
  environmentName: this.#client.environmentName(params?.environment),
43800
43860
  requiredKeys: params?.requiredKeys ?? []
43801
43861
  });
43862
+ this.#client.logger.debug(
43863
+ "Retrieved Secret",
43864
+ "secret_id",
43865
+ resp.secretId,
43866
+ "secret_name",
43867
+ name
43868
+ );
43802
43869
  return new Secret(resp.secretId, name);
43803
43870
  } catch (err) {
43804
43871
  if (err instanceof ClientError2 && err.code === Status2.NOT_FOUND)
@@ -43823,6 +43890,11 @@ var SecretService = class {
43823
43890
  envDict: entries,
43824
43891
  environmentName: this.#client.environmentName(params?.environment)
43825
43892
  });
43893
+ this.#client.logger.debug(
43894
+ "Created ephemeral Secret",
43895
+ "secret_id",
43896
+ resp.secretId
43897
+ );
43826
43898
  return new Secret(resp.secretId);
43827
43899
  } catch (err) {
43828
43900
  if (err instanceof ClientError2 && (err.code === Status2.INVALID_ARGUMENT || err.code === Status2.FAILED_PRECONDITION))
@@ -43943,6 +44015,15 @@ var ClsService = class {
43943
44015
  `Unsupported parameter format: ${parameterInfo?.format}`
43944
44016
  );
43945
44017
  }
44018
+ this.#client.logger.debug(
44019
+ "Retrieved Cls",
44020
+ "function_id",
44021
+ serviceFunction.functionId,
44022
+ "app_name",
44023
+ appName,
44024
+ "cls_name",
44025
+ name
44026
+ );
43946
44027
  return new Cls(
43947
44028
  this.#client,
43948
44029
  serviceFunction.functionId,
@@ -44073,10 +44154,58 @@ function mergeServiceOptions(base, diff) {
44073
44154
  async function buildFunctionOptionsProto(options) {
44074
44155
  if (!options) return void 0;
44075
44156
  const o = options ?? {};
44157
+ checkForRenamedParams(o, {
44158
+ memory: "memoryMiB",
44159
+ memoryLimit: "memoryLimitMiB",
44160
+ scaledownWindow: "scaledownWindowMs",
44161
+ timeout: "timeoutMs"
44162
+ });
44076
44163
  const gpuConfig = parseGpuConfig(o.gpu);
44077
- const resources = o.cpu !== void 0 || o.memory !== void 0 || gpuConfig ? {
44078
- milliCpu: o.cpu !== void 0 ? Math.round(1e3 * o.cpu) : void 0,
44079
- memoryMb: o.memory,
44164
+ let milliCpu = void 0;
44165
+ let milliCpuMax = void 0;
44166
+ if (o.cpu === void 0 && o.cpuLimit !== void 0) {
44167
+ throw new Error("must also specify cpu when cpuLimit is specified");
44168
+ }
44169
+ if (o.cpu !== void 0) {
44170
+ if (o.cpu <= 0) {
44171
+ throw new Error(`cpu (${o.cpu}) must be a positive number`);
44172
+ }
44173
+ milliCpu = Math.trunc(1e3 * o.cpu);
44174
+ if (o.cpuLimit !== void 0) {
44175
+ if (o.cpuLimit < o.cpu) {
44176
+ throw new Error(
44177
+ `cpu (${o.cpu}) cannot be higher than cpuLimit (${o.cpuLimit})`
44178
+ );
44179
+ }
44180
+ milliCpuMax = Math.trunc(1e3 * o.cpuLimit);
44181
+ }
44182
+ }
44183
+ let memoryMb = void 0;
44184
+ let memoryMbMax = void 0;
44185
+ if (o.memoryMiB === void 0 && o.memoryLimitMiB !== void 0) {
44186
+ throw new Error(
44187
+ "must also specify memoryMiB when memoryLimitMiB is specified"
44188
+ );
44189
+ }
44190
+ if (o.memoryMiB !== void 0) {
44191
+ if (o.memoryMiB <= 0) {
44192
+ throw new Error(`memoryMiB (${o.memoryMiB}) must be a positive number`);
44193
+ }
44194
+ memoryMb = o.memoryMiB;
44195
+ if (o.memoryLimitMiB !== void 0) {
44196
+ if (o.memoryLimitMiB < o.memoryMiB) {
44197
+ throw new Error(
44198
+ `memoryMiB (${o.memoryMiB}) cannot be higher than memoryLimitMiB (${o.memoryLimitMiB})`
44199
+ );
44200
+ }
44201
+ memoryMbMax = o.memoryLimitMiB;
44202
+ }
44203
+ }
44204
+ const resources = milliCpu !== void 0 || milliCpuMax !== void 0 || memoryMb !== void 0 || memoryMbMax !== void 0 || gpuConfig ? {
44205
+ milliCpu,
44206
+ milliCpuMax,
44207
+ memoryMb,
44208
+ memoryMbMax,
44080
44209
  gpuConfig
44081
44210
  } : void 0;
44082
44211
  const secretIds = (o.secrets || []).map((s) => s.secretId);
@@ -44093,13 +44222,15 @@ async function buildFunctionOptionsProto(options) {
44093
44222
  initialDelayMs: parsedRetries.initialDelayMs,
44094
44223
  maxDelayMs: parsedRetries.maxDelayMs
44095
44224
  } : void 0;
44096
- if (o.scaledownWindow !== void 0 && o.scaledownWindow % 1e3 !== 0) {
44225
+ if (o.scaledownWindowMs !== void 0 && o.scaledownWindowMs % 1e3 !== 0) {
44097
44226
  throw new Error(
44098
- `scaledownWindow must be a multiple of 1000ms, got ${o.scaledownWindow}`
44227
+ `scaledownWindowMs must be a multiple of 1000ms, got ${o.scaledownWindowMs}`
44099
44228
  );
44100
44229
  }
44101
- if (o.timeout !== void 0 && o.timeout % 1e3 !== 0) {
44102
- throw new Error(`timeout must be a multiple of 1000ms, got ${o.timeout}`);
44230
+ if (o.timeoutMs !== void 0 && o.timeoutMs % 1e3 !== 0) {
44231
+ throw new Error(
44232
+ `timeoutMs must be a multiple of 1000ms, got ${o.timeoutMs}`
44233
+ );
44103
44234
  }
44104
44235
  const functionOptions = FunctionOptions.create({
44105
44236
  secretIds,
@@ -44110,8 +44241,8 @@ async function buildFunctionOptionsProto(options) {
44110
44241
  retryPolicy,
44111
44242
  concurrencyLimit: o.maxContainers,
44112
44243
  bufferContainers: o.bufferContainers,
44113
- taskIdleTimeoutSecs: o.scaledownWindow !== void 0 ? o.scaledownWindow / 1e3 : void 0,
44114
- timeoutSecs: o.timeout !== void 0 ? o.timeout / 1e3 : void 0,
44244
+ taskIdleTimeoutSecs: o.scaledownWindowMs !== void 0 ? o.scaledownWindowMs / 1e3 : void 0,
44245
+ timeoutSecs: o.timeoutMs !== void 0 ? o.timeoutMs / 1e3 : void 0,
44115
44246
  maxConcurrentInputs: o.maxConcurrentInputs,
44116
44247
  targetConcurrentInputs: o.targetConcurrentInputs,
44117
44248
  batchMaxSize: o.batchMaxSize,
@@ -44271,8 +44402,15 @@ var ImageService = class {
44271
44402
  * Delete an {@link Image} by ID. Warning: This removes an *entire Image*, and cannot be undone.
44272
44403
  */
44273
44404
  async delete(imageId, _ = {}) {
44274
- const image = await this.fromId(imageId);
44275
- await this.#client.cpClient.imageDelete({ imageId: image.imageId });
44405
+ try {
44406
+ await this.#client.cpClient.imageDelete({ imageId });
44407
+ } catch (err) {
44408
+ if (err instanceof ClientError4 && err.code === Status4.NOT_FOUND)
44409
+ throw new NotFoundError(err.details);
44410
+ if (err instanceof ClientError4 && err.code === Status4.FAILED_PRECONDITION && err.details.includes("Could not find image with ID"))
44411
+ throw new NotFoundError(err.details);
44412
+ throw err;
44413
+ }
44276
44414
  }
44277
44415
  };
44278
44416
  var Image2 = class _Image {
@@ -44370,6 +44508,7 @@ var Image2 = class _Image {
44370
44508
  if (this.imageId !== "") {
44371
44509
  return this;
44372
44510
  }
44511
+ this.#client.logger.debug("Building image", "app_id", app.appId);
44373
44512
  let baseImageId;
44374
44513
  for (let i = 0; i < this.#layers.length; i++) {
44375
44514
  const layer = this.#layers[i];
@@ -44444,6 +44583,7 @@ ${result.exception}`
44444
44583
  baseImageId = resp.imageId;
44445
44584
  }
44446
44585
  this.#imageId = baseImageId;
44586
+ this.#client.logger.debug("Image build completed", "image_id", baseImageId);
44447
44587
  return this;
44448
44588
  }
44449
44589
  /**
@@ -44891,8 +45031,8 @@ var EphemeralHeartbeatManager = class {
44891
45031
  };
44892
45032
 
44893
45033
  // src/queue.ts
44894
- var queueInitialPutBackoff = 100;
44895
- var queueDefaultPartitionTtl = 24 * 3600 * 1e3;
45034
+ var queueInitialPutBackoffMs = 100;
45035
+ var queueDefaultPartitionTtlMs = 24 * 3600 * 1e3;
44896
45036
  var QueueService = class {
44897
45037
  #client;
44898
45038
  constructor(client2) {
@@ -44907,6 +45047,11 @@ var QueueService = class {
44907
45047
  objectCreationType: 5 /* OBJECT_CREATION_TYPE_EPHEMERAL */,
44908
45048
  environmentName: this.#client.environmentName(params.environment)
44909
45049
  });
45050
+ this.#client.logger.debug(
45051
+ "Created ephemeral Queue",
45052
+ "queue_id",
45053
+ resp.queueId
45054
+ );
44910
45055
  const ephemeralHbManager = new EphemeralHeartbeatManager(
44911
45056
  () => this.#client.cpClient.queueHeartbeat({ queueId: resp.queueId })
44912
45057
  );
@@ -44921,6 +45066,13 @@ var QueueService = class {
44921
45066
  objectCreationType: params.createIfMissing ? 1 /* OBJECT_CREATION_TYPE_CREATE_IF_MISSING */ : void 0,
44922
45067
  environmentName: this.#client.environmentName(params.environment)
44923
45068
  });
45069
+ this.#client.logger.debug(
45070
+ "Retrieved Queue",
45071
+ "queue_id",
45072
+ resp.queueId,
45073
+ "queue_name",
45074
+ name
45075
+ );
44924
45076
  return new Queue(this.#client, resp.queueId, name);
44925
45077
  }
44926
45078
  /**
@@ -44996,30 +45148,30 @@ var Queue = class _Queue {
44996
45148
  allPartitions: params.all
44997
45149
  });
44998
45150
  }
44999
- async #get(n, partition, timeout) {
45151
+ async #get(n, partition, timeoutMs) {
45000
45152
  const partitionKey = _Queue.#validatePartitionKey(partition);
45001
45153
  const startTime = Date.now();
45002
- let pollTimeout = 5e4;
45003
- if (timeout !== void 0) {
45004
- pollTimeout = Math.min(pollTimeout, timeout);
45154
+ let pollTimeoutMs = 5e4;
45155
+ if (timeoutMs !== void 0) {
45156
+ pollTimeoutMs = Math.min(pollTimeoutMs, timeoutMs);
45005
45157
  }
45006
45158
  while (true) {
45007
45159
  const response = await this.#client.cpClient.queueGet({
45008
45160
  queueId: this.queueId,
45009
45161
  partitionKey,
45010
- timeout: pollTimeout / 1e3,
45162
+ timeout: pollTimeoutMs / 1e3,
45011
45163
  nValues: n
45012
45164
  });
45013
45165
  if (response.values && response.values.length > 0) {
45014
45166
  return response.values.map((value) => loads(value));
45015
45167
  }
45016
- if (timeout !== void 0) {
45017
- const remaining = timeout - (Date.now() - startTime);
45018
- if (remaining <= 0) {
45019
- const message = `Queue ${this.queueId} did not return values within ${timeout}ms.`;
45168
+ if (timeoutMs !== void 0) {
45169
+ const remainingMs = timeoutMs - (Date.now() - startTime);
45170
+ if (remainingMs <= 0) {
45171
+ const message = `Queue ${this.queueId} did not return values within ${timeoutMs}ms.`;
45020
45172
  throw new QueueEmptyError(message);
45021
45173
  }
45022
- pollTimeout = Math.min(pollTimeout, remaining);
45174
+ pollTimeoutMs = Math.min(pollTimeoutMs, remainingMs);
45023
45175
  }
45024
45176
  }
45025
45177
  }
@@ -45027,35 +45179,37 @@ var Queue = class _Queue {
45027
45179
  * Remove and return the next object from the Queue.
45028
45180
  *
45029
45181
  * By default, this will wait until at least one item is present in the Queue.
45030
- * If `timeout` is set, raises `QueueEmptyError` if no items are available
45182
+ * If `timeoutMs` is set, raises `QueueEmptyError` if no items are available
45031
45183
  * within that timeout in milliseconds.
45032
45184
  */
45033
45185
  async get(params = {}) {
45034
- const values = await this.#get(1, params.partition, params.timeout);
45186
+ checkForRenamedParams(params, { timeout: "timeoutMs" });
45187
+ const values = await this.#get(1, params.partition, params.timeoutMs);
45035
45188
  return values[0];
45036
45189
  }
45037
45190
  /**
45038
45191
  * Remove and return up to `n` objects from the Queue.
45039
45192
  *
45040
45193
  * By default, this will wait until at least one item is present in the Queue.
45041
- * If `timeout` is set, raises `QueueEmptyError` if no items are available
45194
+ * If `timeoutMs` is set, raises `QueueEmptyError` if no items are available
45042
45195
  * within that timeout in milliseconds.
45043
45196
  */
45044
45197
  async getMany(n, params = {}) {
45045
- return await this.#get(n, params.partition, params.timeout);
45198
+ checkForRenamedParams(params, { timeout: "timeoutMs" });
45199
+ return await this.#get(n, params.partition, params.timeoutMs);
45046
45200
  }
45047
- async #put(values, timeout, partition, partitionTtl) {
45201
+ async #put(values, timeoutMs, partition, partitionTtlMs) {
45048
45202
  const valuesEncoded = values.map((v) => dumps(v));
45049
45203
  const partitionKey = _Queue.#validatePartitionKey(partition);
45050
- let delay = queueInitialPutBackoff;
45051
- const deadline = timeout ? Date.now() + timeout : void 0;
45204
+ let delay = queueInitialPutBackoffMs;
45205
+ const deadline = timeoutMs ? Date.now() + timeoutMs : void 0;
45052
45206
  while (true) {
45053
45207
  try {
45054
45208
  await this.#client.cpClient.queuePut({
45055
45209
  queueId: this.queueId,
45056
45210
  values: valuesEncoded,
45057
45211
  partitionKey,
45058
- partitionTtlSeconds: (partitionTtl || queueDefaultPartitionTtl) / 1e3
45212
+ partitionTtlSeconds: (partitionTtlMs || queueDefaultPartitionTtlMs) / 1e3
45059
45213
  });
45060
45214
  break;
45061
45215
  } catch (e) {
@@ -45078,25 +45232,38 @@ var Queue = class _Queue {
45078
45232
  * Add an item to the end of the Queue.
45079
45233
  *
45080
45234
  * If the Queue is full, this will retry with exponential backoff until the
45081
- * provided `timeout` is reached, or indefinitely if `timeout` is not set.
45235
+ * provided `timeoutMs` is reached, or indefinitely if `timeoutMs` is not set.
45082
45236
  * Raises {@link QueueFullError} if the Queue is still full after the timeout.
45083
45237
  */
45084
45238
  async put(v, params = {}) {
45085
- await this.#put([v], params.timeout, params.partition, params.partitionTtl);
45239
+ checkForRenamedParams(params, {
45240
+ timeout: "timeoutMs",
45241
+ partitionTtl: "partitionTtlMs"
45242
+ });
45243
+ await this.#put(
45244
+ [v],
45245
+ params.timeoutMs,
45246
+ params.partition,
45247
+ params.partitionTtlMs
45248
+ );
45086
45249
  }
45087
45250
  /**
45088
45251
  * Add several items to the end of the Queue.
45089
45252
  *
45090
45253
  * If the Queue is full, this will retry with exponential backoff until the
45091
- * provided `timeout` is reached, or indefinitely if `timeout` is not set.
45254
+ * provided `timeoutMs` is reached, or indefinitely if `timeoutMs` is not set.
45092
45255
  * Raises {@link QueueFullError} if the Queue is still full after the timeout.
45093
45256
  */
45094
45257
  async putMany(values, params = {}) {
45258
+ checkForRenamedParams(params, {
45259
+ timeout: "timeoutMs",
45260
+ partitionTtl: "partitionTtlMs"
45261
+ });
45095
45262
  await this.#put(
45096
45263
  values,
45097
- params.timeout,
45264
+ params.timeoutMs,
45098
45265
  params.partition,
45099
- params.partitionTtl
45266
+ params.partitionTtlMs
45100
45267
  );
45101
45268
  }
45102
45269
  /** Return the number of objects in the Queue. */
@@ -45115,20 +45282,21 @@ var Queue = class _Queue {
45115
45282
  }
45116
45283
  /** Iterate through items in a Queue without mutation. */
45117
45284
  async *iterate(params = {}) {
45118
- const { partition, itemPollTimeout = 0 } = params;
45285
+ checkForRenamedParams(params, { itemPollTimeout: "itemPollTimeoutMs" });
45286
+ const { partition, itemPollTimeoutMs = 0 } = params;
45119
45287
  let lastEntryId = void 0;
45120
45288
  const validatedPartitionKey = _Queue.#validatePartitionKey(partition);
45121
- let fetchDeadline = Date.now() + itemPollTimeout;
45122
- const maxPollDuration = 3e4;
45289
+ let fetchDeadline = Date.now() + itemPollTimeoutMs;
45290
+ const maxPollDurationMs = 3e4;
45123
45291
  while (true) {
45124
- const pollDuration = Math.max(
45292
+ const pollDurationMs = Math.max(
45125
45293
  0,
45126
- Math.min(maxPollDuration, fetchDeadline - Date.now())
45294
+ Math.min(maxPollDurationMs, fetchDeadline - Date.now())
45127
45295
  );
45128
45296
  const request = {
45129
45297
  queueId: this.queueId,
45130
45298
  partitionKey: validatedPartitionKey,
45131
- itemPollTimeout: pollDuration / 1e3,
45299
+ itemPollTimeout: pollDurationMs / 1e3,
45132
45300
  lastEntryId: lastEntryId || ""
45133
45301
  };
45134
45302
  const response = await this.#client.cpClient.queueNextItems(request);
@@ -45137,7 +45305,7 @@ var Queue = class _Queue {
45137
45305
  yield loads(item.value);
45138
45306
  lastEntryId = item.entryId;
45139
45307
  }
45140
- fetchDeadline = Date.now() + itemPollTimeout;
45308
+ fetchDeadline = Date.now() + itemPollTimeoutMs;
45141
45309
  } else if (Date.now() > fetchDeadline) {
45142
45310
  break;
45143
45311
  }
@@ -45424,15 +45592,21 @@ function cloudBucketMountToProto(mount, mountPath) {
45424
45592
 
45425
45593
  // src/sandbox.ts
45426
45594
  async function buildSandboxCreateRequestProto(appId, imageId, params = {}) {
45595
+ checkForRenamedParams(params, {
45596
+ memory: "memoryMiB",
45597
+ memoryLimit: "memoryLimitMiB",
45598
+ timeout: "timeoutMs",
45599
+ idleTimeout: "idleTimeoutMs"
45600
+ });
45427
45601
  const gpuConfig = parseGpuConfig(params.gpu);
45428
- if (params.timeout && params.timeout % 1e3 !== 0) {
45602
+ if (params.timeoutMs && params.timeoutMs % 1e3 !== 0) {
45429
45603
  throw new Error(
45430
- `timeout must be a multiple of 1000ms, got ${params.timeout}`
45604
+ `timeoutMs must be a multiple of 1000ms, got ${params.timeoutMs}`
45431
45605
  );
45432
45606
  }
45433
- if (params.idleTimeout && params.idleTimeout % 1e3 !== 0) {
45607
+ if (params.idleTimeoutMs && params.idleTimeoutMs % 1e3 !== 0) {
45434
45608
  throw new Error(
45435
- `idleTimeout must be a multiple of 1000ms, got ${params.idleTimeout}`
45609
+ `idleTimeoutMs must be a multiple of 1000ms, got ${params.idleTimeoutMs}`
45436
45610
  );
45437
45611
  }
45438
45612
  if (params.workdir && !params.workdir.startsWith("/")) {
@@ -45503,20 +45677,63 @@ async function buildSandboxCreateRequestProto(appId, imageId, params = {}) {
45503
45677
  if (params.pty) {
45504
45678
  ptyInfo = defaultSandboxPTYInfo();
45505
45679
  }
45680
+ let milliCpu = void 0;
45681
+ let milliCpuMax = void 0;
45682
+ if (params.cpu === void 0 && params.cpuLimit !== void 0) {
45683
+ throw new Error("must also specify cpu when cpuLimit is specified");
45684
+ }
45685
+ if (params.cpu !== void 0) {
45686
+ if (params.cpu <= 0) {
45687
+ throw new Error(`cpu (${params.cpu}) must be a positive number`);
45688
+ }
45689
+ milliCpu = Math.trunc(1e3 * params.cpu);
45690
+ if (params.cpuLimit !== void 0) {
45691
+ if (params.cpuLimit < params.cpu) {
45692
+ throw new Error(
45693
+ `cpu (${params.cpu}) cannot be higher than cpuLimit (${params.cpuLimit})`
45694
+ );
45695
+ }
45696
+ milliCpuMax = Math.trunc(1e3 * params.cpuLimit);
45697
+ }
45698
+ }
45699
+ let memoryMb = void 0;
45700
+ let memoryMbMax = void 0;
45701
+ if (params.memoryMiB === void 0 && params.memoryLimitMiB !== void 0) {
45702
+ throw new Error(
45703
+ "must also specify memoryMiB when memoryLimitMiB is specified"
45704
+ );
45705
+ }
45706
+ if (params.memoryMiB !== void 0) {
45707
+ if (params.memoryMiB <= 0) {
45708
+ throw new Error(
45709
+ `the memoryMiB request (${params.memoryMiB}) must be a positive number`
45710
+ );
45711
+ }
45712
+ memoryMb = params.memoryMiB;
45713
+ if (params.memoryLimitMiB !== void 0) {
45714
+ if (params.memoryLimitMiB < params.memoryMiB) {
45715
+ throw new Error(
45716
+ `the memoryMiB request (${params.memoryMiB}) cannot be higher than memoryLimitMiB (${params.memoryLimitMiB})`
45717
+ );
45718
+ }
45719
+ memoryMbMax = params.memoryLimitMiB;
45720
+ }
45721
+ }
45506
45722
  return SandboxCreateRequest.create({
45507
45723
  appId,
45508
45724
  definition: {
45509
45725
  // Sleep default is implicit in image builder version <=2024.10
45510
45726
  entrypointArgs: params.command ?? ["sleep", "48h"],
45511
45727
  imageId,
45512
- timeoutSecs: params.timeout != void 0 ? params.timeout / 1e3 : 600,
45513
- idleTimeoutSecs: params.idleTimeout != void 0 ? params.idleTimeout / 1e3 : void 0,
45728
+ timeoutSecs: params.timeoutMs != void 0 ? params.timeoutMs / 1e3 : 600,
45729
+ idleTimeoutSecs: params.idleTimeoutMs != void 0 ? params.idleTimeoutMs / 1e3 : void 0,
45514
45730
  workdir: params.workdir ?? void 0,
45515
45731
  networkAccess,
45516
45732
  resources: {
45517
- // https://modal.com/docs/guide/resources
45518
- milliCpu: Math.round(1e3 * (params.cpu ?? 0.125)),
45519
- memoryMb: params.memory ?? 128,
45733
+ milliCpu,
45734
+ milliCpuMax,
45735
+ memoryMb,
45736
+ memoryMbMax,
45520
45737
  gpuConfig
45521
45738
  },
45522
45739
  volumeMounts,
@@ -45567,6 +45784,11 @@ var SandboxService = class {
45567
45784
  }
45568
45785
  throw err;
45569
45786
  }
45787
+ this.#client.logger.debug(
45788
+ "Created Sandbox",
45789
+ "sandbox_id",
45790
+ createResp.sandboxId
45791
+ );
45570
45792
  return new Sandbox2(this.#client, createResp.sandboxId);
45571
45793
  }
45572
45794
  /** Returns a running {@link Sandbox} object from an ID.
@@ -45691,6 +45913,7 @@ function defaultSandboxPTYInfo() {
45691
45913
  });
45692
45914
  }
45693
45915
  async function buildContainerExecRequestProto(taskId, command, params) {
45916
+ checkForRenamedParams(params, { timeout: "timeoutMs" });
45694
45917
  const secretIds = (params?.secrets || []).map((secret) => secret.secretId);
45695
45918
  let ptyInfo;
45696
45919
  if (params?.pty) {
@@ -45700,7 +45923,7 @@ async function buildContainerExecRequestProto(taskId, command, params) {
45700
45923
  taskId,
45701
45924
  command,
45702
45925
  workdir: params?.workdir,
45703
- timeoutSecs: params?.timeout ? params.timeout / 1e3 : 0,
45926
+ timeoutSecs: params?.timeoutMs ? params.timeoutMs / 1e3 : 0,
45704
45927
  secretIds,
45705
45928
  ptyInfo
45706
45929
  });
@@ -45826,6 +46049,15 @@ var Sandbox2 = class _Sandbox {
45826
46049
  mergedParams
45827
46050
  );
45828
46051
  const resp = await this.#client.cpClient.containerExec(req);
46052
+ this.#client.logger.debug(
46053
+ "Created ContainerProcess",
46054
+ "exec_id",
46055
+ resp.execId,
46056
+ "sandbox_id",
46057
+ this.sandboxId,
46058
+ "command",
46059
+ command
46060
+ );
45829
46061
  return new ContainerProcess(this.#client, resp.execId, params);
45830
46062
  }
45831
46063
  async #getTaskId() {
@@ -45858,7 +46090,17 @@ var Sandbox2 = class _Sandbox {
45858
46090
  timeout: 10
45859
46091
  });
45860
46092
  if (resp.result) {
45861
- return _Sandbox.#getReturnCode(resp.result);
46093
+ const returnCode = _Sandbox.#getReturnCode(resp.result);
46094
+ this.#client.logger.debug(
46095
+ "Sandbox wait completed",
46096
+ "sandbox_id",
46097
+ this.sandboxId,
46098
+ "status",
46099
+ resp.result.status,
46100
+ "return_code",
46101
+ returnCode
46102
+ );
46103
+ return returnCode;
45862
46104
  }
45863
46105
  }
45864
46106
  }
@@ -45868,14 +46110,13 @@ var Sandbox2 = class _Sandbox {
45868
46110
  *
45869
46111
  * @returns A dictionary of {@link Tunnel} objects which are keyed by the container port.
45870
46112
  */
45871
- async tunnels(timeout = 5e4) {
46113
+ async tunnels(timeoutMs = 5e4) {
45872
46114
  if (this.#tunnels) {
45873
46115
  return this.#tunnels;
45874
46116
  }
45875
46117
  const resp = await this.#client.cpClient.sandboxGetTunnels({
45876
46118
  sandboxId: this.sandboxId,
45877
- timeout: timeout / 1e3
45878
- // Convert to seconds
46119
+ timeout: timeoutMs / 1e3
45879
46120
  });
45880
46121
  if (resp.result?.status === 4 /* GENERIC_STATUS_TIMEOUT */) {
45881
46122
  throw new SandboxTimeoutError();
@@ -45896,13 +46137,13 @@ var Sandbox2 = class _Sandbox {
45896
46137
  *
45897
46138
  * Returns an {@link Image} object which can be used to spawn a new Sandbox with the same filesystem.
45898
46139
  *
45899
- * @param timeout - Timeout for the snapshot operation in milliseconds
46140
+ * @param timeoutMs - Timeout for the snapshot operation in milliseconds
45900
46141
  * @returns Promise that resolves to an {@link Image}
45901
46142
  */
45902
- async snapshotFilesystem(timeout = 55e3) {
46143
+ async snapshotFilesystem(timeoutMs = 55e3) {
45903
46144
  const resp = await this.#client.cpClient.sandboxSnapshotFs({
45904
46145
  sandboxId: this.sandboxId,
45905
- timeout: timeout / 1e3
46146
+ timeout: timeoutMs / 1e3
45906
46147
  });
45907
46148
  if (resp.result?.status !== 1 /* GENERIC_STATUS_SUCCESS */) {
45908
46149
  throw new Error(
@@ -46124,6 +46365,13 @@ var VolumeService = class {
46124
46365
  environmentName: this.#client.environmentName(params?.environment),
46125
46366
  objectCreationType: params?.createIfMissing ? 1 /* OBJECT_CREATION_TYPE_CREATE_IF_MISSING */ : 0 /* OBJECT_CREATION_TYPE_UNSPECIFIED */
46126
46367
  });
46368
+ this.#client.logger.debug(
46369
+ "Retrieved Volume",
46370
+ "volume_id",
46371
+ resp.volumeId,
46372
+ "volume_name",
46373
+ name
46374
+ );
46127
46375
  return new Volume(resp.volumeId, name);
46128
46376
  } catch (err) {
46129
46377
  if (err instanceof ClientError8 && err.code === Status8.NOT_FOUND)
@@ -46140,6 +46388,11 @@ var VolumeService = class {
46140
46388
  objectCreationType: 5 /* OBJECT_CREATION_TYPE_EPHEMERAL */,
46141
46389
  environmentName: this.#client.environmentName(params.environment)
46142
46390
  });
46391
+ this.#client.logger.debug(
46392
+ "Created ephemeral Volume",
46393
+ "volume_id",
46394
+ resp.volumeId
46395
+ );
46143
46396
  const ephemeralHbManager = new EphemeralHeartbeatManager(
46144
46397
  () => this.#client.cpClient.volumeHeartbeat({ volumeId: resp.volumeId })
46145
46398
  );
@@ -46192,9 +46445,17 @@ import { readFileSync } from "node:fs";
46192
46445
  import { homedir } from "node:os";
46193
46446
  import path from "node:path";
46194
46447
  import { parse as parseToml } from "smol-toml";
46448
+ function configFilePath() {
46449
+ const configPath = process.env["MODAL_CONFIG_PATH"];
46450
+ if (configPath && configPath !== "") {
46451
+ return configPath;
46452
+ }
46453
+ return path.join(homedir(), ".modal.toml");
46454
+ }
46195
46455
  function readConfigFile() {
46196
46456
  try {
46197
- const configContent = readFileSync(path.join(homedir(), ".modal.toml"), {
46457
+ const configPath = configFilePath();
46458
+ const configContent = readFileSync(configPath, {
46198
46459
  encoding: "utf-8"
46199
46460
  });
46200
46461
  return parseToml(configContent);
@@ -46221,7 +46482,8 @@ function getProfile(profileName) {
46221
46482
  tokenId: process.env["MODAL_TOKEN_ID"] || profileData.token_id,
46222
46483
  tokenSecret: process.env["MODAL_TOKEN_SECRET"] || profileData.token_secret,
46223
46484
  environment: process.env["MODAL_ENVIRONMENT"] || profileData.environment,
46224
- imageBuilderVersion: process.env["MODAL_IMAGE_BUILDER_VERSION"] || profileData.imageBuilderVersion
46485
+ imageBuilderVersion: process.env["MODAL_IMAGE_BUILDER_VERSION"] || profileData.imageBuilderVersion,
46486
+ logLevel: process.env["MODAL_LOGLEVEL"] || profileData.loglevel
46225
46487
  };
46226
46488
  return profile;
46227
46489
  }
@@ -46231,13 +46493,15 @@ var REFRESH_WINDOW = 5 * 60;
46231
46493
  var DEFAULT_EXPIRY_OFFSET = 20 * 60;
46232
46494
  var AuthTokenManager = class {
46233
46495
  client;
46496
+ logger;
46234
46497
  currentToken = "";
46235
46498
  tokenExpiry = 0;
46236
46499
  stopped = false;
46237
46500
  timeoutId = null;
46238
46501
  initialTokenPromise = null;
46239
- constructor(client2) {
46502
+ constructor(client2, logger) {
46240
46503
  this.client = client2;
46504
+ this.logger = logger;
46241
46505
  }
46242
46506
  /**
46243
46507
  * Returns the current cached token.
@@ -46268,9 +46532,19 @@ var AuthTokenManager = class {
46268
46532
  if (exp > 0) {
46269
46533
  this.tokenExpiry = exp;
46270
46534
  } else {
46271
- console.warn("Failed to decode x-modal-auth-token exp field");
46535
+ this.logger.warn("x-modal-auth-token does not contain exp field");
46272
46536
  this.tokenExpiry = Math.floor(Date.now() / 1e3) + DEFAULT_EXPIRY_OFFSET;
46273
46537
  }
46538
+ const now = Math.floor(Date.now() / 1e3);
46539
+ const expiresIn = this.tokenExpiry - now;
46540
+ const refreshIn = this.tokenExpiry - now - REFRESH_WINDOW;
46541
+ this.logger.debug(
46542
+ "Fetched auth token",
46543
+ "expires_in",
46544
+ `${expiresIn}s`,
46545
+ "refresh_in",
46546
+ `${refreshIn}s`
46547
+ );
46274
46548
  }
46275
46549
  /**
46276
46550
  * Background loop that refreshes tokens REFRESH_WINDOW seconds before they expire.
@@ -46290,7 +46564,7 @@ var AuthTokenManager = class {
46290
46564
  try {
46291
46565
  await this.fetchToken();
46292
46566
  } catch (error) {
46293
- console.error("Failed to refresh auth token:", error);
46567
+ this.logger.error("Failed to refresh auth token", "error", error);
46294
46568
  await new Promise((resolve) => setTimeout(resolve, 5e3));
46295
46569
  }
46296
46570
  }
@@ -46354,7 +46628,113 @@ var AuthTokenManager = class {
46354
46628
 
46355
46629
  // src/version.ts
46356
46630
  function getSDKVersion() {
46357
- return true ? "0.5.0-dev.7" : "0.0.0";
46631
+ return true ? "0.5.1" : "0.0.0";
46632
+ }
46633
+
46634
+ // src/logger.ts
46635
+ var LOG_LEVELS = {
46636
+ debug: 0,
46637
+ info: 1,
46638
+ warn: 2,
46639
+ error: 3
46640
+ };
46641
+ function parseLogLevel(level) {
46642
+ if (!level) {
46643
+ return "warn";
46644
+ }
46645
+ const normalized = level.toLowerCase();
46646
+ if (normalized === "debug" || normalized === "info" || normalized === "warn" || normalized === "warning" || normalized === "error") {
46647
+ return normalized === "warning" ? "warn" : normalized;
46648
+ }
46649
+ throw new Error(
46650
+ `Invalid log level value: "${level}" (must be debug, info, warn, or error)`
46651
+ );
46652
+ }
46653
+ var DefaultLogger = class {
46654
+ levelValue;
46655
+ constructor(level = "warn") {
46656
+ this.levelValue = LOG_LEVELS[level];
46657
+ }
46658
+ debug(message, ...args) {
46659
+ if (this.levelValue <= LOG_LEVELS.debug) {
46660
+ console.log(this.formatMessage("DEBUG", message, args));
46661
+ }
46662
+ }
46663
+ info(message, ...args) {
46664
+ if (this.levelValue <= LOG_LEVELS.info) {
46665
+ console.log(this.formatMessage("INFO", message, args));
46666
+ }
46667
+ }
46668
+ warn(message, ...args) {
46669
+ if (this.levelValue <= LOG_LEVELS.warn) {
46670
+ console.warn(this.formatMessage("WARN", message, args));
46671
+ }
46672
+ }
46673
+ error(message, ...args) {
46674
+ if (this.levelValue <= LOG_LEVELS.error) {
46675
+ console.error(this.formatMessage("ERROR", message, args));
46676
+ }
46677
+ }
46678
+ formatMessage(level, message, args) {
46679
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
46680
+ let formatted = `time=${timestamp} level=${level} msg="${message}"`;
46681
+ if (args.length > 0) {
46682
+ for (let i = 0; i < args.length; i += 2) {
46683
+ if (i + 1 < args.length) {
46684
+ const key = args[i];
46685
+ const value = args[i + 1];
46686
+ formatted += ` ${key}=${this.formatValue(value)}`;
46687
+ }
46688
+ }
46689
+ }
46690
+ return formatted;
46691
+ }
46692
+ formatValue(value) {
46693
+ if (typeof value === "string") {
46694
+ return value.includes(" ") ? `"${value}"` : value;
46695
+ }
46696
+ if (value instanceof Error) {
46697
+ return `"${value.message}"`;
46698
+ }
46699
+ if (Array.isArray(value)) {
46700
+ return `[${value.join(",")}]`;
46701
+ }
46702
+ return String(value);
46703
+ }
46704
+ };
46705
+ var FilteredLogger = class {
46706
+ constructor(logger, level) {
46707
+ this.logger = logger;
46708
+ this.levelValue = LOG_LEVELS[level];
46709
+ }
46710
+ levelValue;
46711
+ debug(message, ...args) {
46712
+ if (this.levelValue <= LOG_LEVELS.debug) {
46713
+ this.logger.debug(message, ...args);
46714
+ }
46715
+ }
46716
+ info(message, ...args) {
46717
+ if (this.levelValue <= LOG_LEVELS.info) {
46718
+ this.logger.info(message, ...args);
46719
+ }
46720
+ }
46721
+ warn(message, ...args) {
46722
+ if (this.levelValue <= LOG_LEVELS.warn) {
46723
+ this.logger.warn(message, ...args);
46724
+ }
46725
+ }
46726
+ error(message, ...args) {
46727
+ if (this.levelValue <= LOG_LEVELS.error) {
46728
+ this.logger.error(message, ...args);
46729
+ }
46730
+ }
46731
+ };
46732
+ function createLogger(logger, logLevel = "") {
46733
+ const level = parseLogLevel(logLevel);
46734
+ if (logger) {
46735
+ return new FilteredLogger(logger, level);
46736
+ }
46737
+ return new DefaultLogger(level);
46358
46738
  }
46359
46739
 
46360
46740
  // src/client.ts
@@ -46372,9 +46752,11 @@ var ModalClient = class {
46372
46752
  /** @ignore */
46373
46753
  cpClient;
46374
46754
  profile;
46755
+ logger;
46375
46756
  ipClients;
46376
46757
  authTokenManager = null;
46377
46758
  constructor(params) {
46759
+ checkForRenamedParams(params, { timeout: "timeoutMs" });
46378
46760
  const baseProfile = getProfile(process.env["MODAL_PROFILE"]);
46379
46761
  this.profile = {
46380
46762
  ...baseProfile,
@@ -46382,8 +46764,18 @@ var ModalClient = class {
46382
46764
  ...params?.tokenSecret && { tokenSecret: params.tokenSecret },
46383
46765
  ...params?.environment && { environment: params.environment }
46384
46766
  };
46767
+ const logLevelValue = params?.logLevel || this.profile.logLevel || "";
46768
+ this.logger = createLogger(params?.logger, logLevelValue);
46769
+ this.logger.debug(
46770
+ "Initializing Modal client",
46771
+ "version",
46772
+ getSDKVersion(),
46773
+ "server_url",
46774
+ this.profile.serverUrl
46775
+ );
46385
46776
  this.ipClients = /* @__PURE__ */ new Map();
46386
46777
  this.cpClient = params?.cpClient ?? this.createClient(this.profile);
46778
+ this.logger.debug("Modal client initialized successfully");
46387
46779
  this.apps = new AppService(this);
46388
46780
  this.cls = new ClsService(this);
46389
46781
  this.functions = new FunctionService(this);
@@ -46407,16 +46799,19 @@ var ModalClient = class {
46407
46799
  if (existing) {
46408
46800
  return existing;
46409
46801
  }
46802
+ this.logger.debug("Creating input plane client", "server_url", serverUrl);
46410
46803
  const profile = { ...this.profile, serverUrl };
46411
46804
  const newClient = this.createClient(profile);
46412
46805
  this.ipClients.set(serverUrl, newClient);
46413
46806
  return newClient;
46414
46807
  }
46415
46808
  close() {
46809
+ this.logger.debug("Closing Modal client");
46416
46810
  if (this.authTokenManager) {
46417
46811
  this.authTokenManager.stop();
46418
46812
  this.authTokenManager = null;
46419
46813
  }
46814
+ this.logger.debug("Modal client closed");
46420
46815
  }
46421
46816
  version() {
46422
46817
  return getSDKVersion();
@@ -46427,12 +46822,97 @@ var ModalClient = class {
46427
46822
  "grpc.max_send_message_length": 100 * 1024 * 1024,
46428
46823
  "grpc-node.flow_control_window": 64 * 1024 * 1024
46429
46824
  });
46430
- return createClientFactory().use(this.authMiddleware(profile)).use(retryMiddleware).use(timeoutMiddleware).create(ModalClientDefinition, channel);
46825
+ return createClientFactory().use(this.authMiddleware(profile)).use(this.retryMiddleware()).use(timeoutMiddleware).create(ModalClientDefinition, channel);
46826
+ }
46827
+ /** Middleware to retry transient errors and timeouts for unary requests. */
46828
+ retryMiddleware() {
46829
+ const logger = this.logger;
46830
+ return async function* retryMiddleware(call, options) {
46831
+ const {
46832
+ retries = 3,
46833
+ baseDelay = 100,
46834
+ maxDelay = 1e3,
46835
+ delayFactor = 2,
46836
+ additionalStatusCodes = [],
46837
+ signal,
46838
+ ...restOptions
46839
+ } = options;
46840
+ if (call.requestStream || call.responseStream || !retries) {
46841
+ return yield* call.next(call.request, restOptions);
46842
+ }
46843
+ const retryableCodes = /* @__PURE__ */ new Set([
46844
+ ...retryableGrpcStatusCodes,
46845
+ ...additionalStatusCodes
46846
+ ]);
46847
+ const idempotencyKey = uuidv4();
46848
+ const startTime = Date.now();
46849
+ let attempt = 0;
46850
+ let delayMs = baseDelay;
46851
+ logger.debug("Sending gRPC request", "method", call.method.path);
46852
+ while (true) {
46853
+ const metadata = new Metadata(restOptions.metadata ?? {});
46854
+ metadata.set("x-idempotency-key", idempotencyKey);
46855
+ metadata.set("x-retry-attempt", String(attempt));
46856
+ if (attempt > 0) {
46857
+ metadata.set(
46858
+ "x-retry-delay",
46859
+ ((Date.now() - startTime) / 1e3).toFixed(3)
46860
+ );
46861
+ }
46862
+ try {
46863
+ return yield* call.next(call.request, {
46864
+ ...restOptions,
46865
+ metadata,
46866
+ signal
46867
+ });
46868
+ } catch (err) {
46869
+ if (!(err instanceof ClientError9) || !retryableCodes.has(err.code) || attempt >= retries) {
46870
+ if (attempt === retries && attempt > 0) {
46871
+ logger.debug(
46872
+ "Final retry attempt failed",
46873
+ "error",
46874
+ err,
46875
+ "retries",
46876
+ attempt,
46877
+ "delay",
46878
+ delayMs,
46879
+ "method",
46880
+ call.method.path,
46881
+ "idempotency_key",
46882
+ idempotencyKey.substring(0, 8)
46883
+ );
46884
+ }
46885
+ throw err;
46886
+ }
46887
+ if (attempt > 0) {
46888
+ logger.debug(
46889
+ "Retryable failure",
46890
+ "error",
46891
+ err,
46892
+ "retries",
46893
+ attempt,
46894
+ "delay",
46895
+ delayMs,
46896
+ "method",
46897
+ call.method.path,
46898
+ "idempotency_key",
46899
+ idempotencyKey.substring(0, 8)
46900
+ );
46901
+ }
46902
+ await sleep(delayMs, signal);
46903
+ delayMs = Math.min(delayMs * delayFactor, maxDelay);
46904
+ attempt += 1;
46905
+ }
46906
+ }
46907
+ };
46431
46908
  }
46432
46909
  authMiddleware(profile) {
46433
46910
  const getOrCreateAuthTokenManager = () => {
46434
46911
  if (!this.authTokenManager) {
46435
- this.authTokenManager = new AuthTokenManager(this.cpClient);
46912
+ this.authTokenManager = new AuthTokenManager(
46913
+ this.cpClient,
46914
+ this.logger
46915
+ );
46436
46916
  this.authTokenManager.start();
46437
46917
  }
46438
46918
  return this.authTokenManager;
@@ -46468,10 +46948,10 @@ var ModalClient = class {
46468
46948
  }
46469
46949
  };
46470
46950
  var timeoutMiddleware = async function* timeoutMiddleware2(call, options) {
46471
- if (!options.timeout || options.signal?.aborted) {
46951
+ if (!options.timeoutMs || options.signal?.aborted) {
46472
46952
  return yield* call.next(call.request, options);
46473
46953
  }
46474
- const { timeout, signal: origSignal, ...restOptions } = options;
46954
+ const { timeoutMs, signal: origSignal, ...restOptions } = options;
46475
46955
  const abortController = new AbortController();
46476
46956
  const abortListener = () => abortController.abort();
46477
46957
  origSignal?.addEventListener("abort", abortListener);
@@ -46479,7 +46959,7 @@ var timeoutMiddleware = async function* timeoutMiddleware2(call, options) {
46479
46959
  const timer = setTimeout(() => {
46480
46960
  timedOut = true;
46481
46961
  abortController.abort();
46482
- }, timeout);
46962
+ }, timeoutMs);
46483
46963
  try {
46484
46964
  return yield* call.next(call.request, {
46485
46965
  ...restOptions,
@@ -46492,7 +46972,7 @@ var timeoutMiddleware = async function* timeoutMiddleware2(call, options) {
46492
46972
  throw new ClientError9(
46493
46973
  call.method.path,
46494
46974
  Status9.DEADLINE_EXCEEDED,
46495
- `Timed out after ${timeout}ms`
46975
+ `Timed out after ${timeoutMs}ms`
46496
46976
  );
46497
46977
  }
46498
46978
  }
@@ -46522,53 +47002,6 @@ var sleep = (ms, signal) => new Promise((resolve, reject) => {
46522
47002
  { once: true }
46523
47003
  );
46524
47004
  });
46525
- var retryMiddleware = async function* retryMiddleware2(call, options) {
46526
- const {
46527
- retries = 3,
46528
- baseDelay = 100,
46529
- maxDelay = 1e3,
46530
- delayFactor = 2,
46531
- additionalStatusCodes = [],
46532
- signal,
46533
- ...restOptions
46534
- } = options;
46535
- if (call.requestStream || call.responseStream || !retries) {
46536
- return yield* call.next(call.request, restOptions);
46537
- }
46538
- const retryableCodes = /* @__PURE__ */ new Set([
46539
- ...retryableGrpcStatusCodes,
46540
- ...additionalStatusCodes
46541
- ]);
46542
- const idempotencyKey = uuidv4();
46543
- const startTime = Date.now();
46544
- let attempt = 0;
46545
- let delayMs = baseDelay;
46546
- while (true) {
46547
- const metadata = new Metadata(restOptions.metadata ?? {});
46548
- metadata.set("x-idempotency-key", idempotencyKey);
46549
- metadata.set("x-retry-attempt", String(attempt));
46550
- if (attempt > 0) {
46551
- metadata.set(
46552
- "x-retry-delay",
46553
- ((Date.now() - startTime) / 1e3).toFixed(3)
46554
- );
46555
- }
46556
- try {
46557
- return yield* call.next(call.request, {
46558
- ...restOptions,
46559
- metadata,
46560
- signal
46561
- });
46562
- } catch (err) {
46563
- if (!(err instanceof ClientError9) || !retryableCodes.has(err.code) || attempt >= retries) {
46564
- throw err;
46565
- }
46566
- await sleep(delayMs, signal);
46567
- delayMs = Math.min(delayMs * delayFactor, maxDelay);
46568
- attempt += 1;
46569
- }
46570
- }
46571
- };
46572
47005
  var defaultClient;
46573
47006
  var defaultClientOptions;
46574
47007
  function getDefaultClient() {
@@ -46612,6 +47045,13 @@ var AppService = class {
46612
47045
  environmentName: this.#client.environmentName(params.environment),
46613
47046
  objectCreationType: params.createIfMissing ? 1 /* OBJECT_CREATION_TYPE_CREATE_IF_MISSING */ : 0 /* OBJECT_CREATION_TYPE_UNSPECIFIED */
46614
47047
  });
47048
+ this.#client.logger.debug(
47049
+ "Retrieved App",
47050
+ "app_id",
47051
+ resp.appId,
47052
+ "app_name",
47053
+ name
47054
+ );
46615
47055
  return new App2(resp.appId, name);
46616
47056
  } catch (err) {
46617
47057
  if (err instanceof ClientError10 && err.code === Status10.NOT_FOUND)
@@ -46718,6 +47158,7 @@ export {
46718
47158
  SecretService,
46719
47159
  Volume,
46720
47160
  VolumeService,
47161
+ checkForRenamedParams,
46721
47162
  close,
46722
47163
  initializeClient
46723
47164
  };