withruntime 0.11.1 → 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 +3 -3
- package/COMPATIBILITY.md +74 -9
- package/DAYTONA.md +33 -5
- package/E2B.md +137 -48
- package/README.md +11 -9
- package/README.src.md +11 -9
- 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 +33 -4
- 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 +15 -7
- package/dist/blaxel/sandbox.js +64 -9
- 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 +6 -2
- package/dist/cli.js +468 -219
- package/dist/client.d.ts +13 -63
- package/dist/client.js +35 -124
- 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 +7 -2
- package/dist/daytona/daytona.js +31 -5
- 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 +9 -3
- package/dist/daytona/sandbox.js +17 -3
- package/dist/domains/index.d.ts +9 -0
- package/dist/domains/index.js +10 -0
- package/dist/e2b/client.d.ts +15 -2
- package/dist/e2b/client.js +61 -7
- package/dist/e2b/commands.d.ts +4 -1
- package/dist/e2b/commands.js +17 -7
- package/dist/e2b/errors.d.ts +43 -2
- package/dist/e2b/errors.js +78 -6
- package/dist/e2b/filesystem.d.ts +1 -1
- package/dist/e2b/filesystem.js +82 -16
- package/dist/e2b/index.d.ts +3 -3
- package/dist/e2b/index.js +2 -2
- package/dist/e2b/sandbox.d.ts +50 -35
- package/dist/e2b/sandbox.js +228 -185
- package/dist/e2b/unsupported.d.ts +19 -0
- package/dist/e2b/unsupported.js +22 -1
- package/dist/e2b/users.d.ts +9 -0
- package/dist/e2b/users.js +22 -0
- package/dist/errors.d.ts +14 -5
- package/dist/errors.js +28 -14
- 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 +189 -0
- package/dist/machine.js +521 -0
- 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/openai-agents/index.d.ts +1 -1
- package/dist/openai-agents/index.js +1 -1
- 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 +19 -3
- package/dist/products/jobs.js +28 -12
- package/dist/products/limits.d.ts +4 -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/network.d.ts +1 -1
- 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 +8 -4
- 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 +37 -10
- 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 +10 -94
- package/dist/sandbox.js +22 -371
- 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 +18 -2
- package/dist/transport.js +61 -6
- package/dist/tunnel.js +1 -1
- package/dist/types.d.ts +116 -8
- package/dist/vercel/sandbox.d.ts +1 -2
- package/dist/vercel/sandbox.js +6 -5
- 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
|
@@ -129,9 +129,9 @@ export declare function ports(t: Transport): {
|
|
|
129
129
|
deleted: true;
|
|
130
130
|
}>;
|
|
131
131
|
};
|
|
132
|
-
/** `runtime.
|
|
132
|
+
/** `runtime.ips`: a dedicated outbound address every sandbox of the
|
|
133
133
|
* account sends from, for allow-lists. */
|
|
134
|
-
export declare function
|
|
134
|
+
export declare function ips(t: Transport): {
|
|
135
135
|
reserve: (input?: {
|
|
136
136
|
family?: 4 | 6;
|
|
137
137
|
}, options?: RequestOptions) => Promise<EgressAddress>;
|
|
@@ -142,8 +142,8 @@ export declare function addresses(t: Transport): {
|
|
|
142
142
|
deleted: true;
|
|
143
143
|
}>;
|
|
144
144
|
};
|
|
145
|
-
/** `runtime.
|
|
146
|
-
export declare function
|
|
145
|
+
/** `runtime.networks.wireguard`: a WireGuard tunnel from your own network into your sandboxes. */
|
|
146
|
+
export declare function wireguard(t: Transport): {
|
|
147
147
|
get: (options?: RequestOptions) => Promise<Tunnel>;
|
|
148
148
|
/** Idempotent: returns the tunnel you have. */
|
|
149
149
|
create: (input?: {
|
|
@@ -186,15 +186,39 @@ export type SetUpstreamProxy = {
|
|
|
186
186
|
* every connection when absent. 1 to 16. */
|
|
187
187
|
hosts?: string[];
|
|
188
188
|
};
|
|
189
|
-
/** `runtime.
|
|
189
|
+
/** `runtime.networks`: the networks of the whole account: the WireGuard
|
|
190
|
+
* tunnel in, your sandboxes reaching each other, and the proxy out.
|
|
190
191
|
*
|
|
191
|
-
* await runtime.
|
|
192
|
+
* await runtime.networks.upstreamProxy.set({ url: "http://proxy.example.com:3128" });
|
|
192
193
|
*
|
|
193
194
|
* `upstreamProxy`: after Runtime's own rules allow a connection, the host
|
|
194
195
|
* reaches it with CONNECT through your proxy, so your proxy's controls and
|
|
195
196
|
* logs apply. A proxy that refuses or cannot be reached fails the connection
|
|
196
197
|
* (upstream-proxy-failed); nothing goes around it. Needs a kept top-up. */
|
|
197
|
-
export declare function
|
|
198
|
+
export declare function networks(t: Transport): {
|
|
199
|
+
/** The WireGuard tunnel from your own network into your sandboxes. */
|
|
200
|
+
wireguard: {
|
|
201
|
+
get: (options?: RequestOptions) => Promise<Tunnel>;
|
|
202
|
+
/** Idempotent: returns the tunnel you have. */
|
|
203
|
+
create: (input?: {
|
|
204
|
+
subnet?: string;
|
|
205
|
+
}, options?: RequestOptions) => Promise<Tunnel>;
|
|
206
|
+
delete: (options?: RequestOptions) => Promise<{
|
|
207
|
+
id: string;
|
|
208
|
+
deleted: true;
|
|
209
|
+
}>;
|
|
210
|
+
/** Leave publicKey out and Runtime generates the pair; the private key is
|
|
211
|
+
* then in `config`, shown once. */
|
|
212
|
+
addPeer: (input: {
|
|
213
|
+
name: string;
|
|
214
|
+
publicKey?: string;
|
|
215
|
+
routes?: string[];
|
|
216
|
+
}, options?: RequestOptions) => Promise<TunnelPeerCreated>;
|
|
217
|
+
rotatePeer: (peerId: string, input?: {
|
|
218
|
+
publicKey?: string;
|
|
219
|
+
}, options?: RequestOptions) => Promise<TunnelPeerCreated>;
|
|
220
|
+
removePeer: (peerId: string, options?: RequestOptions) => Promise<Tunnel>;
|
|
221
|
+
};
|
|
198
222
|
/** Your sandboxes reaching each other by name (`private-network.ts`). */
|
|
199
223
|
private: {
|
|
200
224
|
get: (options?: RequestOptions) => Promise<import("./private-network.js").PrivateNetwork>;
|
|
@@ -202,6 +226,13 @@ export declare function network(t: Transport): {
|
|
|
202
226
|
enabled: boolean;
|
|
203
227
|
}, options?: RequestOptions) => Promise<import("./private-network.js").PrivateNetwork>;
|
|
204
228
|
};
|
|
229
|
+
/** Your sandboxes' requests signed as Runtime's agents (`signed-requests.ts`). */
|
|
230
|
+
signedRequests: {
|
|
231
|
+
get: (options?: RequestOptions) => Promise<import("./signed-requests.js").SignedRequests>;
|
|
232
|
+
set: (input: {
|
|
233
|
+
enabled: boolean;
|
|
234
|
+
}, options?: RequestOptions) => Promise<import("./signed-requests.js").SignedRequests>;
|
|
235
|
+
};
|
|
205
236
|
upstreamProxy: {
|
|
206
237
|
/** Send outbound connections through your proxy, replacing any set before. */
|
|
207
238
|
set: (input: SetUpstreamProxy, options?: RequestOptions) => Promise<UpstreamProxy & {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { privateNetwork } from "./private-network.js";
|
|
2
|
+
import { signedRequests } from "./signed-requests.js";
|
|
2
3
|
const enc = encodeURIComponent;
|
|
3
4
|
/** `runtime.domains`: serve a sandbox's port at your own hostname, with HTTPS. */
|
|
4
5
|
export function domains(t) {
|
|
@@ -43,57 +44,69 @@ export function ports(t) {
|
|
|
43
44
|
}),
|
|
44
45
|
};
|
|
45
46
|
}
|
|
46
|
-
/** `runtime.
|
|
47
|
+
/** `runtime.ips`: a dedicated outbound address every sandbox of the
|
|
47
48
|
* account sends from, for allow-lists. */
|
|
48
|
-
export function
|
|
49
|
+
export function ips(t) {
|
|
49
50
|
return {
|
|
50
|
-
reserve: (input = {}, options) => t.json({ method: "POST", path: "/v1/
|
|
51
|
-
list: async (options) => (await t.json({ method: "GET", path: "/v1/
|
|
52
|
-
.data,
|
|
51
|
+
reserve: (input = {}, options) => t.json({ method: "POST", path: "/v1/ips", body: input, ...options }),
|
|
52
|
+
list: async (options) => (await t.json({ method: "GET", path: "/v1/ips", ...options })).data,
|
|
53
53
|
release: (addressId, options) => t.json({
|
|
54
54
|
method: "DELETE",
|
|
55
|
-
path: `/v1/
|
|
55
|
+
path: `/v1/ips/${enc(addressId)}`,
|
|
56
56
|
...options,
|
|
57
57
|
}),
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
-
/** `runtime.
|
|
61
|
-
export function
|
|
60
|
+
/** `runtime.networks.wireguard`: a WireGuard tunnel from your own network into your sandboxes. */
|
|
61
|
+
export function wireguard(t) {
|
|
62
62
|
return {
|
|
63
|
-
get: (options) => t.json({ method: "GET", path: "/v1/
|
|
63
|
+
get: (options) => t.json({ method: "GET", path: "/v1/networks/wireguard", ...options }),
|
|
64
64
|
/** Idempotent: returns the tunnel you have. */
|
|
65
|
-
create: (input = {}, options) => t.json({ method: "POST", path: "/v1/
|
|
66
|
-
delete: (options) => t.json({
|
|
65
|
+
create: (input = {}, options) => t.json({ method: "POST", path: "/v1/networks/wireguard", body: input, ...options }),
|
|
66
|
+
delete: (options) => t.json({
|
|
67
|
+
method: "DELETE",
|
|
68
|
+
path: "/v1/networks/wireguard",
|
|
69
|
+
...options,
|
|
70
|
+
}),
|
|
67
71
|
/** Leave publicKey out and Runtime generates the pair; the private key is
|
|
68
72
|
* then in `config`, shown once. */
|
|
69
73
|
addPeer: (input, options) => t.json({
|
|
70
74
|
method: "POST",
|
|
71
|
-
path: "/v1/
|
|
75
|
+
path: "/v1/networks/wireguard/peers",
|
|
72
76
|
body: input,
|
|
73
77
|
...options,
|
|
74
78
|
}),
|
|
75
79
|
rotatePeer: (peerId, input = {}, options) => t.json({
|
|
76
80
|
method: "POST",
|
|
77
|
-
path: `/v1/
|
|
81
|
+
path: `/v1/networks/wireguard/peers/${enc(peerId)}:rotate`,
|
|
78
82
|
body: input,
|
|
79
83
|
...options,
|
|
80
84
|
}),
|
|
81
|
-
removePeer: (peerId, options) => t.json({
|
|
85
|
+
removePeer: (peerId, options) => t.json({
|
|
86
|
+
method: "DELETE",
|
|
87
|
+
path: `/v1/networks/wireguard/peers/${enc(peerId)}`,
|
|
88
|
+
...options,
|
|
89
|
+
}),
|
|
82
90
|
};
|
|
83
91
|
}
|
|
84
|
-
/** `runtime.
|
|
92
|
+
/** `runtime.networks`: the networks of the whole account: the WireGuard
|
|
93
|
+
* tunnel in, your sandboxes reaching each other, and the proxy out.
|
|
85
94
|
*
|
|
86
|
-
* await runtime.
|
|
95
|
+
* await runtime.networks.upstreamProxy.set({ url: "http://proxy.example.com:3128" });
|
|
87
96
|
*
|
|
88
97
|
* `upstreamProxy`: after Runtime's own rules allow a connection, the host
|
|
89
98
|
* reaches it with CONNECT through your proxy, so your proxy's controls and
|
|
90
99
|
* logs apply. A proxy that refuses or cannot be reached fails the connection
|
|
91
100
|
* (upstream-proxy-failed); nothing goes around it. Needs a kept top-up. */
|
|
92
|
-
export function
|
|
93
|
-
const path = "/v1/
|
|
101
|
+
export function networks(t) {
|
|
102
|
+
const path = "/v1/networks/upstream-proxy";
|
|
94
103
|
return {
|
|
104
|
+
/** The WireGuard tunnel from your own network into your sandboxes. */
|
|
105
|
+
wireguard: wireguard(t),
|
|
95
106
|
/** Your sandboxes reaching each other by name (`private-network.ts`). */
|
|
96
107
|
private: privateNetwork(t),
|
|
108
|
+
/** Your sandboxes' requests signed as Runtime's agents (`signed-requests.ts`). */
|
|
109
|
+
signedRequests: signedRequests(t),
|
|
97
110
|
upstreamProxy: {
|
|
98
111
|
/** Send outbound connections through your proxy, replacing any set before. */
|
|
99
112
|
set: (input, options) => t.json({
|
|
@@ -24,7 +24,7 @@ export type NetworkPolicy = Required<NetworkRules> & {
|
|
|
24
24
|
/** Ports reachable without a connect entry. */
|
|
25
25
|
ports: number[];
|
|
26
26
|
connectAllowed: boolean;
|
|
27
|
-
/** paid, granted, not_paid, revoked, suspended, or trial (a
|
|
27
|
+
/** paid, granted, not_paid, revoked, suspended, or trial (a sandbox without credit reaches ports 80 and 443 only). */
|
|
28
28
|
connectReason: string;
|
|
29
29
|
forbiddenPorts: number[];
|
|
30
30
|
updatedAt: string | null;
|
|
@@ -35,7 +35,7 @@ export type SandboxMetrics = {
|
|
|
35
35
|
latest: MetricPoint | null;
|
|
36
36
|
points: MetricPoint[];
|
|
37
37
|
};
|
|
38
|
-
export type WebhookEventType = "sandbox.created" | "sandbox.running" | "sandbox.paused" | "sandbox.woken" | "sandbox.stopped" | "sandbox.start_failed" | "sandbox.wake_failed" | "sandbox.host_unreachable" | "sandbox.host_reachable" | "sandbox.recovered" | "sandbox.recovery_failed" | "snapshot.ready" | "snapshot.failed" | "snapshot.deleted" | "volume.ready" | "volume.failed" | "volume.deleted";
|
|
38
|
+
export type WebhookEventType = "sandbox.created" | "sandbox.running" | "sandbox.paused" | "sandbox.woken" | "sandbox.stopped" | "sandbox.start_failed" | "sandbox.wake_failed" | "sandbox.host_unreachable" | "sandbox.host_reachable" | "sandbox.recovered" | "sandbox.recovery_failed" | "sandbox.files.changed" | "sandbox.out_of_memory" | "sandbox.secret_not_applied" | "snapshot.ready" | "snapshot.failed" | "snapshot.deleted" | "volume.ready" | "volume.failed" | "volume.deleted" | "egress_secret.created" | "egress_secret.updated" | "egress_secret.deleted" | "upstream_proxy.set" | "upstream_proxy.removed";
|
|
39
39
|
/** An event as /v1/events lists it and a webhook delivers it. */
|
|
40
40
|
export type RuntimeEvent = {
|
|
41
41
|
id: string;
|
|
@@ -113,7 +113,8 @@ export type UsageExportRow = {
|
|
|
113
113
|
name: string | null;
|
|
114
114
|
kind: string;
|
|
115
115
|
meter: string;
|
|
116
|
-
|
|
116
|
+
/** credit, the trial's hours, or the month's included usage. */
|
|
117
|
+
fundedBy: "credit" | "trial" | "allowance";
|
|
117
118
|
startsAt: string;
|
|
118
119
|
endsAt: string;
|
|
119
120
|
settledAt: string;
|
|
@@ -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 }),
|