agental 0.1.0 → 0.2.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/dist/client.js DELETED
@@ -1,451 +0,0 @@
1
- import { Http } from "./http.js";
2
- import { CREATE_TIMEOUT_MS, Email, iso, made, makeSandbox, Sandbox } from "./sandbox.js";
3
- import { Templates } from "./template.js";
4
- class Sandboxes {
5
- http;
6
- constructor(http) {
7
- this.http = http;
8
- }
9
- /**
10
- * Makes a sandbox and waits until it is running. If the create fails part way or its
11
- * answer is lost, it is sent again with the same key, which gives the same machine back
12
- * and never a second one. What it paid in burst fees is in the sandbox's burstFeeMicros.
13
- */
14
- async create(options = {}) {
15
- const body = {
16
- name: options.name ?? made("sbx"),
17
- ...(options.template ? { templateId: typeof options.template === "string" ? options.template : options.template.id } : {}),
18
- ...(options.size ? { size: options.size } : {}),
19
- ...(options.region === undefined ? {} : Array.isArray(options.region) ? { regions: options.region } : { region: options.region }),
20
- ...(options.snapshotId !== undefined ? { snapshotId: options.snapshotId } : {}),
21
- ...(options.ttlSeconds !== undefined ? { ttlSeconds: options.ttlSeconds } : {}),
22
- ...(options.network ? { network: options.network } : {}),
23
- ...(options.sshKeys !== undefined ? { sshKeys: options.sshKeys } : {}),
24
- ...(options.tags !== undefined ? { tags: options.tags } : {}),
25
- ...(options.metadata !== undefined ? { metadata: options.metadata } : {}),
26
- };
27
- const { info, burstFeeMicros } = await makeSandbox(this.http, "/v1/sandboxes", body, options.idempotencyKey ?? made("sdk"), options.timeoutMs ?? CREATE_TIMEOUT_MS, options);
28
- return new Sandbox(this.http, info, burstFeeMicros);
29
- }
30
- /** One of your sandboxes, by its id. */
31
- async get(id) {
32
- const { body } = await this.http.json({ method: "GET", path: `/v1/sandboxes/${encodeURIComponent(id)}`, replay: true });
33
- return new Sandbox(this.http, body);
34
- }
35
- /**
36
- * Your sandboxes, stopped ones included. Given a tag, or several, only those with every
37
- * one of them; given metadata, only those with each key at that value. A template's
38
- * tags and metadata count.
39
- */
40
- async list(filter = {}) {
41
- const query = {};
42
- if (filter.tag !== undefined) {
43
- query["tag"] = filter.tag;
44
- }
45
- for (const [key, value] of Object.entries(filter.metadata ?? {})) {
46
- query[`metadata[${key}]`] = value;
47
- }
48
- const { body } = await this.http.json({ method: "GET", path: "/v1/sandboxes", query, replay: true });
49
- return body.sandboxes.map((info) => new Sandbox(this.http, info));
50
- }
51
- /**
52
- * The mail of one sandbox, by the sandbox's id, without reading the sandbox. It asks
53
- * nothing by itself. It is the way in for a key made with only email.read and
54
- * email.send on this sandbox, which may read and send its mail and is refused
55
- * everything else, get(id) included.
56
- */
57
- email(id) {
58
- return new Email(this.http, `/v1/sandboxes/${encodeURIComponent(id)}/email`);
59
- }
60
- }
61
- class Snapshots {
62
- http;
63
- constructor(http) {
64
- this.http = http;
65
- }
66
- /** Every snapshot you have, those of sandboxes since deleted included. */
67
- async list() {
68
- return (await this.http.json({ method: "GET", path: "/v1/snapshots", replay: true })).body.snapshots;
69
- }
70
- async get(id) {
71
- return (await this.http.json({ method: "GET", path: `/v1/snapshots/${encodeURIComponent(id)}`, replay: true })).body;
72
- }
73
- async delete(id) {
74
- await this.http.send({ method: "DELETE", path: `/v1/snapshots/${encodeURIComponent(id)}` });
75
- }
76
- }
77
- /**
78
- * Your API keys. A key may do what it was made to do and nothing else, and a key used to
79
- * make one makes only a weaker one. Using any of these takes a key with key.manage.
80
- */
81
- class ApiKeys {
82
- http;
83
- constructor(http) {
84
- this.http = http;
85
- }
86
- /** Every key of the account, oldest first. Their secrets are never given. */
87
- async list() {
88
- return (await this.http.json({ method: "GET", path: "/v1/api-keys", replay: true })).body.apiKeys;
89
- }
90
- async get(id) {
91
- return (await this.http.json({ method: "GET", path: this.path(id), replay: true })).body;
92
- }
93
- /**
94
- * Makes a key with a preset, or with the actions named, and limited by the rest: to some
95
- * sandboxes and templates, until expiresAt, and to the addresses in allowFrom. The
96
- * answer holds secret, the one time it is given. It is sent once, so a lost answer is
97
- * not sent again.
98
- */
99
- async create(key) {
100
- // What is left out is not sent: JSON has no undefined.
101
- const body = { ...key, expiresAt: iso(key.expiresAt) };
102
- return (await this.http.json({ method: "POST", path: "/v1/api-keys", body })).body;
103
- }
104
- /**
105
- * Replaces the addresses and ranges a key may be used from, from its next request. It is
106
- * the one thing about a key that changes after it is made. An empty list is anywhere.
107
- */
108
- async setAllowFrom(id, allowFrom) {
109
- return (await this.http.json({ method: "PUT", path: `${this.path(id)}/allow-from`, body: { allowFrom }, replay: true })).body;
110
- }
111
- /** Deletes a key. Whatever holds it is refused from its next request, and the sandboxes it made stay the account's. */
112
- async delete(id) {
113
- await this.http.send({ method: "DELETE", path: this.path(id) });
114
- }
115
- /** How long the sandboxes a key made ran, and what that comes to at the list price. Without since, everything they ever ran. */
116
- async usage(id, window = {}) {
117
- const query = { since: iso(window.since), until: iso(window.until) };
118
- return (await this.http.json({ method: "GET", path: `${this.path(id)}/usage`, query, replay: true })).body;
119
- }
120
- path(id) {
121
- return `/v1/api-keys/${encodeURIComponent(id)}`;
122
- }
123
- }
124
- /**
125
- * The organizations the key's person is in, and the team the key acts in. A key acts in the
126
- * organization it was made in, for good: its person's own or a team. What a key may do of a
127
- * team's is held by its actions, members.read and members.admin (or account.read and
128
- * account.admin), and by its person's role in the team.
129
- */
130
- class Organizations {
131
- http;
132
- constructor(http) {
133
- this.http = http;
134
- }
135
- /** Every organization the key's person is in, with their role in each, their own first. */
136
- async list() {
137
- return (await this.http.json({ method: "GET", path: "/v1/organizations", replay: true })).body.organizations;
138
- }
139
- /** The one the key acts in. */
140
- async current() {
141
- const [list, me] = await Promise.all([this.list(), this.http.json({ method: "GET", path: "/v1/me", replay: true })]);
142
- const found = list.find((organization) => organization.id === me.body.activeOrganizationId);
143
- if (!found) {
144
- throw new Error(`The key acts in ${me.body.activeOrganizationId}, which is not among its person's organizations.`);
145
- }
146
- return found;
147
- }
148
- /**
149
- * Makes a team, with the key's person as its owner. The key goes on acting where it was made:
150
- * a key for the team is made in the console, or with the CLI's agental org use.
151
- */
152
- async createTeam(name) {
153
- return (await this.http.json({ method: "POST", path: "/v1/organizations", body: { kind: "team", name } })).body.organization;
154
- }
155
- /** Renames a team. Only an owner does. */
156
- async rename(id, name) {
157
- return (await this.http.json({ method: "PATCH", path: this.path(id), body: { name }, replay: true })).body;
158
- }
159
- /** A team's members, the earliest first. Every member reads them. */
160
- async members(id) {
161
- return (await this.http.json({ method: "GET", path: `${this.path(id)}/members`, replay: true })).body.members;
162
- }
163
- /** Changes a member's role: an owner any, an admin up to admin and never an owner's. */
164
- async setRole(id, userId, role) {
165
- const path = `${this.path(id)}/members/${encodeURIComponent(userId)}`;
166
- return (await this.http.json({ method: "PATCH", path, body: { role }, replay: true })).body.role;
167
- }
168
- /**
169
- * Removes a member, or the key's person themself. The keys they made in the team go on
170
- * working, as a member's, unless revokeKeys revokes them in the same request.
171
- */
172
- async removeMember(id, userId, options = {}) {
173
- const path = `${this.path(id)}/members/${encodeURIComponent(userId)}`;
174
- const query = options.revokeKeys ? { revokeKeys: "true" } : {};
175
- return (await this.http.json({ method: "DELETE", path, query })).body;
176
- }
177
- /** The invites of the team the key acts in, for its owners and admins. */
178
- async invites() {
179
- return (await this.http.json({ method: "GET", path: "/v1/invites", replay: true })).body.invites;
180
- }
181
- /** Invites an email address to the team the key acts in, as a member or an admin. The team's plan has to allow members. */
182
- async invite(email, options = {}) {
183
- return (await this.http.json({ method: "POST", path: "/v1/invites", body: { email, role: options.role ?? "member" } })).body;
184
- }
185
- /** Revokes an open invite: its link answers 410 from then on. */
186
- async revokeInvite(inviteId) {
187
- await this.http.send({ method: "DELETE", path: `/v1/invites/${encodeURIComponent(inviteId)}` });
188
- }
189
- path(id) {
190
- return `/v1/organizations/${encodeURIComponent(id)}`;
191
- }
192
- }
193
- /**
194
- * The agental API.
195
- *
196
- * ```ts
197
- * const agental = new Agental(); // reads AGENTAL_API_KEY
198
- * const sandbox = await agental.sandboxes.create();
199
- * const { stdout } = await sandbox.exec("uname -a");
200
- * await sandbox.delete();
201
- * ```
202
- */
203
- export class Agental {
204
- sandboxes;
205
- snapshots;
206
- /** What sandboxes are made as and held to: a start, the variables and files every sandbox on one gets, and what it may reach. */
207
- templates;
208
- /** The account's API keys: what each may do, which sandboxes and templates it reaches, until when, and from where. */
209
- apiKeys;
210
- /** The organizations the key's person is in, and the members and invites of a team. */
211
- organizations;
212
- http;
213
- constructor(options = {}) {
214
- this.http = new Http(options);
215
- this.sandboxes = new Sandboxes(this.http);
216
- this.snapshots = new Snapshots(this.http);
217
- this.templates = new Templates(this.http);
218
- this.apiKeys = new ApiKeys(this.http);
219
- this.organizations = new Organizations(this.http);
220
- }
221
- /** The regions sandboxes can be made in now, the default first, with the sizes each has room for. */
222
- async regions() {
223
- return (await this.http.json({ method: "GET", path: "/v1/regions", replay: true })).body.regions;
224
- }
225
- /** Who the key belongs to: the account's id, name and address, its role, and whether it is closed. */
226
- async me() {
227
- return (await this.http.json({ method: "GET", path: "/v1/me", replay: true })).body;
228
- }
229
- /** Every port given an address, across the account's sandboxes that the key reaches. A sandbox's own are in its routes(). */
230
- async hostRoutes() {
231
- return (await this.http.json({ method: "GET", path: "/v1/host-routes", replay: true })).body.routes;
232
- }
233
- /** Hides a port's address: it answers not found from then on. There is no undoing it; give the port an address again instead. */
234
- async hideHostRoute(routeId) {
235
- return (await this.http.json({ method: "POST", path: `/v1/host-routes/${encodeURIComponent(routeId)}/hide`, replay: true })).body;
236
- }
237
- /** The sizes on offer, and how much room there is. */
238
- async limits() {
239
- return (await this.http.json({ method: "GET", path: "/v1/limits", replay: true })).body;
240
- }
241
- /** What applies to every account here: how many sandboxes, how long one runs, whether ports get public addresses. */
242
- async policy() {
243
- return (await this.http.json({ method: "GET", path: "/v1/policy", replay: true })).body;
244
- }
245
- /**
246
- * What is sold: the list price an hour of each size, the monthly plans, the top-ups offered
247
- * with what each adds, the range a top-up may be and its bonus, and the free month. It needs
248
- * no key.
249
- */
250
- async prices() {
251
- return (await this.http.json({ method: "GET", path: "/v1/billing/plans", replay: true })).body;
252
- }
253
- /**
254
- * Where the account stands: its plan, in its free month or not, what it has used this month at list price,
255
- * what is left of its top-ups, and whether it may run a sandbox. Amounts are millionths of a US dollar.
256
- */
257
- async billing() {
258
- return (await this.http.json({ method: "GET", path: "/v1/billing", replay: true })).body;
259
- }
260
- /**
261
- * Starts a purchase and gives the address of the payment page, for a person to open: a
262
- * plan, or a top-up of credits that do not expire, any whole number of US dollars
263
- * from 15 to 100,000. From $200 a top-up adds a bonus, 2% there and growing to 25% at
264
- * $10,000: $500 adds $537. prices() says what each adds.
265
- * An account that already has a plan and asks for another is moved to it at once: url is
266
- * null and changed is true. Nothing is charged until the person pays.
267
- */
268
- async checkout(purchase) {
269
- return (await this.http.json({ method: "POST", path: "/v1/billing/checkout", body: purchase })).body;
270
- }
271
- /**
272
- * Sets the auto-reload, or turns it off with null: when the month's credits and the top-ups run
273
- * out, the card saved at the last purchase is charged for a top-up of this many US dollars, with
274
- * tax, and its credits are added at once, before any sandbox is stopped. At most three times a
275
- * day, and not again for a day after a card that would not pay. It needs a plan or a top-up
276
- * bought first, which saves the card: billing().canAutoReload says whether it can be set.
277
- */
278
- async setAutoReload(dollars) {
279
- return (await this.http.json({ method: "PUT", path: "/v1/billing/auto-reload", body: { dollars } })).body;
280
- }
281
- /** The account's mail: the handle every address of its sandboxes carries, what its plan allows, and what it has had of that today. */
282
- async email() {
283
- return (await this.http.json({ method: "GET", path: "/v1/email", replay: true })).body;
284
- }
285
- /**
286
- * Where your account stands against its plan: how many small sandboxes it runs and may run
287
- * at once (runningUnits; a tiny counts half, a medium 2, a large 4), what its burst meter
288
- * reads against the free burst, what it has spent on burst fees this month against its
289
- * budget, and what one sandbox of each size would cost to start now. With a size, and a
290
- * count, quote says what starting that many now would cost.
291
- *
292
- * Where `enforced` is true, a create, fork or start past the running count throws an
293
- * `ApiError` 429 `running_limit_reached`; one faster than the free burst costs a burst fee,
294
- * and is refused with `burst_budget_reached` past the monthly budget or
295
- * `burst_in_free_month` in the free month. Amounts are millionths of a US dollar.
296
- */
297
- async burst(quote) {
298
- const query = { size: quote?.size, count: quote?.count?.toString() };
299
- return (await this.http.json({ method: "GET", path: "/v1/burst", query, replay: true })).body;
300
- }
301
- /**
302
- * Sets the most the account spends on burst fees in a month, in millionths of a US dollar:
303
- * 0 refuses every start that would cost one. null gives it the default again,
304
- * defaultBudgetMicros. It answers with the account's burst as it stands now.
305
- */
306
- async setBurstBudget(budgetMicros) {
307
- return (await this.http.json({ method: "PUT", path: "/v1/burst/budget", body: { budgetMicros }, replay: true })).body;
308
- }
309
- /**
310
- * Running time and what it comes to at the list price, by sandbox, by key, by day and by hour, and the mail of the same
311
- * window. With apiKeyId, one key or several, only the sandboxes those keys made, "console" standing for those made in
312
- * the console: the keys stay the whole account's.
313
- */
314
- async usage(options = {}) {
315
- const keys = options.apiKeyId;
316
- const query = { since: iso(options.since), until: iso(options.until), apiKeyId: Array.isArray(keys) ? keys.join(",") : keys };
317
- return (await this.http.json({ method: "GET", path: "/v1/usage", query, replay: true })).body;
318
- }
319
- /**
320
- * What each of your sandboxes read at one moment: now, unless at says another. A sandbox
321
- * that was stopped then has a null reading, and so has one on a server that did not
322
- * answer, which complete says. Only where policy() says metrics.
323
- */
324
- async metrics(moment = {}) {
325
- return (await this.http.json({ method: "GET", path: "/v1/metrics", query: { at: iso(moment.at) }, replay: true })).body;
326
- }
327
- /**
328
- * How many of your sandboxes were running at each step between two moments. Without
329
- * since, the last 24 hours. It is counted from the record of what ran, so it answers
330
- * wherever sandboxes run, and a sandbox deleted since is still counted.
331
- */
332
- async runningOverTime(window = {}) {
333
- const query = { since: iso(window.since), until: iso(window.until), stepSeconds: window.stepSeconds?.toString() };
334
- return (await this.http.json({ method: "GET", path: "/v1/metrics/running", query, replay: true })).body;
335
- }
336
- /**
337
- * The OTLP/HTTP collector your sandboxes' metrics and lifecycle events are sent to, with
338
- * the names of its headers and how the last export went. Null when none is set. Only
339
- * where policy() says telemetry.
340
- */
341
- async getTelemetry() {
342
- return (await this.http.json({ method: "GET", path: "/v1/telemetry", replay: true })).body.telemetry;
343
- }
344
- /**
345
- * Sets the collector your sandboxes' metrics and lifecycle events are sent to, in place of
346
- * the one set before. endpoint is its base address, https on port 443 or 4318. headers are
347
- * sent with each export, such as the collector's API key, and their values are never
348
- * shown again. Nothing is sent now: testTelemetry() does that. From the next whole minute
349
- * it is sent the metrics every minute, and each event as it happens.
350
- */
351
- async setTelemetry(collector) {
352
- const body = { endpoint: collector.endpoint, ...(collector.headers ? { headers: collector.headers } : {}) };
353
- return (await this.http.json({ method: "PUT", path: "/v1/telemetry", body, replay: true })).body.telemetry;
354
- }
355
- /**
356
- * Sends your collector one empty export, with its headers, and says what it answered. ok
357
- * is false when it refused, did not answer in 10 seconds, or is at an address that is not
358
- * sent to. Nothing else is changed.
359
- */
360
- async testTelemetry() {
361
- return (await this.http.json({ method: "POST", path: "/v1/telemetry/test" })).body;
362
- }
363
- /** Removes your collector, with its headers, and nothing more is sent to it. When none is set it throws an ApiError with the status 404. */
364
- async deleteTelemetry() {
365
- await this.http.send({ method: "DELETE", path: "/v1/telemetry" });
366
- }
367
- /**
368
- * GitHub Actions jobs on sandboxes: each repository's pool, how many sandboxes of each size it
369
- * keeps and the template they are made on. available is false where jobs do not run on
370
- * sandboxes here. GitHub itself is connected in the console.
371
- */
372
- async runsOnRepositories() {
373
- return (await this.http.json({ method: "GET", path: "/v1/runs-on/repositories", replay: true })).body;
374
- }
375
- /**
376
- * Sets a repository's pool, given as owner/name: poolMax, 1 to 50 sandboxes of each size, and
377
- * templateId, one of your templates, each null for the default and left out to keep what was set.
378
- * The template is used only where GitHub says the repository is private and runs no workflows
379
- * from fork pull requests.
380
- */
381
- async setRunsOnRepository(repository, settings) {
382
- return (await this.http.json({ method: "PUT", path: `/v1/runs-on/repositories/${repoPath(repository)}`, body: settings, replay: true })).body;
383
- }
384
- /** Puts a repository's pool back to the defaults. Its sandboxes are kept. When it has no settings it throws an ApiError with the status 404. */
385
- async resetRunsOnRepository(repository) {
386
- await this.http.send({ method: "DELETE", path: `/v1/runs-on/repositories/${repoPath(repository)}` });
387
- }
388
- /**
389
- * How long your sandboxes' history is kept: the output of their commands, their agent
390
- * conversations and their events. keepDays is 1, 7, 30 or 90, or null to keep it until the
391
- * sandbox is deleted; 30 until you choose. retained lists what is kept for periods agental sets.
392
- */
393
- async getDataRetention() {
394
- return (await this.http.json({ method: "GET", path: "/v1/data-retention", replay: true })).body;
395
- }
396
- /**
397
- * Sets how long your sandboxes' history is kept: 1, 7, 30 or 90 days, or null until the
398
- * sandbox is deleted. History older than that is deleted within the hour and cannot be
399
- * brought back. A deleted sandbox's history is deleted with it, whatever is set, its events a day later.
400
- */
401
- async setDataRetention(keepDays) {
402
- return (await this.http.json({ method: "PATCH", path: "/v1/data-retention", body: { keepDays }, replay: true })).body;
403
- }
404
- /** The webhooks your account's events are posted to, each with its tries of the last 30 days. Their secrets are not given. */
405
- async listWebhooks() {
406
- return (await this.http.json({ method: "GET", path: "/v1/webhooks", replay: true })).body.webhooks;
407
- }
408
- /**
409
- * Adds a webhook. url is posted each event it takes, and has to be on the public internet.
410
- * events names the kinds it takes, such as sandbox.stopped, or "*" for every one and any
411
- * added later, which is what it takes when events is left out. The answer holds
412
- * signingSecret, the one time it is given: each post's X-Agental-Signature is checked
413
- * against it with verifyWebhook. It is sent once, so a lost answer is not sent again.
414
- */
415
- async createWebhook(webhook) {
416
- return (await this.http.json({ method: "POST", path: "/v1/webhooks", body: webhook })).body;
417
- }
418
- /** One webhook, with every try of the last 30 days: the status each was answered, the event it was a try of, and which try. */
419
- async getWebhook(id) {
420
- return (await this.http.json({ method: "GET", path: `/v1/webhooks/${encodeURIComponent(id)}`, replay: true })).body;
421
- }
422
- /** Changes a webhook's url, events or description, and keeps what is left out. A changed url is used from the next try on. */
423
- async updateWebhook(id, changes) {
424
- return (await this.http.json({ method: "PATCH", path: `/v1/webhooks/${encodeURIComponent(id)}`, body: changes, replay: true })).body;
425
- }
426
- /** Gives a webhook a new signing secret, in its signingSecret, once. The old one stops working at once. */
427
- async rotateWebhookSecret(id) {
428
- return (await this.http.json({ method: "POST", path: `/v1/webhooks/${encodeURIComponent(id)}/rotate` })).body;
429
- }
430
- /** Deletes a webhook, the events still owed to it, and its tries. */
431
- async deleteWebhook(id) {
432
- await this.http.send({ method: "DELETE", path: `/v1/webhooks/${encodeURIComponent(id)}` });
433
- }
434
- /**
435
- * Everything agental keeps about your account and the person behind it: the account, its
436
- * sessions with the address and browser each began from, its keys by name, billing,
437
- * payments, usage, and what it has made. Secrets are named, never given. Closing an
438
- * account is not here: only a person signed in to the console can close one.
439
- */
440
- async exportAccount() {
441
- return (await this.http.json({ method: "GET", path: "/v1/me/export", replay: true })).body;
442
- }
443
- }
444
- /** owner/name as a path: each part encoded, the slash between them kept. */
445
- function repoPath(repository) {
446
- const [owner, name, ...rest] = repository.split("/");
447
- if (!owner || !name || rest.length > 0) {
448
- throw new TypeError(`A repository is owner/name, as acme/app, and not ${JSON.stringify(repository)}.`);
449
- }
450
- return `${encodeURIComponent(owner)}/${encodeURIComponent(name)}`;
451
- }
package/dist/errors.d.ts DELETED
@@ -1,62 +0,0 @@
1
- /** Every error this SDK throws is one of these. */
2
- export declare class AgentalError extends Error {
3
- constructor(message: string, options?: ErrorOptions);
4
- }
5
- /**
6
- * The API refused the request and said why. Decide what to do from `code`, such as
7
- * `sandbox_not_running` or `name_taken`. `message` says why in words.
8
- */
9
- export declare class ApiError extends AgentalError {
10
- readonly status: number;
11
- readonly code: string;
12
- /**
13
- * On a create refused with capacity_exceeded: the other regions that have room for its
14
- * size now, to send it again to with a new key. Empty when none has, and undefined on
15
- * any other error.
16
- */
17
- readonly regionsWithRoom?: string[] | undefined;
18
- constructor(status: number, code: string, message: string,
19
- /**
20
- * On a create refused with capacity_exceeded: the other regions that have room for its
21
- * size now, to send it again to with a new key. Empty when none has, and undefined on
22
- * any other error.
23
- */
24
- regionsWithRoom?: string[] | undefined, burst?: {
25
- feeMicros?: number;
26
- retryAfterSeconds?: number | null;
27
- });
28
- /**
29
- * On a start refused with 429 for its burst (see `BurstRefusalCode`): the burst fee it
30
- * would have cost, in millionths of a US dollar. Undefined on any other error.
31
- */
32
- readonly feeMicros?: number;
33
- /**
34
- * On a start refused with 429 for its burst: seconds until the same start would cost no
35
- * burst fee. Null where waiting would not help: on running_limit_reached, or for a start
36
- * larger than the plan's whole free burst. Undefined on any other error.
37
- */
38
- readonly retryAfterSeconds?: number | null;
39
- }
40
- /**
41
- * Why a create, fork or start was refused with the status 429. running_limit_reached: the
42
- * account already runs as many sandboxes as its plan's runningUnits allows. burst_fee_too_high:
43
- * the start would cost more in burst fees than maxBurstFeeMicros allows. burst_budget_reached:
44
- * the fee would take this month's burst fees past the account's budget. burst_in_free_month:
45
- * the start would cost a fee, which the free month does not pay.
46
- */
47
- export type BurstRefusalCode = "running_limit_reached" | "burst_fee_too_high" | "burst_budget_reached" | "burst_in_free_month";
48
- /**
49
- * Something in front of the API answered, not the API: a 502, a 504, a 52x, or any error
50
- * with no code in it. The API was not reached or did not answer in time, so the request
51
- * may still be running. Read the sandbox before sending anything but a create again.
52
- */
53
- export declare class ProxyError extends AgentalError {
54
- readonly status: number;
55
- constructor(status: number);
56
- }
57
- /** The API could not be reached at all. Whether the request arrived is not known. */
58
- export declare class ConnectionError extends AgentalError {
59
- }
60
- /** What was waited for did not happen in the time allowed. It may still happen. */
61
- export declare class TimeoutError extends AgentalError {
62
- }
package/dist/errors.js DELETED
@@ -1,65 +0,0 @@
1
- /** Every error this SDK throws is one of these. */
2
- export class AgentalError extends Error {
3
- constructor(message, options) {
4
- super(message, options);
5
- this.name = new.target.name;
6
- }
7
- }
8
- /**
9
- * The API refused the request and said why. Decide what to do from `code`, such as
10
- * `sandbox_not_running` or `name_taken`. `message` says why in words.
11
- */
12
- export class ApiError extends AgentalError {
13
- status;
14
- code;
15
- regionsWithRoom;
16
- constructor(status, code, message,
17
- /**
18
- * On a create refused with capacity_exceeded: the other regions that have room for its
19
- * size now, to send it again to with a new key. Empty when none has, and undefined on
20
- * any other error.
21
- */
22
- regionsWithRoom, burst) {
23
- super(message);
24
- this.status = status;
25
- this.code = code;
26
- this.regionsWithRoom = regionsWithRoom;
27
- if (burst?.feeMicros !== undefined) {
28
- this.feeMicros = burst.feeMicros;
29
- }
30
- if (burst?.retryAfterSeconds !== undefined) {
31
- this.retryAfterSeconds = burst.retryAfterSeconds;
32
- }
33
- }
34
- /**
35
- * On a start refused with 429 for its burst (see `BurstRefusalCode`): the burst fee it
36
- * would have cost, in millionths of a US dollar. Undefined on any other error.
37
- */
38
- feeMicros;
39
- /**
40
- * On a start refused with 429 for its burst: seconds until the same start would cost no
41
- * burst fee. Null where waiting would not help: on running_limit_reached, or for a start
42
- * larger than the plan's whole free burst. Undefined on any other error.
43
- */
44
- retryAfterSeconds;
45
- }
46
- /**
47
- * Something in front of the API answered, not the API: a 502, a 504, a 52x, or any error
48
- * with no code in it. The API was not reached or did not answer in time, so the request
49
- * may still be running. Read the sandbox before sending anything but a create again.
50
- */
51
- export class ProxyError extends AgentalError {
52
- status;
53
- constructor(status) {
54
- super(status >= 500
55
- ? `HTTP ${status} from a proxy in front of the API, not from the API. The request may still be running.`
56
- : `HTTP ${status} with no error of the API's in it. Check that baseUrl is where the API answers.`);
57
- this.status = status;
58
- }
59
- }
60
- /** The API could not be reached at all. Whether the request arrived is not known. */
61
- export class ConnectionError extends AgentalError {
62
- }
63
- /** What was waited for did not happen in the time allowed. It may still happen. */
64
- export class TimeoutError extends AgentalError {
65
- }
package/dist/http.d.ts DELETED
@@ -1,69 +0,0 @@
1
- export declare const DEFAULT_BASE_URL = "https://agental.io";
2
- export interface AgentalOptions {
3
- /**
4
- * Your API key. Left out, it is read from the environment variable AGENTAL_API_KEY, or else
5
- * from the sign-in the agental command keeps on this computer (`npx agental@latest`).
6
- */
7
- apiKey?: string;
8
- /** Where the API answers. Left out, it is AGENTAL_API_URL, or the API the agental command signed in to, or https://agental.io. */
9
- baseUrl?: string;
10
- /** What requests are sent with. Left out, it is the runtime's own fetch. */
11
- fetch?: typeof fetch;
12
- /** How many times a request that is safe to send again is sent again. Default 3. */
13
- maxRetries?: number;
14
- /** The shortest wait before a request is sent again, in milliseconds. Default 1000. */
15
- retryDelayMs?: number;
16
- /** How often something that is waited for is looked at, in milliseconds. Default 2000. */
17
- pollIntervalMs?: number;
18
- }
19
- export interface Call {
20
- method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
21
- path: string;
22
- query?: Record<string, string | readonly string[] | undefined>;
23
- body?: unknown;
24
- headers?: Record<string, string>;
25
- /**
26
- * Whether sending it twice does what sending it once does. Only such a request is sent
27
- * again by itself: a read, a create with its key, a file write. A command is not.
28
- */
29
- replay?: boolean;
30
- signal?: AbortSignal;
31
- }
32
- export interface StreamEvent {
33
- event: string;
34
- data: unknown;
35
- }
36
- export declare function sleep(ms: number, signal?: AbortSignal): Promise<void>;
37
- /** Sends requests to the API, and sends again the ones that are safe to. */
38
- export declare class Http {
39
- readonly pollIntervalMs: number;
40
- private readonly apiKey;
41
- private readonly baseUrl;
42
- private readonly fetch;
43
- private readonly maxRetries;
44
- private readonly retryDelayMs;
45
- constructor(options?: AgentalOptions);
46
- /** The answer to a request that worked. One that did not is thrown, after it was sent again if that was safe. */
47
- send(call: Call): Promise<Response>;
48
- /** The JSON a request was answered with, and the status and headers it came with. */
49
- json<T>(call: Call): Promise<{
50
- status: number;
51
- body: T;
52
- headers: Headers;
53
- }>;
54
- /** The server-sent events a request is answered with, each as it arrives. */
55
- events(call: Call): AsyncGenerator<StreamEvent, void, void>;
56
- /**
57
- * How long to wait before a failed request is sent again, or null when it is not to be.
58
- * The waits are the ones the API asks for: a request cut off by a move is sent again at
59
- * once, a move under way is waited out, and a proxy or a failing host is given ten times
60
- * the shortest wait. Only a request that may be sent twice is sent again, except one the
61
- * API turned away as it restarted: nothing was done with that one, a command neither.
62
- */
63
- private waitBefore;
64
- }
65
- /**
66
- * A tag as a part of a path: lowercased and trimmed as the API would, and refused here when it
67
- * is not one, so that no word, "..", say, can make the path another.
68
- */
69
- export declare function tagSegment(tag: string): string;