withruntime 0.23.0 → 0.33.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/COMPATIBILITY.md +64 -3
- package/E2B.md +1 -1
- package/README.md +36 -2
- package/README.src.md +35 -1
- package/compatibility-lock.json +3 -3
- package/dist/agents/browser.d.ts +12 -0
- package/dist/agents/browser.js +12 -0
- package/dist/agents/index.d.ts +7 -7
- package/dist/agents/index.js +7 -8
- package/dist/agents-cli.d.ts +1 -1
- package/dist/agents-cli.js +250 -3
- package/dist/agents-deploy.d.ts +186 -0
- package/dist/agents-deploy.js +752 -0
- package/dist/agents-file.d.ts +19 -0
- package/dist/agents-file.js +135 -0
- package/dist/apps/index.d.ts +10 -0
- package/dist/apps/index.js +11 -0
- package/dist/apps-cli.d.ts +3 -1
- package/dist/apps-cli.js +285 -38
- package/dist/blaxel/errors.js +2 -1
- package/dist/ci/index.d.ts +10 -0
- package/dist/ci/index.js +11 -0
- package/dist/ci-cli.d.ts +10 -0
- package/dist/ci-cli.js +343 -0
- package/dist/cli.d.ts +18 -7
- package/dist/cli.js +775 -85
- package/dist/daytona/errors.js +2 -1
- package/dist/e2b/errors.js +2 -1
- package/dist/e2b/filesystem.d.ts +1 -0
- package/dist/e2b/filesystem.js +1 -1
- package/dist/e2b/sandbox.d.ts +11 -2
- package/dist/e2b/sandbox.js +22 -6
- package/dist/errors.d.ts +11 -4
- package/dist/errors.js +27 -4
- package/dist/fly/index.d.ts +102 -0
- package/dist/fly/index.js +930 -0
- package/dist/index.d.ts +7 -3
- package/dist/machine.d.ts +10 -6
- package/dist/machine.js +14 -6
- package/dist/modal/index.d.ts +34 -0
- package/dist/modal/index.js +128 -22
- package/dist/products/agents.d.ts +101 -3
- package/dist/products/agents.js +49 -0
- package/dist/products/apps.d.ts +206 -10
- package/dist/products/apps.js +172 -1
- package/dist/products/ci.d.ts +332 -0
- package/dist/products/ci.js +101 -0
- package/dist/products/index.d.ts +8 -0
- package/dist/products/index.js +15 -0
- package/dist/products/jobs.d.ts +105 -5
- package/dist/products/jobs.js +47 -3
- package/dist/products/network.d.ts +13 -0
- package/dist/products/observability.d.ts +1 -1
- package/dist/products/plans.d.ts +131 -0
- package/dist/products/plans.js +24 -0
- package/dist/products/reservations.d.ts +108 -0
- package/dist/products/reservations.js +41 -0
- package/dist/products/resources.d.ts +2 -1
- package/dist/products/secrets.d.ts +90 -6
- package/dist/products/secrets.js +8 -2
- package/dist/proxy.d.ts +3 -3
- package/dist/proxy.js +20 -0
- package/dist/sandbox.d.ts +29 -1
- package/dist/sandbox.js +56 -3
- package/dist/snapshots.d.ts +1 -1
- package/dist/switched-off.d.ts +5 -0
- package/dist/switched-off.js +8 -0
- package/dist/tar.d.ts +1 -1
- package/dist/tar.js +19 -1
- package/dist/transport.d.ts +1 -1
- package/dist/transport.js +48 -9
- package/dist/types.d.ts +35 -4
- package/dist/vercel/errors.d.ts +1 -1
- package/dist/vercel/errors.js +2 -1
- package/dist/vercel/snapshot.js +4 -2
- package/package.json +23 -6
package/dist/products/jobs.d.ts
CHANGED
|
@@ -15,6 +15,15 @@ export type JobCompute = {
|
|
|
15
15
|
durationSeconds: number;
|
|
16
16
|
/** The most one run may hold, in microdollars. */
|
|
17
17
|
maxCostMicros?: number;
|
|
18
|
+
/** Volumes each run's sandbox attaches, at most four, as a sandbox create
|
|
19
|
+
* takes them. `"rw"` (the default) is read-write, one sandbox at a time, so
|
|
20
|
+
* what one run writes the next run reads; `"snapshot"` is a read-only copy
|
|
21
|
+
* as the run starts. The run starts on the volume's server. */
|
|
22
|
+
volumes?: {
|
|
23
|
+
volumeId: string;
|
|
24
|
+
path: string;
|
|
25
|
+
mode?: "rw" | "snapshot";
|
|
26
|
+
}[];
|
|
18
27
|
};
|
|
19
28
|
export type JobSchedule = {
|
|
20
29
|
kind: "once"; /** Unix milliseconds. */
|
|
@@ -44,6 +53,40 @@ export type JobDefinition = {
|
|
|
44
53
|
name: string;
|
|
45
54
|
secretId: string;
|
|
46
55
|
}>;
|
|
56
|
+
/** The id of the image each run starts from; absent, the standard image. */
|
|
57
|
+
image?: string;
|
|
58
|
+
};
|
|
59
|
+
/** Who hears when a job's runs fail. Once `afterFailures` runs in a row end
|
|
60
|
+
* failed, timed out or unknown, one alert goes out; once a run succeeds
|
|
61
|
+
* again, one more says it recovered. A run that will be retried counts at
|
|
62
|
+
* its last attempt. */
|
|
63
|
+
export type JobAlert = {
|
|
64
|
+
/** Runs in a row, 1 to 100. Default 1. */
|
|
65
|
+
afterFailures?: number;
|
|
66
|
+
/** POSTed the account webhooks' body (`job.run.failed`, `job.recovered`),
|
|
67
|
+
* signed with the jobs secret `secretId` the way those are signed with
|
|
68
|
+
* theirs: check it with `verifyWebhook(body, header, secretValue)`. The
|
|
69
|
+
* key must be allowed to reveal that secret, not only use it. */
|
|
70
|
+
webhook?: {
|
|
71
|
+
url: string;
|
|
72
|
+
secretId?: string;
|
|
73
|
+
};
|
|
74
|
+
/** Mailed to the job's person: who made it, or whom its key serves. */
|
|
75
|
+
email?: true;
|
|
76
|
+
};
|
|
77
|
+
/** The last alert a job sent and how its delivery went. */
|
|
78
|
+
export type JobAlertDelivery = {
|
|
79
|
+
id: string;
|
|
80
|
+
type: "job.run.failed" | "job.recovered";
|
|
81
|
+
channel: "webhook" | "email";
|
|
82
|
+
runId: string;
|
|
83
|
+
/** `pending` while it is retried (about three days, as webhooks are). */
|
|
84
|
+
state: "pending" | "succeeded" | "failed";
|
|
85
|
+
attempts: number;
|
|
86
|
+
lastStatus: number | null;
|
|
87
|
+
lastError: string | null;
|
|
88
|
+
createdAt: number;
|
|
89
|
+
deliveredAt: number | null;
|
|
47
90
|
};
|
|
48
91
|
export type Job = {
|
|
49
92
|
id: string;
|
|
@@ -58,8 +101,18 @@ export type Job = {
|
|
|
58
101
|
runRequestedAt: number | null;
|
|
59
102
|
/** Why the last due run could not start, retried every 30 seconds:
|
|
60
103
|
* `credits` (add credit), `capacity`, `cost_cap` (maxTotalCostMicros or a
|
|
61
|
-
* key's daily limit)
|
|
62
|
-
|
|
104
|
+
* key's daily limit), `permission` (the key that made the job lost it, or
|
|
105
|
+
* may not use a volume it attaches) or `volume` (a volume it attaches is
|
|
106
|
+
* deleted, not ready, or attached read-write to another sandbox). */
|
|
107
|
+
blockedReason: "permission" | "capacity" | "credits" | "cost_cap" | "volume" | null;
|
|
108
|
+
alert: (JobAlert & {
|
|
109
|
+
afterFailures: number;
|
|
110
|
+
}) | null;
|
|
111
|
+
/** Runs in a row that ended failing, until one succeeds. */
|
|
112
|
+
failingRuns: number;
|
|
113
|
+
/** When its alert went out, while its runs keep failing; Unix ms. */
|
|
114
|
+
alertingSince: number | null;
|
|
115
|
+
lastAlert: JobAlertDelivery | null;
|
|
63
116
|
createdAt: number;
|
|
64
117
|
updatedAt: number;
|
|
65
118
|
};
|
|
@@ -137,6 +190,38 @@ export type CreateJob = {
|
|
|
137
190
|
}>;
|
|
138
191
|
/** The most every run of this job together may hold, in microdollars. */
|
|
139
192
|
maxTotalCostMicros?: number;
|
|
193
|
+
/** An image of this account each run starts from: its id, name (its
|
|
194
|
+
* `latest` tag), `name:tag` or `name@version`, resolved to its id now, as
|
|
195
|
+
* an App deploy takes it. Default: the standard image. */
|
|
196
|
+
image?: string;
|
|
197
|
+
/** Tell a webhook or the job's person when runs fail, and when they
|
|
198
|
+
* recover. */
|
|
199
|
+
alert?: JobAlert;
|
|
200
|
+
};
|
|
201
|
+
/** What `jobs.update` changes; everything left out stays. The name stays,
|
|
202
|
+
* and the schedule moves with `reschedule`. */
|
|
203
|
+
export type UpdateJob = {
|
|
204
|
+
command?: CreateJob["command"];
|
|
205
|
+
/** null: back to the standard image. */
|
|
206
|
+
image?: string | null;
|
|
207
|
+
/** The fields given; the rest stay. `volumes` replaces the whole list
|
|
208
|
+
* (`[]`: none). */
|
|
209
|
+
compute?: Partial<JobCompute>;
|
|
210
|
+
/** The whole list, replacing the one before. */
|
|
211
|
+
secrets?: Array<{
|
|
212
|
+
name: string;
|
|
213
|
+
secretId: string;
|
|
214
|
+
}>;
|
|
215
|
+
/** null: no alert. */
|
|
216
|
+
alert?: JobAlert | null;
|
|
217
|
+
timeoutSeconds?: number;
|
|
218
|
+
/** The fields given; the rest stay. */
|
|
219
|
+
retry?: Partial<{
|
|
220
|
+
maxAttempts: number;
|
|
221
|
+
backoffSeconds: number;
|
|
222
|
+
}>;
|
|
223
|
+
/** null: no cap. */
|
|
224
|
+
maxTotalCostMicros?: number | null;
|
|
140
225
|
};
|
|
141
226
|
/** The size a run gets when `compute` leaves a field out: the sandbox
|
|
142
227
|
* defaults, in the region `us-east`. */
|
|
@@ -161,6 +246,7 @@ export declare const JOB_LIMITS: {
|
|
|
161
246
|
maxDurationSeconds: number;
|
|
162
247
|
maxAttempts: number;
|
|
163
248
|
maxSecrets: number;
|
|
249
|
+
maxVolumes: number;
|
|
164
250
|
};
|
|
165
251
|
/** Unix milliseconds from a Date, an ISO time or a number. */
|
|
166
252
|
export declare function jobTime(at: Date | string | number): number;
|
|
@@ -170,8 +256,11 @@ export declare function jobSchedule(input: CreateJob["schedule"]): JobSchedule;
|
|
|
170
256
|
/** The API's job body from `CreateJob`, with every default filled in and the
|
|
171
257
|
* sandbox's size checked before anything is sent. */
|
|
172
258
|
export declare function jobBody(input: CreateJob): Record<string, unknown>;
|
|
173
|
-
/** The API
|
|
174
|
-
*
|
|
259
|
+
/** The API's update body from `UpdateJob`: a command as an argv array is
|
|
260
|
+
* sent as `{ argv }`; the rest as given. */
|
|
261
|
+
export declare function jobUpdateBody(input: UpdateJob): Record<string, unknown>;
|
|
262
|
+
/** The API answers a product switched off where it runs with 501 (503
|
|
263
|
+
* from an older server) `unavailable` and words that do not name it ("This product is not enabled
|
|
175
264
|
* on this deployment."). This names the product, keeps the code, status and
|
|
176
265
|
* request id, and says no retry will change it. */
|
|
177
266
|
export declare function switchedOff(product: string): (error: unknown) => never;
|
|
@@ -199,10 +288,14 @@ export declare function jobs(transport: Transport): {
|
|
|
199
288
|
cursor?: string;
|
|
200
289
|
}, options?: RequestOptions) => Promise<Page<Job>>;
|
|
201
290
|
get: (id: string, options?: RequestOptions) => Promise<Job>;
|
|
202
|
-
/** A job's runs, oldest first: each attempt of each occurrence.
|
|
291
|
+
/** A job's runs, oldest first: each attempt of each occurrence.
|
|
292
|
+
* `{ order: "newest" }`: newest first, so the last run is one call.
|
|
293
|
+
*
|
|
294
|
+
* const [last] = (await runtime.jobs.runs(job.id, { limit: 1, order: "newest" })).data; */
|
|
203
295
|
runs: (jobId: string, query?: {
|
|
204
296
|
limit?: number;
|
|
205
297
|
cursor?: string;
|
|
298
|
+
order?: "oldest" | "newest";
|
|
206
299
|
}, options?: RequestOptions) => Promise<Page<JobRun>>;
|
|
207
300
|
/** One run by its id. */
|
|
208
301
|
run: (runId: string, options?: RequestOptions) => Promise<JobRun>;
|
|
@@ -228,4 +321,11 @@ export declare function jobs(transport: Transport): {
|
|
|
228
321
|
* `{ at }`. The next run is the new schedule's next time; a run going
|
|
229
322
|
* finishes as it began, and a paused job stays paused. */
|
|
230
323
|
reschedule: (id: string, schedule: CreateJob["schedule"], options?: RequestOptions) => Promise<Job>;
|
|
324
|
+
/** Change a job in place: its command, image, compute, secrets, alert,
|
|
325
|
+
* timeout or retry. Its id, history and schedule stay; a run already
|
|
326
|
+
* started finishes as it began, and the next run is the new job.
|
|
327
|
+
*
|
|
328
|
+
* await runtime.jobs.update(job.id, { image: "hub:latest" });
|
|
329
|
+
* await runtime.jobs.update(job.id, { alert: { afterFailures: 3, email: true } }); */
|
|
330
|
+
update: (id: string, changes: UpdateJob, options?: RequestOptions) => Promise<Job>;
|
|
231
331
|
};
|
package/dist/products/jobs.js
CHANGED
|
@@ -24,6 +24,7 @@ export const JOB_LIMITS = {
|
|
|
24
24
|
maxDurationSeconds: 3600,
|
|
25
25
|
maxAttempts: 5,
|
|
26
26
|
maxSecrets: 16,
|
|
27
|
+
maxVolumes: 4,
|
|
27
28
|
};
|
|
28
29
|
function invalid(message, field) {
|
|
29
30
|
return new RuntimeError({
|
|
@@ -87,7 +88,20 @@ export function jobBody(input) {
|
|
|
87
88
|
durationSeconds: given.durationSeconds ??
|
|
88
89
|
Math.min(JOB_LIMITS.maxDurationSeconds, timeoutSeconds + JOB_DEFAULTS.startSeconds),
|
|
89
90
|
...(given.maxCostMicros === undefined ? {} : { maxCostMicros: given.maxCostMicros }),
|
|
91
|
+
...(given.volumes === undefined ? {} : { volumes: given.volumes }),
|
|
90
92
|
};
|
|
93
|
+
// The API checks each volume is the key's, in the job's region; this
|
|
94
|
+
// catches a malformed list before anything is sent.
|
|
95
|
+
if (compute.volumes !== undefined) {
|
|
96
|
+
const volumes = compute.volumes;
|
|
97
|
+
if (!Array.isArray(volumes) ||
|
|
98
|
+
volumes.length > JOB_LIMITS.maxVolumes ||
|
|
99
|
+
volumes.some((v) => typeof v?.volumeId !== "string" ||
|
|
100
|
+
typeof v.path !== "string" ||
|
|
101
|
+
!v.path.startsWith("/") ||
|
|
102
|
+
(v.mode !== undefined && v.mode !== "rw" && v.mode !== "snapshot")))
|
|
103
|
+
throw invalid(`compute.volumes is at most ${JOB_LIMITS.maxVolumes} of { volumeId, path: "/data", mode?: "rw" | "snapshot" }.`, "compute.volumes");
|
|
104
|
+
}
|
|
91
105
|
if (compute.vcpu > JOB_LIMITS.maxVcpu || compute.memoryMiB > JOB_LIMITS.maxMemoryMiB)
|
|
92
106
|
throw invalid(`A run's sandbox is at most ${JOB_LIMITS.maxVcpu} vCPU and ${JOB_LIMITS.maxMemoryMiB / 1024} GiB of memory; asked for ${compute.vcpu} vCPU and ${compute.memoryMiB} MiB.`, compute.vcpu > JOB_LIMITS.maxVcpu ? "compute.vcpu" : "compute.memoryMiB");
|
|
93
107
|
if (compute.diskMiB < JOB_LIMITS.minDiskMiB)
|
|
@@ -108,11 +122,26 @@ export function jobBody(input) {
|
|
|
108
122
|
...(input.maxTotalCostMicros === undefined
|
|
109
123
|
? {}
|
|
110
124
|
: { maxTotalCostMicros: input.maxTotalCostMicros }),
|
|
125
|
+
...(input.image === undefined ? {} : { image: input.image }),
|
|
126
|
+
...(input.alert === undefined ? {} : { alert: input.alert }),
|
|
111
127
|
};
|
|
112
128
|
}
|
|
129
|
+
/** The API's update body from `UpdateJob`: a command as an argv array is
|
|
130
|
+
* sent as `{ argv }`; the rest as given. */
|
|
131
|
+
export function jobUpdateBody(input) {
|
|
132
|
+
const body = {};
|
|
133
|
+
for (const [field, value] of Object.entries(input))
|
|
134
|
+
if (value !== undefined)
|
|
135
|
+
body[field] = value;
|
|
136
|
+
if (Array.isArray(input.command))
|
|
137
|
+
body.command = { argv: input.command };
|
|
138
|
+
if (!Object.keys(body).length)
|
|
139
|
+
throw invalid("update takes at least one of command, image, compute, secrets, alert, timeoutSeconds, retry or maxTotalCostMicros.", "update");
|
|
140
|
+
return body;
|
|
141
|
+
}
|
|
113
142
|
const enc = encodeURIComponent;
|
|
114
|
-
/** The API answers a product switched off where it runs with 503
|
|
115
|
-
* `unavailable` and words that do not name it ("This product is not enabled
|
|
143
|
+
/** The API answers a product switched off where it runs with 501 (503
|
|
144
|
+
* from an older server) `unavailable` and words that do not name it ("This product is not enabled
|
|
116
145
|
* on this deployment."). This names the product, keeps the code, status and
|
|
117
146
|
* request id, and says no retry will change it. */
|
|
118
147
|
export function switchedOff(product) {
|
|
@@ -170,7 +199,10 @@ export function jobs(transport) {
|
|
|
170
199
|
/** Your jobs, oldest first. Await for a page, or `for await` for all. */
|
|
171
200
|
list,
|
|
172
201
|
get: (id, options) => t.json({ method: "GET", path: `/v1/jobs/${enc(id)}`, ...options }),
|
|
173
|
-
/** A job's runs, oldest first: each attempt of each occurrence.
|
|
202
|
+
/** A job's runs, oldest first: each attempt of each occurrence.
|
|
203
|
+
* `{ order: "newest" }`: newest first, so the last run is one call.
|
|
204
|
+
*
|
|
205
|
+
* const [last] = (await runtime.jobs.runs(job.id, { limit: 1, order: "newest" })).data; */
|
|
174
206
|
runs,
|
|
175
207
|
/** One run by its id. */
|
|
176
208
|
run: (runId, options) => t.json({ method: "GET", path: `/v1/job-runs/${enc(runId)}`, ...options }),
|
|
@@ -203,5 +235,17 @@ export function jobs(transport) {
|
|
|
203
235
|
body: { schedule: jobSchedule(schedule) },
|
|
204
236
|
...options,
|
|
205
237
|
}),
|
|
238
|
+
/** Change a job in place: its command, image, compute, secrets, alert,
|
|
239
|
+
* timeout or retry. Its id, history and schedule stay; a run already
|
|
240
|
+
* started finishes as it began, and the next run is the new job.
|
|
241
|
+
*
|
|
242
|
+
* await runtime.jobs.update(job.id, { image: "hub:latest" });
|
|
243
|
+
* await runtime.jobs.update(job.id, { alert: { afterFailures: 3, email: true } }); */
|
|
244
|
+
update: (id, changes, options) => t.json({
|
|
245
|
+
method: "POST",
|
|
246
|
+
path: `/v1/jobs/${enc(id)}:update`,
|
|
247
|
+
body: jobUpdateBody(changes),
|
|
248
|
+
...options,
|
|
249
|
+
}),
|
|
206
250
|
};
|
|
207
251
|
}
|
|
@@ -28,6 +28,19 @@ export type NetworkPolicy = Required<NetworkRules> & {
|
|
|
28
28
|
connectReason: string;
|
|
29
29
|
forbiddenPorts: number[];
|
|
30
30
|
updatedAt: string | null;
|
|
31
|
+
/** The outbound limits the sandbox's host holds it to. Open connections
|
|
32
|
+
* grow with its vCPUs when its organization keeps a top-up; past the rate
|
|
33
|
+
* or the new destinations a connection waits its turn. Meeting one sends
|
|
34
|
+
* the event `sandbox.network.limited`. */
|
|
35
|
+
limits: NetworkLimits;
|
|
36
|
+
};
|
|
37
|
+
export type NetworkLimits = {
|
|
38
|
+
/** Open connections at once. */
|
|
39
|
+
connections: number;
|
|
40
|
+
newConnectionsPerSecond: number;
|
|
41
|
+
/** New connections it may open at once before the rate holds. */
|
|
42
|
+
newConnectionBurst: number;
|
|
43
|
+
destinationsPerMinute: number;
|
|
31
44
|
};
|
|
32
45
|
/** `sbx.network`: turn the sandbox's internet off or on, narrow it to a list,
|
|
33
46
|
* refuse destinations, or open host:port pairs. Changes apply at once, to open
|
|
@@ -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" | "sandbox.files.changed" | "sandbox.out_of_memory" | "sandbox.secret_not_applied" | "snapshot.ready" | "snapshot.failed" | "snapshot.deleted" | "volume.ready" | "volume.failed" | "volume.deleted" | "volume.recovered" | "egress_secret.created" | "egress_secret.updated" | "egress_secret.deleted" | "upstream_proxy.set" | "upstream_proxy.removed" | "credit.low" | "credit.empty";
|
|
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" | "sandbox.network.limited" | "snapshot.ready" | "snapshot.failed" | "snapshot.deleted" | "volume.ready" | "volume.failed" | "volume.deleted" | "volume.recovered" | "egress_secret.created" | "egress_secret.updated" | "egress_secret.deleted" | "upstream_proxy.set" | "upstream_proxy.removed" | "credit.low" | "credit.empty" | "job.run.failed" | "job.recovered";
|
|
39
39
|
/** An event as /v1/events lists it and a webhook delivers it. */
|
|
40
40
|
export type RuntimeEvent = {
|
|
41
41
|
id: string;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type { RequestOptions, Transport } from "../transport.js";
|
|
2
|
+
/** A ceiling a plan raises, as GET /v1/limits and quota_exceeded name it
|
|
3
|
+
* (sandbox.count); a null max is no limit at all. */
|
|
4
|
+
export type PlanLimit = {
|
|
5
|
+
limit: string;
|
|
6
|
+
max: number | null;
|
|
7
|
+
};
|
|
8
|
+
/** Usage a plan includes each month beside its fee, such as Apps' traffic
|
|
9
|
+
* out. */
|
|
10
|
+
export type PlanIncluded = {
|
|
11
|
+
product: string;
|
|
12
|
+
meter: string;
|
|
13
|
+
quantity: number;
|
|
14
|
+
unit: string;
|
|
15
|
+
};
|
|
16
|
+
/** An add-on a plan offers, charged monthly beside its fee. */
|
|
17
|
+
export type PlanAddOn = {
|
|
18
|
+
/** What `addOn` takes. */
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
/** Monthly, beside the plan's fee. */
|
|
22
|
+
feeMicros: string;
|
|
23
|
+
/** What it adds to a limit. */
|
|
24
|
+
limits: {
|
|
25
|
+
limit: string;
|
|
26
|
+
add: number;
|
|
27
|
+
}[];
|
|
28
|
+
/** The feature it turns on, if any. */
|
|
29
|
+
feature: string | null;
|
|
30
|
+
};
|
|
31
|
+
/** One plan: a monthly fee that comes back as plan usage, spent first each
|
|
32
|
+
* month at the same measured prices, plus a bonus for committing. Money is
|
|
33
|
+
* integer microdollars in strings (1,000,000 = $1). */
|
|
34
|
+
export type Plan = {
|
|
35
|
+
/** What choose takes. */
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
/** Plans shown as one card with a switch share it, such as Pro and its
|
|
39
|
+
* larger option. */
|
|
40
|
+
card: string | null;
|
|
41
|
+
/** The monthly fee, before tax; 0 for Free. */
|
|
42
|
+
feeMicros: string;
|
|
43
|
+
/** A year paid at once: ten months' fee for twelve. Null without a yearly
|
|
44
|
+
* price. */
|
|
45
|
+
yearlyFeeMicros: string | null;
|
|
46
|
+
/** Usage given on top of the fee each month. */
|
|
47
|
+
bonusMicros: string;
|
|
48
|
+
/** Days of trial, no card; 0 for none. */
|
|
49
|
+
trialDays: number;
|
|
50
|
+
/** The first month on the plan, and the first after an upgrade to it,
|
|
51
|
+
* holds twice its usage. */
|
|
52
|
+
firstPeriodDouble: boolean;
|
|
53
|
+
support: "docs" | "agent" | "slack" | "dedicated";
|
|
54
|
+
/** card: the fee is charged to the card the plan saves. invoice: a
|
|
55
|
+
* contract, invoiced. */
|
|
56
|
+
collection: "card" | "invoice";
|
|
57
|
+
/** A contract made for your organization alone. */
|
|
58
|
+
contract: boolean;
|
|
59
|
+
/** The catalogue's order: the next plan up is next. */
|
|
60
|
+
position: number;
|
|
61
|
+
included: PlanIncluded[];
|
|
62
|
+
/** Ceilings the plan raises, never lowers. A ceiling is not reserved room. */
|
|
63
|
+
limits: PlanLimit[];
|
|
64
|
+
/** What the plan turns on: sso, roles, audit, support-agent… */
|
|
65
|
+
features: string[];
|
|
66
|
+
addOns: PlanAddOn[];
|
|
67
|
+
};
|
|
68
|
+
/** The plan your organization is on, or null with none (Free). */
|
|
69
|
+
export type PlanNow = {
|
|
70
|
+
planId: string;
|
|
71
|
+
name: string;
|
|
72
|
+
/** incomplete: the first payment is not through yet. trialing: a trial,
|
|
73
|
+
* until trialEndsAt. past_due: a payment failed and is retried. */
|
|
74
|
+
status: "incomplete" | "trialing" | "active" | "past_due" | "canceled";
|
|
75
|
+
interval: "month" | "year";
|
|
76
|
+
periodStart: string | null;
|
|
77
|
+
/** The next fee, or the end of a cancelled plan. */
|
|
78
|
+
periodEnd: string | null;
|
|
79
|
+
/** When a trial ends; null outside one. */
|
|
80
|
+
trialEndsAt: string | null;
|
|
81
|
+
/** True once a cancel takes effect at periodEnd. */
|
|
82
|
+
cancelAtPeriodEnd: boolean;
|
|
83
|
+
/** The plan a downgrade moves to at periodEnd. */
|
|
84
|
+
nextPlanId: string | null;
|
|
85
|
+
startedAt: string;
|
|
86
|
+
/** endsAt: when a removed add-on stops; null while it renews. */
|
|
87
|
+
addOns: {
|
|
88
|
+
id: string;
|
|
89
|
+
quantity: number;
|
|
90
|
+
endsAt: string | null;
|
|
91
|
+
}[];
|
|
92
|
+
/** An owner said yes to moving up a plan when a limit refuses. */
|
|
93
|
+
autoUpgrade: boolean;
|
|
94
|
+
/** This period's plan usage, spent before any credit; it ends with the
|
|
95
|
+
* period. */
|
|
96
|
+
planUsage: {
|
|
97
|
+
grantedMicros: string;
|
|
98
|
+
leftMicros: string;
|
|
99
|
+
expiresAt: string;
|
|
100
|
+
} | null;
|
|
101
|
+
};
|
|
102
|
+
export type Plans = {
|
|
103
|
+
current: PlanNow | null;
|
|
104
|
+
plans: Plan[];
|
|
105
|
+
};
|
|
106
|
+
/** What a change answers: a link where a person starts a first plan or a
|
|
107
|
+
* trial in the browser, or the plan as changed. */
|
|
108
|
+
export type PlanChange = {
|
|
109
|
+
checkoutUrl: string | null;
|
|
110
|
+
current: PlanNow | null;
|
|
111
|
+
};
|
|
112
|
+
/** `runtime.plans`: monthly plans whose fee is prepaid usage. You still pay
|
|
113
|
+
* only for what runs, at the same prices; the fee comes back as usage. */
|
|
114
|
+
export declare function plans(t: Transport): {
|
|
115
|
+
list: (options?: RequestOptions) => Promise<Plans>;
|
|
116
|
+
/** Start a plan, or move to another; interval year pays ten months for
|
|
117
|
+
* twelve. */
|
|
118
|
+
choose: (plan: string, options?: RequestOptions & {
|
|
119
|
+
interval?: "month" | "year";
|
|
120
|
+
}) => Promise<PlanChange>;
|
|
121
|
+
/** End the plan at periodEnd. */
|
|
122
|
+
cancel: (options?: RequestOptions) => Promise<PlanChange>;
|
|
123
|
+
/** Keep a plan you cancelled, before periodEnd. */
|
|
124
|
+
resume: (options?: RequestOptions) => Promise<PlanChange>;
|
|
125
|
+
/** Add an add-on to the plan, charged now prorated. */
|
|
126
|
+
addOn: (addOn: string, options?: RequestOptions) => Promise<PlanChange>;
|
|
127
|
+
/** Remove an add-on: its charge stops now, and it holds to periodEnd. */
|
|
128
|
+
removeAddOn: (addOn: string, options?: RequestOptions) => Promise<PlanChange>;
|
|
129
|
+
/** Move up a plan by itself when a limit refuses, or not. Owners only. */
|
|
130
|
+
autoUpgrade: (on: boolean, options?: RequestOptions) => Promise<PlanChange>;
|
|
131
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** `runtime.plans`: monthly plans whose fee is prepaid usage. You still pay
|
|
2
|
+
* only for what runs, at the same prices; the fee comes back as usage. */
|
|
3
|
+
export function plans(t) {
|
|
4
|
+
const change = (method, path, body) => (options) => t.json({ method, path, ...(body ? { body } : {}), ...options });
|
|
5
|
+
return {
|
|
6
|
+
list: (options) => t.json({ method: "GET", path: "/v1/plans", ...options }),
|
|
7
|
+
/** Start a plan, or move to another; interval year pays ten months for
|
|
8
|
+
* twelve. */
|
|
9
|
+
choose: (plan, options) => {
|
|
10
|
+
const { interval, ...rest } = options ?? {};
|
|
11
|
+
return change("POST", "/v1/plans/choose", { plan, ...(interval ? { interval } : {}) })(rest);
|
|
12
|
+
},
|
|
13
|
+
/** End the plan at periodEnd. */
|
|
14
|
+
cancel: (options) => change("POST", "/v1/plans/cancel", {})(options),
|
|
15
|
+
/** Keep a plan you cancelled, before periodEnd. */
|
|
16
|
+
resume: (options) => change("POST", "/v1/plans/resume", {})(options),
|
|
17
|
+
/** Add an add-on to the plan, charged now prorated. */
|
|
18
|
+
addOn: (addOn, options) => change("POST", "/v1/plans/add-ons", { addOn })(options),
|
|
19
|
+
/** Remove an add-on: its charge stops now, and it holds to periodEnd. */
|
|
20
|
+
removeAddOn: (addOn, options) => change("DELETE", `/v1/plans/add-ons/${encodeURIComponent(addOn)}`, undefined)(options),
|
|
21
|
+
/** Move up a plan by itself when a limit refuses, or not. Owners only. */
|
|
22
|
+
autoUpgrade: (on, options) => change("PUT", "/v1/plans/auto-upgrade", { on })(options),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { RequestOptions, Transport } from "../transport.js";
|
|
2
|
+
export type BookRoom = {
|
|
3
|
+
/** How many sandboxes of this size to hold room for: 1 to 10000. */
|
|
4
|
+
sandboxes: number;
|
|
5
|
+
/** When the window starts: a Date or an ISO 8601 time, within 14 days. */
|
|
6
|
+
startsAt: Date | string;
|
|
7
|
+
/** When it ends: at most 24 hours after it starts. */
|
|
8
|
+
endsAt: Date | string;
|
|
9
|
+
/** Size of each sandbox. Default 2 vCPU, 4096 MiB memory, 4096 MiB disk. */
|
|
10
|
+
vcpu?: number;
|
|
11
|
+
memoryMiB?: number;
|
|
12
|
+
diskMiB?: number;
|
|
13
|
+
/** Default: the account's default region. */
|
|
14
|
+
region?: string;
|
|
15
|
+
};
|
|
16
|
+
export type KeepRoom = {
|
|
17
|
+
/** How many sandboxes to hold room for: 1 to 10000. Keep a few more than
|
|
18
|
+
* the pool runs, for deletes the servers are still finishing. */
|
|
19
|
+
sandboxes: number;
|
|
20
|
+
/** The snapshots its sandboxes fork from (at most 20, one size): the room is
|
|
21
|
+
* held on the servers holding them, at their size. */
|
|
22
|
+
snapshots?: string[];
|
|
23
|
+
/** Size of each sandbox when no snapshots are named. Default 2 vCPU, 4096
|
|
24
|
+
* MiB memory, 4096 MiB disk. */
|
|
25
|
+
vcpu?: number;
|
|
26
|
+
memoryMiB?: number;
|
|
27
|
+
diskMiB?: number;
|
|
28
|
+
/** Hold it for this key's sandboxes alone. Default: the whole account's. */
|
|
29
|
+
forKey?: boolean;
|
|
30
|
+
/** Default: the account's default region. */
|
|
31
|
+
region?: string;
|
|
32
|
+
};
|
|
33
|
+
/** A change to standing room: how many it holds, its snapshots, or both. */
|
|
34
|
+
export type ChangeRoom = {
|
|
35
|
+
sandboxes?: number;
|
|
36
|
+
snapshots?: string[];
|
|
37
|
+
};
|
|
38
|
+
export type RoomBooking = {
|
|
39
|
+
id: string;
|
|
40
|
+
/** confirmed: the room is held. declined: nothing is held; `reason`,
|
|
41
|
+
* `message`, `largestSandboxes` and `nearestWindow` say why and what would
|
|
42
|
+
* fit. cancelled: given back. */
|
|
43
|
+
status: "confirmed" | "declined" | "cancelled";
|
|
44
|
+
/** Standing room: held until cancelled, with no window. */
|
|
45
|
+
standing: boolean;
|
|
46
|
+
/** Standing room's snapshots; empty: any server in the region. */
|
|
47
|
+
snapshots: string[];
|
|
48
|
+
/** Held for the key that booked it alone. */
|
|
49
|
+
forKey: boolean;
|
|
50
|
+
reason: "room" | "share" | "usage" | "credit" | null;
|
|
51
|
+
message: string;
|
|
52
|
+
region: string;
|
|
53
|
+
sandboxes: number;
|
|
54
|
+
vcpu: number;
|
|
55
|
+
memoryMiB: number;
|
|
56
|
+
diskMiB: number;
|
|
57
|
+
startsAt: string;
|
|
58
|
+
/** Null for standing room. */
|
|
59
|
+
endsAt: string | null;
|
|
60
|
+
/** endsAt while confirmed; null for standing room. */
|
|
61
|
+
heldUntil: string | null;
|
|
62
|
+
phase: "upcoming" | "active" | "ended" | null;
|
|
63
|
+
/** The most sandboxes of this size that fit in the window. */
|
|
64
|
+
largestSandboxes: number;
|
|
65
|
+
/** The nearest window the whole booking fits in, or null. */
|
|
66
|
+
nearestWindow: {
|
|
67
|
+
startsAt: string;
|
|
68
|
+
endsAt: string;
|
|
69
|
+
} | null;
|
|
70
|
+
/** The most the booking can cost: every booked sandbox running the whole window (any mix of running and unused costs less). */
|
|
71
|
+
estimateMicros: string;
|
|
72
|
+
/** What booked room no sandbox of the account uses costs, in microdollars per GiB-hour of the booked sandboxes' memory, as quoted when booked ("0" before it had a price). */
|
|
73
|
+
unusedRateMicros: string;
|
|
74
|
+
/** The most the booking costs if none of its sandboxes run (nothing if cancelled at least an hour before it starts). */
|
|
75
|
+
unusedMaxMicros: string | null;
|
|
76
|
+
/** The most its unused room costs an hour. */
|
|
77
|
+
unusedPerHourMicros: string;
|
|
78
|
+
/** What its unused room has been charged so far. */
|
|
79
|
+
unusedChargedMicros: string;
|
|
80
|
+
/** Sandboxes in use now, up to what it holds; for standing room, read live. */
|
|
81
|
+
inUse: number;
|
|
82
|
+
peakInUse: number;
|
|
83
|
+
releasedPercent: number;
|
|
84
|
+
createdAt: string;
|
|
85
|
+
cancelledAt: string | null;
|
|
86
|
+
};
|
|
87
|
+
export type RoomBookingPage = {
|
|
88
|
+
items: RoomBooking[];
|
|
89
|
+
nextCursor: string | null;
|
|
90
|
+
};
|
|
91
|
+
export declare function reservations(t: Transport): {
|
|
92
|
+
/** Book room. Check `status`: a decline is a 200, not an error. */
|
|
93
|
+
create: (input: BookRoom, options?: RequestOptions) => Promise<RoomBooking>;
|
|
94
|
+
/** Keep standing room until you cancel it. Check `status`: a decline is a
|
|
95
|
+
* 200, not an error. */
|
|
96
|
+
keep: (input: KeepRoom, options?: RequestOptions) => Promise<RoomBooking>;
|
|
97
|
+
/** Change standing room in place. It moves or grows only when all of it
|
|
98
|
+
* fits now; otherwise it throws `no_capacity` and nothing changes. */
|
|
99
|
+
update: (id: string, change: ChangeRoom, options?: RequestOptions) => Promise<RoomBooking>;
|
|
100
|
+
/** Bookings, newest first; pass `nextCursor` as `cursor` for the next page. */
|
|
101
|
+
list: (query?: {
|
|
102
|
+
limit?: number;
|
|
103
|
+
cursor?: string;
|
|
104
|
+
}, options?: RequestOptions) => Promise<RoomBookingPage>;
|
|
105
|
+
get: (id: string, options?: RequestOptions) => Promise<RoomBooking>;
|
|
106
|
+
/** Give the room back. The booking comes back with status "cancelled". */
|
|
107
|
+
cancel: (id: string, options?: RequestOptions) => Promise<RoomBooking>;
|
|
108
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const iso = (time) => (time instanceof Date ? time.toISOString() : time);
|
|
2
|
+
export function reservations(t) {
|
|
3
|
+
return {
|
|
4
|
+
/** Book room. Check `status`: a decline is a 200, not an error. */
|
|
5
|
+
create: (input, options) => t.json({
|
|
6
|
+
method: "POST",
|
|
7
|
+
path: "/v1/reservations",
|
|
8
|
+
body: { ...input, startsAt: iso(input.startsAt), endsAt: iso(input.endsAt) },
|
|
9
|
+
...options,
|
|
10
|
+
}),
|
|
11
|
+
/** Keep standing room until you cancel it. Check `status`: a decline is a
|
|
12
|
+
* 200, not an error. */
|
|
13
|
+
keep: (input, options) => t.json({
|
|
14
|
+
method: "POST",
|
|
15
|
+
path: "/v1/reservations",
|
|
16
|
+
body: { ...input, standing: true },
|
|
17
|
+
...options,
|
|
18
|
+
}),
|
|
19
|
+
/** Change standing room in place. It moves or grows only when all of it
|
|
20
|
+
* fits now; otherwise it throws `no_capacity` and nothing changes. */
|
|
21
|
+
update: (id, change, options) => t.json({
|
|
22
|
+
method: "POST",
|
|
23
|
+
path: `/v1/reservations/${encodeURIComponent(id)}:update`,
|
|
24
|
+
body: change,
|
|
25
|
+
...options,
|
|
26
|
+
}),
|
|
27
|
+
/** Bookings, newest first; pass `nextCursor` as `cursor` for the next page. */
|
|
28
|
+
list: (query = {}, options) => t.json({ method: "GET", path: "/v1/reservations", query, ...options }),
|
|
29
|
+
get: (id, options) => t.json({
|
|
30
|
+
method: "GET",
|
|
31
|
+
path: `/v1/reservations/${encodeURIComponent(id)}`,
|
|
32
|
+
...options,
|
|
33
|
+
}),
|
|
34
|
+
/** Give the room back. The booking comes back with status "cancelled". */
|
|
35
|
+
cancel: (id, options) => t.json({
|
|
36
|
+
method: "DELETE",
|
|
37
|
+
path: `/v1/reservations/${encodeURIComponent(id)}`,
|
|
38
|
+
...options,
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -3,7 +3,8 @@ import type { RequestOptions, Transport } from "../transport.js";
|
|
|
3
3
|
/** The five verbs every resource product shares (CLOUD.md section 4, "One
|
|
4
4
|
* shape for every interface"; packages/cloud/src/api/resource-product.ts),
|
|
5
5
|
* and following one to a state. A product builds its client on these and
|
|
6
|
-
* adds only its own verbs.
|
|
6
|
+
* adds only its own verbs. Plain request builders over Transport: nothing
|
|
7
|
+
* runs at import, no dependency beyond this package. */
|
|
7
8
|
export type ResourceRecord = {
|
|
8
9
|
id: string;
|
|
9
10
|
state: string;
|