multitenancy.ts124 lines · main
1/**
2 * Multitenancy on Doltgres — project → tenant rows in be_tenants.
3 */
4
5import { getEnginePool } from './db.js';
6import { isAuthCoreInitialized } from './engine.js';
7import { mapProjectToAuthCore } from './project-map.js';
8import { log } from '../../lib/logger.js';
9
10export type EnsureTenantResult = {
11 engine: 'briven-engine';
12 projectId: string;
13 appId: string;
14 tenantId: string;
15 created: boolean;
16 ok: boolean;
17 message?: string;
18 storage: 'doltgres';
19};
20
21export async function ensureBrivenEngineTenant(
22 projectId: string,
23): Promise<EnsureTenantResult> {
24 const map = mapProjectToAuthCore(projectId);
25 const base = {
26 engine: 'briven-engine' as const,
27 storage: 'doltgres' as const,
28 projectId: map.projectId,
29 appId: map.appId,
30 tenantId: map.tenantId,
31 };
32
33 if (!isAuthCoreInitialized()) {
34 return {
35 ...base,
36 created: false,
37 ok: false,
38 message: 'briven-engine not ready on Doltgres',
39 };
40 }
41
42 try {
43 const pool = getEnginePool();
44 const existing = await pool.query(
45 `SELECT tenant_id FROM be_tenants WHERE tenant_id = $1 LIMIT 1`,
46 [map.tenantId],
47 );
48 if (existing.rowCount && existing.rowCount > 0) {
49 return { ...base, created: false, ok: true, message: 'tenant exists' };
50 }
51 await pool.query(
52 `INSERT INTO be_tenants (tenant_id, project_id) VALUES ($1, $2)`,
53 [map.tenantId, map.projectId],
54 );
55 log.info('briven_engine_tenant_created', {
56 tenantId: map.tenantId,
57 projectId,
58 storage: 'doltgres',
59 });
60 return { ...base, created: true, ok: true, message: 'tenant created on Doltgres' };
61 } catch (err) {
62 const message = err instanceof Error ? err.message : String(err);
63 return { ...base, created: false, ok: false, message };
64 }
65}
66
67export async function listBrivenEngineTenants(): Promise<{
68 engine: 'briven-engine';
69 tenantIds: string[];
70 tenants: Array<{
71 tenantId: string;
72 projectId: string;
73 createdAt: string | null;
74 authEnabled: true;
75 }>;
76 ok: boolean;
77 message?: string;
78 storage: 'doltgres';
79}> {
80 if (!isAuthCoreInitialized()) {
81 return {
82 engine: 'briven-engine',
83 storage: 'doltgres',
84 tenantIds: [],
85 tenants: [],
86 ok: false,
87 message: 'sdk not ready',
88 };
89 }
90 try {
91 const pool = getEnginePool();
92 const res = await pool.query(
93 `SELECT tenant_id, project_id, created_at FROM be_tenants ORDER BY created_at`,
94 );
95 const tenants = (
96 res.rows as Array<{
97 tenant_id: string;
98 project_id: string;
99 created_at: Date | string | null;
100 }>
101 ).map((r) => ({
102 tenantId: r.tenant_id,
103 projectId: r.project_id,
104 createdAt: r.created_at ? new Date(r.created_at).toISOString() : null,
105 authEnabled: true as const,
106 }));
107 return {
108 engine: 'briven-engine',
109 storage: 'doltgres',
110 tenantIds: tenants.map((t) => t.tenantId),
111 tenants,
112 ok: true,
113 };
114 } catch (err) {
115 return {
116 engine: 'briven-engine',
117 storage: 'doltgres',
118 tenantIds: [],
119 tenants: [],
120 ok: false,
121 message: err instanceof Error ? err.message : String(err),
122 };
123 }
124}