@nylorun/agents 0.12.0-beta → 0.14.0-beta
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/CHANGELOG.md +72 -0
- package/README.md +104 -125
- package/dist/access.d.ts +6 -72
- package/dist/access.js +2 -78
- package/dist/ag-ui/handler.d.ts +3 -6
- package/dist/ag-ui/handler.js +2 -2
- package/dist/artifacts.d.ts +116 -0
- package/dist/artifacts.js +116 -0
- package/dist/delivery-token.js +3 -3
- package/dist/http.d.ts +6 -8
- package/dist/http.js +6 -9
- package/dist/index.d.ts +6 -6
- package/dist/index.js +3 -2
- package/dist/sandboxes.d.ts +77 -0
- package/dist/sandboxes.js +100 -0
- package/dist/session-client.d.ts +60 -29
- package/dist/session-client.js +41 -11
- package/dist/sse.js +1 -1
- package/dist/studio-embed.d.ts +1 -1
- package/dist/studio-embed.js +1 -1
- package/package.json +3 -7
- package/dist/browser.d.ts +0 -97
- package/dist/browser.js +0 -277
- package/dist/token-endpoint.d.ts +0 -23
- package/dist/token-endpoint.js +0 -30
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,77 @@
|
|
|
1
1
|
# @nylorun/agents
|
|
2
2
|
|
|
3
|
+
## 0.14.0-beta
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- bd478ee: **Subject tokens, browser keys and derived principals leave open source (F9 I3, protocol 7).** Upgrade these with the Runtime: they speak protocol 7, which this Runtime serves beside 4, 5 and 6; protocol 6 clients keep working on every route that remains. Browsers and apps present a trusted issuer's token (F9 I2), servers an operator key (F9 I1), and a person's own credentials come from the operator's credential resolver (F9 C1). See MIGRATION.md.
|
|
8
|
+
|
|
9
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`): subject tokens are gone.** `POST /v1/tokens`, `POST /v1/access/revocations`, subject-token verification, revocation epochs and the `subject.revoked` stream signal are removed; the routes answer `404`, and a JWT no trusted issuer signed is the opaque `404`. A stream opened with a token now ends only at its expiry (`event: nylorun.closed`, reason `token_expired`; `StreamClosedFrame` loses `revoked`). Migration `0010_oss_auth_removals` drops the `subject_epochs`, `subject_usage` and `publishable_keys` tables. The `token` caller is a trusted issuer's token only: it loses `role`, `limits` and `epoch`, and `issuer` is always set; `GET /v1/me` no longer reports `via: token`. Core drops `SUBJECT_TOKEN_TYPE`, `SUBJECT_TOKEN_AUDIENCE`, `subjectTokenIssuer` (the Runtime's own tokens use `tenantTokenIssuer`, same value), `CreateTokenRequest`/`Response`, `RevokeSubject*`, `SubjectTokenClaims`, `TOKEN_TTL_MIN_SECONDS` and `TOKEN_TTL_DEFAULT_SECONDS`; `TOKEN_SCOPES` is `agents:read`, `sessions:own`, `sandboxes:write`.
|
|
10
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`): the access policy and role limits are gone.** `GET`/`PUT /v1/access/policy` answer `404`, a turn is never refused with `429 limit_exceeded` for a role (limit requests at your proxy), and an existing `access.policy` setting is ignored. Core drops `AccessPolicy*`, `AccessRole*`, `RoleLimits*`, `DEFAULT_ACCESS_POLICY`, `PutAccessPolicyRequest` and `ROLE_NAME_PATTERN`.
|
|
11
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`): publishable keys and the Runtime's CORS are gone.** `/v1/access/publishable-keys*` answer `404`, `Nylorun-Key` is ignored, `NYLORUN_BROWSER_ACCESS` and `browserAccess` (host.json, `createHost`, `startEphemeralRuntime`) are removed, and the Runtime sends no CORS headers. A request with `Origin` reaches the Tenant routes of the public listener with no toggle: a trusted issuer's token is served, an application key or delivery token is `403 origin_rejected`; admin routes, `/health`, `/ready` and the operator listener still refuse `Origin`. Any `OPTIONS` request is `204` with `Allow` and no CORS header: the operator's proxy answers preflights. Route declarations lose `browser` (`x-nylorun-browser` leaves the OpenAPI document) and the `publishable` credential; the token security scheme is `issuerToken`. Core drops `PUBLISHABLE_KEY_HEADER`, `PUBLISHABLE_KEY_PATTERN`, `PUBLISHABLE_KEY_ID_PATTERN`, `tenantOfPublishableKey`, `newPublishableKey`, `newPublishableKeyId`, `PublishableKey*`, `OriginEntrySchema`, `originAllowed` and `LOOPBACK_ORIGIN_WILDCARDS`.
|
|
12
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`, `@nylorun/agents`): vault routes are application-only, and `vaults:own` is retired.** Every `/v1/vaults` route takes an application key acting for no one (operator keys, Studio); a request acting for a subject or a trusted issuer's token gets `403 scope_required`. `vaults:own` leaves `SUBJECT_SCOPES`, `TOKEN_SCOPES` and the issuer scopes; `Nylorun-Scopes` may still name it and it grants nothing. Existing user vaults stay attachable to their own owner's sessions. `client.createVault` takes `{ scope: "installation" }` or `ownerUserId`, and `client.listVaults()` takes an optional owner.
|
|
13
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`, `@nylorun/admin`, `nylorun`): derived principals are gone.** Only Studio's key is derived from the admin key. `NYLORUN_DERIVED_PRINCIPALS` is ignored and no longer written, `hostPrincipals` takes no `derived`, `startEphemeralRuntime` no `derivedPrincipals`, and `@nylorun/admin` drops `deriveTenantKey`, `PROJECT_PRINCIPAL_ID` and `admin.deriveTenantKey`. Keys an earlier Host derived stay in the database and keep working as ordinary keys; replace them with operator keys. Core renames `DERIVED_PRINCIPAL_ID_PATTERN` to `APPLICATION_KEY_ID_PATTERN`.
|
|
14
|
+
- **Breaking (`@nylorun/agents`):** `createTokenEndpoint`, `createBrowserClient` and the `@nylorun/agents/browser` entry, `client.tokens`, `TokensClient`, `PublishableKeysClient`, `client.access.getPolicy`/`putPolicy`/`revokeSubject`/`publishableKeys` and `Destination.publishableKey` are removed. `client.access.signingKeys` and `client.access.jwks()` stay, and `Destination.token` takes a trusted issuer's tokens.
|
|
15
|
+
- **Breaking (`@nylorun/cli`):** `nylo access policy|keys|revoke|token` are removed and name what replaces them; `nylo access signing-keys list|rotate|revoke` stays.
|
|
16
|
+
- **Breaking (`@nylorun/core`, `@nylorun/agents`, `@nylorun/studio`): the Studio embed message `open.babai` is now `open.session`** (`{ sessionId }`): it asks the embedding app to open that session in its own UI. Studio sends no such message itself.
|
|
17
|
+
- **Breaking (`nylorun`): Studio embedding is opt-in.** No origin may frame Studio by default; list your app's origins with `nylorun start --studio-embed-origin <origin>`. A Tenant's `.env` from an earlier nylorun keeps the origins it had until `--studio-embed-origin-reset`.
|
|
18
|
+
- `PROTOCOL_VERSION` is 7 and `HOST_PROTOCOL` 4–7; the Host features `subject-tokens`, `browser-access` and `derived-principals` are removed. `@nylorun/studio` and `@nylorun/create-agent` speak protocol 7.
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- Pin core to the tested release.
|
|
23
|
+
- Updated dependencies [8773586]
|
|
24
|
+
- Updated dependencies [e1bfb4b]
|
|
25
|
+
- Updated dependencies [5cfaed9]
|
|
26
|
+
- Updated dependencies [bd478ee]
|
|
27
|
+
- Updated dependencies [c0b604e]
|
|
28
|
+
- @nylorun/core@0.13.0-beta
|
|
29
|
+
|
|
30
|
+
## 0.13.0-beta
|
|
31
|
+
|
|
32
|
+
### Major Changes
|
|
33
|
+
|
|
34
|
+
- b352feb: **File artifacts, message parts and capability links (protocol 6).** Upgrade these with the Runtime: they speak protocol 6, which this Runtime serves beside 4 and 5. See MIGRATION.md.
|
|
35
|
+
|
|
36
|
+
- **`@nylorun/runtime`: file artifacts.** A file is an artifact: an `af_` id, a name and numbered immutable versions, with rows in the new `artifacts` and `artifact_versions` tables (migration `0004_artifacts`) and bytes in the Object store (`BlobStore`). `POST /v1/artifacts?name=&sessionId=` uploads a file in one streamed request and `POST /v1/artifacts/{id}/versions` adds a version, within the Tenant's limits (`GET`/`PUT /v1/tenant/artifacts`: 100 MiB per file and 10 GiB in all by default); a body past either is `413 limit_exceeded`, refused mid-stream with nothing stored. `GET /v1/artifacts` lists them (by session), `GET /v1/artifacts/{id}` reads one with its versions, `GET /v1/artifacts/{id}/versions/{n|latest}/content` downloads through the Runtime with HTTP Range (`206`, `Content-Range`, `416`), and `DELETE /v1/artifacts/{id}` deletes it with its bytes. A session's artifacts go with it on a sessions reset, and appear in its history as `artifact.created`, `artifact.version.created` and `artifact.deleted` (new in the event catalog). A subject reaches only the artifacts of their own sessions.
|
|
37
|
+
- **`@nylorun/runtime`: capability links.** `POST /v1/artifacts/{id}/links` mints a short-lived path, `/v1/artifact-links/<token>`, that downloads one version (with Range) with no credential and no `Nylorun-Protocol`: an ES256 JWT (`typ: nylorun-artifact+jwt`) signed with the Tenant's signing key, at most 15 minutes, and dead once the artifact is deleted. The Host logs its path without the token.
|
|
38
|
+
- **Breaking (`@nylorun/core`, `@nylorun/runtime`): message `parts`.** A user message may carry `parts`: `text`, and `file` by `artifactId` (and `version`, else the latest, pinned when the message is accepted). Model-gate reads the file from the Object store: an image goes to the model as image input, a text file as text, and any other file fails the call (`invalid_request`). The record and the transcript hold only the reference. The gateway builds its `BlobStore` from `NYLORUN_OBJECT_STORE_*` (the Tenant's `fs` store without it). `PROTOCOL_VERSION` is 6; `HOST_PROTOCOL` is 4–6 and protocol 6 clients require the feature `artifacts`.
|
|
39
|
+
- **`@nylorun/runtime`: `save_artifact`.** A session with a sandbox gets the `nylorun.artifacts` capability, whose `save_artifact` tool saves a sandbox file (`path`) or text (`content`) as an artifact of the session, carrying the turn and tool call on its event.
|
|
40
|
+
- **Breaking (`@nylorun/runtime`): `MediaStore` is removed.** `MediaStore` and `localMedia` leave `@nylorun/runtime/node`, and `piModel` takes `files` (a resolver from an artifact reference to its bytes) instead of `media`; images are file artifacts. The image checks (`decodeImageBase64`, `validateImageBytes`, `IMAGE_MEDIA_TYPES`, `MAX_IMAGE_BYTES`) stay.
|
|
41
|
+
- **`@nylorun/agents`:** `client.artifacts` (`upload`, `uploadVersion`, `list`, `get`, `download` with a range, `link`, `delete`), also on `BrowserClient`, and `session.inputParts(parts)`. A request with a body of its own type keeps it.
|
|
42
|
+
- `@nylorun/admin`, `@nylorun/cli`, `nylorun`, `@nylorun/studio`: speak protocol 6.
|
|
43
|
+
|
|
44
|
+
### Minor Changes
|
|
45
|
+
|
|
46
|
+
- 6077272: **Folder artifacts and the turn-end outputs export (F8.2).** Part of protocol 6, with file artifacts.
|
|
47
|
+
|
|
48
|
+
- **`@nylorun/runtime`: the turn-end export.** When an agent's turn completes, the Runtime reads `/workspace/outputs` of the session's sandbox and keeps it as a version of the session's folder artifact `outputs`: the first export creates it, and each later turn whose outputs changed adds a version (`artifact.created` / `artifact.version.created` with `kind: "folder"`, `source: "export"`, `fileCount` and `claimed: true`, since the listing and bytes are what the sandbox supplied). Nothing is exported without a sandbox or without outputs. An export past 10,000 files, 1 GiB, the per-file limit or the Tenant total stores nothing and records `artifact.export.skipped` with its reason; a failure records `artifact.export.failed`. Neither fails the turn. Core reads the workspace through one seam, `WorkspaceReader`, which the Harness API and pod sandboxes will implement later.
|
|
49
|
+
- **`@nylorun/runtime`: folder artifacts.** A folder version is a manifest of paths to content-addressed files: each file's bytes are stored once at `blobs/sha256/<hex>`, so an unchanged file is never stored again, and the Tenant total (`GET /v1/tenant/artifacts` `usedBytes`) counts it once. New routes: `GET /v1/artifacts/{id}/versions/{n|latest}/tree` (the manifest), `…/files/{path}` (one file by its percent-encoded path, with Range), `…/diff?from=n` (files added, removed and changed) and `…/zip` (a streamed zip). `POST /v1/artifacts/{id}/links` takes `file` to link one file of a folder; a folder's link without it opens the zip. A folder's `/content`, a new version uploaded to a folder, and a message part naming a folder are `400`. Deleting a folder removes the files no other version names. Migration `0006_folder_artifacts` allows the `folder` kind and adds the `artifact_content` table.
|
|
50
|
+
- **`@nylorun/core`:** `ArtifactKindSchema` (`file`, `folder`), the `export` source, `FolderEntrySchema`, `FolderManifestSchema`, `ArtifactTreeSchema`, `ArtifactDiffSchema`, the `artifact.export.skipped` and `artifact.export.failed` events, and `fileCount` and `claimed` on `artifact.created` / `artifact.version.created`.
|
|
51
|
+
- **`@nylorun/agents`:** `client.artifacts.tree()`, `file()`, `diff()` and `zip()`, and `link(id, { file })`.
|
|
52
|
+
|
|
53
|
+
- 926711b: **Sandboxes are a resource (F7.1, blueprint D39; Host feature `sandboxes`).** A sandbox has its own id, a kind, a spec and labels, and outlives the sessions attached to it. Additive: protocol 5 is unchanged.
|
|
54
|
+
|
|
55
|
+
- `PUT /v1/sandboxes/{id}` creates a sandbox or finds the one with that id (get-or-create in one call); `GET /v1/sandboxes/{id}`, `GET /v1/sandboxes?label=key=value` (repeatable), `GET /v1/sandboxes/{id}/events` and `DELETE /v1/sandboxes/{id}`. Ids are `/`-separated segments (`team-a/proj-42`), sent percent-encoded as one path segment. Only kind `virtual` runs; `pod` is refused with `sandbox_unavailable`. The spec is resolved against the Tenant's limits and fixed once the sandbox exists; labels can change.
|
|
56
|
+
- A session attaches with `sandbox: { id }` and shares the sandbox's `/workspace` with every other session attached to it. Turns are serial per sandbox: a second session's turn is refused with `409 sandbox_busy` while another runs. Deleting a session (a sessions reset) only detaches it. Deleting a sandbox is refused while a turn runs in it; afterwards an attached session's next turn is refused with `sandbox_unavailable` until a sandbox with that id exists again.
|
|
57
|
+
- Subject tokens carry an `sbx` claim: `POST /v1/tokens` takes `sandboxes`, exact ids or prefixes ending in `/*` (at most 16). A token reaches only the sandboxes they match, checked when a session attaches and at every turn start (`403 sandbox_not_granted`); any other sandbox is the 404 of a missing one. The new scope `sandboxes:write` lets a role create and delete the sandboxes its grants reach. Application keys reach every sandbox.
|
|
58
|
+
- The Tenant holds at most `limits.sandboxes` sandboxes (`PUT /v1/tenant/sandbox`, default 100); one more is `409 limit_exceeded`.
|
|
59
|
+
- Lifecycle events (`sandbox.created`, `sandbox.attached`, `sandbox.detached`, `sandbox.deleted`) go to the sandbox's own stream in the record, through the record module; the session's log records `sandbox.attached`. The sandbox stream is not relayed to S2.
|
|
60
|
+
- New error codes `sandbox_not_granted`, `sandbox_busy` and `sandbox_unavailable`; the session view gains `sandboxId` and `sandboxSource: "sandbox"`. Migration `0004_sandbox_resources` adds `sandbox_resources`, `nylorun_streams.sandbox_events` and the sessions' `sandbox_id` column.
|
|
61
|
+
- `@nylorun/agents`: `client.sandboxes` with `ensure(id, spec)`, `get`, `list({ labels })`, `delete`, `events`, and `forSession({ session, spec })`, which creates a sandbox for one session, opens the session on it, and deletes it with `release()`. It replaces sharing through another session (`sandbox: { session }` and the view's `sandboxOwnerId`, now deprecated). `client.tokens.create` takes `sandboxes`.
|
|
62
|
+
- `nylorun sandbox ls [--label key=value]... [--json]` and `nylorun sandbox rm <id>` list and delete the running local Tenant's sandboxes.
|
|
63
|
+
|
|
64
|
+
### Patch Changes
|
|
65
|
+
|
|
66
|
+
- Pin core to the tested release.
|
|
67
|
+
- Updated dependencies [b352feb]
|
|
68
|
+
- Updated dependencies [6077272]
|
|
69
|
+
- Updated dependencies [b6bf1f5]
|
|
70
|
+
- Updated dependencies [8ed4ea6]
|
|
71
|
+
- Updated dependencies [678e085]
|
|
72
|
+
- Updated dependencies [926711b]
|
|
73
|
+
- @nylorun/core@0.12.0-beta
|
|
74
|
+
|
|
3
75
|
## 0.12.0-beta
|
|
4
76
|
|
|
5
77
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -107,7 +107,7 @@ eval "$(npx @nylorun/cli env)"
|
|
|
107
107
|
# → NYLORUN_RUNTIME_URL, NYLORUN_SERVER_KEY
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
Every request sets `Nylorun-Protocol` (
|
|
110
|
+
Every request sets `Nylorun-Protocol` (6) and no `Nylorun-Tenant`: the Runtime
|
|
111
111
|
serves one Tenant. Before the first authenticated
|
|
112
112
|
request, `Transport` fetches `/health` once, checks protocol compatibility, and
|
|
113
113
|
throws `IncompatibleRuntimeError` / `incompatible_host` when the Host range or
|
|
@@ -156,7 +156,22 @@ const session = await client.createSession({
|
|
|
156
156
|
|
|
157
157
|
The model gets `bash`, `read`, `write`, `edit`, `grep` and `glob` on a persistent `/workspace`. These tools run in the Runtime, not in your process, so sandbox-only agents need no Action endpoint. The Runtime decides where the sandbox runs: today an emulated shell in the Runtime process, which is not a VM boundary and takes no `image`.
|
|
158
158
|
|
|
159
|
-
`sandbox` takes `false` for none, `{
|
|
159
|
+
`sandbox` takes `false` for none, `{ id }` to attach a sandbox resource (below), or an inline sandbox as above; omit it for the Tenant's default. `{ session }`, sharing another session's sandbox, still works and is deprecated. The Runtime checks it against the Tenant's limits (`GET`/`PUT /v1/tenant/sandbox`: a network ceiling, a resource maximum, the idle timeout) and answers `400` with every problem it finds. A caller acting for a user (`app.as(...)`) can't define one inline; it gets the Tenant's default or `false`. Private networks, loopback, the host and cloud metadata endpoints are always blocked.
|
|
160
|
+
|
|
161
|
+
A sandbox can also be a resource with its own id, which outlives the sessions attached to it (Host feature `sandboxes`). Whether it serves one session, one person or a project is your choice:
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
// One per session: created with the session, deleted by release().
|
|
165
|
+
const { session, release } = await client.sandboxes.forSession({
|
|
166
|
+
session: { agentId: "analyst", ownerUserId },
|
|
167
|
+
spec: { network: { allow: ["pypi.org"] } },
|
|
168
|
+
});
|
|
169
|
+
// One per person or project: get-or-create by id, then attach sessions to it.
|
|
170
|
+
await client.sandboxes.ensure("team-a/proj-42", { labels: { project: "acme" } });
|
|
171
|
+
await client.createSession({ agentId: "analyst", ownerUserId, sandbox: { id: "team-a/proj-42" } });
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Sessions attached to one sandbox share its `/workspace`, and one turn runs in it at a time: a second session's turn is refused with `409 sandbox_busy` until the first ends. Deleting a session only detaches it. A spec is fixed once the sandbox exists; `labels` can change. `client.sandboxes.list({ labels })`, `get(id)` and `delete(id)` manage them, and `npx nylorun sandbox ls | rm` does the same on a local Tenant. A trusted issuer's token reaches only the sandboxes its issuer grants (the identity file's `sandboxes` templates, exact ids or prefixes ending in `/*`), checked at every turn start; creating and deleting through one needs `sandboxes:write`. The Tenant holds at most `limits.sandboxes` of them (`PUT /v1/tenant/sandbox`, default 100).
|
|
160
175
|
|
|
161
176
|
Add an agent with `.subagents()` to let the model delegate to it:
|
|
162
177
|
|
|
@@ -263,7 +278,8 @@ directly and run as before; a flow agent can't be a child of them.
|
|
|
263
278
|
|
|
264
279
|
The agents in a flow share one sandbox: open the flow's session with it,
|
|
265
280
|
`createSession({ …, sandbox: { … } })`, and every agent, tool step and `verify` in the
|
|
266
|
-
flow uses it. Share it with
|
|
281
|
+
flow uses it. Share it with other sessions by opening them all on one sandbox resource
|
|
282
|
+
(`sandbox: { id }`, see `client.sandboxes`), and call
|
|
267
283
|
built-ins via `session.sandbox` (application) or `ctx.sandbox` (a tool).
|
|
268
284
|
Observe with `session.observe({ follow: true })` to merge linked agent streams;
|
|
269
285
|
`pending()` lists waits across the tree. Studio renders the manifest tree and
|
|
@@ -297,9 +313,10 @@ thread is one session per person, agent and thread. There are two ways in:
|
|
|
297
313
|
- **From your own server**, with `@nylorun/agents/ag-ui` (below): your server
|
|
298
314
|
signs people in and the handler forwards each request to the Runtime acting
|
|
299
315
|
for that person. The browser never sees the Runtime.
|
|
300
|
-
- **From the page itself**, with `@
|
|
301
|
-
|
|
302
|
-
through your
|
|
316
|
+
- **From the page itself**, with `@ag-ui/client`'s `HttpAgent` and a `fetch`
|
|
317
|
+
that sends your identity provider's token
|
|
318
|
+
([In the browser](#in-the-browser)). No chat traffic passes through your
|
|
319
|
+
server.
|
|
303
320
|
|
|
304
321
|
Both reach the same threads: one started through the handler continues from
|
|
305
322
|
the page.
|
|
@@ -346,8 +363,7 @@ created, on its first run; later runs keep them. Whatever the browser sends in
|
|
|
346
363
|
- A busy or paused thread ends the run with `RUN_ERROR` code `session_busy`.
|
|
347
364
|
- The handler calls the Runtime as each person (`client.as(subject, { scopes })`,
|
|
348
365
|
below), so the Runtime itself keeps one person out of another's threads.
|
|
349
|
-
`scopes` defaults to `["sessions:own"]
|
|
350
|
-
attaches the person's vaults. A `subject` the Runtime cannot name (see below)
|
|
366
|
+
`scopes` defaults to `["sessions:own"]`. A `subject` the Runtime cannot name (see below)
|
|
351
367
|
answers `500` (`subject_invalid`).
|
|
352
368
|
- The handler needs a Runtime with the optional feature `ag-ui-endpoint` and
|
|
353
369
|
answers `502` (`runtime_feature_missing`) without it. It loads no AG-UI
|
|
@@ -360,8 +376,8 @@ Limitations: assistant text arrives once per model step (no token streaming);
|
|
|
360
376
|
no reasoning, state, activity or subagent events, and an agent used as a tool
|
|
361
377
|
shows only its result; frontend tools in `RunAgentInput.tools` are rejected
|
|
362
378
|
(`400`); one text part per user message; earlier messages cannot be edited or
|
|
363
|
-
regenerated. A browser reaches the Runtime only with a
|
|
364
|
-
|
|
379
|
+
regenerated. A browser reaches the Runtime only with a trusted issuer's token,
|
|
380
|
+
never with a Tenant key.
|
|
365
381
|
|
|
366
382
|
## A2A
|
|
367
383
|
|
|
@@ -426,6 +442,56 @@ What the Runtime answers (Host feature `a2a-endpoint`):
|
|
|
426
442
|
no header the partner chose except `A2A-Version` and `A2A-Extensions`. Without
|
|
427
443
|
`a2a-endpoint` on the Runtime it answers `502` (`runtime_feature_missing`).
|
|
428
444
|
|
|
445
|
+
## Files: artifacts and message parts
|
|
446
|
+
|
|
447
|
+
Files users upload or agents make are **artifacts** (protocol 6): an id, a name and
|
|
448
|
+
numbered versions, kept by the Runtime. `client.artifacts` uploads a file in one
|
|
449
|
+
streamed request, lists, downloads with Range, mints capability links and deletes;
|
|
450
|
+
a message names files in its `parts`, and the model reads an image as an image and
|
|
451
|
+
a text file as text:
|
|
452
|
+
|
|
453
|
+
```ts
|
|
454
|
+
const { artifact } = await client.artifacts.upload(file, { name: "room.png", sessionId });
|
|
455
|
+
await session.inputParts(
|
|
456
|
+
[{ type: "text", text: "Redesign this room" }, { type: "file", artifactId: artifact.artifactId }],
|
|
457
|
+
{ idempotencyKey: crypto.randomUUID() },
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
const files = await client.artifacts.list({ sessionId }); // what the user and the agent saved
|
|
461
|
+
const part = await client.artifacts.download(files[0].artifactId, { range: { start: 0, end: 1023 } });
|
|
462
|
+
const { url } = await client.artifacts.link(files[0].artifactId); // no credential needed, 5 minutes
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
A session with a sandbox gives the agent `save_artifact`, which saves a file it
|
|
466
|
+
made as an artifact of the session; each new artifact or version appears in the
|
|
467
|
+
session's events as `artifact.created` or `artifact.version.created`. The Tenant's
|
|
468
|
+
limits (`PUT /v1/tenant/artifacts`: 100 MiB per file and 10 GiB in all by default)
|
|
469
|
+
refuse a larger upload with `413 limit_exceeded`, and nothing is stored. Acting for
|
|
470
|
+
a person (`as()`, or a trusted issuer's token), a client reaches only the artifacts of that
|
|
471
|
+
person's sessions, and an upload names one of them.
|
|
472
|
+
|
|
473
|
+
### Outputs: folder artifacts
|
|
474
|
+
|
|
475
|
+
At the end of each turn, the Runtime exports the files the agent wrote into
|
|
476
|
+
`/workspace/outputs` of its sandbox as a version of the session's **folder**
|
|
477
|
+
artifact `outputs` (kind `folder`): the first export creates it, and each later
|
|
478
|
+
turn whose outputs changed adds a version, announced by `artifact.created` or
|
|
479
|
+
`artifact.version.created` with `source: "export"`. A file that did not change is
|
|
480
|
+
stored once. Read a folder as a tree, one file by path, a diff or a zip:
|
|
481
|
+
|
|
482
|
+
```ts
|
|
483
|
+
const outputs = (await client.artifacts.list({ sessionId })).find((a) => a.kind === "folder");
|
|
484
|
+
const { entries } = await client.artifacts.tree(outputs.artifactId); // [{ path, size, sha256, contentType }]
|
|
485
|
+
const page = await client.artifacts.file(outputs.artifactId, "app/index.html", { range: { start: 0 } });
|
|
486
|
+
const { added, removed, changed } = await client.artifacts.diff(outputs.artifactId, { from: 1 });
|
|
487
|
+
const zip = await client.artifacts.zip(outputs.artifactId); // a streamed Response
|
|
488
|
+
const { url } = await client.artifacts.link(outputs.artifactId, { file: "app/index.html" }); // or the zip without `file`
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
An export past a limit (10,000 files, 1 GiB, the per-file limit or the Tenant
|
|
492
|
+
total) stores nothing and records `artifact.export.skipped`; the turn still
|
|
493
|
+
completes.
|
|
494
|
+
|
|
429
495
|
## Acting for a person (app servers)
|
|
430
496
|
|
|
431
497
|
A server that signs people in and calls the Runtime for them (an "app server")
|
|
@@ -437,147 +503,58 @@ import { createClient } from "@nylorun/agents";
|
|
|
437
503
|
const app = createClient(); // the Tenant key, on the server only
|
|
438
504
|
|
|
439
505
|
// Per request, after your own sign-in:
|
|
440
|
-
const person = app.as(`app:${user.id}`, { scopes: ["sessions:own"
|
|
506
|
+
const person = app.as(`app:${user.id}`, { scopes: ["sessions:own"] });
|
|
441
507
|
await person.createSession({ agentId: "support", ownerUserId: `app:${user.id}` });
|
|
442
508
|
await person.listSessions(); // only this person's sessions
|
|
443
509
|
```
|
|
444
510
|
|
|
445
511
|
`as()` sends `Nylorun-Subject` and `Nylorun-Scopes` on every call, event
|
|
446
512
|
streams included, and the Runtime (optional feature `subject-headers`)
|
|
447
|
-
enforces both: another person's sessions
|
|
448
|
-
|
|
513
|
+
enforces both: another person's sessions answer the same `404` as missing
|
|
514
|
+
ones, and a route outside the scopes answers `403` (`scope_required`).
|
|
449
515
|
Nothing is minted, cached or refreshed, and the copy shares the client's
|
|
450
516
|
compatibility check, so calling `as()` per request is cheap.
|
|
451
517
|
|
|
452
518
|
| Scope | Allows |
|
|
453
519
|
| --- | --- |
|
|
454
|
-
| `sessions:own` | The person's own sessions: create, list, read, stream, message, approve, respond, cancel |
|
|
455
|
-
| `vaults:own` | The person's own vaults and credentials |
|
|
520
|
+
| `sessions:own` | The person's own sessions: create, list, read, stream, message, approve, respond, cancel; and their artifacts |
|
|
456
521
|
| `agents:read` | Listing the Tenant's agents |
|
|
457
522
|
| `agents:write` | Saving agents; listing agents, models and providers |
|
|
458
523
|
| `tenant:settings` | The Tenant's status, model provider and sandbox settings |
|
|
459
524
|
|
|
460
|
-
No scope reaches Tenant reset, config seed, Action endpoints, actions or
|
|
461
|
-
tool routes; call those without `as()`.
|
|
525
|
+
No scope reaches Tenant reset, config seed, Action endpoints, actions, vaults or
|
|
526
|
+
the sandbox tool routes; call those without `as()`. Vaults are the
|
|
527
|
+
installation's (`createVault({ scope: "installation", … })`); a person's own
|
|
528
|
+
credentials come from your credential resolver
|
|
529
|
+
([DEPLOYMENT.md](../DEPLOYMENT.md#credentials)). A subject is 1–200 visible ASCII
|
|
462
530
|
characters (spaces only inside) and `host` is reserved. Your server must drop
|
|
463
531
|
any `Nylorun-*` header its own clients send, and only an application key can act
|
|
464
532
|
for a subject.
|
|
465
533
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
(optional feature `subject-tokens`). What a token may do comes from the Tenant's
|
|
471
|
-
access policy, not from the caller:
|
|
472
|
-
|
|
473
|
-
```ts
|
|
474
|
-
import { createClient } from "@nylorun/agents";
|
|
475
|
-
|
|
476
|
-
const app = createClient(); // the Tenant key, on the server only
|
|
477
|
-
|
|
478
|
-
// Once: roles, their agents and limits (or `nylo access policy init`).
|
|
479
|
-
await app.access.putPolicy({
|
|
480
|
-
version: 1,
|
|
481
|
-
roles: {
|
|
482
|
-
user: {
|
|
483
|
-
scopes: ["sessions:own", "agents:read"],
|
|
484
|
-
agents: ["support"],
|
|
485
|
-
limits: { turnsPerHour: 60, concurrentTurns: 2 },
|
|
486
|
-
},
|
|
487
|
-
},
|
|
488
|
-
anon: { scopes: [], agents: [] },
|
|
489
|
-
tokens: { maxTtlSeconds: 600 },
|
|
490
|
-
});
|
|
491
|
-
|
|
492
|
-
// Per signed-in person, from a same-origin POST route:
|
|
493
|
-
const { token, expiresAt } = await app.tokens.create({
|
|
494
|
-
subject: `app:${user.id}`,
|
|
495
|
-
role: "user",
|
|
496
|
-
});
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
The client sends it as `Authorization: Bearer <token>`.
|
|
500
|
-
Tokens carry only `sessions:own`, `vaults:own` and `agents:read`, live at most
|
|
501
|
-
15 minutes, and see only `{ agentId, name, description }` of their role's
|
|
502
|
-
agents. A token that expired or was revoked answers `401` with
|
|
503
|
-
`code: "token_expired"`: fetch a new one and retry. Starting more turns than the
|
|
504
|
-
role allows answers `429` with `code: "limit_exceeded"` and `Retry-After`.
|
|
505
|
-
|
|
506
|
-
| Call | Does |
|
|
507
|
-
| --- | --- |
|
|
508
|
-
| `app.access.revokeSubject(subject)` | Ends every token minted so far for the person and their open event streams |
|
|
509
|
-
| `app.access.signingKeys.rotate()` | Rotates the Tenant's signing keys without signing anyone out (`{ force: true }` for incidents) |
|
|
510
|
-
| `app.access.signingKeys.list()`, `.revoke(kid)`, `app.access.jwks()` | Inspect and retire keys; the public keys |
|
|
511
|
-
|
|
512
|
-
Keep tokens in memory on the client, never in `localStorage`, and serve the
|
|
513
|
-
minting route without CORS. `nylo access …` does the same from the terminal.
|
|
514
|
-
|
|
515
|
-
`createTokenEndpoint` is that route, ready to mount (Next.js, Hono or any
|
|
516
|
-
`Request` → `Response` handler):
|
|
517
|
-
|
|
518
|
-
```ts
|
|
519
|
-
import { createTokenEndpoint } from "@nylorun/agents";
|
|
520
|
-
|
|
521
|
-
export const POST = createTokenEndpoint({
|
|
522
|
-
client: app,
|
|
523
|
-
role: "user",
|
|
524
|
-
subject: (request) => userFromCookie(request)?.id,
|
|
525
|
-
});
|
|
526
|
-
```
|
|
534
|
+
The Tenant's signing keys sign delivery tokens and capability links:
|
|
535
|
+
`app.access.signingKeys.list()`, `.rotate()` (`{ force: true }` for incidents),
|
|
536
|
+
`.revoke(kid)` and `app.access.jwks()`, or `nylo access signing-keys …` from the
|
|
537
|
+
terminal.
|
|
527
538
|
|
|
528
539
|
## In the browser
|
|
529
540
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
token: () => fetch("/api/nylorun/token", { method: "POST" }).then((r) => r.json()),
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
const session = await nylo.createSession({ agentId: "support" }); // owned by the token's subject
|
|
544
|
-
await session.input("Where is my order?", { idempotencyKey: crypto.randomUUID() });
|
|
545
|
-
for await (const event of session.observe()) console.log(event.type);
|
|
546
|
-
```
|
|
547
|
-
|
|
548
|
-
For a chat UI, `agUi()` gives `@ag-ui/client`'s `HttpAgent` a `fetch` with the
|
|
549
|
-
key and a current token:
|
|
550
|
-
|
|
551
|
-
```ts
|
|
552
|
-
import { HttpAgent } from "@ag-ui/client";
|
|
553
|
-
|
|
554
|
-
const { url, fetch } = nylo.agUi("support");
|
|
555
|
-
const agent = new HttpAgent({
|
|
556
|
-
url,
|
|
557
|
-
fetch,
|
|
558
|
-
threadId,
|
|
559
|
-
initialMessages: await nylo.agUiHistory("support", threadId),
|
|
560
|
-
});
|
|
561
|
-
```
|
|
562
|
-
|
|
563
|
-
When the Runtime ends a run's stream because the token expired or was revoked,
|
|
564
|
-
that `fetch` reattaches from the last event with a new token, so the agent sees
|
|
565
|
-
one run. A person's token may attach their own vaults to a new thread
|
|
566
|
-
(`forwardedProps: { nylorun: { session: { vaultIds } } }`) but not set `info`.
|
|
567
|
-
|
|
568
|
-
The client keeps the token in memory, fetches a new one a minute before it
|
|
569
|
-
expires or when the Runtime answers `401 token_expired`, and never asks for two
|
|
570
|
-
at once. Event streams that the Runtime ends at token expiry or revocation
|
|
571
|
-
reconnect from their last event with a new token. Create a publishable key per
|
|
572
|
-
app with the origins that serve it (`http://localhost:*` for development);
|
|
573
|
-
requests from other origins get the opaque `404`.
|
|
541
|
+
A web page or an app calls the Runtime directly with the JWT your identity
|
|
542
|
+
provider gave the person: list the provider in the Runtime's identity file
|
|
543
|
+
([Trusted issuers](../DEPLOYMENT.md#trusted-issuers)), and the Runtime takes the
|
|
544
|
+
token's subject, scopes, agents and sandbox grants from it. Nylorun mints no
|
|
545
|
+
token and ships no browser client: use your provider's SDK for sign-in and send
|
|
546
|
+
the token as `Authorization: Bearer <token>` with `Nylorun-Protocol`, through a
|
|
547
|
+
reverse proxy that answers CORS (the Runtime sends no CORS headers). An expired
|
|
548
|
+
token answers `401` with `code: "token_expired"`; `GET /v1/me` shows what a token
|
|
549
|
+
renders to. For a chat UI, give `@ag-ui/client`'s `HttpAgent` a `fetch` that adds
|
|
550
|
+
those headers.
|
|
574
551
|
|
|
575
|
-
The SDK depends only on core within the Nylorun packages; installing it does not install harness or any AG-UI or A2A package. Use `/define`, `/client`, `/ag-ui
|
|
552
|
+
The SDK depends only on core within the Nylorun packages; installing it does not install harness or any AG-UI or A2A package. Use `/define`, `/client`, `/ag-ui` or `/a2a` for focused imports, or the root for convenience. Studio uses `/client`. See [the adopted host contract](../harness/HOST_CONTRACT.md).
|
|
576
553
|
|
|
577
554
|
## Embedding Studio (desktop apps)
|
|
578
555
|
|
|
579
556
|
`@nylorun/agents/studio-embed` is the contract between Studio and an app that
|
|
580
|
-
shows it in an iframe
|
|
557
|
+
shows it in an iframe. It exports the message schema
|
|
581
558
|
(`StudioEmbedMessageSchema`, envelope `{ type: "nylorun.studio", protocol, kind }`),
|
|
582
559
|
the login-token and session schemas, `STUDIO_EMBED_PROTOCOLS` and
|
|
583
560
|
`parseFrameAncestors`.
|
|
@@ -596,4 +573,6 @@ window.addEventListener("message", (event) => {
|
|
|
596
573
|
The embedder's backend mints the login token with the admin key
|
|
597
574
|
(`mintStudioLoginToken` in `@nylorun/admin`) and the page passes it to Studio in
|
|
598
575
|
`init`. No key reaches the page. Studio's origin allowlist is
|
|
599
|
-
`NYLORUN_STUDIO_FRAME_ANCESTORS
|
|
576
|
+
`NYLORUN_STUDIO_FRAME_ANCESTORS`, empty by default: list your app's origins with
|
|
577
|
+
`nylorun start --studio-embed-origin <origin>`. The message `open.session`
|
|
578
|
+
(`{ sessionId }`) asks the embedding app to open that session in its own UI.
|
package/dist/access.d.ts
CHANGED
|
@@ -1,30 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* revocations. Each call checks the Host feature before sending anything.
|
|
2
|
+
* The Tenant's signing keys and public keys, for app servers on the application key. The
|
|
3
|
+
* Runtime signs delivery tokens (Action endpoints) and capability links with them; an Action
|
|
4
|
+
* endpoint verifies delivery tokens with the public keys (`jwks`).
|
|
6
5
|
*/
|
|
7
|
-
import type {
|
|
6
|
+
import type { Jwks, SigningKeyView } from "@nylorun/core/contracts";
|
|
8
7
|
import { type Transport } from "./http.js";
|
|
9
|
-
export interface CreateTokenOptions {
|
|
10
|
-
/** The person the token is for, e.g. `app:42`. */
|
|
11
|
-
subject: string;
|
|
12
|
-
/** A role of the Tenant's access policy. */
|
|
13
|
-
role: string;
|
|
14
|
-
/** Narrow the role's scopes. Default: all of the role's scopes. */
|
|
15
|
-
scopes?: readonly TokenScope[];
|
|
16
|
-
/** Narrow the role's agents. Default: all of the role's agents. */
|
|
17
|
-
agents?: readonly string[];
|
|
18
|
-
/** 60 to 900 seconds, at most the policy's `maxTtlSeconds`. Default: that maximum. */
|
|
19
|
-
ttlSeconds?: number;
|
|
20
|
-
signal?: AbortSignal;
|
|
21
|
-
}
|
|
22
|
-
export declare class TokensClient {
|
|
23
|
-
private readonly transport;
|
|
24
|
-
constructor(transport: Transport);
|
|
25
|
-
/** Mints a subject token. Only the application key may; never acting for a subject. */
|
|
26
|
-
create(options: CreateTokenOptions): Promise<CreateTokenResponse>;
|
|
27
|
-
}
|
|
28
8
|
export declare class SigningKeysClient {
|
|
29
9
|
private readonly transport;
|
|
30
10
|
constructor(transport: Transport);
|
|
@@ -33,7 +13,7 @@ export declare class SigningKeysClient {
|
|
|
33
13
|
}): Promise<SigningKeyView[]>;
|
|
34
14
|
/**
|
|
35
15
|
* standby → current → previous → revoked, and a new standby. Refused while the previous key
|
|
36
|
-
* may still verify live tokens; `force` skips that and
|
|
16
|
+
* may still verify live tokens; `force` skips that and ends those tokens.
|
|
37
17
|
*/
|
|
38
18
|
rotate(options?: {
|
|
39
19
|
force?: boolean;
|
|
@@ -44,57 +24,11 @@ export declare class SigningKeysClient {
|
|
|
44
24
|
signal?: AbortSignal;
|
|
45
25
|
}): Promise<SigningKeyView>;
|
|
46
26
|
}
|
|
47
|
-
/**
|
|
48
|
-
* Publishable keys (Host feature `browser-access`): shipped in a web page or an app, they name
|
|
49
|
-
* the Tenant and the app, and list the origins a browser may use them from.
|
|
50
|
-
*/
|
|
51
|
-
export declare class PublishableKeysClient {
|
|
52
|
-
private readonly transport;
|
|
53
|
-
constructor(transport: Transport);
|
|
54
|
-
list(options?: {
|
|
55
|
-
signal?: AbortSignal;
|
|
56
|
-
}): Promise<PublishableKey[]>;
|
|
57
|
-
/**
|
|
58
|
-
* A new key. `origins` are exact origins (`https://app.example.com`) or
|
|
59
|
-
* `http://localhost:*`; `[]` allows native apps only.
|
|
60
|
-
*/
|
|
61
|
-
create(options: {
|
|
62
|
-
name: string;
|
|
63
|
-
origins: readonly string[];
|
|
64
|
-
signal?: AbortSignal;
|
|
65
|
-
}): Promise<PublishableKey>;
|
|
66
|
-
/** Replaces the key's origins. */
|
|
67
|
-
update(keyId: string, options: {
|
|
68
|
-
origins: readonly string[];
|
|
69
|
-
signal?: AbortSignal;
|
|
70
|
-
}): Promise<PublishableKey>;
|
|
71
|
-
/** Revokes the key: every request that sends it gets the opaque 404. */
|
|
72
|
-
revoke(keyId: string, options?: {
|
|
73
|
-
signal?: AbortSignal;
|
|
74
|
-
}): Promise<PublishableKey>;
|
|
75
|
-
}
|
|
76
27
|
export declare class AccessClient {
|
|
77
28
|
private readonly transport;
|
|
78
29
|
readonly signingKeys: SigningKeysClient;
|
|
79
|
-
readonly publishableKeys: PublishableKeysClient;
|
|
80
30
|
constructor(transport: Transport);
|
|
81
|
-
|
|
82
|
-
signal?: AbortSignal;
|
|
83
|
-
}): Promise<AccessPolicy>;
|
|
84
|
-
putPolicy(policy: AccessPolicy, options?: {
|
|
85
|
-
signal?: AbortSignal;
|
|
86
|
-
}): Promise<AccessPolicy>;
|
|
87
|
-
/**
|
|
88
|
-
* Ends every token minted so far for `subject` and its open streams. Running turns continue;
|
|
89
|
-
* cancel them separately if they must stop.
|
|
90
|
-
*/
|
|
91
|
-
revokeSubject(subject: string, options?: {
|
|
92
|
-
signal?: AbortSignal;
|
|
93
|
-
}): Promise<{
|
|
94
|
-
subject: string;
|
|
95
|
-
epoch: number;
|
|
96
|
-
}>;
|
|
97
|
-
/** The public keys that verify the Tenant's subject tokens. */
|
|
31
|
+
/** The public keys that verify the Tenant's delivery tokens. */
|
|
98
32
|
jwks(options?: {
|
|
99
33
|
signal?: AbortSignal;
|
|
100
34
|
}): Promise<Jwks>;
|
package/dist/access.js
CHANGED
|
@@ -1,111 +1,35 @@
|
|
|
1
1
|
import { id, segment } from "./http.js";
|
|
2
|
-
const FEATURE = "subject-tokens";
|
|
3
|
-
export class TokensClient {
|
|
4
|
-
transport;
|
|
5
|
-
constructor(transport) {
|
|
6
|
-
this.transport = transport;
|
|
7
|
-
}
|
|
8
|
-
/** Mints a subject token. Only the application key may; never acting for a subject. */
|
|
9
|
-
async create(options) {
|
|
10
|
-
await this.transport.requireFeature(FEATURE, options.signal);
|
|
11
|
-
return this.transport.json("/v1/tokens", "POST", {
|
|
12
|
-
requestId: id(),
|
|
13
|
-
subject: options.subject,
|
|
14
|
-
role: options.role,
|
|
15
|
-
...(options.scopes ? { scopes: [...options.scopes] } : {}),
|
|
16
|
-
...(options.agents ? { agents: [...options.agents] } : {}),
|
|
17
|
-
...(options.ttlSeconds === undefined ? {} : { ttlSeconds: options.ttlSeconds }),
|
|
18
|
-
}, options.signal);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
2
|
export class SigningKeysClient {
|
|
22
3
|
transport;
|
|
23
4
|
constructor(transport) {
|
|
24
5
|
this.transport = transport;
|
|
25
6
|
}
|
|
26
7
|
async list(options = {}) {
|
|
27
|
-
await this.transport.requireFeature(FEATURE, options.signal);
|
|
28
8
|
const reply = await this.transport.json("/v1/access/signing-keys", "GET", undefined, options.signal);
|
|
29
9
|
return reply.keys;
|
|
30
10
|
}
|
|
31
11
|
/**
|
|
32
12
|
* standby → current → previous → revoked, and a new standby. Refused while the previous key
|
|
33
|
-
* may still verify live tokens; `force` skips that and
|
|
13
|
+
* may still verify live tokens; `force` skips that and ends those tokens.
|
|
34
14
|
*/
|
|
35
15
|
async rotate(options = {}) {
|
|
36
|
-
await this.transport.requireFeature(FEATURE, options.signal);
|
|
37
16
|
const reply = await this.transport.json("/v1/access/signing-keys/rotate", "POST", { requestId: id(), ...(options.force ? { force: true } : {}) }, options.signal);
|
|
38
17
|
return reply.keys;
|
|
39
18
|
}
|
|
40
19
|
/** Revokes a previous or standby key; the current key must be rotated first. */
|
|
41
20
|
async revoke(keyId, options = {}) {
|
|
42
|
-
await this.transport.requireFeature(FEATURE, options.signal);
|
|
43
21
|
return this.transport.json(`/v1/access/signing-keys/${segment(keyId)}/revoke`, "POST", { requestId: id() }, options.signal);
|
|
44
22
|
}
|
|
45
23
|
}
|
|
46
|
-
/**
|
|
47
|
-
* Publishable keys (Host feature `browser-access`): shipped in a web page or an app, they name
|
|
48
|
-
* the Tenant and the app, and list the origins a browser may use them from.
|
|
49
|
-
*/
|
|
50
|
-
export class PublishableKeysClient {
|
|
51
|
-
transport;
|
|
52
|
-
constructor(transport) {
|
|
53
|
-
this.transport = transport;
|
|
54
|
-
}
|
|
55
|
-
async list(options = {}) {
|
|
56
|
-
await this.transport.requireFeature("browser-access", options.signal);
|
|
57
|
-
const reply = await this.transport.json("/v1/access/publishable-keys", "GET", undefined, options.signal);
|
|
58
|
-
return reply.keys;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* A new key. `origins` are exact origins (`https://app.example.com`) or
|
|
62
|
-
* `http://localhost:*`; `[]` allows native apps only.
|
|
63
|
-
*/
|
|
64
|
-
async create(options) {
|
|
65
|
-
await this.transport.requireFeature("browser-access", options.signal);
|
|
66
|
-
return this.transport.json("/v1/access/publishable-keys", "POST", { requestId: id(), name: options.name, origins: [...options.origins] }, options.signal);
|
|
67
|
-
}
|
|
68
|
-
/** Replaces the key's origins. */
|
|
69
|
-
async update(keyId, options) {
|
|
70
|
-
await this.transport.requireFeature("browser-access", options.signal);
|
|
71
|
-
return this.transport.json(`/v1/access/publishable-keys/${segment(keyId)}`, "PUT", { requestId: id(), origins: [...options.origins] }, options.signal);
|
|
72
|
-
}
|
|
73
|
-
/** Revokes the key: every request that sends it gets the opaque 404. */
|
|
74
|
-
async revoke(keyId, options = {}) {
|
|
75
|
-
await this.transport.requireFeature("browser-access", options.signal);
|
|
76
|
-
return this.transport.json(`/v1/access/publishable-keys/${segment(keyId)}`, "DELETE", undefined, options.signal);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
24
|
export class AccessClient {
|
|
80
25
|
transport;
|
|
81
26
|
signingKeys;
|
|
82
|
-
publishableKeys;
|
|
83
27
|
constructor(transport) {
|
|
84
28
|
this.transport = transport;
|
|
85
29
|
this.signingKeys = new SigningKeysClient(transport);
|
|
86
|
-
this.publishableKeys = new PublishableKeysClient(transport);
|
|
87
|
-
}
|
|
88
|
-
async getPolicy(options = {}) {
|
|
89
|
-
await this.transport.requireFeature(FEATURE, options.signal);
|
|
90
|
-
const reply = await this.transport.json("/v1/access/policy", "GET", undefined, options.signal);
|
|
91
|
-
return reply.policy;
|
|
92
|
-
}
|
|
93
|
-
async putPolicy(policy, options = {}) {
|
|
94
|
-
await this.transport.requireFeature(FEATURE, options.signal);
|
|
95
|
-
const reply = await this.transport.json("/v1/access/policy", "PUT", { requestId: id(), policy }, options.signal);
|
|
96
|
-
return reply.policy;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Ends every token minted so far for `subject` and its open streams. Running turns continue;
|
|
100
|
-
* cancel them separately if they must stop.
|
|
101
|
-
*/
|
|
102
|
-
async revokeSubject(subject, options = {}) {
|
|
103
|
-
await this.transport.requireFeature(FEATURE, options.signal);
|
|
104
|
-
return this.transport.json("/v1/access/revocations", "POST", { requestId: id(), subject }, options.signal);
|
|
105
30
|
}
|
|
106
|
-
/** The public keys that verify the Tenant's
|
|
31
|
+
/** The public keys that verify the Tenant's delivery tokens. */
|
|
107
32
|
async jwks(options = {}) {
|
|
108
|
-
await this.transport.requireFeature(FEATURE, options.signal);
|
|
109
33
|
return this.transport.json("/v1/access/jwks", "GET", undefined, options.signal);
|
|
110
34
|
}
|
|
111
35
|
}
|