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.
Files changed (76) hide show
  1. package/COMPATIBILITY.md +64 -3
  2. package/E2B.md +1 -1
  3. package/README.md +36 -2
  4. package/README.src.md +35 -1
  5. package/compatibility-lock.json +3 -3
  6. package/dist/agents/browser.d.ts +12 -0
  7. package/dist/agents/browser.js +12 -0
  8. package/dist/agents/index.d.ts +7 -7
  9. package/dist/agents/index.js +7 -8
  10. package/dist/agents-cli.d.ts +1 -1
  11. package/dist/agents-cli.js +250 -3
  12. package/dist/agents-deploy.d.ts +186 -0
  13. package/dist/agents-deploy.js +752 -0
  14. package/dist/agents-file.d.ts +19 -0
  15. package/dist/agents-file.js +135 -0
  16. package/dist/apps/index.d.ts +10 -0
  17. package/dist/apps/index.js +11 -0
  18. package/dist/apps-cli.d.ts +3 -1
  19. package/dist/apps-cli.js +285 -38
  20. package/dist/blaxel/errors.js +2 -1
  21. package/dist/ci/index.d.ts +10 -0
  22. package/dist/ci/index.js +11 -0
  23. package/dist/ci-cli.d.ts +10 -0
  24. package/dist/ci-cli.js +343 -0
  25. package/dist/cli.d.ts +18 -7
  26. package/dist/cli.js +775 -85
  27. package/dist/daytona/errors.js +2 -1
  28. package/dist/e2b/errors.js +2 -1
  29. package/dist/e2b/filesystem.d.ts +1 -0
  30. package/dist/e2b/filesystem.js +1 -1
  31. package/dist/e2b/sandbox.d.ts +11 -2
  32. package/dist/e2b/sandbox.js +22 -6
  33. package/dist/errors.d.ts +11 -4
  34. package/dist/errors.js +27 -4
  35. package/dist/fly/index.d.ts +102 -0
  36. package/dist/fly/index.js +930 -0
  37. package/dist/index.d.ts +7 -3
  38. package/dist/machine.d.ts +10 -6
  39. package/dist/machine.js +14 -6
  40. package/dist/modal/index.d.ts +34 -0
  41. package/dist/modal/index.js +128 -22
  42. package/dist/products/agents.d.ts +101 -3
  43. package/dist/products/agents.js +49 -0
  44. package/dist/products/apps.d.ts +206 -10
  45. package/dist/products/apps.js +172 -1
  46. package/dist/products/ci.d.ts +332 -0
  47. package/dist/products/ci.js +101 -0
  48. package/dist/products/index.d.ts +8 -0
  49. package/dist/products/index.js +15 -0
  50. package/dist/products/jobs.d.ts +105 -5
  51. package/dist/products/jobs.js +47 -3
  52. package/dist/products/network.d.ts +13 -0
  53. package/dist/products/observability.d.ts +1 -1
  54. package/dist/products/plans.d.ts +131 -0
  55. package/dist/products/plans.js +24 -0
  56. package/dist/products/reservations.d.ts +108 -0
  57. package/dist/products/reservations.js +41 -0
  58. package/dist/products/resources.d.ts +2 -1
  59. package/dist/products/secrets.d.ts +90 -6
  60. package/dist/products/secrets.js +8 -2
  61. package/dist/proxy.d.ts +3 -3
  62. package/dist/proxy.js +20 -0
  63. package/dist/sandbox.d.ts +29 -1
  64. package/dist/sandbox.js +56 -3
  65. package/dist/snapshots.d.ts +1 -1
  66. package/dist/switched-off.d.ts +5 -0
  67. package/dist/switched-off.js +8 -0
  68. package/dist/tar.d.ts +1 -1
  69. package/dist/tar.js +19 -1
  70. package/dist/transport.d.ts +1 -1
  71. package/dist/transport.js +48 -9
  72. package/dist/types.d.ts +35 -4
  73. package/dist/vercel/errors.d.ts +1 -1
  74. package/dist/vercel/errors.js +2 -1
  75. package/dist/vercel/snapshot.js +4 -2
  76. package/package.json +23 -6
@@ -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) or `permission` (the key that made the job lost it). */
62
- blockedReason: "permission" | "capacity" | "credits" | "cost_cap" | null;
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 answers a product switched off where it runs with 503
174
- * `unavailable` and words that do not name it ("This product is not enabled
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
  };
@@ -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;