Adds the addAccountByToken procedure to accountProcedures(), which accepts an email and raw OAuth token, stores the token as claudeAiOauth credentials, and upserts the account (create or updateAccountAuth based on findByEmail). Covers the four scenarios with unit tests: new account, existing account, empty email, and empty token validation errors. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
101 lines
3.2 KiB
TypeScript
101 lines
3.2 KiB
TypeScript
/**
|
|
* Account Router — list, add, remove, refresh, update auth, mark exhausted, providers
|
|
*/
|
|
|
|
import { z } from 'zod';
|
|
import type { ProcedureBuilder } from '../trpc.js';
|
|
import { requireAccountRepository } from './_helpers.js';
|
|
import { listProviders as listProviderNames } from '../../agent/providers/registry.js';
|
|
|
|
export function accountProcedures(publicProcedure: ProcedureBuilder) {
|
|
return {
|
|
listAccounts: publicProcedure
|
|
.query(async ({ ctx }) => {
|
|
const repo = requireAccountRepository(ctx);
|
|
return repo.findAll();
|
|
}),
|
|
|
|
addAccount: publicProcedure
|
|
.input(z.object({
|
|
email: z.string().min(1),
|
|
provider: z.string().default('claude'),
|
|
configJson: z.string().optional(),
|
|
credentials: z.string().optional(),
|
|
}))
|
|
.mutation(async ({ ctx, input }) => {
|
|
const repo = requireAccountRepository(ctx);
|
|
return repo.create({
|
|
email: input.email,
|
|
provider: input.provider,
|
|
configJson: input.configJson,
|
|
credentials: input.credentials,
|
|
});
|
|
}),
|
|
|
|
removeAccount: publicProcedure
|
|
.input(z.object({ id: z.string().min(1) }))
|
|
.mutation(async ({ ctx, input }) => {
|
|
const repo = requireAccountRepository(ctx);
|
|
await repo.delete(input.id);
|
|
return { success: true };
|
|
}),
|
|
|
|
refreshAccounts: publicProcedure
|
|
.mutation(async ({ ctx }) => {
|
|
const repo = requireAccountRepository(ctx);
|
|
const cleared = await repo.clearExpiredExhaustion();
|
|
return { cleared };
|
|
}),
|
|
|
|
updateAccountAuth: publicProcedure
|
|
.input(z.object({
|
|
id: z.string().min(1),
|
|
configJson: z.string(),
|
|
credentials: z.string(),
|
|
}))
|
|
.mutation(async ({ ctx, input }) => {
|
|
const repo = requireAccountRepository(ctx);
|
|
return repo.updateAccountAuth(input.id, input.configJson, input.credentials);
|
|
}),
|
|
|
|
markAccountExhausted: publicProcedure
|
|
.input(z.object({
|
|
id: z.string().min(1),
|
|
until: z.string().datetime(),
|
|
}))
|
|
.mutation(async ({ ctx, input }) => {
|
|
const repo = requireAccountRepository(ctx);
|
|
return repo.markExhausted(input.id, new Date(input.until));
|
|
}),
|
|
|
|
listProviderNames: publicProcedure
|
|
.query(() => {
|
|
return listProviderNames();
|
|
}),
|
|
|
|
addAccountByToken: publicProcedure
|
|
.input(z.object({
|
|
email: z.string().min(1),
|
|
provider: z.string().default('claude'),
|
|
token: z.string().min(1),
|
|
}))
|
|
.mutation(async ({ ctx, input }) => {
|
|
const repo = requireAccountRepository(ctx);
|
|
const credentials = JSON.stringify({ claudeAiOauth: { accessToken: input.token } });
|
|
const configJson = JSON.stringify({ hasCompletedOnboarding: true });
|
|
const existing = await repo.findByEmail(input.email);
|
|
if (existing) {
|
|
const account = await repo.updateAccountAuth(existing.id, configJson, credentials);
|
|
return { upserted: true, account };
|
|
}
|
|
const account = await repo.create({
|
|
email: input.email,
|
|
provider: input.provider,
|
|
configJson,
|
|
credentials,
|
|
});
|
|
return { upserted: false, account };
|
|
}),
|
|
};
|
|
}
|