Skip to content

feat(agent-vault): add Agent Vault proxies, sessions, access bundles and delegations - #46

Merged
scott-ray-wilson merged 14 commits into
mainfrom
AGE2-179
Nov 4, 2026
Merged

scott-ray-wilson merged 14 commits into
mainfrom
AGE2-179

Conversation

@scott-ray-wilson

@scott-ray-wilson scott-ray-wilson commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Context

This adds Agent Vault to the Node.js SDK, at parity with the Python SDK as of Infisical/python-sdk-official#66. sdk.agentVault() has four groups of methods:

  • Proxies (proxies): list, create, update, delete, rotateToken and revoke. create and update take description, and update removes it when you pass an empty string. An empty allowedHosts array or string removes every allowed host on update, since the API rejects an empty host pattern, and is left out on create.
  • Sessions (sessions): list, get, create, update and revoke. create takes onBehalfOfUserEmail or onBehalfOfUserId to start a session on behalf of a user. Passing both throws an InfisicalSDKError before any request. An empty string is sent, not dropped, so the server rejects it instead of the SDK quietly creating the session for the machine identity. ttl is left out unless you pass it, so the server picks the default: 7d, or 1h for a session on behalf of a user. update always sends label, and null removes it.
  • Access bundles (accessBundles): list, get, create, update and delete, plus listGrantees, listAvailableGrantees, grant and revoke for the API's /members routes. listGrantees and listAvailableGrantees take actorType, to list only users, machine identities or groups. list takes onBehalfOfUserEmail or onBehalfOfUserId, and update removes the description when you pass an empty string. The SDK doesn't manage services, so a service's nested settings, such as its credential, are typed loosely, as the API returns them.
  • Delegations (delegations): list, get, set, delete, addSubjects, removeSubjects and listAvailableSubjects. removeSubjects returns null once it takes out the last user or group, since the API then removes the delegation.

