better-auth-studio 1.1.3-beta.9 → 1.1.3

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.
Files changed (196) hide show
  1. package/README.md +145 -16
  2. package/dist/adapters/astro.d.ts +0 -1
  3. package/dist/adapters/astro.js +5 -2
  4. package/dist/adapters/cloudflare-workers.d.ts +101 -0
  5. package/dist/adapters/cloudflare-workers.js +494 -0
  6. package/dist/adapters/elysia.d.ts +0 -1
  7. package/dist/adapters/elysia.js +7 -33
  8. package/dist/adapters/express.d.ts +0 -1
  9. package/dist/adapters/express.js +4 -1
  10. package/dist/adapters/hono.d.ts +0 -1
  11. package/dist/adapters/hono.js +7 -27
  12. package/dist/adapters/nextjs.d.ts +0 -1
  13. package/dist/adapters/nextjs.js +5 -2
  14. package/dist/adapters/nuxt.d.ts +0 -1
  15. package/dist/adapters/nuxt.js +5 -2
  16. package/dist/adapters/remix.d.ts +0 -1
  17. package/dist/adapters/remix.js +5 -2
  18. package/dist/adapters/solid-start.d.ts +0 -1
  19. package/dist/adapters/solid-start.js +5 -2
  20. package/dist/adapters/svelte-kit.d.ts +0 -1
  21. package/dist/adapters/svelte-kit.js +5 -2
  22. package/dist/adapters/tanstack-start.d.ts +0 -1
  23. package/dist/adapters/tanstack-start.js +36 -8
  24. package/dist/add-svelte-kit-env-modules.d.ts +0 -1
  25. package/dist/add-svelte-kit-env-modules.js +0 -1
  26. package/dist/auth-adapter.d.ts +5 -2
  27. package/dist/auth-adapter.js +39 -4
  28. package/dist/cli/commands/init.d.ts +0 -1
  29. package/dist/cli/commands/init.js +0 -1
  30. package/dist/cli.d.ts +0 -1
  31. package/dist/cli.js +6 -1
  32. package/dist/config.d.ts +0 -1
  33. package/dist/config.js +0 -1
  34. package/dist/core/handler.d.ts +0 -1
  35. package/dist/core/handler.js +36 -5
  36. package/dist/data.d.ts +10 -4
  37. package/dist/data.js +40 -6
  38. package/dist/geo-service.d.ts +0 -1
  39. package/dist/geo-service.js +0 -1
  40. package/dist/get-tsconfig-info.d.ts +0 -1
  41. package/dist/get-tsconfig-info.js +0 -1
  42. package/dist/index.d.ts +0 -1
  43. package/dist/index.js +0 -1
  44. package/dist/providers/events/helpers.d.ts +3 -2
  45. package/dist/providers/events/helpers.js +303 -93
  46. package/dist/public/assets/main-C-R_HO98.css +1 -0
  47. package/dist/public/assets/main-DDypFItU.js +1302 -0
  48. package/dist/public/index.html +2 -2
  49. package/dist/public/shaders.png +0 -0
  50. package/dist/routes/api-router.d.ts +2 -3
  51. package/dist/routes/api-router.js +0 -1
  52. package/dist/routes.d.ts +2 -3
  53. package/dist/routes.js +813 -172
  54. package/dist/studio.d.ts +0 -1
  55. package/dist/studio.js +6 -4
  56. package/dist/types/events.d.ts +0 -1
  57. package/dist/types/events.js +0 -1
  58. package/dist/types/handler.d.ts +13 -3
  59. package/dist/types/handler.js +0 -1
  60. package/dist/types/index.d.ts +0 -1
  61. package/dist/types/index.js +0 -1
  62. package/dist/utils/access-rules.d.ts +19 -0
  63. package/dist/utils/access-rules.js +126 -0
  64. package/dist/utils/auth-callbacks-injector.d.ts +0 -1
  65. package/dist/utils/auth-callbacks-injector.js +0 -1
  66. package/dist/utils/database-detection.d.ts +0 -1
  67. package/dist/utils/database-detection.js +33 -4
  68. package/dist/utils/event-ingestion.d.ts +0 -1
  69. package/dist/utils/event-ingestion.js +1 -1
  70. package/dist/utils/hook-injector.d.ts +0 -1
  71. package/dist/utils/hook-injector.js +2 -2
  72. package/dist/utils/html-injector.d.ts +1 -7
  73. package/dist/utils/html-injector.js +15 -1
  74. package/dist/utils/org-hooks-injector.d.ts +0 -1
  75. package/dist/utils/org-hooks-injector.js +0 -1
  76. package/dist/utils/package-json.d.ts +1 -1
  77. package/dist/utils/package-json.js +21 -1
  78. package/dist/utils/paths.d.ts +0 -1
  79. package/dist/utils/paths.js +0 -1
  80. package/dist/utils/reason-messages.d.ts +0 -1
  81. package/dist/utils/reason-messages.js +0 -1
  82. package/dist/utils/session.d.ts +0 -1
  83. package/dist/utils/session.js +0 -1
  84. package/dist/utils.d.ts +0 -1
  85. package/dist/utils.js +0 -1
  86. package/package.json +30 -39
  87. package/dist/adapters/astro.d.ts.map +0 -1
  88. package/dist/adapters/astro.js.map +0 -1
  89. package/dist/adapters/elysia.d.ts.map +0 -1
  90. package/dist/adapters/elysia.js.map +0 -1
  91. package/dist/adapters/express.d.ts.map +0 -1
  92. package/dist/adapters/express.js.map +0 -1
  93. package/dist/adapters/hono.d.ts.map +0 -1
  94. package/dist/adapters/hono.js.map +0 -1
  95. package/dist/adapters/nextjs.d.ts.map +0 -1
  96. package/dist/adapters/nextjs.js.map +0 -1
  97. package/dist/adapters/nuxt.d.ts.map +0 -1
  98. package/dist/adapters/nuxt.js.map +0 -1
  99. package/dist/adapters/remix.d.ts.map +0 -1
  100. package/dist/adapters/remix.js.map +0 -1
  101. package/dist/adapters/solid-start.d.ts.map +0 -1
  102. package/dist/adapters/solid-start.js.map +0 -1
  103. package/dist/adapters/svelte-kit.d.ts.map +0 -1
  104. package/dist/adapters/svelte-kit.js.map +0 -1
  105. package/dist/adapters/tanstack-start.d.ts.map +0 -1
  106. package/dist/adapters/tanstack-start.js.map +0 -1
  107. package/dist/add-svelte-kit-env-modules.d.ts.map +0 -1
  108. package/dist/add-svelte-kit-env-modules.js.map +0 -1
  109. package/dist/auth-adapter.d.ts.map +0 -1
  110. package/dist/auth-adapter.js.map +0 -1
  111. package/dist/cli/commands/init.d.ts.map +0 -1
  112. package/dist/cli/commands/init.js.map +0 -1
  113. package/dist/cli.d.ts.map +0 -1
  114. package/dist/cli.js.map +0 -1
  115. package/dist/config.d.ts.map +0 -1
  116. package/dist/config.js.map +0 -1
  117. package/dist/core/handler.d.ts.map +0 -1
  118. package/dist/core/handler.js.map +0 -1
  119. package/dist/data.d.ts.map +0 -1
  120. package/dist/data.js.map +0 -1
  121. package/dist/geo-service.d.ts.map +0 -1
  122. package/dist/geo-service.js.map +0 -1
  123. package/dist/get-tsconfig-info.d.ts.map +0 -1
  124. package/dist/get-tsconfig-info.js.map +0 -1
  125. package/dist/index.d.ts.map +0 -1
  126. package/dist/index.js.map +0 -1
  127. package/dist/providers/events/helpers.d.ts.map +0 -1
  128. package/dist/providers/events/helpers.js.map +0 -1
  129. package/dist/public/assets/main-D7_GjGqW.js +0 -1216
  130. package/dist/public/assets/main-Ru3ybjQp.css +0 -1
  131. package/dist/routes/api-router.d.ts.map +0 -1
  132. package/dist/routes/api-router.js.map +0 -1
  133. package/dist/routes.d.ts.map +0 -1
  134. package/dist/routes.js.map +0 -1
  135. package/dist/studio.d.ts.map +0 -1
  136. package/dist/studio.js.map +0 -1
  137. package/dist/types/events.d.ts.map +0 -1
  138. package/dist/types/events.js.map +0 -1
  139. package/dist/types/handler.d.ts.map +0 -1
  140. package/dist/types/handler.js.map +0 -1
  141. package/dist/types/index.d.ts.map +0 -1
  142. package/dist/types/index.js.map +0 -1
  143. package/dist/utils/auth-callbacks-injector.d.ts.map +0 -1
  144. package/dist/utils/auth-callbacks-injector.js.map +0 -1
  145. package/dist/utils/auth-callbacks-wrapper.d.ts +0 -7
  146. package/dist/utils/auth-callbacks-wrapper.d.ts.map +0 -1
  147. package/dist/utils/auth-callbacks-wrapper.js +0 -133
  148. package/dist/utils/auth-callbacks-wrapper.js.map +0 -1
  149. package/dist/utils/database-detection.d.ts.map +0 -1
  150. package/dist/utils/database-detection.js.map +0 -1
  151. package/dist/utils/database-hook-injector.d.ts +0 -3
  152. package/dist/utils/database-hook-injector.d.ts.map +0 -1
  153. package/dist/utils/database-hook-injector.js +0 -145
  154. package/dist/utils/database-hook-injector.js.map +0 -1
  155. package/dist/utils/email-otp-hooks-injector.d.ts +0 -45
  156. package/dist/utils/email-otp-hooks-injector.d.ts.map +0 -1
  157. package/dist/utils/email-otp-hooks-injector.js +0 -141
  158. package/dist/utils/email-otp-hooks-injector.js.map +0 -1
  159. package/dist/utils/event-ingestion.d.ts.map +0 -1
  160. package/dist/utils/event-ingestion.js.map +0 -1
  161. package/dist/utils/hook-injector.d.ts.map +0 -1
  162. package/dist/utils/hook-injector.js.map +0 -1
  163. package/dist/utils/html-injector.d.ts.map +0 -1
  164. package/dist/utils/html-injector.js.map +0 -1
  165. package/dist/utils/org-hooks-injector.d.ts.map +0 -1
  166. package/dist/utils/org-hooks-injector.js.map +0 -1
  167. package/dist/utils/org-hooks-wrapper.d.ts +0 -80
  168. package/dist/utils/org-hooks-wrapper.d.ts.map +0 -1
  169. package/dist/utils/org-hooks-wrapper.js +0 -807
  170. package/dist/utils/org-hooks-wrapper.js.map +0 -1
  171. package/dist/utils/organization-hooks-wrapper.d.ts +0 -44
  172. package/dist/utils/organization-hooks-wrapper.d.ts.map +0 -1
  173. package/dist/utils/organization-hooks-wrapper.js +0 -345
  174. package/dist/utils/organization-hooks-wrapper.js.map +0 -1
  175. package/dist/utils/package-json.d.ts.map +0 -1
  176. package/dist/utils/package-json.js.map +0 -1
  177. package/dist/utils/paths.d.ts.map +0 -1
  178. package/dist/utils/paths.js.map +0 -1
  179. package/dist/utils/reason-messages.d.ts.map +0 -1
  180. package/dist/utils/reason-messages.js.map +0 -1
  181. package/dist/utils/server-init.d.ts +0 -10
  182. package/dist/utils/server-init.d.ts.map +0 -1
  183. package/dist/utils/server-init.js +0 -40
  184. package/dist/utils/server-init.js.map +0 -1
  185. package/dist/utils/session.d.ts.map +0 -1
  186. package/dist/utils/session.js.map +0 -1
  187. package/dist/utils.d.ts.map +0 -1
  188. package/dist/utils.js.map +0 -1
  189. package/public/assets/main-D7_GjGqW.js +0 -1216
  190. package/public/assets/main-Ru3ybjQp.css +0 -1
  191. package/public/favicon.svg +0 -6
  192. package/public/index.html +0 -14
  193. package/public/logo.png +0 -0
  194. package/public/vite.svg +0 -5
  195. package/scripts/download-geolite2.js +0 -42
  196. package/scripts/generate-default-db.js +0 -462
