modal 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.d.ts +219 -60
- package/dist/index.js +392 -24
- package/package.json +14 -2
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,59 @@
|
|
|
1
1
|
import { BinaryWriter, BinaryReader } from '@bufbuild/protobuf/wire';
|
|
2
2
|
|
|
3
|
+
declare enum ParameterType {
|
|
4
|
+
PARAM_TYPE_UNSPECIFIED = 0,
|
|
5
|
+
PARAM_TYPE_STRING = 1,
|
|
6
|
+
PARAM_TYPE_INT = 2,
|
|
7
|
+
/** PARAM_TYPE_PICKLE - currently unused */
|
|
8
|
+
PARAM_TYPE_PICKLE = 3,
|
|
9
|
+
PARAM_TYPE_BYTES = 4,
|
|
10
|
+
/** PARAM_TYPE_UNKNOWN - used in schemas to signify unrecognized or un-annotated types */
|
|
11
|
+
PARAM_TYPE_UNKNOWN = 5,
|
|
12
|
+
PARAM_TYPE_LIST = 6,
|
|
13
|
+
PARAM_TYPE_DICT = 7,
|
|
14
|
+
PARAM_TYPE_NONE = 8,
|
|
15
|
+
PARAM_TYPE_BOOL = 9,
|
|
16
|
+
UNRECOGNIZED = -1
|
|
17
|
+
}
|
|
18
|
+
/** TODO: rename into NamedPayloadType or similar */
|
|
19
|
+
interface ClassParameterSpec {
|
|
20
|
+
name: string;
|
|
21
|
+
/** TODO: deprecate - use full_type instead */
|
|
22
|
+
type: ParameterType;
|
|
23
|
+
hasDefault: boolean;
|
|
24
|
+
/** Default *values* are only registered for class parameters */
|
|
25
|
+
stringDefault?: string | undefined;
|
|
26
|
+
intDefault?: number | undefined;
|
|
27
|
+
pickleDefault?: Uint8Array | undefined;
|
|
28
|
+
bytesDefault?: Uint8Array | undefined;
|
|
29
|
+
boolDefault?: boolean | undefined;
|
|
30
|
+
/** supersedes `type` */
|
|
31
|
+
fullType: GenericPayloadType | undefined;
|
|
32
|
+
}
|
|
33
|
+
declare const ClassParameterSpec: MessageFns<ClassParameterSpec>;
|
|
34
|
+
interface GenericPayloadType {
|
|
35
|
+
baseType: ParameterType;
|
|
36
|
+
/** sub-type for generic types like lists */
|
|
37
|
+
subTypes: GenericPayloadType[];
|
|
38
|
+
}
|
|
39
|
+
declare const GenericPayloadType: MessageFns<GenericPayloadType>;
|
|
40
|
+
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
|
|
41
|
+
type DeepPartial<T> = T extends Builtin ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : T extends {} ? {
|
|
42
|
+
[K in keyof T]?: DeepPartial<T[K]>;
|
|
43
|
+
} : Partial<T>;
|
|
44
|
+
interface MessageFns<T> {
|
|
45
|
+
encode(message: T, writer?: BinaryWriter): BinaryWriter;
|
|
46
|
+
decode(input: BinaryReader | Uint8Array, length?: number): T;
|
|
47
|
+
fromJSON(object: any): T;
|
|
48
|
+
toJSON(message: T): unknown;
|
|
49
|
+
create(base?: DeepPartial<T>): T;
|
|
50
|
+
fromPartial(object: DeepPartial<T>): T;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** A container image, used for starting sandboxes. */
|
|
3
54
|
declare class Image {
|
|
4
55
|
readonly imageId: string;
|
|
56
|
+
/** @ignore */
|
|
5
57
|
constructor(imageId: string);
|
|
6
58
|
}
|
|
7
59
|
|
|
@@ -42,19 +94,33 @@ interface ModalWriteStream<R = any> extends WritableStream<R> {
|
|
|
42
94
|
writeBytes(bytes: Uint8Array): Promise<void>;
|
|
43
95
|
}
|
|
44
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Stdin is always present, but this option allow you to drop stdout or stderr
|
|
99
|
+
* if you don't need them. The default is "pipe", matching Node.js behavior.
|
|
100
|
+
*
|
|
101
|
+
* If behavior is set to "ignore", the output streams will be empty.
|
|
102
|
+
*/
|
|
45
103
|
type StdioBehavior = "pipe" | "ignore";
|
|
104
|
+
/**
|
|
105
|
+
* Specifies the type of data that will be read from the sandbox or container
|
|
106
|
+
* process. "text" means the data will be read as UTF-8 text, while "binary"
|
|
107
|
+
* means the data will be read as raw bytes (Uint8Array).
|
|
108
|
+
*/
|
|
46
109
|
type StreamMode = "text" | "binary";
|
|
110
|
+
/** Options to configure a `Sandbox.exec()` operation. */
|
|
47
111
|
type ExecOptions = {
|
|
48
112
|
mode?: StreamMode;
|
|
49
113
|
stdout?: StdioBehavior;
|
|
50
114
|
stderr?: StdioBehavior;
|
|
51
115
|
};
|
|
116
|
+
/** Sandboxes are secure, isolated containers in Modal that boot in seconds. */
|
|
52
117
|
declare class Sandbox {
|
|
53
118
|
#private;
|
|
54
119
|
readonly sandboxId: string;
|
|
55
120
|
stdin: ModalWriteStream<string>;
|
|
56
121
|
stdout: ModalReadStream<string>;
|
|
57
122
|
stderr: ModalReadStream<string>;
|
|
123
|
+
/** @ignore */
|
|
58
124
|
constructor(sandboxId: string);
|
|
59
125
|
exec(command: string[], options?: ExecOptions & {
|
|
60
126
|
mode?: "text";
|
|
@@ -76,86 +142,64 @@ declare class ContainerProcess<R extends string | Uint8Array = any> {
|
|
|
76
142
|
wait(): Promise<number>;
|
|
77
143
|
}
|
|
78
144
|
|
|
145
|
+
/** Options for `Secret.fromName()`. */
|
|
146
|
+
type SecretFromNameOptions = {
|
|
147
|
+
environment?: string;
|
|
148
|
+
requiredKeys?: string[];
|
|
149
|
+
};
|
|
150
|
+
/** Secrets provide a dictionary of environment variables for images. */
|
|
151
|
+
declare class Secret {
|
|
152
|
+
readonly secretId: string;
|
|
153
|
+
/** @ignore */
|
|
154
|
+
constructor(secretId: string);
|
|
155
|
+
/** Reference a Secret by its name. */
|
|
156
|
+
static fromName(name: string, options?: SecretFromNameOptions): Promise<Secret>;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Options for functions that find deployed Modal objects. */
|
|
79
160
|
type LookupOptions = {
|
|
80
161
|
environment?: string;
|
|
81
162
|
createIfMissing?: boolean;
|
|
82
163
|
};
|
|
164
|
+
/** Options for deleting a named object. */
|
|
165
|
+
type DeleteOptions = {
|
|
166
|
+
environment?: string;
|
|
167
|
+
};
|
|
168
|
+
/** Options for constructors that create a temporary, nameless object. */
|
|
169
|
+
type EphemeralOptions = {
|
|
170
|
+
environment?: string;
|
|
171
|
+
};
|
|
172
|
+
/** Options for `App.createSandbox()`. */
|
|
83
173
|
type SandboxCreateOptions = {
|
|
174
|
+
/** Reservation of physical CPU cores for the sandbox, can be fractional. */
|
|
84
175
|
cpu?: number;
|
|
176
|
+
/** Reservation of memory in MiB. */
|
|
85
177
|
memory?: number;
|
|
178
|
+
/** Timeout of the sandbox container, defaults to 10 minutes. */
|
|
86
179
|
timeout?: number;
|
|
180
|
+
/**
|
|
181
|
+
* Sequence of program arguments for the main process.
|
|
182
|
+
* Default behavior is to sleep indefinitely until timeout or termination.
|
|
183
|
+
*/
|
|
87
184
|
command?: string[];
|
|
88
185
|
};
|
|
186
|
+
/** Represents a deployed Modal App. */
|
|
89
187
|
declare class App {
|
|
90
188
|
readonly appId: string;
|
|
189
|
+
/** @ignore */
|
|
91
190
|
constructor(appId: string);
|
|
92
191
|
/** Lookup a deployed app by name, or create if it does not exist. */
|
|
93
192
|
static lookup(name: string, options?: LookupOptions): Promise<App>;
|
|
94
193
|
createSandbox(image: Image, options?: SandboxCreateOptions): Promise<Sandbox>;
|
|
95
194
|
imageFromRegistry(tag: string): Promise<Image>;
|
|
195
|
+
imageFromAwsEcr(tag: string, secret: Secret): Promise<Image>;
|
|
96
196
|
}
|
|
97
197
|
|
|
98
|
-
|
|
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
|
-
declare enum ParameterType {
|
|
107
|
-
PARAM_TYPE_UNSPECIFIED = 0,
|
|
108
|
-
PARAM_TYPE_STRING = 1,
|
|
109
|
-
PARAM_TYPE_INT = 2,
|
|
110
|
-
/** PARAM_TYPE_PICKLE - currently unused */
|
|
111
|
-
PARAM_TYPE_PICKLE = 3,
|
|
112
|
-
PARAM_TYPE_BYTES = 4,
|
|
113
|
-
/** PARAM_TYPE_UNKNOWN - used in schemas to signify unrecognized or un-annotated types */
|
|
114
|
-
PARAM_TYPE_UNKNOWN = 5,
|
|
115
|
-
PARAM_TYPE_LIST = 6,
|
|
116
|
-
PARAM_TYPE_DICT = 7,
|
|
117
|
-
PARAM_TYPE_NONE = 8,
|
|
118
|
-
PARAM_TYPE_BOOL = 9,
|
|
119
|
-
UNRECOGNIZED = -1
|
|
120
|
-
}
|
|
121
|
-
/** TODO: rename into NamedPayloadType or similar */
|
|
122
|
-
interface ClassParameterSpec {
|
|
123
|
-
name: string;
|
|
124
|
-
/** TODO: deprecate - use full_type instead */
|
|
125
|
-
type: ParameterType;
|
|
126
|
-
hasDefault: boolean;
|
|
127
|
-
/** Default *values* are only registered for class parameters */
|
|
128
|
-
stringDefault?: string | undefined;
|
|
129
|
-
intDefault?: number | undefined;
|
|
130
|
-
pickleDefault?: Uint8Array | undefined;
|
|
131
|
-
bytesDefault?: Uint8Array | undefined;
|
|
132
|
-
boolDefault?: boolean | undefined;
|
|
133
|
-
/** supersedes `type` */
|
|
134
|
-
fullType: GenericPayloadType | undefined;
|
|
135
|
-
}
|
|
136
|
-
declare const ClassParameterSpec: MessageFns<ClassParameterSpec>;
|
|
137
|
-
interface GenericPayloadType {
|
|
138
|
-
baseType: ParameterType;
|
|
139
|
-
/** sub-type for generic types like lists */
|
|
140
|
-
subTypes: GenericPayloadType[];
|
|
141
|
-
}
|
|
142
|
-
declare const GenericPayloadType: MessageFns<GenericPayloadType>;
|
|
143
|
-
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
|
|
144
|
-
type DeepPartial<T> = T extends Builtin ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : T extends {} ? {
|
|
145
|
-
[K in keyof T]?: DeepPartial<T[K]>;
|
|
146
|
-
} : Partial<T>;
|
|
147
|
-
interface MessageFns<T> {
|
|
148
|
-
encode(message: T, writer?: BinaryWriter): BinaryWriter;
|
|
149
|
-
decode(input: BinaryReader | Uint8Array, length?: number): T;
|
|
150
|
-
fromJSON(object: any): T;
|
|
151
|
-
toJSON(message: T): unknown;
|
|
152
|
-
create(base?: DeepPartial<T>): T;
|
|
153
|
-
fromPartial(object: DeepPartial<T>): T;
|
|
154
|
-
}
|
|
155
|
-
|
|
198
|
+
/** Options for `FunctionCall.get()`. */
|
|
156
199
|
type FunctionCallGetOptions = {
|
|
157
200
|
timeout?: number;
|
|
158
201
|
};
|
|
202
|
+
/** Options for `FunctionCall.cancel()`. */
|
|
159
203
|
type FunctionCallCancelOptions = {
|
|
160
204
|
terminateContainers?: boolean;
|
|
161
205
|
};
|
|
@@ -166,6 +210,7 @@ type FunctionCallCancelOptions = {
|
|
|
166
210
|
*/
|
|
167
211
|
declare class FunctionCall {
|
|
168
212
|
readonly functionCallId: string;
|
|
213
|
+
/** @ignore */
|
|
169
214
|
constructor(functionCallId: string);
|
|
170
215
|
/** Create a new function call from ID. */
|
|
171
216
|
fromId(functionCallId: string): FunctionCall;
|
|
@@ -177,18 +222,20 @@ declare class FunctionCall {
|
|
|
177
222
|
|
|
178
223
|
/** Represents a deployed Modal Function, which can be invoked remotely. */
|
|
179
224
|
declare class Function_ {
|
|
225
|
+
#private;
|
|
180
226
|
readonly functionId: string;
|
|
181
227
|
readonly methodName: string | undefined;
|
|
228
|
+
/** @ignore */
|
|
182
229
|
constructor(functionId: string, methodName?: string);
|
|
183
230
|
static lookup(appName: string, name: string, options?: LookupOptions): Promise<Function_>;
|
|
184
231
|
remote(args?: any[], kwargs?: Record<string, any>): Promise<any>;
|
|
185
232
|
spawn(args?: any[], kwargs?: Record<string, any>): Promise<FunctionCall>;
|
|
186
|
-
execFunctionCall(args?: any[], kwargs?: Record<string, any>, invocationType?: FunctionCallInvocationType): Promise<string>;
|
|
187
233
|
}
|
|
188
234
|
|
|
189
235
|
/** Represents a deployed Modal Cls. */
|
|
190
236
|
declare class Cls {
|
|
191
237
|
#private;
|
|
238
|
+
/** @ignore */
|
|
192
239
|
constructor(serviceFunctionId: string, schema: ClassParameterSpec[], methodNames: string[]);
|
|
193
240
|
static lookup(appName: string, name: string, options?: LookupOptions): Promise<Cls>;
|
|
194
241
|
/** Create a new instance of the Cls with parameters. */
|
|
@@ -217,5 +264,117 @@ declare class InternalFailure extends Error {
|
|
|
217
264
|
declare class NotFoundError extends Error {
|
|
218
265
|
constructor(message: string);
|
|
219
266
|
}
|
|
267
|
+
/** A request or other operation was invalid. */
|
|
268
|
+
declare class InvalidError extends Error {
|
|
269
|
+
constructor(message: string);
|
|
270
|
+
}
|
|
271
|
+
/** The queue is empty. */
|
|
272
|
+
declare class QueueEmptyError extends Error {
|
|
273
|
+
constructor(message: string);
|
|
274
|
+
}
|
|
275
|
+
/** The queue is full. */
|
|
276
|
+
declare class QueueFullError extends Error {
|
|
277
|
+
constructor(message: string);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/** Options to configure a `Queue.clear()` operation. */
|
|
281
|
+
type QueueClearOptions = {
|
|
282
|
+
/** Partition to clear, uses default partition if not set. */
|
|
283
|
+
partition?: string;
|
|
284
|
+
/** Set to clear all queue partitions. */
|
|
285
|
+
all?: boolean;
|
|
286
|
+
};
|
|
287
|
+
/** Options to configure a `Queue.get()` or `Queue.getMany()` operation. */
|
|
288
|
+
type QueueGetOptions = {
|
|
289
|
+
/** How long to wait if the queue is empty (default: indefinite). */
|
|
290
|
+
timeout?: number;
|
|
291
|
+
/** Partition to fetch values from, uses default partition if not set. */
|
|
292
|
+
partition?: string;
|
|
293
|
+
};
|
|
294
|
+
/** Options to configure a `Queue.put()` or `Queue.putMany()` operation. */
|
|
295
|
+
type QueuePutOptions = {
|
|
296
|
+
/** How long to wait if the queue is full (default: indefinite). */
|
|
297
|
+
timeout?: number;
|
|
298
|
+
/** Partition to add items to, uses default partition if not set. */
|
|
299
|
+
partition?: string;
|
|
300
|
+
/** TTL for the partition in seconds (default: 1 day). */
|
|
301
|
+
partitionTtl?: number;
|
|
302
|
+
};
|
|
303
|
+
/** Options to configure a `Queue.len()` operation. */
|
|
304
|
+
type QueueLenOptions = {
|
|
305
|
+
/** Partition to compute length, uses default partition if not set. */
|
|
306
|
+
partition?: string;
|
|
307
|
+
/** Return the total length across all partitions. */
|
|
308
|
+
total?: boolean;
|
|
309
|
+
};
|
|
310
|
+
/** Options to configure a `Queue.iterate()` operation. */
|
|
311
|
+
type QueueIterateOptions = {
|
|
312
|
+
/** How long to wait between successive items before exiting iteration (default: 0). */
|
|
313
|
+
itemPollTimeout?: number;
|
|
314
|
+
/** Partition to iterate, uses default partition if not set. */
|
|
315
|
+
partition?: string;
|
|
316
|
+
};
|
|
317
|
+
/**
|
|
318
|
+
* Distributed, FIFO queue for data flow in Modal apps.
|
|
319
|
+
*/
|
|
320
|
+
declare class Queue {
|
|
321
|
+
#private;
|
|
322
|
+
readonly queueId: string;
|
|
323
|
+
/** @ignore */
|
|
324
|
+
constructor(queueId: string, ephemeral?: boolean);
|
|
325
|
+
/**
|
|
326
|
+
* Create a nameless, temporary queue.
|
|
327
|
+
* You will need to call `closeEphemeral()` to delete the queue.
|
|
328
|
+
*/
|
|
329
|
+
static ephemeral(options?: EphemeralOptions): Promise<Queue>;
|
|
330
|
+
/** Delete the ephemeral queue. Only usable with `Queue.ephemeral()`. */
|
|
331
|
+
closeEphemeral(): void;
|
|
332
|
+
/**
|
|
333
|
+
* Lookup a queue by name.
|
|
334
|
+
*/
|
|
335
|
+
static lookup(name: string, options?: LookupOptions): Promise<Queue>;
|
|
336
|
+
/** Delete a queue by name. */
|
|
337
|
+
static delete(name: string, options?: DeleteOptions): Promise<void>;
|
|
338
|
+
/**
|
|
339
|
+
* Remove all objects from a queue partition.
|
|
340
|
+
*/
|
|
341
|
+
clear(options?: QueueClearOptions): Promise<void>;
|
|
342
|
+
/**
|
|
343
|
+
* Remove and return the next object from the queue.
|
|
344
|
+
*
|
|
345
|
+
* By default, this will wait until at least one item is present in the queue.
|
|
346
|
+
* If `timeout` is set, raises `QueueEmptyError` if no items are available
|
|
347
|
+
* within that timeout in milliseconds.
|
|
348
|
+
*/
|
|
349
|
+
get(options?: QueueGetOptions): Promise<any | null>;
|
|
350
|
+
/**
|
|
351
|
+
* Remove and return up to `n` objects from the queue.
|
|
352
|
+
*
|
|
353
|
+
* By default, this will wait until at least one item is present in the queue.
|
|
354
|
+
* If `timeout` is set, raises `QueueEmptyError` if no items are available
|
|
355
|
+
* within that timeout in milliseconds.
|
|
356
|
+
*/
|
|
357
|
+
getMany(n: number, options?: QueueGetOptions): Promise<any[]>;
|
|
358
|
+
/**
|
|
359
|
+
* Add an item to the end of the queue.
|
|
360
|
+
*
|
|
361
|
+
* If the queue is full, this will retry with exponential backoff until the
|
|
362
|
+
* provided `timeout` is reached, or indefinitely if `timeout` is not set.
|
|
363
|
+
* Raises `QueueFullError` if the queue is still full after the timeout.
|
|
364
|
+
*/
|
|
365
|
+
put(v: any, options?: QueuePutOptions): Promise<void>;
|
|
366
|
+
/**
|
|
367
|
+
* Add several items to the end of the queue.
|
|
368
|
+
*
|
|
369
|
+
* If the queue is full, this will retry with exponential backoff until the
|
|
370
|
+
* provided `timeout` is reached, or indefinitely if `timeout` is not set.
|
|
371
|
+
* Raises `QueueFullError` if the queue is still full after the timeout.
|
|
372
|
+
*/
|
|
373
|
+
putMany(values: any[], options?: QueuePutOptions): Promise<void>;
|
|
374
|
+
/** Return the number of objects in the queue. */
|
|
375
|
+
len(options?: QueueLenOptions): Promise<number>;
|
|
376
|
+
/** Iterate through items in a queue without mutation. */
|
|
377
|
+
iterate(options?: QueueIterateOptions): AsyncGenerator<any, void, unknown>;
|
|
378
|
+
}
|
|
220
379
|
|
|
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 };
|
|
380
|
+
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, Secret, type SecretFromNameOptions, type StdioBehavior, type StreamMode };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/app.ts
|
|
2
|
-
import { ClientError as
|
|
2
|
+
import { ClientError as ClientError3, Status as Status3 } from "nice-grpc";
|
|
3
3
|
|
|
4
4
|
// node_modules/@bufbuild/protobuf/dist/esm/wire/varint.js
|
|
5
5
|
function varint64read() {
|
|
@@ -37831,11 +37831,12 @@ 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,
|
|
37838
|
-
environment: process.env["MODAL_ENVIRONMENT"] || profileData.environment
|
|
37838
|
+
environment: process.env["MODAL_ENVIRONMENT"] || profileData.environment,
|
|
37839
|
+
imageBuilderVersion: process.env["MODAL_IMAGE_BUILDER_VERSION"] || profileData.imageBuilderVersion
|
|
37839
37840
|
};
|
|
37840
37841
|
if (!profile2.tokenId || !profile2.tokenSecret) {
|
|
37841
37842
|
throw new Error(
|
|
@@ -37848,6 +37849,9 @@ var profile = getProfile(process.env["MODAL_PROFILE"] || void 0);
|
|
|
37848
37849
|
function environmentName(environment) {
|
|
37849
37850
|
return environment || profile.environment || "";
|
|
37850
37851
|
}
|
|
37852
|
+
function imageBuilderVersion(version) {
|
|
37853
|
+
return version || profile.imageBuilderVersion || "2024.10";
|
|
37854
|
+
}
|
|
37851
37855
|
|
|
37852
37856
|
// src/client.ts
|
|
37853
37857
|
function authMiddleware(profile2) {
|
|
@@ -37975,19 +37979,20 @@ var client = createClientFactory().use(authMiddleware(profile)).use(retryMiddlew
|
|
|
37975
37979
|
// src/image.ts
|
|
37976
37980
|
var Image2 = class {
|
|
37977
37981
|
imageId;
|
|
37982
|
+
/** @ignore */
|
|
37978
37983
|
constructor(imageId) {
|
|
37979
37984
|
this.imageId = imageId;
|
|
37980
37985
|
}
|
|
37981
37986
|
};
|
|
37982
|
-
async function fromRegistryInternal(appId, tag) {
|
|
37987
|
+
async function fromRegistryInternal(appId, tag, imageRegistryConfig) {
|
|
37983
37988
|
const resp = await client.imageGetOrCreate({
|
|
37984
37989
|
appId,
|
|
37985
37990
|
image: {
|
|
37986
|
-
dockerfileCommands: [`FROM ${tag}`]
|
|
37991
|
+
dockerfileCommands: [`FROM ${tag}`],
|
|
37992
|
+
imageRegistryConfig
|
|
37987
37993
|
},
|
|
37988
37994
|
namespace: 1 /* DEPLOYMENT_NAMESPACE_WORKSPACE */,
|
|
37989
|
-
builderVersion:
|
|
37990
|
-
// TODO: make this configurable
|
|
37995
|
+
builderVersion: imageBuilderVersion()
|
|
37991
37996
|
});
|
|
37992
37997
|
let result;
|
|
37993
37998
|
let metadata = void 0;
|
|
@@ -38013,6 +38018,7 @@ async function fromRegistryInternal(appId, tag) {
|
|
|
38013
38018
|
}
|
|
38014
38019
|
result = resultJoined;
|
|
38015
38020
|
}
|
|
38021
|
+
void metadata;
|
|
38016
38022
|
if (result.status === 2 /* GENERIC_STATUS_FAILURE */) {
|
|
38017
38023
|
throw new Error(
|
|
38018
38024
|
`Image build for ${resp.imageId} failed with the exception:
|
|
@@ -38151,6 +38157,7 @@ var Sandbox2 = class {
|
|
|
38151
38157
|
stdout;
|
|
38152
38158
|
stderr;
|
|
38153
38159
|
#taskId;
|
|
38160
|
+
/** @ignore */
|
|
38154
38161
|
constructor(sandboxId) {
|
|
38155
38162
|
this.sandboxId = sandboxId;
|
|
38156
38163
|
this.stdin = toModalWriteStream(inputStreamSb(sandboxId));
|
|
@@ -38381,10 +38388,57 @@ var NotFoundError = class extends Error {
|
|
|
38381
38388
|
this.name = "NotFoundError";
|
|
38382
38389
|
}
|
|
38383
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
|
+
// src/secret.ts
|
|
38411
|
+
import { ClientError as ClientError2, Status as Status2 } from "nice-grpc";
|
|
38412
|
+
var Secret = class _Secret {
|
|
38413
|
+
secretId;
|
|
38414
|
+
/** @ignore */
|
|
38415
|
+
constructor(secretId) {
|
|
38416
|
+
this.secretId = secretId;
|
|
38417
|
+
}
|
|
38418
|
+
/** Reference a Secret by its name. */
|
|
38419
|
+
static async fromName(name, options) {
|
|
38420
|
+
try {
|
|
38421
|
+
const resp = await client.secretGetOrCreate({
|
|
38422
|
+
deploymentName: name,
|
|
38423
|
+
namespace: 1 /* DEPLOYMENT_NAMESPACE_WORKSPACE */,
|
|
38424
|
+
environmentName: environmentName(options?.environment),
|
|
38425
|
+
requiredKeys: options?.requiredKeys ?? []
|
|
38426
|
+
});
|
|
38427
|
+
return new _Secret(resp.secretId);
|
|
38428
|
+
} catch (err) {
|
|
38429
|
+
if (err instanceof ClientError2 && err.code === Status2.NOT_FOUND)
|
|
38430
|
+
throw new NotFoundError(err.details);
|
|
38431
|
+
if (err instanceof ClientError2 && err.code === Status2.FAILED_PRECONDITION && err.details.includes("Secret is missing key"))
|
|
38432
|
+
throw new NotFoundError(err.details);
|
|
38433
|
+
throw err;
|
|
38434
|
+
}
|
|
38435
|
+
}
|
|
38436
|
+
};
|
|
38384
38437
|
|
|
38385
38438
|
// src/app.ts
|
|
38386
38439
|
var App = class _App {
|
|
38387
38440
|
appId;
|
|
38441
|
+
/** @ignore */
|
|
38388
38442
|
constructor(appId) {
|
|
38389
38443
|
this.appId = appId;
|
|
38390
38444
|
}
|
|
@@ -38398,7 +38452,7 @@ var App = class _App {
|
|
|
38398
38452
|
});
|
|
38399
38453
|
return new _App(resp.appId);
|
|
38400
38454
|
} catch (err) {
|
|
38401
|
-
if (err instanceof
|
|
38455
|
+
if (err instanceof ClientError3 && err.code === Status3.NOT_FOUND)
|
|
38402
38456
|
throw new NotFoundError(`App '${name}' not found`);
|
|
38403
38457
|
throw err;
|
|
38404
38458
|
}
|
|
@@ -38431,10 +38485,22 @@ var App = class _App {
|
|
|
38431
38485
|
async imageFromRegistry(tag) {
|
|
38432
38486
|
return await fromRegistryInternal(this.appId, tag);
|
|
38433
38487
|
}
|
|
38488
|
+
async imageFromAwsEcr(tag, secret) {
|
|
38489
|
+
if (!(secret instanceof Secret)) {
|
|
38490
|
+
throw new TypeError(
|
|
38491
|
+
"secret must be a reference to an existing Secret, e.g. `await Secret.fromName('my_secret')`"
|
|
38492
|
+
);
|
|
38493
|
+
}
|
|
38494
|
+
const imageRegistryConfig = {
|
|
38495
|
+
registryAuthType: 1 /* REGISTRY_AUTH_TYPE_AWS */,
|
|
38496
|
+
secretId: secret.secretId
|
|
38497
|
+
};
|
|
38498
|
+
return await fromRegistryInternal(this.appId, tag, imageRegistryConfig);
|
|
38499
|
+
}
|
|
38434
38500
|
};
|
|
38435
38501
|
|
|
38436
38502
|
// src/cls.ts
|
|
38437
|
-
import { ClientError as
|
|
38503
|
+
import { ClientError as ClientError5, Status as Status5 } from "nice-grpc";
|
|
38438
38504
|
|
|
38439
38505
|
// src/function.ts
|
|
38440
38506
|
import { createHash } from "node:crypto";
|
|
@@ -38442,6 +38508,7 @@ import { createHash } from "node:crypto";
|
|
|
38442
38508
|
// src/function_call.ts
|
|
38443
38509
|
var FunctionCall = class _FunctionCall {
|
|
38444
38510
|
functionCallId;
|
|
38511
|
+
/** @ignore */
|
|
38445
38512
|
constructor(functionCallId) {
|
|
38446
38513
|
this.functionCallId = functionCallId;
|
|
38447
38514
|
}
|
|
@@ -38525,6 +38592,15 @@ var Reader = class {
|
|
|
38525
38592
|
const hi = this.uint32LE() >>> 0;
|
|
38526
38593
|
return hi * 2 ** 32 + lo;
|
|
38527
38594
|
}
|
|
38595
|
+
int32LE() {
|
|
38596
|
+
const v = new DataView(
|
|
38597
|
+
this.buf.buffer,
|
|
38598
|
+
this.buf.byteOffset + this.pos,
|
|
38599
|
+
4
|
|
38600
|
+
).getInt32(0, true);
|
|
38601
|
+
this.pos += 4;
|
|
38602
|
+
return v;
|
|
38603
|
+
}
|
|
38528
38604
|
float64BE() {
|
|
38529
38605
|
const v = new DataView(
|
|
38530
38606
|
this.buf.buffer,
|
|
@@ -38570,7 +38646,7 @@ function encodeValue(val, w, proto) {
|
|
|
38570
38646
|
w.byte(140 /* SHORT_BINUNICODE */);
|
|
38571
38647
|
w.byte(utf8.length);
|
|
38572
38648
|
} else if (proto >= 4 && utf8.length > 4294967295) {
|
|
38573
|
-
w.byte(
|
|
38649
|
+
w.byte(141 /* BINUNICODE8 */);
|
|
38574
38650
|
w.uint64LE(utf8.length);
|
|
38575
38651
|
} else {
|
|
38576
38652
|
w.byte(88 /* BINUNICODE */);
|
|
@@ -38583,10 +38659,10 @@ function encodeValue(val, w, proto) {
|
|
|
38583
38659
|
if (val instanceof Uint8Array) {
|
|
38584
38660
|
const len = val.length;
|
|
38585
38661
|
if (proto >= 4 && len < 256) {
|
|
38586
|
-
w.byte(
|
|
38662
|
+
w.byte(67 /* SHORT_BINBYTES */);
|
|
38587
38663
|
w.byte(len);
|
|
38588
38664
|
} else if (proto >= 4 && len > 4294967295) {
|
|
38589
|
-
w.byte(
|
|
38665
|
+
w.byte(142 /* BINBYTES8 */);
|
|
38590
38666
|
w.uint64LE(len);
|
|
38591
38667
|
} else {
|
|
38592
38668
|
w.byte(66 /* BINBYTES */);
|
|
@@ -38657,6 +38733,7 @@ function loads(buf) {
|
|
|
38657
38733
|
const size = r.uint64LE();
|
|
38658
38734
|
void size;
|
|
38659
38735
|
}
|
|
38736
|
+
const MARK = Symbol("pickle-mark");
|
|
38660
38737
|
while (!r.eof()) {
|
|
38661
38738
|
const op = r.byte();
|
|
38662
38739
|
switch (op) {
|
|
@@ -38681,8 +38758,7 @@ function loads(buf) {
|
|
|
38681
38758
|
break;
|
|
38682
38759
|
}
|
|
38683
38760
|
case 74 /* BININT4 */: {
|
|
38684
|
-
|
|
38685
|
-
push(n >>> 31 ? n - 4294967296 : n);
|
|
38761
|
+
push(r.int32LE());
|
|
38686
38762
|
break;
|
|
38687
38763
|
}
|
|
38688
38764
|
case 71 /* BINFLOAT */:
|
|
@@ -38698,12 +38774,12 @@ function loads(buf) {
|
|
|
38698
38774
|
push(tdec.decode(r.take(n)));
|
|
38699
38775
|
break;
|
|
38700
38776
|
}
|
|
38701
|
-
case
|
|
38777
|
+
case 141 /* BINUNICODE8 */: {
|
|
38702
38778
|
const n = r.uint64LE();
|
|
38703
38779
|
push(tdec.decode(r.take(n)));
|
|
38704
38780
|
break;
|
|
38705
38781
|
}
|
|
38706
|
-
case
|
|
38782
|
+
case 67 /* SHORT_BINBYTES */: {
|
|
38707
38783
|
const n = r.byte();
|
|
38708
38784
|
push(r.take(n));
|
|
38709
38785
|
break;
|
|
@@ -38713,7 +38789,7 @@ function loads(buf) {
|
|
|
38713
38789
|
push(r.take(n));
|
|
38714
38790
|
break;
|
|
38715
38791
|
}
|
|
38716
|
-
case
|
|
38792
|
+
case 142 /* BINBYTES8 */: {
|
|
38717
38793
|
const n = r.uint64LE();
|
|
38718
38794
|
push(r.take(n));
|
|
38719
38795
|
break;
|
|
@@ -38757,6 +38833,43 @@ function loads(buf) {
|
|
|
38757
38833
|
const _size = r.uint64LE();
|
|
38758
38834
|
break;
|
|
38759
38835
|
}
|
|
38836
|
+
case 40 /* MARK */:
|
|
38837
|
+
push(MARK);
|
|
38838
|
+
break;
|
|
38839
|
+
case 101 /* APPENDS */: {
|
|
38840
|
+
const markIndex = stack.lastIndexOf(MARK);
|
|
38841
|
+
if (markIndex === -1) {
|
|
38842
|
+
throw new PickleError("APPENDS without MARK");
|
|
38843
|
+
}
|
|
38844
|
+
const lst = stack[markIndex - 1];
|
|
38845
|
+
if (!Array.isArray(lst)) {
|
|
38846
|
+
throw new PickleError("APPENDS expects a list below MARK");
|
|
38847
|
+
}
|
|
38848
|
+
const items = stack.slice(markIndex + 1);
|
|
38849
|
+
lst.push(...items);
|
|
38850
|
+
stack.length = markIndex - 1;
|
|
38851
|
+
push(lst);
|
|
38852
|
+
break;
|
|
38853
|
+
}
|
|
38854
|
+
case 117 /* SETITEMS */: {
|
|
38855
|
+
const markIndex = stack.lastIndexOf(MARK);
|
|
38856
|
+
if (markIndex === -1) {
|
|
38857
|
+
throw new PickleError("SETITEMS without MARK");
|
|
38858
|
+
}
|
|
38859
|
+
const d = stack[markIndex - 1];
|
|
38860
|
+
if (typeof d !== "object" || d === null || Array.isArray(d)) {
|
|
38861
|
+
throw new PickleError("SETITEMS expects a dict below MARK");
|
|
38862
|
+
}
|
|
38863
|
+
const items = stack.slice(markIndex + 1);
|
|
38864
|
+
for (let i = 0; i < items.length; i += 2) {
|
|
38865
|
+
if (i + 1 < items.length) {
|
|
38866
|
+
d[items[i]] = items[i + 1];
|
|
38867
|
+
}
|
|
38868
|
+
}
|
|
38869
|
+
stack.length = markIndex - 1;
|
|
38870
|
+
push(d);
|
|
38871
|
+
break;
|
|
38872
|
+
}
|
|
38760
38873
|
default:
|
|
38761
38874
|
throw new PickleError(`Unsupported opcode 0x${op.toString(16)}`);
|
|
38762
38875
|
}
|
|
@@ -38765,7 +38878,7 @@ function loads(buf) {
|
|
|
38765
38878
|
}
|
|
38766
38879
|
|
|
38767
38880
|
// src/function.ts
|
|
38768
|
-
import { ClientError as
|
|
38881
|
+
import { ClientError as ClientError4, Status as Status4 } from "nice-grpc";
|
|
38769
38882
|
var maxObjectSizeBytes = 2 * 1024 * 1024;
|
|
38770
38883
|
var outputsTimeout = 55 * 1e3;
|
|
38771
38884
|
function timeNowSeconds() {
|
|
@@ -38774,6 +38887,7 @@ function timeNowSeconds() {
|
|
|
38774
38887
|
var Function_ = class _Function_ {
|
|
38775
38888
|
functionId;
|
|
38776
38889
|
methodName;
|
|
38890
|
+
/** @ignore */
|
|
38777
38891
|
constructor(functionId, methodName) {
|
|
38778
38892
|
this.functionId = functionId;
|
|
38779
38893
|
this.methodName = methodName;
|
|
@@ -38788,14 +38902,14 @@ var Function_ = class _Function_ {
|
|
|
38788
38902
|
});
|
|
38789
38903
|
return new _Function_(resp.functionId);
|
|
38790
38904
|
} catch (err) {
|
|
38791
|
-
if (err instanceof
|
|
38905
|
+
if (err instanceof ClientError4 && err.code === Status4.NOT_FOUND)
|
|
38792
38906
|
throw new NotFoundError(`Function '${appName}/${name}' not found`);
|
|
38793
38907
|
throw err;
|
|
38794
38908
|
}
|
|
38795
38909
|
}
|
|
38796
38910
|
// Execute a single input into a remote Function.
|
|
38797
38911
|
async remote(args = [], kwargs = {}) {
|
|
38798
|
-
const functionCallId = await this
|
|
38912
|
+
const functionCallId = await this.#execFunctionCall(
|
|
38799
38913
|
args,
|
|
38800
38914
|
kwargs,
|
|
38801
38915
|
4 /* FUNCTION_CALL_INVOCATION_TYPE_SYNC */
|
|
@@ -38804,14 +38918,14 @@ var Function_ = class _Function_ {
|
|
|
38804
38918
|
}
|
|
38805
38919
|
// Spawn a single input into a remote function.
|
|
38806
38920
|
async spawn(args = [], kwargs = {}) {
|
|
38807
|
-
const functionCallId = await this
|
|
38921
|
+
const functionCallId = await this.#execFunctionCall(
|
|
38808
38922
|
args,
|
|
38809
38923
|
kwargs,
|
|
38810
38924
|
4 /* FUNCTION_CALL_INVOCATION_TYPE_SYNC */
|
|
38811
38925
|
);
|
|
38812
38926
|
return new FunctionCall(functionCallId);
|
|
38813
38927
|
}
|
|
38814
|
-
async execFunctionCall(args = [], kwargs = {}, invocationType = 4 /* FUNCTION_CALL_INVOCATION_TYPE_SYNC */) {
|
|
38928
|
+
async #execFunctionCall(args = [], kwargs = {}, invocationType = 4 /* FUNCTION_CALL_INVOCATION_TYPE_SYNC */) {
|
|
38815
38929
|
const payload = dumps([args, kwargs]);
|
|
38816
38930
|
let argsBlobId = void 0;
|
|
38817
38931
|
if (payload.length > maxObjectSizeBytes) {
|
|
@@ -38952,6 +39066,7 @@ var Cls = class _Cls {
|
|
|
38952
39066
|
#serviceFunctionId;
|
|
38953
39067
|
#schema;
|
|
38954
39068
|
#methodNames;
|
|
39069
|
+
/** @ignore */
|
|
38955
39070
|
constructor(serviceFunctionId, schema, methodNames) {
|
|
38956
39071
|
this.#serviceFunctionId = serviceFunctionId;
|
|
38957
39072
|
this.#schema = schema;
|
|
@@ -38985,7 +39100,7 @@ var Cls = class _Cls {
|
|
|
38985
39100
|
}
|
|
38986
39101
|
return new _Cls(serviceFunction.functionId, schema, methodNames);
|
|
38987
39102
|
} catch (err) {
|
|
38988
|
-
if (err instanceof
|
|
39103
|
+
if (err instanceof ClientError5 && err.code === Status5.NOT_FOUND)
|
|
38989
39104
|
throw new NotFoundError(`Class '${appName}/${name}' not found`);
|
|
38990
39105
|
throw err;
|
|
38991
39106
|
}
|
|
@@ -39082,16 +39197,269 @@ var ClsInstance = class {
|
|
|
39082
39197
|
return method;
|
|
39083
39198
|
}
|
|
39084
39199
|
};
|
|
39200
|
+
|
|
39201
|
+
// src/queue.ts
|
|
39202
|
+
import { ClientError as ClientError6, Status as Status6 } from "nice-grpc";
|
|
39203
|
+
var ephemeralObjectHeartbeatSleep = 3e5;
|
|
39204
|
+
var queueInitialPutBackoff = 100;
|
|
39205
|
+
var queueDefaultPartitionTtl = 24 * 3600 * 1e3;
|
|
39206
|
+
var Queue = class _Queue {
|
|
39207
|
+
queueId;
|
|
39208
|
+
#ephemeral;
|
|
39209
|
+
#abortController;
|
|
39210
|
+
/** @ignore */
|
|
39211
|
+
constructor(queueId, ephemeral = false) {
|
|
39212
|
+
this.queueId = queueId;
|
|
39213
|
+
this.#ephemeral = ephemeral;
|
|
39214
|
+
this.#abortController = ephemeral ? new AbortController() : void 0;
|
|
39215
|
+
}
|
|
39216
|
+
static #validatePartitionKey(partition) {
|
|
39217
|
+
if (partition) {
|
|
39218
|
+
const partitionKey = new TextEncoder().encode(partition);
|
|
39219
|
+
if (partitionKey.length === 0 || partitionKey.length > 64) {
|
|
39220
|
+
throw new InvalidError(
|
|
39221
|
+
"Queue partition key must be between 1 and 64 bytes."
|
|
39222
|
+
);
|
|
39223
|
+
}
|
|
39224
|
+
return partitionKey;
|
|
39225
|
+
}
|
|
39226
|
+
return new Uint8Array();
|
|
39227
|
+
}
|
|
39228
|
+
/**
|
|
39229
|
+
* Create a nameless, temporary queue.
|
|
39230
|
+
* You will need to call `closeEphemeral()` to delete the queue.
|
|
39231
|
+
*/
|
|
39232
|
+
static async ephemeral(options = {}) {
|
|
39233
|
+
const resp = await client.queueGetOrCreate({
|
|
39234
|
+
objectCreationType: 5 /* OBJECT_CREATION_TYPE_EPHEMERAL */,
|
|
39235
|
+
environmentName: environmentName(options.environment)
|
|
39236
|
+
});
|
|
39237
|
+
const queue = new _Queue(resp.queueId, true);
|
|
39238
|
+
const signal = queue.#abortController.signal;
|
|
39239
|
+
(async () => {
|
|
39240
|
+
while (true) {
|
|
39241
|
+
await client.queueHeartbeat({ queueId: resp.queueId });
|
|
39242
|
+
await Promise.race([
|
|
39243
|
+
new Promise(
|
|
39244
|
+
(resolve) => setTimeout(resolve, ephemeralObjectHeartbeatSleep)
|
|
39245
|
+
),
|
|
39246
|
+
new Promise((resolve) => {
|
|
39247
|
+
signal.addEventListener("abort", resolve, { once: true });
|
|
39248
|
+
})
|
|
39249
|
+
]);
|
|
39250
|
+
}
|
|
39251
|
+
})();
|
|
39252
|
+
return queue;
|
|
39253
|
+
}
|
|
39254
|
+
/** Delete the ephemeral queue. Only usable with `Queue.ephemeral()`. */
|
|
39255
|
+
closeEphemeral() {
|
|
39256
|
+
if (this.#ephemeral) {
|
|
39257
|
+
this.#abortController.abort();
|
|
39258
|
+
} else {
|
|
39259
|
+
throw new InvalidError("Queue is not ephemeral.");
|
|
39260
|
+
}
|
|
39261
|
+
}
|
|
39262
|
+
/**
|
|
39263
|
+
* Lookup a queue by name.
|
|
39264
|
+
*/
|
|
39265
|
+
static async lookup(name, options = {}) {
|
|
39266
|
+
const resp = await client.queueGetOrCreate({
|
|
39267
|
+
deploymentName: name,
|
|
39268
|
+
objectCreationType: options.createIfMissing ? 1 /* OBJECT_CREATION_TYPE_CREATE_IF_MISSING */ : void 0,
|
|
39269
|
+
namespace: 1 /* DEPLOYMENT_NAMESPACE_WORKSPACE */,
|
|
39270
|
+
environmentName: environmentName(options.environment)
|
|
39271
|
+
});
|
|
39272
|
+
return new _Queue(resp.queueId);
|
|
39273
|
+
}
|
|
39274
|
+
/** Delete a queue by name. */
|
|
39275
|
+
static async delete(name, options = {}) {
|
|
39276
|
+
const queue = await _Queue.lookup(name, options);
|
|
39277
|
+
await client.queueDelete({ queueId: queue.queueId });
|
|
39278
|
+
}
|
|
39279
|
+
/**
|
|
39280
|
+
* Remove all objects from a queue partition.
|
|
39281
|
+
*/
|
|
39282
|
+
async clear(options = {}) {
|
|
39283
|
+
if (options.partition && options.all) {
|
|
39284
|
+
throw new InvalidError(
|
|
39285
|
+
"Partition must be null when requesting to clear all."
|
|
39286
|
+
);
|
|
39287
|
+
}
|
|
39288
|
+
await client.queueClear({
|
|
39289
|
+
queueId: this.queueId,
|
|
39290
|
+
partitionKey: _Queue.#validatePartitionKey(options.partition),
|
|
39291
|
+
allPartitions: options.all
|
|
39292
|
+
});
|
|
39293
|
+
}
|
|
39294
|
+
async #get(n, partition, timeout) {
|
|
39295
|
+
const partitionKey = _Queue.#validatePartitionKey(partition);
|
|
39296
|
+
const startTime = Date.now();
|
|
39297
|
+
let pollTimeout = 5e4;
|
|
39298
|
+
if (timeout !== void 0) {
|
|
39299
|
+
pollTimeout = Math.min(pollTimeout, timeout);
|
|
39300
|
+
}
|
|
39301
|
+
while (true) {
|
|
39302
|
+
const response = await client.queueGet({
|
|
39303
|
+
queueId: this.queueId,
|
|
39304
|
+
partitionKey,
|
|
39305
|
+
timeout: pollTimeout / 1e3,
|
|
39306
|
+
nValues: n
|
|
39307
|
+
});
|
|
39308
|
+
if (response.values && response.values.length > 0) {
|
|
39309
|
+
return response.values.map((value) => loads(value));
|
|
39310
|
+
}
|
|
39311
|
+
if (timeout !== void 0) {
|
|
39312
|
+
const remaining = timeout - (Date.now() - startTime);
|
|
39313
|
+
if (remaining <= 0) {
|
|
39314
|
+
const message = `Queue ${this.queueId} did not return values within ${timeout}ms.`;
|
|
39315
|
+
throw new QueueEmptyError(message);
|
|
39316
|
+
}
|
|
39317
|
+
pollTimeout = Math.min(pollTimeout, remaining);
|
|
39318
|
+
}
|
|
39319
|
+
}
|
|
39320
|
+
}
|
|
39321
|
+
/**
|
|
39322
|
+
* Remove and return the next object from the queue.
|
|
39323
|
+
*
|
|
39324
|
+
* By default, this will wait until at least one item is present in the queue.
|
|
39325
|
+
* If `timeout` is set, raises `QueueEmptyError` if no items are available
|
|
39326
|
+
* within that timeout in milliseconds.
|
|
39327
|
+
*/
|
|
39328
|
+
async get(options = {}) {
|
|
39329
|
+
const values = await this.#get(1, options.partition, options.timeout);
|
|
39330
|
+
return values[0];
|
|
39331
|
+
}
|
|
39332
|
+
/**
|
|
39333
|
+
* Remove and return up to `n` objects from the queue.
|
|
39334
|
+
*
|
|
39335
|
+
* By default, this will wait until at least one item is present in the queue.
|
|
39336
|
+
* If `timeout` is set, raises `QueueEmptyError` if no items are available
|
|
39337
|
+
* within that timeout in milliseconds.
|
|
39338
|
+
*/
|
|
39339
|
+
async getMany(n, options = {}) {
|
|
39340
|
+
return await this.#get(n, options.partition, options.timeout);
|
|
39341
|
+
}
|
|
39342
|
+
async #put(values, timeout, partition, partitionTtl) {
|
|
39343
|
+
const valuesEncoded = values.map((v) => dumps(v));
|
|
39344
|
+
const partitionKey = _Queue.#validatePartitionKey(partition);
|
|
39345
|
+
let delay = queueInitialPutBackoff;
|
|
39346
|
+
const deadline = timeout ? Date.now() + timeout : void 0;
|
|
39347
|
+
while (true) {
|
|
39348
|
+
try {
|
|
39349
|
+
await client.queuePut({
|
|
39350
|
+
queueId: this.queueId,
|
|
39351
|
+
values: valuesEncoded,
|
|
39352
|
+
partitionKey,
|
|
39353
|
+
partitionTtlSeconds: (partitionTtl || queueDefaultPartitionTtl) / 1e3
|
|
39354
|
+
});
|
|
39355
|
+
break;
|
|
39356
|
+
} catch (e) {
|
|
39357
|
+
if (e instanceof ClientError6 && e.code === Status6.RESOURCE_EXHAUSTED) {
|
|
39358
|
+
delay = Math.min(delay * 2, 3e4);
|
|
39359
|
+
if (deadline !== void 0) {
|
|
39360
|
+
const remaining = deadline - Date.now();
|
|
39361
|
+
if (remaining <= 0)
|
|
39362
|
+
throw new QueueFullError(`Put failed on ${this.queueId}.`);
|
|
39363
|
+
delay = Math.min(delay, remaining);
|
|
39364
|
+
}
|
|
39365
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
39366
|
+
} else {
|
|
39367
|
+
throw e;
|
|
39368
|
+
}
|
|
39369
|
+
}
|
|
39370
|
+
}
|
|
39371
|
+
}
|
|
39372
|
+
/**
|
|
39373
|
+
* Add an item to the end of the queue.
|
|
39374
|
+
*
|
|
39375
|
+
* If the queue is full, this will retry with exponential backoff until the
|
|
39376
|
+
* provided `timeout` is reached, or indefinitely if `timeout` is not set.
|
|
39377
|
+
* Raises `QueueFullError` if the queue is still full after the timeout.
|
|
39378
|
+
*/
|
|
39379
|
+
async put(v, options = {}) {
|
|
39380
|
+
await this.#put(
|
|
39381
|
+
[v],
|
|
39382
|
+
options.timeout,
|
|
39383
|
+
options.partition,
|
|
39384
|
+
options.partitionTtl
|
|
39385
|
+
);
|
|
39386
|
+
}
|
|
39387
|
+
/**
|
|
39388
|
+
* Add several items to the end of the queue.
|
|
39389
|
+
*
|
|
39390
|
+
* If the queue is full, this will retry with exponential backoff until the
|
|
39391
|
+
* provided `timeout` is reached, or indefinitely if `timeout` is not set.
|
|
39392
|
+
* Raises `QueueFullError` if the queue is still full after the timeout.
|
|
39393
|
+
*/
|
|
39394
|
+
async putMany(values, options = {}) {
|
|
39395
|
+
await this.#put(
|
|
39396
|
+
values,
|
|
39397
|
+
options.timeout,
|
|
39398
|
+
options.partition,
|
|
39399
|
+
options.partitionTtl
|
|
39400
|
+
);
|
|
39401
|
+
}
|
|
39402
|
+
/** Return the number of objects in the queue. */
|
|
39403
|
+
async len(options = {}) {
|
|
39404
|
+
if (options.partition && options.total) {
|
|
39405
|
+
throw new InvalidError(
|
|
39406
|
+
"Partition must be null when requesting total length."
|
|
39407
|
+
);
|
|
39408
|
+
}
|
|
39409
|
+
const resp = await client.queueLen({
|
|
39410
|
+
queueId: this.queueId,
|
|
39411
|
+
partitionKey: _Queue.#validatePartitionKey(options.partition),
|
|
39412
|
+
total: options.total
|
|
39413
|
+
});
|
|
39414
|
+
return resp.len;
|
|
39415
|
+
}
|
|
39416
|
+
/** Iterate through items in a queue without mutation. */
|
|
39417
|
+
async *iterate(options = {}) {
|
|
39418
|
+
const { partition, itemPollTimeout = 0 } = options;
|
|
39419
|
+
let lastEntryId = void 0;
|
|
39420
|
+
const validatedPartitionKey = _Queue.#validatePartitionKey(partition);
|
|
39421
|
+
let fetchDeadline = Date.now() + itemPollTimeout;
|
|
39422
|
+
const maxPollDuration = 3e4;
|
|
39423
|
+
while (true) {
|
|
39424
|
+
const pollDuration = Math.max(
|
|
39425
|
+
0,
|
|
39426
|
+
Math.min(maxPollDuration, fetchDeadline - Date.now())
|
|
39427
|
+
);
|
|
39428
|
+
const request = {
|
|
39429
|
+
queueId: this.queueId,
|
|
39430
|
+
partitionKey: validatedPartitionKey,
|
|
39431
|
+
itemPollTimeout: pollDuration / 1e3,
|
|
39432
|
+
lastEntryId: lastEntryId || ""
|
|
39433
|
+
};
|
|
39434
|
+
const response = await client.queueNextItems(request);
|
|
39435
|
+
if (response.items && response.items.length > 0) {
|
|
39436
|
+
for (const item of response.items) {
|
|
39437
|
+
yield loads(item.value);
|
|
39438
|
+
lastEntryId = item.entryId;
|
|
39439
|
+
}
|
|
39440
|
+
fetchDeadline = Date.now() + itemPollTimeout;
|
|
39441
|
+
} else if (Date.now() > fetchDeadline) {
|
|
39442
|
+
break;
|
|
39443
|
+
}
|
|
39444
|
+
}
|
|
39445
|
+
}
|
|
39446
|
+
};
|
|
39085
39447
|
export {
|
|
39086
39448
|
App,
|
|
39087
39449
|
Cls,
|
|
39088
39450
|
ClsInstance,
|
|
39451
|
+
ContainerProcess,
|
|
39089
39452
|
FunctionCall,
|
|
39090
39453
|
FunctionTimeoutError,
|
|
39091
39454
|
Function_,
|
|
39092
39455
|
Image2 as Image,
|
|
39093
39456
|
InternalFailure,
|
|
39457
|
+
InvalidError,
|
|
39094
39458
|
NotFoundError,
|
|
39459
|
+
Queue,
|
|
39460
|
+
QueueEmptyError,
|
|
39461
|
+
QueueFullError,
|
|
39095
39462
|
RemoteError,
|
|
39096
|
-
Sandbox2 as Sandbox
|
|
39463
|
+
Sandbox2 as Sandbox,
|
|
39464
|
+
Secret
|
|
39097
39465
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "modal",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "Modal client library for JavaScript",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://modal.com/docs",
|
|
@@ -23,10 +23,16 @@
|
|
|
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
|
-
"test": "vitest"
|
|
32
|
+
"test": "vitest",
|
|
33
|
+
"preversion": "(git update-index --really-refresh && git diff-index --quiet HEAD) || (echo 'You must commit all changes before running npm version' && exit 1)",
|
|
34
|
+
"version": "npm run build && git add package.json package-lock.json && git commit -m \"modal-js/v$npm_package_version\" && git tag modal-js/v$npm_package_version",
|
|
35
|
+
"postversion": "git push && git push --tags && npm publish"
|
|
30
36
|
},
|
|
31
37
|
"dependencies": {
|
|
32
38
|
"long": "^5.3.1",
|
|
@@ -36,14 +42,20 @@
|
|
|
36
42
|
"uuid": "^11.1.0"
|
|
37
43
|
},
|
|
38
44
|
"devDependencies": {
|
|
45
|
+
"@eslint/js": "^9.28.0",
|
|
39
46
|
"@types/node": "^22.15.2",
|
|
47
|
+
"eslint": "^9.28.0",
|
|
48
|
+
"globals": "^16.2.0",
|
|
40
49
|
"grpc-tools": "^1.13.0",
|
|
50
|
+
"http-server": "^14.1.1",
|
|
41
51
|
"p-queue": "^8.1.0",
|
|
42
52
|
"prettier": "^3.5.3",
|
|
43
53
|
"ts-proto": "^2.7.0",
|
|
44
54
|
"tsup": "^8.4.0",
|
|
45
55
|
"tsx": "^4.19.3",
|
|
56
|
+
"typedoc": "^0.28.5",
|
|
46
57
|
"typescript": "~5.8.3",
|
|
58
|
+
"typescript-eslint": "^8.33.1",
|
|
47
59
|
"vitest": "^3.1.2"
|
|
48
60
|
}
|
|
49
61
|
}
|