Service hosts and inline services (from Infisical/infisical#9064)

  • Traffic policy: AgentVaultTrafficPolicy has AnyHost and ServiceHosts, the new name of bundle-hosts. The SDK sends ServiceHosts as bundle-hosts, which every Infisical version accepts, and reports bundle-hosts from a version before the rename as ServiceHosts. There's no BundleHosts member, since this SDK has never shipped Agent Vault.
  • Inline services: sessions.create takes services, the inline services to send with the session, and accessBundle is now optional. Each service is typed: an HTTP API with a bearer, basic or passthrough credential, or an MCP server with a bearer credential. Sessions return their inline services without secrets, and a session from a version without inline services gets an empty list. sessions.revoke leaves them out, as the API does.
  • Models: services in access bundles have allowedTools, and user grantees have isOrgMembershipPending, both of which the API already returns.

One access bundle per session (from Infisical/infisical#9099, as in Infisical/python-sdk-official#67): sessions.create sends accessBundle, and sessions have accessBundle instead of an accessBundles list: { id, name }, or null for a session with only inline services. id is null once the bundle is deleted. sessions.revoke leaves it out, as the API does.

Validation errors: a 422 lists its issues in message as an array, so for every method the SDK used to throw a generic error without them. The error message is now the whole response body, so it says what the server refused.

Errors: InfisicalSDKError and InfisicalSDKRequestError are exported from the package root, and InfisicalSDKRequestError has statusCode. Every error keeps the one it came from in cause, a request that times out throws a TimeoutError that says how long it waited, and an error the SDK raises itself isn't wrapped again. An HTTP error's response stays readable as cause.response, but it isn't enumerable, so printing or logging an error leaves out the body. These reach every method of the SDK, not only Agent Vault.

IDs: an empty ID, . or .. is refused before any request. fetch resolves . and .. like directories, so accessBundles.revoke("..") reached the route that removes members from Agent Vault, which takes the same body.

The enums AgentVaultTrafficPolicy, AgentVaultSessionStatus, AgentVaultSessionScope, AgentVaultMemberType and AgentVaultDelegationScope are exported from the package root. Like the Python SDK, each method takes an enum member or its string value.

Retries for creates, grants, revokes and deletes: creating a proxy, a session or an access bundle, rotating a proxy token, granting or revoking an access bundle, deleting a proxy, an access bundle or a delegation, and removing a delegation's users and groups use a new ApiClient.postOnce or ApiClient.deleteOnce, the counterparts of the Python SDK's post_once and delete_once. Grants and revokes say which grantees changed, so after a lost response, a retry would report each one as skipped, and a retried delete would get a 404 for a delete that worked. These methods retry a network error only if the connection never opened: a failed DNS lookup (ENOTFOUND, EAI_AGAIN), a refused connection (ECONNREFUSED), or an unreachable host or network (EHOSTUNREACH, ENETUNREACH). It doesn't retry a request timeout or a dropped connection, since the server may already have handled the request. That includes a connection that stalls before it opens: the SDK's 10-second request timeout fires before undici's connect timeout, and the timeout looks the same whether or not the request was sent. UND_ERR_CONNECT_TIMEOUT stays in the list for the rare case where it does show up. It still retries a 429, as every request does. Other requests retry as before.

For the reviewer

Steps to verify the change

  1. Run npm ci, then npm test and npm run build.
  2. Run Infisical from main, and set the environment variables listed at the top of sink/test-agent-vault.ts: a machine identity with the Admin role in Agent Vault, a machine identity that's a member of Agent Vault without a delegation, and a user who's a member of Agent Vault. Run npx tsx sink/test-agent-vault.ts. Following the steps in feat(agent-vault): sessions on behalf of users, access bundles, delegations and proxy descriptions python-sdk-official#66, it creates an access bundle, grants it to the machine identity and the user, sets a delegation, and creates a session on behalf of the user as the machine identity. On the way it calls every method once, and it deletes what it creates.

Testing done

  • Unit: 157 tests pass, 121 of them new. A route table checks the method, path, query, body and return value of all 27 methods against the routes on Infisical main, and the other new tests port the Python SDK's tests. With each of 24 rules broken on purpose, such as a create that's retried, a dropped empty email, or a 7d default for ttl, only the tests written for that rule fail. For the review changes, each of 14 deliberate breaks fails a test.
  • Built package: the CJS and ESM builds, run against a local HTTP server, send the expected methods, paths, headers and bodies, including a JSON body on DELETE and no body or Content-Type on a POST that takes none.
  • Network errors: the error codes that postOnce retries match what Node 24's fetch reports for a failed DNS lookup and a refused connection. A connection that drops after the request is sent reports UND_ERR_SOCKET, which isn't retried. A create sent to an address that drops packets ends after one attempt, when the SDK's 10-second timeout fires.
  • Live: against a local instance running main with feat(agent-vault): inline services on sessions infisical#9140 (inline services) and improvement(agent-vault): sessions take and return one accessBundle infisical#9099 (one access bundle), sink/test-agent-vault.ts passed all 38 checks on the final code, including service hosts, inline services, and accessBundle on sessions with and without one. 22 extra checks also passed, including two that failed before the validation-error fix, and a shape check of 22 responses matched the SDK's types. 16 more checks covered the review changes: statusCode on a live 404, 403 and 422, refused IDs (the user stayed a grantee and in Agent Vault), actorType and isOrgMembershipPending on live grantees, and, against local servers, one request each for grant and revoke when the connection drops, where proxies.update sends five, and a timeout after 10 seconds with the TimeoutError in cause. 3 more checked accessBundle against #9099: a session reads its bundle back, revoke leaves it out, and a session keeps the bundle's name, with a null id, once the bundle is deleted.

Type

  • Fix
  • Feature
  • Improvement
  • Breaking
  • Docs
  • Chore

Checklist

  • Title follows the conventional commit format: type(scope): short description (scope is optional, e.g., fix: prevent crash on sync or fix(api): handle null response).
  • Tested locally
  • Updated docs (if needed)
  • Updated AGENTS.md files (if needed)
  • Read the contributing guide

🤖 Generated with Claude Code

scott-ray-wilson and others added 3 commits November 2, 2026 18:06
A POST that creates something, such as a session, can't be retried after a
network error once the request may have reached the server: the retry could
create a second one. postOnce retries a network error only if the connection
never opened (a failed DNS lookup, a refused connection, or a connect timeout),
and still retries a rate-limited response. Other requests retry as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and delegations

Adds sdk.agentVault() with proxies, sessions, accessBundles and delegations,
at parity with the Python SDK as of Infisical/python-sdk-official#66,
including sessions on behalf of users and proxy descriptions. Creates and
proxy token rotations use postOnce.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nstance

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@infisical-review-police

Copy link
Copy Markdown

💬 Discussion in Slack: #pr-review-node-sdk-v2-46-feat-agent-vault-add-agent-vault-proxies-sessions-acces

Posted by Review Police — reviews, comments, new commits, and CI failures will stream into this channel.

@linear

linear Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

AGE2-179

AGE2-316

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.

Comment thread src/api/retry.ts Resolved
@greptile-apps

greptile-apps Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5 Tier: plus

[Critical impact] The latest changes appear safe to merge; no new actionable issues were found.

Summary

Adds sdk.agentVault() for proxies, sessions, access bundles, and delegations.

  • The Node SDK can manage Agent Vault proxies, sessions, access bundles, and delegations.
  • SDK errors keep their causes, and selected writes retry only when a connection never opened.

All three supplied previous threads are fully addressed: cleanup handles are saved before checks, failed cleanup names remaining resources, and exported error constructors no longer require ErrorOptions. These threads have no supplied comment numbers.

scott-ray-wilson documents older-server limits and defers publishing JSDoc to a separate change.

Reviews (10) · Last reviewed commit: "fix(agent-vault): send deletes once" · Reviewed by Greptile

Comment thread sink/test-agent-vault.ts Resolved
Comment thread sink/test-agent-vault.ts Resolved
scott-ray-wilson and others added 5 commits November 3, 2026 12:22
…the request timeout

With the SDK's 10-second request timeout, a stalled connection ends in an
AbortError before undici's connect timeout fires, so UND_ERR_CONNECT_TIMEOUT
rarely shows up and the stalled create isn't retried. An abort can't be
retried safely, since it looks the same whether or not the request was sent,
so the comments now say that instead of claiming connect timeouts are retried.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…up can't remove

The live-check script now records each resource as soon as its request
resolves, before checking the response, so a failed check no longer leaks the
proxy, access bundle, delegation or session. Cleanup reports each removal it
couldn't make, with the resource ID, and a failed request names its step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…with 422

Infisical's validation errors (422) list their issues in message as an array
rather than a string, so the SDK threw a generic error without them. The error
message is now the whole response body, so it says what the server refused,
such as a session with more than 20 inline services.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Infisical renamed the bundle-hosts traffic policy to service-hosts and added
inline services, which are services sent with a session instead of added to
an access bundle (Infisical/infisical#9064).

- AgentVaultTrafficPolicy.BundleHosts is now ServiceHosts. The SDK sends it as
  bundle-hosts, which every Infisical version accepts, and reports bundle-hosts
  from a version before the rename as ServiceHosts.
- sessions.create takes services, and accessBundle is optional. Sessions
  return their inline services without secrets, and a session from a version
  without inline services gets an empty list.
- Services in access bundles have allowedTools, and grantees have
  isOrgMembershipPending.
- The live-check script covers service hosts and inline services.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…of its tools

Infisical refuses a non-empty allowedTools on a service sent with a session, so
the JSDoc of the services option now lists that limit with the others, and says
to add the MCP server to an access bundle to limit its tools.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread src/api/endpoints/agent-vault.ts Outdated

const BASE_PATH = "/api/v1/agent-vault";

const segment = (id: string) => encodeURIComponent(id);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

encodeURIComponent("..") stays .., so fetch resolves it and accessBundles.revoke("..", { userIds: [u] }) becomes DELETE /api/v1/agent-vault/members, which removes u from agent vault and every bundle, and the reply has the same { members, skipped } shape. matters for any bot or tool that passes user input as an id. can we have segment throw for ., .. and empty?

const segment = (id: string) => {
  if (!id || id === "." || id === "..") throw new InfisicalSDKError(`Invalid ID "${id}"`);
  return encodeURIComponent(id);
};

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, fixed in af882be. segment now throws an InfisicalSDKError for an empty ID, . and .. before any request, as you suggested. I confirmed that .. resolved to DELETE /api/v1/agent-vault/members with the same body and reply shape, so a revoke would have removed the user from Agent Vault without any sign. An ID like %2e%2e stays one segment, since encodeURIComponent turns % into %25, and a test covers it.

The Python SDK had the same problem, and worse, since it didn't encode IDs at all, so a/../.. got there too. Infisical/python-sdk-official@1540d7d encodes every ID and refuses the same values.

Comment thread src/index.ts
dynamicSecrets = () => this.dynamicSecretsClient;
auth = () => this.authClient;
kms = () => this.kmsClient;
agentVault = () => this.agentVaultClient;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the docs name InfisicalSDKError and InfisicalSDKRequestError, but neither is exported from the package root (the exports at the bottom of this file), so import { InfisicalSDKRequestError } from "@infisical/sdk" fails. can we export both and add a statusCode on the request error? then the delegations.get line in the docs can say statusCode 404 instead of matching [StatusCode=404] in the message.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in af882be. Both classes are exported from the package root, and InfisicalSDKRequestError has statusCode. The message format is unchanged, so code that matches [StatusCode=404] keeps working. The docs now say that delegations.get throws one whose statusCode is 404 (Infisical/infisical@d70053dd8a).

Comment on lines +122 to +132
grant: (accessBundleId: string, data: ChangeAgentVaultAccessBundleGrantsRequest) =>
this.apiClient.post<GrantAgentVaultAccessBundleResponse>(
`${BASE_PATH}/access-bundles/${segment(accessBundleId)}/members`,
data
),

revoke: (accessBundleId: string, data: ChangeAgentVaultAccessBundleGrantsRequest) =>
this.apiClient.delete<RevokeAgentVaultAccessBundleResponse>(
`${BASE_PATH}/access-bundles/${segment(accessBundleId)}/members`,
{ data }
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

grant and revoke go through the retrying post/delete, so if the first call lands and the response is lost, the retry returns { members: [], skipped: [u] } and the caller thinks u already had it. can these not retry once the request may have been sent, like the creates? revoke is a DELETE, so it'd need a no-retry delete next to postOnce.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, fixed in af882be. grant uses postOnce, and revoke uses a new ApiClient.deleteOnce that retries in the same cases. Against a local server that drops the connection after reading the request, each now sends one request, where proxies.update sends five.

I left the other deletes retrying. After a lost response, their retry can fail with a 404, which is an error rather than a wrong answer, and addSubjects returns the whole delegation, so a retry reports the right state. The Python SDK got the same change in Infisical/python-sdk-official@1540d7d.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up: on the Python SDK, Sheen pointed out that a 404 for a delete that worked is a wrong answer too, so I've changed my mind on the deletes. proxies.delete, accessBundles.delete, delegations.delete and delegations.removeSubjects now use deleteOnce as well, in d0754d0.

Comment thread src/custom/errors.ts
@@ -26,12 +26,11 @@ export class InfisicalSDKRequestError extends Error {
export const newInfisicalError = (error: any) => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

at the end of this function (return new InfisicalSDKError(error?.message || "An error occurred")), network errors lose the original error, so a create that timed out and one that was refused only differ by message ("This operation was aborted" vs "fetch failed"). with postOnce the caller now has to decide whether to retry, so it'd help to keep cause and say it timed out:

return new InfisicalSDKError(isTimeout ? "Request timed out after 10s" : error?.message || "An error occurred", { cause: error });

openai-node does the same (APIConnectionError with cause, and "Request timed out.").

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in af882be, with one change: the timeout isn't always 10 seconds, since the AWS auth client uses 5, so the message isn't hardcoded in newInfisicalError. Instead, the request timeout aborts with a TimeoutError that says how long it waited, such as "The request timed out after 10 seconds". Every error now keeps the one it came from in cause, so a caller can tell a timeout (cause.name === "TimeoutError") from a connection that was refused or reset (cause.cause.code). An error the SDK raises itself, such as for passing both an email and an ID, is no longer wrapped a second time.

Comment thread src/api/retry.ts
// connection, or undici's connect timeout. The connect timeout shows up only if it fires before the request
// timeout. With the SDK's 10-second request timeout, a stalled connection ends in an AbortError instead, which
// can't be retried safely, since an abort looks the same whether or not the request was sent.
const CONNECT_ERROR_CODES = new Set([

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EHOSTUNREACH and ENETUNREACH also fail before anything is sent, so postOnce could retry them too. they're in the aws sdk's network error list next to ENOTFOUND and EAI_AGAIN:

"EHOSTUNREACH", "ENETUNREACH",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added both in af882be, and updated the comment above the list.

description?: string;
};

export type ListAgentVaultGranteesOptions = {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the backend takes actorType on both /members and /members/available, but listGrantees and listAvailableGrantees don't expose it, so getting just the groups means paging through everything and filtering locally. can we add actorType?: AgentVaultMemberType to the options, like listAvailableSubjects has?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in af882be. Both methods take actorType with all three member types, and the docs list it. Checked against a local instance: each value returns only that kind of grantee, and the available list leaves out existing grantees. The Python SDK's list_grantees and list_available_grantees got actor_type too.

Comment thread src/api/types/agent-vault.ts Outdated
export type AgentVaultGrantee = (
| (AgentVaultUser & {
/** Whether the user still has an unaccepted invitation to the organization. */
isOrgMembershipPending?: boolean;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isOrgMembershipPending is optional here, but the grantee schema on main always returns it (z.boolean()), and AgentVaultMember below already has it required. can we drop the ??

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in af882be. AgentVaultGrantee is only used by the grantee list, whose schema always returns it.

…filters

- An empty ID, "." or ".." is refused before any request. fetch resolves "."
  and ".." like directories, so accessBundles.revoke("..") reached the route
  that removes members from Agent Vault, which takes the same body.
- accessBundles.grant uses postOnce, and revoke a new ApiClient.deleteOnce, so
  neither is retried once the request may have reached the server. Their
  responses say which grantees changed, so after a lost response, a retry
  would report each one as skipped.
- InfisicalSDKError and InfisicalSDKRequestError are exported from the package
  root, and InfisicalSDKRequestError has statusCode.
- Every error keeps the one it came from in cause, and a request that times
  out throws a TimeoutError that says how long it waited, instead of "This
  operation was aborted". An error the SDK raises itself isn't wrapped again.
- postOnce also retries EHOSTUNREACH and ENETUNREACH, which are raised before
  a connection opens.
- listGrantees and listAvailableGrantees take actorType.
- isOrgMembershipPending is required on grantees, as the API always returns it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scott-ray-wilson added a commit to Infisical/python-sdk-official that referenced this pull request Nov 4, 2026
…r grantees by type

From the review of the same methods in Infisical/node-sdk-v2#46:

- Each ID goes into the path as one encoded segment, and an empty ID, ".",
  ".." or None raises a ValueError before any request. Before, an ID such as
  ".." or "a/../.." reached the route that removes members from Agent Vault,
  which takes the same body as access_bundles.revoke.
- access_bundles.grant uses post_once, and revoke a new delete_once, so
  neither is retried once the request may have reached the server. Their
  responses say which grantees changed, so after a lost response, a retry
  would report each one as skipped.
- list_grantees and list_available_grantees take actor_type.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread src/custom/errors.ts Resolved
scott-ray-wilson and others added 2 commits November 4, 2026 10:57
Matches the session API change in Infisical/infisical#9099 and the Python
SDK's Infisical/python-sdk-official#67. sessions.create sends accessBundle,
and sessions have accessBundle ({ id, name }, or null for a session with only
inline services) instead of an accessBundles list. id is null once the bundle
is deleted, and position is gone. sessions.revoke leaves out accessBundle and
services, as the API does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The error constructors took ErrorOptions, which exists only in TypeScript's
ES2022 library, so a project that compiles the SDK's types against an older
library, with skipLibCheck off, failed with "Cannot find name
'ErrorOptions'". They take { cause?: unknown } instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread src/custom/errors.ts
);
} else if (error.message) {
return new InfisicalSDKError(error.message);
return new InfisicalSDKError(error.message, { cause: error });

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with cause on every error, an uncaught one now prints the whole response body. a 502 from nginx dumped a ~150KB html page into the terminal, where before it was one line. options:

  • make response on FetchHttpError non-enumerable, so err.cause.response.data still works but doesn't print
  • leave it, since it only hits uncaught errors with non-json bodies

leaning the first, your call

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, went with the first option in 85a945f. FetchHttpError.response is no longer enumerable, so err.cause.response.data still returns the body, but printing or logging the error leaves it out. With a 153KB HTML 502 from a local server, an uncaught error now prints 896 characters, down from about 11,000 (Node cuts long strings at 10,000), and a logger that records every property stores 148 characters, down from the whole page. A test covers both: the body is out of util.inspect and still in cause.response.data.

scott-ray-wilson and others added 3 commits November 4, 2026 13:42
Since errors keep the one they came from in cause, an HTTP error's cause holds
the whole response, so an uncaught 502 printed about 10KB of an nginx HTML
page, and a logger that records every property stored all of it.
FetchHttpError.response is now not enumerable: err.cause.response.data still
returns the body, and printing or logging the error leaves it out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…change

Taking users out of a delegation or deleting it doesn't revoke the sessions
created on their behalf: the proxy refuses them until a delegation covers the
users again. The delete and removeSubjects JSDoc now says so, and that
revoking the sessions ends them for good.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
proxies.delete, accessBundles.delete, delegations.delete and
delegations.removeSubjects use deleteOnce, like grants and revokes. After a
lost response, a retry got a 404 for a delete that worked, and removing the
last user or group threw instead of returning null.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@scott-ray-wilson
scott-ray-wilson merged commit dd3cd8d into main Nov 4, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants