dashboard.ts156 lines · main
| 1 | /** |
| 2 | * Yellow Authentication dashboard data — all from Doltgres briven-engine. |
| 3 | */ |
| 4 | |
| 5 | import { getEnginePool } from './db.js'; |
| 6 | import { |
| 7 | BRIVEN_ENGINE_ID, |
| 8 | getAuthCoreRecipeMeta, |
| 9 | isAuthCoreInitialized, |
| 10 | probeBrivenEngine, |
| 11 | } from './engine.js'; |
| 12 | import { BRIVEN_ENGINE_RECIPE_CATALOG, getRecipePhase } from './recipes.js'; |
| 13 | import { listBrivenEngineUsers } from './users.js'; |
| 14 | |
| 15 | export type BrivenEngineDashboard = { |
| 16 | engine: typeof BRIVEN_ENGINE_ID; |
| 17 | storage: 'doltgres'; |
| 18 | database: 'briven_engine'; |
| 19 | ok: boolean; |
| 20 | message: string; |
| 21 | counts: { |
| 22 | users: number; |
| 23 | sessions: number; |
| 24 | tenants: number; |
| 25 | thirdPartyLinks: number; |
| 26 | passwordlessCodesActive: number; |
| 27 | }; |
| 28 | methods: { |
| 29 | emailPassword: boolean; |
| 30 | passwordlessEmail: boolean; |
| 31 | passwordlessSms: boolean; |
| 32 | google: boolean; |
| 33 | github: boolean; |
| 34 | webauthn: boolean; |
| 35 | mfa: boolean; |
| 36 | }; |
| 37 | recentUsers: Array<{ |
| 38 | id: string; |
| 39 | emails: string[]; |
| 40 | phoneNumbers: string[]; |
| 41 | tenantId?: string; |
| 42 | timeJoined: number; |
| 43 | }>; |
| 44 | recipesLoaded: string[]; |
| 45 | recipePhase: number | null; |
| 46 | }; |
| 47 | |
| 48 | export async function getBrivenEngineDashboard(opts?: { |
| 49 | tenantId?: string; |
| 50 | projectId?: string; |
| 51 | }): Promise<BrivenEngineDashboard & { projectId?: string; tenantId?: string }> { |
| 52 | const probe = await probeBrivenEngine(); |
| 53 | const meta = getAuthCoreRecipeMeta(); |
| 54 | const phase = getRecipePhase(); |
| 55 | const names = new Set(meta.names.length ? meta.names : BRIVEN_ENGINE_RECIPE_CATALOG.filter((r) => r.phase <= phase).map((r) => r.id)); |
| 56 | |
| 57 | const baseMethods = { |
| 58 | emailPassword: names.has('emailpassword'), |
| 59 | passwordlessEmail: names.has('passwordless'), |
| 60 | passwordlessSms: names.has('passwordless'), |
| 61 | google: names.has('thirdparty'), |
| 62 | github: names.has('thirdparty'), |
| 63 | webauthn: names.has('webauthn'), |
| 64 | mfa: names.has('multifactorauth'), |
| 65 | }; |
| 66 | |
| 67 | if (!isAuthCoreInitialized() || !probe.ok) { |
| 68 | return { |
| 69 | engine: BRIVEN_ENGINE_ID, |
| 70 | storage: 'doltgres', |
| 71 | database: 'briven_engine', |
| 72 | ok: false, |
| 73 | message: probe.message, |
| 74 | counts: { |
| 75 | users: 0, |
| 76 | sessions: 0, |
| 77 | tenants: 0, |
| 78 | thirdPartyLinks: 0, |
| 79 | passwordlessCodesActive: 0, |
| 80 | }, |
| 81 | methods: baseMethods, |
| 82 | recentUsers: [], |
| 83 | recipesLoaded: meta.names, |
| 84 | recipePhase: meta.phase, |
| 85 | projectId: opts?.projectId, |
| 86 | tenantId: opts?.tenantId, |
| 87 | }; |
| 88 | } |
| 89 | |
| 90 | const pool = getEnginePool(); |
| 91 | const tid = opts?.tenantId; |
| 92 | const [usersC, sessionsC, tenantsC, linksC, codesC] = await Promise.all([ |
| 93 | tid |
| 94 | ? pool.query( |
| 95 | `SELECT COUNT(*)::int AS n FROM be_users WHERE tenant_id = $1`, |
| 96 | [tid], |
| 97 | ) |
| 98 | : pool.query(`SELECT COUNT(*)::int AS n FROM be_users`), |
| 99 | tid |
| 100 | ? pool.query( |
| 101 | `SELECT COUNT(*)::int AS n FROM be_sessions WHERE expires_at > NOW() AND tenant_id = $1`, |
| 102 | [tid], |
| 103 | ) |
| 104 | : pool.query( |
| 105 | `SELECT COUNT(*)::int AS n FROM be_sessions WHERE expires_at > NOW()`, |
| 106 | ), |
| 107 | pool.query(`SELECT COUNT(*)::int AS n FROM be_tenants`), |
| 108 | tid |
| 109 | ? pool.query( |
| 110 | `SELECT COUNT(*)::int AS n FROM be_third_party_links WHERE tenant_id = $1`, |
| 111 | [tid], |
| 112 | ) |
| 113 | : pool.query(`SELECT COUNT(*)::int AS n FROM be_third_party_links`), |
| 114 | tid |
| 115 | ? pool.query( |
| 116 | `SELECT COUNT(*)::int AS n FROM be_passwordless_codes WHERE expires_at > NOW() AND tenant_id = $1`, |
| 117 | [tid], |
| 118 | ) |
| 119 | : pool.query( |
| 120 | `SELECT COUNT(*)::int AS n FROM be_passwordless_codes WHERE expires_at > NOW()`, |
| 121 | ), |
| 122 | ]); |
| 123 | |
| 124 | const listed = await listBrivenEngineUsers({ |
| 125 | limit: 20, |
| 126 | tenantId: tid, |
| 127 | }); |
| 128 | |
| 129 | return { |
| 130 | engine: BRIVEN_ENGINE_ID, |
| 131 | storage: 'doltgres', |
| 132 | database: 'briven_engine', |
| 133 | ok: true, |
| 134 | message: tid |
| 135 | ? 'dashboard data for one Auth project (tenant)' |
| 136 | : 'dashboard data from Doltgres', |
| 137 | counts: { |
| 138 | users: (usersC.rows[0] as { n: number }).n, |
| 139 | sessions: (sessionsC.rows[0] as { n: number }).n, |
| 140 | tenants: (tenantsC.rows[0] as { n: number }).n, |
| 141 | thirdPartyLinks: (linksC.rows[0] as { n: number }).n, |
| 142 | passwordlessCodesActive: (codesC.rows[0] as { n: number }).n, |
| 143 | }, |
| 144 | methods: baseMethods, |
| 145 | recentUsers: listed.users.map((u) => ({ |
| 146 | id: u.id, |
| 147 | emails: u.emails, |
| 148 | phoneNumbers: u.phoneNumbers, |
| 149 | timeJoined: u.timeJoined, |
| 150 | })), |
| 151 | recipesLoaded: meta.names, |
| 152 | recipePhase: meta.phase, |
| 153 | projectId: opts?.projectId, |
| 154 | tenantId: opts?.tenantId, |
| 155 | }; |
| 156 | } |