package/dist/studio.d.ts CHANGED
@@ -17,4 +17,3 @@ export declare function startStudio(options: StudioOptions): Promise<{
17
17
  wss: WebSocketServer | null;
18
18
  }>;
19
19
  export {};
20
- //# sourceMappingURL=studio.d.ts.map
package/dist/studio.js CHANGED
@@ -58,9 +58,12 @@ export async function startStudio(options) {
58
58
  });
59
59
  }
60
60
  app.use(createRoutes(authConfig, configPath, geoDbPath));
61
- const publicDir = existsSync(join(__dirname, "../public"))
62
- ? join(__dirname, "../public")
63
- : join(__dirname, "../../public");
61
+ const publicDirCandidates = [
62
+ join(__dirname, "public"),
63
+ join(__dirname, "../public"),
64
+ join(__dirname, "../../public"),
65
+ ];
66
+ const publicDir = publicDirCandidates.find((candidate) => existsSync(candidate)) || publicDirCandidates[0];
64
67
  let studioEnabled = false;
65
68
  let studioConfigPath = null;
66
69
  const possibleFiles = [
@@ -213,4 +216,3 @@ export async function startStudio(options) {
213
216
  });
214
217
  return { server, wss };
215
218
  }
216
- //# sourceMappingURL=studio.js.map
@@ -51,4 +51,3 @@ export declare function getEventSeverity(event: AuthEvent | {
51
51
  type: AuthEventType;
52
52
  status?: "success" | "failed";
53
53
  }, status?: "success" | "failed"): "info" | "success" | "warning" | "failed";
