better-auth-studio 1.1.2-beta.7 → 1.1.2-beta.9

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.
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" type="image/png" href="/logo.png" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Better Auth Studio</title>
8
- <script type="module" crossorigin src="/assets/main-D2k7jV-x.js"></script>
8
+ <script type="module" crossorigin src="/assets/main-BwHzqU9D.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/main-GcANPjqc.css">
10
10
  </head>
11
11
  <body>
@@ -1,3 +1,4 @@
1
+ import type { StudioConfig } from '../types/handler.js';
1
2
  import type { StudioAccessConfig } from '../utils/html-injector.js';
2
3
  export type ApiContext = {
3
4
  path: string;
@@ -7,6 +8,7 @@ export type ApiContext = {
7
8
  auth: any;
8
9
  basePath?: string;
9
10
  accessConfig?: StudioAccessConfig;
11
+ studioConfig?: StudioConfig;
10
12
  };
11
13
  export type ApiResponse = {
12
14
  status: number;
@@ -1 +1 @@
1
- {"version":3,"file":"api-router.d.ts","sourceRoot":"","sources":["../../src/routes/api-router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,IAAI,EAAE,GAAG,CAAC;IACV,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,GAAG,CAAC;IACV,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;CAChE,CAAC;AAEF,wBAAsB,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAY3E"}
1
+ {"version":3,"file":"api-router.d.ts","sourceRoot":"","sources":["../../src/routes/api-router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,IAAI,EAAE,GAAG,CAAC;IACV,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,GAAG,CAAC;IACV,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;CAChE,CAAC;AAEF,wBAAsB,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAY3E"}
@@ -1 +1 @@
1
- {"version":3,"file":"api-router.js","sourceRoot":"","sources":["../../src/routes/api-router.ts"],"names":[],"mappings":"AAkBA,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAe;IACnD,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;IAEhE,IAAI,CAAC;QACH,OAAO,MAAM,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;QAC3C,OAAO;YACL,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE;SACzC,CAAC;IACJ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"api-router.js","sourceRoot":"","sources":["../../src/routes/api-router.ts"],"names":[],"mappings":"AAoBA,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAe;IACnD,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;IAEhE,IAAI,CAAC;QACH,OAAO,MAAM,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;QAC3C,OAAO;YACL,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE;SACzC,CAAC;IACJ,CAAC;AACH,CAAC"}
package/dist/routes.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { Router } from 'express';
2
2
  import type { AuthConfig } from './config.js';
3
+ import type { StudioConfig } from './types/handler.js';
3
4
  import type { StudioAccessConfig } from './utils/html-injector.js';
4
5
  export declare function safeImportAuthConfig(authConfigPath: string, noCache?: boolean): Promise<any>;
5
- export declare function createRoutes(authConfig: AuthConfig, configPath?: string, geoDbPath?: string, preloadedAdapter?: any, preloadedAuthOptions?: any, accessConfig?: StudioAccessConfig, authInstance?: any): Router;
6
+ export declare function createRoutes(authConfig: AuthConfig, configPath?: string, geoDbPath?: string, preloadedAdapter?: any, preloadedAuthOptions?: any, accessConfig?: StudioAccessConfig, authInstance?: any, studioConfig?: StudioConfig): Router;
6
7
  export declare function handleStudioApiRequest(ctx: {
7
8
  path: string;
8
9
  method: string;
@@ -12,6 +13,7 @@ export declare function handleStudioApiRequest(ctx: {
12
13
  basePath?: string;
13
14
  configPath?: string;
14
15
  accessConfig?: StudioAccessConfig;
16
+ studioConfig?: StudioConfig;
15
17
  }): Promise<{
16
18
  status: number;
17
19
  data: any;
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAqBA,OAAO,EAA+B,MAAM,EAAE,MAAM,SAAS,CAAC;AAU9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAM9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AA4GnE,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAqLhG;AAeD,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,EAClB,gBAAgB,CAAC,EAAE,GAAG,EACtB,oBAAoB,CAAC,EAAE,GAAG,EAC1B,YAAY,CAAC,EAAE,kBAAkB,EACjC,YAAY,CAAC,EAAE,GAAG,GACjB,MAAM,CAyzNR;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,IAAI,EAAE,GAAG,CAAC;IACV,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,GAAG,CAAC;IACV,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;CAChE,CAAC,CA+FD"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAqBA,OAAO,EAA+B,MAAM,EAAE,MAAM,SAAS,CAAC;AAW9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AA0GnE,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAqLhG;AAeD,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,EAClB,gBAAgB,CAAC,EAAE,GAAG,EACtB,oBAAoB,CAAC,EAAE,GAAG,EAC1B,YAAY,CAAC,EAAE,kBAAkB,EACjC,YAAY,CAAC,EAAE,GAAG,EAClB,YAAY,CAAC,EAAE,YAAY,GAC1B,MAAM,CAo3NR;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,IAAI,EAAE,GAAG,CAAC;IACV,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,GAAG,CAAC;IACV,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;CAChE,CAAC,CAgGD"}
package/dist/routes.js CHANGED
@@ -9,6 +9,7 @@ import babelPresetTypeScript from '@babel/preset-typescript';
9
9
  // @ts-expect-error
10
10
  import { hex } from '@better-auth/utils/hex';
11
11
  import { scryptAsync } from '@noble/hashes/scrypt.js';
12
+ import { loadConfig } from 'c12';
12
13
  import { Router } from 'express';
13
14
  import { createJiti } from 'jiti';
14
15
  import { createRequire } from 'module';
@@ -18,7 +19,6 @@ import { getAuthData } from './data.js';
18
19
  import { initializeGeoService, resolveIPLocation, setGeoDbPath } from './geo-service.js';
19
20
  import { detectDatabaseWithDialect } from './utils/database-detection.js';
20
21
  import { createStudioSession, decryptSession, encryptSession, isSessionValid, STUDIO_COOKIE_NAME, } from './utils/session.js';
21
- import { loadConfig } from 'c12';
22
22
  const config = {
23
23
  N: 16384,
24
24
  r: 16,
@@ -269,7 +269,7 @@ async function findAuthConfigPath() {
269
269
  }
270
270
  return null;
271
271
  }
272
- export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter, preloadedAuthOptions, accessConfig, authInstance) {
272
+ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter, preloadedAuthOptions, accessConfig, authInstance, studioConfig) {
273
273
  const isSelfHosted = !!preloadedAdapter;
274
274
  const getAuthConfigSafe = async () => {
275
275
  if (isSelfHosted) {
@@ -418,6 +418,23 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
418
418
  return res.status(401).json({ error: 'Unauthorized', message: result.error });
419
419
  }
420
420
  req.studioSession = result.session;
421
+ // Extend session expiry time on each authenticated request
422
+ if (result.session) {
423
+ const refreshedSession = createStudioSession({
424
+ id: result.session.userId,
425
+ email: result.session.email,
426
+ name: result.session.name,
427
+ role: result.session.role,
428
+ }, getSessionDuration());
429
+ const encryptedSession = encryptSession(refreshedSession, getSessionSecret());
430
+ res.cookie(STUDIO_COOKIE_NAME, encryptedSession, {
431
+ httpOnly: true,
432
+ secure: process.env.NODE_ENV === 'production',
433
+ sameSite: 'lax',
434
+ maxAge: getSessionDuration(),
435
+ path: '/',
436
+ });
437
+ }
421
438
  }
422
439
  next();
423
440
  });
@@ -705,6 +722,23 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
705
722
  if (!isSessionValid(session)) {
706
723
  return res.json({ authenticated: false, reason: 'expired' });
707
724
  }
725
+ // Extend session expiry time on each successful check
726
+ if (session) {
727
+ const refreshedSession = createStudioSession({
728
+ id: session.userId,
729
+ email: session.email,
730
+ name: session.name,
731
+ role: session.role,
732
+ }, getSessionDuration());
733
+ const encryptedSession = encryptSession(refreshedSession, getSessionSecret());
734
+ res.cookie(STUDIO_COOKIE_NAME, encryptedSession, {
735
+ httpOnly: true,
736
+ secure: process.env.NODE_ENV === 'production',
737
+ sameSite: 'lax',
738
+ maxAge: getSessionDuration(),
739
+ path: '/',
740
+ });
741
+ }
708
742
  return res.json({
709
743
  authenticated: true,
710
744
  user: {
@@ -712,7 +746,6 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
712
746
  email: session.email,
713
747
  name: session.name,
714
748
  role: session.role,
715
- image: session.image,
716
749
  },
717
750
  });
718
751
  });
@@ -938,7 +971,8 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
938
971
  const { isEventIngestionInitialized, getEventIngestionProvider } = await import('./utils/event-ingestion.js');
939
972
  const initialized = isEventIngestionInitialized();
940
973
  const provider = getEventIngestionProvider();
941
- if (!initialized) {
974
+ let configToUse = studioConfig || null;
975
+ if (!initialized && !configToUse) {
942
976
  try {
943
977
  const { initializeEventIngestionAndHooks } = await import('./core/handler.js');
944
978
  const { existsSync } = await import('node:fs');
@@ -957,34 +991,7 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
957
991
  break;
958
992
  }
959
993
  }
960
- const alias = getPathAliases(process.cwd()) || {};
961
- const jitiOptions = {
962
- debug: false,
963
- transformOptions: {
964
- babel: {
965
- presets: [
966
- [
967
- babelPresetTypeScript,
968
- {
969
- isTSX: true,
970
- allExtensions: true,
971
- },
972
- ],
973
- [babelPresetReact, { runtime: 'automatic' }],
974
- ],
975
- },
976
- },
977
- extensions: ['.ts', '.js', '.tsx', '.jsx'],
978
- alias,
979
- interopDefault: true,
980
- };
981
- const { config } = await loadConfig({
982
- configFile: studioConfigPath || undefined,
983
- cwd: process.cwd(),
984
- dotenv: true,
985
- jitiOptions,
986
- });
987
- if (!config) {
994
+ if (!studioConfigPath && configPath) {
988
995
  const configDir = require('node:path').dirname(configPath);
989
996
  for (const file of possibleFiles) {
990
997
  const path = require('node:path').join(configDir, file);
@@ -994,18 +1001,55 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
994
1001
  }
995
1002
  }
996
1003
  }
997
- if (config) {
998
- const studioConfig = config?.default || config?.config || config;
999
- if (studioConfig.events?.enabled) {
1000
- await initializeEventIngestionAndHooks(studioConfig);
1004
+ if (studioConfigPath) {
1005
+ const alias = getPathAliases(process.cwd()) || {};
1006
+ const jitiOptions = {
1007
+ debug: false,
1008
+ transformOptions: {
1009
+ babel: {
1010
+ presets: [
1011
+ [
1012
+ babelPresetTypeScript,
1013
+ {
1014
+ isTSX: true,
1015
+ allExtensions: true,
1016
+ },
1017
+ ],
1018
+ [babelPresetReact, { runtime: 'automatic' }],
1019
+ ],
1020
+ },
1021
+ },
1022
+ extensions: ['.ts', '.js', '.tsx', '.jsx'],
1023
+ alias,
1024
+ interopDefault: true,
1025
+ };
1026
+ const { config } = await loadConfig({
1027
+ configFile: studioConfigPath || undefined,
1028
+ cwd: process.cwd(),
1029
+ dotenv: true,
1030
+ jitiOptions,
1031
+ });
1032
+ if (config) {
1033
+ configToUse = config?.default || config?.config || config;
1001
1034
  }
1002
1035
  }
1003
1036
  }
1037
+ catch (initError) {
1038
+ console.warn('Failed to load studio config:', initError?.message || initError);
1039
+ }
1040
+ }
1041
+ if (!initialized && configToUse?.events?.enabled) {
1042
+ try {
1043
+ const { initializeEventIngestionAndHooks } = await import('./core/handler.js');
1044
+ await initializeEventIngestionAndHooks(configToUse);
1045
+ }
1004
1046
  catch (initError) {
1005
1047
  console.warn('Failed to initialize event ingestion:', initError?.message || initError);
1006
1048
  }
1007
1049
  }
1008
- const isEnabled = isEventIngestionInitialized() && !!getEventIngestionProvider();
1050
+ const isEnabled = configToUse?.events?.enabled === true &&
1051
+ isEventIngestionInitialized() &&
1052
+ !!getEventIngestionProvider();
1009
1053
  res.json({
1010
1054
  enabled: isEnabled,
1011
1055
  initialized: isEventIngestionInitialized(),
@@ -1635,6 +1679,8 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
1635
1679
  const sort = req.query.sort || 'desc'; // Default: 'desc' = newest first
1636
1680
  const type = req.query.type;
1637
1681
  const userId = req.query.userId;
1682
+ const sinceParam = req.query.since; // ISO timestamp string
1683
+ const since = sinceParam ? new Date(sinceParam) : undefined;
1638
1684
  const { getEventIngestionProvider, isEventIngestionInitialized } = await import('./utils/event-ingestion.js');
1639
1685
  // Check if event ingestion is initialized, if not, try to initialize it
1640
1686
  if (!isEventIngestionInitialized()) {
@@ -1705,6 +1751,7 @@ export function createRoutes(authConfig, configPath, geoDbPath, preloadedAdapter
1705
1751
  sort: sort,
1706
1752
  type,
1707
1753
  userId,
1754
+ since,
1708
1755
  });
1709
1756
  // Import event utilities for template fallback
1710
1757
  const eventTypes = await import('./types/events.js');
@@ -6391,7 +6438,7 @@ export async function handleStudioApiRequest(ctx) {
6391
6438
  catch { }
6392
6439
  }
6393
6440
  const authOptions = ctx.auth?.options || null;
6394
- const router = createRoutes(ctx.auth, ctx.configPath || '', undefined, preloadedAdapter, authOptions, ctx.accessConfig, ctx.auth);
6441
+ const router = createRoutes(ctx.auth, ctx.configPath || '', undefined, preloadedAdapter, authOptions, ctx.accessConfig, ctx.auth, ctx.studioConfig);
6395
6442
  const [pathname, queryString] = ctx.path.split('?');
6396
6443
  const query = {};
6397
6444
  if (queryString) {