modal 0.3.7 → 0.3.9
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/README.md +1 -1
- package/dist/index.cjs +39704 -0
- package/dist/index.d.cts +417 -0
- package/dist/index.d.ts +38 -1
- package/dist/index.js +363 -172
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -37797,13 +37797,13 @@ import {
|
|
|
37797
37797
|
} from "nice-grpc";
|
|
37798
37798
|
|
|
37799
37799
|
// src/config.ts
|
|
37800
|
-
import {
|
|
37801
|
-
import path from "node:path";
|
|
37800
|
+
import { readFileSync } from "node:fs";
|
|
37802
37801
|
import { homedir } from "node:os";
|
|
37802
|
+
import path from "node:path";
|
|
37803
37803
|
import { parse as parseToml } from "smol-toml";
|
|
37804
|
-
|
|
37804
|
+
function readConfigFile() {
|
|
37805
37805
|
try {
|
|
37806
|
-
const configContent =
|
|
37806
|
+
const configContent = readFileSync(path.join(homedir(), ".modal.toml"), {
|
|
37807
37807
|
encoding: "utf-8"
|
|
37808
37808
|
});
|
|
37809
37809
|
return parseToml(configContent);
|
|
@@ -37814,7 +37814,7 @@ async function readConfigFile() {
|
|
|
37814
37814
|
throw new Error(`Failed to read or parse .modal.toml: ${err.message}`);
|
|
37815
37815
|
}
|
|
37816
37816
|
}
|
|
37817
|
-
var config =
|
|
37817
|
+
var config = readConfigFile();
|
|
37818
37818
|
function getProfile(profileName) {
|
|
37819
37819
|
profileName = profileName || process.env["MODAL_PROFILE"] || void 0;
|
|
37820
37820
|
if (!profileName) {
|
|
@@ -38040,6 +38040,156 @@ ${result.exception}`
|
|
|
38040
38040
|
return new Image2(resp.imageId);
|
|
38041
38041
|
}
|
|
38042
38042
|
|
|
38043
|
+
// src/errors.ts
|
|
38044
|
+
var FunctionTimeoutError = class extends Error {
|
|
38045
|
+
constructor(message) {
|
|
38046
|
+
super(message);
|
|
38047
|
+
this.name = "FunctionTimeoutError";
|
|
38048
|
+
}
|
|
38049
|
+
};
|
|
38050
|
+
var RemoteError = class extends Error {
|
|
38051
|
+
constructor(message) {
|
|
38052
|
+
super(message);
|
|
38053
|
+
this.name = "RemoteError";
|
|
38054
|
+
}
|
|
38055
|
+
};
|
|
38056
|
+
var InternalFailure = class extends Error {
|
|
38057
|
+
constructor(message) {
|
|
38058
|
+
super(message);
|
|
38059
|
+
this.name = "InternalFailure";
|
|
38060
|
+
}
|
|
38061
|
+
};
|
|
38062
|
+
var NotFoundError = class extends Error {
|
|
38063
|
+
constructor(message) {
|
|
38064
|
+
super(message);
|
|
38065
|
+
this.name = "NotFoundError";
|
|
38066
|
+
}
|
|
38067
|
+
};
|
|
38068
|
+
var InvalidError = class extends Error {
|
|
38069
|
+
constructor(message) {
|
|
38070
|
+
super(message);
|
|
38071
|
+
this.name = "InvalidError";
|
|
38072
|
+
}
|
|
38073
|
+
};
|
|
38074
|
+
var QueueEmptyError = class extends Error {
|
|
38075
|
+
constructor(message) {
|
|
38076
|
+
super(message);
|
|
38077
|
+
this.name = "QueueEmptyError";
|
|
38078
|
+
}
|
|
38079
|
+
};
|
|
38080
|
+
var QueueFullError = class extends Error {
|
|
38081
|
+
constructor(message) {
|
|
38082
|
+
super(message);
|
|
38083
|
+
this.name = "QueueFullError";
|
|
38084
|
+
}
|
|
38085
|
+
};
|
|
38086
|
+
var SandboxFilesystemError = class extends Error {
|
|
38087
|
+
constructor(message) {
|
|
38088
|
+
super(message);
|
|
38089
|
+
this.name = "SandboxFilesystemError";
|
|
38090
|
+
}
|
|
38091
|
+
};
|
|
38092
|
+
|
|
38093
|
+
// src/sandbox_filesystem.ts
|
|
38094
|
+
var SandboxFile = class {
|
|
38095
|
+
#fileDescriptor;
|
|
38096
|
+
#taskId;
|
|
38097
|
+
/** @ignore */
|
|
38098
|
+
constructor(fileDescriptor, taskId) {
|
|
38099
|
+
this.#fileDescriptor = fileDescriptor;
|
|
38100
|
+
this.#taskId = taskId;
|
|
38101
|
+
}
|
|
38102
|
+
/**
|
|
38103
|
+
* Read data from the file.
|
|
38104
|
+
* @returns Promise that resolves to the read data as Uint8Array
|
|
38105
|
+
*/
|
|
38106
|
+
async read() {
|
|
38107
|
+
const resp = await runFilesystemExec({
|
|
38108
|
+
fileReadRequest: {
|
|
38109
|
+
fileDescriptor: this.#fileDescriptor
|
|
38110
|
+
},
|
|
38111
|
+
taskId: this.#taskId
|
|
38112
|
+
});
|
|
38113
|
+
const chunks = resp.chunks;
|
|
38114
|
+
const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
|
|
38115
|
+
const result = new Uint8Array(totalLength);
|
|
38116
|
+
let offset = 0;
|
|
38117
|
+
for (const chunk of chunks) {
|
|
38118
|
+
result.set(chunk, offset);
|
|
38119
|
+
offset += chunk.length;
|
|
38120
|
+
}
|
|
38121
|
+
return result;
|
|
38122
|
+
}
|
|
38123
|
+
/**
|
|
38124
|
+
* Write data to the file.
|
|
38125
|
+
* @param data - Data to write (string or Uint8Array)
|
|
38126
|
+
*/
|
|
38127
|
+
async write(data) {
|
|
38128
|
+
await runFilesystemExec({
|
|
38129
|
+
fileWriteRequest: {
|
|
38130
|
+
fileDescriptor: this.#fileDescriptor,
|
|
38131
|
+
data
|
|
38132
|
+
},
|
|
38133
|
+
taskId: this.#taskId
|
|
38134
|
+
});
|
|
38135
|
+
}
|
|
38136
|
+
/**
|
|
38137
|
+
* Flush any buffered data to the file.
|
|
38138
|
+
*/
|
|
38139
|
+
async flush() {
|
|
38140
|
+
await runFilesystemExec({
|
|
38141
|
+
fileFlushRequest: {
|
|
38142
|
+
fileDescriptor: this.#fileDescriptor
|
|
38143
|
+
},
|
|
38144
|
+
taskId: this.#taskId
|
|
38145
|
+
});
|
|
38146
|
+
}
|
|
38147
|
+
/**
|
|
38148
|
+
* Close the file handle.
|
|
38149
|
+
*/
|
|
38150
|
+
async close() {
|
|
38151
|
+
await runFilesystemExec({
|
|
38152
|
+
fileCloseRequest: {
|
|
38153
|
+
fileDescriptor: this.#fileDescriptor
|
|
38154
|
+
},
|
|
38155
|
+
taskId: this.#taskId
|
|
38156
|
+
});
|
|
38157
|
+
}
|
|
38158
|
+
};
|
|
38159
|
+
async function runFilesystemExec(request) {
|
|
38160
|
+
const response = await client.containerFilesystemExec(request);
|
|
38161
|
+
const chunks = [];
|
|
38162
|
+
let retries = 10;
|
|
38163
|
+
let completed = false;
|
|
38164
|
+
while (!completed) {
|
|
38165
|
+
try {
|
|
38166
|
+
const outputIterator = client.containerFilesystemExecGetOutput({
|
|
38167
|
+
execId: response.execId,
|
|
38168
|
+
timeout: 55
|
|
38169
|
+
});
|
|
38170
|
+
for await (const batch of outputIterator) {
|
|
38171
|
+
chunks.push(...batch.output);
|
|
38172
|
+
if (batch.eof) {
|
|
38173
|
+
completed = true;
|
|
38174
|
+
break;
|
|
38175
|
+
}
|
|
38176
|
+
if (batch.error !== void 0) {
|
|
38177
|
+
if (retries > 0) {
|
|
38178
|
+
retries--;
|
|
38179
|
+
break;
|
|
38180
|
+
}
|
|
38181
|
+
throw new SandboxFilesystemError(batch.error.errorMessage);
|
|
38182
|
+
}
|
|
38183
|
+
}
|
|
38184
|
+
} catch (err) {
|
|
38185
|
+
if (isRetryableGrpc(err) && retries > 0) {
|
|
38186
|
+
retries--;
|
|
38187
|
+
} else throw err;
|
|
38188
|
+
}
|
|
38189
|
+
}
|
|
38190
|
+
return { chunks, response };
|
|
38191
|
+
}
|
|
38192
|
+
|
|
38043
38193
|
// src/streams.ts
|
|
38044
38194
|
function toModalReadStream(stream) {
|
|
38045
38195
|
return Object.assign(stream, readMixin);
|
|
@@ -38172,28 +38322,50 @@ var Sandbox2 = class {
|
|
|
38172
38322
|
).pipeThrough(new TextDecoderStream())
|
|
38173
38323
|
);
|
|
38174
38324
|
}
|
|
38325
|
+
/**
|
|
38326
|
+
* Open a file in the sandbox filesystem.
|
|
38327
|
+
* @param path - Path to the file to open
|
|
38328
|
+
* @param mode - File open mode (r, w, a, r+, w+, a+)
|
|
38329
|
+
* @returns Promise that resolves to a SandboxFile
|
|
38330
|
+
*/
|
|
38331
|
+
async open(path2, mode = "r") {
|
|
38332
|
+
const taskId = await this.#getTaskId();
|
|
38333
|
+
const resp = await runFilesystemExec({
|
|
38334
|
+
fileOpenRequest: {
|
|
38335
|
+
path: path2,
|
|
38336
|
+
mode
|
|
38337
|
+
},
|
|
38338
|
+
taskId
|
|
38339
|
+
});
|
|
38340
|
+
const fileDescriptor = resp.response.fileDescriptor;
|
|
38341
|
+
return new SandboxFile(fileDescriptor, taskId);
|
|
38342
|
+
}
|
|
38175
38343
|
async exec(command, options) {
|
|
38344
|
+
const taskId = await this.#getTaskId();
|
|
38345
|
+
const resp = await client.containerExec({
|
|
38346
|
+
taskId,
|
|
38347
|
+
command
|
|
38348
|
+
});
|
|
38349
|
+
return new ContainerProcess(resp.execId, options);
|
|
38350
|
+
}
|
|
38351
|
+
async #getTaskId() {
|
|
38176
38352
|
if (this.#taskId === void 0) {
|
|
38177
|
-
const
|
|
38353
|
+
const resp = await client.sandboxGetTaskId({
|
|
38178
38354
|
sandboxId: this.sandboxId
|
|
38179
38355
|
});
|
|
38180
|
-
if (!
|
|
38356
|
+
if (!resp.taskId) {
|
|
38181
38357
|
throw new Error(
|
|
38182
38358
|
`Sandbox ${this.sandboxId} does not have a task ID. It may not be running.`
|
|
38183
38359
|
);
|
|
38184
38360
|
}
|
|
38185
|
-
if (
|
|
38361
|
+
if (resp.taskResult) {
|
|
38186
38362
|
throw new Error(
|
|
38187
|
-
`Sandbox ${this.sandboxId} has already completed with result: ${
|
|
38363
|
+
`Sandbox ${this.sandboxId} has already completed with result: ${resp.taskResult}`
|
|
38188
38364
|
);
|
|
38189
38365
|
}
|
|
38190
|
-
this.#taskId =
|
|
38366
|
+
this.#taskId = resp.taskId;
|
|
38191
38367
|
}
|
|
38192
|
-
|
|
38193
|
-
taskId: this.#taskId,
|
|
38194
|
-
command
|
|
38195
|
-
});
|
|
38196
|
-
return new ContainerProcess(resp.execId, options);
|
|
38368
|
+
return this.#taskId;
|
|
38197
38369
|
}
|
|
38198
38370
|
async terminate() {
|
|
38199
38371
|
await client.sandboxTerminate({ sandboxId: this.sandboxId });
|
|
@@ -38363,50 +38535,6 @@ function encodeIfString(chunk) {
|
|
|
38363
38535
|
return typeof chunk === "string" ? new TextEncoder().encode(chunk) : chunk;
|
|
38364
38536
|
}
|
|
38365
38537
|
|
|
38366
|
-
// src/errors.ts
|
|
38367
|
-
var FunctionTimeoutError = class extends Error {
|
|
38368
|
-
constructor(message) {
|
|
38369
|
-
super(message);
|
|
38370
|
-
this.name = "FunctionTimeoutError";
|
|
38371
|
-
}
|
|
38372
|
-
};
|
|
38373
|
-
var RemoteError = class extends Error {
|
|
38374
|
-
constructor(message) {
|
|
38375
|
-
super(message);
|
|
38376
|
-
this.name = "RemoteError";
|
|
38377
|
-
}
|
|
38378
|
-
};
|
|
38379
|
-
var InternalFailure = class extends Error {
|
|
38380
|
-
constructor(message) {
|
|
38381
|
-
super(message);
|
|
38382
|
-
this.name = "InternalFailure";
|
|
38383
|
-
}
|
|
38384
|
-
};
|
|
38385
|
-
var NotFoundError = class extends Error {
|
|
38386
|
-
constructor(message) {
|
|
38387
|
-
super(message);
|
|
38388
|
-
this.name = "NotFoundError";
|
|
38389
|
-
}
|
|
38390
|
-
};
|
|
38391
|
-
var InvalidError = class extends Error {
|
|
38392
|
-
constructor(message) {
|
|
38393
|
-
super(message);
|
|
38394
|
-
this.name = "InvalidError";
|
|
38395
|
-
}
|
|
38396
|
-
};
|
|
38397
|
-
var QueueEmptyError = class extends Error {
|
|
38398
|
-
constructor(message) {
|
|
38399
|
-
super(message);
|
|
38400
|
-
this.name = "QueueEmptyError";
|
|
38401
|
-
}
|
|
38402
|
-
};
|
|
38403
|
-
var QueueFullError = class extends Error {
|
|
38404
|
-
constructor(message) {
|
|
38405
|
-
super(message);
|
|
38406
|
-
this.name = "QueueFullError";
|
|
38407
|
-
}
|
|
38408
|
-
};
|
|
38409
|
-
|
|
38410
38538
|
// src/secret.ts
|
|
38411
38539
|
import { ClientError as ClientError2, Status as Status2 } from "nice-grpc";
|
|
38412
38540
|
var Secret = class _Secret {
|
|
@@ -38505,31 +38633,6 @@ import { ClientError as ClientError5, Status as Status5 } from "nice-grpc";
|
|
|
38505
38633
|
// src/function.ts
|
|
38506
38634
|
import { createHash } from "node:crypto";
|
|
38507
38635
|
|
|
38508
|
-
// src/function_call.ts
|
|
38509
|
-
var FunctionCall = class _FunctionCall {
|
|
38510
|
-
functionCallId;
|
|
38511
|
-
/** @ignore */
|
|
38512
|
-
constructor(functionCallId) {
|
|
38513
|
-
this.functionCallId = functionCallId;
|
|
38514
|
-
}
|
|
38515
|
-
/** Create a new function call from ID. */
|
|
38516
|
-
fromId(functionCallId) {
|
|
38517
|
-
return new _FunctionCall(functionCallId);
|
|
38518
|
-
}
|
|
38519
|
-
/** Get the result of a function call, optionally waiting with a timeout. */
|
|
38520
|
-
async get(options = {}) {
|
|
38521
|
-
const timeout = options.timeout;
|
|
38522
|
-
return await pollFunctionOutput(this.functionCallId, timeout);
|
|
38523
|
-
}
|
|
38524
|
-
/** Cancel a running function call. */
|
|
38525
|
-
async cancel(options = {}) {
|
|
38526
|
-
await client.functionCallCancel({
|
|
38527
|
-
functionCallId: this.functionCallId,
|
|
38528
|
-
terminateContainers: options.terminateContainers
|
|
38529
|
-
});
|
|
38530
|
-
}
|
|
38531
|
-
};
|
|
38532
|
-
|
|
38533
38636
|
// src/pickle.ts
|
|
38534
38637
|
var PickleError = class extends Error {
|
|
38535
38638
|
constructor(message) {
|
|
@@ -38877,79 +38980,62 @@ function loads(buf) {
|
|
|
38877
38980
|
throw new PickleError("pickle stream ended without STOP");
|
|
38878
38981
|
}
|
|
38879
38982
|
|
|
38880
|
-
// src/
|
|
38881
|
-
import { ClientError as ClientError4, Status as Status4 } from "nice-grpc";
|
|
38882
|
-
var maxObjectSizeBytes = 2 * 1024 * 1024;
|
|
38983
|
+
// src/invocation.ts
|
|
38883
38984
|
var outputsTimeout = 55 * 1e3;
|
|
38884
|
-
|
|
38885
|
-
|
|
38886
|
-
|
|
38887
|
-
|
|
38888
|
-
|
|
38889
|
-
|
|
38890
|
-
|
|
38891
|
-
|
|
38892
|
-
this.
|
|
38893
|
-
this.
|
|
38894
|
-
}
|
|
38895
|
-
static async lookup(appName, name, options = {}) {
|
|
38896
|
-
try {
|
|
38897
|
-
const resp = await client.functionGet({
|
|
38898
|
-
appName,
|
|
38899
|
-
objectTag: name,
|
|
38900
|
-
namespace: 1 /* DEPLOYMENT_NAMESPACE_WORKSPACE */,
|
|
38901
|
-
environmentName: environmentName(options.environment)
|
|
38902
|
-
});
|
|
38903
|
-
return new _Function_(resp.functionId);
|
|
38904
|
-
} catch (err) {
|
|
38905
|
-
if (err instanceof ClientError4 && err.code === Status4.NOT_FOUND)
|
|
38906
|
-
throw new NotFoundError(`Function '${appName}/${name}' not found`);
|
|
38907
|
-
throw err;
|
|
38908
|
-
}
|
|
38985
|
+
var ControlPlaneInvocation = class _ControlPlaneInvocation {
|
|
38986
|
+
functionCallId;
|
|
38987
|
+
input;
|
|
38988
|
+
functionCallJwt;
|
|
38989
|
+
inputJwt;
|
|
38990
|
+
constructor(functionCallId, input, functionCallJwt, inputJwt) {
|
|
38991
|
+
this.functionCallId = functionCallId;
|
|
38992
|
+
this.input = input;
|
|
38993
|
+
this.functionCallJwt = functionCallJwt;
|
|
38994
|
+
this.inputJwt = inputJwt;
|
|
38909
38995
|
}
|
|
38910
|
-
|
|
38911
|
-
|
|
38912
|
-
|
|
38913
|
-
|
|
38914
|
-
|
|
38915
|
-
|
|
38996
|
+
static async create(functionId, input, invocationType) {
|
|
38997
|
+
const functionPutInputsItem = {
|
|
38998
|
+
idx: 0,
|
|
38999
|
+
input
|
|
39000
|
+
};
|
|
39001
|
+
const functionMapResponse = await client.functionMap({
|
|
39002
|
+
functionId,
|
|
39003
|
+
functionCallType: 1 /* FUNCTION_CALL_TYPE_UNARY */,
|
|
39004
|
+
functionCallInvocationType: invocationType,
|
|
39005
|
+
pipelinedInputs: [functionPutInputsItem]
|
|
39006
|
+
});
|
|
39007
|
+
return new _ControlPlaneInvocation(
|
|
39008
|
+
functionMapResponse.functionCallId,
|
|
39009
|
+
input,
|
|
39010
|
+
functionMapResponse.functionCallJwt,
|
|
39011
|
+
functionMapResponse.pipelinedInputs[0].inputJwt
|
|
38916
39012
|
);
|
|
38917
|
-
return await pollFunctionOutput(functionCallId);
|
|
38918
39013
|
}
|
|
38919
|
-
|
|
38920
|
-
|
|
38921
|
-
const functionCallId = await this.#execFunctionCall(
|
|
38922
|
-
args,
|
|
38923
|
-
kwargs,
|
|
38924
|
-
4 /* FUNCTION_CALL_INVOCATION_TYPE_SYNC */
|
|
38925
|
-
);
|
|
38926
|
-
return new FunctionCall(functionCallId);
|
|
39014
|
+
static fromFunctionCallId(functionCallId) {
|
|
39015
|
+
return new _ControlPlaneInvocation(functionCallId);
|
|
38927
39016
|
}
|
|
38928
|
-
async
|
|
38929
|
-
|
|
38930
|
-
|
|
38931
|
-
|
|
38932
|
-
|
|
39017
|
+
async awaitOutput(timeout) {
|
|
39018
|
+
return await pollFunctionOutput(this.functionCallId, timeout);
|
|
39019
|
+
}
|
|
39020
|
+
async retry(retryCount) {
|
|
39021
|
+
if (!this.input) {
|
|
39022
|
+
throw new Error("Cannot retry function invocation - input missing");
|
|
38933
39023
|
}
|
|
38934
|
-
const
|
|
38935
|
-
|
|
38936
|
-
|
|
38937
|
-
|
|
38938
|
-
|
|
38939
|
-
|
|
38940
|
-
|
|
38941
|
-
|
|
38942
|
-
args: argsBlobId ? void 0 : payload,
|
|
38943
|
-
argsBlobId,
|
|
38944
|
-
dataFormat: 1 /* DATA_FORMAT_PICKLE */,
|
|
38945
|
-
methodName: this.methodName
|
|
38946
|
-
}
|
|
38947
|
-
}
|
|
38948
|
-
]
|
|
39024
|
+
const retryItem = {
|
|
39025
|
+
inputJwt: this.inputJwt,
|
|
39026
|
+
input: this.input,
|
|
39027
|
+
retryCount
|
|
39028
|
+
};
|
|
39029
|
+
const functionRetryResponse = await client.functionRetryInputs({
|
|
39030
|
+
functionCallJwt: this.functionCallJwt,
|
|
39031
|
+
inputs: [retryItem]
|
|
38949
39032
|
});
|
|
38950
|
-
|
|
39033
|
+
this.inputJwt = functionRetryResponse.inputJwts[0];
|
|
38951
39034
|
}
|
|
38952
39035
|
};
|
|
39036
|
+
function timeNowSeconds() {
|
|
39037
|
+
return Date.now() / 1e3;
|
|
39038
|
+
}
|
|
38953
39039
|
async function pollFunctionOutput(functionCallId, timeout) {
|
|
38954
39040
|
const startTime = Date.now();
|
|
38955
39041
|
let pollTimeout = outputsTimeout;
|
|
@@ -39007,6 +39093,134 @@ async function processResult(result, dataFormat) {
|
|
|
39007
39093
|
}
|
|
39008
39094
|
return deserializeDataFormat(data, dataFormat);
|
|
39009
39095
|
}
|
|
39096
|
+
async function blobDownload(blobId) {
|
|
39097
|
+
const resp = await client.blobGet({ blobId });
|
|
39098
|
+
const s3resp = await fetch(resp.downloadUrl);
|
|
39099
|
+
if (!s3resp.ok) {
|
|
39100
|
+
throw new Error(`Failed to download blob: ${s3resp.statusText}`);
|
|
39101
|
+
}
|
|
39102
|
+
const buf = await s3resp.arrayBuffer();
|
|
39103
|
+
return new Uint8Array(buf);
|
|
39104
|
+
}
|
|
39105
|
+
function deserializeDataFormat(data, dataFormat) {
|
|
39106
|
+
if (!data) {
|
|
39107
|
+
return null;
|
|
39108
|
+
}
|
|
39109
|
+
switch (dataFormat) {
|
|
39110
|
+
case 1 /* DATA_FORMAT_PICKLE */:
|
|
39111
|
+
return loads(data);
|
|
39112
|
+
case 2 /* DATA_FORMAT_ASGI */:
|
|
39113
|
+
throw new Error("ASGI data format is not supported in Go");
|
|
39114
|
+
case 3 /* DATA_FORMAT_GENERATOR_DONE */:
|
|
39115
|
+
return GeneratorDone.decode(data);
|
|
39116
|
+
default:
|
|
39117
|
+
throw new Error(`Unsupported data format: ${dataFormat}`);
|
|
39118
|
+
}
|
|
39119
|
+
}
|
|
39120
|
+
|
|
39121
|
+
// src/function_call.ts
|
|
39122
|
+
var FunctionCall = class _FunctionCall {
|
|
39123
|
+
functionCallId;
|
|
39124
|
+
/** @ignore */
|
|
39125
|
+
constructor(functionCallId) {
|
|
39126
|
+
this.functionCallId = functionCallId;
|
|
39127
|
+
}
|
|
39128
|
+
/** Create a new function call from ID. */
|
|
39129
|
+
fromId(functionCallId) {
|
|
39130
|
+
return new _FunctionCall(functionCallId);
|
|
39131
|
+
}
|
|
39132
|
+
/** Get the result of a function call, optionally waiting with a timeout. */
|
|
39133
|
+
async get(options = {}) {
|
|
39134
|
+
const timeout = options.timeout;
|
|
39135
|
+
const invocation = ControlPlaneInvocation.fromFunctionCallId(
|
|
39136
|
+
this.functionCallId
|
|
39137
|
+
);
|
|
39138
|
+
return invocation.awaitOutput(timeout);
|
|
39139
|
+
}
|
|
39140
|
+
/** Cancel a running function call. */
|
|
39141
|
+
async cancel(options = {}) {
|
|
39142
|
+
await client.functionCallCancel({
|
|
39143
|
+
functionCallId: this.functionCallId,
|
|
39144
|
+
terminateContainers: options.terminateContainers
|
|
39145
|
+
});
|
|
39146
|
+
}
|
|
39147
|
+
};
|
|
39148
|
+
|
|
39149
|
+
// src/function.ts
|
|
39150
|
+
import { ClientError as ClientError4, Status as Status4 } from "nice-grpc";
|
|
39151
|
+
var maxObjectSizeBytes = 2 * 1024 * 1024;
|
|
39152
|
+
var maxSystemRetries = 8;
|
|
39153
|
+
var Function_ = class _Function_ {
|
|
39154
|
+
functionId;
|
|
39155
|
+
methodName;
|
|
39156
|
+
/** @ignore */
|
|
39157
|
+
constructor(functionId, methodName) {
|
|
39158
|
+
this.functionId = functionId;
|
|
39159
|
+
this.methodName = methodName;
|
|
39160
|
+
}
|
|
39161
|
+
static async lookup(appName, name, options = {}) {
|
|
39162
|
+
try {
|
|
39163
|
+
const resp = await client.functionGet({
|
|
39164
|
+
appName,
|
|
39165
|
+
objectTag: name,
|
|
39166
|
+
namespace: 1 /* DEPLOYMENT_NAMESPACE_WORKSPACE */,
|
|
39167
|
+
environmentName: environmentName(options.environment)
|
|
39168
|
+
});
|
|
39169
|
+
return new _Function_(resp.functionId);
|
|
39170
|
+
} catch (err) {
|
|
39171
|
+
if (err instanceof ClientError4 && err.code === Status4.NOT_FOUND)
|
|
39172
|
+
throw new NotFoundError(`Function '${appName}/${name}' not found`);
|
|
39173
|
+
throw err;
|
|
39174
|
+
}
|
|
39175
|
+
}
|
|
39176
|
+
// Execute a single input into a remote Function.
|
|
39177
|
+
async remote(args = [], kwargs = {}) {
|
|
39178
|
+
const input = await this.#createInput(args, kwargs);
|
|
39179
|
+
const invocation = await ControlPlaneInvocation.create(
|
|
39180
|
+
this.functionId,
|
|
39181
|
+
input,
|
|
39182
|
+
4 /* FUNCTION_CALL_INVOCATION_TYPE_SYNC */
|
|
39183
|
+
);
|
|
39184
|
+
let retryCount = 0;
|
|
39185
|
+
while (true) {
|
|
39186
|
+
try {
|
|
39187
|
+
return await invocation.awaitOutput();
|
|
39188
|
+
} catch (err) {
|
|
39189
|
+
if (err instanceof InternalFailure && retryCount <= maxSystemRetries) {
|
|
39190
|
+
await invocation.retry(retryCount);
|
|
39191
|
+
retryCount++;
|
|
39192
|
+
} else {
|
|
39193
|
+
throw err;
|
|
39194
|
+
}
|
|
39195
|
+
}
|
|
39196
|
+
}
|
|
39197
|
+
}
|
|
39198
|
+
// Spawn a single input into a remote function.
|
|
39199
|
+
async spawn(args = [], kwargs = {}) {
|
|
39200
|
+
const input = await this.#createInput(args, kwargs);
|
|
39201
|
+
const invocation = await ControlPlaneInvocation.create(
|
|
39202
|
+
this.functionId,
|
|
39203
|
+
input,
|
|
39204
|
+
3 /* FUNCTION_CALL_INVOCATION_TYPE_ASYNC */
|
|
39205
|
+
);
|
|
39206
|
+
return new FunctionCall(invocation.functionCallId);
|
|
39207
|
+
}
|
|
39208
|
+
async #createInput(args = [], kwargs = {}) {
|
|
39209
|
+
const payload = dumps([args, kwargs]);
|
|
39210
|
+
let argsBlobId = void 0;
|
|
39211
|
+
if (payload.length > maxObjectSizeBytes) {
|
|
39212
|
+
argsBlobId = await blobUpload(payload);
|
|
39213
|
+
}
|
|
39214
|
+
return {
|
|
39215
|
+
args: argsBlobId ? void 0 : payload,
|
|
39216
|
+
argsBlobId,
|
|
39217
|
+
dataFormat: 1 /* DATA_FORMAT_PICKLE */,
|
|
39218
|
+
methodName: this.methodName,
|
|
39219
|
+
finalInput: false
|
|
39220
|
+
// This field isn't specified in the Python client, so it defaults to false.
|
|
39221
|
+
};
|
|
39222
|
+
}
|
|
39223
|
+
};
|
|
39010
39224
|
async function blobUpload(data) {
|
|
39011
39225
|
const contentMd5 = createHash("md5").update(data).digest("base64");
|
|
39012
39226
|
const contentSha256 = createHash("sha256").update(data).digest("base64");
|
|
@@ -39036,30 +39250,6 @@ async function blobUpload(data) {
|
|
|
39036
39250
|
throw new Error("Missing upload URL in BlobCreate response");
|
|
39037
39251
|
}
|
|
39038
39252
|
}
|
|
39039
|
-
async function blobDownload(blobId) {
|
|
39040
|
-
const resp = await client.blobGet({ blobId });
|
|
39041
|
-
const s3resp = await fetch(resp.downloadUrl);
|
|
39042
|
-
if (!s3resp.ok) {
|
|
39043
|
-
throw new Error(`Failed to download blob: ${s3resp.statusText}`);
|
|
39044
|
-
}
|
|
39045
|
-
const buf = await s3resp.arrayBuffer();
|
|
39046
|
-
return new Uint8Array(buf);
|
|
39047
|
-
}
|
|
39048
|
-
function deserializeDataFormat(data, dataFormat) {
|
|
39049
|
-
if (!data) {
|
|
39050
|
-
return null;
|
|
39051
|
-
}
|
|
39052
|
-
switch (dataFormat) {
|
|
39053
|
-
case 1 /* DATA_FORMAT_PICKLE */:
|
|
39054
|
-
return loads(data);
|
|
39055
|
-
case 2 /* DATA_FORMAT_ASGI */:
|
|
39056
|
-
throw new Error("ASGI data format is not supported in Go");
|
|
39057
|
-
case 3 /* DATA_FORMAT_GENERATOR_DONE */:
|
|
39058
|
-
return GeneratorDone.decode(data);
|
|
39059
|
-
default:
|
|
39060
|
-
throw new Error(`Unsupported data format: ${dataFormat}`);
|
|
39061
|
-
}
|
|
39062
|
-
}
|
|
39063
39253
|
|
|
39064
39254
|
// src/cls.ts
|
|
39065
39255
|
var Cls = class _Cls {
|
|
@@ -39461,5 +39651,6 @@ export {
|
|
|
39461
39651
|
QueueFullError,
|
|
39462
39652
|
RemoteError,
|
|
39463
39653
|
Sandbox2 as Sandbox,
|
|
39654
|
+
SandboxFile,
|
|
39464
39655
|
Secret
|
|
39465
39656
|
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "modal",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"description": "Modal client library for JavaScript",
|
|
5
|
-
"license": "
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://modal.com/docs",
|
|
7
7
|
"repository": "github:modal-labs/libmodal",
|
|
8
8
|
"bugs": "https://github.com/modal-labs/libmodal/issues",
|