withruntime 0.11.2 → 0.12.0
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/BLAXEL.md +2 -2
- package/COMPATIBILITY.md +74 -9
- package/DAYTONA.md +33 -5
- package/E2B.md +85 -24
- package/README.md +9 -8
- package/README.src.md +8 -7
- package/VERCEL.md +43 -5
- package/compatibility-lock.json +58 -49
- package/dist/billing-cli.d.ts +1 -1
- package/dist/billing-cli.js +77 -1
- package/dist/blaxel/errors.d.ts +14 -0
- package/dist/blaxel/errors.js +29 -0
- package/dist/blaxel/index.d.ts +2 -2
- package/dist/blaxel/index.js +4 -4
- package/dist/blaxel/interpreter.d.ts +2 -5
- package/dist/blaxel/sandbox.d.ts +14 -5
- package/dist/blaxel/sandbox.js +63 -7
- package/dist/blaxel/snapshot.d.ts +4 -0
- package/dist/blaxel/snapshot.js +4 -0
- package/dist/cli/logs.d.ts +21 -0
- package/dist/cli/logs.js +188 -0
- package/dist/cli/logs.test.d.ts +1 -0
- package/dist/cli/logs.test.js +272 -0
- package/dist/cli-extras.d.ts +3 -3
- package/dist/cli-extras.js +17 -12
- package/dist/cli-words.d.ts +10 -1
- package/dist/cli-words.js +18 -0
- package/dist/cli.d.ts +5 -1
- package/dist/cli.js +405 -204
- package/dist/client.d.ts +2 -4
- package/dist/client.js +27 -11
- package/dist/cloudflare/errors.d.ts +143 -0
- package/dist/cloudflare/errors.js +167 -0
- package/dist/cloudflare/index.d.ts +175 -6
- package/dist/cloudflare/index.js +416 -26
- package/dist/cloudflare/interpreter.d.ts +119 -0
- package/dist/cloudflare/interpreter.js +223 -0
- package/dist/cloudflare/streams.d.ts +38 -0
- package/dist/cloudflare/streams.js +145 -0
- package/dist/cloudflare/watch.d.ts +9 -0
- package/dist/cloudflare/watch.js +24 -0
- package/dist/codesandbox/index.d.ts +216 -28
- package/dist/codesandbox/index.js +478 -78
- package/dist/compat/core.d.ts +18 -0
- package/dist/compat/core.js +29 -0
- package/dist/compat/files.d.ts +1 -0
- package/dist/compat/files.js +25 -5
- package/dist/daytona/computer-use.d.ts +13 -4
- package/dist/daytona/computer-use.js +66 -8
- package/dist/daytona/daytona.d.ts +6 -0
- package/dist/daytona/daytona.js +30 -3
- package/dist/daytona/errors.d.ts +11 -0
- package/dist/daytona/errors.js +18 -0
- package/dist/daytona/filesystem.js +2 -1
- package/dist/daytona/image.d.ts +13 -9
- package/dist/daytona/image.js +18 -12
- package/dist/daytona/index.d.ts +1 -1
- package/dist/daytona/sandbox.d.ts +8 -2
- package/dist/daytona/sandbox.js +16 -2
- package/dist/domains/index.d.ts +9 -0
- package/dist/domains/index.js +10 -0
- package/dist/e2b/commands.d.ts +1 -1
- package/dist/e2b/commands.js +6 -7
- package/dist/e2b/errors.d.ts +17 -0
- package/dist/e2b/errors.js +40 -1
- package/dist/e2b/index.d.ts +2 -2
- package/dist/e2b/index.js +1 -1
- package/dist/e2b/sandbox.d.ts +27 -21
- package/dist/e2b/sandbox.js +34 -8
- package/dist/e2b/unsupported.js +1 -1
- package/dist/errors.d.ts +10 -1
- package/dist/errors.js +16 -4
- package/dist/freestyle/index.d.ts +285 -37
- package/dist/freestyle/index.js +656 -144
- package/dist/identity.d.ts +3 -0
- package/dist/identity.js +27 -0
- package/dist/images/index.d.ts +9 -0
- package/dist/images/index.js +10 -0
- package/dist/index.d.ts +1 -0
- package/dist/ips/index.d.ts +9 -0
- package/dist/ips/index.js +10 -0
- package/dist/jobs/index.d.ts +9 -0
- package/dist/jobs/index.js +10 -0
- package/dist/keys.js +2 -0
- package/dist/login.js +2 -0
- package/dist/machine.d.ts +12 -3
- package/dist/machine.js +20 -3
- package/dist/mcp.js +1 -1
- package/dist/modal/index.d.ts +339 -61
- package/dist/modal/index.js +781 -121
- package/dist/network-cli.d.ts +3 -1
- package/dist/network-cli.js +78 -36
- package/dist/networks/index.d.ts +11 -0
- package/dist/networks/index.js +10 -0
- package/dist/ports/index.d.ts +9 -0
- package/dist/ports/index.js +10 -0
- package/dist/product-names.d.ts +52 -0
- package/dist/product-names.js +164 -0
- package/dist/product-renames.d.ts +103 -0
- package/dist/product-renames.js +189 -0
- package/dist/products/apps.d.ts +176 -0
- package/dist/products/apps.js +165 -0
- package/dist/products/billing.d.ts +41 -0
- package/dist/products/billing.js +13 -0
- package/dist/products/browser.d.ts +10 -0
- package/dist/products/browsers.d.ts +71 -0
- package/dist/products/browsers.js +102 -0
- package/dist/products/builds.d.ts +126 -0
- package/dist/products/builds.js +221 -0
- package/dist/products/index.d.ts +3 -16
- package/dist/products/index.js +3 -14
- package/dist/products/jobs.d.ts +17 -0
- package/dist/products/jobs.js +27 -10
- package/dist/products/logs.d.ts +245 -0
- package/dist/products/logs.js +274 -0
- package/dist/products/logs.test.d.ts +1 -0
- package/dist/products/logs.test.js +343 -0
- package/dist/products/network-products.d.ts +38 -7
- package/dist/products/network-products.js +31 -18
- package/dist/products/observability.d.ts +3 -2
- package/dist/products/private-network.js +1 -1
- package/dist/products/queues.d.ts +149 -0
- package/dist/products/queues.js +213 -0
- package/dist/products/referrals.d.ts +21 -7
- package/dist/products/referrals.js +3 -3
- package/dist/products/secrets.d.ts +7 -3
- package/dist/products/secrets.js +39 -18
- package/dist/products/signed-requests.d.ts +21 -0
- package/dist/products/signed-requests.js +11 -0
- package/dist/products/streams.d.ts +73 -0
- package/dist/products/streams.js +17 -0
- package/dist/products/switching.d.ts +35 -7
- package/dist/products/switching.js +4 -3
- package/dist/products/volumes.d.ts +3 -0
- package/dist/record-cli.d.ts +23 -0
- package/dist/record-cli.js +308 -0
- package/dist/renamed-products.d.ts +38 -0
- package/dist/renamed-products.js +34 -0
- package/dist/runloop/index.d.ts +9 -2
- package/dist/runloop/index.js +29 -8
- package/dist/runloop/sdk.d.ts +131 -0
- package/dist/runloop/sdk.js +167 -0
- package/dist/sandbox.d.ts +3 -2
- package/dist/sandbox.js +14 -9
- package/dist/sandboxes/index.d.ts +11 -0
- package/dist/sandboxes/index.js +12 -0
- package/dist/snapshots/index.d.ts +9 -0
- package/dist/snapshots/index.js +11 -0
- package/dist/snapshots.d.ts +7 -4
- package/dist/sprites/index.d.ts +343 -31
- package/dist/sprites/index.js +866 -84
- package/dist/ssh.d.ts +1 -1
- package/dist/ssh.js +11 -11
- package/dist/terminal.d.ts +24 -0
- package/dist/terminal.js +32 -0
- package/dist/transport.d.ts +15 -1
- package/dist/transport.js +56 -3
- package/dist/tunnel.js +1 -1
- package/dist/types.d.ts +63 -0
- package/dist/vercel/sandbox.js +5 -3
- package/dist/vercel/snapshot.js +10 -2
- package/dist/volumes/index.d.ts +9 -0
- package/dist/volumes/index.js +10 -0
- package/package.json +48 -2
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { Page } from "../page.js";
|
|
2
|
+
import type { RequestOptions, Transport } from "../transport.js";
|
|
3
|
+
/** Private until launch.
|
|
4
|
+
* This is the proposed management contract, not an installed API route.
|
|
5
|
+
* SQS clients use the returned sqs URL with their existing client. */
|
|
6
|
+
export type RecordState = "creating" | "ready" | "updating" | "deleting" | "deleted" | "failed";
|
|
7
|
+
export type RecordResource = {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
labels: Record<string, string>;
|
|
11
|
+
state: RecordState;
|
|
12
|
+
createdAt: string;
|
|
13
|
+
error?: {
|
|
14
|
+
code: string;
|
|
15
|
+
message: string;
|
|
16
|
+
hint: string;
|
|
17
|
+
} | null;
|
|
18
|
+
};
|
|
19
|
+
export type QueueSettings = {
|
|
20
|
+
visibilityTimeoutSeconds: number;
|
|
21
|
+
retentionSeconds: number;
|
|
22
|
+
maxMessageBytes: number;
|
|
23
|
+
delaySeconds: number;
|
|
24
|
+
fifo: boolean;
|
|
25
|
+
deadLetter: {
|
|
26
|
+
queue: string;
|
|
27
|
+
maxReceives: number;
|
|
28
|
+
} | null;
|
|
29
|
+
};
|
|
30
|
+
export type Queue = RecordResource & {
|
|
31
|
+
settings: QueueSettings;
|
|
32
|
+
counts: {
|
|
33
|
+
visible: number;
|
|
34
|
+
inFlight: number;
|
|
35
|
+
delayed: number;
|
|
36
|
+
};
|
|
37
|
+
sqs: string;
|
|
38
|
+
};
|
|
39
|
+
export type CreateQueue = {
|
|
40
|
+
name: string;
|
|
41
|
+
labels?: Record<string, string>;
|
|
42
|
+
settings?: Partial<QueueSettings>;
|
|
43
|
+
};
|
|
44
|
+
export type UpdateQueue = Partial<CreateQueue>;
|
|
45
|
+
export type RecordListQuery = {
|
|
46
|
+
name?: string;
|
|
47
|
+
label?: readonly string[];
|
|
48
|
+
state?: readonly RecordState[];
|
|
49
|
+
limit?: number;
|
|
50
|
+
cursor?: string;
|
|
51
|
+
};
|
|
52
|
+
export type RecordWaitOptions = RequestOptions & {
|
|
53
|
+
pollMs?: number;
|
|
54
|
+
};
|
|
55
|
+
export type QueueAttribute = {
|
|
56
|
+
dataType: string;
|
|
57
|
+
stringValue?: string;
|
|
58
|
+
binaryValue?: string;
|
|
59
|
+
};
|
|
60
|
+
export type SendMessage = {
|
|
61
|
+
body: string;
|
|
62
|
+
attributes?: Record<string, QueueAttribute>;
|
|
63
|
+
delaySeconds?: number;
|
|
64
|
+
groupId?: string;
|
|
65
|
+
dedupId?: string;
|
|
66
|
+
};
|
|
67
|
+
export type ReceiveMessages = {
|
|
68
|
+
max?: number;
|
|
69
|
+
waitSeconds?: number;
|
|
70
|
+
visibilitySeconds?: number;
|
|
71
|
+
};
|
|
72
|
+
export type QueueMessage = SendMessage & {
|
|
73
|
+
id: string;
|
|
74
|
+
receiptHandle: string;
|
|
75
|
+
receives: number;
|
|
76
|
+
};
|
|
77
|
+
export type MessageSent = {
|
|
78
|
+
id: string;
|
|
79
|
+
md5: string;
|
|
80
|
+
sequenceNumber?: string;
|
|
81
|
+
};
|
|
82
|
+
export type ReceiptResult = {
|
|
83
|
+
successful: string[];
|
|
84
|
+
failed: {
|
|
85
|
+
receiptHandle: string;
|
|
86
|
+
code: string;
|
|
87
|
+
message: string;
|
|
88
|
+
hint: string;
|
|
89
|
+
}[];
|
|
90
|
+
};
|
|
91
|
+
/** A consume call handles messages sequentially. max counts handler attempts,
|
|
92
|
+
* including failures. Omit max to run until cancelled. timeoutMs bounds each
|
|
93
|
+
* network call, including settlement after cancellation, not the handler.
|
|
94
|
+
* Choose visibilitySeconds longer than the handler's work; delivery is at least once. */
|
|
95
|
+
export type ConsumeOptions = ReceiveMessages & {
|
|
96
|
+
signal?: AbortSignal;
|
|
97
|
+
timeoutMs?: number;
|
|
98
|
+
};
|
|
99
|
+
export type ConsumeResult = {
|
|
100
|
+
processed: number;
|
|
101
|
+
acknowledged: number;
|
|
102
|
+
retried: number;
|
|
103
|
+
aborted: boolean;
|
|
104
|
+
};
|
|
105
|
+
export type QueueHandler = (message: QueueMessage, signal: AbortSignal) => unknown;
|
|
106
|
+
/** Shared only by the private record products. The server owns field defaults
|
|
107
|
+
* and protocol refusals; the SDK preserves their codes and recovery hints. */
|
|
108
|
+
export declare function recordResources<R extends RecordResource, C, U>(t: Transport, plural: "queues" | "streams"): {
|
|
109
|
+
create: (input: C, options?: RequestOptions) => Promise<R>;
|
|
110
|
+
get: (id: string, options?: RequestOptions) => Promise<R>;
|
|
111
|
+
list: (query?: RecordListQuery, options?: RequestOptions) => Promise<Page<R>>;
|
|
112
|
+
update: (id: string, input: U, options?: RequestOptions) => Promise<R>;
|
|
113
|
+
delete: (id: string, options?: RequestOptions) => Promise<R>;
|
|
114
|
+
/** Poll one resource with a deadline across every read, including retries. */
|
|
115
|
+
wait(id: string, target?: "ready" | "deleted", options?: RecordWaitOptions): Promise<R>;
|
|
116
|
+
};
|
|
117
|
+
/** Private until launch. No public Runtime property is installed here. */
|
|
118
|
+
export declare function queues(t: Transport): {
|
|
119
|
+
send: (id: string, input: SendMessage, options?: RequestOptions) => Promise<MessageSent>;
|
|
120
|
+
receive: (id: string, input?: ReceiveMessages, options?: RequestOptions) => Promise<{
|
|
121
|
+
messages: QueueMessage[];
|
|
122
|
+
}>;
|
|
123
|
+
ack: (id: string, input: {
|
|
124
|
+
receiptHandles: string[];
|
|
125
|
+
}, options?: RequestOptions) => Promise<ReceiptResult>;
|
|
126
|
+
retry: (id: string, input: {
|
|
127
|
+
receiptHandle: string;
|
|
128
|
+
visibilitySeconds: number;
|
|
129
|
+
}, options?: RequestOptions) => Promise<{
|
|
130
|
+
receiptHandle: string;
|
|
131
|
+
visibilitySeconds: number;
|
|
132
|
+
}>;
|
|
133
|
+
/** Receive, handle, then acknowledge. No acknowledgement precedes success.
|
|
134
|
+
* A failed or cancelled handler releases its receipt at once. Aborting
|
|
135
|
+
* during receive can lose its reply; that lease expires without an ack.
|
|
136
|
+
* Settlement ignores the cancelled signal and has a bounded deadline.
|
|
137
|
+
* A lost settlement reply is retried once with the same key, even when
|
|
138
|
+
* transport retries were disabled. A remaining failure is thrown. */
|
|
139
|
+
consume(id: string, handler: QueueHandler, options?: ConsumeOptions): Promise<ConsumeResult>;
|
|
140
|
+
/** Purge returns the resource; follow its state with wait(id). */
|
|
141
|
+
purge: (id: string, options?: RequestOptions) => Promise<Queue>;
|
|
142
|
+
create: (input: CreateQueue, options?: RequestOptions) => Promise<Queue>;
|
|
143
|
+
get: (id: string, options?: RequestOptions) => Promise<Queue>;
|
|
144
|
+
list: (query?: RecordListQuery, options?: RequestOptions) => Promise<Page<Queue>>;
|
|
145
|
+
update: (id: string, input: Partial<CreateQueue>, options?: RequestOptions) => Promise<Queue>;
|
|
146
|
+
delete: (id: string, options?: RequestOptions) => Promise<Queue>;
|
|
147
|
+
/** Poll one resource with a deadline across every read, including retries. */
|
|
148
|
+
wait(id: string, target?: "ready" | "deleted", options?: RecordWaitOptions): Promise<Queue>;
|
|
149
|
+
};
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { RuntimeError } from "../errors.js";
|
|
2
|
+
import { Page } from "../page.js";
|
|
3
|
+
import { pause } from "../wait.js";
|
|
4
|
+
/** Stop waiting for user code on abort. Its rejection stays observed even if
|
|
5
|
+
* it finishes later. Handlers should use the signal to stop their own work. */
|
|
6
|
+
function handleMessage(handler, message, signal) {
|
|
7
|
+
return new Promise((resolve) => {
|
|
8
|
+
let finished = false;
|
|
9
|
+
const done = (success) => {
|
|
10
|
+
if (finished)
|
|
11
|
+
return;
|
|
12
|
+
finished = true;
|
|
13
|
+
signal.removeEventListener("abort", abort);
|
|
14
|
+
resolve(success);
|
|
15
|
+
};
|
|
16
|
+
const abort = () => done(false);
|
|
17
|
+
if (signal.aborted) {
|
|
18
|
+
done(false);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
22
|
+
// Observe synchronous throws and late rejections by the same path.
|
|
23
|
+
Promise.resolve()
|
|
24
|
+
.then(() => signal.aborted ? false : Promise.resolve(handler(message, signal)).then(() => true))
|
|
25
|
+
.then(done, () => done(false));
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/** Shared only by the private record products. The server owns field defaults
|
|
29
|
+
* and protocol refusals; the SDK preserves their codes and recovery hints. */
|
|
30
|
+
export function recordResources(t, plural) {
|
|
31
|
+
const base = `/v1/${plural}`;
|
|
32
|
+
const path = (id) => `${base}/${encodeURIComponent(id)}`;
|
|
33
|
+
const get = (id, options) => t.json({ ...options, method: "GET", path: path(id) });
|
|
34
|
+
const list = async (query = {}, options) => {
|
|
35
|
+
const page = await t.json({
|
|
36
|
+
...options,
|
|
37
|
+
method: "GET",
|
|
38
|
+
path: base,
|
|
39
|
+
query,
|
|
40
|
+
});
|
|
41
|
+
return new Page(page.data, page.nextCursor, (cursor) => list({ ...query, cursor }, options));
|
|
42
|
+
};
|
|
43
|
+
return {
|
|
44
|
+
create: (input, options) => t.json({ ...options, method: "POST", path: base, body: input }),
|
|
45
|
+
get,
|
|
46
|
+
list,
|
|
47
|
+
update: (id, input, options) => t.json({ ...options, method: "POST", path: `${path(id)}:update`, body: input }),
|
|
48
|
+
delete: (id, options) => t.json({ ...options, method: "DELETE", path: path(id) }),
|
|
49
|
+
/** Poll one resource with a deadline across every read, including retries. */
|
|
50
|
+
async wait(id, target = "ready", options = {}) {
|
|
51
|
+
const { pollMs = 250, timeoutMs = 300_000, signal } = options;
|
|
52
|
+
if (!Number.isSafeInteger(pollMs) ||
|
|
53
|
+
pollMs < 0 ||
|
|
54
|
+
!Number.isSafeInteger(timeoutMs) ||
|
|
55
|
+
timeoutMs < 0)
|
|
56
|
+
throw new RuntimeError({
|
|
57
|
+
code: "invalid_request",
|
|
58
|
+
status: 0,
|
|
59
|
+
message: "pollMs and timeoutMs must be nonnegative safe integers.",
|
|
60
|
+
hint: "Use milliseconds; zero timeout disables the deadline.",
|
|
61
|
+
});
|
|
62
|
+
const deadline = new AbortController();
|
|
63
|
+
const combined = signal ? AbortSignal.any([signal, deadline.signal]) : deadline.signal;
|
|
64
|
+
const timer = timeoutMs ? setTimeout(() => deadline.abort(), timeoutMs) : undefined;
|
|
65
|
+
try {
|
|
66
|
+
for (;;) {
|
|
67
|
+
combined.throwIfAborted();
|
|
68
|
+
const current = await get(id, {
|
|
69
|
+
signal: combined,
|
|
70
|
+
timeoutMs: 0,
|
|
71
|
+
});
|
|
72
|
+
combined.throwIfAborted();
|
|
73
|
+
if (current.state === "failed" || (current.state === "deleted" && target !== "deleted"))
|
|
74
|
+
throw new RuntimeError({
|
|
75
|
+
code: current.error?.code ?? "unexpected_state",
|
|
76
|
+
status: 0,
|
|
77
|
+
message: current.error?.message ?? `Resource reached ${current.state}.`,
|
|
78
|
+
hint: current.error?.hint ?? "Read the resource before retrying the change.",
|
|
79
|
+
details: { id, target, state: current.state },
|
|
80
|
+
});
|
|
81
|
+
if (current.state === target)
|
|
82
|
+
return current;
|
|
83
|
+
await pause(pollMs, combined);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch (cause) {
|
|
87
|
+
if (!combined.aborted)
|
|
88
|
+
throw cause;
|
|
89
|
+
throw new RuntimeError({
|
|
90
|
+
code: "timeout",
|
|
91
|
+
status: 0,
|
|
92
|
+
message: "Waiting ended before the target state was observed.",
|
|
93
|
+
hint: "Read the resource to resume; retry a write with its original idempotency key.",
|
|
94
|
+
cause,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
clearTimeout(timer);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/** Private until launch. No public Runtime property is installed here. */
|
|
104
|
+
export function queues(t) {
|
|
105
|
+
const action = (id, verb, body, options) => t.json({
|
|
106
|
+
...options,
|
|
107
|
+
method: "POST",
|
|
108
|
+
path: `/v1/queues/${encodeURIComponent(id)}:${verb}`,
|
|
109
|
+
body,
|
|
110
|
+
});
|
|
111
|
+
return {
|
|
112
|
+
...recordResources(t, "queues"),
|
|
113
|
+
send: (id, input, options) => action(id, "send", input, options),
|
|
114
|
+
receive: (id, input = {}, options) => action(id, "receive", input, options),
|
|
115
|
+
ack: (id, input, options) => action(id, "ack", input, options),
|
|
116
|
+
retry: (id, input, options) => action(id, "retry", input, options),
|
|
117
|
+
/** Receive, handle, then acknowledge. No acknowledgement precedes success.
|
|
118
|
+
* A failed or cancelled handler releases its receipt at once. Aborting
|
|
119
|
+
* during receive can lose its reply; that lease expires without an ack.
|
|
120
|
+
* Settlement ignores the cancelled signal and has a bounded deadline.
|
|
121
|
+
* A lost settlement reply is retried once with the same key, even when
|
|
122
|
+
* transport retries were disabled. A remaining failure is thrown. */
|
|
123
|
+
async consume(id, handler, options = {}) {
|
|
124
|
+
const { max, waitSeconds = 20, visibilitySeconds, timeoutMs = 30_000 } = options;
|
|
125
|
+
for (const [field, value, minimum, maximum] of [
|
|
126
|
+
["max", max, 0, Number.MAX_SAFE_INTEGER],
|
|
127
|
+
["waitSeconds", waitSeconds, 0, 20],
|
|
128
|
+
["visibilitySeconds", visibilitySeconds, 0, 43_200],
|
|
129
|
+
["timeoutMs", timeoutMs, 1, 2_147_483_647],
|
|
130
|
+
]) {
|
|
131
|
+
if (value !== undefined &&
|
|
132
|
+
(!Number.isSafeInteger(value) || value < minimum || value > maximum))
|
|
133
|
+
throw new RuntimeError({
|
|
134
|
+
code: "invalid_request",
|
|
135
|
+
status: 0,
|
|
136
|
+
message: `${field} must be an integer from ${minimum} to ${maximum}.`,
|
|
137
|
+
hint: "Correct the consume option; no message was received.",
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
const signal = options.signal ?? new AbortController().signal;
|
|
141
|
+
const result = { processed: 0, acknowledged: 0, retried: 0, aborted: false };
|
|
142
|
+
const settle = async (verb, body) => {
|
|
143
|
+
const request = { idempotencyKey: crypto.randomUUID(), timeoutMs };
|
|
144
|
+
try {
|
|
145
|
+
return await action(id, verb, body, request);
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
if (!(error instanceof RuntimeError) ||
|
|
149
|
+
!["connection_error", "timeout"].includes(error.code))
|
|
150
|
+
throw error;
|
|
151
|
+
return action(id, verb, body, request);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
while (!signal.aborted && (max === undefined || result.processed < max)) {
|
|
155
|
+
let received;
|
|
156
|
+
try {
|
|
157
|
+
received = await action(id, "receive", {
|
|
158
|
+
max: 1,
|
|
159
|
+
waitSeconds,
|
|
160
|
+
...(visibilitySeconds === undefined ? {} : { visibilitySeconds }),
|
|
161
|
+
}, { signal, timeoutMs, idempotencyKey: crypto.randomUUID() });
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
if (!signal.aborted)
|
|
165
|
+
throw error;
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
if (received.messages.length > 1)
|
|
169
|
+
throw new RuntimeError({
|
|
170
|
+
code: "invalid_response",
|
|
171
|
+
status: 0,
|
|
172
|
+
message: "Receive returned more than the one message requested.",
|
|
173
|
+
hint: "No message was acknowledged; their visibility leases will expire.",
|
|
174
|
+
});
|
|
175
|
+
const message = received.messages[0];
|
|
176
|
+
if (!message) {
|
|
177
|
+
// Empty short polls must yield to cancellation and avoid a hot loop.
|
|
178
|
+
await pause(100, signal).catch(() => { });
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
let success = false;
|
|
182
|
+
if (!signal.aborted) {
|
|
183
|
+
result.processed++;
|
|
184
|
+
success = await handleMessage(handler, message, signal);
|
|
185
|
+
}
|
|
186
|
+
if (success && !signal.aborted) {
|
|
187
|
+
const ack = await settle("ack", {
|
|
188
|
+
receiptHandles: [message.receiptHandle],
|
|
189
|
+
});
|
|
190
|
+
const failed = ack.failed[0];
|
|
191
|
+
if (failed || !ack.successful.includes(message.receiptHandle))
|
|
192
|
+
throw new RuntimeError({
|
|
193
|
+
code: failed?.code ?? "invalid_response",
|
|
194
|
+
status: 0,
|
|
195
|
+
message: failed?.message ?? "The receipt was not acknowledged.",
|
|
196
|
+
hint: failed?.hint ??
|
|
197
|
+
"Do not assume delivery completed; this message can be delivered again.",
|
|
198
|
+
details: { receiptHandle: message.receiptHandle },
|
|
199
|
+
});
|
|
200
|
+
result.acknowledged++;
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
await settle("retry", { receiptHandle: message.receiptHandle, visibilitySeconds: 0 });
|
|
204
|
+
result.retried++;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
result.aborted = signal.aborted;
|
|
208
|
+
return result;
|
|
209
|
+
},
|
|
210
|
+
/** Purge returns the resource; follow its state with wait(id). */
|
|
211
|
+
purge: (id, options) => action(id, "purge", {}, options),
|
|
212
|
+
};
|
|
213
|
+
}
|
|
@@ -5,13 +5,16 @@ export type ReferralSummary = {
|
|
|
5
5
|
code: string;
|
|
6
6
|
/** Share this: https://withruntime.com/r/<code>. */
|
|
7
7
|
link: string;
|
|
8
|
-
/** The least each side gets
|
|
8
|
+
/** The least each side gets on the referred company's first qualifying
|
|
9
|
+
* payment: a smaller one is matched up to this. */
|
|
9
10
|
rewardMicros: string;
|
|
10
|
-
/** The most each side gets
|
|
11
|
+
/** The most each side gets per referred company, all its matched payments
|
|
12
|
+
* together. */
|
|
11
13
|
maxRewardMicros: string;
|
|
12
|
-
/** The smallest
|
|
14
|
+
/** The smallest payment a referral matches. */
|
|
13
15
|
minPurchaseMicros: string;
|
|
14
|
-
/** The most referral credit you can earn in
|
|
16
|
+
/** The most referral credit, matches and share together, you can earn in
|
|
17
|
+
* one calendar year (UTC). */
|
|
15
18
|
yearlyCapMicros: string;
|
|
16
19
|
enabled: boolean;
|
|
17
20
|
year: number;
|
|
@@ -27,10 +30,21 @@ export type ReferralSummary = {
|
|
|
27
30
|
status: "pending" | "paid" | "refused" | "reversed";
|
|
28
31
|
creditMicros: string;
|
|
29
32
|
} | null;
|
|
33
|
+
/** Referred companies with a matched payment still standing. */
|
|
34
|
+
payingCompanies: number;
|
|
35
|
+
/** Share credit you kept, all time. */
|
|
36
|
+
shareEarnedMicros: string;
|
|
37
|
+
/** Your share of what a referred company spends from credit it paid for,
|
|
38
|
+
* in basis points: 1000 is 10%. */
|
|
39
|
+
shareBasisPoints: number;
|
|
40
|
+
/** How long the share runs from a company's first matched payment. */
|
|
41
|
+
shareMonths: number;
|
|
42
|
+
/** How long after sign-up a referred company's payments are matched. */
|
|
43
|
+
windowDays: number;
|
|
30
44
|
};
|
|
31
|
-
/** `runtime.referrals
|
|
32
|
-
* its first
|
|
33
|
-
*
|
|
45
|
+
/** `runtime.referrals`: a company that signs up with your link has every
|
|
46
|
+
* payment in its first 30 days matched, up to $1,000, and you get the same;
|
|
47
|
+
* then for 12 months you earn 10% of what it spends from credit it paid for. */
|
|
34
48
|
export declare function referrals(t: Transport): {
|
|
35
49
|
get: (options?: RequestOptions) => Promise<ReferralSummary>;
|
|
36
50
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/** `runtime.referrals
|
|
2
|
-
* its first
|
|
3
|
-
*
|
|
1
|
+
/** `runtime.referrals`: a company that signs up with your link has every
|
|
2
|
+
* payment in its first 30 days matched, up to $1,000, and you get the same;
|
|
3
|
+
* then for 12 months you earn 10% of what it spends from credit it paid for. */
|
|
4
4
|
export function referrals(t) {
|
|
5
5
|
return {
|
|
6
6
|
get: (options) => t.json({ method: "GET", path: "/v1/referrals", ...options }),
|
|
@@ -11,8 +11,10 @@ export type SecretRule = {
|
|
|
11
11
|
};
|
|
12
12
|
/** A secret your sandboxes use without seeing it. Every sandbox of your
|
|
13
13
|
* organization has an environment variable of the secret's name holding
|
|
14
|
-
* `placeholder`; the egress proxy
|
|
15
|
-
* `hosts
|
|
14
|
+
* `placeholder`; the egress proxy sets `header` on every HTTPS request to
|
|
15
|
+
* `hosts`, or, without `header`, replaces the placeholder in a credential
|
|
16
|
+
* header (Authorization, x-api-key, x-goog-api-key, api-key, xi-api-key,
|
|
17
|
+
* x-subscription-token, private-token). Never in the URL or another header.
|
|
16
18
|
* The value is never returned. */
|
|
17
19
|
export type Secret = {
|
|
18
20
|
name: string;
|
|
@@ -33,7 +35,9 @@ export type SetSecret = {
|
|
|
33
35
|
/** Where the value may go: `api.openai.com`, `*.github.com`. 1 to 16.
|
|
34
36
|
* Required unless `jobs` is true. */
|
|
35
37
|
hosts?: string[];
|
|
36
|
-
/** Set this header on every request to the hosts, replacing the sandbox's
|
|
38
|
+
/** Set this header on every request to the hosts, replacing the sandbox's
|
|
39
|
+
* own; the value then goes nowhere else. Needed when the API reads its key
|
|
40
|
+
* from a header that is not a credential header (see `Secret`). */
|
|
37
41
|
header?: string;
|
|
38
42
|
/** With `header`: its value, `{value}` where the secret goes. Default `{value}`. */
|
|
39
43
|
format?: string;
|
package/dist/products/secrets.js
CHANGED
|
@@ -36,16 +36,47 @@ export function secrets(t) {
|
|
|
36
36
|
const key = (options, part) => options?.idempotencyKey
|
|
37
37
|
? { ...options, idempotencyKey: `${options.idempotencyKey}:${part}`.slice(0, 128) }
|
|
38
38
|
: options;
|
|
39
|
+
const create = (name, value, options) => store({ method: "POST", path: "/v1/secrets", body: { name, value }, ...options });
|
|
40
|
+
const rotate = (live, value, version, options) => store({
|
|
41
|
+
method: "POST",
|
|
42
|
+
path: `${jobPath(live.id)}:rotate`,
|
|
43
|
+
body: { value, expectedVersion: version },
|
|
44
|
+
...options,
|
|
45
|
+
});
|
|
46
|
+
/** Rotates the jobs copy from the version it has now. A key used before,
|
|
47
|
+
* by this same call whose answer was lost, is answered by the identical
|
|
48
|
+
* request again, with no second rotation: the rotate from the version
|
|
49
|
+
* before, or one of `earlier` (a set's create). Until 10 October 2026 the
|
|
50
|
+
* retry read the copy as it is now, changed its request, and was refused
|
|
51
|
+
* as a conflict. */
|
|
52
|
+
async function rotateOrReplay(live, value, options, earlier = []) {
|
|
53
|
+
try {
|
|
54
|
+
return await rotate(live, value, live.version, options);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (!(error instanceof RuntimeError) || error.code !== "idempotency_conflict")
|
|
58
|
+
throw error;
|
|
59
|
+
const replays = [
|
|
60
|
+
...earlier,
|
|
61
|
+
...(live.version > 1 ? [() => rotate(live, value, live.version - 1, options)] : []),
|
|
62
|
+
];
|
|
63
|
+
for (const replay of replays) {
|
|
64
|
+
const answer = await replay().catch((again) => {
|
|
65
|
+
if (again instanceof RuntimeError && again.status === 409)
|
|
66
|
+
return undefined;
|
|
67
|
+
throw again;
|
|
68
|
+
});
|
|
69
|
+
if (answer)
|
|
70
|
+
return answer;
|
|
71
|
+
}
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
39
75
|
async function setJobCopy(name, value, options) {
|
|
40
76
|
const copies = await jobCopies(options);
|
|
41
77
|
const live = copies.find((s) => s.name === name && s.deletedAt === null);
|
|
42
78
|
if (live)
|
|
43
|
-
return
|
|
44
|
-
method: "POST",
|
|
45
|
-
path: `${jobPath(live.id)}:rotate`,
|
|
46
|
-
body: { value, expectedVersion: live.version },
|
|
47
|
-
...options,
|
|
48
|
-
});
|
|
79
|
+
return rotateOrReplay(live, value, options, [() => create(name, value, options)]);
|
|
49
80
|
if (copies.some((s) => s.name === name))
|
|
50
81
|
throw new RuntimeError({
|
|
51
82
|
message: `A jobs secret named ${name} was deleted, and a deleted name cannot be used again.`,
|
|
@@ -54,12 +85,7 @@ export function secrets(t) {
|
|
|
54
85
|
hint: "Store it under another name.",
|
|
55
86
|
details: { field: "name" },
|
|
56
87
|
});
|
|
57
|
-
return
|
|
58
|
-
method: "POST",
|
|
59
|
-
path: "/v1/secrets",
|
|
60
|
-
body: { name, value },
|
|
61
|
-
...options,
|
|
62
|
-
});
|
|
88
|
+
return create(name, value, options);
|
|
63
89
|
}
|
|
64
90
|
async function all(options) {
|
|
65
91
|
const [forSandboxes, forJobs] = await Promise.all([
|
|
@@ -156,12 +182,7 @@ export function secrets(t) {
|
|
|
156
182
|
status: 404,
|
|
157
183
|
hint: "Store one with set(name, { value, jobs: true }). The sandboxes' copy is replaced by set, not rotated.",
|
|
158
184
|
});
|
|
159
|
-
return
|
|
160
|
-
method: "POST",
|
|
161
|
-
path: `${jobPath(live.id)}:rotate`,
|
|
162
|
-
body: { value, expectedVersion: live.version },
|
|
163
|
-
...options,
|
|
164
|
-
});
|
|
185
|
+
return rotateOrReplay(live, value, options);
|
|
165
186
|
},
|
|
166
187
|
/** Read the jobs copy's value back (needs the key's secrets_reveal
|
|
167
188
|
* permission). The sandboxes' copy can never be read back. */
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RequestOptions, Transport } from "../transport.js";
|
|
2
|
+
export type SignedRequests = {
|
|
3
|
+
/** Whether your sandboxes may get Runtime's request signature now. */
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
/** Whether this account may turn it on: it must have credit. */
|
|
6
|
+
allowed: boolean;
|
|
7
|
+
/** Why not, when `allowed` is false: `no_credit`, `revoked` or `suspended`. */
|
|
8
|
+
why: string | null;
|
|
9
|
+
enabledAt: string | null;
|
|
10
|
+
disabledAt: string | null;
|
|
11
|
+
};
|
|
12
|
+
export declare function signedRequests(t: Transport): {
|
|
13
|
+
/** On or off, and whether this account may turn it on. */
|
|
14
|
+
get: (options?: RequestOptions) => Promise<SignedRequests>;
|
|
15
|
+
/** `enabled: true` lets your sandboxes get Runtime's request signature;
|
|
16
|
+
* `false` stops new signatures at once, and ones already given expire
|
|
17
|
+
* within 5 minutes. */
|
|
18
|
+
set: (input: {
|
|
19
|
+
enabled: boolean;
|
|
20
|
+
}, options?: RequestOptions) => Promise<SignedRequests>;
|
|
21
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function signedRequests(t) {
|
|
2
|
+
const path = "/v1/networks/signed-requests";
|
|
3
|
+
return {
|
|
4
|
+
/** On or off, and whether this account may turn it on. */
|
|
5
|
+
get: (options) => t.json({ method: "GET", path, ...options }),
|
|
6
|
+
/** `enabled: true` lets your sandboxes get Runtime's request signature;
|
|
7
|
+
* `false` stops new signatures at once, and ones already given expire
|
|
8
|
+
* within 5 minutes. */
|
|
9
|
+
set: (input, options) => t.json({ method: "PUT", path, body: input, ...options }),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { RequestOptions, Transport } from "../transport.js";
|
|
2
|
+
import { type RecordResource } from "./queues.js";
|
|
3
|
+
/** Private until launch.
|
|
4
|
+
* Kafka clients use kafka.bootstrap and kafka.topic unchanged.
|
|
5
|
+
* Offsets and byte counts use decimal strings so JSON never rounds them. */
|
|
6
|
+
export type Stream = RecordResource & {
|
|
7
|
+
partitions: number;
|
|
8
|
+
retentionMs: number;
|
|
9
|
+
retentionBytes: string;
|
|
10
|
+
kafka: {
|
|
11
|
+
bootstrap: string;
|
|
12
|
+
topic: string;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export type CreateStream = {
|
|
16
|
+
name: string;
|
|
17
|
+
labels?: Record<string, string>;
|
|
18
|
+
partitions?: number;
|
|
19
|
+
retentionMs?: number;
|
|
20
|
+
retentionBytes?: string;
|
|
21
|
+
};
|
|
22
|
+
export type UpdateStream = Partial<CreateStream>;
|
|
23
|
+
/** Text values are UTF-8. Use a Kafka client for arbitrary binary records. */
|
|
24
|
+
export type StreamRecord = {
|
|
25
|
+
key?: string | null;
|
|
26
|
+
value: string | null;
|
|
27
|
+
headers?: {
|
|
28
|
+
key: string;
|
|
29
|
+
value: string | null;
|
|
30
|
+
}[];
|
|
31
|
+
};
|
|
32
|
+
export type PublishRecords = {
|
|
33
|
+
records: StreamRecord[];
|
|
34
|
+
};
|
|
35
|
+
export type ReadStream = {
|
|
36
|
+
partition: number;
|
|
37
|
+
maxBytes?: number;
|
|
38
|
+
waitMs?: number;
|
|
39
|
+
} & ({
|
|
40
|
+
offset: string;
|
|
41
|
+
time?: never;
|
|
42
|
+
} | {
|
|
43
|
+
time: number;
|
|
44
|
+
offset?: never;
|
|
45
|
+
});
|
|
46
|
+
export type PublishedRecord = {
|
|
47
|
+
partition: number;
|
|
48
|
+
offset: string;
|
|
49
|
+
};
|
|
50
|
+
export type StreamRead = {
|
|
51
|
+
records: (StreamRecord & PublishedRecord & {
|
|
52
|
+
time: number;
|
|
53
|
+
})[];
|
|
54
|
+
nextOffset: string;
|
|
55
|
+
};
|
|
56
|
+
/** Private until launch. Proposed routes only; nothing is registered here. */
|
|
57
|
+
export declare function streams(t: Transport): {
|
|
58
|
+
publish: (id: string, input: PublishRecords, options?: RequestOptions) => Promise<{
|
|
59
|
+
records: PublishedRecord[];
|
|
60
|
+
}>;
|
|
61
|
+
read: (id: string, input: ReadStream, options?: RequestOptions) => Promise<StreamRead>;
|
|
62
|
+
/** Trim returns the resource; follow its state with wait(id). */
|
|
63
|
+
trim: (id: string, input: {
|
|
64
|
+
partition: number;
|
|
65
|
+
before: string;
|
|
66
|
+
}, options?: RequestOptions) => Promise<Stream>;
|
|
67
|
+
create: (input: CreateStream, options?: RequestOptions) => Promise<Stream>;
|
|
68
|
+
get: (id: string, options?: RequestOptions) => Promise<Stream>;
|
|
69
|
+
list: (query?: import("./queues.js").RecordListQuery, options?: RequestOptions) => Promise<import("../page.js").Page<Stream>>;
|
|
70
|
+
update: (id: string, input: Partial<CreateStream>, options?: RequestOptions) => Promise<Stream>;
|
|
71
|
+
delete: (id: string, options?: RequestOptions) => Promise<Stream>;
|
|
72
|
+
wait(id: string, target?: "ready" | "deleted", options?: import("./queues.js").RecordWaitOptions): Promise<Stream>;
|
|
73
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { recordResources } from "./queues.js";
|
|
2
|
+
/** Private until launch. Proposed routes only; nothing is registered here. */
|
|
3
|
+
export function streams(t) {
|
|
4
|
+
const path = (id) => `/v1/streams/${encodeURIComponent(id)}`;
|
|
5
|
+
return {
|
|
6
|
+
...recordResources(t, "streams"),
|
|
7
|
+
publish: (id, input, options) => t.json({
|
|
8
|
+
...options,
|
|
9
|
+
method: "POST",
|
|
10
|
+
path: `${path(id)}:publish`,
|
|
11
|
+
body: input,
|
|
12
|
+
}),
|
|
13
|
+
read: (id, input, options) => t.json({ ...options, method: "GET", path: `${path(id)}:read`, query: input }),
|
|
14
|
+
/** Trim returns the resource; follow its state with wait(id). */
|
|
15
|
+
trim: (id, input, options) => t.json({ ...options, method: "POST", path: `${path(id)}:trim`, body: input }),
|
|
16
|
+
};
|
|
17
|
+
}
|