54
- //# sourceMappingURL=events.d.ts.map
@@ -259,4 +259,3 @@ export function getEventSeverity(event, status) {
259
259
  // rejected, cancelled, removed, updated are informational
260
260
  return "info";
261
261
  }
262
- //# sourceMappingURL=events.js.map
@@ -2,12 +2,14 @@ export type UniversalRequest = {
2
2
  url: string;
3
3
  method: string;
4
4
  headers: Record<string, string>;
5
+ ip?: string;
5
6
  body?: any;
6
7
  };
7
8
  export type UniversalResponse = {
8
9
  status: number;
9
10
  headers: Record<string, string>;
10
- body: string | Buffer;
11
+ setCookies?: string[];
12
+ body: string | Uint8Array | ArrayBuffer;
11
13
  };
12
14
  export type TimeWindowPreset = "15m" | "30m" | "1h" | "2h" | "4h" | "6h" | "12h" | "1d" | "2d" | "3d" | "7d" | "14d" | "30d";
13
15
  export type TimeWindowConfig = {
@@ -59,6 +61,15 @@ export type StudioMetadata = {
59
61
  export type StudioAccessConfig = {
60
62
  roles?: string[];
61
63
  allowEmails?: string[];
64
+ /**
65
+ * Optional IP allowlist. Supports exact IPs and wildcard patterns (e.g. "10.0.*").
66
+ * When set, only matching IPs can access Studio.
67
+ */
68
+ allowIpAddresses?: string[];
69
+ /**
70
+ * Optional IP blocklist. Supports exact IPs and wildcard patterns (e.g. "203.0.113.*").
71
+ */
72
+ blockIpAddresses?: string[];
62
73
  sessionDuration?: number;
63
74
  secret?: string;
64
75
  };
@@ -113,7 +124,7 @@ export type StudioConfig = {
113
124
  tableName?: string;
114
125
  provider?: EventIngestionProvider;
115
126
  client?: any;
116
- clientType?: "postgres" | "prisma" | "drizzle" | "clickhouse" | "https" | "custom" | "sqlite" | "node-sqlite";
127
+ clientType?: "postgres" | "prisma" | "drizzle" | "kysely" | "clickhouse" | "https" | "custom" | "sqlite" | "node-sqlite";
117
128
  include?: AuthEventType[];
118
129
  exclude?: AuthEventType[];
119
130
  batchSize?: number;
@@ -140,4 +151,3 @@ export type WindowStudioConfig = {
140
151
  };
141
152
  };
142
153
  export declare function defineStudioConfig(config: StudioConfig): StudioConfig;
143
- //# sourceMappingURL=handler.d.ts.map
@@ -18,4 +18,3 @@ export const STUDIO_TOOL_IDS = [
18
18
  export function defineStudioConfig(config) {
19
19
  return config;
20
20
  }
21
- //# sourceMappingURL=handler.js.map
@@ -6,4 +6,3 @@ export interface DatabaseDetectionResult extends DetectionInfo {
6
6
  dialect?: string;
7
7
  adapter?: string;
8
8
  }
9
- //# sourceMappingURL=index.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=index.js.map
@@ -0,0 +1,19 @@
1
+ import type { StudioAccessConfig } from "../types/handler.js";
2
+ export type AccessEvaluationInput = {
3
+ accessConfig?: StudioAccessConfig;
4
+ path: string;
5
+ method: string;
6
+ headers: Record<string, string>;
7
+ ip?: string | null;
8
+ };
9
+ export type AccessEvaluationResult = {
10
+ allowed: true;
11
+ ipAddress: string | null;
12
+ } | {
13
+ allowed: false;
14
+ ipAddress: string | null;
15
+ reason: "ip_not_allowed" | "ip_blocked";
16
+ message: string;
17
+ };
18
+ export declare function extractClientIp(headers: Record<string, string>, fallbackIp?: string | null): string | null;
19
+ export declare function evaluateRequestAccess(input: AccessEvaluationInput): AccessEvaluationResult;
@@ -0,0 +1,126 @@
1
+ import { isIP } from "node:net";
2
+ const IP_HEADER_CANDIDATES = [
3
+ "x-forwarded-for",
4
+ "cf-connecting-ip",
5
+ "x-real-ip",
6
+ "x-client-ip",
7
+ "true-client-ip",
8
+ ];
9
+ function normalizeIpToken(raw) {
10
+ if (!raw)
11
+ return null;
12
+ let value = raw.trim();
13
+ if (!value || value.toLowerCase() === "unknown") {
14
+ return null;
15
+ }
16
+ // RFC 7239 may include entries like: for="1.2.3.4:1234"
17
+ if (value.toLowerCase().startsWith("for=")) {
18
+ value = value.slice(4).trim();
19
+ }
20
+ value = value.replace(/^"+|"+$/g, "");
21
+ // Strip IPv6 brackets when present.
22
+ if (value.startsWith("[")) {
23
+ const end = value.indexOf("]");
24
+ if (end > 0) {
25
+ value = value.slice(1, end);
26
+ }
27
+ }
28
+ // Handle IPv4 with port.
29
+ if (/^\d{1,3}(?:\.\d{1,3}){3}:\d+$/.test(value)) {
30
+ value = value.split(":")[0] || value;
31
+ }
32
+ // Normalize IPv6-mapped IPv4 (e.g. ::ffff:127.0.0.1)
33
+ if (value.startsWith("::ffff:")) {
34
+ value = value.slice(7);
35
+ }
36
+ return isIP(value) ? value : null;
37
+ }
38
+ function getHeaderValue(headers, headerName) {
39
+ const target = headerName.toLowerCase();
40
+ for (const [key, value] of Object.entries(headers)) {
41
+ if (key.toLowerCase() === target) {
42
+ return value;
43
+ }
44
+ }
45
+ return undefined;
46
+ }
47
+ function getForwardedIp(headers) {
48
+ const forwarded = getHeaderValue(headers, "forwarded");
49
+ if (!forwarded)
50
+ return null;
51
+ const entries = forwarded.split(",");
52
+ for (const entry of entries) {
53
+ const match = entry.match(/for=("?\[?[a-fA-F0-9:.]+\]?"?)/i);
54
+ if (!match)
55
+ continue;
56
+ const ip = normalizeIpToken(match[1]);
57
+ if (ip)
58
+ return ip;
59
+ }
60
+ return null;
61
+ }
62
+ export function extractClientIp(headers, fallbackIp) {
63
+ for (const header of IP_HEADER_CANDIDATES) {
64
+ const value = getHeaderValue(headers, header);
65
+ if (!value)
66
+ continue;
67
+ const firstValue = value.split(",")[0];
68
+ const ip = normalizeIpToken(firstValue);
69
+ if (ip)
70
+ return ip;
71
+ }
72
+ const forwardedIp = getForwardedIp(headers);
73
+ if (forwardedIp)
74
+ return forwardedIp;
75
+ return normalizeIpToken(fallbackIp);
76
+ }
77
+ function escapeRegExp(value) {
78
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
79
+ }
80
+ function ipMatchesRule(ipAddress, rule) {
81
+ const trimmedRule = rule.trim();
82
+ if (!trimmedRule)
83
+ return false;
84
+ if (trimmedRule.includes("*")) {
85
+ const pattern = `^${escapeRegExp(trimmedRule).replace(/\\\*/g, ".*")}$`;
86
+ return new RegExp(pattern).test(ipAddress);
87
+ }
88
+ const normalizedRuleIp = normalizeIpToken(trimmedRule);
89
+ if (!normalizedRuleIp)
90
+ return false;
91
+ return normalizedRuleIp === ipAddress;
92
+ }
93
+ function hasRules(values) {
94
+ return Array.isArray(values) && values.some((value) => value.trim().length > 0);
95
+ }
96
+ export function evaluateRequestAccess(input) {
97
+ const { accessConfig, headers, ip } = input;
98
+ const ipAddress = extractClientIp(headers, ip);
99
+ const allowIpAddresses = accessConfig?.allowIpAddresses?.filter((value) => value.trim().length > 0);
100
+ if (hasRules(allowIpAddresses)) {
101
+ if (!ipAddress || !allowIpAddresses.some((rule) => ipMatchesRule(ipAddress, rule))) {
102
+ return {
103
+ allowed: false,
104
+ ipAddress,
105
+ reason: "ip_not_allowed",
106
+ message: "Access denied. This IP address is not in the allowed list.",
107
+ };
108
+ }
109
+ }
110
+ const blockIpAddresses = accessConfig?.blockIpAddresses?.filter((value) => value.trim().length > 0);
111
+ if (hasRules(blockIpAddresses) && ipAddress) {
112
+ const blocked = blockIpAddresses.some((rule) => ipMatchesRule(ipAddress, rule));
113
+ if (blocked) {
114
+ return {
115
+ allowed: false,
116
+ ipAddress,
117
+ reason: "ip_blocked",
118
+ message: "Access denied. This IP address is blocked.",
119
+ };
120
+ }
121
+ }
122
+ return {
123
+ allowed: true,
124
+ ipAddress,
125
+ };
126
+ }
@@ -1,3 +1,2 @@
1
1
  import type { StudioConfig } from "../types/handler.js";
2
2
  export declare function wrapAuthCallbacks(auth: any, eventsConfig: StudioConfig["events"]): void;
3
- //# sourceMappingURL=auth-callbacks-injector.d.ts.map
@@ -222,4 +222,3 @@ export function wrapAuthCallbacks(auth, eventsConfig) {
222
222
  }
223
223
  catch (error) { }
224
224
  }
225
- //# sourceMappingURL=auth-callbacks-injector.js.map
@@ -17,4 +17,3 @@ export declare function detectDatabaseWithDialect(cwd?: string): Promise<Databas
17
17
  * @returns Array of all detected databases
18
18
  */
19
19
  export declare function detectAllDatabases(cwd?: string): Promise<DatabaseDetectionResult[]>;
20
- //# sourceMappingURL=database-detection.d.ts.map
@@ -1,7 +1,8 @@
1
- import { getPackageVersion } from "./package-json.js";
1
+ import { getDirectPackageVersion, getPackageVersion } from "./package-json.js";
2
2
  const DATABASES = {
3
3
  "drizzle-orm": "drizzle",
4
4
  "@prisma/client": "prisma",
5
+ kysely: "kysely",
5
6
  mongoose: "mongodb",
6
7
  mongodb: "mongodb",
7
8
  pg: "postgresql",
@@ -16,6 +17,7 @@ const _DATABASE_DIALECTS = {
16
17
  mariadb: ["mariadb"],
17
18
  sqlite: ["sqlite3", "better-sqlite3"],
18
19
  prisma: ["@prisma/client"],
20
+ kysely: ["kysely"],
19
21
  mongodb: ["mongoose", "mongodb"],
20
22
  drizzle: ["drizzle-orm"],
21
23
  };
@@ -26,7 +28,7 @@ const _DATABASE_DIALECTS = {
26
28
  */
27
29
  export async function detectDatabase(cwd) {
28
30
  for (const [pkg, name] of Object.entries(DATABASES)) {
29
- const version = await getPackageVersion(pkg, cwd);
31
+ const version = pkg === "kysely" ? getDirectPackageVersion(pkg, cwd) : await getPackageVersion(pkg, cwd);
30
32
  if (version)
31
33
  return { name, version };
32
34
  }
@@ -79,6 +81,14 @@ export async function detectDatabaseWithDialect(cwd) {
79
81
  adapter = "drizzle";
80
82
  break;
81
83
  }
84
+ case "kysely": {
85
+ const kyselyDialect = await detectKyselyDialect(cwd);
86
+ if (kyselyDialect) {
87
+ dialect = kyselyDialect;
88
+ }
89
+ adapter = "kysely";
90
+ break;
91
+ }
82
92
  }
83
93
  return {
84
94
  name: detection.name,
@@ -113,6 +123,26 @@ async function detectDrizzleDialect(cwd) {
113
123
  { pkg: "better-sqlite3", dialect: "sqlite" },
114
124
  ];
115
125
  for (const { pkg, dialect } of drizzleDrivers) {
126
+ try {
127
+ const version = await getPackageVersion(pkg, cwd);
128
+ if (version)
129
+ return dialect;
130
+ }
131
+ catch { }
132
+ }
133
+ return undefined;
134
+ }
135
+ async function detectKyselyDialect(cwd) {
136
+ const kyselyDrivers = [
137
+ { pkg: "pg", dialect: "postgresql" },
138
+ { pkg: "postgres", dialect: "postgresql" },
139
+ { pkg: "mysql2", dialect: "mysql" },
140
+ { pkg: "better-sqlite3", dialect: "sqlite" },
141
+ { pkg: "sqlite3", dialect: "sqlite" },
142
+ { pkg: "tedious", dialect: "mssql" },
143
+ { pkg: "mssql", dialect: "mssql" },
144
+ ];
145
+ for (const { pkg, dialect } of kyselyDrivers) {
116
146
  try {
117
147
  const version = await getPackageVersion(pkg, cwd);
118
148
  if (version)
@@ -130,7 +160,7 @@ async function detectDrizzleDialect(cwd) {
130
160
  export async function detectAllDatabases(cwd) {
131
161
  const results = [];
132
162
  for (const [pkg, name] of Object.entries(DATABASES)) {
133
- const version = await getPackageVersion(pkg, cwd);
163
+ const version = pkg === "kysely" ? getDirectPackageVersion(pkg, cwd) : await getPackageVersion(pkg, cwd);
134
164
  if (version) {
135
165
  const detection = await detectDatabaseWithDialect(cwd);
136
166
  if (detection && detection.name === name) {
@@ -140,4 +170,3 @@ export async function detectAllDatabases(cwd) {
140
170
  }
141
171
  return results;
142
172
  }
143
- //# sourceMappingURL=database-detection.js.map
@@ -35,4 +35,3 @@ export declare function getEventQueueSize(): number;
35
35
  * Get the current event ingestion provider
36
36
  */
37
37
  export declare function getEventIngestionProvider(): EventIngestionProvider | null;
38
- //# sourceMappingURL=event-ingestion.d.ts.map
@@ -25,6 +25,7 @@ export function initializeEventIngestion(eventsConfig) {
25
25
  case "postgres":
26
26
  case "prisma":
27
27
  case "drizzle":
28
+ case "kysely":
28
29
  try {
29
30
  provider = createPostgresProvider({
30
31
  client: eventsConfig.client,
@@ -244,4 +245,3 @@ export function getEventQueueSize() {
244
245
  export function getEventIngestionProvider() {
245
246
  return provider;
246
247
  }
247
- //# sourceMappingURL=event-ingestion.js.map
@@ -9,4 +9,3 @@ export declare function injectLastSeenAtHooks(auth: any, config?: {
9
9
  * Inject middleware hooks into Better Auth using plugins
10
10
  */
11
11
  export declare function injectEventHooks(auth: any, eventsConfig: StudioConfig["events"]): void;
12
- //# sourceMappingURL=hook-injector.d.ts.map
@@ -1,4 +1,4 @@
1
- import { createAuthMiddleware } from "better-auth/plugins";
1
+ import { createAuthMiddleware } from "better-auth/api";
2
2
  import { createClickHouseProvider, createHttpProvider, createNodeSqliteProvider, createPostgresProvider, createSqliteProvider, } from "../providers/events/helpers.js";
3
3
  import { wrapAuthCallbacks } from "./auth-callbacks-injector.js";
4
4
  import { emitEvent, isEventIngestionInitialized, } from "./event-ingestion.js";
@@ -967,6 +967,7 @@ function createEventIngestionPlugin(eventsConfig) {
967
967
  case "postgres":
968
968
  case "prisma":
969
969
  case "drizzle":
970
+ case "kysely":
970
971
  provider = createPostgresProvider({
971
972
  client: capturedConfig.client,
972
973
  tableName: capturedConfig.tableName,
@@ -1261,4 +1262,3 @@ export function injectEventHooks(auth, eventsConfig) {
1261
1262
  console.error("[Event Hooks] Failed to inject:", error);
1262
1263
  }
1263
1264
  }
1264
- //# sourceMappingURL=hook-injector.js.map
@@ -1,3 +1,4 @@
1
+ import type { StudioAccessConfig } from "../types/handler.js";
1
2
  export interface StudioMetadata {
2
3
  title?: string;
3
4
  logo?: string;
@@ -9,12 +10,6 @@ export interface StudioMetadata {
9
10
  theme?: "light" | "dark";
10
11
  customStyles?: string;
11
12
  }
12
- export interface StudioAccessConfig {
13
- roles?: string[];
14
- allowEmails?: string[];
15
- sessionDuration?: number;
16
- secret?: string;
17
- }
18
13
  export interface StudioConfig {
19
14
  basePath?: string;
20
15
  metadata?: StudioMetadata;
@@ -63,4 +58,3 @@ export interface WindowStudioConfig {
63
58
  };
64
59
  }
65
60
  export declare function serveIndexHtml(publicDir: string, config?: Partial<StudioConfig>): string;
66
- //# sourceMappingURL=html-injector.d.ts.map
@@ -71,8 +71,23 @@ function injectConfig(html, config) {
71
71
  .replace(/'/g, "&#39;");
72
72
  const script = `
73
73
  <script>
74
+ const __BAS_THEME_KEY__ = "better-auth-studio-theme";
74
75
  window.__STUDIO_CONFIG__ = ${safeJson};
75
76
  Object.freeze(window.__STUDIO_CONFIG__);
77
+ try {
78
+ const configuredTheme = window.__STUDIO_CONFIG__?.metadata?.theme === "light" ? "light" : "dark";
79
+ const storedTheme = window.localStorage.getItem(__BAS_THEME_KEY__);
80
+ const activeTheme = storedTheme === "light" || storedTheme === "dark" ? storedTheme : configuredTheme;
81
+ document.documentElement.dataset.theme = activeTheme;
82
+ document.documentElement.style.colorScheme = activeTheme;
83
+ document.documentElement.classList.remove("light", "dark");
84
+ document.documentElement.classList.add(activeTheme);
85
+ } catch {
86
+ document.documentElement.dataset.theme = window.__STUDIO_CONFIG__?.metadata?.theme === "light" ? "light" : "dark";
87
+ document.documentElement.style.colorScheme = document.documentElement.dataset.theme;
88
+ document.documentElement.classList.remove("light", "dark");
89
+ document.documentElement.classList.add(document.documentElement.dataset.theme);
90
+ }
76
91
  // Update document title from config
77
92
  if (window.__STUDIO_CONFIG__?.metadata?.title) {
78
93
  document.title = window.__STUDIO_CONFIG__.metadata.title;
@@ -124,4 +139,3 @@ function injectConfig(html, config) {
124
139
  }
125
140
  return modifiedHtml.replace("</head>", `${script}</head>`);
126
141
  }
127
- //# sourceMappingURL=html-injector.js.map
@@ -71,4 +71,3 @@ export declare function createOrganizationHooksWithEvents(eventsConfig: StudioCo
71
71
  * This should be called during Better Auth initialization
72
72
  */
73
73
  export declare function wrapOrganizationPluginHooks(auth: any, eventsConfig: StudioConfig["events"]): void;
74
- //# sourceMappingURL=org-hooks-injector.d.ts.map
@@ -645,4 +645,3 @@ export function wrapOrganizationPluginHooks(auth, eventsConfig) {
645
645
  console.error("[Organization Hooks] Failed to wrap hooks:", error);
646
646
  }
647
647
  }
648
- //# sourceMappingURL=org-hooks-injector.js.map
@@ -5,4 +5,4 @@
5
5
  * @returns The version string if found, undefined otherwise
6
6
  */
7
7
  export declare function getPackageVersion(packageName: string, cwd?: string): Promise<string | undefined>;
8
- //# sourceMappingURL=package-json.d.ts.map
8
+ export declare function getDirectPackageVersion(packageName: string, cwd?: string): string | undefined;
@@ -60,4 +60,24 @@ export async function getPackageVersion(packageName, cwd) {
60
60
  return undefined;
61
61
  }
62
62
  }
63
- //# sourceMappingURL=package-json.js.map
63
+ export function getDirectPackageVersion(packageName, cwd) {
64
+ const searchDir = cwd || process.cwd();
65
+ const projectRoot = findProjectRoot(searchDir);
66
+ const packageJsonPaths = Array.from(new Set([join(searchDir, "package.json"), join(projectRoot, "package.json")]));
67
+ for (const packageJsonPath of packageJsonPaths) {
68
+ if (!existsSync(packageJsonPath)) {
69
+ continue;
70
+ }
71
+ try {
72
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
73
+ const version = packageJson.dependencies?.[packageName] ||
74
+ packageJson.devDependencies?.[packageName] ||
75
+ packageJson.peerDependencies?.[packageName];
76
+ if (version) {
77
+ return version.replace(/[\^~]/, "");
78
+ }
79
+ }
80
+ catch { }
81
+ }
82
+ return undefined;
83
+ }
@@ -1,2 +1 @@
1
1
  export declare const possiblePaths: string[];
2
- //# sourceMappingURL=paths.d.ts.map
@@ -9,4 +9,3 @@ export const possiblePaths = [
9
9
  ...basePaths.map((it) => `app/${it}`),
10
10
  ...basePaths.map((it) => `apps/${it}`),
11
11
  ];
12
- //# sourceMappingURL=paths.js.map
@@ -3,4 +3,3 @@
3
3
  * Known codes (e.g. invalid_credentials) are mapped; other values are used as-is (e.g. API messages).
4
4
  */
5
5
  export declare function reasonToMessage(reason: string | undefined): string;
6
- //# sourceMappingURL=reason-messages.d.ts.map
@@ -30,4 +30,3 @@ export function reasonToMessage(reason) {
30
30
  return mapped;
31
31
  return trimmed;
32
32
  }
33
- //# sourceMappingURL=reason-messages.js.map
@@ -17,4 +17,3 @@ export declare function createStudioSession(user: {
17
17
  image?: string;
18
18
  }, durationMs?: number): StudioSession;
19
19
  export declare const STUDIO_COOKIE_NAME = "better_auth_studio_session";
20
- //# sourceMappingURL=session.d.ts.map
@@ -55,4 +55,3 @@ export function createStudioSession(user, durationMs = 7 * 24 * 60 * 60 * 1000)
55
55
  };
56
56
  }
57
57
  export const STUDIO_COOKIE_NAME = "better_auth_studio_session";
58
- //# sourceMappingURL=session.js.map
package/dist/utils.d.ts CHANGED
@@ -1,2 +1 @@
1
1
  export declare const possibleConfigFiles: string[];
2
- //# sourceMappingURL=utils.d.ts.map
package/dist/utils.js CHANGED
@@ -24,4 +24,3 @@ export const possibleConfigFiles = [
24
24
  "auth.config.ts",
25
25
  "auth.config.js",
26
26
  ];
27
- //# sourceMappingURL=utils.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-auth-studio",
3
- "version": "1.1.3-beta.9",
3
+ "version": "1.1.3",
4
4
  "description": "Studio for Better Auth",
5
5
  "keywords": [
6
6
  "admin",
@@ -19,8 +19,7 @@
19
19
  "README.md",
20
20
  "data/default-geo.json",
21
21
  "dist/",
22
- "public/",
23
- "scripts/"
22
+ "scripts/postinstall.js"
24
23
  ],
25
24
  "type": "module",
26
25
  "main": "dist/index.js",
@@ -29,6 +28,7 @@
29
28
  "./express": "./dist/adapters/express.js",
30
29
  "./nextjs": "./dist/adapters/nextjs.js",
31
30
  "./hono": "./dist/adapters/hono.js",
31
+ "./cloudflare-workers": "./dist/adapters/cloudflare-workers.js",
32
32
  "./elysia": "./dist/adapters/elysia.js",
33
33
  "./svelte-kit": "./dist/adapters/svelte-kit.js",
34
34
  "./solid-start": "./dist/adapters/solid-start.js",
@@ -38,33 +38,6 @@
38
38
  "./nuxt": "./dist/adapters/nuxt.js",
39
39
  "./config": "./dist/types/handler.js"
40
40
  },
41
- "scripts": {
42
- "build": "tsc && pnpm run frontend:build && pnpm run copy:public && pnpm run verify:public",
43
- "geo:update": "node scripts/download-geolite2.js",
44
- "copy:public": "rm -rf dist/public && cp -r public dist/",
45
- "verify:public": "test -f dist/public/index.html && echo '✓ Public directory copied successfully' || (echo '✗ ERROR: Public directory not copied!' && exit 1)",
46
- "postinstall": "node scripts/postinstall.js",
47
- "dev": "tsx src/cli.ts",
48
- "start": "node dist/cli.js",
49
- "studio": "tsx src/cli.ts",
50
- "clean": "rm -rf dist",
51
- "frontend:dev": "cd frontend && pnpm run dev",
52
- "frontend:build": "cd frontend && pnpm run build",
53
- "frontend:preview": "cd frontend && pnpm run preview",
54
- "lint": "oxlint . && oxfmt --check .",
55
- "format": "oxlint --fix . && oxfmt .",
56
- "lint:fix": "oxlint --fix . && oxfmt .",
57
- "type-check": "tsc --noEmit",
58
- "test": "vitest",
59
- "test:watch": "vitest --watch",
60
- "test:coverage": "vitest --coverage",
61
- "test:ci": "pnpm test --run",
62
- "release": "pnpm build && bumpp && pnpm publish --access public --no-git-checks",
63
- "release:beta": "pnpm build && bumpp --preid beta && pnpm publish --access public --tag beta --no-git-checks",
64
- "release:no-build": "bumpp && pnpm publish --access public --no-git-checks --tag next",
65
- "release:canary": "pnpm build && bumpp --preid canary --no-commit --no-tag --no-push && pnpm publish --access public --tag canary --no-git-checks",
66
- "bump": "bumpp"
67
- },
68
41
  "dependencies": {
69
42
  "@babel/preset-react": "^7.27.1",
70
43
  "@babel/preset-typescript": "^7.27.1",
@@ -104,13 +77,31 @@
104
77
  "engines": {
105
78
  "node": ">=18.0.0"
106
79
  },
107
- "pnpm": {
108
- "overrides": {
109
- "qs": ">=6.14.1",
110
- "@remix-run/router": ">=1.23.2",
111
- "devalue": ">=5.6.2",
112
- "@sveltejs/kit": ">=2.49.5",
113
- "next": ">=15.5.10"
114
- }
80
+ "scripts": {
81
+ "build": "pnpm run clean && tsc && pnpm run frontend:build && pnpm run copy:public && pnpm run verify:public",
82
+ "geo:update": "node scripts/download-geolite2.js",
83
+ "copy:public": "rm -rf dist/public && cp -r public dist/",
84
+ "verify:public": "test -f dist/public/index.html && echo '✓ Public directory copied successfully' || (echo '✗ ERROR: Public directory not copied!' && exit 1)",
85
+ "postinstall": "node scripts/postinstall.js",
86
+ "dev": "tsx src/cli.ts",
87
+ "start": "node dist/cli.js",
88
+ "studio": "tsx src/cli.ts",
89
+ "clean": "rm -rf dist",
90
+ "frontend:dev": "cd frontend && pnpm run dev",
91
+ "frontend:build": "cd frontend && pnpm run build",
92
+ "frontend:preview": "cd frontend && pnpm run preview",
93
+ "lint": "oxlint . && oxfmt --check .",
94
+ "format": "oxlint --fix . && oxfmt .",
95
+ "lint:fix": "oxlint --fix . && oxfmt .",
96
+ "type-check": "tsc --noEmit",
97
+ "test": "vitest",
98
+ "test:watch": "vitest --watch",
99
+ "test:coverage": "vitest --coverage",
100
+ "test:ci": "pnpm test --run",
101
+ "release": "pnpm build && bumpp && pnpm publish --access public --no-git-checks",
102
+ "release:beta": "pnpm build && bumpp --preid beta && pnpm publish --access public --tag beta --no-git-checks",
103
+ "release:no-build": "bumpp && pnpm publish --access public --no-git-checks --tag next",
104
+ "release:canary": "pnpm build && bumpp --preid canary --no-commit --no-tag --no-push && pnpm publish --access public --tag canary --no-git-checks",
105
+ "bump": "bumpp"
115
106
  }
116
- }
107
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"astro.d.ts","sourceRoot":"","sources":["../../src/adapters/astro.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAuC,MAAM,qBAAqB,CAAC;AAG7F;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,IAMrC,KAAK;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,KAAG,OAAO,CAAC,QAAQ,CAAC,CAa5D"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"astro.js","sourceRoot":"","sources":["../../src/adapters/astro.ts"],"names":[],"mappings":"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"}