better-auth-studio 1.1.2-beta.2 → 1.1.2-beta.20
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/README.md +48 -78
- package/data/default-geo.json +1 -1
- package/dist/adapters/astro.d.ts +1 -1
- package/dist/adapters/astro.js +13 -13
- package/dist/adapters/elysia.d.ts +2 -2
- package/dist/adapters/elysia.js +13 -13
- package/dist/adapters/express.d.ts +2 -2
- package/dist/adapters/express.js +4 -4
- package/dist/adapters/hono.d.ts +2 -2
- package/dist/adapters/hono.js +12 -12
- package/dist/adapters/nextjs.d.ts +1 -1
- package/dist/adapters/nextjs.js +10 -10
- package/dist/adapters/nuxt.d.ts +1 -1
- package/dist/adapters/nuxt.js +22 -22
- package/dist/adapters/remix.d.ts +1 -1
- package/dist/adapters/remix.js +13 -13
- package/dist/adapters/solid-start.d.ts +1 -1
- package/dist/adapters/solid-start.js +13 -13
- package/dist/adapters/svelte-kit.d.ts +2 -2
- package/dist/adapters/svelte-kit.js +13 -13
- package/dist/adapters/tanstack-start.d.ts +1 -1
- package/dist/adapters/tanstack-start.js +13 -13
- package/dist/add-svelte-kit-env-modules.js +11 -11
- package/dist/auth-adapter.d.ts +1 -1
- package/dist/auth-adapter.js +96 -96
- package/dist/cli/commands/init.js +57 -57
- package/dist/cli.js +75 -75
- package/dist/config.d.ts +5 -5
- package/dist/config.js +37 -37
- package/dist/core/handler.d.ts +1 -1
- package/dist/core/handler.js +116 -115
- package/dist/core/handler.js.map +1 -1
- package/dist/data.d.ts +2 -2
- package/dist/data.js +60 -60
- package/dist/geo-service.js +78 -78
- package/dist/get-tsconfig-info.js +4 -4
- package/dist/index.d.ts +8 -8
- package/dist/index.js +6 -6
- package/dist/providers/events/helpers.d.ts +2 -2
- package/dist/providers/events/helpers.d.ts.map +1 -1
- package/dist/providers/events/helpers.js +178 -154
- package/dist/providers/events/helpers.js.map +1 -1
- package/dist/public/assets/{main-BDJUrMKx.js → main-BeCk6LUx.js} +133 -133
- package/dist/public/assets/main-w2bJSKlF.css +1 -0
- package/dist/public/index.html +2 -2
- package/dist/routes/api-router.d.ts +3 -1
- package/dist/routes/api-router.d.ts.map +1 -1
- package/dist/routes/api-router.js +3 -3
- package/dist/routes/api-router.js.map +1 -1
- package/dist/routes.d.ts +6 -4
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +1333 -1277
- package/dist/routes.js.map +1 -1
- package/dist/studio.d.ts +3 -3
- package/dist/studio.d.ts.map +1 -1
- package/dist/studio.js +64 -65
- package/dist/studio.js.map +1 -1
- package/dist/types/events.d.ts +8 -7
- package/dist/types/events.d.ts.map +1 -1
- package/dist/types/events.js +165 -165
- package/dist/types/events.js.map +1 -1
- package/dist/types/handler.d.ts +14 -4
- package/dist/types/handler.d.ts.map +1 -1
- package/dist/types/handler.js.map +1 -1
- package/dist/utils/auth-callbacks-injector.d.ts +2 -2
- package/dist/utils/auth-callbacks-injector.js +27 -27
- package/dist/utils/auth-callbacks-wrapper.d.ts +3 -3
- package/dist/utils/auth-callbacks-wrapper.js +117 -107
- package/dist/utils/database-detection.d.ts +1 -1
- package/dist/utils/database-detection.js +44 -44
- package/dist/utils/database-hook-injector.d.ts +3 -3
- package/dist/utils/database-hook-injector.js +135 -131
- package/dist/utils/email-otp-hooks-injector.d.ts +28 -12
- package/dist/utils/email-otp-hooks-injector.js +104 -97
- package/dist/utils/event-ingestion.d.ts +5 -5
- package/dist/utils/event-ingestion.d.ts.map +1 -1
- package/dist/utils/event-ingestion.js +32 -12
- package/dist/utils/event-ingestion.js.map +1 -1
- package/dist/utils/hook-injector.d.ts +2 -2
- package/dist/utils/hook-injector.js +199 -199
- package/dist/utils/html-injector.d.ts +11 -2
- package/dist/utils/html-injector.d.ts.map +1 -1
- package/dist/utils/html-injector.js +40 -39
- package/dist/utils/html-injector.js.map +1 -1
- package/dist/utils/org-hooks-injector.d.ts +3 -3
- package/dist/utils/org-hooks-injector.js +63 -63
- package/dist/utils/org-hooks-wrapper.d.ts +41 -35
- package/dist/utils/org-hooks-wrapper.js +778 -658
- package/dist/utils/organization-hooks-wrapper.d.ts +23 -17
- package/dist/utils/organization-hooks-wrapper.js +325 -277
- package/dist/utils/package-json.js +11 -11
- package/dist/utils/paths.js +1 -1
- package/dist/utils/server-init.d.ts +1 -1
- package/dist/utils/server-init.js +25 -25
- package/dist/utils/session.d.ts +0 -1
- package/dist/utils/session.d.ts.map +1 -1
- package/dist/utils/session.js +19 -12
- package/dist/utils/session.js.map +1 -1
- package/dist/utils.js +24 -24
- package/package.json +25 -24
- package/public/assets/{main-BDJUrMKx.js → main-BeCk6LUx.js} +133 -133
- package/public/assets/main-w2bJSKlF.css +1 -0
- package/public/index.html +2 -2
- package/scripts/download-geolite2.js +8 -8
- package/scripts/generate-default-db.js +324 -324
- package/scripts/postinstall.js +25 -25
- package/dist/public/assets/main-CBA9bZ-w.css +0 -1
- package/public/assets/main-CBA9bZ-w.css +0 -1
|
@@ -1,141 +1,145 @@
|
|
|
1
|
-
import { emitEvent } from
|
|
1
|
+
import { emitEvent } from "./event-ingestion.js";
|
|
2
2
|
export function wrapDatabaseHooks(auth, eventsConfig) {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
if (!auth || !eventsConfig?.enabled) {
|
|
4
|
+
return;
|
|
5
|
+
}
|
|
6
|
+
try {
|
|
7
|
+
// Ensure auth.options exists
|
|
8
|
+
if (!auth.options) {
|
|
9
|
+
auth.options = {};
|
|
10
|
+
}
|
|
11
|
+
// Only proceed if auth.options is a valid object
|
|
12
|
+
if (typeof auth.options !== "object" || auth.options === null) {
|
|
13
|
+
console.warn("[Database Hooks] auth.options is not a valid object");
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const capturedConfig = eventsConfig;
|
|
17
|
+
// Initialize databaseHooks if it doesn't exist
|
|
18
|
+
if (!auth.options.databaseHooks) {
|
|
19
|
+
auth.options.databaseHooks = {};
|
|
20
|
+
}
|
|
21
|
+
// Check if already wrapped
|
|
22
|
+
if (auth.options.databaseHooks.__studio_wrapped) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// Ensure databaseHooks is an object
|
|
26
|
+
if (typeof auth.options.databaseHooks !== "object" || auth.options.databaseHooks === null) {
|
|
27
|
+
console.warn("[Database Hooks] databaseHooks is not a valid object");
|
|
28
|
+
return;
|
|
5
29
|
}
|
|
6
30
|
try {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
//
|
|
12
|
-
if (
|
|
13
|
-
|
|
14
|
-
|
|
31
|
+
const existingAccountHooks = auth.options.databaseHooks.account || {};
|
|
32
|
+
const existingCreateHooks = existingAccountHooks.create || {};
|
|
33
|
+
const existingAfter = existingCreateHooks.after;
|
|
34
|
+
const oauthAccountAfter = async (account, context) => {
|
|
35
|
+
// Validate context and internalAdapter exist
|
|
36
|
+
if (!context || !context.internalAdapter) {
|
|
37
|
+
console.warn("[OAuth DB Hook] Context or internalAdapter is missing");
|
|
38
|
+
return;
|
|
15
39
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
auth.options.databaseHooks = {};
|
|
40
|
+
// Validate account exists
|
|
41
|
+
if (!account || !account.userId || !account.providerId) {
|
|
42
|
+
return;
|
|
20
43
|
}
|
|
21
|
-
|
|
22
|
-
if (
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const existingAccountHooks = auth.options.databaseHooks.account || {};
|
|
32
|
-
const existingCreateHooks = existingAccountHooks.create || {};
|
|
33
|
-
const existingAfter = existingCreateHooks.after;
|
|
34
|
-
const oauthAccountAfter = async (account, context) => {
|
|
35
|
-
// Validate context and internalAdapter exist
|
|
36
|
-
if (!context || !context.internalAdapter) {
|
|
37
|
-
console.warn('[OAuth DB Hook] Context or internalAdapter is missing');
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
// Validate account exists
|
|
41
|
-
if (!account || !account.userId || !account.providerId) {
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
console.log('OAuth account created', account);
|
|
45
|
-
if (account.providerId !== 'credential') {
|
|
46
|
-
try {
|
|
47
|
-
// Ensure internalAdapter methods exist
|
|
48
|
-
if (typeof context.internalAdapter.findUserById !== 'function' ||
|
|
49
|
-
typeof context.internalAdapter.findAccounts !== 'function') {
|
|
50
|
-
console.warn('[OAuth DB Hook] internalAdapter methods are missing');
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
const user = await context.internalAdapter.findUserById(account.userId);
|
|
54
|
-
if (user) {
|
|
55
|
-
const existingAccounts = await context.internalAdapter.findAccounts(account.userId);
|
|
56
|
-
const isLinking = existingAccounts && existingAccounts.length > 1; // More than just this new account
|
|
57
|
-
if (isLinking) {
|
|
58
|
-
await emitEvent('oauth.linked', {
|
|
59
|
-
status: 'success',
|
|
60
|
-
userId: account.userId,
|
|
61
|
-
metadata: {
|
|
62
|
-
provider: account.providerId,
|
|
63
|
-
providerId: account.providerId,
|
|
64
|
-
userEmail: user.email,
|
|
65
|
-
email: user.email,
|
|
66
|
-
name: user.name,
|
|
67
|
-
accountId: account.accountId,
|
|
68
|
-
linkedAt: new Date().toISOString(),
|
|
69
|
-
},
|
|
70
|
-
}, capturedConfig).catch(() => { });
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
await emitEvent('oauth.sign_in', {
|
|
74
|
-
status: 'success',
|
|
75
|
-
userId: account.userId,
|
|
76
|
-
metadata: {
|
|
77
|
-
provider: account.providerId,
|
|
78
|
-
providerId: account.providerId,
|
|
79
|
-
userEmail: user.email,
|
|
80
|
-
email: user.email,
|
|
81
|
-
name: user.name,
|
|
82
|
-
emailVerified: user.emailVerified,
|
|
83
|
-
accountId: account.accountId,
|
|
84
|
-
createdAt: user.createdAt
|
|
85
|
-
? new Date(user.createdAt).toISOString()
|
|
86
|
-
: new Date().toISOString(),
|
|
87
|
-
},
|
|
88
|
-
}, capturedConfig).catch(() => { });
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
catch (error) {
|
|
93
|
-
console.error('[OAuth DB Hook] Error:', error);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
// Safely assign the hook - wrap in try-catch to prevent any Better Auth initialization errors
|
|
98
|
-
try {
|
|
99
|
-
auth.options.databaseHooks.account = {
|
|
100
|
-
...existingAccountHooks,
|
|
101
|
-
create: {
|
|
102
|
-
...existingCreateHooks,
|
|
103
|
-
before: existingCreateHooks.before,
|
|
104
|
-
after: async (account, context) => {
|
|
105
|
-
try {
|
|
106
|
-
// Call existing hook first if it exists
|
|
107
|
-
if (existingAfter && typeof existingAfter === 'function') {
|
|
108
|
-
await existingAfter(account, context);
|
|
109
|
-
}
|
|
110
|
-
// Then call our OAuth tracking hook
|
|
111
|
-
await oauthAccountAfter(account, context);
|
|
112
|
-
}
|
|
113
|
-
catch (error) {
|
|
114
|
-
// Don't let hook errors break the flow
|
|
115
|
-
console.error('[Database Hook] Error in after hook:', error);
|
|
116
|
-
// Re-throw only if it's not a reloadNavigation error (Better Auth internal issue)
|
|
117
|
-
if (error instanceof Error && !error.message.includes('reloadNavigation')) {
|
|
118
|
-
throw error;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
};
|
|
124
|
-
auth.options.databaseHooks.__studio_wrapped = true;
|
|
44
|
+
console.log("OAuth account created", account);
|
|
45
|
+
if (account.providerId !== "credential") {
|
|
46
|
+
try {
|
|
47
|
+
// Ensure internalAdapter methods exist
|
|
48
|
+
if (
|
|
49
|
+
typeof context.internalAdapter.findUserById !== "function" ||
|
|
50
|
+
typeof context.internalAdapter.findAccounts !== "function"
|
|
51
|
+
) {
|
|
52
|
+
console.warn("[OAuth DB Hook] internalAdapter methods are missing");
|
|
53
|
+
return;
|
|
125
54
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
55
|
+
const user = await context.internalAdapter.findUserById(account.userId);
|
|
56
|
+
if (user) {
|
|
57
|
+
const existingAccounts = await context.internalAdapter.findAccounts(account.userId);
|
|
58
|
+
const isLinking = existingAccounts && existingAccounts.length > 1; // More than just this new account
|
|
59
|
+
if (isLinking) {
|
|
60
|
+
await emitEvent(
|
|
61
|
+
"oauth.linked",
|
|
62
|
+
{
|
|
63
|
+
status: "success",
|
|
64
|
+
userId: account.userId,
|
|
65
|
+
metadata: {
|
|
66
|
+
provider: account.providerId,
|
|
67
|
+
providerId: account.providerId,
|
|
68
|
+
userEmail: user.email,
|
|
69
|
+
email: user.email,
|
|
70
|
+
name: user.name,
|
|
71
|
+
accountId: account.accountId,
|
|
72
|
+
linkedAt: new Date().toISOString(),
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
capturedConfig,
|
|
76
|
+
).catch(() => {});
|
|
77
|
+
} else {
|
|
78
|
+
await emitEvent(
|
|
79
|
+
"oauth.sign_in",
|
|
80
|
+
{
|
|
81
|
+
status: "success",
|
|
82
|
+
userId: account.userId,
|
|
83
|
+
metadata: {
|
|
84
|
+
provider: account.providerId,
|
|
85
|
+
providerId: account.providerId,
|
|
86
|
+
userEmail: user.email,
|
|
87
|
+
email: user.email,
|
|
88
|
+
name: user.name,
|
|
89
|
+
emailVerified: user.emailVerified,
|
|
90
|
+
accountId: account.accountId,
|
|
91
|
+
createdAt: user.createdAt
|
|
92
|
+
? new Date(user.createdAt).toISOString()
|
|
93
|
+
: new Date().toISOString(),
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
capturedConfig,
|
|
97
|
+
).catch(() => {});
|
|
98
|
+
}
|
|
130
99
|
}
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error("[OAuth DB Hook] Error:", error);
|
|
102
|
+
}
|
|
131
103
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
104
|
+
};
|
|
105
|
+
// Safely assign the hook - wrap in try-catch to prevent any Better Auth initialization errors
|
|
106
|
+
try {
|
|
107
|
+
auth.options.databaseHooks.account = {
|
|
108
|
+
...existingAccountHooks,
|
|
109
|
+
create: {
|
|
110
|
+
...existingCreateHooks,
|
|
111
|
+
before: existingCreateHooks.before,
|
|
112
|
+
after: async (account, context) => {
|
|
113
|
+
try {
|
|
114
|
+
// Call existing hook first if it exists
|
|
115
|
+
if (existingAfter && typeof existingAfter === "function") {
|
|
116
|
+
await existingAfter(account, context);
|
|
117
|
+
}
|
|
118
|
+
// Then call our OAuth tracking hook
|
|
119
|
+
await oauthAccountAfter(account, context);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
// Don't let hook errors break the flow
|
|
122
|
+
console.error("[Database Hook] Error in after hook:", error);
|
|
123
|
+
// Re-throw only if it's not a reloadNavigation error (Better Auth internal issue)
|
|
124
|
+
if (error instanceof Error && !error.message.includes("reloadNavigation")) {
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
auth.options.databaseHooks.__studio_wrapped = true;
|
|
132
|
+
} catch (assignError) {
|
|
133
|
+
// If assignment fails, log but don't crash
|
|
134
|
+
console.error("[Database Hooks] Error assigning hooks:", assignError);
|
|
135
|
+
// Don't mark as wrapped if assignment failed
|
|
136
|
+
}
|
|
137
|
+
} catch (hookError) {
|
|
138
|
+
console.error("[Database Hooks] Error setting up hooks:", hookError);
|
|
139
|
+
// Don't mark as wrapped if there was an error
|
|
139
140
|
}
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error("[Database Hooks] Failed to wrap:", error);
|
|
143
|
+
}
|
|
140
144
|
}
|
|
141
|
-
//# sourceMappingURL=database-hook-injector.js.map
|
|
145
|
+
//# sourceMappingURL=database-hook-injector.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { StudioConfig } from
|
|
1
|
+
import type { StudioConfig } from "../types/handler.js";
|
|
2
2
|
/**
|
|
3
3
|
* Wraps email-otp plugin callbacks to automatically emit events
|
|
4
4
|
* This wraps the sendVerificationOTP callback similar to how organization hooks work
|
|
@@ -7,15 +7,27 @@ import type { StudioConfig } from '../types/handler.js';
|
|
|
7
7
|
* @param existingCallback - The original sendVerificationOTP callback
|
|
8
8
|
* @param passwordResetMethodMap - Optional shared Map to track password reset method (OTP vs token)
|
|
9
9
|
*/
|
|
10
|
-
export declare function wrapEmailOTPPluginCallbacks(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
export declare function wrapEmailOTPPluginCallbacks(
|
|
11
|
+
eventsConfig: StudioConfig["events"],
|
|
12
|
+
existingCallback?: (
|
|
13
|
+
data: {
|
|
14
|
+
email: string;
|
|
15
|
+
otp: string;
|
|
16
|
+
type: "sign-in" | "email-verification" | "forget-password";
|
|
17
|
+
},
|
|
18
|
+
ctx?: any,
|
|
19
|
+
) => Promise<void>,
|
|
20
|
+
passwordResetMethodMap?: Map<string, "otp" | "token">,
|
|
21
|
+
):
|
|
22
|
+
| ((
|
|
23
|
+
data: {
|
|
24
|
+
email: string;
|
|
25
|
+
otp: string;
|
|
26
|
+
type: "sign-in" | "email-verification" | "forget-password";
|
|
27
|
+
},
|
|
28
|
+
ctx?: any,
|
|
29
|
+
) => Promise<void>)
|
|
30
|
+
| undefined;
|
|
19
31
|
/**
|
|
20
32
|
* Automatically wraps email-otp plugin callbacks to emit events
|
|
21
33
|
* This should be called during Better Auth initialization
|
|
@@ -25,5 +37,9 @@ export declare function wrapEmailOTPPluginCallbacks(eventsConfig: StudioConfig['
|
|
|
25
37
|
* @param eventsConfig - The events configuration
|
|
26
38
|
* @param passwordResetMethodMap - Optional shared Map to track password reset method (OTP vs token)
|
|
27
39
|
*/
|
|
28
|
-
export declare function wrapEmailOTPPluginHooks(
|
|
29
|
-
|
|
40
|
+
export declare function wrapEmailOTPPluginHooks(
|
|
41
|
+
auth: any,
|
|
42
|
+
eventsConfig: StudioConfig["events"],
|
|
43
|
+
passwordResetMethodMap?: Map<string, "otp" | "token">,
|
|
44
|
+
): void;
|
|
45
|
+
//# sourceMappingURL=email-otp-hooks-injector.d.ts.map
|
|
@@ -1,40 +1,37 @@
|
|
|
1
|
-
import { emitEvent } from
|
|
1
|
+
import { emitEvent } from "./event-ingestion.js";
|
|
2
2
|
/**
|
|
3
3
|
* Helper to extract request info from Better Auth request object
|
|
4
4
|
*/
|
|
5
5
|
function getRequestInfo(request) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
headersObj[key] = String(value);
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
catch (e) {
|
|
34
|
-
// Ignore errors
|
|
6
|
+
const headersObj = {};
|
|
7
|
+
let ip;
|
|
8
|
+
if (request) {
|
|
9
|
+
try {
|
|
10
|
+
if (request instanceof Request) {
|
|
11
|
+
request.headers.forEach((value, key) => {
|
|
12
|
+
headersObj[key] = value;
|
|
13
|
+
});
|
|
14
|
+
ip =
|
|
15
|
+
request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || undefined;
|
|
16
|
+
} else if (request.headers) {
|
|
17
|
+
if (typeof request.headers.get === "function") {
|
|
18
|
+
ip =
|
|
19
|
+
request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || undefined;
|
|
20
|
+
request.headers.forEach?.((value, key) => {
|
|
21
|
+
headersObj[key] = value;
|
|
22
|
+
});
|
|
23
|
+
} else {
|
|
24
|
+
ip = request.headers["x-forwarded-for"] || request.headers["x-real-ip"] || undefined;
|
|
25
|
+
Object.entries(request.headers).forEach(([key, value]) => {
|
|
26
|
+
headersObj[key] = String(value);
|
|
27
|
+
});
|
|
35
28
|
}
|
|
29
|
+
}
|
|
30
|
+
} catch (e) {
|
|
31
|
+
// Ignore errors
|
|
36
32
|
}
|
|
37
|
-
|
|
33
|
+
}
|
|
34
|
+
return { headers: headersObj, ip };
|
|
38
35
|
}
|
|
39
36
|
// Share password reset method tracking with auth-callbacks-injector
|
|
40
37
|
// This is used to determine if password reset was via OTP or token
|
|
@@ -50,45 +47,52 @@ function getRequestInfo(request) {
|
|
|
50
47
|
* @param existingCallback - The original sendVerificationOTP callback
|
|
51
48
|
* @param passwordResetMethodMap - Optional shared Map to track password reset method (OTP vs token)
|
|
52
49
|
*/
|
|
53
|
-
export function wrapEmailOTPPluginCallbacks(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
50
|
+
export function wrapEmailOTPPluginCallbacks(
|
|
51
|
+
eventsConfig,
|
|
52
|
+
existingCallback,
|
|
53
|
+
passwordResetMethodMap,
|
|
54
|
+
) {
|
|
55
|
+
if (!eventsConfig?.enabled) {
|
|
56
|
+
return existingCallback;
|
|
57
|
+
}
|
|
58
|
+
if (!existingCallback) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
const capturedConfig = eventsConfig;
|
|
62
|
+
return async (data, ctx) => {
|
|
63
|
+
const requestInfo = getRequestInfo(ctx?.request || ctx);
|
|
64
|
+
// Call the original callback first
|
|
65
|
+
const originalPromise = existingCallback(data, ctx);
|
|
66
|
+
// Track and emit event for password reset OTP
|
|
67
|
+
if (data.type === "forget-password") {
|
|
68
|
+
const email = data.email.toLowerCase();
|
|
69
|
+
// Track that this is an OTP-based password reset
|
|
70
|
+
// This will be checked by onPasswordReset in auth-callbacks-injector
|
|
71
|
+
if (passwordResetMethodMap) {
|
|
72
|
+
passwordResetMethodMap.set(email, "otp");
|
|
73
|
+
}
|
|
74
|
+
// Emit event for password reset OTP requested
|
|
75
|
+
const eventPromise = emitEvent(
|
|
76
|
+
"password.reset_requested_otp",
|
|
77
|
+
{
|
|
78
|
+
status: "success",
|
|
79
|
+
metadata: {
|
|
80
|
+
email: data.email,
|
|
81
|
+
type: "forget-password",
|
|
82
|
+
requestedAt: new Date().toISOString(),
|
|
83
|
+
},
|
|
84
|
+
request: requestInfo,
|
|
85
|
+
},
|
|
86
|
+
capturedConfig,
|
|
87
|
+
).catch(() => {});
|
|
88
|
+
// Wait for original callback to complete
|
|
89
|
+
await originalPromise;
|
|
90
|
+
// Don't wait for event emission to avoid blocking
|
|
91
|
+
eventPromise.catch(() => {});
|
|
92
|
+
} else {
|
|
93
|
+
await originalPromise;
|
|
59
94
|
}
|
|
60
|
-
|
|
61
|
-
return async (data, ctx) => {
|
|
62
|
-
const requestInfo = getRequestInfo(ctx?.request || ctx);
|
|
63
|
-
// Call the original callback first
|
|
64
|
-
const originalPromise = existingCallback(data, ctx);
|
|
65
|
-
// Track and emit event for password reset OTP
|
|
66
|
-
if (data.type === 'forget-password') {
|
|
67
|
-
const email = data.email.toLowerCase();
|
|
68
|
-
// Track that this is an OTP-based password reset
|
|
69
|
-
// This will be checked by onPasswordReset in auth-callbacks-injector
|
|
70
|
-
if (passwordResetMethodMap) {
|
|
71
|
-
passwordResetMethodMap.set(email, 'otp');
|
|
72
|
-
}
|
|
73
|
-
// Emit event for password reset OTP requested
|
|
74
|
-
const eventPromise = emitEvent('password.reset_requested_otp', {
|
|
75
|
-
status: 'success',
|
|
76
|
-
metadata: {
|
|
77
|
-
email: data.email,
|
|
78
|
-
type: 'forget-password',
|
|
79
|
-
requestedAt: new Date().toISOString(),
|
|
80
|
-
},
|
|
81
|
-
request: requestInfo,
|
|
82
|
-
}, capturedConfig).catch(() => { });
|
|
83
|
-
// Wait for original callback to complete
|
|
84
|
-
await originalPromise;
|
|
85
|
-
// Don't wait for event emission to avoid blocking
|
|
86
|
-
eventPromise.catch(() => { });
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
await originalPromise;
|
|
90
|
-
}
|
|
91
|
-
};
|
|
95
|
+
};
|
|
92
96
|
}
|
|
93
97
|
/**
|
|
94
98
|
* Automatically wraps email-otp plugin callbacks to emit events
|
|
@@ -100,35 +104,38 @@ export function wrapEmailOTPPluginCallbacks(eventsConfig, existingCallback, pass
|
|
|
100
104
|
* @param passwordResetMethodMap - Optional shared Map to track password reset method (OTP vs token)
|
|
101
105
|
*/
|
|
102
106
|
export function wrapEmailOTPPluginHooks(auth, eventsConfig, passwordResetMethodMap) {
|
|
103
|
-
|
|
104
|
-
|
|
107
|
+
if (!auth || !eventsConfig?.enabled) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
const plugins = auth.options?.plugins || [];
|
|
112
|
+
const emailOtpPlugin = plugins.find((p) => p?.id === "email-otp");
|
|
113
|
+
if (!emailOtpPlugin) {
|
|
114
|
+
return;
|
|
105
115
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (!emailOtpPlugin) {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
// Check if already wrapped to avoid double wrapping
|
|
113
|
-
if (emailOtpPlugin.__studio_callbacks_wrapped) {
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
// Wrap the sendVerificationOTP callback
|
|
117
|
-
const existingSendVerificationOTP = emailOtpPlugin.options?.sendVerificationOTP;
|
|
118
|
-
if (existingSendVerificationOTP) {
|
|
119
|
-
const wrappedCallback = wrapEmailOTPPluginCallbacks(eventsConfig, existingSendVerificationOTP, passwordResetMethodMap);
|
|
120
|
-
if (wrappedCallback) {
|
|
121
|
-
if (!emailOtpPlugin.options) {
|
|
122
|
-
emailOtpPlugin.options = {};
|
|
123
|
-
}
|
|
124
|
-
emailOtpPlugin.options.sendVerificationOTP = wrappedCallback;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
// Mark as wrapped to prevent double wrapping
|
|
128
|
-
emailOtpPlugin.__studio_callbacks_wrapped = true;
|
|
116
|
+
// Check if already wrapped to avoid double wrapping
|
|
117
|
+
if (emailOtpPlugin.__studio_callbacks_wrapped) {
|
|
118
|
+
return;
|
|
129
119
|
}
|
|
130
|
-
|
|
131
|
-
|
|
120
|
+
// Wrap the sendVerificationOTP callback
|
|
121
|
+
const existingSendVerificationOTP = emailOtpPlugin.options?.sendVerificationOTP;
|
|
122
|
+
if (existingSendVerificationOTP) {
|
|
123
|
+
const wrappedCallback = wrapEmailOTPPluginCallbacks(
|
|
124
|
+
eventsConfig,
|
|
125
|
+
existingSendVerificationOTP,
|
|
126
|
+
passwordResetMethodMap,
|
|
127
|
+
);
|
|
128
|
+
if (wrappedCallback) {
|
|
129
|
+
if (!emailOtpPlugin.options) {
|
|
130
|
+
emailOtpPlugin.options = {};
|
|
131
|
+
}
|
|
132
|
+
emailOtpPlugin.options.sendVerificationOTP = wrappedCallback;
|
|
133
|
+
}
|
|
132
134
|
}
|
|
135
|
+
// Mark as wrapped to prevent double wrapping
|
|
136
|
+
emailOtpPlugin.__studio_callbacks_wrapped = true;
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.error("[Email OTP Callbacks] Failed to wrap callbacks:", error);
|
|
139
|
+
}
|
|
133
140
|
}
|
|
134
|
-
//# sourceMappingURL=email-otp-hooks-injector.js.map
|
|
141
|
+
//# sourceMappingURL=email-otp-hooks-injector.js.map
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import type { AuthEventType, EventIngestionProvider } from
|
|
2
|
-
import type { StudioConfig } from
|
|
1
|
+
import type { AuthEventType, EventIngestionProvider } from "../types/events.js";
|
|
2
|
+
import type { StudioConfig } from "../types/handler.js";
|
|
3
3
|
/**
|
|
4
4
|
* Initialize event ingestion
|
|
5
5
|
*/
|
|
6
|
-
export declare function initializeEventIngestion(eventsConfig: StudioConfig[
|
|
6
|
+
export declare function initializeEventIngestion(eventsConfig: StudioConfig["events"]): void;
|
|
7
7
|
/**
|
|
8
8
|
* Emit an event
|
|
9
9
|
*/
|
|
10
10
|
export declare function emitEvent(type: AuthEventType, data: {
|
|
11
|
-
status:
|
|
11
|
+
status: "success" | "failed";
|
|
12
12
|
userId?: string;
|
|
13
13
|
sessionId?: string;
|
|
14
14
|
organizationId?: string;
|
|
@@ -17,7 +17,7 @@ export declare function emitEvent(type: AuthEventType, data: {
|
|
|
17
17
|
headers: Record<string, string>;
|
|
18
18
|
ip?: string;
|
|
19
19
|
};
|
|
20
|
-
}, eventsConfig?: StudioConfig[
|
|
20
|
+
}, eventsConfig?: StudioConfig["events"]): Promise<void>;
|
|
21
21
|
export declare function shutdownEventIngestion(): Promise<void>;
|
|
22
22
|
/**
|
|
23
23
|
* Health check
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-ingestion.d.ts","sourceRoot":"","sources":["../../src/utils/event-ingestion.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,aAAa,EACb,sBAAsB,EAGvB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AASxD;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,YAAY,CAAC,QAAQ,CAAC,GAAG,IAAI,CAiEnF;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE;IACJ,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5D,EACD,YAAY,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC,GACpC,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"event-ingestion.d.ts","sourceRoot":"","sources":["../../src/utils/event-ingestion.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,aAAa,EACb,sBAAsB,EAGvB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AASxD;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,YAAY,CAAC,QAAQ,CAAC,GAAG,IAAI,CAiEnF;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE;IACJ,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5D,EACD,YAAY,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC,GACpC,OAAO,CAAC,IAAI,CAAC,CAuFf;AAiCD,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAmB5D;AAED;;GAEG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,OAAO,CAAC,CAUlE;AAED;;GAEG;AACH,wBAAgB,2BAA2B,IAAI,OAAO,CAErD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,sBAAsB,GAAG,IAAI,CAEzE"}
|