modal 0.3.5 → 0.3.6
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 -0
- package/dist/index.d.ts +154 -10
- package/dist/index.js +287 -10
- package/package.json +10 -1
package/README.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# Modal JavaScript Library
|
|
2
2
|
|
|
3
|
+
[](https://modal-labs.github.io/libmodal/)
|
|
3
4
|
[](https://www.npmjs.org/package/modal)
|
|
4
5
|
[](https://github.com/modal-labs/libmodal/actions?query=branch%3Amain)
|
|
5
6
|
[](https://www.npmjs.com/package/modal)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { BinaryWriter, BinaryReader } from '@bufbuild/protobuf/wire';
|
|
2
2
|
|
|
3
|
+
/** A container image, used for starting sandboxes. */
|
|
3
4
|
declare class Image {
|
|
4
5
|
readonly imageId: string;
|
|
6
|
+
/** @ignore */
|
|
5
7
|
constructor(imageId: string);
|
|
6
8
|
}
|
|
7
9
|
|
|
@@ -42,19 +44,33 @@ interface ModalWriteStream<R = any> extends WritableStream<R> {
|
|
|
42
44
|
writeBytes(bytes: Uint8Array): Promise<void>;
|
|
43
45
|
}
|
|
44
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Stdin is always present, but this option allow you to drop stdout or stderr
|
|
49
|
+
* if you don't need them. The default is "pipe", matching Node.js behavior.
|
|
50
|
+
*
|
|
51
|
+
* If behavior is set to "ignore", the output streams will be empty.
|
|
52
|
+
*/
|
|
45
53
|
type StdioBehavior = "pipe" | "ignore";
|
|
54
|
+
/**
|
|
55
|
+
* Specifies the type of data that will be read from the sandbox or container
|
|
56
|
+
* process. "text" means the data will be read as UTF-8 text, while "binary"
|
|
57
|
+
* means the data will be read as raw bytes (Uint8Array).
|
|
58
|
+
*/
|
|
46
59
|
type StreamMode = "text" | "binary";
|
|
60
|
+
/** Options to configure a `Sandbox.exec()` operation. */
|
|
47
61
|
type ExecOptions = {
|
|
48
62
|
mode?: StreamMode;
|
|
49
63
|
stdout?: StdioBehavior;
|
|
50
64
|
stderr?: StdioBehavior;
|
|
51
65
|
};
|
|
66
|
+
/** Sandboxes are secure, isolated containers in Modal that boot in seconds. */
|
|
52
67
|
declare class Sandbox {
|
|
53
68
|
#private;
|
|
54
69
|
readonly sandboxId: string;
|
|
55
70
|
stdin: ModalWriteStream<string>;
|
|
56
71
|
stdout: ModalReadStream<string>;
|
|
57
72
|
stderr: ModalReadStream<string>;
|
|
73
|
+
/** @ignore */
|
|
58
74
|
constructor(sandboxId: string);
|
|
59
75
|
exec(command: string[], options?: ExecOptions & {
|
|
60
76
|
mode?: "text";
|
|
@@ -76,18 +92,37 @@ declare class ContainerProcess<R extends string | Uint8Array = any> {
|
|
|
76
92
|
wait(): Promise<number>;
|
|
77
93
|
}
|
|
78
94
|
|
|
95
|
+
/** Options for functions that find deployed Modal objects. */
|
|
79
96
|
type LookupOptions = {
|
|
80
97
|
environment?: string;
|
|
81
98
|
createIfMissing?: boolean;
|
|
82
99
|
};
|
|
100
|
+
/** Options for deleting a named object. */
|
|
101
|
+
type DeleteOptions = {
|
|
102
|
+
environment?: string;
|
|
103
|
+
};
|
|
104
|
+
/** Options for constructors that create a temporary, nameless object. */
|
|
105
|
+
type EphemeralOptions = {
|
|
106
|
+
environment?: string;
|
|
107
|
+
};
|
|
108
|
+
/** Options for `App.createSandbox()`. */
|
|
83
109
|
type SandboxCreateOptions = {
|
|
110
|
+
/** Reservation of physical CPU cores for the sandbox, can be fractional. */
|
|
84
111
|
cpu?: number;
|
|
112
|
+
/** Reservation of memory in MiB. */
|
|
85
113
|
memory?: number;
|
|
114
|
+
/** Timeout of the sandbox container, defaults to 10 minutes. */
|
|
86
115
|
timeout?: number;
|
|
116
|
+
/**
|
|
117
|
+
* Sequence of program arguments for the main process.
|
|
118
|
+
* Default behavior is to sleep indefinitely until timeout or termination.
|
|
119
|
+
*/
|
|
87
120
|
command?: string[];
|
|
88
121
|
};
|
|
122
|
+
/** Represents a deployed Modal App. */
|
|
89
123
|
declare class App {
|
|
90
124
|
readonly appId: string;
|
|
125
|
+
/** @ignore */
|
|
91
126
|
constructor(appId: string);
|
|
92
127
|
/** Lookup a deployed app by name, or create if it does not exist. */
|
|
93
128
|
static lookup(name: string, options?: LookupOptions): Promise<App>;
|
|
@@ -95,14 +130,6 @@ declare class App {
|
|
|
95
130
|
imageFromRegistry(tag: string): Promise<Image>;
|
|
96
131
|
}
|
|
97
132
|
|
|
98
|
-
declare enum FunctionCallInvocationType {
|
|
99
|
-
FUNCTION_CALL_INVOCATION_TYPE_UNSPECIFIED = 0,
|
|
100
|
-
FUNCTION_CALL_INVOCATION_TYPE_SYNC_LEGACY = 1,
|
|
101
|
-
FUNCTION_CALL_INVOCATION_TYPE_ASYNC_LEGACY = 2,
|
|
102
|
-
FUNCTION_CALL_INVOCATION_TYPE_ASYNC = 3,
|
|
103
|
-
FUNCTION_CALL_INVOCATION_TYPE_SYNC = 4,
|
|
104
|
-
UNRECOGNIZED = -1
|
|
105
|
-
}
|
|
106
133
|
declare enum ParameterType {
|
|
107
134
|
PARAM_TYPE_UNSPECIFIED = 0,
|
|
108
135
|
PARAM_TYPE_STRING = 1,
|
|
@@ -153,9 +180,11 @@ interface MessageFns<T> {
|
|
|
153
180
|
fromPartial(object: DeepPartial<T>): T;
|
|
154
181
|
}
|
|
155
182
|
|
|
183
|
+
/** Options for `FunctionCall.get()`. */
|
|
156
184
|
type FunctionCallGetOptions = {
|
|
157
185
|
timeout?: number;
|
|
158
186
|
};
|
|
187
|
+
/** Options for `FunctionCall.cancel()`. */
|
|
159
188
|
type FunctionCallCancelOptions = {
|
|
160
189
|
terminateContainers?: boolean;
|
|
161
190
|
};
|
|
@@ -166,6 +195,7 @@ type FunctionCallCancelOptions = {
|
|
|
166
195
|
*/
|
|
167
196
|
declare class FunctionCall {
|
|
168
197
|
readonly functionCallId: string;
|
|
198
|
+
/** @ignore */
|
|
169
199
|
constructor(functionCallId: string);
|
|
170
200
|
/** Create a new function call from ID. */
|
|
171
201
|
fromId(functionCallId: string): FunctionCall;
|
|
@@ -177,18 +207,20 @@ declare class FunctionCall {
|
|
|
177
207
|
|
|
178
208
|
/** Represents a deployed Modal Function, which can be invoked remotely. */
|
|
179
209
|
declare class Function_ {
|
|
210
|
+
#private;
|
|
180
211
|
readonly functionId: string;
|
|
181
212
|
readonly methodName: string | undefined;
|
|
213
|
+
/** @ignore */
|
|
182
214
|
constructor(functionId: string, methodName?: string);
|
|
183
215
|
static lookup(appName: string, name: string, options?: LookupOptions): Promise<Function_>;
|
|
184
216
|
remote(args?: any[], kwargs?: Record<string, any>): Promise<any>;
|
|
185
217
|
spawn(args?: any[], kwargs?: Record<string, any>): Promise<FunctionCall>;
|
|
186
|
-
execFunctionCall(args?: any[], kwargs?: Record<string, any>, invocationType?: FunctionCallInvocationType): Promise<string>;
|
|
187
218
|
}
|
|
188
219
|
|
|
189
220
|
/** Represents a deployed Modal Cls. */
|
|
190
221
|
declare class Cls {
|
|
191
222
|
#private;
|
|
223
|
+
/** @ignore */
|
|
192
224
|
constructor(serviceFunctionId: string, schema: ClassParameterSpec[], methodNames: string[]);
|
|
193
225
|
static lookup(appName: string, name: string, options?: LookupOptions): Promise<Cls>;
|
|
194
226
|
/** Create a new instance of the Cls with parameters. */
|
|
@@ -217,5 +249,117 @@ declare class InternalFailure extends Error {
|
|
|
217
249
|
declare class NotFoundError extends Error {
|
|
218
250
|
constructor(message: string);
|
|
219
251
|
}
|
|
252
|
+
/** A request or other operation was invalid. */
|
|
253
|
+
declare class InvalidError extends Error {
|
|
254
|
+
constructor(message: string);
|
|
255
|
+
}
|
|
256
|
+
/** The queue is empty. */
|
|
257
|
+
declare class QueueEmptyError extends Error {
|
|
258
|
+
constructor(message: string);
|
|
259
|
+
}
|
|
260
|
+
/** The queue is full. */
|
|
261
|
+
declare class QueueFullError extends Error {
|
|
262
|
+
constructor(message: string);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** Options to configure a `Queue.clear()` operation. */
|
|
266
|
+
type QueueClearOptions = {
|
|
267
|
+
/** Partition to clear, uses default partition if not set. */
|
|
268
|
+
partition?: string;
|
|
269
|
+
/** Set to clear all queue partitions. */
|
|
270
|
+
all?: boolean;
|
|
271
|
+
};
|
|
272
|
+
/** Options to configure a `Queue.get()` or `Queue.getMany()` operation. */
|
|
273
|
+
type QueueGetOptions = {
|
|
274
|
+
/** How long to wait if the queue is empty (default: indefinite). */
|
|
275
|
+
timeout?: number;
|
|
276
|
+
/** Partition to fetch values from, uses default partition if not set. */
|
|
277
|
+
partition?: string;
|
|
278
|
+
};
|
|
279
|
+
/** Options to configure a `Queue.put()` or `Queue.putMany()` operation. */
|
|
280
|
+
type QueuePutOptions = {
|
|
281
|
+
/** How long to wait if the queue is full (default: indefinite). */
|
|
282
|
+
timeout?: number;
|
|
283
|
+
/** Partition to add items to, uses default partition if not set. */
|
|
284
|
+
partition?: string;
|
|
285
|
+
/** TTL for the partition in seconds (default: 1 day). */
|
|
286
|
+
partitionTtl?: number;
|
|
287
|
+
};
|
|
288
|
+
/** Options to configure a `Queue.len()` operation. */
|
|
289
|
+
type QueueLenOptions = {
|
|
290
|
+
/** Partition to compute length, uses default partition if not set. */
|
|
291
|
+
partition?: string;
|
|
292
|
+
/** Return the total length across all partitions. */
|
|
293
|
+
total?: boolean;
|
|
294
|
+
};
|
|
295
|
+
/** Options to configure a `Queue.iterate()` operation. */
|
|
296
|
+
type QueueIterateOptions = {
|
|
297
|
+
/** How long to wait between successive items before exiting iteration (default: 0). */
|
|
298
|
+
itemPollTimeout?: number;
|
|
299
|
+
/** Partition to iterate, uses default partition if not set. */
|
|
300
|
+
partition?: string;
|
|
301
|
+
};
|
|
302
|
+
/**
|
|
303
|
+
* Distributed, FIFO queue for data flow in Modal apps.
|
|
304
|
+
*/
|
|
305
|
+
declare class Queue {
|
|
306
|
+
#private;
|
|
307
|
+
readonly queueId: string;
|
|
308
|
+
/** @ignore */
|
|
309
|
+
constructor(queueId: string, ephemeral?: boolean);
|
|
310
|
+
/**
|
|
311
|
+
* Create a nameless, temporary queue.
|
|
312
|
+
* You will need to call `closeEphemeral()` to delete the queue.
|
|
313
|
+
*/
|
|
314
|
+
static ephemeral(options?: EphemeralOptions): Promise<Queue>;
|
|
315
|
+
/** Delete the ephemeral queue. Only usable with `Queue.ephemeral()`. */
|
|
316
|
+
closeEphemeral(): void;
|
|
317
|
+
/**
|
|
318
|
+
* Lookup a queue by name.
|
|
319
|
+
*/
|
|
320
|
+
static lookup(name: string, options?: LookupOptions): Promise<Queue>;
|
|
321
|
+
/** Delete a queue by name. */
|
|
322
|
+
static delete(name: string, options?: DeleteOptions): Promise<void>;
|
|
323
|
+
/**
|
|
324
|
+
* Remove all objects from a queue partition.
|
|
325
|
+
*/
|
|
326
|
+
clear(options?: QueueClearOptions): Promise<void>;
|
|
327
|
+
/**
|
|
328
|
+
* Remove and return the next object from the queue.
|
|
329
|
+
*
|
|
330
|
+
* By default, this will wait until at least one item is present in the queue.
|
|
331
|
+
* If `timeout` is set, raises `QueueEmptyError` if no items are available
|
|
332
|
+
* within that timeout in milliseconds.
|
|
333
|
+
*/
|
|
334
|
+
get(options?: QueueGetOptions): Promise<any | null>;
|
|
335
|
+
/**
|
|
336
|
+
* Remove and return up to `n` objects from the queue.
|
|
337
|
+
*
|
|
338
|
+
* By default, this will wait until at least one item is present in the queue.
|
|
339
|
+
* If `timeout` is set, raises `QueueEmptyError` if no items are available
|
|
340
|
+
* within that timeout in milliseconds.
|
|
341
|
+
*/
|
|
342
|
+
getMany(n: number, options?: QueueGetOptions): Promise<any[]>;
|
|
343
|
+
/**
|
|
344
|
+
* Add an item to the end of the queue.
|
|
345
|
+
*
|
|
346
|
+
* If the queue is full, this will retry with exponential backoff until the
|
|
347
|
+
* provided `timeout` is reached, or indefinitely if `timeout` is not set.
|
|
348
|
+
* Raises `QueueFullError` if the queue is still full after the timeout.
|
|
349
|
+
*/
|
|
350
|
+
put(v: any, options?: QueuePutOptions): Promise<void>;
|
|
351
|
+
/**
|
|
352
|
+
* Add several items to the end of the queue.
|
|
353
|
+
*
|
|
354
|
+
* If the queue is full, this will retry with exponential backoff until the
|
|
355
|
+
* provided `timeout` is reached, or indefinitely if `timeout` is not set.
|
|
356
|
+
* Raises `QueueFullError` if the queue is still full after the timeout.
|
|
357
|
+
*/
|
|
358
|
+
putMany(values: any[], options?: QueuePutOptions): Promise<void>;
|
|
359
|
+
/** Return the number of objects in the queue. */
|
|
360
|
+
len(options?: QueueLenOptions): Promise<number>;
|
|
361
|
+
/** Iterate through items in a queue without mutation. */
|
|
362
|
+
iterate(options?: QueueIterateOptions): AsyncGenerator<any, void, unknown>;
|
|
363
|
+
}
|
|
220
364
|
|
|
221
|
-
export { App, Cls, ClsInstance, FunctionCall, type FunctionCallCancelOptions, type FunctionCallGetOptions, FunctionTimeoutError, Function_, Image, InternalFailure, type LookupOptions, NotFoundError, RemoteError, Sandbox, type SandboxCreateOptions, type StdioBehavior, type StreamMode };
|
|
365
|
+
export { App, Cls, ClsInstance, ContainerProcess, type DeleteOptions, type EphemeralOptions, type ExecOptions, FunctionCall, type FunctionCallCancelOptions, type FunctionCallGetOptions, FunctionTimeoutError, Function_, Image, InternalFailure, InvalidError, type LookupOptions, type ModalReadStream, type ModalWriteStream, NotFoundError, Queue, type QueueClearOptions, QueueEmptyError, QueueFullError, type QueueGetOptions, type QueueIterateOptions, type QueueLenOptions, type QueuePutOptions, RemoteError, Sandbox, type SandboxCreateOptions, type StdioBehavior, type StreamMode };
|
package/dist/index.js
CHANGED
|
@@ -37831,7 +37831,7 @@ function getProfile(profileName) {
|
|
|
37831
37831
|
);
|
|
37832
37832
|
}
|
|
37833
37833
|
const profileData = profileName ? config[profileName] : {};
|
|
37834
|
-
|
|
37834
|
+
const profile2 = {
|
|
37835
37835
|
serverUrl: process.env["MODAL_SERVER_URL"] || profileData.server_url || "https://api.modal.com:443",
|
|
37836
37836
|
tokenId: process.env["MODAL_TOKEN_ID"] || profileData.token_id,
|
|
37837
37837
|
tokenSecret: process.env["MODAL_TOKEN_SECRET"] || profileData.token_secret,
|
|
@@ -37975,6 +37975,7 @@ var client = createClientFactory().use(authMiddleware(profile)).use(retryMiddlew
|
|
|
37975
37975
|
// src/image.ts
|
|
37976
37976
|
var Image2 = class {
|
|
37977
37977
|
imageId;
|
|
37978
|
+
/** @ignore */
|
|
37978
37979
|
constructor(imageId) {
|
|
37979
37980
|
this.imageId = imageId;
|
|
37980
37981
|
}
|
|
@@ -38013,6 +38014,7 @@ async function fromRegistryInternal(appId, tag) {
|
|
|
38013
38014
|
}
|
|
38014
38015
|
result = resultJoined;
|
|
38015
38016
|
}
|
|
38017
|
+
void metadata;
|
|
38016
38018
|
if (result.status === 2 /* GENERIC_STATUS_FAILURE */) {
|
|
38017
38019
|
throw new Error(
|
|
38018
38020
|
`Image build for ${resp.imageId} failed with the exception:
|
|
@@ -38151,6 +38153,7 @@ var Sandbox2 = class {
|
|
|
38151
38153
|
stdout;
|
|
38152
38154
|
stderr;
|
|
38153
38155
|
#taskId;
|
|
38156
|
+
/** @ignore */
|
|
38154
38157
|
constructor(sandboxId) {
|
|
38155
38158
|
this.sandboxId = sandboxId;
|
|
38156
38159
|
this.stdin = toModalWriteStream(inputStreamSb(sandboxId));
|
|
@@ -38381,10 +38384,29 @@ var NotFoundError = class extends Error {
|
|
|
38381
38384
|
this.name = "NotFoundError";
|
|
38382
38385
|
}
|
|
38383
38386
|
};
|
|
38387
|
+
var InvalidError = class extends Error {
|
|
38388
|
+
constructor(message) {
|
|
38389
|
+
super(message);
|
|
38390
|
+
this.name = "InvalidError";
|
|
38391
|
+
}
|
|
38392
|
+
};
|
|
38393
|
+
var QueueEmptyError = class extends Error {
|
|
38394
|
+
constructor(message) {
|
|
38395
|
+
super(message);
|
|
38396
|
+
this.name = "QueueEmptyError";
|
|
38397
|
+
}
|
|
38398
|
+
};
|
|
38399
|
+
var QueueFullError = class extends Error {
|
|
38400
|
+
constructor(message) {
|
|
38401
|
+
super(message);
|
|
38402
|
+
this.name = "QueueFullError";
|
|
38403
|
+
}
|
|
38404
|
+
};
|
|
38384
38405
|
|
|
38385
38406
|
// src/app.ts
|
|
38386
38407
|
var App = class _App {
|
|
38387
38408
|
appId;
|
|
38409
|
+
/** @ignore */
|
|
38388
38410
|
constructor(appId) {
|
|
38389
38411
|
this.appId = appId;
|
|
38390
38412
|
}
|
|
@@ -38442,6 +38464,7 @@ import { createHash } from "node:crypto";
|
|
|
38442
38464
|
// src/function_call.ts
|
|
38443
38465
|
var FunctionCall = class _FunctionCall {
|
|
38444
38466
|
functionCallId;
|
|
38467
|
+
/** @ignore */
|
|
38445
38468
|
constructor(functionCallId) {
|
|
38446
38469
|
this.functionCallId = functionCallId;
|
|
38447
38470
|
}
|
|
@@ -38570,7 +38593,7 @@ function encodeValue(val, w, proto) {
|
|
|
38570
38593
|
w.byte(140 /* SHORT_BINUNICODE */);
|
|
38571
38594
|
w.byte(utf8.length);
|
|
38572
38595
|
} else if (proto >= 4 && utf8.length > 4294967295) {
|
|
38573
|
-
w.byte(
|
|
38596
|
+
w.byte(141 /* BINUNICODE8 */);
|
|
38574
38597
|
w.uint64LE(utf8.length);
|
|
38575
38598
|
} else {
|
|
38576
38599
|
w.byte(88 /* BINUNICODE */);
|
|
@@ -38583,10 +38606,10 @@ function encodeValue(val, w, proto) {
|
|
|
38583
38606
|
if (val instanceof Uint8Array) {
|
|
38584
38607
|
const len = val.length;
|
|
38585
38608
|
if (proto >= 4 && len < 256) {
|
|
38586
|
-
w.byte(
|
|
38609
|
+
w.byte(67 /* SHORT_BINBYTES */);
|
|
38587
38610
|
w.byte(len);
|
|
38588
38611
|
} else if (proto >= 4 && len > 4294967295) {
|
|
38589
|
-
w.byte(
|
|
38612
|
+
w.byte(142 /* BINBYTES8 */);
|
|
38590
38613
|
w.uint64LE(len);
|
|
38591
38614
|
} else {
|
|
38592
38615
|
w.byte(66 /* BINBYTES */);
|
|
@@ -38698,12 +38721,12 @@ function loads(buf) {
|
|
|
38698
38721
|
push(tdec.decode(r.take(n)));
|
|
38699
38722
|
break;
|
|
38700
38723
|
}
|
|
38701
|
-
case
|
|
38724
|
+
case 141 /* BINUNICODE8 */: {
|
|
38702
38725
|
const n = r.uint64LE();
|
|
38703
38726
|
push(tdec.decode(r.take(n)));
|
|
38704
38727
|
break;
|
|
38705
38728
|
}
|
|
38706
|
-
case
|
|
38729
|
+
case 67 /* SHORT_BINBYTES */: {
|
|
38707
38730
|
const n = r.byte();
|
|
38708
38731
|
push(r.take(n));
|
|
38709
38732
|
break;
|
|
@@ -38713,7 +38736,7 @@ function loads(buf) {
|
|
|
38713
38736
|
push(r.take(n));
|
|
38714
38737
|
break;
|
|
38715
38738
|
}
|
|
38716
|
-
case
|
|
38739
|
+
case 142 /* BINBYTES8 */: {
|
|
38717
38740
|
const n = r.uint64LE();
|
|
38718
38741
|
push(r.take(n));
|
|
38719
38742
|
break;
|
|
@@ -38774,6 +38797,7 @@ function timeNowSeconds() {
|
|
|
38774
38797
|
var Function_ = class _Function_ {
|
|
38775
38798
|
functionId;
|
|
38776
38799
|
methodName;
|
|
38800
|
+
/** @ignore */
|
|
38777
38801
|
constructor(functionId, methodName) {
|
|
38778
38802
|
this.functionId = functionId;
|
|
38779
38803
|
this.methodName = methodName;
|
|
@@ -38795,7 +38819,7 @@ var Function_ = class _Function_ {
|
|
|
38795
38819
|
}
|
|
38796
38820
|
// Execute a single input into a remote Function.
|
|
38797
38821
|
async remote(args = [], kwargs = {}) {
|
|
38798
|
-
const functionCallId = await this
|
|
38822
|
+
const functionCallId = await this.#execFunctionCall(
|
|
38799
38823
|
args,
|
|
38800
38824
|
kwargs,
|
|
38801
38825
|
4 /* FUNCTION_CALL_INVOCATION_TYPE_SYNC */
|
|
@@ -38804,14 +38828,14 @@ var Function_ = class _Function_ {
|
|
|
38804
38828
|
}
|
|
38805
38829
|
// Spawn a single input into a remote function.
|
|
38806
38830
|
async spawn(args = [], kwargs = {}) {
|
|
38807
|
-
const functionCallId = await this
|
|
38831
|
+
const functionCallId = await this.#execFunctionCall(
|
|
38808
38832
|
args,
|
|
38809
38833
|
kwargs,
|
|
38810
38834
|
4 /* FUNCTION_CALL_INVOCATION_TYPE_SYNC */
|
|
38811
38835
|
);
|
|
38812
38836
|
return new FunctionCall(functionCallId);
|
|
38813
38837
|
}
|
|
38814
|
-
async execFunctionCall(args = [], kwargs = {}, invocationType = 4 /* FUNCTION_CALL_INVOCATION_TYPE_SYNC */) {
|
|
38838
|
+
async #execFunctionCall(args = [], kwargs = {}, invocationType = 4 /* FUNCTION_CALL_INVOCATION_TYPE_SYNC */) {
|
|
38815
38839
|
const payload = dumps([args, kwargs]);
|
|
38816
38840
|
let argsBlobId = void 0;
|
|
38817
38841
|
if (payload.length > maxObjectSizeBytes) {
|
|
@@ -38952,6 +38976,7 @@ var Cls = class _Cls {
|
|
|
38952
38976
|
#serviceFunctionId;
|
|
38953
38977
|
#schema;
|
|
38954
38978
|
#methodNames;
|
|
38979
|
+
/** @ignore */
|
|
38955
38980
|
constructor(serviceFunctionId, schema, methodNames) {
|
|
38956
38981
|
this.#serviceFunctionId = serviceFunctionId;
|
|
38957
38982
|
this.#schema = schema;
|
|
@@ -39082,16 +39107,268 @@ var ClsInstance = class {
|
|
|
39082
39107
|
return method;
|
|
39083
39108
|
}
|
|
39084
39109
|
};
|
|
39110
|
+
|
|
39111
|
+
// src/queue.ts
|
|
39112
|
+
import { ClientError as ClientError5, Status as Status5 } from "nice-grpc";
|
|
39113
|
+
var ephemeralObjectHeartbeatSleep = 3e5;
|
|
39114
|
+
var queueInitialPutBackoff = 100;
|
|
39115
|
+
var queueDefaultPartitionTtl = 24 * 3600 * 1e3;
|
|
39116
|
+
var Queue = class _Queue {
|
|
39117
|
+
queueId;
|
|
39118
|
+
#ephemeral;
|
|
39119
|
+
#abortController;
|
|
39120
|
+
/** @ignore */
|
|
39121
|
+
constructor(queueId, ephemeral = false) {
|
|
39122
|
+
this.queueId = queueId;
|
|
39123
|
+
this.#ephemeral = ephemeral;
|
|
39124
|
+
this.#abortController = ephemeral ? new AbortController() : void 0;
|
|
39125
|
+
}
|
|
39126
|
+
static #validatePartitionKey(partition) {
|
|
39127
|
+
if (partition) {
|
|
39128
|
+
const partitionKey = new TextEncoder().encode(partition);
|
|
39129
|
+
if (partitionKey.length === 0 || partitionKey.length > 64) {
|
|
39130
|
+
throw new InvalidError(
|
|
39131
|
+
"Queue partition key must be between 1 and 64 bytes."
|
|
39132
|
+
);
|
|
39133
|
+
}
|
|
39134
|
+
return partitionKey;
|
|
39135
|
+
}
|
|
39136
|
+
return new Uint8Array();
|
|
39137
|
+
}
|
|
39138
|
+
/**
|
|
39139
|
+
* Create a nameless, temporary queue.
|
|
39140
|
+
* You will need to call `closeEphemeral()` to delete the queue.
|
|
39141
|
+
*/
|
|
39142
|
+
static async ephemeral(options = {}) {
|
|
39143
|
+
const resp = await client.queueGetOrCreate({
|
|
39144
|
+
objectCreationType: 5 /* OBJECT_CREATION_TYPE_EPHEMERAL */,
|
|
39145
|
+
environmentName: environmentName(options.environment)
|
|
39146
|
+
});
|
|
39147
|
+
const queue = new _Queue(resp.queueId, true);
|
|
39148
|
+
const signal = queue.#abortController.signal;
|
|
39149
|
+
(async () => {
|
|
39150
|
+
while (true) {
|
|
39151
|
+
await client.queueHeartbeat({ queueId: resp.queueId });
|
|
39152
|
+
await Promise.race([
|
|
39153
|
+
new Promise(
|
|
39154
|
+
(resolve) => setTimeout(resolve, ephemeralObjectHeartbeatSleep)
|
|
39155
|
+
),
|
|
39156
|
+
new Promise((resolve) => {
|
|
39157
|
+
signal.addEventListener("abort", resolve, { once: true });
|
|
39158
|
+
})
|
|
39159
|
+
]);
|
|
39160
|
+
}
|
|
39161
|
+
})();
|
|
39162
|
+
return queue;
|
|
39163
|
+
}
|
|
39164
|
+
/** Delete the ephemeral queue. Only usable with `Queue.ephemeral()`. */
|
|
39165
|
+
closeEphemeral() {
|
|
39166
|
+
if (this.#ephemeral) {
|
|
39167
|
+
this.#abortController.abort();
|
|
39168
|
+
} else {
|
|
39169
|
+
throw new InvalidError("Queue is not ephemeral.");
|
|
39170
|
+
}
|
|
39171
|
+
}
|
|
39172
|
+
/**
|
|
39173
|
+
* Lookup a queue by name.
|
|
39174
|
+
*/
|
|
39175
|
+
static async lookup(name, options = {}) {
|
|
39176
|
+
const resp = await client.queueGetOrCreate({
|
|
39177
|
+
deploymentName: name,
|
|
39178
|
+
objectCreationType: options.createIfMissing ? 1 /* OBJECT_CREATION_TYPE_CREATE_IF_MISSING */ : void 0,
|
|
39179
|
+
namespace: 1 /* DEPLOYMENT_NAMESPACE_WORKSPACE */,
|
|
39180
|
+
environmentName: environmentName(options.environment)
|
|
39181
|
+
});
|
|
39182
|
+
return new _Queue(resp.queueId);
|
|
39183
|
+
}
|
|
39184
|
+
/** Delete a queue by name. */
|
|
39185
|
+
static async delete(name, options = {}) {
|
|
39186
|
+
const queue = await _Queue.lookup(name, options);
|
|
39187
|
+
await client.queueDelete({ queueId: queue.queueId });
|
|
39188
|
+
}
|
|
39189
|
+
/**
|
|
39190
|
+
* Remove all objects from a queue partition.
|
|
39191
|
+
*/
|
|
39192
|
+
async clear(options = {}) {
|
|
39193
|
+
if (options.partition && options.all) {
|
|
39194
|
+
throw new InvalidError(
|
|
39195
|
+
"Partition must be null when requesting to clear all."
|
|
39196
|
+
);
|
|
39197
|
+
}
|
|
39198
|
+
await client.queueClear({
|
|
39199
|
+
queueId: this.queueId,
|
|
39200
|
+
partitionKey: _Queue.#validatePartitionKey(options.partition),
|
|
39201
|
+
allPartitions: options.all
|
|
39202
|
+
});
|
|
39203
|
+
}
|
|
39204
|
+
async #get(n, partition, timeout) {
|
|
39205
|
+
const partitionKey = _Queue.#validatePartitionKey(partition);
|
|
39206
|
+
const startTime = Date.now();
|
|
39207
|
+
let pollTimeout = 5e4;
|
|
39208
|
+
if (timeout !== void 0) {
|
|
39209
|
+
pollTimeout = Math.min(pollTimeout, timeout);
|
|
39210
|
+
}
|
|
39211
|
+
while (true) {
|
|
39212
|
+
const response = await client.queueGet({
|
|
39213
|
+
queueId: this.queueId,
|
|
39214
|
+
partitionKey,
|
|
39215
|
+
timeout: pollTimeout / 1e3,
|
|
39216
|
+
nValues: n
|
|
39217
|
+
});
|
|
39218
|
+
if (response.values && response.values.length > 0) {
|
|
39219
|
+
return response.values.map((value) => loads(value));
|
|
39220
|
+
}
|
|
39221
|
+
if (timeout !== void 0) {
|
|
39222
|
+
const remaining = timeout - (Date.now() - startTime);
|
|
39223
|
+
if (remaining <= 0) {
|
|
39224
|
+
const message = `Queue ${this.queueId} did not return values within ${timeout}ms.`;
|
|
39225
|
+
throw new QueueEmptyError(message);
|
|
39226
|
+
}
|
|
39227
|
+
pollTimeout = Math.min(pollTimeout, remaining);
|
|
39228
|
+
}
|
|
39229
|
+
}
|
|
39230
|
+
}
|
|
39231
|
+
/**
|
|
39232
|
+
* Remove and return the next object from the queue.
|
|
39233
|
+
*
|
|
39234
|
+
* By default, this will wait until at least one item is present in the queue.
|
|
39235
|
+
* If `timeout` is set, raises `QueueEmptyError` if no items are available
|
|
39236
|
+
* within that timeout in milliseconds.
|
|
39237
|
+
*/
|
|
39238
|
+
async get(options = {}) {
|
|
39239
|
+
const values = await this.#get(1, options.partition, options.timeout);
|
|
39240
|
+
return values[0];
|
|
39241
|
+
}
|
|
39242
|
+
/**
|
|
39243
|
+
* Remove and return up to `n` objects from the queue.
|
|
39244
|
+
*
|
|
39245
|
+
* By default, this will wait until at least one item is present in the queue.
|
|
39246
|
+
* If `timeout` is set, raises `QueueEmptyError` if no items are available
|
|
39247
|
+
* within that timeout in milliseconds.
|
|
39248
|
+
*/
|
|
39249
|
+
async getMany(n, options = {}) {
|
|
39250
|
+
return await this.#get(n, options.partition, options.timeout);
|
|
39251
|
+
}
|
|
39252
|
+
async #put(values, timeout, partition, partitionTtl) {
|
|
39253
|
+
const valuesEncoded = values.map((v) => dumps(v));
|
|
39254
|
+
const partitionKey = _Queue.#validatePartitionKey(partition);
|
|
39255
|
+
let delay = queueInitialPutBackoff;
|
|
39256
|
+
const deadline = timeout ? Date.now() + timeout : void 0;
|
|
39257
|
+
while (true) {
|
|
39258
|
+
try {
|
|
39259
|
+
await client.queuePut({
|
|
39260
|
+
queueId: this.queueId,
|
|
39261
|
+
values: valuesEncoded,
|
|
39262
|
+
partitionKey,
|
|
39263
|
+
partitionTtlSeconds: (partitionTtl || queueDefaultPartitionTtl) / 1e3
|
|
39264
|
+
});
|
|
39265
|
+
break;
|
|
39266
|
+
} catch (e) {
|
|
39267
|
+
if (e instanceof ClientError5 && e.code === Status5.RESOURCE_EXHAUSTED) {
|
|
39268
|
+
delay = Math.min(delay * 2, 3e4);
|
|
39269
|
+
if (deadline !== void 0) {
|
|
39270
|
+
const remaining = deadline - Date.now();
|
|
39271
|
+
if (remaining <= 0)
|
|
39272
|
+
throw new QueueFullError(`Put failed on ${this.queueId}.`);
|
|
39273
|
+
delay = Math.min(delay, remaining);
|
|
39274
|
+
}
|
|
39275
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
39276
|
+
} else {
|
|
39277
|
+
throw e;
|
|
39278
|
+
}
|
|
39279
|
+
}
|
|
39280
|
+
}
|
|
39281
|
+
}
|
|
39282
|
+
/**
|
|
39283
|
+
* Add an item to the end of the queue.
|
|
39284
|
+
*
|
|
39285
|
+
* If the queue is full, this will retry with exponential backoff until the
|
|
39286
|
+
* provided `timeout` is reached, or indefinitely if `timeout` is not set.
|
|
39287
|
+
* Raises `QueueFullError` if the queue is still full after the timeout.
|
|
39288
|
+
*/
|
|
39289
|
+
async put(v, options = {}) {
|
|
39290
|
+
await this.#put(
|
|
39291
|
+
[v],
|
|
39292
|
+
options.timeout,
|
|
39293
|
+
options.partition,
|
|
39294
|
+
options.partitionTtl
|
|
39295
|
+
);
|
|
39296
|
+
}
|
|
39297
|
+
/**
|
|
39298
|
+
* Add several items to the end of the queue.
|
|
39299
|
+
*
|
|
39300
|
+
* If the queue is full, this will retry with exponential backoff until the
|
|
39301
|
+
* provided `timeout` is reached, or indefinitely if `timeout` is not set.
|
|
39302
|
+
* Raises `QueueFullError` if the queue is still full after the timeout.
|
|
39303
|
+
*/
|
|
39304
|
+
async putMany(values, options = {}) {
|
|
39305
|
+
await this.#put(
|
|
39306
|
+
values,
|
|
39307
|
+
options.timeout,
|
|
39308
|
+
options.partition,
|
|
39309
|
+
options.partitionTtl
|
|
39310
|
+
);
|
|
39311
|
+
}
|
|
39312
|
+
/** Return the number of objects in the queue. */
|
|
39313
|
+
async len(options = {}) {
|
|
39314
|
+
if (options.partition && options.total) {
|
|
39315
|
+
throw new InvalidError(
|
|
39316
|
+
"Partition must be null when requesting total length."
|
|
39317
|
+
);
|
|
39318
|
+
}
|
|
39319
|
+
const resp = await client.queueLen({
|
|
39320
|
+
queueId: this.queueId,
|
|
39321
|
+
partitionKey: _Queue.#validatePartitionKey(options.partition),
|
|
39322
|
+
total: options.total
|
|
39323
|
+
});
|
|
39324
|
+
return resp.len;
|
|
39325
|
+
}
|
|
39326
|
+
/** Iterate through items in a queue without mutation. */
|
|
39327
|
+
async *iterate(options = {}) {
|
|
39328
|
+
const { partition, itemPollTimeout = 0 } = options;
|
|
39329
|
+
let lastEntryId = void 0;
|
|
39330
|
+
const validatedPartitionKey = _Queue.#validatePartitionKey(partition);
|
|
39331
|
+
let fetchDeadline = Date.now() + itemPollTimeout;
|
|
39332
|
+
const maxPollDuration = 3e4;
|
|
39333
|
+
while (true) {
|
|
39334
|
+
const pollDuration = Math.max(
|
|
39335
|
+
0,
|
|
39336
|
+
Math.min(maxPollDuration, fetchDeadline - Date.now())
|
|
39337
|
+
);
|
|
39338
|
+
const request = {
|
|
39339
|
+
queueId: this.queueId,
|
|
39340
|
+
partitionKey: validatedPartitionKey,
|
|
39341
|
+
itemPollTimeout: pollDuration / 1e3,
|
|
39342
|
+
lastEntryId: lastEntryId || ""
|
|
39343
|
+
};
|
|
39344
|
+
const response = await client.queueNextItems(request);
|
|
39345
|
+
if (response.items && response.items.length > 0) {
|
|
39346
|
+
for (const item of response.items) {
|
|
39347
|
+
yield loads(item.value);
|
|
39348
|
+
lastEntryId = item.entryId;
|
|
39349
|
+
}
|
|
39350
|
+
fetchDeadline = Date.now() + itemPollTimeout;
|
|
39351
|
+
} else if (Date.now() > fetchDeadline) {
|
|
39352
|
+
break;
|
|
39353
|
+
}
|
|
39354
|
+
}
|
|
39355
|
+
}
|
|
39356
|
+
};
|
|
39085
39357
|
export {
|
|
39086
39358
|
App,
|
|
39087
39359
|
Cls,
|
|
39088
39360
|
ClsInstance,
|
|
39361
|
+
ContainerProcess,
|
|
39089
39362
|
FunctionCall,
|
|
39090
39363
|
FunctionTimeoutError,
|
|
39091
39364
|
Function_,
|
|
39092
39365
|
Image2 as Image,
|
|
39093
39366
|
InternalFailure,
|
|
39367
|
+
InvalidError,
|
|
39094
39368
|
NotFoundError,
|
|
39369
|
+
Queue,
|
|
39370
|
+
QueueEmptyError,
|
|
39371
|
+
QueueFullError,
|
|
39095
39372
|
RemoteError,
|
|
39096
39373
|
Sandbox2 as Sandbox
|
|
39097
39374
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "modal",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "Modal client library for JavaScript",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://modal.com/docs",
|
|
@@ -23,8 +23,11 @@
|
|
|
23
23
|
"scripts": {
|
|
24
24
|
"build": "tsup",
|
|
25
25
|
"check": "tsc",
|
|
26
|
+
"docs": "typedoc src/index.ts --treatWarningsAsErrors",
|
|
27
|
+
"docs:serve": "npm run docs && http-server ./docs",
|
|
26
28
|
"format": "prettier --write .",
|
|
27
29
|
"format:check": "prettier --check .",
|
|
30
|
+
"lint": "eslint",
|
|
28
31
|
"prepare": "scripts/gen-proto.sh",
|
|
29
32
|
"test": "vitest"
|
|
30
33
|
},
|
|
@@ -36,14 +39,20 @@
|
|
|
36
39
|
"uuid": "^11.1.0"
|
|
37
40
|
},
|
|
38
41
|
"devDependencies": {
|
|
42
|
+
"@eslint/js": "^9.28.0",
|
|
39
43
|
"@types/node": "^22.15.2",
|
|
44
|
+
"eslint": "^9.28.0",
|
|
45
|
+
"globals": "^16.2.0",
|
|
40
46
|
"grpc-tools": "^1.13.0",
|
|
47
|
+
"http-server": "^14.1.1",
|
|
41
48
|
"p-queue": "^8.1.0",
|
|
42
49
|
"prettier": "^3.5.3",
|
|
43
50
|
"ts-proto": "^2.7.0",
|
|
44
51
|
"tsup": "^8.4.0",
|
|
45
52
|
"tsx": "^4.19.3",
|
|
53
|
+
"typedoc": "^0.28.5",
|
|
46
54
|
"typescript": "~5.8.3",
|
|
55
|
+
"typescript-eslint": "^8.33.1",
|
|
47
56
|
"vitest": "^3.1.2"
|
|
48
57
|
}
|
|
49
58
|
}
|