better-auth-studio 1.0.5 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -1
- package/frontend/index.html +0 -13
- package/frontend/package-lock.json +0 -4675
- package/frontend/package.json +0 -52
- package/frontend/pnpm-lock.yaml +0 -4020
- package/frontend/postcss.config.js +0 -6
- package/frontend/src/App.tsx +0 -36
- package/frontend/src/components/CommandPalette.tsx +0 -219
- package/frontend/src/components/Layout.tsx +0 -159
- package/frontend/src/components/ui/badge.tsx +0 -40
- package/frontend/src/components/ui/button.tsx +0 -53
- package/frontend/src/components/ui/card.tsx +0 -78
- package/frontend/src/components/ui/input.tsx +0 -20
- package/frontend/src/components/ui/label.tsx +0 -19
- package/frontend/src/components/ui/select.tsx +0 -71
- package/frontend/src/index.css +0 -130
- package/frontend/src/lib/utils.ts +0 -6
- package/frontend/src/main.tsx +0 -10
- package/frontend/src/pages/Dashboard.tsx +0 -231
- package/frontend/src/pages/OrganizationDetails.tsx +0 -1281
- package/frontend/src/pages/Organizations.tsx +0 -874
- package/frontend/src/pages/Sessions.tsx +0 -623
- package/frontend/src/pages/Settings.tsx +0 -1019
- package/frontend/src/pages/TeamDetails.tsx +0 -666
- package/frontend/src/pages/Users.tsx +0 -728
- package/frontend/tailwind.config.js +0 -75
- package/frontend/tsconfig.json +0 -31
- package/frontend/tsconfig.node.json +0 -10
- package/frontend/vite.config.ts +0 -31
- package/src/auth-adapter.ts +0 -473
- package/src/cli.ts +0 -51
- package/src/config.ts +0 -320
- package/src/data.ts +0 -351
- package/src/routes.ts +0 -1585
- package/src/studio.ts +0 -86
- package/test-project/README.md +0 -0
- package/test-project/better-auth.db +0 -0
- package/test-project/better-auth_migrations/2025-08-27T15-55-04.099Z.sql +0 -7
- package/test-project/better-auth_migrations/2025-09-04T02-33-19.422Z.sql +0 -7
- package/test-project/package.json +0 -29
- package/test-project/pnpm-lock.yaml +0 -1728
- package/test-project/src/auth.ts +0 -47
- package/test-project/src/index.ts +0 -40
- package/tsconfig.json +0 -21
package/src/config.ts
DELETED
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
import { readFileSync, existsSync } from 'fs';
|
|
2
|
-
import { join, dirname } from 'path';
|
|
3
|
-
|
|
4
|
-
export interface AuthProvider {
|
|
5
|
-
type: string;
|
|
6
|
-
clientId?: string;
|
|
7
|
-
clientSecret?: string;
|
|
8
|
-
redirectUri?: string;
|
|
9
|
-
[key: string]: any;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface AuthDatabase {
|
|
13
|
-
url?: string;
|
|
14
|
-
type?: string;
|
|
15
|
-
dialect?: string;
|
|
16
|
-
[key: string]: any;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface AuthConfig {
|
|
20
|
-
database?: AuthDatabase;
|
|
21
|
-
providers?: AuthProvider[];
|
|
22
|
-
socialProviders?: Record<string, any>;
|
|
23
|
-
emailAndPassword?: any;
|
|
24
|
-
session?: any;
|
|
25
|
-
secret?: string;
|
|
26
|
-
rateLimit?: any;
|
|
27
|
-
[key: string]: any;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export async function findAuthConfig(): Promise<AuthConfig | null> {
|
|
31
|
-
const possibleConfigFiles = [
|
|
32
|
-
'studio-config.json',
|
|
33
|
-
'auth.ts',
|
|
34
|
-
'auth.js',
|
|
35
|
-
'src/auth.ts',
|
|
36
|
-
'src/auth.js',
|
|
37
|
-
'lib/auth.ts',
|
|
38
|
-
'lib/auth.js',
|
|
39
|
-
'better-auth.config.ts',
|
|
40
|
-
'better-auth.config.js',
|
|
41
|
-
'better-auth.config.json',
|
|
42
|
-
'auth.config.ts',
|
|
43
|
-
'auth.config.js',
|
|
44
|
-
'auth.config.json'
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
let currentDir = process.cwd();
|
|
48
|
-
const maxDepth = 10;
|
|
49
|
-
let depth = 0;
|
|
50
|
-
|
|
51
|
-
while (currentDir && depth < maxDepth) {
|
|
52
|
-
for (const configFile of possibleConfigFiles) {
|
|
53
|
-
const configPath = join(currentDir, configFile);
|
|
54
|
-
|
|
55
|
-
if (existsSync(configPath)) {
|
|
56
|
-
try {
|
|
57
|
-
const config = await loadConfig(configPath);
|
|
58
|
-
if (config) {
|
|
59
|
-
return config;
|
|
60
|
-
}
|
|
61
|
-
} catch (error) {
|
|
62
|
-
console.warn(`Failed to load config from ${configPath}:`, error);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const parentDir = dirname(currentDir);
|
|
68
|
-
if (parentDir === currentDir) {
|
|
69
|
-
break;
|
|
70
|
-
}
|
|
71
|
-
currentDir = parentDir;
|
|
72
|
-
depth++;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async function loadConfig(configPath: string): Promise<AuthConfig | null> {
|
|
79
|
-
const ext = configPath.split('.').pop();
|
|
80
|
-
|
|
81
|
-
try {
|
|
82
|
-
if (ext === 'json') {
|
|
83
|
-
const content = readFileSync(configPath, 'utf-8');
|
|
84
|
-
return JSON.parse(content);
|
|
85
|
-
} else if (ext === 'js' || ext === 'ts') {
|
|
86
|
-
return await loadTypeScriptConfig(configPath);
|
|
87
|
-
}
|
|
88
|
-
} catch (error) {
|
|
89
|
-
console.warn(`Error loading config from ${configPath}:`, error);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return null;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async function loadTypeScriptConfig(configPath: string): Promise<AuthConfig | null> {
|
|
96
|
-
try {
|
|
97
|
-
if (configPath.endsWith('.ts')) {
|
|
98
|
-
try {
|
|
99
|
-
const authModule = await import(configPath);
|
|
100
|
-
|
|
101
|
-
if (authModule.auth) {
|
|
102
|
-
console.log('Found auth export, extracting configuration...');
|
|
103
|
-
const config = authModule.auth.options || authModule.auth;
|
|
104
|
-
return extractBetterAuthFields(config);
|
|
105
|
-
} else if (authModule.default) {
|
|
106
|
-
console.log('Found default export, extracting configuration...');
|
|
107
|
-
const config = authModule.default.options || authModule.default;
|
|
108
|
-
return extractBetterAuthFields(config);
|
|
109
|
-
}
|
|
110
|
-
} catch (importError) {
|
|
111
|
-
console.warn(`Failed to import auth config from ${configPath}:`, importError);
|
|
112
|
-
console.log('Falling back to regex extraction...');
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const content = readFileSync(configPath, 'utf-8');
|
|
117
|
-
const authConfig = extractBetterAuthConfig(content);
|
|
118
|
-
if (authConfig) {
|
|
119
|
-
return authConfig;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (configPath.endsWith('.js')) {
|
|
123
|
-
return await evaluateJSConfig(configPath);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return null;
|
|
127
|
-
} catch (error) {
|
|
128
|
-
console.warn(`Error loading TypeScript config from ${configPath}:`, error);
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function extractBetterAuthConfig(content: string): AuthConfig | null {
|
|
134
|
-
console.log('Extracting config from content:', content.substring(0, 500) + '...');
|
|
135
|
-
|
|
136
|
-
const patterns = [
|
|
137
|
-
/export\s+const\s+\w+\s*=\s*betterAuth\s*\(\s*({[\s\S]*?})\s*\)/,
|
|
138
|
-
/export\s+const\s+\w+\s*=\s*BetterAuth\s*\(\s*({[\s\S]*?})\s*\)/,
|
|
139
|
-
/const\s+\w+\s*=\s*betterAuth\s*\(\s*({[\s\S]*?})\s*\)/,
|
|
140
|
-
/const\s+\w+\s*=\s*BetterAuth\s*\(\s*({[\s\S]*?})\s*\)/,
|
|
141
|
-
/export\s+default\s+betterAuth\s*\(\s*({[\s\S]*?})\s*\)/,
|
|
142
|
-
/export\s+default\s+BetterAuth\s*\(\s*({[\s\S]*?})\s*\)/,
|
|
143
|
-
/module\.exports\s*=\s*betterAuth\s*\(\s*({[\s\S]*?})\s*\)/,
|
|
144
|
-
/module\.exports\s*=\s*BetterAuth\s*\(\s*({[\s\S]*?})\s*\)/,
|
|
145
|
-
/export\s+default\s*({[\s\S]*?});?$/m,
|
|
146
|
-
/module\.exports\s*=\s*({[\s\S]*?});?$/m,
|
|
147
|
-
/betterAuth\s*\(\s*({[\s\S]*?})\s*\)/,
|
|
148
|
-
/BetterAuth\s*\(\s*({[\s\S]*?})\s*\)/,
|
|
149
|
-
/({[\s\S]*?"socialProviders"[\s\S]*?})/,
|
|
150
|
-
/({[\s\S]*?"emailAndPassword"[\s\S]*?})/,
|
|
151
|
-
/({[\s\S]*?"database"[\s\S]*?})/
|
|
152
|
-
];
|
|
153
|
-
|
|
154
|
-
for (let i = 0; i < patterns.length; i++) {
|
|
155
|
-
const pattern = patterns[i];
|
|
156
|
-
const match = content.match(pattern);
|
|
157
|
-
if (match) {
|
|
158
|
-
console.log(`Pattern ${i + 1} matched!`);
|
|
159
|
-
console.log('Matched content:', match[1].substring(0, 200) + '...');
|
|
160
|
-
try {
|
|
161
|
-
let configStr = match[1];
|
|
162
|
-
|
|
163
|
-
configStr = configStr
|
|
164
|
-
.replace(/(\d+\s*\*\s*\d+\s*\*\s*\d+\s*\*\s*\d+)/g, (match) => {
|
|
165
|
-
try {
|
|
166
|
-
return eval(match).toString();
|
|
167
|
-
} catch {
|
|
168
|
-
return match;
|
|
169
|
-
}
|
|
170
|
-
})
|
|
171
|
-
.replace(/(\d+\s*\*\s*\d+\s*\*\s*\d+)/g, (match) => {
|
|
172
|
-
try {
|
|
173
|
-
return eval(match).toString();
|
|
174
|
-
} catch {
|
|
175
|
-
return match;
|
|
176
|
-
}
|
|
177
|
-
})
|
|
178
|
-
.replace(/(\d+\s*\*\s*\d+)/g, (match) => {
|
|
179
|
-
try {
|
|
180
|
-
return eval(match).toString();
|
|
181
|
-
} catch {
|
|
182
|
-
return match;
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
configStr = configStr
|
|
187
|
-
.replace(/:\s*process\.env\.(\w+)(\s*\|\|\s*"[^"]*")?/g, ':"$1"') // Replace process.env.VAR || "default" with "VAR"
|
|
188
|
-
.replace(/:\s*`([^`]*)`/g, ':"$1"') // Replace template literals
|
|
189
|
-
.replace(/:\s*'([^']*)'/g, ':"$1"') // Replace single quotes
|
|
190
|
-
.replace(/:\s*"([^"]*)"/g, ':"$1"') // Keep double quotes
|
|
191
|
-
.replace(/:\s*(\w+)/g, ':"$1"') // Replace unquoted keys
|
|
192
|
-
.replace(/(\w+):/g, '"$1":') // Quote property names
|
|
193
|
-
.replace(/,\s*}/g, '}') // Remove trailing commas
|
|
194
|
-
.replace(/,\s*]/g, ']') // Remove trailing commas in arrays
|
|
195
|
-
.replace(/\/\/.*$/gm, '') // Remove single-line comments
|
|
196
|
-
.replace(/\/\*[\s\S]*?\*\//g, '') // Remove multi-line comments
|
|
197
|
-
.replace(/\s+/g, ' ') // Normalize whitespace
|
|
198
|
-
.replace(/:\s*(\d+)/g, ':$1') // Keep numbers
|
|
199
|
-
.replace(/:\s*(true|false)/g, ':$1') // Keep booleans
|
|
200
|
-
.replace(/:\s*null/g, ':null') // Keep null
|
|
201
|
-
.trim();
|
|
202
|
-
|
|
203
|
-
console.log('Cleaned config string:', configStr.substring(0, 300) + '...');
|
|
204
|
-
|
|
205
|
-
let config;
|
|
206
|
-
try {
|
|
207
|
-
config = JSON.parse(configStr);
|
|
208
|
-
} catch (error) {
|
|
209
|
-
console.warn(`Failed to parse config: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
210
|
-
console.warn('Config string that failed:', configStr.substring(0, 200) + '...');
|
|
211
|
-
return null;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return extractBetterAuthFields(config);
|
|
215
|
-
} catch (error) {
|
|
216
|
-
console.warn(`Failed to parse config pattern: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
return null;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function extractBetterAuthFields(config: any): AuthConfig {
|
|
226
|
-
console.log('Extracting fields from config:', JSON.stringify(config, null, 2));
|
|
227
|
-
|
|
228
|
-
const authConfig: AuthConfig = {};
|
|
229
|
-
|
|
230
|
-
if (config.database) {
|
|
231
|
-
let dbType = 'postgresql'; // default
|
|
232
|
-
let dbName = config.database.name;
|
|
233
|
-
|
|
234
|
-
if (config.database.constructor && config.database.constructor.name === 'Database') {
|
|
235
|
-
dbType = 'sqlite';
|
|
236
|
-
dbName = config.database.name || './better-auth.db';
|
|
237
|
-
} else if (config.database.name && config.database.name.endsWith('.db')) {
|
|
238
|
-
dbType = 'sqlite';
|
|
239
|
-
} else if (config.database.type) {
|
|
240
|
-
dbType = config.database.type;
|
|
241
|
-
} else if (config.database.dialect) {
|
|
242
|
-
dbType = config.database.dialect;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
authConfig.database = {
|
|
246
|
-
url: config.database.url || config.database.connectionString,
|
|
247
|
-
name: dbName,
|
|
248
|
-
type: dbType,
|
|
249
|
-
dialect: config.database.dialect,
|
|
250
|
-
casing: config.database.casing
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (config.socialProviders) {
|
|
255
|
-
if (typeof config.socialProviders === 'object' && !Array.isArray(config.socialProviders)) {
|
|
256
|
-
authConfig.socialProviders = config.socialProviders;
|
|
257
|
-
authConfig.providers = Object.entries(config.socialProviders).map(([provider, config]: [string, any]) => ({
|
|
258
|
-
type: provider,
|
|
259
|
-
clientId: config.clientId,
|
|
260
|
-
clientSecret: config.clientSecret,
|
|
261
|
-
redirectUri: config.redirectUri,
|
|
262
|
-
...config
|
|
263
|
-
}));
|
|
264
|
-
} else if (Array.isArray(config.socialProviders)) {
|
|
265
|
-
authConfig.socialProviders = config.socialProviders;
|
|
266
|
-
authConfig.providers = config.socialProviders;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
if (config.providers && Array.isArray(config.providers)) {
|
|
271
|
-
authConfig.providers = config.providers.map((provider: any) => ({
|
|
272
|
-
type: provider.type || provider.id,
|
|
273
|
-
clientId: provider.clientId || provider.client_id,
|
|
274
|
-
clientSecret: provider.clientSecret || provider.client_secret,
|
|
275
|
-
...provider
|
|
276
|
-
}));
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if (config.emailAndPassword) {
|
|
280
|
-
authConfig.emailAndPassword = config.emailAndPassword;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
if (config.session) {
|
|
284
|
-
authConfig.session = config.session;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
if (config.secret) {
|
|
288
|
-
authConfig.secret = config.secret;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (config.rateLimit) {
|
|
292
|
-
authConfig.rateLimit = config.rateLimit;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if (config.telemetry) {
|
|
296
|
-
authConfig.telemetry = config.telemetry;
|
|
297
|
-
}
|
|
298
|
-
if(config.plugins) {
|
|
299
|
-
authConfig.plugins = config.plugins.map((plugin: any) => plugin.id);
|
|
300
|
-
}
|
|
301
|
-
console.log('Extracted auth config:', JSON.stringify(authConfig, null, 2));
|
|
302
|
-
return authConfig;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
async function evaluateJSConfig(configPath: string): Promise<AuthConfig | null> {
|
|
306
|
-
try {
|
|
307
|
-
const config = require(configPath);
|
|
308
|
-
|
|
309
|
-
if (config.default) {
|
|
310
|
-
return extractBetterAuthFields(config.default);
|
|
311
|
-
} else if (typeof config === 'object') {
|
|
312
|
-
return extractBetterAuthFields(config);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
return null;
|
|
316
|
-
} catch (error) {
|
|
317
|
-
console.warn(`Error evaluating JS config from ${configPath}:`, error);
|
|
318
|
-
return null;
|
|
319
|
-
}
|
|
320
|
-
}
|
package/src/data.ts
DELETED
|
@@ -1,351 +0,0 @@
|
|
|
1
|
-
import { AuthConfig } from './config';
|
|
2
|
-
import { getAuthAdapter } from './auth-adapter';
|
|
3
|
-
|
|
4
|
-
export interface User {
|
|
5
|
-
id: string;
|
|
6
|
-
email?: string;
|
|
7
|
-
name?: string;
|
|
8
|
-
image?: string;
|
|
9
|
-
emailVerified?: Date;
|
|
10
|
-
createdAt: Date;
|
|
11
|
-
updatedAt: Date;
|
|
12
|
-
provider?: string;
|
|
13
|
-
lastSignIn?: Date;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface Session {
|
|
17
|
-
id: string;
|
|
18
|
-
userId: string;
|
|
19
|
-
expires: Date;
|
|
20
|
-
createdAt: Date;
|
|
21
|
-
userAgent?: string;
|
|
22
|
-
ip?: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface AuthStats {
|
|
26
|
-
totalUsers: number;
|
|
27
|
-
activeUsers: number;
|
|
28
|
-
totalSessions: number;
|
|
29
|
-
activeSessions: number;
|
|
30
|
-
usersByProvider: Record<string, number>;
|
|
31
|
-
recentSignups: User[];
|
|
32
|
-
recentLogins: Session[];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface PaginatedResult<T> {
|
|
36
|
-
data: T[];
|
|
37
|
-
total: number;
|
|
38
|
-
page: number;
|
|
39
|
-
limit: number;
|
|
40
|
-
totalPages: number;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export async function getAuthData(
|
|
44
|
-
authConfig: AuthConfig,
|
|
45
|
-
type: 'stats' | 'users' | 'sessions' | 'providers' | 'deleteUser' | 'updateUser' = 'stats',
|
|
46
|
-
options?: any
|
|
47
|
-
): Promise<any> {
|
|
48
|
-
try {
|
|
49
|
-
const adapter = await getAuthAdapter();
|
|
50
|
-
|
|
51
|
-
if (!adapter) {
|
|
52
|
-
console.log('No adapter available, falling back to mock data');
|
|
53
|
-
return getMockData(type, options);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
switch (type) {
|
|
57
|
-
case 'stats':
|
|
58
|
-
return await getRealStats(adapter);
|
|
59
|
-
case 'users':
|
|
60
|
-
return await getRealUsers(adapter, options);
|
|
61
|
-
case 'sessions':
|
|
62
|
-
return await getRealSessions(adapter, options);
|
|
63
|
-
case 'providers':
|
|
64
|
-
return await getRealProviderStats(adapter);
|
|
65
|
-
case 'deleteUser':
|
|
66
|
-
return await deleteRealUser(adapter, options.id);
|
|
67
|
-
case 'updateUser':
|
|
68
|
-
console.log({adapter})
|
|
69
|
-
return await updateRealUser(adapter, options.id, options.userData);
|
|
70
|
-
default:
|
|
71
|
-
throw new Error(`Unknown data type: ${type}`);
|
|
72
|
-
}
|
|
73
|
-
} catch (error) {
|
|
74
|
-
console.error(`Error fetching ${type} data:`, error);
|
|
75
|
-
return getMockData(type, options);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async function getRealStats(adapter: any): Promise<AuthStats> {
|
|
80
|
-
try {
|
|
81
|
-
const users = adapter.getUsers ? await adapter.getUsers() : [];
|
|
82
|
-
const sessions = adapter.getSessions ? await adapter.getSessions() : [];
|
|
83
|
-
|
|
84
|
-
const now = new Date();
|
|
85
|
-
const activeSessions = sessions.filter((s: any) => new Date(s.expiresAt || s.expires) > now);
|
|
86
|
-
const activeUsers = new Set(activeSessions.map((s: any) => s.userId)).size;
|
|
87
|
-
|
|
88
|
-
const usersByProvider: Record<string, number> = {
|
|
89
|
-
email: users.length,
|
|
90
|
-
github: 0
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const recentSignups = users
|
|
94
|
-
.sort((a: any, b: any) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
|
|
95
|
-
.slice(0, 5)
|
|
96
|
-
.map((user: any) => ({
|
|
97
|
-
...user,
|
|
98
|
-
provider: 'email'
|
|
99
|
-
}));
|
|
100
|
-
|
|
101
|
-
const recentLogins = activeSessions
|
|
102
|
-
.sort((a: any, b: any) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
|
|
103
|
-
.slice(0, 5);
|
|
104
|
-
|
|
105
|
-
return {
|
|
106
|
-
totalUsers: users.length,
|
|
107
|
-
activeUsers,
|
|
108
|
-
totalSessions: sessions.length,
|
|
109
|
-
activeSessions: activeSessions.length,
|
|
110
|
-
usersByProvider,
|
|
111
|
-
recentSignups,
|
|
112
|
-
recentLogins
|
|
113
|
-
};
|
|
114
|
-
} catch (error) {
|
|
115
|
-
console.error('Error fetching stats from adapter:', error);
|
|
116
|
-
return getMockData('stats');
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async function getRealUsers(adapter: any, options: { page: number; limit: number; search?: string }): Promise<PaginatedResult<User>> {
|
|
121
|
-
const { page, limit, search } = options;
|
|
122
|
-
|
|
123
|
-
try {
|
|
124
|
-
if (adapter.getUsers) {
|
|
125
|
-
const allUsers = await adapter.getUsers();
|
|
126
|
-
|
|
127
|
-
let filteredUsers = allUsers;
|
|
128
|
-
if (search) {
|
|
129
|
-
filteredUsers = allUsers.filter((user: any) =>
|
|
130
|
-
user.email?.toLowerCase().includes(search.toLowerCase()) ||
|
|
131
|
-
user.name?.toLowerCase().includes(search.toLowerCase())
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const startIndex = (page - 1) * limit;
|
|
136
|
-
const endIndex = startIndex + limit;
|
|
137
|
-
const paginatedUsers = filteredUsers.slice(startIndex, endIndex);
|
|
138
|
-
|
|
139
|
-
return {
|
|
140
|
-
data: paginatedUsers,
|
|
141
|
-
total: filteredUsers.length,
|
|
142
|
-
page,
|
|
143
|
-
limit,
|
|
144
|
-
totalPages: Math.ceil(filteredUsers.length / limit)
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return getMockData('users', options);
|
|
149
|
-
} catch (error) {
|
|
150
|
-
console.error('Error fetching users from adapter:', error);
|
|
151
|
-
return getMockData('users', options);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
async function getRealSessions(adapter: any, options: { page: number; limit: number }): Promise<PaginatedResult<Session>> {
|
|
156
|
-
const { page, limit } = options;
|
|
157
|
-
|
|
158
|
-
try {
|
|
159
|
-
if (adapter.getSessions) {
|
|
160
|
-
const allSessions = await adapter.getSessions();
|
|
161
|
-
|
|
162
|
-
const startIndex = (page - 1) * limit;
|
|
163
|
-
const endIndex = startIndex + limit;
|
|
164
|
-
const paginatedSessions = allSessions.slice(startIndex, endIndex);
|
|
165
|
-
|
|
166
|
-
return {
|
|
167
|
-
data: paginatedSessions,
|
|
168
|
-
total: allSessions.length,
|
|
169
|
-
page,
|
|
170
|
-
limit,
|
|
171
|
-
totalPages: Math.ceil(allSessions.length / limit)
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return getMockData('sessions', options);
|
|
176
|
-
} catch (error) {
|
|
177
|
-
console.error('Error fetching sessions from adapter:', error);
|
|
178
|
-
return getMockData('sessions', options);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
async function getRealProviderStats(adapter: any) {
|
|
183
|
-
try {
|
|
184
|
-
return [
|
|
185
|
-
{ type: 'email', users: 0, active: 0 },
|
|
186
|
-
{ type: 'github', users: 0, active: 0 }
|
|
187
|
-
];
|
|
188
|
-
} catch (error) {
|
|
189
|
-
console.error('Error fetching provider stats from adapter:', error);
|
|
190
|
-
return getMockData('providers');
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
async function deleteRealUser(adapter: any, userId: string): Promise<void> {
|
|
195
|
-
try {
|
|
196
|
-
if (adapter.delete) {
|
|
197
|
-
await adapter.delete({ model: 'user', where: [{ field: 'id', value: userId }] });
|
|
198
|
-
} else {
|
|
199
|
-
console.warn('Delete method not available on adapter');
|
|
200
|
-
}
|
|
201
|
-
} catch (error) {
|
|
202
|
-
console.error('Error deleting user from adapter:', error);
|
|
203
|
-
throw error;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
async function updateRealUser(adapter: any, userId: string, userData: Partial<User>): Promise<User> {
|
|
208
|
-
console.log({userId, userData})
|
|
209
|
-
try {
|
|
210
|
-
const updatedUser = await adapter.update({
|
|
211
|
-
model: 'user',
|
|
212
|
-
where: [
|
|
213
|
-
{
|
|
214
|
-
field: 'id',
|
|
215
|
-
value: userId
|
|
216
|
-
}
|
|
217
|
-
],
|
|
218
|
-
update: {...userData}
|
|
219
|
-
});
|
|
220
|
-
console.log({updatedUser})
|
|
221
|
-
return updatedUser;
|
|
222
|
-
|
|
223
|
-
} catch (error) {
|
|
224
|
-
console.error('Error updating user from adapter:', error);
|
|
225
|
-
throw error;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function getMockData(type: string, options?: any): any {
|
|
230
|
-
switch (type) {
|
|
231
|
-
case 'stats':
|
|
232
|
-
return getMockStats();
|
|
233
|
-
case 'users':
|
|
234
|
-
return getMockUsers(options);
|
|
235
|
-
case 'sessions':
|
|
236
|
-
return getMockSessions(options);
|
|
237
|
-
case 'providers':
|
|
238
|
-
return getMockProviderStats();
|
|
239
|
-
case 'deleteUser':
|
|
240
|
-
return Promise.resolve();
|
|
241
|
-
case 'updateUser':
|
|
242
|
-
return Promise.resolve(generateMockUsers(1)[0]);
|
|
243
|
-
default:
|
|
244
|
-
throw new Error(`Unknown data type: ${type}`);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
function getMockStats(): AuthStats {
|
|
249
|
-
return {
|
|
250
|
-
totalUsers: 1247,
|
|
251
|
-
activeUsers: 892,
|
|
252
|
-
totalSessions: 3456,
|
|
253
|
-
activeSessions: 1234,
|
|
254
|
-
usersByProvider: {
|
|
255
|
-
'google': 456,
|
|
256
|
-
'github': 234,
|
|
257
|
-
'email': 557
|
|
258
|
-
},
|
|
259
|
-
recentSignups: generateMockUsers(5),
|
|
260
|
-
recentLogins: generateMockSessions(5)
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
function getMockUsers(options: { page: number; limit: number; search?: string }): PaginatedResult<User> {
|
|
265
|
-
const { page, limit, search } = options;
|
|
266
|
-
const allUsers = generateMockUsers(100);
|
|
267
|
-
|
|
268
|
-
let filteredUsers = allUsers;
|
|
269
|
-
if (search) {
|
|
270
|
-
filteredUsers = allUsers.filter(user =>
|
|
271
|
-
user.email?.toLowerCase().includes(search.toLowerCase()) ||
|
|
272
|
-
user.name?.toLowerCase().includes(search.toLowerCase())
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
const start = (page - 1) * limit;
|
|
277
|
-
const end = start + limit;
|
|
278
|
-
const data = filteredUsers.slice(start, end);
|
|
279
|
-
|
|
280
|
-
return {
|
|
281
|
-
data,
|
|
282
|
-
total: filteredUsers.length,
|
|
283
|
-
page,
|
|
284
|
-
limit,
|
|
285
|
-
totalPages: Math.ceil(filteredUsers.length / limit)
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
function getMockSessions(options: { page: number; limit: number }): PaginatedResult<Session> {
|
|
290
|
-
const { page, limit } = options;
|
|
291
|
-
const allSessions = generateMockSessions(200);
|
|
292
|
-
|
|
293
|
-
const start = (page - 1) * limit;
|
|
294
|
-
const end = start + limit;
|
|
295
|
-
const data = allSessions.slice(start, end);
|
|
296
|
-
|
|
297
|
-
return {
|
|
298
|
-
data,
|
|
299
|
-
total: allSessions.length,
|
|
300
|
-
page,
|
|
301
|
-
limit,
|
|
302
|
-
totalPages: Math.ceil(allSessions.length / limit)
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
function getMockProviderStats() {
|
|
307
|
-
return [
|
|
308
|
-
{ type: 'google', users: 456, active: 234 },
|
|
309
|
-
{ type: 'github', users: 234, active: 123 },
|
|
310
|
-
{ type: 'email', users: 557, active: 345 }
|
|
311
|
-
];
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
function generateMockUsers(count: number): User[] {
|
|
315
|
-
const users: User[] = [];
|
|
316
|
-
const providers = ['google', 'github', 'email'];
|
|
317
|
-
|
|
318
|
-
for (let i = 0; i < count; i++) {
|
|
319
|
-
const provider = providers[Math.floor(Math.random() * providers.length)];
|
|
320
|
-
users.push({
|
|
321
|
-
id: `user_${i + 1}`,
|
|
322
|
-
email: `user${i + 1}@example.com`,
|
|
323
|
-
name: `User ${i + 1}`,
|
|
324
|
-
image: `https://api.dicebear.com/7.x/avataaars/svg?seed=user${i + 1}`,
|
|
325
|
-
emailVerified: Math.random() > 0.3 ? new Date() : undefined,
|
|
326
|
-
createdAt: new Date(Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000),
|
|
327
|
-
updatedAt: new Date(),
|
|
328
|
-
provider,
|
|
329
|
-
lastSignIn: new Date(Date.now() - Math.random() * 7 * 24 * 60 * 60 * 1000)
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
return users;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
function generateMockSessions(count: number): Session[] {
|
|
337
|
-
const sessions: Session[] = [];
|
|
338
|
-
|
|
339
|
-
for (let i = 0; i < count; i++) {
|
|
340
|
-
sessions.push({
|
|
341
|
-
id: `session_${i + 1}`,
|
|
342
|
-
userId: `user_${Math.floor(Math.random() * 100) + 1}`,
|
|
343
|
-
expires: new Date(Date.now() + Math.random() * 24 * 60 * 60 * 1000),
|
|
344
|
-
createdAt: new Date(Date.now() - Math.random() * 7 * 24 * 60 * 60 * 1000),
|
|
345
|
-
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
|
|
346
|
-
ip: `192.168.1.${Math.floor(Math.random() * 255)}`
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
return sessions;
|
|
351
|
-
}
|