(
row: ConnectionRow,
provider: CredentialProvider,
trigger: RefreshTrigger = "proactive",
)
| 2944 | ); |
| 2945 | |
| 2946 | const refreshConnectionToken = ( |
| 2947 | row: ConnectionRow, |
| 2948 | provider: CredentialProvider, |
| 2949 | trigger: RefreshTrigger = "proactive", |
| 2950 | ): Effect.Effect<string | null, StorageFailure | CredentialResolutionError> => |
| 2951 | // Share a single refresh per connection so concurrent resolves of the same |
| 2952 | // connection all await one refresh-token grant (the AS rotates the refresh |
| 2953 | // token; parallel grants would race on a consumed token — v1's refresh |
| 2954 | // deferred-map). The gate is cleared once the refresh settles so a later |
| 2955 | // expiry can refresh again. |
| 2956 | Effect.suspend(() => { |
| 2957 | const key = connectionKey(row); |
| 2958 | // Joining an in-flight grant is correct for BOTH triggers: whatever |
| 2959 | // that peer mints is newer than the token this fiber just saw rejected, |
| 2960 | // which is exactly what a reactive retry wants. The gate is cleared on |
| 2961 | // settle, so a 401 arriving after a refresh completed starts a fresh |
| 2962 | // grant rather than replaying a stale result. |
| 2963 | const existing = refreshInFlight.get(key); |
| 2964 | if (existing) return Deferred.await(existing); |
| 2965 | |
| 2966 | // The grant runs on a DETACHED fiber and every caller — including this |
| 2967 | // one — only awaits its deferred. The entry is shared across execution |
| 2968 | // stacks, so the fiber that registers it is merely the first arrival, |
| 2969 | // not an owner. Running the grant ON that fiber would hand it that |
| 2970 | // caller's interruption: a disconnected MCP client, an execution |
| 2971 | // deadline or a cancelled tool call would fail every peer awaiting the |
| 2972 | // same entry with an interrupt none of them caused and none can act on. |
| 2973 | // Awaiting is per-caller, so a cancelled peer detaches without touching |
| 2974 | // the grant or its siblings, and a grant nobody is left waiting on |
| 2975 | // still settles and still persists the rotated token — which is what |
| 2976 | // keeps the next caller off a consumed one. Token requests are bounded |
| 2977 | // by `AbortSignal.timeout`, so the detached fiber cannot outlive its |
| 2978 | // request. |
| 2979 | const deferred = Deferred.makeUnsafe< |
| 2980 | string | null, |
| 2981 | StorageFailure | CredentialResolutionError |
| 2982 | >(); |
| 2983 | // Nothing suspends between the lookup above and this registration, so |
| 2984 | // check-and-set is atomic against peer fibers and cannot double-fire. |
| 2985 | refreshInFlight.set(key, deferred); |
| 2986 | const run = performTokenRefresh(row, provider, trigger).pipe( |
| 2987 | Effect.exit, |
| 2988 | Effect.flatMap((exit) => Deferred.done(deferred, exit)), |
| 2989 | Effect.ensuring(Effect.sync(() => void refreshInFlight.delete(key))), |
| 2990 | ); |
| 2991 | return Effect.forkDetach(run).pipe(Effect.andThen(Deferred.await(deferred))); |
| 2992 | }); |
| 2993 | |
| 2994 | // Resolve every named input of a connection (`variable → value`). A |
| 2995 | // single-secret connection yields `{ token: <value> }`; an apiKey method with |
no test coverage detected