@oh-my-pi/pi-ai 18.3.5 → 18.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/CHANGELOG.md +47 -48
  2. package/README.md +12 -0
  3. package/dist/types/auth/blocks.d.ts +10 -19
  4. package/dist/types/auth/cascade.d.ts +1 -1
  5. package/dist/types/auth/oauth.d.ts +2 -2
  6. package/dist/types/auth/refresh.d.ts +3 -3
  7. package/dist/types/auth/rotation.d.ts +6 -3
  8. package/dist/types/auth/store.d.ts +4 -2
  9. package/dist/types/auth/types.d.ts +43 -6
  10. package/dist/types/auth/usage-cache.d.ts +22 -3
  11. package/dist/types/auth/usage.d.ts +8 -7
  12. package/dist/types/auth-broker/client.d.ts +4 -3
  13. package/dist/types/auth-broker/remote-store.d.ts +7 -8
  14. package/dist/types/auth-broker/types.d.ts +3 -1
  15. package/dist/types/auth-broker/wire-schemas.d.ts +2 -1
  16. package/dist/types/auth-retry.d.ts +22 -13
  17. package/dist/types/error/rate-limit.d.ts +3 -2
  18. package/dist/types/images/types.d.ts +9 -0
  19. package/dist/types/judgment/types.d.ts +3 -2
  20. package/dist/types/providers/cursor/exec-modern.d.ts +1 -1
  21. package/dist/types/providers/cursor-pi-args.d.ts +10 -0
  22. package/dist/types/providers/cursor.d.ts +6 -2
  23. package/dist/types/providers/google-shared.d.ts +13 -2
  24. package/dist/types/stream.d.ts +7 -0
  25. package/dist/types/usage/claude-reset.d.ts +6 -0
  26. package/dist/types/usage/claude.d.ts +6 -0
  27. package/dist/types/usage/cursor.d.ts +3 -1
  28. package/dist/types/usage/zai.d.ts +2 -0
  29. package/dist/types/usage.d.ts +8 -0
  30. package/dist/types/utils/proxy.d.ts +2 -2
  31. package/package.json +6 -6
  32. package/src/auth/blocks.ts +79 -37
  33. package/src/auth/cascade.ts +6 -4
  34. package/src/auth/oauth.ts +4 -3
  35. package/src/auth/refresh.ts +105 -16
  36. package/src/auth/resets.ts +108 -40
  37. package/src/auth/rotation.ts +62 -21
  38. package/src/auth/select.ts +20 -3
  39. package/src/auth/store.ts +4 -0
  40. package/src/auth/types.ts +50 -5
  41. package/src/auth/usage-cache.ts +55 -8
  42. package/src/auth/usage.ts +97 -44
  43. package/src/auth-broker/client.ts +21 -3
  44. package/src/auth-broker/remote-store.ts +132 -29
  45. package/src/auth-broker/server.ts +27 -1
  46. package/src/auth-broker/types.ts +4 -1
  47. package/src/auth-broker/wire-schemas.ts +7 -0
  48. package/src/auth-gateway/dispatch.ts +1 -0
  49. package/src/auth-retry.ts +55 -29
  50. package/src/error/rate-limit.ts +23 -3
  51. package/src/images/openai-hosted.ts +18 -3
  52. package/src/images/types.ts +9 -0
  53. package/src/judgment/types.ts +10 -6
  54. package/src/judgment/typesafe.ts +2 -2
  55. package/src/providers/anthropic.ts +115 -66
  56. package/src/providers/cowork-fetch.ts +45 -3
  57. package/src/providers/cursor/exec-modern.ts +1 -0
  58. package/src/providers/cursor/proto/agent.proto +5 -0
  59. package/src/providers/cursor-pi-args.ts +14 -0
  60. package/src/providers/cursor.ts +66 -28
  61. package/src/providers/devin.ts +43 -13
  62. package/src/providers/google-gemini-cli.ts +2 -19
  63. package/src/providers/google-shared.ts +30 -22
  64. package/src/providers/ollama.ts +2 -0
  65. package/src/providers/openai-completions.ts +122 -30
  66. package/src/registry/oauth/oauth.html +206 -185
  67. package/src/stream.ts +52 -1
  68. package/src/usage/claude-reset.ts +45 -11
  69. package/src/usage/claude.ts +84 -49
  70. package/src/usage/cursor.ts +43 -1
  71. package/src/usage/devin.ts +8 -7
  72. package/src/usage/registry.ts +2 -1
  73. package/src/usage/zai.ts +20 -0
  74. package/src/usage.ts +8 -0
  75. package/src/utils/proxy.ts +3 -3
  76. package/src/utils/schema/CONSTRAINTS.md +30 -28
  77. package/src/utils/schema/normalize.ts +1 -1
  78. package/src/utils/schema/wire.ts +3 -3
package/CHANGELOG.md CHANGED
@@ -2,6 +2,52 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.4.1] - 2026-09-28
6
+
7
+ ### Fixed
8
+
9
+ - Fixed extension-provided usage reports missing from broker-connected clients when the broker does not have that provider ([#13579](https://github.com/can1357/oh-my-pi/issues/13579)).
10
+ - Fixed signed LiteLLM `thinking_blocks` being dropped on openai-completions tool-call turns ([#13407](https://github.com/can1357/oh-my-pi/issues/13407)).
11
+ - Fixed Anthropic turns ending on a bare `aborted` error with no retry when the connection dropped mid-response (typically during long thinking). The first-party Anthropic transport runs on `node:https`, whose Bun shim reports a response cut off mid-body as `Error("aborted")` (ECONNRESET) — indistinguishable from a cancellation, so it classified as unknown. It now surfaces as "The socket connection was closed unexpectedly…", the same wording native `fetch` uses, so the drop classifies as transient and the turn is retried; caller aborts keep their original error ([#13384](https://github.com/can1357/oh-my-pi/pull/13384) by [@jerryfane](https://github.com/jerryfane))
12
+ - Fixed a stale Z.AI quota block pinning sessions to a fallback model after live usage recovered ([#13343](https://github.com/can1357/oh-my-pi/issues/13343)).
13
+ - Fixed OAuth credentials being re-minted on every provider 401 during an outage; recently minted tokens are reused for auth recovery ([#13350](https://github.com/can1357/oh-my-pi/issues/13350)) ([#13485](https://github.com/can1357/oh-my-pi/pull/13485) by [@ShivamB25](https://github.com/ShivamB25)).
14
+ - Fixed Claude usage reports intermittently dropping an account's saved resets when the separate reset probe was rate-limited or timed out; the last known saved resets now stay visible until the probe answers again ([#13474](https://github.com/can1357/oh-my-pi/pull/13474) by [@schickling-assistant](https://github.com/schickling-assistant))
15
+ - Fixed transient Windows `EPERM` when creating the provider in-flight lock failing the request instead of retrying ([#13334](https://github.com/can1357/oh-my-pi/pull/13334) by [@1Morganmore](https://github.com/1Morganmore)).
16
+ - Fixed rolling per-minute TPM/RPM 429s worded as quota errors being treated as exhausted quota and ending the turn ([#13253](https://github.com/can1357/oh-my-pi/issues/13253)).
17
+ - Fixed keyless Anthropic-compatible endpoints receiving `Authorization: Bearer N/A` and `X-Api-Key: N/A` headers ([#13043](https://github.com/can1357/oh-my-pi/pull/13043) by [@jchanghong023](https://github.com/jchanghong023)).
18
+ - Fixed legacy Windsurf Enterprise API keys being rejected because they were always sent with the Devin session-token prefix ([#12960](https://github.com/can1357/oh-my-pi/pull/12960)).
19
+ - Fixed an exhausted Cursor "Other Models" pool blocking Grok and Composer, which Cursor bills to its own pool ([#13198](https://github.com/can1357/oh-my-pi/issues/13198)).
20
+ - Fixed Anthropic OAuth requests leaving the agent system prompt without its own cache breakpoint: the breakpoint on the short Claude Code identity block now moves to the last system block, so a request whose messages miss the cache (such as the first after a compaction) reads the cached system prompt instead of writing it again ([#13104](https://github.com/can1357/oh-my-pi/issues/13104), [#13556](https://github.com/can1357/oh-my-pi/pull/13556) by [@aktanazat](https://github.com/aktanazat)).
21
+ - Fixed the Anthropic system cache breakpoint covering working-directory-specific system text: it now sits before the first `<project-context>` or `<memories>` block, and on OAuth it replaces the identity-block breakpoint instead of taking a message breakpoint ([#13104](https://github.com/can1357/oh-my-pi/issues/13104)).
22
+
23
+ ## [18.4.0] - 2026-09-28
24
+
25
+ ### Breaking Changes
26
+
27
+ - Changed `LimitsApi.rotate()` to return a `CredentialRotation` object (`{ switched, afterSiblingWait? }`) instead of a boolean. Check `.switched` explicitly, since the returned object is always truthy.
28
+
29
+ ### Added
30
+
31
+ - Added image metadata to hosted OpenAI image-generation results, including the model used and each generated image’s dimensions and quality.
32
+
33
+ ### Changed
34
+
35
+ - Redesigned the browser page displayed during OAuth login.
36
+
37
+ ### Fixed
38
+
39
+ - Fixed Anthropic accounts remaining blocked after quota resets, including for broker-connected clients, while preserving independent authentication and model-limit restrictions.
40
+ - Fixed concurrent usage refreshes repeatedly probing providers after failures, reducing unnecessary usage-endpoint requests.
41
+ - Fixed Gemini and Antigravity usage and cost reporting when upstream responses omit prompt-token counts or report more cached tokens than prompt tokens.
42
+ - Fixed credential failover after authentication errors so stored credentials rotate through every distinct sibling instead of stopping after one attempt; rotation can also wait briefly for a temporarily blocked healthy sibling to become available.
43
+ - Fixed native judge responses without token counts producing invalid usage and cost values.
44
+ - Fixed Cursor usage, cost, and context accounting to include final input, cache, reasoning, and output metrics, improving compaction and handoff sizing.
45
+ - Fixed Cursor MCP tool calls routed through external executors being returned as text instead of tool calls.
46
+ - Fixed Cursor shell-tool timeouts being displayed in milliseconds rather than seconds.
47
+ - Fixed fetch requests over Unix sockets when `PI_PROXY` is configured.
48
+ - Fixed Ollama chat turns being recorded with zero cost; usage is now priced using the model’s cost information.
49
+ - Fixed Anthropic requests failing after native compaction when per-message effort settings were present; effort controls are now handled correctly with compaction.
50
+
5
51
  ## [18.3.5] - 2026-09-27
6
52
 
7
53
  ### Breaking Changes
@@ -2276,51 +2322,4 @@
2276
2322
  - Fixed explicit request-debug mode to overwrite existing `.res.log` files for the requested path instead of failing when they already exist
2277
2323
  - Fixed OpenAI Responses `previous_response_id` chaining on Zero Data Retention orgs: the in-provider retry classifier missed the ZDR-specific 400 ("Previous response cannot be used for this organization due to Zero Data Retention"), so chained turns kept failing every other request after a brief recovery — the chain was reset but not disabled, so the next successful full-replay turn re-armed it. The ZDR phrasing is now classified categorically: one strike disables chaining for the session (skipping the three-strike circuit breaker) and the in-call retry drops `store: true`/`previous_response_id` and replays the full transcript instead ([#2341](https://github.com/can1357/oh-my-pi/issues/2341)).
2278
2324
 
2279
- ## [15.11.4] - 2026-06-12
2280
-
2281
- ### Added
2282
-
2283
- - Codex/Responses providers now map `end_turn: false` on the terminal stream event (Codex backend signal for "response ended, turn didn't" — commentary-only progress updates) to `stopDetails: { type: "pause_turn" }` with stopReason `"stop"`, so the agent loop can re-sample instead of ending the turn. Wired in `openai-codex-responses` and `processResponsesStream` (`openai-responses`/`azure-openai-responses`); inert for backends that never send the field.
2284
- - Added Codex upstream protocol features to `openai-codex-responses` (tracking codex-rs as of June 2026): `onModerationMetadata` callback surfacing `response.metadata` → `openai_chatgpt_moderation_metadata` on both transports; `reasoningContext` option emitting `reasoning.context` (`auto`/`current_turn`/`all_turns`); `clientMetadata` option emitting `client_metadata` in the request body (canonical `x-codex-turn-metadata` envelope) without breaking the websocket append fast-path; and an opt-in `responsesLite` mode mirroring codex-rs — lite header on HTTP requests and the websocket upgrade, `ws_request_header_*` marker in `response.create` client metadata, lite-keyed socket pooling, image-detail stripping, forced serial tool calls, and `reasoning.context: all_turns` default. Dormant until OpenAI flips `use_responses_lite` in the model catalog.
2285
- - Added `withOAuthAccess` — the `withAuth` counterpart for OAuth-access consumers: runs an operation through the central a/b/c auth-retry policy (resolve → force-refresh same account → rotate to a sibling) while handing the attempt the full `OAuthAccess` (bearer plus `accountId`/`projectId`/`enterpriseUrl` identity metadata). Use it instead of hand-rolled `getOAuthAccess` + fetch flows so 401s and usage-limits rotate credentials instead of failing the call.
2286
- - Added `ProviderHttpError` — a typed HTTP error carrying `status`, `headers`, and `code` — replacing the ad-hoc `as Error & { status?... }` / `Object.assign` hacks at provider throw sites, with per-provider subclasses `CodexApiError`, `AuthGatewayError`, `GoogleApiError`, `GeminiCliApiError`, `OllamaApiError`, and `BedrockApiError`; `AnthropicApiError` now extends it. Google, Gemini CLI, Ollama, and Bedrock HTTP errors now also carry response headers, so server-suggested `retry-after` delays are visible to retry classification on those paths. The internal `withHttpStatus` helper was removed.
2287
- - Added stateful SSE turn chaining for OpenAI Codex (on by default; disable with `PI_CODEX_STATEFUL=0` or `statefulResponses: false`): SSE requests now reuse `previous_response_id` with delta-only input instead of replaying the full transcript, mirroring the websocket fast-path via a shared transport-aware builder. Any history mutation or option change falls back to a full replay; a server-side `previous_response_not_found` (HTTP or in-stream) resets the chain and retries the turn with full context, and three consecutive stale failures disable chaining for the session.
2288
- - Added stateful `previous_response_id` chaining to the platform OpenAI Responses provider (`openai-responses`): on by default against the official api.openai.com endpoint (forces `store: true`, which chaining requires), off for other Responses endpoints; override with `statefulResponses` or `PI_OPENAI_STATEFUL`. Chain detection compares the wire form of the conversation arguments alone — per-turn trailing scaffolding such as the GPT-5 "Juice: 0" developer item is excluded from the append-baseline prefix check and re-appended to the delta — and a rejected/stale previous response falls back to a one-shot full replay with the same circuit breaker.
2289
- - Added `AuthStorage.getOAuthAccountIdentity()` and the `OAuthAccountIdentity` type — a read-only lookup returning the `accountId`/`email`/`projectId` of the OAuth credential a session is currently routed to, for display and metadata paths.
2290
-
2291
- ### Changed
2292
-
2293
- - The GPT-5 "Juice: 0" no-reasoning developer item in `applyResponsesReasoningParams` is now gated on the resolved `compat.requiresJuiceZeroHack` flag (auto-detected from GPT-5-family model names by `@oh-my-pi/pi-catalog`, overridable per model) instead of an inline model-name check.
2294
-
2295
- ### Fixed
2296
-
2297
- - Fixed websocket append fast-path to remain usable when only `client_metadata` changes between turns
2298
- - Fixed `onModerationMetadata` handling so exceptions thrown by callback observers no longer terminate the response stream
2299
- - Fixed local SQLite OAuth credential caches returning a stale Anthropic access token after another `omp` process refreshed and persisted the same row. `AuthStorage` now syncs the selected row from storage before returning or force-refreshing OAuth credentials, so concurrent sessions pick up peer-rotated tokens instead of surfacing a one-turn `401 Invalid authentication credentials`.
2300
- - Fixed forced OAuth preflight refresh failures being swallowed silently in credential selection; they now emit a debug log (`OAuth preflight refresh failed`) so stale-refresh-token replays from concurrent sessions are diagnosable.
2301
-
2302
- ## [15.11.3] - 2026-06-11
2303
-
2304
- ### Fixed
2305
-
2306
- - Fixed GitHub Copilot long-context model requests to use the upstream `requestModelId` when calling Anthropic, OpenAI Responses, and OpenAI Completions APIs
2307
- - Fixed GitHub Copilot model enablement to deduplicate catalog variants by upstream model ID when enabling all models
2308
-
2309
- ## [15.11.2] - 2026-06-11
2310
-
2311
- ### Fixed
2312
-
2313
- - Fixed Anthropic encoding of error tool results with whitespace-only content so requests no longer 400 with `tool_result: content cannot be empty if is_error is true`
2314
-
2315
- ## [15.11.1] - 2026-06-11
2316
-
2317
- ### Changed
2318
-
2319
- - Exported `resolveAnthropicMetadataUserId` so non-streaming Anthropic Messages consumers (e.g. the coding-agent web search provider) can produce the same Claude-Code-shaped `metadata.user_id` as the main streaming path.
2320
-
2321
- ### Fixed
2322
-
2323
- - Preserved Anthropic `stop_details` on assistant messages so refusal and sensitive classifier stops remain structurally visible to callers. ([#2290](https://github.com/can1357/oh-my-pi/issues/2290))
2324
- - Fixed OpenAI Responses, Azure OpenAI Responses, and OpenAI Completions streams hanging until the 120s idle watchdog errored the turn when a provider delivers the terminal frame but never sends `[DONE]` nor closes the connection. `processResponsesStream` now breaks out of the event loop on `response.completed`/`response.incomplete` (mirroring the Codex websocket/SSE terminal break), and the completions consumer breaks once `finish_reason` plus a usage payload arrived — or, for hosts that never send usage, ends the stream cleanly via a short post-finish grace window (`iterateWithTerminalGrace`) that aborts the transport to release the socket.
2325
-
2326
- Older entries are archived in [packages/ai/CHANGELOG.md@d58593a30902](https://github.com/can1357/oh-my-pi/blob/d58593a3090258473304608d68ffd1f620e6b695/packages/ai/CHANGELOG.md).
2325
+ Older entries are archived in [packages/ai/CHANGELOG.md@dfbf3cc34eeb](https://github.com/can1357/oh-my-pi/blob/dfbf3cc34eeb5653580f51bfbcae558a9840f697/packages/ai/CHANGELOG.md).
package/README.md CHANGED
@@ -1161,6 +1161,18 @@ const response = await complete(
1161
1161
  );
1162
1162
  ```
1163
1163
 
1164
+ When an auth-broker client requests recovery after a provider rejects an OAuth
1165
+ bearer, the broker may reuse a still-fresh token that it minted in the previous
1166
+ five minutes instead of rotating the refresh token again. The process-local
1167
+ cache is bound to the credential ID and access token. Scheduled expiry refreshes,
1168
+ direct forced refreshes such as MCP recovery, ordinary hard-auth blocks, and
1169
+ sibling rotation keep their existing behavior. Cached refresh responses rebind
1170
+ by durable credential ID so concurrent row removal cannot switch a pinned
1171
+ session to another account.
1172
+ Generic `forceRefresh: true` requests do not opt into reuse. Provider-401 retry
1173
+ paths pass `refreshReason: "auth-recovery"` explicitly; expiry sentinels and
1174
+ usage polling do not imply that reason.
1175
+
1164
1176
  ### Provider Notes
1165
1177
 
1166
1178
  **OpenAI Codex**: Requires a ChatGPT Plus or Pro subscription. Provides access to GPT-5.x Codex models with extended context windows and reasoning capabilities. The library automatically handles session-based prompt caching when `sessionId` is provided in stream options.
@@ -11,6 +11,10 @@ export declare const DEFAULT_BLOCK_MS = 60000;
11
11
  export declare function providerTypeKey(provider: string, type: AuthCredential["type"]): string;
12
12
  /** Scoped backoff map key used by the credential block store. */
13
13
  export declare function scopedBackoffKey(providerKey: string, blockScope: string | undefined): string;
14
+ /** Authentication backoffs apply to every model and cannot be healed by quota evidence. */
15
+ export declare const AUTH_BLOCK_SCOPE = "auth";
16
+ /** Account-policy backoffs apply to every model and survive quota resets. */
17
+ export declare const ACCOUNT_POLICY_BLOCK_SCOPE = "account-policy";
14
18
  /** Scope key for one model-specific account-policy block, shared by selectors and rate limits. */
15
19
  export declare function modelAccountPolicyBlockScope(provider: string, modelId: string | undefined): string | undefined;
16
20
  /** Scope keys that a request must check, including model-policy constraints. */
@@ -67,26 +71,15 @@ export declare class CredentialBlocks implements BlocksApi {
67
71
  * that `markUsageLimitReached` set for the now-obsolete reset time.
68
72
  */
69
73
  clearAll(provider: string, credentialId: number): void;
70
- /**
71
- * Clear one backoff scope. The in-memory backoff is per scope so it is
72
- * dropped directly; the persisted store deletes a credential's blocks as a
73
- * unit, so it is only purged once no other scope still holds a live block.
74
- * Leaving a persisted row behind is safe: the scope it belongs to is
75
- * unblocked in memory, and the row heals on the pass where its own meter
76
- * recovers.
77
- */
78
- clearScope(provider: string, credentialId: number, providerKey: string, blockScope: string | undefined): void;
74
+ /** Clear exactly one quota scope, preserving unrelated account and model blocks. */
75
+ clearScope(provider: string, credentialId: number, providerKey: string, blockScope: string | undefined): boolean;
79
76
  /** Providers whose stale usage-limit blocks a healthy live report may clear. */
80
77
  supportsHealing(provider: Provider): boolean;
81
78
  /**
82
79
  * Whether a fresh report could lift what currently blocks this credential.
83
80
  *
84
- * A strategy that names healable scopes can only vouch for those scopes, so
85
- * a live unscoped block — an Opus/Sonnet usage limit, a refresh failure —
86
- * keeps the credential unusable whatever the report says about a tier. A
87
- * probe then cannot change the outcome and must not be spent; the tier scope
88
- * heals on a later pass, once the block that actually holds the credential
89
- * has lifted.
81
+ * Claude reports can heal legacy account-wide quota blocks too. Explicit
82
+ * auth/account-policy blocks never justify a usage probe.
90
83
  */
91
84
  canHeal(provider: Provider, providerKey: string, credentialIndex: number, blockScopeOrScopes: string | readonly string[] | undefined): boolean;
92
85
  /**
@@ -107,9 +100,7 @@ export declare class CredentialBlocks implements BlocksApi {
107
100
  * Broker-server seam: persist one credential block and notify snapshot waiters.
108
101
  */
109
102
  upsert(block: StoredCredentialBlock): void;
110
- /**
111
- * Broker-server seam: clear all persisted blocks for one credential and notify snapshot waiters.
112
- */
113
- delete(credentialId: number, providerKey: string, blockScope: string): void;
103
+ /** Broker-server seam: clear exactly one persisted and local block and notify snapshot waiters. */
104
+ delete(credentialId: number, providerKey: string, blockScope: string, invalidateUsage?: boolean): void;
114
105
  deleteAll(credentialId: number): void;
115
106
  }
@@ -1,4 +1,4 @@
1
- import type { ApiKeyResolver, ResolvedApiKey } from "../auth-retry.js";
1
+ import { type ApiKeyResolver, type ResolvedApiKey } from "../auth-retry.js";
2
2
  import type { SessionAffinity } from "./affinity.js";
3
3
  import type { CredentialPool } from "./pool.js";
4
4
  import type { CredentialSelector } from "./select.js";
@@ -5,7 +5,7 @@ import type { AccountPolicies } from "./policy.js";
5
5
  import type { CredentialPool } from "./pool.js";
6
6
  import type { OAuthRefresher } from "./refresh.js";
7
7
  import type { CredentialSelector } from "./select.js";
8
- import type { AuthAccountPolicy, AuthApiKeyOptions, OAuthAccess, OAuthAccessResolution, OAuthAccountIdentity, OAuthAccountSummary, OAuthApi, OAuthCredential, OAuthLoginController, OAuthLoginIdentity, StoredOAuthRefreshOptions, StoredOAuthRefreshResult, AuthCredentialSnapshotEntry } from "./types.js";
8
+ import type { AuthAccountPolicy, AuthApiKeyOptions, AuthCredentialSnapshotEntry, OAuthAccess, OAuthAccessResolution, OAuthAccountIdentity, OAuthAccountSummary, OAuthApi, OAuthCredential, OAuthLoginController, OAuthLoginIdentity, OAuthRefreshByIdOptions, StoredOAuthRefreshOptions, StoredOAuthRefreshResult } from "./types.js";
9
9
  /** Dependencies used by the OAuth account operations. */
10
10
  export interface OAuthAccountsDeps {
11
11
  pool: CredentialPool;
@@ -87,7 +87,7 @@ export declare class OAuthAccounts implements OAuthApi {
87
87
  */
88
88
  policy(provider: string, identity: OAuthAccountIdentity): AuthAccountPolicy | undefined;
89
89
  /** Force-refresh one stored credential by its durable row id. */
90
- refresh(id: number, signal?: AbortSignal): Promise<AuthCredentialSnapshotEntry>;
90
+ refresh(id: number, signal?: AbortSignal, options?: OAuthRefreshByIdOptions): Promise<AuthCredentialSnapshotEntry>;
91
91
  /** Refresh one stored OAuth credential through the durable ownership path. */
92
92
  refreshStored<T extends OAuthCredential = OAuthCredential>(provider: string, options: StoredOAuthRefreshOptions<T>): Promise<StoredOAuthRefreshResult<T>>;
93
93
  }
@@ -3,7 +3,7 @@ import type { Provider } from "../types.js";
3
3
  import { type CredentialPool } from "./pool.js";
4
4
  import type { AccountPolicies } from "./policy.js";
5
5
  import { type AuthCredentialStore } from "./store.js";
6
- import { type AuthCredentialSnapshotEntry, type AuthStorageOptions, type OAuthCredential, type StoredOAuthRefreshOptions, type StoredOAuthRefreshResult } from "./types.js";
6
+ import { type AuthCredentialSnapshotEntry, type AuthStorageOptions, type OAuthCredential, type OAuthRefreshByIdOptions, type OAuthRefreshReason, type StoredOAuthRefreshOptions, type StoredOAuthRefreshResult } from "./types.js";
7
7
  /**
8
8
  * Refresh OAuth access tokens this many ms before their stated expiry. The
9
9
  * skew exists so callers downstream of {@link OAuthRefresher} (stream providers,
@@ -48,12 +48,12 @@ export declare class OAuthRefresher {
48
48
  * continuing.
49
49
  */
50
50
  disableDefinitiveFailure(provider: string, credentialId: number | undefined, attemptedCredential: OAuthCredential, index: number, errorMsg: string): Promise<"disabled" | "peer-rotated" | "cas-lost">;
51
- refresh(provider: Provider, credential: OAuthCredential, credentialId: number | undefined, signal?: AbortSignal): Promise<OAuthCredentials>;
51
+ refresh(provider: Provider, credential: OAuthCredential, credentialId: number | undefined, signal?: AbortSignal, reason?: OAuthRefreshReason): Promise<OAuthCredentials>;
52
52
  /**
53
53
  * Refresh the OAuth credential with the given id through a per-credential
54
54
  * single-flight. Concurrent callers for the same row await the same upstream
55
55
  * refresh attempt, which is required for providers that rotate refresh tokens
56
56
  * on every successful refresh.
57
57
  */
58
- refreshById(id: number, signal?: AbortSignal): Promise<AuthCredentialSnapshotEntry>;
58
+ refreshById(id: number, signal?: AbortSignal, options?: OAuthRefreshByIdOptions): Promise<AuthCredentialSnapshotEntry>;
59
59
  }
@@ -5,7 +5,7 @@ import type { KeyOverrides } from "./cascade.js";
5
5
  import type { SessionAffinity } from "./affinity.js";
6
6
  import type { CredentialPool } from "./pool.js";
7
7
  import type { AuthCredentialStore } from "./store.js";
8
- import type { InvalidateCredentialMatchingOptions, LimitsApi, MarkUsageLimitOptions, RotateCredentialOptions, UsageLimitMarkResult } from "./types.js";
8
+ import type { CredentialRotation, InvalidateCredentialMatchingOptions, LimitsApi, MarkUsageLimitOptions, RotateCredentialOptions, UsageLimitMarkResult } from "./types.js";
9
9
  import type { UsageService } from "./usage.js";
10
10
  /** Routing scope and strategy for one failed credential. */
11
11
  export type CredentialBlockRouting = {
@@ -60,7 +60,10 @@ export declare class RateLimits implements LimitsApi {
60
60
  * reload when no broker hook is wired) and block it, then drop matching
61
61
  * sticky state.
62
62
  *
63
- * Returns whether another usable credential of the same type remains.
63
+ * For usage-limit and account-policy failures with no free sibling, sleeps
64
+ * until the earliest sibling unblocks when that is at most
65
+ * {@link SIBLING_UNBLOCK_WAIT_MAX_MS} away, then reports `afterSiblingWait`.
66
+ * Aborting `options.signal` during that wait rejects.
64
67
  */
65
- rotate(provider: string, sessionId: string | undefined, options?: RotateCredentialOptions): Promise<boolean>;
68
+ rotate(provider: string, sessionId: string | undefined, options?: RotateCredentialOptions): Promise<CredentialRotation>;
66
69
  }
@@ -1,7 +1,7 @@
1
1
  import type { OAuthCredentials } from "../registry/oauth/types.js";
2
2
  import type { Provider } from "../types.js";
3
3
  import type { ClientUsageIdentity, ClientUsageReport, ClientUsageSummary, ObservedUsageEntry, UsageHistoryEntry, UsageHistoryQuery, UsageReport } from "../usage.js";
4
- import type { AuthCredential, DisabledCredentialSummary, OAuthCredential, StoredAuthCredential, StoredCredentialBlock } from "./types.js";
4
+ import type { AuthCredential, DisabledCredentialSummary, OAuthCredential, OAuthRefreshReason, StoredAuthCredential, StoredCredentialBlock } from "./types.js";
5
5
  /** Owner and timestamp that fence a durable credential refresh lease. */
6
6
  export interface CredentialRefreshLeaseFence {
7
7
  owner: string;
@@ -128,8 +128,10 @@ export interface CredentialUpstream {
128
128
  * `signal` propagates the agent's cancel (ESC, request abort, …) all the
129
129
  * way to the broker fetch so a hung connection can't strand the caller
130
130
  * for `timeoutMs * (maxRetries + 1)`.
131
+ * `reason` distinguishes provider-auth recovery from generic/MCP refreshes
132
+ * that must always mint a new access token.
131
133
  */
132
- refreshOAuthCredential(provider: Provider, credentialId: number, credential: OAuthCredential, signal?: AbortSignal): Promise<OAuthCredentials>;
134
+ refreshOAuthCredential(provider: Provider, credentialId: number, credential: OAuthCredential, signal?: AbortSignal, reason?: OAuthRefreshReason): Promise<OAuthCredentials>;
133
135
  /**
134
136
  * Optional async pre-read hook invoked after AuthStorage selects a stored
135
137
  * credential but before it returns that credential for an outbound request.
@@ -272,6 +272,8 @@ export interface CredentialDisabledEvent {
272
272
  orgId?: string;
273
273
  orgName?: string;
274
274
  }
275
+ /** Why a delegated OAuth refresh was requested. */
276
+ export type OAuthRefreshReason = "auth-recovery";
275
277
  /** Configuration supplied when constructing credential storage. */
276
278
  export type AuthStorageOptions = {
277
279
  usageProviderResolver?: (provider: Provider) => UsageProvider | undefined;
@@ -301,11 +303,14 @@ export type AuthStorageOptions = {
301
303
  * per-provider local refresh function. Receives the credential id so the
302
304
  * implementation can address remote credentials.
303
305
  *
306
+ * `reason` is `"auth-recovery"` only for a provider-auth retry; generic and
307
+ * managed MCP force-refresh calls leave it unset.
308
+ *
304
309
  * Must return updated {@link OAuthCredentials} with at least `access` and
305
310
  * `expires`. `refresh` may be an opaque sentinel (e.g. `"__remote__"`) when
306
311
  * the actual refresh token never leaves the broker.
307
312
  */
308
- refreshOAuthCredential?: (provider: Provider, credentialId: number, credential: OAuthCredential, signal?: AbortSignal) => Promise<OAuthCredentials>;
313
+ refreshOAuthCredential?: (provider: Provider, credentialId: number, credential: OAuthCredential, signal?: AbortSignal, reason?: OAuthRefreshReason) => Promise<OAuthCredentials>;
309
314
  /**
310
315
  * Human-readable description of the credential store backing this
311
316
  * AuthStorage instance. Surfaced through {@link AuthStorage.keys.describe}
@@ -414,6 +419,8 @@ export type AuthApiKeyOptions = {
414
419
  * that a peer/broker rotated out from under us is replaced before retrying.
415
420
  */
416
421
  forceRefresh?: boolean;
422
+ /** Explicit provider-401 recovery; generic force refreshes leave this unset. */
423
+ refreshReason?: OAuthRefreshReason;
417
424
  };
418
425
  /**
419
426
  * Refreshed OAuth access plus identity metadata returned by
@@ -564,6 +571,10 @@ export interface ResetCreditRedeemOutcome {
564
571
  /** One stored account's live saved-reset status, from {@link AuthStorage.resets.list}. */
565
572
  export interface ResetCreditAccountStatus extends UsageResetCredits {
566
573
  provider: string;
574
+ /** Live quota evidence from this exact account's reset-discovery response. */
575
+ report?: UsageReport;
576
+ /** Provider-requested wait before retrying throttled reset discovery (not redemption). */
577
+ retryAfterMs?: number;
567
578
  credentialId: number;
568
579
  accountId?: string;
569
580
  email?: string;
@@ -627,6 +638,20 @@ export type RotateCredentialOptions = {
627
638
  credentialId?: number;
628
639
  signal?: AbortSignal;
629
640
  };
641
+ /**
642
+ * Outcome of {@link LimitsApi.rotate}.
643
+ *
644
+ * `switched` is `true` when a usable same-type sibling credential is available,
645
+ * so the caller's next resolve hands it out. `afterSiblingWait` is `true` when
646
+ * no sibling was free at the failure but rotation slept out a sibling's short
647
+ * block (e.g. a Cloud Code Assist capacity 429 that resets in under a second);
648
+ * the freed credential may be one the caller already sent in this request, so
649
+ * attempted-bearer dedupe must let it through once.
650
+ */
651
+ export interface CredentialRotation {
652
+ switched: boolean;
653
+ afterSiblingWait?: boolean;
654
+ }
630
655
  /** Filter saved reset credits by provider and session. */
631
656
  export type ListResetCreditsOptions = {
632
657
  provider?: string;
@@ -858,6 +883,15 @@ export interface KeysApi {
858
883
  modelId?: string;
859
884
  }): ApiKeyResolver;
860
885
  }
886
+ /** Controls whether a row-id refresh may reuse a token minted by this refresher. */
887
+ export interface OAuthRefreshByIdOptions {
888
+ /**
889
+ * Return the stored credential when it still holds a fresh access token this
890
+ * refresher minted recently. Auth-recovery callers use this to avoid rotating
891
+ * refresh tokens repeatedly when a provider rejects every valid bearer.
892
+ */
893
+ reuseRecentMint?: boolean;
894
+ }
861
895
  /** OAuth login, access, account identity, and refresh operations. */
862
896
  export interface OAuthApi {
863
897
  /**
@@ -932,9 +966,10 @@ export interface OAuthApi {
932
966
  * Refresh the OAuth credential with the given id through a per-credential
933
967
  * single-flight. Concurrent callers for the same row await the same upstream
934
968
  * refresh attempt, which is required for providers that rotate refresh tokens
935
- * on every successful refresh.
969
+ * on every successful refresh. Mints unconditionally unless
970
+ * {@link OAuthRefreshByIdOptions.reuseRecentMint} is set.
936
971
  */
937
- refresh(id: number, signal?: AbortSignal): Promise<AuthCredentialSnapshotEntry>;
972
+ refresh(id: number, signal?: AbortSignal, options?: OAuthRefreshByIdOptions): Promise<AuthCredentialSnapshotEntry>;
938
973
  /**
939
974
  * Refresh one stored OAuth credential under durable row ownership.
940
975
  */
@@ -1107,9 +1142,11 @@ export interface LimitsApi {
1107
1142
  * reload when no broker hook is wired) and block it, then drop matching
1108
1143
  * sticky state.
1109
1144
  *
1110
- * Returns whether another usable credential of the same type remains.
1145
+ * For usage-limit and account-policy failures with no free sibling, waits
1146
+ * (abortable via `options.signal`) when a sibling's block expires within a
1147
+ * few seconds, then reports `afterSiblingWait`.
1111
1148
  */
1112
- rotate(provider: string, sessionId: string | undefined, options?: RotateCredentialOptions): Promise<boolean>;
1149
+ rotate(provider: string, sessionId: string | undefined, options?: RotateCredentialOptions): Promise<CredentialRotation>;
1113
1150
  /** Invalidate a credential matching an API key after authentication failure. */
1114
1151
  invalidateMatching(provider: string, apiKey: string, options?: InvalidateCredentialMatchingOptions): Promise<boolean>;
1115
1152
  }
@@ -1134,7 +1171,7 @@ export interface BlocksApi {
1134
1171
  */
1135
1172
  upsert(block: StoredCredentialBlock): void;
1136
1173
  /**
1137
- * Broker-server seam: clear all persisted blocks for one credential and notify snapshot waiters.
1174
+ * Broker-server seam: clear one exact persisted block and notify snapshot waiters.
1138
1175
  */
1139
1176
  delete(credentialId: number, providerKey: string, blockScope: string): void;
1140
1177
  /** Delete all persisted blocks for a credential. */
@@ -8,8 +8,8 @@ export declare const USAGE_HEADER_INGEST_INTERVAL_MS = 60000;
8
8
  /**
9
9
  * Per-credential cool-down after a usage fetch fails. While this window is
10
10
  * active we serve the last successful value to avoid dropping the credential
11
- * from the report; without a previous value we just return null and retry
12
- * on the next poll. Used by UsageService.
11
+ * from the report; without a previous value we return null until the
12
+ * cooldown expires. Report invalidation does not bypass this cooldown.
13
13
  */
14
14
  export declare const USAGE_FAILURE_BACKOFF_MS = 10000;
15
15
  /** Default usage fetch timeout; used by the AuthStorage facade. */
@@ -44,6 +44,16 @@ export declare class UsageCache {
44
44
  constructor(store: AuthCredentialStore, pool: CredentialPool, usageProviders: (provider: Provider) => UsageProvider | undefined);
45
45
  get epoch(): number;
46
46
  bumpEpoch(): void;
47
+ /** Identifies confirmed recoveries that supersede an in-flight failed probe. */
48
+ recoveryEpoch(provider: Provider): number;
49
+ /**
50
+ * Changes when a user refresh, confirmed reset, or usage-implementation swap
51
+ * makes an in-flight probe too old to answer. Block marks do not change it:
52
+ * they stop a racing report from being cached, never trigger a re-probe.
53
+ */
54
+ refreshEpoch(provider: Provider): number;
55
+ /** Failure cooldowns survive report invalidation and process restarts. */
56
+ failureKey(reportKey: string): string;
47
57
  get<T>(key: string): UsageCacheEntry<T> | undefined;
48
58
  getStale<T>(key: string): UsageCacheEntry<T> | undefined;
49
59
  set<T>(key: string, entry: UsageCacheEntry<T>): void;
@@ -56,8 +66,17 @@ export declare class UsageCache {
56
66
  /**
57
67
  * Force the next usage fetch for `provider` to bypass the 5-min cache, so
58
68
  * `/usage` reflects a freshly-redeemed reset instead of stale numbers.
69
+ * `resetSpentCredentialId` also forgets that credential's cached saved-reset
70
+ * block, so a failed follow-up reset probe cannot carry the pre-spend
71
+ * inventory forward.
59
72
  */
60
- invalidate(provider: string, baseUrl?: string): void;
73
+ invalidate(provider: string, baseUrl?: string, options?: {
74
+ resetSpentCredentialId?: number;
75
+ }): void;
76
+ /** A confirmed reset permits one fresh probe even during a pre-reset failure cooldown. */
77
+ invalidateAfterReset(provider: Provider, baseUrl?: string, options?: {
78
+ resetSpentCredentialId?: number;
79
+ }): void;
61
80
  /**
62
81
  * Expire cached reports for a provider after its runtime usage implementation changes.
63
82
  * This keeps a newly installed extension provider from serving a built-in snapshot.
@@ -29,6 +29,10 @@ export interface UsageServiceDeps {
29
29
  requestTimeoutMs: number;
30
30
  logger: UsageLogger;
31
31
  }
32
+ type UsageReportsOptions = {
33
+ baseUrlResolver?: (provider: Provider) => string | undefined;
34
+ signal?: AbortSignal;
35
+ };
32
36
  /** Usage reports: per-credential cached fetches, aggregate reports, header ingestion, history. */
33
37
  export declare class UsageService implements UsageApi {
34
38
  #private;
@@ -95,15 +99,12 @@ export declare class UsageService implements UsageApi {
95
99
  */
96
100
  reportingModelIds(provider: Provider, modelIds: readonly string[], reports: readonly UsageReport[]): string[];
97
101
  /** Fetch all providers’ current usage reports, sharing concurrent polls. */
98
- reports(options?: {
99
- baseUrlResolver?: (provider: Provider) => string | undefined;
100
- /** Caller's cancel signal; only rejects this caller, never the shared upstream fetch. */
101
- signal?: AbortSignal;
102
- }): Promise<UsageReport[] | null>;
102
+ reports(options?: UsageReportsOptions): Promise<UsageReport[] | null>;
103
103
  /**
104
104
  * Discard cached usage reports before a user-requested refresh. The next
105
- * read probes upstream serially per provider; a failure reports no fresh
106
- * usage instead of replaying an invalidated last-good snapshot.
105
+ * read probes upstream serially per provider unless a failure cooldown is
106
+ * active. Failed probes never replay an invalidated last-good snapshot.
107
107
  */
108
108
  invalidate(provider?: string, signal?: AbortSignal): Promise<void>;
109
109
  }
110
+ export {};
@@ -5,8 +5,8 @@
5
5
  * `omp auth-broker status` (liveness checks). All endpoints except
6
6
  * `/v1/healthz` require a bearer token.
7
7
  */
8
- import type { AuthCredential, DisabledCredentialSummary } from "../auth-storage.js";
9
- import type { ClientUsageReportRequest, ClientUsageReportResponse, ClientUsageSummaryResponse, CredentialBlockRequest, CredentialBlockResponse, CredentialBlocksDeleteResponse, CredentialDisableResponse, CredentialRefreshResponse, CredentialUploadResponse, HealthzResponse, SnapshotResponse, SnapshotStreamEvent, UsageHistoryResponse, UsageResponse, UsageStaleResponse } from "./types.js";
8
+ import type { AuthCredential, DisabledCredentialSummary, OAuthRefreshReason } from "../auth-storage.js";
9
+ import type { ClientUsageReportRequest, ClientUsageReportResponse, ClientUsageSummaryResponse, CredentialBlockDeleteRequest, CredentialBlockRequest, CredentialBlockResponse, CredentialBlocksDeleteResponse, CredentialDisableResponse, CredentialRefreshResponse, CredentialUploadResponse, HealthzResponse, SnapshotResponse, SnapshotStreamEvent, UsageHistoryResponse, UsageResponse, UsageStaleResponse } from "./types.js";
10
10
  export interface AuthBrokerClientOptions {
11
11
  /** Base URL (e.g. `https://broker.tailnet:8765`). Trailing slashes are trimmed. */
12
12
  url: string;
@@ -86,7 +86,7 @@ export declare class AuthBrokerClient {
86
86
  sinceMs?: number;
87
87
  }, signal?: AbortSignal): Promise<ClientUsageSummaryResponse>;
88
88
  notifyUsageStale(signal?: AbortSignal): Promise<UsageStaleResponse>;
89
- refreshCredential(id: number, signal?: AbortSignal): Promise<CredentialRefreshResponse>;
89
+ refreshCredential(id: number, signal?: AbortSignal, reason?: OAuthRefreshReason): Promise<CredentialRefreshResponse>;
90
90
  disableCredential(id: number, cause: string, signal?: AbortSignal): Promise<CredentialDisableResponse>;
91
91
  /**
92
92
  * Disabled-credential tombstones (identity + cause, no token material).
@@ -96,5 +96,6 @@ export declare class AuthBrokerClient {
96
96
  listDisabledCredentials(provider?: string, signal?: AbortSignal): Promise<DisabledCredentialSummary[]>;
97
97
  uploadCredential(provider: string, credential: AuthCredential, signal?: AbortSignal): Promise<CredentialUploadResponse>;
98
98
  upsertCredentialBlock(id: number, block: CredentialBlockRequest, signal?: AbortSignal): Promise<CredentialBlockResponse>;
99
+ deleteCredentialBlock(id: number, block: CredentialBlockDeleteRequest, signal?: AbortSignal): Promise<CredentialBlocksDeleteResponse>;
99
100
  deleteCredentialBlocks(id: number, signal?: AbortSignal): Promise<CredentialBlocksDeleteResponse>;
100
101
  }
@@ -1,5 +1,5 @@
1
1
  import type { AuthCredentialStore } from "../auth/store.js";
2
- import { type AuthCredential, type DisabledCredentialSummary, type OAuthCredential, type StoredAuthCredential, type StoredCredentialBlock } from "../auth/types.js";
2
+ import { type AuthCredential, type DisabledCredentialSummary, type OAuthCredential, type OAuthRefreshReason, type StoredAuthCredential, type StoredCredentialBlock } from "../auth/types.js";
3
3
  import type { OAuthCredentials } from "../registry/oauth/types.js";
4
4
  import type { Provider } from "../types.js";
5
5
  import type { ClientUsageIdentity, ObservedUsageEntry, UsageReport } from "../usage.js";
@@ -76,7 +76,7 @@ export declare class RemoteAuthCredentialStore implements AuthCredentialStore {
76
76
  getCredentialBlockReconcileAfter(credentialId: number, providerKey: string, blockScope: string): number | undefined;
77
77
  listCredentialBlocks(credentialIds: readonly number[]): StoredCredentialBlock[];
78
78
  upsertCredentialBlock(block: StoredCredentialBlock): void;
79
- deleteCredentialBlock(_credentialId: number, _providerKey: string, _blockScope: string): void;
79
+ deleteCredentialBlock(credentialId: number, providerKey: string, blockScope: string): void;
80
80
  deleteCredentialBlocks(credentialId: number): void;
81
81
  cleanExpiredCredentialBlocks(nowMs: number): void;
82
82
  /**
@@ -128,12 +128,11 @@ export declare class RemoteAuthCredentialStore implements AuthCredentialStore {
128
128
  * the broker-redacted credential with {@link REMOTE_REFRESH_SENTINEL} in
129
129
  * the `refresh` slot.
130
130
  */
131
- refreshOAuthCredential(_provider: Provider, credentialId: number, _credential: OAuthCredential, signal?: AbortSignal): Promise<OAuthCredentials>;
131
+ refreshOAuthCredential(_provider: Provider, credentialId: number, _credential: OAuthCredential, signal?: AbortSignal, reason?: OAuthRefreshReason): Promise<OAuthCredentials>;
132
132
  /**
133
133
  * Store-level hook consumed by `AuthStorage.usage.reports()` — proxies
134
- * to the broker's `/v1/usage` endpoint. The broker's egress IP isn't
135
- * rate-limited by Anthropic's per-IP `/usage` cap the way a heavy
136
- * residential laptop is, so all credentials surface every cycle.
134
+ * to the broker's `/v1/usage` endpoint. Shared per-credential caches and
135
+ * cooldowns keep separate clients from multiplying provider probes.
137
136
  */
138
137
  fetchUsageReports(signal?: AbortSignal): Promise<UsageReport[] | null>;
139
138
  /**
@@ -142,8 +141,8 @@ export declare class RemoteAuthCredentialStore implements AuthCredentialStore {
142
141
  * same response (coalesced + cached), then overlays any client-observed
143
142
  * header hints for the matching credential.
144
143
  *
145
- * The broker already aggregates with its own 30s TTL on the server side; our
146
- * 15s client TTL is below that so we usually re-use the broker's cache too.
144
+ * The broker caches each credential independently; the short client TTL
145
+ * also folds sequential consumers into one broker round-trip.
147
146
  */
148
147
  getUsageReport(provider: Provider, credential: OAuthCredential, signal?: AbortSignal): Promise<UsageReport | null>;
149
148
  ingestUsageReport(provider: Provider, credential: OAuthCredential, report: UsageReport): boolean;
@@ -73,11 +73,13 @@ export interface DisabledCredentialsResponse {
73
73
  }
74
74
  /** POST /v1/credential/:id/block request body. */
75
75
  export type CredentialBlockRequest = CredentialBlockSnapshot;
76
+ /** DELETE /v1/credential/:id/block request body; empty scope targets only the global row. */
77
+ export type CredentialBlockDeleteRequest = Pick<CredentialBlockSnapshot, "providerKey" | "blockScope">;
76
78
  /** POST /v1/credential/:id/block response body. */
77
79
  export interface CredentialBlockResponse {
78
80
  ok: boolean;
79
81
  }
80
- /** DELETE /v1/credential/:id/blocks response body. */
82
+ /** DELETE /v1/credential/:id/block or /blocks response body. */
81
83
  export interface CredentialBlocksDeleteResponse {
82
84
  ok: boolean;
83
85
  }
@@ -14,7 +14,7 @@
14
14
  */
15
15
  import { type FluentType } from "@oh-my-pi/omptype";
16
16
  import { type ApiKeyCredential, type AuthCredential, type AuthCredentialSnapshotEntry, type DisabledCredentialSummary, type OAuthCredential, type RemoteOAuthCredential, type SnapshotCredential } from "../auth-storage.js";
17
- import type { ClientUsageReportRequest, ClientUsageReportResponse, ClientUsageSummaryResponse, CredentialBlockRequest, CredentialBlockResponse, CredentialBlockSnapshot, CredentialBlocksDeleteResponse, CredentialDisableResponse, CredentialRefreshResponse, CredentialUploadRequest, CredentialUploadResponse, DisabledCredentialsResponse, HealthzResponse, RefresherSchedule, SnapshotEntry, SnapshotResponse, SnapshotStreamEntryEvent, SnapshotStreamEvent, SnapshotStreamRemovedEvent, SnapshotStreamSnapshotEvent, UsageHistoryResponse, UsageResponse, UsageStaleResponse } from "./types.js";
17
+ import type { ClientUsageReportRequest, ClientUsageReportResponse, ClientUsageSummaryResponse, CredentialBlockDeleteRequest, CredentialBlockRequest, CredentialBlockResponse, CredentialBlockSnapshot, CredentialBlocksDeleteResponse, CredentialDisableResponse, CredentialRefreshResponse, CredentialUploadRequest, CredentialUploadResponse, DisabledCredentialsResponse, HealthzResponse, RefresherSchedule, SnapshotEntry, SnapshotResponse, SnapshotStreamEntryEvent, SnapshotStreamEvent, SnapshotStreamRemovedEvent, SnapshotStreamSnapshotEvent, UsageHistoryResponse, UsageResponse, UsageStaleResponse } from "./types.js";
18
18
  /** Real OAuth credential (broker-side) — refresh token is the actual upstream value. */
19
19
  export declare const oauthCredentialSchema: FluentType<OAuthCredential>;
20
20
  /** OAuth credential as it appears in broker snapshots — refresh replaced with sentinel. */
@@ -62,6 +62,7 @@ export declare const disabledCredentialSummarySchema: FluentType<DisabledCredent
62
62
  /** Broker `GET /v1/credentials/disabled` response. */
63
63
  export declare const disabledCredentialsResponseSchema: FluentType<DisabledCredentialsResponse>;
64
64
  export declare const credentialBlockRequestSchema: FluentType<CredentialBlockRequest>;
65
+ export declare const credentialBlockDeleteRequestSchema: FluentType<CredentialBlockDeleteRequest>;
65
66
  export declare const credentialBlockResponseSchema: FluentType<CredentialBlockResponse>;
66
67
  export declare const credentialBlocksDeleteResponseSchema: FluentType<CredentialBlocksDeleteResponse>;
67
68
  export declare const usageStaleResponseSchema: FluentType<UsageStaleResponse>;