blob: 84a6b9c536dd3e1a7f46c457821f8b83cab2fc6e [file]
import type { RuntimeExecutionConnection } from '@maka/core';
import type { CredentialLocator } from '@maka/core';
import {
buildSubscriptionModelFetch,
isOAuthSubscriptionProvider,
openAiCodexHeaders,
refreshAndPersistOAuthSubscriptionTokens,
resolveAndPersistOAuthSubscriptionTokens,
type OAuthSubscriptionCredentialStore,
type OAuthSubscriptionProvider,
type OAuthSubscriptionTokens,
type ProxiedFetchTransport,
} from '@maka/runtime';
import {
authenticateRuntimePolicyStoresWriter,
RuntimePolicyStoreError,
type RuntimePolicyCredentialMaterial,
type RuntimePolicyStoresWriter,
} from '@maka/storage/runtime-policy-stores';
export type OAuthExecutionCredentialErrorCode =
| 'credential_unavailable'
| 'credential_superseded'
| 'refresh_failed'
| 'persistence_failed';
type OAuthCredentialLocator = Extract<CredentialLocator, { scope: 'connection' }> & {
readonly kind: 'oauth_token';
};
export class OAuthExecutionCredentialError extends Error {
constructor(
readonly code: OAuthExecutionCredentialErrorCode,
message: string,
options?: ErrorOptions,
) {
super(message, options);
this.name = 'OAuthExecutionCredentialError';
}
}
interface CredentialState {
readonly providerType: OAuthSubscriptionProvider;
readonly connectionSlug: string;
readonly locator: OAuthCredentialLocator;
readonly credentialId: string;
revision: number;
raw: string;
uncertainCommit?: CredentialCommitCandidate;
resolving?: Promise<OAuthSubscriptionTokens>;
resolvingForceRefresh?: boolean;
}
interface CredentialCommitCandidate {
readonly credentialId: string;
readonly revision: number;
readonly raw: string;
}
export interface HostOAuthExecutionBinding {
readonly providerType: OAuthSubscriptionProvider;
readonly connectionSlug: string;
resolve(): Promise<OAuthSubscriptionTokens>;
forceRefresh?(): Promise<OAuthSubscriptionTokens>;
}
/** Host-local generation binding over the canonical Runtime Policy OAuth credential. */
export class HostOAuthExecutionAuthority {
readonly #stores: RuntimePolicyStoresWriter;
readonly #states = new Map<string, CredentialState>();
readonly #now: () => number;
constructor(stores: RuntimePolicyStoresWriter, now: () => number = Date.now) {
this.#stores = authenticateRuntimePolicyStoresWriter(stores);
this.#now = now;
}
bind(input: {
providerType: RuntimeExecutionConnection['providerType'];
connectionSlug: string;
material: RuntimePolicyCredentialMaterial;
createRefreshTransport: () => ProxiedFetchTransport;
}): HostOAuthExecutionBinding {
if (!isOAuthSubscriptionProvider(input.providerType)) {
throw new OAuthExecutionCredentialError(
'credential_unavailable',
`OAuth execution is not available for provider ${input.providerType}`,
);
}
const locator = requireOAuthLocator(input.material.locator);
let state = this.#states.get(locator.connectionId);
if (state) {
if (
state.providerType !== input.providerType ||
state.connectionSlug !== input.connectionSlug ||
!sameLocator(state.locator, locator)
) {
throw new OAuthExecutionCredentialError(
'persistence_failed',
'Canonical OAuth credential identity was reused for a different connection',
);
}
const candidate = state.uncertainCommit;
if (
candidate &&
candidate.credentialId === input.material.credentialId &&
candidate.revision === input.material.revision &&
candidate.raw === input.material.secret
) {
state.revision = candidate.revision;
state.raw = candidate.raw;
state.uncertainCommit = undefined;
}
if (
state.credentialId !== input.material.credentialId ||
state.revision !== input.material.revision ||
state.raw !== input.material.secret
) {
state = undefined;
}
}
if (!state) {
state = {
providerType: input.providerType,
connectionSlug: input.connectionSlug,
locator,
credentialId: input.material.credentialId,
revision: input.material.revision,
raw: input.material.secret,
};
this.#states.set(state.locator.connectionId, state);
}
const bound = state;
return Object.freeze({
providerType: bound.providerType,
connectionSlug: bound.connectionSlug,
resolve: () => this.#resolve(bound, input.createRefreshTransport),
forceRefresh: () => this.#resolve(bound, input.createRefreshTransport, true),
});
}
async #resolve(
state: CredentialState,
createRefreshTransport: () => ProxiedFetchTransport,
forceRefresh = false,
): Promise<OAuthSubscriptionTokens> {
this.#assertCurrent(state);
if (state.resolving) {
if (!forceRefresh || state.resolvingForceRefresh) return state.resolving;
await state.resolving;
this.#assertCurrent(state);
}
if (state.resolving) return this.#resolve(state, createRefreshTransport, forceRefresh);
const resolving = this.#resolveUnshared(state, createRefreshTransport, forceRefresh);
state.resolving = resolving;
state.resolvingForceRefresh = forceRefresh;
try {
return await resolving;
} finally {
if (state.resolving === resolving) {
state.resolving = undefined;
state.resolvingForceRefresh = undefined;
}
}
}
async #resolveUnshared(
state: CredentialState,
createRefreshTransport: () => ProxiedFetchTransport,
forceRefresh: boolean,
): Promise<OAuthSubscriptionTokens> {
await this.#reconcileUncertainCommit(state);
const credentialStore = this.#credentialStore(state);
let refreshTransport: ProxiedFetchTransport | undefined;
let result;
try {
const refreshInput = {
providerType: state.providerType,
slug: state.connectionSlug,
credentialStore,
now: this.#now,
fetchFn: async (url: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => {
if (!this.#isCurrent(state)) throw new OAuthCredentialSupersededError();
refreshTransport ??= createRefreshTransport();
return refreshTransport.fetch(url, init);
},
} as const;
result = forceRefresh
? await refreshAndPersistOAuthSubscriptionTokens(refreshInput)
: await resolveAndPersistOAuthSubscriptionTokens(refreshInput);
} finally {
await refreshTransport?.close();
}
this.#assertCurrent(state);
switch (result.outcome) {
case 'current':
case 'refreshed':
return result.tokens;
case 'superseded':
this.#invalidate(state);
throw supersededError();
case 'logged-out':
throw new OAuthExecutionCredentialError(
'credential_unavailable',
'OAuth credential is no longer configured',
);
case 'refresh-failed':
throw new OAuthExecutionCredentialError(
'refresh_failed',
'OAuth credential refresh failed',
{ cause: result.error },
);
case 'storage-failed':
if (result.error instanceof OAuthCredentialSupersededError) {
throw supersededError(result.error);
}
throw new OAuthExecutionCredentialError(
'persistence_failed',
'OAuth credential persistence failed',
{ cause: result.error },
);
}
}
async #reconcileUncertainCommit(state: CredentialState): Promise<void> {
const candidate = state.uncertainCommit;
if (!candidate) return;
let resolved;
try {
resolved = await this.#stores.operations.resolveExecutionConnection(state.connectionSlug);
} catch (error) {
throw new OAuthExecutionCredentialError(
'persistence_failed',
'Canonical OAuth credential could not be reconciled',
{ cause: error },
);
}
this.#assertCurrent(state);
const material = resolved.kind === 'ready' ? resolved.secretMaterial.connection : undefined;
if (
material &&
material.credentialId === candidate.credentialId &&
material.revision === candidate.revision &&
material.secret === candidate.raw &&
sameLocator(material.locator, state.locator)
) {
state.revision = candidate.revision;
state.raw = candidate.raw;
state.uncertainCommit = undefined;
return;
}
state.uncertainCommit = undefined;
this.#invalidate(state);
throw supersededError();
}
#credentialStore(state: CredentialState): OAuthSubscriptionCredentialStore {
return {
getSecret: async (slug, kind) => {
assertBoundRequest(state, slug, kind);
if (!this.#isCurrent(state)) throw new OAuthCredentialSupersededError();
return state.raw;
},
compareAndSetSecret: async (slug, kind, expected, value) => {
assertBoundRequest(state, slug, kind);
if (!this.#isCurrent(state)) throw new OAuthCredentialSupersededError();
if (expected !== state.raw) return { committed: false, current: state.raw };
let committed;
try {
committed = await this.#stores.operations.compareAndSetOAuthCredential({
locator: state.locator,
expected: {
credentialId: state.credentialId,
revision: state.revision,
},
secret: value,
});
} catch (error) {
if (!this.#isCurrent(state)) throw new OAuthCredentialSupersededError();
if (error instanceof RuntimePolicyStoreError && error.code === 'commit_outcome_unknown') {
state.uncertainCommit = {
credentialId: state.credentialId,
revision: state.revision + 1,
raw: value,
};
}
throw error;
}
if (committed.kind !== 'committed') {
this.#invalidate(state);
throw new OAuthCredentialSupersededError();
}
if (!this.#isCurrent(state)) throw new OAuthCredentialSupersededError();
state.revision = committed.revision;
state.raw = value;
return { committed: true };
},
};
}
#isCurrent(state: CredentialState): boolean {
return this.#states.get(state.locator.connectionId) === state;
}
#assertCurrent(state: CredentialState): void {
if (!this.#isCurrent(state)) throw supersededError();
}
#invalidate(state: CredentialState): void {
if (this.#isCurrent(state)) this.#states.delete(state.locator.connectionId);
}
}
export function createHostOAuthModelFetch(input: {
binding: HostOAuthExecutionBinding;
initialTokens: OAuthSubscriptionTokens;
connection: RuntimeExecutionConnection;
sessionId: string;
modelId: string;
claudeDeviceId: string;
fetchFn: typeof fetch;
}): typeof fetch {
if (
input.binding.providerType === 'claude-subscription' &&
!input.initialTokens.account_uuid?.trim()
) {
throw new OAuthExecutionCredentialError(
'credential_unavailable',
'Claude OAuth credential is missing its canonical account identity',
);
}
return async (url, init) => {
const signal = effectiveRequestSignal(url, init);
signal?.throwIfAborted();
let tokens = await waitForCaller(input.binding.resolve(), signal);
signal?.throwIfAborted();
const authenticatedFetch = authenticatedOAuthFetch(input, () => tokens);
const subscriptionFetch = buildSubscriptionModelFetch({
connection: input.connection,
sessionId: input.sessionId,
modelId: input.modelId,
fetchFn: authenticatedFetch,
...(input.binding.forceRefresh &&
(input.binding.providerType === 'openai-codex' || input.binding.providerType === 'xai-oauth')
? {
refreshOAuthAccessToken: async () =>
(tokens = await input.binding.forceRefresh!()).access_token,
}
: {}),
...(input.binding.providerType === 'claude-subscription'
? {
claude: {
deviceId: input.claudeDeviceId,
accountUuid: tokens.account_uuid ?? '',
},
}
: {}),
});
return (subscriptionFetch ?? authenticatedFetch)(url, init);
};
}
function effectiveRequestSignal(
url: Parameters<typeof fetch>[0],
init: Parameters<typeof fetch>[1],
): AbortSignal | null | undefined {
return init?.signal !== undefined ? init.signal : url instanceof Request ? url.signal : undefined;
}
async function waitForCaller<T>(pending: Promise<T>, signal?: AbortSignal | null): Promise<T> {
if (!signal) return pending;
signal.throwIfAborted();
let onAbort: (() => void) | undefined;
const aborted = new Promise<never>((_resolve, reject) => {
onAbort = () => reject(signal.reason ?? new DOMException('Request aborted', 'AbortError'));
signal.addEventListener('abort', onAbort, { once: true });
});
try {
return await Promise.race([pending, aborted]);
} finally {
if (onAbort) signal.removeEventListener('abort', onAbort);
}
}
function authenticatedOAuthFetch(
input: Pick<Parameters<typeof createHostOAuthModelFetch>[0], 'binding' | 'fetchFn'>,
readTokens: () => OAuthSubscriptionTokens,
): typeof fetch {
return async (url, init) => {
const tokens = readTokens();
const headers = mergedHeaders(url, init?.headers);
headers.delete('api-key');
headers.delete('x-api-key');
headers.set('Authorization', `Bearer ${tokens.access_token}`);
if (input.binding.providerType === 'openai-codex') {
headers.delete('ChatGPT-Account-Id');
for (const [name, value] of Object.entries(openAiCodexHeaders(tokens.access_token))) {
headers.set(name, value);
}
}
return input.fetchFn(url, { ...init, headers });
};
}
class OAuthCredentialSupersededError extends Error {
constructor() {
super('OAuth credential generation is no longer canonical');
this.name = 'OAuthCredentialSupersededError';
}
}
function requireOAuthLocator(locator: CredentialLocator): OAuthCredentialLocator {
if (locator.scope !== 'connection' || locator.kind !== 'oauth_token') {
throw new OAuthExecutionCredentialError(
'persistence_failed',
'Canonical OAuth credential material has an invalid locator',
);
}
return {
scope: 'connection',
connectionId: locator.connectionId,
kind: 'oauth_token',
};
}
function assertBoundRequest(state: CredentialState, slug: string, kind: 'oauth_token'): void {
if (slug !== state.connectionSlug || kind !== 'oauth_token') {
throw new OAuthExecutionCredentialError(
'persistence_failed',
'OAuth credential resolver escaped its bound connection',
);
}
}
function sameLocator(left: CredentialLocator, right: CredentialLocator): boolean {
return (
left.scope === 'connection' &&
right.scope === 'connection' &&
left.connectionId === right.connectionId &&
left.kind === right.kind
);
}
function mergedHeaders(
url: Parameters<typeof fetch>[0],
override: HeadersInit | undefined,
): Headers {
const headers = new Headers(url instanceof Request ? url.headers : undefined);
new Headers(override).forEach((value, name) => headers.set(name, value));
return headers;
}
function supersededError(cause?: unknown): OAuthExecutionCredentialError {
return new OAuthExecutionCredentialError(
'credential_superseded',
'OAuth credential changed during backend execution',
cause === undefined ? undefined : { cause },
);
}