(client: Client)
| 278 | * idempotency reads against the auth tables Better Auth just migrated. |
| 279 | */ |
| 280 | export const buildBetterAuth = async (client: Client): Promise<BetterAuthHandle> => { |
| 281 | const config = loadConfig(); |
| 282 | |
| 283 | // The org id is resolved by the seed below, AFTER this instance is built; the |
| 284 | // session-pin hook and the gate read it through these late-bound accessors |
| 285 | // (no session is created during the seed, so the empty initial id is never |
| 286 | // observed). `getAuth` resolves to this very instance, so the gate's `after` |
| 287 | // hook can call `auth.api.addMember` once a code is redeemed. |
| 288 | let auth: Auth | null = null; |
| 289 | const orgRef = { id: "" }; |
| 290 | const gate: SignupGate = { |
| 291 | client, |
| 292 | get organizationId() { |
| 293 | return orgRef.id; |
| 294 | }, |
| 295 | getAuth: () => auth, |
| 296 | }; |
| 297 | |
| 298 | auth = createAuthInstance(client, () => orgRef.id, gate); |
| 299 | // `runMigrations()` flows through the LibsqlDialect and is idempotent. |
| 300 | await (await auth.$context).runMigrations(); |
| 301 | await ensureInviteCodeTable(client); |
| 302 | const { organizationId, organizationName } = await seedOrgAndAdmin(auth, client, config); |
| 303 | orgRef.id = organizationId; |
| 304 | |
| 305 | return { |
| 306 | auth, |
| 307 | organizationId, |
| 308 | organizationName, |
| 309 | organizationSlug: config.orgSlug, |
| 310 | handler: auth.handler, |
| 311 | }; |
| 312 | }; |
no test coverage detected