@hyperbrowser/sdk 1.2.2 → 1.4.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/README.md +427 -3
- package/dist/client.d.ts +2 -0
- package/dist/client.js +2 -0
- package/dist/error.d.ts +2 -0
- package/dist/error.js +4 -1
- package/dist/sandbox/process.d.ts +7 -3
- package/dist/sandbox/process.js +15 -3
- package/dist/sandbox/secret-references.d.ts +4 -0
- package/dist/sandbox/secret-references.js +11 -2
- package/dist/secret-values.d.ts +14 -0
- package/dist/secret-values.js +153 -0
- package/dist/secrets-envelope.d.ts +5 -0
- package/dist/secrets-envelope.js +17 -7
- package/dist/services/credentials.d.ts +24 -0
- package/dist/services/credentials.js +48 -0
- package/dist/services/sandboxes.d.ts +3 -2
- package/dist/services/sandboxes.js +20 -10
- package/dist/services/secrets.d.ts +19 -4
- package/dist/services/secrets.js +53 -17
- package/dist/services/sessions.d.ts +2 -0
- package/dist/services/sessions.js +2 -0
- package/dist/services/vaults.d.ts +26 -0
- package/dist/services/vaults.js +80 -0
- package/dist/tools/anthropic.d.ts +1 -0
- package/dist/tools/anthropic.js +6 -1
- package/dist/tools/gemini.d.ts +56 -0
- package/dist/tools/gemini.js +40 -0
- package/dist/tools/index.d.ts +92 -0
- package/dist/tools/index.js +81 -1
- package/dist/tools/openai.d.ts +1 -0
- package/dist/tools/openai.js +10 -1
- package/dist/tools/schema.d.ts +49 -0
- package/dist/tools/schema.js +53 -4
- package/dist/types/constants.d.ts +26 -4
- package/dist/types/credential.d.ts +120 -0
- package/dist/types/credential.js +2 -0
- package/dist/types/index.d.ts +4 -2
- package/dist/types/sandbox.d.ts +89 -2
- package/dist/types/secret.d.ts +61 -3
- package/dist/types/session.d.ts +14 -0
- package/dist/types/vault.d.ts +55 -0
- package/dist/types/vault.js +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -89,6 +89,409 @@ or `*` (every host). Proxy routes only apply to `sessions.create` and cannot be
|
|
|
89
89
|
combined with `allowInternetAccess: false`, `allowOut`, or `denyOut`. See the
|
|
90
90
|
[proxy routes guide](https://hyperbrowser.ai/docs/sessions/proxy-routes).
|
|
91
91
|
|
|
92
|
+
## Secrets, vaults and credential fill
|
|
93
|
+
|
|
94
|
+
Secrets are encrypted locally before upload; after that, neither the API, your
|
|
95
|
+
code, nor an LLM ever sees the values. A login is two secrets (or three, with a
|
|
96
|
+
TOTP seed), each limited to the origins it may be filled into, grouped in a
|
|
97
|
+
**vault** that names them as entries such as `USERNAME` and `PASSWORD`.
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import { chromium } from "playwright-core";
|
|
101
|
+
import { Hyperbrowser } from "@hyperbrowser/sdk";
|
|
102
|
+
|
|
103
|
+
const client = new Hyperbrowser({ apiKey: process.env.HYPERBROWSER_API_KEY });
|
|
104
|
+
|
|
105
|
+
// Once: the secrets, fillable only on their allowed origins, and a vault.
|
|
106
|
+
const allowedOrigins = ["https://github.com"];
|
|
107
|
+
await client.secrets.create({ name: "github-username", value: "ada", allowedOrigins });
|
|
108
|
+
await client.secrets.create({
|
|
109
|
+
name: "github-password",
|
|
110
|
+
value: process.env.GITHUB_PASSWORD!,
|
|
111
|
+
allowedOrigins,
|
|
112
|
+
});
|
|
113
|
+
// A TOTP secret holds the seed (base32 or an otpauth://totp/ URI); fills and
|
|
114
|
+
// sandboxes get its current code.
|
|
115
|
+
await client.secrets.create({
|
|
116
|
+
name: "github-otp",
|
|
117
|
+
type: "totp",
|
|
118
|
+
value: process.env.GITHUB_TOTP_SEED!,
|
|
119
|
+
allowedOrigins,
|
|
120
|
+
});
|
|
121
|
+
await client.vaults.create({
|
|
122
|
+
name: "github-login",
|
|
123
|
+
entries: {
|
|
124
|
+
USERNAME: { name: "github-username" },
|
|
125
|
+
PASSWORD: { name: "github-password" },
|
|
126
|
+
OTP: { name: "github-otp" },
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Secrets can only be attached when the session is created.
|
|
131
|
+
const session = await client.sessions.create({ credentials: [{ vault: "github-login" }] });
|
|
132
|
+
try {
|
|
133
|
+
const browser = await chromium.connectOverCDP(session.wsEndpoint);
|
|
134
|
+
const page = await browser.contexts()[0].newPage();
|
|
135
|
+
await page.goto("https://github.com/login");
|
|
136
|
+
|
|
137
|
+
// Fill only types into the inputs; it never submits.
|
|
138
|
+
const result = await client.sessions.credentials.fill(session.id, {
|
|
139
|
+
vault: "github-login",
|
|
140
|
+
fields: [
|
|
141
|
+
{ field: "USERNAME", selector: "#login_field" },
|
|
142
|
+
{ field: "PASSWORD", selector: "#password" },
|
|
143
|
+
],
|
|
144
|
+
});
|
|
145
|
+
if (result.fields.every(({ outcome }) => outcome === "filled")) {
|
|
146
|
+
await page.click('input[type="submit"]');
|
|
147
|
+
} else {
|
|
148
|
+
console.log(result.fields); // e.g. [{ selector: "#password", outcome: "not_found", ... }]
|
|
149
|
+
}
|
|
150
|
+
// On the next screen: { field: "OTP", selector: "#app_totp" } types the current code.
|
|
151
|
+
} finally {
|
|
152
|
+
await client.sessions.stop(session.id);
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
- `credentials` takes up to 20 items: a secret's name (or `{ secret }`),
|
|
157
|
+
`{ vault }` for the secrets a stored vault names when the session is created,
|
|
158
|
+
or `{ onePassword }` for an `op_token` secret (see
|
|
159
|
+
[Fill from 1Password](#fill-from-1password)); the API validates names and limits.
|
|
160
|
+
`session.credentials` lists the attached secrets as `{ id, name }`. Fill a
|
|
161
|
+
single secret with `{ credential: "github-password", fields: [{ selector }] }`;
|
|
162
|
+
with `vault`, each field names its entry in `field`.
|
|
163
|
+
- Each input reports an `outcome`: `filled`, `not_found` (no input matched),
|
|
164
|
+
`ambiguous` (several visible inputs matched), `not_editable` (disabled,
|
|
165
|
+
read-only, hidden or not a text input), or `not_accepted` (the page didn't
|
|
166
|
+
keep the value, e.g. `maxlength`), plus its `secretId` and `version`, the
|
|
167
|
+
vault `field`, and for TOTP inputs `expiresAt`. Submit only when the inputs
|
|
168
|
+
you need are `filled`. Fill is safe to retry; it is not retried automatically.
|
|
169
|
+
- Without `pageId`, fill considers the tabs whose URL starts with `pageUrl`
|
|
170
|
+
(all tabs when it's not given). If one is left, that's the target. If several
|
|
171
|
+
are left, it prefers the tabs on an origin every secret allows (not for an
|
|
172
|
+
iframe fill, whose tab is usually on another origin), then the visible one
|
|
173
|
+
among them; if more than one still qualifies, it fails with
|
|
174
|
+
`CREDENTIAL_PAGE_AMBIGUOUS` and the candidates in
|
|
175
|
+
`error.details.details.pages` (`{ pageId, url, title }`). The chosen tab's
|
|
176
|
+
origin is then checked: on any other origin nothing is typed and the fill
|
|
177
|
+
fails with `CREDENTIAL_ORIGIN_NOT_ALLOWED`.
|
|
178
|
+
Under Playwright every tab reports as visible, so pass `pageUrl` or the
|
|
179
|
+
page's target ID: `(await page.context().newCDPSession(page)).send("Target.getTargetInfo")`
|
|
180
|
+
(in Puppeteer, `page.createCDPSession()`) returns it as `targetInfo.targetId`.
|
|
181
|
+
For a form inside an iframe, pass `frameUrl` (a URL prefix).
|
|
182
|
+
- Origins are `scheme://host[:port]`, 1-20 per secret; a leading `*.` matches
|
|
183
|
+
subdomains only (of a domain such as `example.com`, not `*.com` or an IP
|
|
184
|
+
address), and `http:` is accepted only for `localhost`, `127.0.0.1` and
|
|
185
|
+
`[::1]`. The API validates and normalizes them.
|
|
186
|
+
`setAllowedOrigins(secret, origins)` replaces them and `null`
|
|
187
|
+
clears them (the secret then can't be filled). `list({ type })` filters by
|
|
188
|
+
type.
|
|
189
|
+
- Values are checked locally before anything is sent (`invalid_secret_value`):
|
|
190
|
+
1 byte to 32 KiB of UTF-8 without NUL, and for TOTP a base32 seed (spaces,
|
|
191
|
+
hyphens, line breaks, lowercase and trailing `=` padding are fine) or an `otpauth://totp/`
|
|
192
|
+
URI with `secret` and optionally `algorithm` (SHA1, SHA256, SHA512), `digits`
|
|
193
|
+
(6 or 8) and `period` (1-300). HOTP is not supported, and a seed whose
|
|
194
|
+
length is 1, 3 or 6 characters past a multiple of 8 is refused as
|
|
195
|
+
incompletely copied. Seeds under 10 bytes (16 characters) are accepted, but
|
|
196
|
+
check that a short one was copied whole. `addVersion` applies the rules of
|
|
197
|
+
the secret's type. Fill, origin, vault-entry and 1Password policy errors come
|
|
198
|
+
from the API; inspect the error's status, code (when supplied) and details.
|
|
199
|
+
- Session create needs the API key scope `secrets.use`; fill also needs
|
|
200
|
+
`browser.sessions.update`. Attaching secrets runs the session on Firecracker
|
|
201
|
+
with Chrome's password manager off. Fills are recorded in the session event
|
|
202
|
+
log as `credential_filled` and `credential_fill_refused`.
|
|
203
|
+
|
|
204
|
+
### Vaults
|
|
205
|
+
|
|
206
|
+
Vaults also deliver environment variables to sandboxes (see
|
|
207
|
+
[Sandboxes](#sandboxes)). A vault names stored secrets and holds no values
|
|
208
|
+
itself.
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
await client.vaults.create({
|
|
212
|
+
name: "prod-db",
|
|
213
|
+
entries: {
|
|
214
|
+
DB_USER: { name: "db-user" },
|
|
215
|
+
DB_PASS: { name: "db-pass", version: 2 },
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
await client.vaults.update("prod-db", {
|
|
219
|
+
entries: { DB_OTP: { name: "db-otp" }, DB_USER: null },
|
|
220
|
+
});
|
|
221
|
+
const vault = await client.vaults.get("prod-db"); // entries include each secret's ID
|
|
222
|
+
const { vaults } = await client.vaults.list({ search: "prod" });
|
|
223
|
+
await client.vaults.delete("prod-db");
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
- Vault methods take a vault's ID or exact name. Entry names are environment
|
|
227
|
+
variable names (`^[A-Za-z_][A-Za-z0-9_]*$`, at most 256 characters), and
|
|
228
|
+
entries are `{ name, version? }` (an omitted version, or `"latest"`, follows
|
|
229
|
+
the latest). `update` takes a description or entries; an entry set to `null`
|
|
230
|
+
is removed and entries not given are kept. Limits: 100 vaults per team, 32
|
|
231
|
+
entries per vault. Vaults use the `secrets.read` and `secrets.manage`
|
|
232
|
+
scopes, like secrets.
|
|
233
|
+
- A secret a vault uses can't be deleted (`SECRET_IN_USE`), nor a version a
|
|
234
|
+
vault pins (`SECRET_VERSION_IN_USE`).
|
|
235
|
+
|
|
236
|
+
### 1Password
|
|
237
|
+
|
|
238
|
+
Sandbox processes, and an image's startup command, can read fields from a
|
|
239
|
+
1Password vault when they start: pass `onePassword` to `processes.start`,
|
|
240
|
+
`processes.exec` or `sandboxes.create`. It signs in with a service account
|
|
241
|
+
token stored as an `op_token` secret. Tokens start with `ops_`, but the SDK
|
|
242
|
+
doesn't refuse other values. `op_token` secrets are never environment
|
|
243
|
+
variables or typed into pages themselves, so they take no `allowedOrigins`.
|
|
244
|
+
Nothing about the fields is stored. Browser sessions can fill 1Password
|
|
245
|
+
fields too: see [Fill from 1Password](#fill-from-1password).
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
await client.secrets.create({
|
|
249
|
+
name: "op-token",
|
|
250
|
+
type: "op_token",
|
|
251
|
+
value: process.env.OP_SERVICE_ACCOUNT_TOKEN!,
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
const onePassword = {
|
|
255
|
+
token: "op-token",
|
|
256
|
+
vault: "Engineering",
|
|
257
|
+
fields: {
|
|
258
|
+
DB_PASS: { item: "Postgres", section: "prod", field: "password" },
|
|
259
|
+
DB_OTP: { item: "Postgres", field: "one-time password?attribute=totp" },
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
const sandbox = await client.sandboxes.create({ imageName: "my-image", onePassword });
|
|
263
|
+
const migrate = await sandbox.exec("node migrate.js", {
|
|
264
|
+
onePassword,
|
|
265
|
+
secrets: { API_KEY: "provider-key" },
|
|
266
|
+
});
|
|
267
|
+
const worker = await sandbox.processes.start("node worker.js", { onePassword });
|
|
268
|
+
console.log(worker.secrets); // [{ env: "DB_PASS", reference: "op://Engineering/Postgres/prod/password", tokenSecret: "op-token", source: { type: "onePassword" } }, ...]
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
- `token` names the `op_token` secret (its latest version is used), `vault`
|
|
272
|
+
is the 1Password vault's name or ID, and `fields` maps 1 to 32 environment
|
|
273
|
+
variables to `{ item, section?, field }`. Names and IDs are 1-256
|
|
274
|
+
characters without `/` or `?`, control or format characters, and not `.` or
|
|
275
|
+
`..`; the field may end with a query such as `?attribute=totp` or
|
|
276
|
+
`?ssh-format=openssh`. The full `op://<vault>/<item>/[<section>/]<field>`
|
|
277
|
+
reference is at most 512 bytes. The API validates these rules and rejects
|
|
278
|
+
unknown members.
|
|
279
|
+
- A 1Password field's variable must come from it alone: `secrets` or `env`
|
|
280
|
+
setting it too, including a `vault` entry, is refused by the API
|
|
281
|
+
(`SECRET_SOURCES_INVALID`). Together with `vault` and
|
|
282
|
+
`secrets` it delivers at most 32 variables.
|
|
283
|
+
- Requirements are those of `secrets`: the `secrets.use` scope, and for
|
|
284
|
+
`sandboxes.create` an image launch with a startup command on Firecracker.
|
|
285
|
+
|
|
286
|
+
### Fill from 1Password
|
|
287
|
+
|
|
288
|
+
Attach the `op_token` secret when the session is created, then fill fields
|
|
289
|
+
read with it. The request names the 1Password vault, each input's field as
|
|
290
|
+
`ref`, and the origins the values may be typed on: nothing stored says where
|
|
291
|
+
a 1Password value belongs.
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
const session = await client.sessions.create({ credentials: [{ onePassword: "op-token" }] });
|
|
295
|
+
// ... open https://www.scrapingcourse.com/login in the session ...
|
|
296
|
+
const result = await client.sessions.credentials.fill(session.id, {
|
|
297
|
+
onePassword: {
|
|
298
|
+
token: "op-token",
|
|
299
|
+
vault: "Dev Vault for Testing",
|
|
300
|
+
allowedOrigins: ["https://www.scrapingcourse.com"],
|
|
301
|
+
},
|
|
302
|
+
fields: [
|
|
303
|
+
{ selector: "#email", ref: { item: "scrapingcourse login", field: "username" } },
|
|
304
|
+
{ selector: "#password", ref: { item: "scrapingcourse login", field: "password" } },
|
|
305
|
+
],
|
|
306
|
+
pageUrl: "https://www.scrapingcourse.com/login",
|
|
307
|
+
});
|
|
308
|
+
console.log(result.fields);
|
|
309
|
+
// [{ selector: "#email", outcome: "filled", secretId: "<op-token's ID>", version: 1,
|
|
310
|
+
// reference: "op://Dev Vault for Testing/scrapingcourse login/username" }, ...]
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
- Pass exactly one of `credential`, `vault` and `onePassword`. With
|
|
314
|
+
`onePassword` every field needs `ref` (`{ item, section?, field }`) and none
|
|
315
|
+
may have `field`; without it, none may have `ref`.
|
|
316
|
+
- `token` names an `op_token` secret attached as `{ onePassword }` (its
|
|
317
|
+
latest version is used), and `vault` is the 1Password vault's name or ID.
|
|
318
|
+
`ref` and `vault` follow the rules of sandbox `onePassword` fields above,
|
|
319
|
+
so `{ field: "one-time password?attribute=otp" }` types the current code,
|
|
320
|
+
and each `op://` reference is at most 512 bytes.
|
|
321
|
+
- `allowedOrigins` is required: 1-20 origins with the same rules as a
|
|
322
|
+
secret's. A page on any other origin is refused with
|
|
323
|
+
`CREDENTIAL_ORIGIN_NOT_ALLOWED`, and tab choice treats these as the
|
|
324
|
+
allowed origins.
|
|
325
|
+
- The API validates these rules and rejects unknown members of `onePassword`
|
|
326
|
+
and `ref`, along with the usual 1-16 fields and unique selectors.
|
|
327
|
+
- The result has no top-level `version`. Each field's `secretId` and
|
|
328
|
+
`version` are the `op_token`'s, and `reference` is the field that was read.
|
|
329
|
+
- A missing item or field fails with `SECRET_ONEPASSWORD_REFERENCE_FAILED`
|
|
330
|
+
and fills nothing; `error.details.details.selectors` lists the inputs and
|
|
331
|
+
`reasons` says why, by selector. Without the token attached it is
|
|
332
|
+
`CREDENTIAL_NOT_ATTACHED`; a host that can't read 1Password for browsers
|
|
333
|
+
gives `CREDENTIAL_VALUE_UNSUPPORTED`.
|
|
334
|
+
- An `op_token` is still refused as a plain credential (`"op-token"` or
|
|
335
|
+
`{ secret: "op-token" }` at create, or `credential` in a fill) with
|
|
336
|
+
`SECRET_TYPE_MISMATCH`.
|
|
337
|
+
- The session event log records these fills with the token's name as
|
|
338
|
+
`onePasswordToken` and its `secretId` in the metadata.
|
|
339
|
+
- `CredentialFillTool` can't fill from 1Password; call
|
|
340
|
+
`sessions.credentials.fill` directly (see [Use with LLM SDKs](#use-with-llm-sdks)).
|
|
341
|
+
|
|
342
|
+
### Errors
|
|
343
|
+
|
|
344
|
+
API errors are `HyperbrowserError`s with `statusCode`, `code` and `retryable`
|
|
345
|
+
(the API's own flag when it sends one); `details` is the API's error body, whose
|
|
346
|
+
own `details` holds the specifics (such as `error.details.details.origin`).
|
|
347
|
+
|
|
348
|
+
| Code | Meaning |
|
|
349
|
+
|---|---|
|
|
350
|
+
| `CREDENTIAL_NOT_ATTACHED` | The secret, vault or 1Password token wasn't attached to the session, or a vault entry was repointed since. |
|
|
351
|
+
| `CREDENTIAL_ORIGIN_NOT_ALLOWED` | The page isn't on the secret's allowed origins (for 1Password, the request's); nothing was typed. |
|
|
352
|
+
| `CREDENTIAL_NOT_READY` | The secret has no allowed origins or no value. |
|
|
353
|
+
| `CREDENTIAL_PAGE_NOT_FOUND`, `CREDENTIAL_FRAME_NOT_FOUND` | No tab or iframe matched. |
|
|
354
|
+
| `CREDENTIAL_PAGE_AMBIGUOUS`, `CREDENTIAL_FRAME_AMBIGUOUS` | Several matched; pass `pageId` or `pageUrl` (`details.pages`), or a longer `frameUrl`. |
|
|
355
|
+
| `CREDENTIAL_FILL_TIMEOUT` | Retryable. |
|
|
356
|
+
| `CREDENTIAL_FILL_FAILED` | The fill failed in the browser. |
|
|
357
|
+
| `CREDENTIAL_FILL_UNSUPPORTED`, `CREDENTIAL_VALUE_UNSUPPORTED` | The browser image predates fill, or the host can't resolve this value type (such as 1Password). |
|
|
358
|
+
| `CREDENTIALS_UNSUPPORTED_RUNTIME`, `CREDENTIALS_SNAPSHOT_PASSWORD_MANAGER_ENABLED` | Session create: secrets need Firecracker, and a snapshot taken with the password manager off. |
|
|
359
|
+
| `SESSION_NOT_ACTIVE` | The session has stopped. |
|
|
360
|
+
| `SECRET_NOT_FOUND`, `SECRET_VERSION_NOT_FOUND` | |
|
|
361
|
+
| `SECRET_TYPE_MISMATCH` | A secret used where its type can't be, such as an `op_token` in `secrets`, a vault entry, or attached or filled as a plain credential, or another type as a `onePassword` token. |
|
|
362
|
+
| `SECRET_METADATA_INVALID` | A bad allowed origin, or allowed origins on an `op_token`. |
|
|
363
|
+
| `SECRET_VALUE_INVALID` | The stored value is unusable (such as a bad TOTP seed); add a new version. |
|
|
364
|
+
| `SECRET_IN_USE`, `SECRET_VERSION_IN_USE`, `SECRET_VERSION_IS_LATEST` | Delete refused: a vault uses the secret or pins the version, or the version is the latest. An `op_token` is never in use. |
|
|
365
|
+
| `SECRET_TOTP_UNSUPPORTED`, `SECRET_ONEPASSWORD_UNSUPPORTED` | The sandbox host predates TOTP or 1Password, so nothing started. Retryable on sandbox create (another host), not on a process start. |
|
|
366
|
+
| `SECRET_ONEPASSWORD_REFERENCE_FAILED` | A 1Password field couldn't be read; `details` names the variables (`envs`), or on a fill the inputs (`selectors`), with `reasons` for each. |
|
|
367
|
+
| `SECRET_ONEPASSWORD_AUTH_FAILED` | 1Password refused the token, or the token is malformed or signs in somewhere other than `1password.com`, `.ca` or `.eu` (or their subdomains). |
|
|
368
|
+
| `SECRET_ONEPASSWORD_RATE_LIMITED`, `SECRET_ONEPASSWORD_FAILED` | Retryable. |
|
|
369
|
+
| `SECRET_SOURCES_INVALID` | Bad `vault`/`onePassword`/`secrets`/`env` combination, such as a `onePassword` variable also set by the vault, more than 32 variables, or a vault with no entries. |
|
|
370
|
+
| `VAULT_NOT_FOUND`, `VAULT_ENTRY_NOT_FOUND` | |
|
|
371
|
+
| `VAULT_NAME_TAKEN`, `VAULT_LIMIT_REACHED`, `VAULT_ENTRY_LIMIT_REACHED` | |
|
|
372
|
+
| `SECRETS_FEATURE_DISABLED` | The team doesn't have secrets enabled. |
|
|
373
|
+
|
|
374
|
+
### Use with LLM SDKs
|
|
375
|
+
|
|
376
|
+
`CredentialFillTool` from `@hyperbrowser/sdk/tools` exposes fill as a
|
|
377
|
+
`fill_credential` tool. Your application binds the session ID; the model picks
|
|
378
|
+
only a `credential` or a `vault` (with a `field` per input), the selectors and,
|
|
379
|
+
when needed, `page_id`, `page_url` or `frame_url`. In OpenAI's strict mode every
|
|
380
|
+
property is required, so unused ones are `null`. Results and errors come back as
|
|
381
|
+
JSON text and never contain values; an error's `details` there is the API's own
|
|
382
|
+
details object (such as `pages`). Fill doesn't submit, so give the model your
|
|
383
|
+
other browser tools as well (to click the login button, for example).
|
|
384
|
+
|
|
385
|
+
The tool has no `onePassword`: a 1Password fill names the origins its values
|
|
386
|
+
may be typed on, and a model shouldn't choose those. Call
|
|
387
|
+
`sessions.credentials.fill` directly for [1Password](#fill-from-1password).
|
|
388
|
+
|
|
389
|
+
OpenAI (Chat Completions):
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
import OpenAI from "openai";
|
|
393
|
+
import type { ChatCompletionMessageParam } from "openai/resources/chat/completions";
|
|
394
|
+
import { CredentialFillTool } from "@hyperbrowser/sdk/tools";
|
|
395
|
+
|
|
396
|
+
const openai = new OpenAI();
|
|
397
|
+
const messages: ChatCompletionMessageParam[] = [
|
|
398
|
+
{ role: "user", content: "Sign in to GitHub with the github-login vault." },
|
|
399
|
+
];
|
|
400
|
+
for (;;) {
|
|
401
|
+
const completion = await openai.chat.completions.create({
|
|
402
|
+
model: "gpt-5",
|
|
403
|
+
messages,
|
|
404
|
+
tools: [CredentialFillTool.openaiToolDefinition /* , your browser tools */],
|
|
405
|
+
});
|
|
406
|
+
const message = completion.choices[0].message;
|
|
407
|
+
messages.push(message);
|
|
408
|
+
if (!message.tool_calls?.length) break;
|
|
409
|
+
for (const call of message.tool_calls) {
|
|
410
|
+
if (call.type !== "function" || call.function.name !== "fill_credential") continue;
|
|
411
|
+
const content = await CredentialFillTool.runnable(
|
|
412
|
+
client,
|
|
413
|
+
session.id,
|
|
414
|
+
JSON.parse(call.function.arguments)
|
|
415
|
+
);
|
|
416
|
+
messages.push({ role: "tool", tool_call_id: call.id, content });
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
Anthropic (Messages):
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
425
|
+
import { CredentialFillTool, type CredentialFillToolParams } from "@hyperbrowser/sdk/tools";
|
|
426
|
+
|
|
427
|
+
const anthropic = new Anthropic();
|
|
428
|
+
const messages: Anthropic.MessageParam[] = [
|
|
429
|
+
{ role: "user", content: "Sign in to GitHub with the github-login vault." },
|
|
430
|
+
];
|
|
431
|
+
for (;;) {
|
|
432
|
+
const response = await anthropic.messages.create({
|
|
433
|
+
model: "claude-sonnet-5-5",
|
|
434
|
+
max_tokens: 4096,
|
|
435
|
+
tools: [CredentialFillTool.anthropicToolDefinition /* , your browser tools */],
|
|
436
|
+
messages,
|
|
437
|
+
});
|
|
438
|
+
messages.push({ role: "assistant", content: response.content });
|
|
439
|
+
if (response.stop_reason !== "tool_use") break;
|
|
440
|
+
const results: Anthropic.ToolResultBlockParam[] = [];
|
|
441
|
+
for (const block of response.content) {
|
|
442
|
+
if (block.type !== "tool_use" || block.name !== "fill_credential") continue;
|
|
443
|
+
const content = await CredentialFillTool.runnable(
|
|
444
|
+
client,
|
|
445
|
+
session.id,
|
|
446
|
+
block.input as CredentialFillToolParams
|
|
447
|
+
);
|
|
448
|
+
results.push({ type: "tool_result", tool_use_id: block.id, content });
|
|
449
|
+
}
|
|
450
|
+
messages.push({ role: "user", content: results });
|
|
451
|
+
}
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
Gemini (`@google/genai`):
|
|
455
|
+
|
|
456
|
+
```typescript
|
|
457
|
+
import { GoogleGenAI, type Content, type Part } from "@google/genai";
|
|
458
|
+
import { CredentialFillTool, type CredentialFillToolParams } from "@hyperbrowser/sdk/tools";
|
|
459
|
+
|
|
460
|
+
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
|
|
461
|
+
const contents: Content[] = [
|
|
462
|
+
{ role: "user", parts: [{ text: "Sign in to GitHub with the github-login vault." }] },
|
|
463
|
+
];
|
|
464
|
+
for (;;) {
|
|
465
|
+
const response = await ai.models.generateContent({
|
|
466
|
+
model: "gemini-3.5-flash",
|
|
467
|
+
contents,
|
|
468
|
+
config: {
|
|
469
|
+
tools: [{ functionDeclarations: [CredentialFillTool.geminiToolDefinition] }],
|
|
470
|
+
},
|
|
471
|
+
});
|
|
472
|
+
const calls = response.functionCalls ?? [];
|
|
473
|
+
if (calls.length === 0) break;
|
|
474
|
+
contents.push(response.candidates![0].content!);
|
|
475
|
+
const parts: Part[] = [];
|
|
476
|
+
for (const call of calls) {
|
|
477
|
+
if (call.name !== "fill_credential") continue;
|
|
478
|
+
const output = await CredentialFillTool.runnable(
|
|
479
|
+
client,
|
|
480
|
+
session.id,
|
|
481
|
+
call.args as unknown as CredentialFillToolParams
|
|
482
|
+
);
|
|
483
|
+
parts.push({
|
|
484
|
+
functionResponse: { id: call.id, name: call.name, response: JSON.parse(output) },
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
contents.push({ role: "user", parts });
|
|
488
|
+
}
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
`FILL_CREDENTIAL_TOOL_OPENAI`, `FILL_CREDENTIAL_TOOL_ANTHROPIC` and
|
|
492
|
+
`FILL_CREDENTIAL_TOOL_GEMINI` are also exported. `CredentialFillTool` provides
|
|
493
|
+
`geminiToolDefinition` for the credential-fill tool.
|
|
494
|
+
|
|
92
495
|
## Usage
|
|
93
496
|
|
|
94
497
|
### Playwright
|
|
@@ -439,15 +842,36 @@ const worker = await sandbox.processes.start("node worker.js", {
|
|
|
439
842
|
});
|
|
440
843
|
console.log(worker.secrets);
|
|
441
844
|
|
|
845
|
+
// A vault's entries as variables; `secrets` is merged over it and wins on a clash.
|
|
846
|
+
const migrate = await sandbox.exec("node migrate.js", {
|
|
847
|
+
vault: "prod-db",
|
|
848
|
+
secrets: { API_KEY: "provider-key" },
|
|
849
|
+
});
|
|
850
|
+
|
|
442
851
|
// Secrets for the image's startup command (image launches only).
|
|
443
|
-
await client.sandboxes.create({
|
|
852
|
+
const started = await client.sandboxes.create({
|
|
853
|
+
imageName: "my-image",
|
|
854
|
+
vault: "prod-db",
|
|
855
|
+
secrets: { API_KEY: "provider-key" },
|
|
856
|
+
});
|
|
857
|
+
console.log(started.toJSON().startupSecrets);
|
|
444
858
|
|
|
445
859
|
await client.secrets.deleteVersion("provider-key", 1);
|
|
446
860
|
await client.secrets.delete("provider-key");
|
|
447
861
|
```
|
|
448
862
|
|
|
449
863
|
- Secret methods take a secret's ID or exact name. Values are strings or bytes,
|
|
450
|
-
used byte-for-byte: 1 to 32,768 bytes of UTF-8 without NUL.
|
|
864
|
+
used byte-for-byte: 1 to 32,768 bytes of UTF-8 without NUL. A `totp`
|
|
865
|
+
secret's variable holds the code that is current when the process starts
|
|
866
|
+
(it isn't refreshed); `op_token` secrets can't be variables.
|
|
867
|
+
- `secrets` on a process handle (and `startupSecrets` on a created sandbox)
|
|
868
|
+
report what each variable received, never a value: a stored secret's
|
|
869
|
+
`name`, `secretId` and `version` (with `secretType: "totp"` for TOTP), its
|
|
870
|
+
`source` (`{ type: "vault", name }` or `{ type: "secrets" }`) and any
|
|
871
|
+
`overrides` it replaced; or for [1Password](#1password) the `reference`,
|
|
872
|
+
`tokenSecret` and `source: { type: "onePassword" }`. `vault`, `onePassword`
|
|
873
|
+
and `secrets` together hold at most 32 variables, and `env` can't set one
|
|
874
|
+
of them.
|
|
451
875
|
- A secret is delivered only to the process it is passed to, but anything
|
|
452
876
|
running as the same user (or root) in the sandbox can read that process's
|
|
453
877
|
environment. The sandbox and its later snapshots are marked
|
|
@@ -465,7 +889,7 @@ await client.secrets.delete("provider-key");
|
|
|
465
889
|
the start (`SECRET_PROCESS_OUTCOME_UNKNOWN`), the error code is
|
|
466
890
|
`secret_process_outcome_unknown` and the API's response, if any, is in
|
|
467
891
|
`details`: check the sandbox's processes before starting it again.
|
|
468
|
-
- The same applies to `sandboxes.create` with `secrets`: if the create result
|
|
892
|
+
- The same applies to `sandboxes.create` with `secrets`, `vault` or `onePassword`: if the create result
|
|
469
893
|
can't be confirmed, the error code is `secret_process_outcome_unknown`, since
|
|
470
894
|
a sandbox may already be running its startup command with the secrets. List
|
|
471
895
|
sandboxes before creating it again.
|
package/dist/client.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { WebService } from "./services/web";
|
|
|
19
19
|
import { SandboxesService } from "./services/sandboxes";
|
|
20
20
|
import { VolumesService } from "./services/volumes";
|
|
21
21
|
import { SecretsService } from "./services/secrets";
|
|
22
|
+
import { VaultsService } from "./services/vaults";
|
|
22
23
|
export { HyperbrowserError } from "./error";
|
|
23
24
|
export type { HyperbrowserErrorOptions, HyperbrowserService } from "./error";
|
|
24
25
|
export declare class HyperbrowserClient {
|
|
@@ -44,5 +45,6 @@ export declare class HyperbrowserClient {
|
|
|
44
45
|
readonly sandboxes: SandboxesService;
|
|
45
46
|
readonly volumes: VolumesService;
|
|
46
47
|
readonly secrets: SecretsService;
|
|
48
|
+
readonly vaults: VaultsService;
|
|
47
49
|
constructor(config?: HyperbrowserConfig);
|
|
48
50
|
}
|
package/dist/client.js
CHANGED
|
@@ -21,6 +21,7 @@ const web_1 = require("./services/web");
|
|
|
21
21
|
const sandboxes_1 = require("./services/sandboxes");
|
|
22
22
|
const volumes_1 = require("./services/volumes");
|
|
23
23
|
const secrets_1 = require("./services/secrets");
|
|
24
|
+
const vaults_1 = require("./services/vaults");
|
|
24
25
|
const error_1 = require("./error");
|
|
25
26
|
var error_2 = require("./error");
|
|
26
27
|
Object.defineProperty(exports, "HyperbrowserError", { enumerable: true, get: function () { return error_2.HyperbrowserError; } });
|
|
@@ -45,6 +46,7 @@ class HyperbrowserClient {
|
|
|
45
46
|
this.sandboxes = new sandboxes_1.SandboxesService(apiKey, baseUrl, timeout, runtimeProxyOverride);
|
|
46
47
|
this.volumes = new volumes_1.VolumesService(apiKey, baseUrl, timeout);
|
|
47
48
|
this.secrets = new secrets_1.SecretsService(apiKey, baseUrl, timeout);
|
|
49
|
+
this.vaults = new vaults_1.VaultsService(apiKey, baseUrl, timeout);
|
|
48
50
|
this.agents = {
|
|
49
51
|
browserUse: new browser_use_1.BrowserUseService(apiKey, baseUrl, timeout),
|
|
50
52
|
claudeComputerUse: new claude_computer_use_1.ClaudeComputerUseService(apiKey, baseUrl, timeout),
|
package/dist/error.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export declare class HyperbrowserError extends Error {
|
|
|
25
25
|
readonly path?: string;
|
|
26
26
|
constructor(message: string, options?: number | HyperbrowserErrorOptions);
|
|
27
27
|
}
|
|
28
|
+
/** @internal A request the SDK refuses to send because the API would reject it. */
|
|
29
|
+
export declare const invalidRequest: (message: string) => HyperbrowserError;
|
|
28
30
|
/** @internal The response body could not be read or decoded as JSON. */
|
|
29
31
|
export declare class ResponseDecodingError extends HyperbrowserError {
|
|
30
32
|
}
|
package/dist/error.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ResponseDecodingError = exports.HyperbrowserError = exports.networkErrorMessage = exports.errorRequestPath = void 0;
|
|
3
|
+
exports.ResponseDecodingError = exports.invalidRequest = exports.HyperbrowserError = exports.networkErrorMessage = exports.errorRequestPath = void 0;
|
|
4
4
|
/** Keep diagnostics useful without retaining query credentials or URL hosts. */
|
|
5
5
|
const errorRequestPath = (target) => {
|
|
6
6
|
try {
|
|
@@ -30,6 +30,9 @@ class HyperbrowserError extends Error {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
exports.HyperbrowserError = HyperbrowserError;
|
|
33
|
+
/** @internal A request the SDK refuses to send because the API would reject it. */
|
|
34
|
+
const invalidRequest = (message) => new HyperbrowserError(message, { code: "invalid_request", retryable: false });
|
|
35
|
+
exports.invalidRequest = invalidRequest;
|
|
33
36
|
/** @internal The response body could not be read or decoded as JSON. */
|
|
34
37
|
class ResponseDecodingError extends HyperbrowserError {
|
|
35
38
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RuntimeSSEStream, RuntimeTransport } from "./base";
|
|
2
|
-
import { WireSecretReference } from "./secret-references";
|
|
2
|
+
import { WireOnePassword, WireSecretReference } from "./secret-references";
|
|
3
3
|
import { SandboxExecParams, SandboxExecOptions, SandboxResolvedSecret, SandboxProcessListParams, SandboxProcessListResponse, SandboxProcessResult, SandboxProcessSignal, SandboxProcessStdinParams, SandboxProcessStreamEvent, SandboxProcessSummary, SandboxProcessWaitParams } from "../types/sandbox";
|
|
4
4
|
export interface RawProcessSummary extends Partial<SandboxProcessSummary> {
|
|
5
5
|
id: string;
|
|
@@ -19,7 +19,11 @@ export interface SecretProcessStartPayload {
|
|
|
19
19
|
env?: Record<string, string>;
|
|
20
20
|
timeoutMs?: number;
|
|
21
21
|
runAs?: string;
|
|
22
|
-
secrets
|
|
22
|
+
secrets?: Record<string, WireSecretReference>;
|
|
23
|
+
/** A vault name; `secrets` is merged over its entries. */
|
|
24
|
+
vault?: string;
|
|
25
|
+
/** 1Password fields; their variables can't come from any other source. */
|
|
26
|
+
onePassword?: WireOnePassword;
|
|
23
27
|
}
|
|
24
28
|
export interface SecretProcessStartResponse {
|
|
25
29
|
/** The sandbox agent's summary, passed through unchanged. */
|
|
@@ -51,7 +55,7 @@ export declare class SandboxProcessHandle {
|
|
|
51
55
|
private collector;
|
|
52
56
|
private closeStream;
|
|
53
57
|
private readonly changed;
|
|
54
|
-
/**
|
|
58
|
+
/** What a process started with `secrets`, `vault` or `onePassword` received. */
|
|
55
59
|
readonly secrets?: SandboxResolvedSecret[];
|
|
56
60
|
constructor(transport: RuntimeTransport, summary: SandboxProcessSummary, secrets?: SandboxResolvedSecret[], secretWait?: SecretProcessWaitContext | undefined);
|
|
57
61
|
/** @internal Collect output from the start-stream that created this process. */
|
package/dist/sandbox/process.js
CHANGED
|
@@ -5,6 +5,12 @@ const perf_hooks_1 = require("perf_hooks");
|
|
|
5
5
|
const error_1 = require("../error");
|
|
6
6
|
const process_output_1 = require("./process-output");
|
|
7
7
|
const secret_references_1 = require("./secret-references");
|
|
8
|
+
/** Whether a start delivers secrets, so it goes through the control API. */
|
|
9
|
+
const deliversSecrets = (params) => params.vault !== undefined ||
|
|
10
|
+
params.onePassword !== undefined ||
|
|
11
|
+
(params.secrets !== undefined &&
|
|
12
|
+
params.secrets !== null &&
|
|
13
|
+
Object.keys(params.secrets).length > 0);
|
|
8
14
|
/** Errors from connecting at all; anything else may have reached the API. */
|
|
9
15
|
const CONNECT_ERROR_CODES = new Set(["ECONNREFUSED", "ENOTFOUND", "EAI_AGAIN", "EHOSTUNREACH"]);
|
|
10
16
|
/** The control API's code for a secret process start it could not confirm. */
|
|
@@ -497,7 +503,7 @@ class SandboxProcessesApi {
|
|
|
497
503
|
}
|
|
498
504
|
async exec(input, options) {
|
|
499
505
|
const params = normalizeExecParams(input, options);
|
|
500
|
-
if (
|
|
506
|
+
if (deliversSecrets(params)) {
|
|
501
507
|
return this.execWithSecrets(params);
|
|
502
508
|
}
|
|
503
509
|
const handle = await this.start(params);
|
|
@@ -510,7 +516,7 @@ class SandboxProcessesApi {
|
|
|
510
516
|
}
|
|
511
517
|
async start(input, options) {
|
|
512
518
|
const params = normalizeExecParams(input, options);
|
|
513
|
-
if (
|
|
519
|
+
if (deliversSecrets(params)) {
|
|
514
520
|
return this.startWithSecrets(params);
|
|
515
521
|
}
|
|
516
522
|
const maxOutputBytes = params.maxOutputBytes ?? process_output_1.DEFAULT_MAX_PROCESS_OUTPUT_BYTES;
|
|
@@ -551,7 +557,11 @@ class SandboxProcessesApi {
|
|
|
551
557
|
throw new error_1.HyperbrowserError("Starting a process with secrets requires a sandbox handle");
|
|
552
558
|
}
|
|
553
559
|
const secrets = (0, secret_references_1.serializeSecretReferences)(params.secrets);
|
|
554
|
-
|
|
560
|
+
const vault = params.vault;
|
|
561
|
+
const onePassword = params.onePassword;
|
|
562
|
+
// A clash between env and the vault's variables is reported by the API.
|
|
563
|
+
if (secrets !== undefined)
|
|
564
|
+
(0, secret_references_1.assertNoEnvSecretOverlap)(params.env, secrets);
|
|
555
565
|
const timeoutMs = secretProcessTimeoutMs(params);
|
|
556
566
|
let response;
|
|
557
567
|
try {
|
|
@@ -562,6 +572,8 @@ class SandboxProcessesApi {
|
|
|
562
572
|
timeoutMs,
|
|
563
573
|
runAs: params.runAs,
|
|
564
574
|
secrets,
|
|
575
|
+
vault,
|
|
576
|
+
onePassword,
|
|
565
577
|
}, params.signal);
|
|
566
578
|
}
|
|
567
579
|
catch (error) {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { SandboxSecrets } from "../types/sandbox";
|
|
2
|
+
/** Names of secrets and vaults. */
|
|
2
3
|
export declare const SECRET_NAME_PATTERN: RegExp;
|
|
3
4
|
/** The largest version number the API stores. */
|
|
4
5
|
export declare const MAX_SECRET_VERSION = 2147483647;
|
|
6
|
+
/** An environment variable name the API accepts for a secret or a vault entry. */
|
|
7
|
+
export declare const isSecretEnvName: (name: unknown) => name is string;
|
|
5
8
|
export interface WireSecretReference {
|
|
6
9
|
name: string;
|
|
7
10
|
version?: number | "latest";
|
|
@@ -13,3 +16,4 @@ export interface WireSecretReference {
|
|
|
13
16
|
export declare const serializeSecretReferences: (secrets: SandboxSecrets | undefined) => Record<string, WireSecretReference> | undefined;
|
|
14
17
|
/** An environment variable must come from either `env` or `secrets`, not both. */
|
|
15
18
|
export declare const assertNoEnvSecretOverlap: (env: Record<string, string> | undefined, secrets: Record<string, WireSecretReference>) => void;
|
|
19
|
+
export type { SandboxOnePassword as WireOnePassword } from "../types/sandbox";
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.assertNoEnvSecretOverlap = exports.serializeSecretReferences = exports.MAX_SECRET_VERSION = exports.SECRET_NAME_PATTERN = void 0;
|
|
3
|
+
exports.assertNoEnvSecretOverlap = exports.serializeSecretReferences = exports.isSecretEnvName = exports.MAX_SECRET_VERSION = exports.SECRET_NAME_PATTERN = void 0;
|
|
4
4
|
const error_1 = require("../error");
|
|
5
5
|
const ENV_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
6
|
+
/** The longest environment variable name the API stores. */
|
|
7
|
+
const MAX_ENV_NAME_LENGTH = 256;
|
|
8
|
+
/** Names of secrets and vaults. */
|
|
6
9
|
exports.SECRET_NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,127}$/;
|
|
7
10
|
/** The largest version number the API stores. */
|
|
8
11
|
exports.MAX_SECRET_VERSION = 2147483647;
|
|
9
12
|
const MAX_SECRETS = 32;
|
|
13
|
+
/** An environment variable name the API accepts for a secret or a vault entry. */
|
|
14
|
+
const isSecretEnvName = (name) => typeof name === "string" &&
|
|
15
|
+
name.length <= MAX_ENV_NAME_LENGTH &&
|
|
16
|
+
ENV_NAME_PATTERN.test(name) &&
|
|
17
|
+
name !== "__proto__";
|
|
18
|
+
exports.isSecretEnvName = isSecretEnvName;
|
|
10
19
|
/**
|
|
11
20
|
* Check secret references locally and convert them to the API's
|
|
12
21
|
* `{ name, version? }` shape. Returns undefined when there are none.
|
|
@@ -27,7 +36,7 @@ const serializeSecretReferences = (secrets) => {
|
|
|
27
36
|
}
|
|
28
37
|
const wire = {};
|
|
29
38
|
for (const [env, reference] of entries) {
|
|
30
|
-
if (!
|
|
39
|
+
if (!(0, exports.isSecretEnvName)(env)) {
|
|
31
40
|
throw new error_1.HyperbrowserError(`Invalid environment variable name for a secret: ${env}`);
|
|
32
41
|
}
|
|
33
42
|
const { name, version } = typeof reference === "string" ? { name: reference, version: undefined } : (reference ?? {});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SecretValue } from "./types/secret";
|
|
2
|
+
/**
|
|
3
|
+
* Check a TOTP seed as the platform will read it at fill or process time; the
|
|
4
|
+
* API can't see values, so a bad seed would otherwise only fail then. Seeds
|
|
5
|
+
* under 10 bytes (16 base32 characters) are accepted, though they are
|
|
6
|
+
* unusually short.
|
|
7
|
+
*/
|
|
8
|
+
export declare const checkTotpSeed: (value: string) => void;
|
|
9
|
+
/**
|
|
10
|
+
* The plaintext stored for a secret of `type`, after the platform's rules
|
|
11
|
+
* for every value (1 byte to 32 KiB of UTF-8, no NUL) and the type's own.
|
|
12
|
+
* Types this SDK doesn't know get the common rules only.
|
|
13
|
+
*/
|
|
14
|
+
export declare const secretPlaintext: (type: string, value: SecretValue) => Buffer;
|