mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-15 09:01:17 +00:00
fix(foundry): move Better Auth operations from queues to actions to fix production auth timeout
The org actor's workflow queue is shared with GitHub sync, webhooks, task mutations, and billing (20+ queue names processed sequentially). During OAuth callback, auth operations would time out waiting behind long-running queue handlers, causing Better Auth's parseState to redirect to ?error=please_restart_the_process. Auth operations are simple SQLite reads/writes with no cross-actor side effects, so they are safe to run as actions that execute immediately without competing in the queue. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
84a80d59d7
commit
e7b9ac6854
7 changed files with 211 additions and 233 deletions
|
|
@ -272,6 +272,16 @@ Each user has independent unread state. The existing `userTaskState` table track
|
||||||
|
|
||||||
These two unread systems must stay in sync via the `user.mark_read` queue command.
|
These two unread systems must stay in sync via the `user.mark_read` queue command.
|
||||||
|
|
||||||
|
## Better Auth: Actions, Not Queues
|
||||||
|
|
||||||
|
All Better Auth adapter operations (verification CRUD, session/email/account index mutations, and user-actor auth record mutations) are exposed as **actions**, not queue commands. This is an intentional exception to the normal pattern of using queues for mutations.
|
||||||
|
|
||||||
|
**Why:** The org actor's workflow queue is shared with GitHub sync, webhook processing, task mutations, and billing — 20+ queue names processed sequentially. During the OAuth callback, Better Auth needs to read/write verification records and upsert session/account indexes. If any long-running queue handler (e.g., a GitHub sync step) is ahead in the queue, auth operations time out (10s), `expectQueueResponse` throws a regular `Error`, and Better Auth's `parseState` catches it as a non-`StateError` → redirects to `?error=please_restart_the_process`.
|
||||||
|
|
||||||
|
**Why it's safe:** Auth operations are simple SQLite reads/writes scoped to a single actor instance with no cross-actor side effects. They don't need workflow replay semantics or sequential ordering guarantees relative to other queue commands.
|
||||||
|
|
||||||
|
**Rule:** Never move Better Auth operations back to queue commands. If new auth-related mutations are added, expose them as actions on the relevant actor.
|
||||||
|
|
||||||
## Maintenance
|
## Maintenance
|
||||||
|
|
||||||
- Keep this file up to date whenever actor ownership, hierarchy, or lifecycle responsibilities change.
|
- Keep this file up to date whenever actor ownership, hierarchy, or lifecycle responsibilities change.
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,4 @@
|
||||||
import {
|
import { and, asc, count as sqlCount, desc, eq, gt, gte, inArray, isNotNull, isNull, like, lt, lte, ne, notInArray, or } from "drizzle-orm";
|
||||||
and,
|
|
||||||
asc,
|
|
||||||
count as sqlCount,
|
|
||||||
desc,
|
|
||||||
eq,
|
|
||||||
gt,
|
|
||||||
gte,
|
|
||||||
inArray,
|
|
||||||
isNotNull,
|
|
||||||
isNull,
|
|
||||||
like,
|
|
||||||
lt,
|
|
||||||
lte,
|
|
||||||
ne,
|
|
||||||
notInArray,
|
|
||||||
or,
|
|
||||||
} from "drizzle-orm";
|
|
||||||
import { authAccountIndex, authEmailIndex, authSessionIndex, authVerification } from "../db/schema.js";
|
import { authAccountIndex, authEmailIndex, authSessionIndex, authVerification } from "../db/schema.js";
|
||||||
import { APP_SHELL_ORGANIZATION_ID } from "../constants.js";
|
import { APP_SHELL_ORGANIZATION_ID } from "../constants.js";
|
||||||
|
|
||||||
|
|
@ -151,10 +134,7 @@ export async function betterAuthDeleteEmailIndexMutation(c: any, input: { email:
|
||||||
await c.db.delete(authEmailIndex).where(eq(authEmailIndex.email, input.email)).run();
|
await c.db.delete(authEmailIndex).where(eq(authEmailIndex.email, input.email)).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function betterAuthUpsertAccountIndexMutation(
|
export async function betterAuthUpsertAccountIndexMutation(c: any, input: { id: string; providerId: string; accountId: string; userId: string }) {
|
||||||
c: any,
|
|
||||||
input: { id: string; providerId: string; accountId: string; userId: string },
|
|
||||||
) {
|
|
||||||
assertAppOrganization(c);
|
assertAppOrganization(c);
|
||||||
|
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
|
|
@ -198,8 +178,15 @@ export async function betterAuthDeleteAccountIndexMutation(c: any, input: { id?:
|
||||||
export async function betterAuthCreateVerificationMutation(c: any, input: { data: Record<string, unknown> }) {
|
export async function betterAuthCreateVerificationMutation(c: any, input: { data: Record<string, unknown> }) {
|
||||||
assertAppOrganization(c);
|
assertAppOrganization(c);
|
||||||
|
|
||||||
await c.db.insert(authVerification).values(input.data as any).run();
|
await c.db
|
||||||
return await c.db.select().from(authVerification).where(eq(authVerification.id, input.data.id as string)).get();
|
.insert(authVerification)
|
||||||
|
.values(input.data as any)
|
||||||
|
.run();
|
||||||
|
return await c.db
|
||||||
|
.select()
|
||||||
|
.from(authVerification)
|
||||||
|
.where(eq(authVerification.id, input.data.id as string))
|
||||||
|
.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function betterAuthUpdateVerificationMutation(c: any, input: { where: any[]; update: Record<string, unknown> }) {
|
export async function betterAuthUpdateVerificationMutation(c: any, input: { where: any[]; update: Record<string, unknown> }) {
|
||||||
|
|
@ -209,7 +196,11 @@ export async function betterAuthUpdateVerificationMutation(c: any, input: { wher
|
||||||
if (!predicate) {
|
if (!predicate) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
await c.db.update(authVerification).set(input.update as any).where(predicate).run();
|
await c.db
|
||||||
|
.update(authVerification)
|
||||||
|
.set(input.update as any)
|
||||||
|
.where(predicate)
|
||||||
|
.run();
|
||||||
return await c.db.select().from(authVerification).where(predicate).get();
|
return await c.db.select().from(authVerification).where(predicate).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -220,7 +211,11 @@ export async function betterAuthUpdateManyVerificationMutation(c: any, input: {
|
||||||
if (!predicate) {
|
if (!predicate) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
await c.db.update(authVerification).set(input.update as any).where(predicate).run();
|
await c.db
|
||||||
|
.update(authVerification)
|
||||||
|
.set(input.update as any)
|
||||||
|
.where(predicate)
|
||||||
|
.run();
|
||||||
const row = await c.db.select({ value: sqlCount() }).from(authVerification).where(predicate).get();
|
const row = await c.db.select({ value: sqlCount() }).from(authVerification).where(predicate).get();
|
||||||
return row?.value ?? 0;
|
return row?.value ?? 0;
|
||||||
}
|
}
|
||||||
|
|
@ -247,7 +242,71 @@ export async function betterAuthDeleteManyVerificationMutation(c: any, input: {
|
||||||
return rows.length;
|
return rows.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Better Auth adapter actions — exposed as actions (not queue commands) so they
|
||||||
|
* execute immediately without competing in the organization workflow queue.
|
||||||
|
*
|
||||||
|
* The org actor's workflow queue is shared with GitHub sync, webhook processing,
|
||||||
|
* task mutations, and billing operations. When the queue is busy, auth operations
|
||||||
|
* would time out (10s), causing Better Auth's parseState to throw a non-StateError
|
||||||
|
* which redirects to ?error=please_restart_the_process.
|
||||||
|
*
|
||||||
|
* Auth operations are safe to run as actions because they are simple SQLite
|
||||||
|
* reads/writes scoped to this actor instance with no cross-actor side effects.
|
||||||
|
*/
|
||||||
export const organizationBetterAuthActions = {
|
export const organizationBetterAuthActions = {
|
||||||
|
// --- Mutation actions (formerly queue commands) ---
|
||||||
|
|
||||||
|
async betterAuthCreateVerification(c: any, input: { data: Record<string, unknown> }) {
|
||||||
|
return await betterAuthCreateVerificationMutation(c, input);
|
||||||
|
},
|
||||||
|
|
||||||
|
async betterAuthUpdateVerification(c: any, input: { where: any[]; update: Record<string, unknown> }) {
|
||||||
|
return await betterAuthUpdateVerificationMutation(c, input);
|
||||||
|
},
|
||||||
|
|
||||||
|
async betterAuthUpdateManyVerification(c: any, input: { where: any[]; update: Record<string, unknown> }) {
|
||||||
|
return await betterAuthUpdateManyVerificationMutation(c, input);
|
||||||
|
},
|
||||||
|
|
||||||
|
async betterAuthDeleteVerification(c: any, input: { where: any[] }) {
|
||||||
|
await betterAuthDeleteVerificationMutation(c, input);
|
||||||
|
return { ok: true };
|
||||||
|
},
|
||||||
|
|
||||||
|
async betterAuthDeleteManyVerification(c: any, input: { where: any[] }) {
|
||||||
|
return await betterAuthDeleteManyVerificationMutation(c, input);
|
||||||
|
},
|
||||||
|
|
||||||
|
async betterAuthUpsertSessionIndex(c: any, input: { sessionId: string; sessionToken: string; userId: string }) {
|
||||||
|
return await betterAuthUpsertSessionIndexMutation(c, input);
|
||||||
|
},
|
||||||
|
|
||||||
|
async betterAuthDeleteSessionIndex(c: any, input: { sessionId?: string; sessionToken?: string }) {
|
||||||
|
await betterAuthDeleteSessionIndexMutation(c, input);
|
||||||
|
return { ok: true };
|
||||||
|
},
|
||||||
|
|
||||||
|
async betterAuthUpsertEmailIndex(c: any, input: { email: string; userId: string }) {
|
||||||
|
return await betterAuthUpsertEmailIndexMutation(c, input);
|
||||||
|
},
|
||||||
|
|
||||||
|
async betterAuthDeleteEmailIndex(c: any, input: { email: string }) {
|
||||||
|
await betterAuthDeleteEmailIndexMutation(c, input);
|
||||||
|
return { ok: true };
|
||||||
|
},
|
||||||
|
|
||||||
|
async betterAuthUpsertAccountIndex(c: any, input: { id: string; providerId: string; accountId: string; userId: string }) {
|
||||||
|
return await betterAuthUpsertAccountIndexMutation(c, input);
|
||||||
|
},
|
||||||
|
|
||||||
|
async betterAuthDeleteAccountIndex(c: any, input: { id?: string; providerId?: string; accountId?: string }) {
|
||||||
|
await betterAuthDeleteAccountIndexMutation(c, input);
|
||||||
|
return { ok: true };
|
||||||
|
},
|
||||||
|
|
||||||
|
// --- Read actions ---
|
||||||
|
|
||||||
async betterAuthFindSessionIndex(c: any, input: { sessionId?: string; sessionToken?: string }) {
|
async betterAuthFindSessionIndex(c: any, input: { sessionId?: string; sessionToken?: string }) {
|
||||||
assertAppOrganization(c);
|
assertAppOrganization(c);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,6 @@ export const ORGANIZATION_QUEUE_NAMES = [
|
||||||
"organization.command.refreshTaskSummaryForBranch",
|
"organization.command.refreshTaskSummaryForBranch",
|
||||||
"organization.command.snapshot.broadcast",
|
"organization.command.snapshot.broadcast",
|
||||||
"organization.command.syncGithubSession",
|
"organization.command.syncGithubSession",
|
||||||
"organization.command.better_auth.session_index.upsert",
|
|
||||||
"organization.command.better_auth.session_index.delete",
|
|
||||||
"organization.command.better_auth.email_index.upsert",
|
|
||||||
"organization.command.better_auth.email_index.delete",
|
|
||||||
"organization.command.better_auth.account_index.upsert",
|
|
||||||
"organization.command.better_auth.account_index.delete",
|
|
||||||
"organization.command.better_auth.verification.create",
|
|
||||||
"organization.command.better_auth.verification.update",
|
|
||||||
"organization.command.better_auth.verification.update_many",
|
|
||||||
"organization.command.better_auth.verification.delete",
|
|
||||||
"organization.command.better_auth.verification.delete_many",
|
|
||||||
"organization.command.github.sync_progress.apply",
|
"organization.command.github.sync_progress.apply",
|
||||||
"organization.command.github.webhook_receipt.record",
|
"organization.command.github.webhook_receipt.record",
|
||||||
"organization.command.github.organization_shell.sync_from_github",
|
"organization.command.github.organization_shell.sync_from_github",
|
||||||
|
|
|
||||||
|
|
@ -20,19 +20,6 @@ import {
|
||||||
registerTaskBranchMutation,
|
registerTaskBranchMutation,
|
||||||
removeTaskSummaryMutation,
|
removeTaskSummaryMutation,
|
||||||
} from "./actions/task-mutations.js";
|
} from "./actions/task-mutations.js";
|
||||||
import {
|
|
||||||
betterAuthCreateVerificationMutation,
|
|
||||||
betterAuthDeleteAccountIndexMutation,
|
|
||||||
betterAuthDeleteEmailIndexMutation,
|
|
||||||
betterAuthDeleteManyVerificationMutation,
|
|
||||||
betterAuthDeleteSessionIndexMutation,
|
|
||||||
betterAuthDeleteVerificationMutation,
|
|
||||||
betterAuthUpdateManyVerificationMutation,
|
|
||||||
betterAuthUpdateVerificationMutation,
|
|
||||||
betterAuthUpsertAccountIndexMutation,
|
|
||||||
betterAuthUpsertEmailIndexMutation,
|
|
||||||
betterAuthUpsertSessionIndexMutation,
|
|
||||||
} from "./actions/better-auth.js";
|
|
||||||
import {
|
import {
|
||||||
applyOrganizationFreePlanMutation,
|
applyOrganizationFreePlanMutation,
|
||||||
applyOrganizationStripeCustomerMutation,
|
applyOrganizationStripeCustomerMutation,
|
||||||
|
|
@ -85,31 +72,6 @@ const COMMAND_HANDLERS: Record<OrganizationQueueName, WorkflowHandler> = {
|
||||||
return { ok: true };
|
return { ok: true };
|
||||||
},
|
},
|
||||||
|
|
||||||
// Better Auth index mutations
|
|
||||||
"organization.command.better_auth.session_index.upsert": async (c, body) => betterAuthUpsertSessionIndexMutation(c, body),
|
|
||||||
"organization.command.better_auth.session_index.delete": async (c, body) => {
|
|
||||||
await betterAuthDeleteSessionIndexMutation(c, body);
|
|
||||||
return { ok: true };
|
|
||||||
},
|
|
||||||
"organization.command.better_auth.email_index.upsert": async (c, body) => betterAuthUpsertEmailIndexMutation(c, body),
|
|
||||||
"organization.command.better_auth.email_index.delete": async (c, body) => {
|
|
||||||
await betterAuthDeleteEmailIndexMutation(c, body);
|
|
||||||
return { ok: true };
|
|
||||||
},
|
|
||||||
"organization.command.better_auth.account_index.upsert": async (c, body) => betterAuthUpsertAccountIndexMutation(c, body),
|
|
||||||
"organization.command.better_auth.account_index.delete": async (c, body) => {
|
|
||||||
await betterAuthDeleteAccountIndexMutation(c, body);
|
|
||||||
return { ok: true };
|
|
||||||
},
|
|
||||||
"organization.command.better_auth.verification.create": async (c, body) => betterAuthCreateVerificationMutation(c, body),
|
|
||||||
"organization.command.better_auth.verification.update": async (c, body) => betterAuthUpdateVerificationMutation(c, body),
|
|
||||||
"organization.command.better_auth.verification.update_many": async (c, body) => betterAuthUpdateManyVerificationMutation(c, body),
|
|
||||||
"organization.command.better_auth.verification.delete": async (c, body) => {
|
|
||||||
await betterAuthDeleteVerificationMutation(c, body);
|
|
||||||
return { ok: true };
|
|
||||||
},
|
|
||||||
"organization.command.better_auth.verification.delete_many": async (c, body) => betterAuthDeleteManyVerificationMutation(c, body),
|
|
||||||
|
|
||||||
// GitHub sync mutations
|
// GitHub sync mutations
|
||||||
"organization.command.github.sync_progress.apply": async (c, body) => {
|
"organization.command.github.sync_progress.apply": async (c, body) => {
|
||||||
await applyGithubSyncProgressMutation(c, body);
|
await applyGithubSyncProgressMutation(c, body);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,51 @@
|
||||||
import { asc, count as sqlCount, desc } from "drizzle-orm";
|
import { asc, count as sqlCount, desc } from "drizzle-orm";
|
||||||
import { applyJoinToRow, applyJoinToRows, buildWhere, columnFor, tableFor } from "../query-helpers.js";
|
import { applyJoinToRow, applyJoinToRows, buildWhere, columnFor, tableFor } from "../query-helpers.js";
|
||||||
|
import {
|
||||||
|
createAuthRecordMutation,
|
||||||
|
updateAuthRecordMutation,
|
||||||
|
updateManyAuthRecordsMutation,
|
||||||
|
deleteAuthRecordMutation,
|
||||||
|
deleteManyAuthRecordsMutation,
|
||||||
|
} from "../workflow.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Better Auth adapter actions — exposed as actions (not queue commands) so they
|
||||||
|
* execute immediately without competing in the user workflow queue.
|
||||||
|
*
|
||||||
|
* The user actor's workflow queue is shared with profile upserts, session state,
|
||||||
|
* and task state operations. When the queue is busy, auth operations would time
|
||||||
|
* out (10s), causing Better Auth's parseState to throw a non-StateError which
|
||||||
|
* redirects to ?error=please_restart_the_process.
|
||||||
|
*
|
||||||
|
* Auth operations are safe to run as actions because they are simple SQLite
|
||||||
|
* reads/writes scoped to this actor instance with no cross-actor side effects.
|
||||||
|
*/
|
||||||
export const betterAuthActions = {
|
export const betterAuthActions = {
|
||||||
|
// --- Mutation actions (formerly queue commands) ---
|
||||||
|
|
||||||
|
async betterAuthCreateRecord(c: any, input: { model: string; data: Record<string, unknown> }) {
|
||||||
|
return await createAuthRecordMutation(c, input);
|
||||||
|
},
|
||||||
|
|
||||||
|
async betterAuthUpdateRecord(c: any, input: { model: string; where: any[]; update: Record<string, unknown> }) {
|
||||||
|
return await updateAuthRecordMutation(c, input);
|
||||||
|
},
|
||||||
|
|
||||||
|
async betterAuthUpdateManyRecords(c: any, input: { model: string; where: any[]; update: Record<string, unknown> }) {
|
||||||
|
return await updateManyAuthRecordsMutation(c, input);
|
||||||
|
},
|
||||||
|
|
||||||
|
async betterAuthDeleteRecord(c: any, input: { model: string; where: any[] }) {
|
||||||
|
await deleteAuthRecordMutation(c, input);
|
||||||
|
return { ok: true };
|
||||||
|
},
|
||||||
|
|
||||||
|
async betterAuthDeleteManyRecords(c: any, input: { model: string; where: any[] }) {
|
||||||
|
return await deleteManyAuthRecordsMutation(c, input);
|
||||||
|
},
|
||||||
|
|
||||||
|
// --- Read actions ---
|
||||||
|
|
||||||
// Better Auth adapter action — called by the Better Auth adapter in better-auth.ts.
|
// Better Auth adapter action — called by the Better Auth adapter in better-auth.ts.
|
||||||
// Schema and behavior are constrained by Better Auth.
|
// Schema and behavior are constrained by Better Auth.
|
||||||
async betterAuthFindOneRecord(c, input: { model: string; where: any[]; join?: any }) {
|
async betterAuthFindOneRecord(c, input: { model: string; where: any[]; join?: any }) {
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,6 @@ import { buildWhere, columnFor, materializeRow, persistInput, persistPatch, tabl
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export const USER_QUEUE_NAMES = [
|
export const USER_QUEUE_NAMES = [
|
||||||
"user.command.auth.create",
|
|
||||||
"user.command.auth.update",
|
|
||||||
"user.command.auth.update_many",
|
|
||||||
"user.command.auth.delete",
|
|
||||||
"user.command.auth.delete_many",
|
|
||||||
"user.command.profile.upsert",
|
"user.command.profile.upsert",
|
||||||
"user.command.session_state.upsert",
|
"user.command.session_state.upsert",
|
||||||
"user.command.task_state.upsert",
|
"user.command.task_state.upsert",
|
||||||
|
|
@ -240,14 +235,6 @@ export async function deleteTaskStateMutation(c: any, input: { taskId: string; s
|
||||||
type WorkflowHandler = (loopCtx: any, body: any) => Promise<any>;
|
type WorkflowHandler = (loopCtx: any, body: any) => Promise<any>;
|
||||||
|
|
||||||
const COMMAND_HANDLERS: Record<UserQueueName, WorkflowHandler> = {
|
const COMMAND_HANDLERS: Record<UserQueueName, WorkflowHandler> = {
|
||||||
"user.command.auth.create": async (c, body) => createAuthRecordMutation(c, body),
|
|
||||||
"user.command.auth.update": async (c, body) => updateAuthRecordMutation(c, body),
|
|
||||||
"user.command.auth.update_many": async (c, body) => updateManyAuthRecordsMutation(c, body),
|
|
||||||
"user.command.auth.delete": async (c, body) => {
|
|
||||||
await deleteAuthRecordMutation(c, body);
|
|
||||||
return { ok: true };
|
|
||||||
},
|
|
||||||
"user.command.auth.delete_many": async (c, body) => deleteManyAuthRecordsMutation(c, body),
|
|
||||||
"user.command.profile.upsert": async (c, body) => upsertUserProfileMutation(c, body),
|
"user.command.profile.upsert": async (c, body) => upsertUserProfileMutation(c, body),
|
||||||
"user.command.session_state.upsert": async (c, body) => upsertSessionStateMutation(c, body),
|
"user.command.session_state.upsert": async (c, body) => upsertSessionStateMutation(c, body),
|
||||||
"user.command.task_state.upsert": async (c, body) => upsertTaskStateMutation(c, body),
|
"user.command.task_state.upsert": async (c, body) => upsertTaskStateMutation(c, body),
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import { organizationKey, userKey } from "../actors/keys.js";
|
||||||
import { logger } from "../logging.js";
|
import { logger } from "../logging.js";
|
||||||
import { expectQueueResponse } from "./queue.js";
|
import { expectQueueResponse } from "./queue.js";
|
||||||
import { userWorkflowQueueName } from "../actors/user/workflow.js";
|
import { userWorkflowQueueName } from "../actors/user/workflow.js";
|
||||||
import { organizationWorkflowQueueName } from "../actors/organization/queues.js";
|
|
||||||
|
|
||||||
const AUTH_BASE_PATH = "/v1/auth";
|
const AUTH_BASE_PATH = "/v1/auth";
|
||||||
const SESSION_COOKIE = "better-auth.session_token";
|
const SESSION_COOKIE = "better-auth.session_token";
|
||||||
|
|
@ -160,11 +159,6 @@ export function initBetterAuthService(actorClient: any, options: { apiUrl: strin
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ensureOrganizationVerification = async (queueName: string, payload: Record<string, unknown>) => {
|
|
||||||
const organization = await appOrganization();
|
|
||||||
return expectQueueResponse(await organization.send(organizationWorkflowQueueName(queueName as any), payload, { wait: true, timeout: 10_000 }));
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
options: {
|
options: {
|
||||||
useDatabaseGeneratedIds: false,
|
useDatabaseGeneratedIds: false,
|
||||||
|
|
@ -173,7 +167,8 @@ export function initBetterAuthService(actorClient: any, options: { apiUrl: strin
|
||||||
create: async ({ model, data }) => {
|
create: async ({ model, data }) => {
|
||||||
const transformed = await transformInput(data, model, "create", true);
|
const transformed = await transformInput(data, model, "create", true);
|
||||||
if (model === "verification") {
|
if (model === "verification") {
|
||||||
return await ensureOrganizationVerification("organization.command.better_auth.verification.create", { data: transformed });
|
const organization = await appOrganization();
|
||||||
|
return await organization.betterAuthCreateVerification({ data: transformed });
|
||||||
}
|
}
|
||||||
|
|
||||||
const userId = await resolveUserIdForQuery(model, undefined, transformed);
|
const userId = await resolveUserIdForQuery(model, undefined, transformed);
|
||||||
|
|
@ -182,51 +177,31 @@ export function initBetterAuthService(actorClient: any, options: { apiUrl: strin
|
||||||
}
|
}
|
||||||
|
|
||||||
const userActor = await getUser(userId);
|
const userActor = await getUser(userId);
|
||||||
const created = expectQueueResponse(
|
const created = await userActor.betterAuthCreateRecord({ model, data: transformed });
|
||||||
await userActor.send(userWorkflowQueueName("user.command.auth.create"), { model, data: transformed }, { wait: true, timeout: 10_000 }),
|
|
||||||
);
|
|
||||||
const organization = await appOrganization();
|
const organization = await appOrganization();
|
||||||
|
|
||||||
if (model === "user" && typeof transformed.email === "string" && transformed.email.length > 0) {
|
if (model === "user" && typeof transformed.email === "string" && transformed.email.length > 0) {
|
||||||
expectQueueResponse(
|
await organization.betterAuthUpsertEmailIndex({
|
||||||
await organization.send(
|
email: transformed.email.toLowerCase(),
|
||||||
organizationWorkflowQueueName("organization.command.better_auth.email_index.upsert"),
|
userId,
|
||||||
{
|
});
|
||||||
email: transformed.email.toLowerCase(),
|
|
||||||
userId,
|
|
||||||
},
|
|
||||||
{ wait: true, timeout: 10_000 },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model === "session") {
|
if (model === "session") {
|
||||||
expectQueueResponse(
|
await organization.betterAuthUpsertSessionIndex({
|
||||||
await organization.send(
|
sessionId: String(created.id),
|
||||||
organizationWorkflowQueueName("organization.command.better_auth.session_index.upsert"),
|
sessionToken: String(created.token),
|
||||||
{
|
userId,
|
||||||
sessionId: String(created.id),
|
});
|
||||||
sessionToken: String(created.token),
|
|
||||||
userId,
|
|
||||||
},
|
|
||||||
{ wait: true, timeout: 10_000 },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model === "account") {
|
if (model === "account") {
|
||||||
expectQueueResponse(
|
await organization.betterAuthUpsertAccountIndex({
|
||||||
await organization.send(
|
id: String(created.id),
|
||||||
organizationWorkflowQueueName("organization.command.better_auth.account_index.upsert"),
|
providerId: String(created.providerId),
|
||||||
{
|
accountId: String(created.accountId),
|
||||||
id: String(created.id),
|
userId,
|
||||||
providerId: String(created.providerId),
|
});
|
||||||
accountId: String(created.accountId),
|
|
||||||
userId,
|
|
||||||
},
|
|
||||||
{ wait: true, timeout: 10_000 },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (await transformOutput(created, model)) as any;
|
return (await transformOutput(created, model)) as any;
|
||||||
|
|
@ -309,7 +284,8 @@ export function initBetterAuthService(actorClient: any, options: { apiUrl: strin
|
||||||
const transformedWhere = transformWhereClause({ model, where, action: "update" });
|
const transformedWhere = transformWhereClause({ model, where, action: "update" });
|
||||||
const transformedUpdate = (await transformInput(update as Record<string, unknown>, model, "update", true)) as Record<string, unknown>;
|
const transformedUpdate = (await transformInput(update as Record<string, unknown>, model, "update", true)) as Record<string, unknown>;
|
||||||
if (model === "verification") {
|
if (model === "verification") {
|
||||||
return await ensureOrganizationVerification("organization.command.better_auth.verification.update", {
|
const organization = await appOrganization();
|
||||||
|
return await organization.betterAuthUpdateVerification({
|
||||||
where: transformedWhere,
|
where: transformedWhere,
|
||||||
update: transformedUpdate,
|
update: transformedUpdate,
|
||||||
});
|
});
|
||||||
|
|
@ -329,66 +305,42 @@ export function initBetterAuthService(actorClient: any, options: { apiUrl: strin
|
||||||
: model === "session"
|
: model === "session"
|
||||||
? await userActor.betterAuthFindOneRecord({ model, where: transformedWhere })
|
? await userActor.betterAuthFindOneRecord({ model, where: transformedWhere })
|
||||||
: null;
|
: null;
|
||||||
const updated = expectQueueResponse(
|
const updated = await userActor.betterAuthUpdateRecord({
|
||||||
await userActor.send(
|
model,
|
||||||
userWorkflowQueueName("user.command.auth.update"),
|
where: transformedWhere,
|
||||||
{ model, where: transformedWhere, update: transformedUpdate },
|
update: transformedUpdate,
|
||||||
{ wait: true, timeout: 10_000 },
|
});
|
||||||
),
|
|
||||||
);
|
|
||||||
const organization = await appOrganization();
|
const organization = await appOrganization();
|
||||||
|
|
||||||
if (model === "user" && updated) {
|
if (model === "user" && updated) {
|
||||||
if (before?.email && before.email !== updated.email) {
|
if (before?.email && before.email !== updated.email) {
|
||||||
await organization.send(
|
await organization.betterAuthDeleteEmailIndex({
|
||||||
organizationWorkflowQueueName("organization.command.better_auth.email_index.delete"),
|
email: before.email.toLowerCase(),
|
||||||
{
|
});
|
||||||
email: before.email.toLowerCase(),
|
|
||||||
},
|
|
||||||
{ wait: true, timeout: 10_000 },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (updated.email) {
|
if (updated.email) {
|
||||||
expectQueueResponse(
|
await organization.betterAuthUpsertEmailIndex({
|
||||||
await organization.send(
|
email: updated.email.toLowerCase(),
|
||||||
organizationWorkflowQueueName("organization.command.better_auth.email_index.upsert"),
|
userId,
|
||||||
{
|
});
|
||||||
email: updated.email.toLowerCase(),
|
|
||||||
userId,
|
|
||||||
},
|
|
||||||
{ wait: true, timeout: 10_000 },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model === "session" && updated) {
|
if (model === "session" && updated) {
|
||||||
expectQueueResponse(
|
await organization.betterAuthUpsertSessionIndex({
|
||||||
await organization.send(
|
sessionId: String(updated.id),
|
||||||
organizationWorkflowQueueName("organization.command.better_auth.session_index.upsert"),
|
sessionToken: String(updated.token),
|
||||||
{
|
userId,
|
||||||
sessionId: String(updated.id),
|
});
|
||||||
sessionToken: String(updated.token),
|
|
||||||
userId,
|
|
||||||
},
|
|
||||||
{ wait: true, timeout: 10_000 },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model === "account" && updated) {
|
if (model === "account" && updated) {
|
||||||
expectQueueResponse(
|
await organization.betterAuthUpsertAccountIndex({
|
||||||
await organization.send(
|
id: String(updated.id),
|
||||||
organizationWorkflowQueueName("organization.command.better_auth.account_index.upsert"),
|
providerId: String(updated.providerId),
|
||||||
{
|
accountId: String(updated.accountId),
|
||||||
id: String(updated.id),
|
userId,
|
||||||
providerId: String(updated.providerId),
|
});
|
||||||
accountId: String(updated.accountId),
|
|
||||||
userId,
|
|
||||||
},
|
|
||||||
{ wait: true, timeout: 10_000 },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return updated ? ((await transformOutput(updated, model)) as any) : null;
|
return updated ? ((await transformOutput(updated, model)) as any) : null;
|
||||||
|
|
@ -398,7 +350,8 @@ export function initBetterAuthService(actorClient: any, options: { apiUrl: strin
|
||||||
const transformedWhere = transformWhereClause({ model, where, action: "updateMany" });
|
const transformedWhere = transformWhereClause({ model, where, action: "updateMany" });
|
||||||
const transformedUpdate = (await transformInput(update as Record<string, unknown>, model, "update", true)) as Record<string, unknown>;
|
const transformedUpdate = (await transformInput(update as Record<string, unknown>, model, "update", true)) as Record<string, unknown>;
|
||||||
if (model === "verification") {
|
if (model === "verification") {
|
||||||
return await ensureOrganizationVerification("organization.command.better_auth.verification.update_many", {
|
const organization = await appOrganization();
|
||||||
|
return await organization.betterAuthUpdateManyVerification({
|
||||||
where: transformedWhere,
|
where: transformedWhere,
|
||||||
update: transformedUpdate,
|
update: transformedUpdate,
|
||||||
});
|
});
|
||||||
|
|
@ -410,24 +363,18 @@ export function initBetterAuthService(actorClient: any, options: { apiUrl: strin
|
||||||
}
|
}
|
||||||
|
|
||||||
const userActor = await getUser(userId);
|
const userActor = await getUser(userId);
|
||||||
return expectQueueResponse(
|
return await userActor.betterAuthUpdateManyRecords({
|
||||||
await userActor.send(
|
model,
|
||||||
userWorkflowQueueName("user.command.auth.update_many"),
|
where: transformedWhere,
|
||||||
{ model, where: transformedWhere, update: transformedUpdate },
|
update: transformedUpdate,
|
||||||
{ wait: true, timeout: 10_000 },
|
});
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
delete: async ({ model, where }) => {
|
delete: async ({ model, where }) => {
|
||||||
const transformedWhere = transformWhereClause({ model, where, action: "delete" });
|
const transformedWhere = transformWhereClause({ model, where, action: "delete" });
|
||||||
if (model === "verification") {
|
if (model === "verification") {
|
||||||
const organization = await appOrganization();
|
const organization = await appOrganization();
|
||||||
await organization.send(
|
await organization.betterAuthDeleteVerification({ where: transformedWhere });
|
||||||
organizationWorkflowQueueName("organization.command.better_auth.verification.delete"),
|
|
||||||
{ where: transformedWhere },
|
|
||||||
{ wait: true, timeout: 10_000 },
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -439,46 +386,35 @@ export function initBetterAuthService(actorClient: any, options: { apiUrl: strin
|
||||||
const userActor = await getUser(userId);
|
const userActor = await getUser(userId);
|
||||||
const organization = await appOrganization();
|
const organization = await appOrganization();
|
||||||
const before = await userActor.betterAuthFindOneRecord({ model, where: transformedWhere });
|
const before = await userActor.betterAuthFindOneRecord({ model, where: transformedWhere });
|
||||||
await userActor.send(userWorkflowQueueName("user.command.auth.delete"), { model, where: transformedWhere }, { wait: true, timeout: 10_000 });
|
await userActor.betterAuthDeleteRecord({ model, where: transformedWhere });
|
||||||
|
|
||||||
if (model === "session" && before) {
|
if (model === "session" && before) {
|
||||||
await organization.send(
|
await organization.betterAuthDeleteSessionIndex({
|
||||||
organizationWorkflowQueueName("organization.command.better_auth.session_index.delete"),
|
sessionId: before.id,
|
||||||
{
|
sessionToken: before.token,
|
||||||
sessionId: before.id,
|
});
|
||||||
sessionToken: before.token,
|
|
||||||
},
|
|
||||||
{ wait: true, timeout: 10_000 },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model === "account" && before) {
|
if (model === "account" && before) {
|
||||||
await organization.send(
|
await organization.betterAuthDeleteAccountIndex({
|
||||||
organizationWorkflowQueueName("organization.command.better_auth.account_index.delete"),
|
id: before.id,
|
||||||
{
|
providerId: before.providerId,
|
||||||
id: before.id,
|
accountId: before.accountId,
|
||||||
providerId: before.providerId,
|
});
|
||||||
accountId: before.accountId,
|
|
||||||
},
|
|
||||||
{ wait: true, timeout: 10_000 },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model === "user" && before?.email) {
|
if (model === "user" && before?.email) {
|
||||||
await organization.send(
|
await organization.betterAuthDeleteEmailIndex({
|
||||||
organizationWorkflowQueueName("organization.command.better_auth.email_index.delete"),
|
email: before.email.toLowerCase(),
|
||||||
{
|
});
|
||||||
email: before.email.toLowerCase(),
|
|
||||||
},
|
|
||||||
{ wait: true, timeout: 10_000 },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteMany: async ({ model, where }) => {
|
deleteMany: async ({ model, where }) => {
|
||||||
const transformedWhere = transformWhereClause({ model, where, action: "deleteMany" });
|
const transformedWhere = transformWhereClause({ model, where, action: "deleteMany" });
|
||||||
if (model === "verification") {
|
if (model === "verification") {
|
||||||
return await ensureOrganizationVerification("organization.command.better_auth.verification.delete_many", { where: transformedWhere });
|
const organization = await appOrganization();
|
||||||
|
return await organization.betterAuthDeleteManyVerification({ where: transformedWhere });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model === "session") {
|
if (model === "session") {
|
||||||
|
|
@ -489,18 +425,12 @@ export function initBetterAuthService(actorClient: any, options: { apiUrl: strin
|
||||||
const userActor = await getUser(userId);
|
const userActor = await getUser(userId);
|
||||||
const organization = await appOrganization();
|
const organization = await appOrganization();
|
||||||
const sessions = await userActor.betterAuthFindManyRecords({ model, where: transformedWhere, limit: 5000 });
|
const sessions = await userActor.betterAuthFindManyRecords({ model, where: transformedWhere, limit: 5000 });
|
||||||
const deleted = expectQueueResponse(
|
const deleted = await userActor.betterAuthDeleteManyRecords({ model, where: transformedWhere });
|
||||||
await userActor.send(userWorkflowQueueName("user.command.auth.delete_many"), { model, where: transformedWhere }, { wait: true, timeout: 10_000 }),
|
|
||||||
);
|
|
||||||
for (const session of sessions) {
|
for (const session of sessions) {
|
||||||
await organization.send(
|
await organization.betterAuthDeleteSessionIndex({
|
||||||
organizationWorkflowQueueName("organization.command.better_auth.session_index.delete"),
|
sessionId: session.id,
|
||||||
{
|
sessionToken: session.token,
|
||||||
sessionId: session.id,
|
});
|
||||||
sessionToken: session.token,
|
|
||||||
},
|
|
||||||
{ wait: true, timeout: 10_000 },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return deleted;
|
return deleted;
|
||||||
}
|
}
|
||||||
|
|
@ -511,10 +441,7 @@ export function initBetterAuthService(actorClient: any, options: { apiUrl: strin
|
||||||
}
|
}
|
||||||
|
|
||||||
const userActor = await getUser(userId);
|
const userActor = await getUser(userId);
|
||||||
const deleted = expectQueueResponse(
|
return await userActor.betterAuthDeleteManyRecords({ model, where: transformedWhere });
|
||||||
await userActor.send(userWorkflowQueueName("user.command.auth.delete_many"), { model, where: transformedWhere }, { wait: true, timeout: 10_000 }),
|
|
||||||
);
|
|
||||||
return deleted;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
count: async ({ model, where }) => {
|
count: async ({ model, where }) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue