@digilogiclabs/saas-factory-auth 0.2.0 → 0.3.2
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/dist/components/native/index.js +603 -0
- package/dist/components/native/index.js.map +1 -0
- package/dist/components/native/index.mjs +595 -0
- package/dist/components/native/index.mjs.map +1 -0
- package/dist/components/web/index.d.mts +39 -0
- package/dist/components/web/index.d.ts +39 -0
- package/dist/components/web/index.js +417 -0
- package/dist/components/web/index.js.map +1 -0
- package/dist/components/web/index.mjs +411 -0
- package/dist/components/web/index.mjs.map +1 -0
- package/dist/index.d.mts +582 -56
- package/dist/index.d.ts +582 -56
- package/dist/index.js +1833 -91
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1809 -89
- package/dist/index.mjs.map +1 -1
- package/package.json +139 -93
- package/src/components/native/index.d.ts +29 -0
- package/README.md +0 -148
package/dist/index.mjs
CHANGED
|
@@ -1,141 +1,1861 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createClient } from '@supabase/supabase-js';
|
|
2
|
+
import { initializeApp } from 'firebase/app';
|
|
3
|
+
import { getAuth, signInWithEmailAndPassword, createUserWithEmailAndPassword, signInWithPopup, sendSignInLinkToEmail, signOut, sendPasswordResetEmail, onAuthStateChanged, OAuthProvider, TwitterAuthProvider, FacebookAuthProvider, GithubAuthProvider, GoogleAuthProvider } from 'firebase/auth';
|
|
4
|
+
import { createContext, useState, useEffect, useContext } from 'react';
|
|
2
5
|
import { create } from 'zustand';
|
|
3
|
-
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs';
|
|
4
6
|
import { jsx } from 'react/jsx-runtime';
|
|
7
|
+
import { createClientComponentClient, createMiddlewareClient, createServerComponentClient } from '@supabase/auth-helpers-nextjs';
|
|
8
|
+
import { useSearchParams } from 'next/navigation';
|
|
9
|
+
import { NextResponse } from 'next/server';
|
|
10
|
+
import { cookies } from 'next/headers';
|
|
5
11
|
|
|
6
|
-
var
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
var __defProp = Object.defineProperty;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
17
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
18
|
+
var __spreadValues = (a, b) => {
|
|
19
|
+
for (var prop in b || (b = {}))
|
|
20
|
+
if (__hasOwnProp.call(b, prop))
|
|
21
|
+
__defNormalProp(a, prop, b[prop]);
|
|
22
|
+
if (__getOwnPropSymbols)
|
|
23
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
24
|
+
if (__propIsEnum.call(b, prop))
|
|
25
|
+
__defNormalProp(a, prop, b[prop]);
|
|
26
|
+
}
|
|
27
|
+
return a;
|
|
28
|
+
};
|
|
29
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
30
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
31
|
+
}) : x)(function(x) {
|
|
32
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
33
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
34
|
+
});
|
|
35
|
+
var __esm = (fn, res) => function __init() {
|
|
36
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
37
|
+
};
|
|
38
|
+
var __export = (target, all) => {
|
|
39
|
+
for (var name in all)
|
|
40
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// src/config/storage.ts
|
|
44
|
+
var storage_exports = {};
|
|
45
|
+
__export(storage_exports, {
|
|
46
|
+
NativeAuthStorage: () => NativeAuthStorage,
|
|
47
|
+
WebAuthStorage: () => WebAuthStorage,
|
|
48
|
+
createAuthStorage: () => createAuthStorage
|
|
49
|
+
});
|
|
50
|
+
var WebAuthStorage, NativeAuthStorage, createAuthStorage;
|
|
51
|
+
var init_storage = __esm({
|
|
52
|
+
"src/config/storage.ts"() {
|
|
53
|
+
WebAuthStorage = class {
|
|
54
|
+
async getItem(key) {
|
|
55
|
+
if (typeof window === "undefined") return null;
|
|
56
|
+
return localStorage.getItem(key);
|
|
57
|
+
}
|
|
58
|
+
async setItem(key, value) {
|
|
59
|
+
if (typeof window === "undefined") return;
|
|
60
|
+
localStorage.setItem(key, value);
|
|
61
|
+
}
|
|
62
|
+
async removeItem(key) {
|
|
63
|
+
if (typeof window === "undefined") return;
|
|
64
|
+
localStorage.removeItem(key);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
NativeAuthStorage = class {
|
|
68
|
+
constructor() {
|
|
69
|
+
try {
|
|
70
|
+
this.AsyncStorage = __require("@react-native-async-storage/async-storage").default;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
throw new Error("AsyncStorage is required for React Native. Install @react-native-async-storage/async-storage");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async getItem(key) {
|
|
76
|
+
return await this.AsyncStorage.getItem(key);
|
|
77
|
+
}
|
|
78
|
+
async setItem(key, value) {
|
|
79
|
+
await this.AsyncStorage.setItem(key, value);
|
|
80
|
+
}
|
|
81
|
+
async removeItem(key) {
|
|
82
|
+
await this.AsyncStorage.removeItem(key);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
createAuthStorage = () => {
|
|
86
|
+
const isReactNative2 = typeof navigator !== "undefined" && navigator.product === "ReactNative";
|
|
87
|
+
if (isReactNative2) {
|
|
88
|
+
return new NativeAuthStorage();
|
|
89
|
+
} else {
|
|
90
|
+
return new WebAuthStorage();
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// src/core/IAuthProvider.ts
|
|
97
|
+
var AuthErrorType = /* @__PURE__ */ ((AuthErrorType2) => {
|
|
98
|
+
AuthErrorType2["INVALID_CREDENTIALS"] = "INVALID_CREDENTIALS";
|
|
99
|
+
AuthErrorType2["USER_NOT_FOUND"] = "USER_NOT_FOUND";
|
|
100
|
+
AuthErrorType2["EMAIL_ALREADY_EXISTS"] = "EMAIL_ALREADY_EXISTS";
|
|
101
|
+
AuthErrorType2["WEAK_PASSWORD"] = "WEAK_PASSWORD";
|
|
102
|
+
AuthErrorType2["NETWORK_ERROR"] = "NETWORK_ERROR";
|
|
103
|
+
AuthErrorType2["PROVIDER_ERROR"] = "PROVIDER_ERROR";
|
|
104
|
+
AuthErrorType2["CONFIGURATION_ERROR"] = "CONFIGURATION_ERROR";
|
|
105
|
+
AuthErrorType2["VALIDATION_ERROR"] = "VALIDATION_ERROR";
|
|
106
|
+
return AuthErrorType2;
|
|
107
|
+
})(AuthErrorType || {});
|
|
108
|
+
var AuthError = class _AuthError extends Error {
|
|
109
|
+
constructor(type, message, originalError, context) {
|
|
110
|
+
super(message);
|
|
111
|
+
this.type = type;
|
|
112
|
+
this.originalError = originalError;
|
|
113
|
+
this.context = context;
|
|
114
|
+
this.name = "AuthError";
|
|
115
|
+
this.timestamp = /* @__PURE__ */ new Date();
|
|
116
|
+
this.code = type;
|
|
117
|
+
Object.setPrototypeOf(this, _AuthError.prototype);
|
|
118
|
+
if (Error.captureStackTrace) {
|
|
119
|
+
Error.captureStackTrace(this, _AuthError);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Convert error to JSON for logging/debugging
|
|
124
|
+
*/
|
|
125
|
+
toJSON() {
|
|
126
|
+
return {
|
|
127
|
+
name: this.name,
|
|
128
|
+
type: this.type,
|
|
129
|
+
code: this.code,
|
|
130
|
+
message: this.message,
|
|
131
|
+
timestamp: this.timestamp.toISOString(),
|
|
132
|
+
context: this.context,
|
|
133
|
+
originalError: this.originalError ? {
|
|
134
|
+
name: this.originalError.name,
|
|
135
|
+
message: this.originalError.message,
|
|
136
|
+
code: this.originalError.code
|
|
137
|
+
} : undefined
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Check if error is of a specific type
|
|
142
|
+
*/
|
|
143
|
+
isType(type) {
|
|
144
|
+
return this.type === type;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Check if error is retryable
|
|
148
|
+
*/
|
|
149
|
+
isRetryable() {
|
|
150
|
+
return [
|
|
151
|
+
"NETWORK_ERROR" /* NETWORK_ERROR */,
|
|
152
|
+
"PROVIDER_ERROR" /* PROVIDER_ERROR */
|
|
153
|
+
].includes(this.type);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
var AuthEvent = /* @__PURE__ */ ((AuthEvent2) => {
|
|
157
|
+
AuthEvent2["SIGNED_IN"] = "SIGNED_IN";
|
|
158
|
+
AuthEvent2["SIGNED_OUT"] = "SIGNED_OUT";
|
|
159
|
+
AuthEvent2["TOKEN_REFRESHED"] = "TOKEN_REFRESHED";
|
|
160
|
+
AuthEvent2["USER_UPDATED"] = "USER_UPDATED";
|
|
161
|
+
return AuthEvent2;
|
|
162
|
+
})(AuthEvent || {});
|
|
163
|
+
|
|
164
|
+
// src/config/env.ts
|
|
165
|
+
var isNextJS = typeof window !== "undefined" && typeof process !== "undefined";
|
|
166
|
+
var isExpo = typeof global !== "undefined" && global.__expo;
|
|
167
|
+
var isReactNative = typeof navigator !== "undefined" && navigator.product === "ReactNative";
|
|
168
|
+
var getAuthConfig = () => {
|
|
169
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
170
|
+
let config = {};
|
|
171
|
+
if (isNextJS) {
|
|
172
|
+
config = {
|
|
173
|
+
supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
|
174
|
+
supabaseAnonKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
|
175
|
+
firebaseApiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
|
|
176
|
+
firebaseAuthDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
|
|
177
|
+
firebaseProjectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
|
|
178
|
+
redirectUrl: process.env.NEXT_PUBLIC_AUTH_REDIRECT_URL
|
|
179
|
+
};
|
|
180
|
+
} else if (isExpo) {
|
|
181
|
+
try {
|
|
182
|
+
const Constants = __require("expo-constants").default;
|
|
183
|
+
config = {
|
|
184
|
+
supabaseUrl: (_b = (_a = Constants.expoConfig) == null ? void 0 : _a.extra) == null ? void 0 : _b.supabaseUrl,
|
|
185
|
+
supabaseAnonKey: (_d = (_c = Constants.expoConfig) == null ? void 0 : _c.extra) == null ? void 0 : _d.supabaseAnonKey,
|
|
186
|
+
firebaseApiKey: (_f = (_e = Constants.expoConfig) == null ? void 0 : _e.extra) == null ? void 0 : _f.firebaseApiKey,
|
|
187
|
+
firebaseAuthDomain: (_h = (_g = Constants.expoConfig) == null ? void 0 : _g.extra) == null ? void 0 : _h.firebaseAuthDomain,
|
|
188
|
+
firebaseProjectId: (_j = (_i = Constants.expoConfig) == null ? void 0 : _i.extra) == null ? void 0 : _j.firebaseProjectId,
|
|
189
|
+
redirectUrl: (_l = (_k = Constants.expoConfig) == null ? void 0 : _k.extra) == null ? void 0 : _l.authRedirectUrl
|
|
190
|
+
};
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.warn("Expo Constants not available, using empty config");
|
|
193
|
+
}
|
|
194
|
+
} else if (isReactNative) {
|
|
195
|
+
try {
|
|
196
|
+
const Config = __require("react-native-config").default;
|
|
197
|
+
config = {
|
|
198
|
+
supabaseUrl: Config.SUPABASE_URL,
|
|
199
|
+
supabaseAnonKey: Config.SUPABASE_ANON_KEY,
|
|
200
|
+
firebaseApiKey: Config.FIREBASE_API_KEY,
|
|
201
|
+
firebaseAuthDomain: Config.FIREBASE_AUTH_DOMAIN,
|
|
202
|
+
firebaseProjectId: Config.FIREBASE_PROJECT_ID,
|
|
203
|
+
redirectUrl: Config.AUTH_REDIRECT_URL
|
|
204
|
+
};
|
|
205
|
+
} catch (error) {
|
|
206
|
+
console.warn("react-native-config not available, using empty config");
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return config;
|
|
210
|
+
};
|
|
211
|
+
var validateConfig = (config, provider) => {
|
|
212
|
+
if (provider === "supabase") {
|
|
213
|
+
if (!config.supabaseUrl || !config.supabaseAnonKey) {
|
|
214
|
+
throw new Error(`Missing required Supabase configuration. Required: SUPABASE_URL, SUPABASE_ANON_KEY`);
|
|
215
|
+
}
|
|
216
|
+
} else if (provider === "firebase") {
|
|
217
|
+
if (!config.firebaseApiKey || !config.firebaseAuthDomain || !config.firebaseProjectId) {
|
|
218
|
+
throw new Error(`Missing required Firebase configuration. Required: FIREBASE_API_KEY, FIREBASE_AUTH_DOMAIN, FIREBASE_PROJECT_ID`);
|
|
219
|
+
}
|
|
9
220
|
}
|
|
10
|
-
return createClientComponentClient();
|
|
11
221
|
};
|
|
12
|
-
var supabase = createClient();
|
|
13
222
|
|
|
14
|
-
// src/
|
|
15
|
-
var
|
|
223
|
+
// src/core/SupabaseAuthProvider.ts
|
|
224
|
+
var mapSupabaseUserToCommonUser = (supabaseUser) => {
|
|
225
|
+
var _a, _b, _c;
|
|
226
|
+
if (!supabaseUser) return null;
|
|
227
|
+
return {
|
|
228
|
+
id: supabaseUser.id,
|
|
229
|
+
email: supabaseUser.email,
|
|
230
|
+
displayName: ((_a = supabaseUser.user_metadata) == null ? undefined : _a.full_name) || ((_b = supabaseUser.user_metadata) == null ? undefined : _b.name) || null,
|
|
231
|
+
photoURL: ((_c = supabaseUser.user_metadata) == null ? undefined : _c.avatar_url) || null,
|
|
232
|
+
metadata: supabaseUser.user_metadata || {}
|
|
233
|
+
};
|
|
234
|
+
};
|
|
235
|
+
var mapSupabaseError = (error) => {
|
|
236
|
+
const message = error.message || "Unknown error occurred";
|
|
237
|
+
if (message.includes("Invalid login credentials")) {
|
|
238
|
+
return new AuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, message, error);
|
|
239
|
+
}
|
|
240
|
+
if (message.includes("User not found")) {
|
|
241
|
+
return new AuthError("USER_NOT_FOUND" /* USER_NOT_FOUND */, message, error);
|
|
242
|
+
}
|
|
243
|
+
if (message.includes("User already registered")) {
|
|
244
|
+
return new AuthError("EMAIL_ALREADY_EXISTS" /* EMAIL_ALREADY_EXISTS */, message, error);
|
|
245
|
+
}
|
|
246
|
+
if (message.includes("Password should be")) {
|
|
247
|
+
return new AuthError("WEAK_PASSWORD" /* WEAK_PASSWORD */, message, error);
|
|
248
|
+
}
|
|
249
|
+
if (message.includes("network") || message.includes("fetch")) {
|
|
250
|
+
return new AuthError("NETWORK_ERROR" /* NETWORK_ERROR */, message, error);
|
|
251
|
+
}
|
|
252
|
+
return new AuthError("PROVIDER_ERROR" /* PROVIDER_ERROR */, message, error);
|
|
253
|
+
};
|
|
254
|
+
var validateEmail = (email) => {
|
|
255
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
256
|
+
if (!emailRegex.test(email)) {
|
|
257
|
+
throw new AuthError("VALIDATION_ERROR" /* VALIDATION_ERROR */, "Invalid email format");
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
var SupabaseAuthProvider = class {
|
|
261
|
+
constructor(storage) {
|
|
262
|
+
this.storage = storage;
|
|
263
|
+
const config = getAuthConfig();
|
|
264
|
+
validateConfig(config, "supabase");
|
|
265
|
+
this.client = createClient(config.supabaseUrl, config.supabaseAnonKey, {
|
|
266
|
+
auth: {
|
|
267
|
+
storage: {
|
|
268
|
+
getItem: (key) => this.storage.getItem(key),
|
|
269
|
+
setItem: (key, value) => this.storage.setItem(key, value),
|
|
270
|
+
removeItem: (key) => this.storage.removeItem(key)
|
|
271
|
+
},
|
|
272
|
+
autoRefreshToken: true,
|
|
273
|
+
persistSession: true
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Validates Supabase configuration
|
|
279
|
+
*/
|
|
280
|
+
async validateConfiguration() {
|
|
281
|
+
try {
|
|
282
|
+
const config = getAuthConfig();
|
|
283
|
+
validateConfig(config, "supabase");
|
|
284
|
+
} catch (error) {
|
|
285
|
+
throw new AuthError(
|
|
286
|
+
"CONFIGURATION_ERROR" /* CONFIGURATION_ERROR */,
|
|
287
|
+
error instanceof Error ? error.message : "Invalid Supabase configuration"
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
async signIn(email, password) {
|
|
292
|
+
try {
|
|
293
|
+
validateEmail(email);
|
|
294
|
+
if (!password) {
|
|
295
|
+
throw new AuthError(
|
|
296
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
297
|
+
"Password is required for email sign-in with Supabase"
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
const { data, error } = await this.client.auth.signInWithPassword({ email, password });
|
|
301
|
+
if (error) {
|
|
302
|
+
throw mapSupabaseError(error);
|
|
303
|
+
}
|
|
304
|
+
return mapSupabaseUserToCommonUser(data.user);
|
|
305
|
+
} catch (error) {
|
|
306
|
+
if (error instanceof AuthError) {
|
|
307
|
+
throw error;
|
|
308
|
+
}
|
|
309
|
+
throw new AuthError("PROVIDER_ERROR" /* PROVIDER_ERROR */, "Sign in failed", error);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
async signUp(email, password) {
|
|
313
|
+
try {
|
|
314
|
+
validateEmail(email);
|
|
315
|
+
if (!password) {
|
|
316
|
+
throw new AuthError(
|
|
317
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
318
|
+
"Password is required for email sign-up with Supabase"
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
const { data, error } = await this.client.auth.signUp({ email, password });
|
|
322
|
+
if (error) {
|
|
323
|
+
throw mapSupabaseError(error);
|
|
324
|
+
}
|
|
325
|
+
return mapSupabaseUserToCommonUser(data.user);
|
|
326
|
+
} catch (error) {
|
|
327
|
+
if (error instanceof AuthError) {
|
|
328
|
+
throw error;
|
|
329
|
+
}
|
|
330
|
+
throw new AuthError("PROVIDER_ERROR" /* PROVIDER_ERROR */, "Sign up failed", error);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
async signInWithOAuth(provider, redirectTo) {
|
|
334
|
+
try {
|
|
335
|
+
const { error } = await this.client.auth.signInWithOAuth({
|
|
336
|
+
provider,
|
|
337
|
+
options: { redirectTo }
|
|
338
|
+
});
|
|
339
|
+
if (error) {
|
|
340
|
+
throw mapSupabaseError(error);
|
|
341
|
+
}
|
|
342
|
+
} catch (error) {
|
|
343
|
+
if (error instanceof AuthError) {
|
|
344
|
+
throw error;
|
|
345
|
+
}
|
|
346
|
+
throw new AuthError("PROVIDER_ERROR" /* PROVIDER_ERROR */, "OAuth sign in failed", error);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
async signInWithMagicLink(email, redirectTo) {
|
|
350
|
+
try {
|
|
351
|
+
validateEmail(email);
|
|
352
|
+
const { error } = await this.client.auth.signInWithOtp({
|
|
353
|
+
email,
|
|
354
|
+
options: { emailRedirectTo: redirectTo }
|
|
355
|
+
});
|
|
356
|
+
if (error) {
|
|
357
|
+
throw mapSupabaseError(error);
|
|
358
|
+
}
|
|
359
|
+
} catch (error) {
|
|
360
|
+
if (error instanceof AuthError) {
|
|
361
|
+
throw error;
|
|
362
|
+
}
|
|
363
|
+
throw new AuthError("PROVIDER_ERROR" /* PROVIDER_ERROR */, "Magic link sign in failed", error);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
async signOut() {
|
|
367
|
+
try {
|
|
368
|
+
const { error } = await this.client.auth.signOut();
|
|
369
|
+
if (error) {
|
|
370
|
+
throw mapSupabaseError(error);
|
|
371
|
+
}
|
|
372
|
+
} catch (error) {
|
|
373
|
+
if (error instanceof AuthError) {
|
|
374
|
+
throw error;
|
|
375
|
+
}
|
|
376
|
+
throw new AuthError("PROVIDER_ERROR" /* PROVIDER_ERROR */, "Sign out failed", error);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
async resetPassword(email) {
|
|
380
|
+
try {
|
|
381
|
+
validateEmail(email);
|
|
382
|
+
const { error } = await this.client.auth.resetPasswordForEmail(email);
|
|
383
|
+
if (error) {
|
|
384
|
+
throw mapSupabaseError(error);
|
|
385
|
+
}
|
|
386
|
+
} catch (error) {
|
|
387
|
+
if (error instanceof AuthError) {
|
|
388
|
+
throw error;
|
|
389
|
+
}
|
|
390
|
+
throw new AuthError("PROVIDER_ERROR" /* PROVIDER_ERROR */, "Password reset failed", error);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
async getUser() {
|
|
394
|
+
try {
|
|
395
|
+
const { data: { user }, error } = await this.client.auth.getUser();
|
|
396
|
+
if (error) {
|
|
397
|
+
throw mapSupabaseError(error);
|
|
398
|
+
}
|
|
399
|
+
return mapSupabaseUserToCommonUser(user);
|
|
400
|
+
} catch (error) {
|
|
401
|
+
if (error instanceof AuthError) {
|
|
402
|
+
throw error;
|
|
403
|
+
}
|
|
404
|
+
throw new AuthError("PROVIDER_ERROR" /* PROVIDER_ERROR */, "Get user failed", error);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
onAuthStateChange(callback) {
|
|
408
|
+
const { data: { subscription } } = this.client.auth.onAuthStateChange((event, session) => {
|
|
409
|
+
const commonUser = mapSupabaseUserToCommonUser((session == null ? undefined : session.user) || null);
|
|
410
|
+
let authEvent;
|
|
411
|
+
switch (event) {
|
|
412
|
+
case "SIGNED_IN":
|
|
413
|
+
authEvent = "SIGNED_IN" /* SIGNED_IN */;
|
|
414
|
+
break;
|
|
415
|
+
case "SIGNED_OUT":
|
|
416
|
+
authEvent = "SIGNED_OUT" /* SIGNED_OUT */;
|
|
417
|
+
break;
|
|
418
|
+
case "TOKEN_REFRESHED":
|
|
419
|
+
authEvent = "TOKEN_REFRESHED" /* TOKEN_REFRESHED */;
|
|
420
|
+
break;
|
|
421
|
+
case "USER_UPDATED":
|
|
422
|
+
authEvent = "USER_UPDATED" /* USER_UPDATED */;
|
|
423
|
+
break;
|
|
424
|
+
default:
|
|
425
|
+
authEvent = "USER_UPDATED" /* USER_UPDATED */;
|
|
426
|
+
}
|
|
427
|
+
const authSession = commonUser ? {
|
|
428
|
+
user: commonUser,
|
|
429
|
+
expiresAt: (session == null ? undefined : session.expires_at) ? session.expires_at * 1e3 : undefined,
|
|
430
|
+
accessToken: session == null ? undefined : session.access_token
|
|
431
|
+
} : null;
|
|
432
|
+
callback(authEvent, authSession);
|
|
433
|
+
});
|
|
434
|
+
return { data: { subscription } };
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
var mapFirebaseUserToCommonUser = (firebaseUser) => {
|
|
438
|
+
var _a, _b;
|
|
439
|
+
if (!firebaseUser) return null;
|
|
440
|
+
return {
|
|
441
|
+
id: firebaseUser.uid,
|
|
442
|
+
email: firebaseUser.email || undefined,
|
|
443
|
+
displayName: firebaseUser.displayName,
|
|
444
|
+
photoURL: firebaseUser.photoURL,
|
|
445
|
+
metadata: {
|
|
446
|
+
phoneNumber: firebaseUser.phoneNumber,
|
|
447
|
+
emailVerified: firebaseUser.emailVerified,
|
|
448
|
+
isAnonymous: firebaseUser.isAnonymous,
|
|
449
|
+
tenantId: firebaseUser.tenantId,
|
|
450
|
+
providerData: firebaseUser.providerData,
|
|
451
|
+
creationTime: (_a = firebaseUser.metadata) == null ? undefined : _a.creationTime,
|
|
452
|
+
lastSignInTime: (_b = firebaseUser.metadata) == null ? undefined : _b.lastSignInTime
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
};
|
|
456
|
+
var mapFirebaseError = (error) => {
|
|
457
|
+
const code = error.code || "";
|
|
458
|
+
const message = error.message || "Unknown error occurred";
|
|
459
|
+
switch (code) {
|
|
460
|
+
case "auth/invalid-email":
|
|
461
|
+
case "auth/user-disabled":
|
|
462
|
+
case "auth/user-not-found":
|
|
463
|
+
case "auth/wrong-password":
|
|
464
|
+
case "auth/invalid-credential":
|
|
465
|
+
return new AuthError("INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */, message, error);
|
|
466
|
+
case "auth/email-already-in-use":
|
|
467
|
+
return new AuthError("EMAIL_ALREADY_EXISTS" /* EMAIL_ALREADY_EXISTS */, message, error);
|
|
468
|
+
case "auth/weak-password":
|
|
469
|
+
return new AuthError("WEAK_PASSWORD" /* WEAK_PASSWORD */, message, error);
|
|
470
|
+
case "auth/network-request-failed":
|
|
471
|
+
case "auth/timeout":
|
|
472
|
+
return new AuthError("NETWORK_ERROR" /* NETWORK_ERROR */, message, error);
|
|
473
|
+
case "auth/configuration-not-found":
|
|
474
|
+
case "auth/invalid-api-key":
|
|
475
|
+
return new AuthError("CONFIGURATION_ERROR" /* CONFIGURATION_ERROR */, message, error);
|
|
476
|
+
default:
|
|
477
|
+
return new AuthError("PROVIDER_ERROR" /* PROVIDER_ERROR */, message, error);
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
var validateEmail2 = (email) => {
|
|
481
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
482
|
+
if (!emailRegex.test(email)) {
|
|
483
|
+
throw new AuthError("VALIDATION_ERROR" /* VALIDATION_ERROR */, "Invalid email format");
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
var getOAuthProvider = (provider) => {
|
|
487
|
+
switch (provider) {
|
|
488
|
+
case "google":
|
|
489
|
+
return new GoogleAuthProvider();
|
|
490
|
+
case "github":
|
|
491
|
+
return new GithubAuthProvider();
|
|
492
|
+
case "facebook":
|
|
493
|
+
return new FacebookAuthProvider();
|
|
494
|
+
case "twitter":
|
|
495
|
+
return new TwitterAuthProvider();
|
|
496
|
+
case "apple":
|
|
497
|
+
const appleProvider = new OAuthProvider("apple.com");
|
|
498
|
+
return appleProvider;
|
|
499
|
+
case "discord":
|
|
500
|
+
const discordProvider = new OAuthProvider("discord.com");
|
|
501
|
+
return discordProvider;
|
|
502
|
+
default:
|
|
503
|
+
throw new AuthError(
|
|
504
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
505
|
+
`Unsupported OAuth provider for Firebase: ${provider}`
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
var FirebaseAuthProvider = class {
|
|
510
|
+
constructor(storage) {
|
|
511
|
+
this.storage = storage;
|
|
512
|
+
const config = getAuthConfig();
|
|
513
|
+
validateConfig(config, "firebase");
|
|
514
|
+
this.app = initializeApp({
|
|
515
|
+
apiKey: config.firebaseApiKey,
|
|
516
|
+
authDomain: config.firebaseAuthDomain,
|
|
517
|
+
projectId: config.firebaseProjectId
|
|
518
|
+
});
|
|
519
|
+
this.auth = getAuth(this.app);
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Validates Firebase configuration
|
|
523
|
+
*/
|
|
524
|
+
async validateConfiguration() {
|
|
525
|
+
try {
|
|
526
|
+
const config = getAuthConfig();
|
|
527
|
+
validateConfig(config, "firebase");
|
|
528
|
+
} catch (error) {
|
|
529
|
+
throw new AuthError(
|
|
530
|
+
"CONFIGURATION_ERROR" /* CONFIGURATION_ERROR */,
|
|
531
|
+
error instanceof Error ? error.message : "Invalid Firebase configuration"
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
async signIn(email, password) {
|
|
536
|
+
try {
|
|
537
|
+
validateEmail2(email);
|
|
538
|
+
if (!password) {
|
|
539
|
+
throw new AuthError(
|
|
540
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
541
|
+
"Password is required for email sign-in with Firebase"
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
const userCredential = await signInWithEmailAndPassword(this.auth, email, password);
|
|
545
|
+
return mapFirebaseUserToCommonUser(userCredential.user);
|
|
546
|
+
} catch (error) {
|
|
547
|
+
if (error instanceof AuthError) {
|
|
548
|
+
throw error;
|
|
549
|
+
}
|
|
550
|
+
throw mapFirebaseError(error);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
async signUp(email, password) {
|
|
554
|
+
try {
|
|
555
|
+
validateEmail2(email);
|
|
556
|
+
if (!password) {
|
|
557
|
+
throw new AuthError(
|
|
558
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
559
|
+
"Password is required for email sign-up with Firebase"
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
const userCredential = await createUserWithEmailAndPassword(this.auth, email, password);
|
|
563
|
+
return mapFirebaseUserToCommonUser(userCredential.user);
|
|
564
|
+
} catch (error) {
|
|
565
|
+
if (error instanceof AuthError) {
|
|
566
|
+
throw error;
|
|
567
|
+
}
|
|
568
|
+
throw mapFirebaseError(error);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
async signInWithOAuth(provider, redirectTo) {
|
|
572
|
+
try {
|
|
573
|
+
const authProvider = getOAuthProvider(provider);
|
|
574
|
+
if (redirectTo) {
|
|
575
|
+
console.warn(
|
|
576
|
+
"redirectTo is not directly supported for Firebase signInWithPopup. Consider using signInWithRedirect or handling redirects manually."
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
await signInWithPopup(this.auth, authProvider);
|
|
580
|
+
} catch (error) {
|
|
581
|
+
if (error instanceof AuthError) {
|
|
582
|
+
throw error;
|
|
583
|
+
}
|
|
584
|
+
throw mapFirebaseError(error);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
async signInWithMagicLink(email, redirectTo) {
|
|
588
|
+
try {
|
|
589
|
+
validateEmail2(email);
|
|
590
|
+
if (!redirectTo) {
|
|
591
|
+
throw new AuthError(
|
|
592
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
593
|
+
"redirectTo is required for Firebase magic link sign-in"
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
await sendSignInLinkToEmail(this.auth, email, {
|
|
597
|
+
url: redirectTo,
|
|
598
|
+
handleCodeInApp: true
|
|
599
|
+
});
|
|
600
|
+
} catch (error) {
|
|
601
|
+
if (error instanceof AuthError) {
|
|
602
|
+
throw error;
|
|
603
|
+
}
|
|
604
|
+
throw mapFirebaseError(error);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
async signOut() {
|
|
608
|
+
try {
|
|
609
|
+
await signOut(this.auth);
|
|
610
|
+
} catch (error) {
|
|
611
|
+
if (error instanceof AuthError) {
|
|
612
|
+
throw error;
|
|
613
|
+
}
|
|
614
|
+
throw mapFirebaseError(error);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
async resetPassword(email) {
|
|
618
|
+
try {
|
|
619
|
+
validateEmail2(email);
|
|
620
|
+
await sendPasswordResetEmail(this.auth, email);
|
|
621
|
+
} catch (error) {
|
|
622
|
+
if (error instanceof AuthError) {
|
|
623
|
+
throw error;
|
|
624
|
+
}
|
|
625
|
+
throw mapFirebaseError(error);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
async getUser() {
|
|
629
|
+
return mapFirebaseUserToCommonUser(this.auth.currentUser);
|
|
630
|
+
}
|
|
631
|
+
onAuthStateChange(callback) {
|
|
632
|
+
const unsubscribe = onAuthStateChanged(this.auth, (user) => {
|
|
633
|
+
const commonUser = mapFirebaseUserToCommonUser(user);
|
|
634
|
+
let authEvent;
|
|
635
|
+
if (user) {
|
|
636
|
+
authEvent = "SIGNED_IN" /* SIGNED_IN */;
|
|
637
|
+
} else {
|
|
638
|
+
authEvent = "SIGNED_OUT" /* SIGNED_OUT */;
|
|
639
|
+
}
|
|
640
|
+
const authSession = commonUser ? {
|
|
641
|
+
user: commonUser,
|
|
642
|
+
// Firebase doesn't provide explicit expiration time in the same way as Supabase
|
|
643
|
+
// You might need to get this from the ID token if needed
|
|
644
|
+
expiresAt: undefined,
|
|
645
|
+
// Explicitly undefined if not available
|
|
646
|
+
accessToken: undefined
|
|
647
|
+
// Explicitly undefined if not available
|
|
648
|
+
} : null;
|
|
649
|
+
callback(authEvent, authSession);
|
|
650
|
+
});
|
|
651
|
+
return { data: { subscription: { unsubscribe } } };
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
// src/core/AuthProviderFactory.ts
|
|
656
|
+
init_storage();
|
|
657
|
+
var AuthProviderFactory = class {
|
|
658
|
+
/**
|
|
659
|
+
* Gets provider based on environment variables (auto-detection)
|
|
660
|
+
* @param config Optional configuration overrides
|
|
661
|
+
* @returns Authentication provider instance
|
|
662
|
+
*/
|
|
663
|
+
static async getProviderFromEnvironment(config) {
|
|
664
|
+
const detectedType = this.detectProviderFromEnvironment();
|
|
665
|
+
return this.getProvider(__spreadValues({
|
|
666
|
+
type: detectedType,
|
|
667
|
+
validateConfig: true,
|
|
668
|
+
useSingleton: true
|
|
669
|
+
}, config));
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Gets provider instance with configuration
|
|
673
|
+
* @param config Provider configuration
|
|
674
|
+
* @returns Authentication provider instance
|
|
675
|
+
*/
|
|
676
|
+
static async getProvider(config) {
|
|
677
|
+
const { type, validateConfig: validateConfig3 = false, useSingleton = false, storage } = config;
|
|
678
|
+
if (useSingleton && this.instances.has(type)) {
|
|
679
|
+
const instance = this.instances.get(type);
|
|
680
|
+
if (validateConfig3 && instance.validateConfiguration) {
|
|
681
|
+
await instance.validateConfiguration();
|
|
682
|
+
}
|
|
683
|
+
return instance;
|
|
684
|
+
}
|
|
685
|
+
const provider = this.createProvider(type, storage);
|
|
686
|
+
if (validateConfig3 && provider.validateConfiguration) {
|
|
687
|
+
await provider.validateConfiguration();
|
|
688
|
+
}
|
|
689
|
+
if (useSingleton) {
|
|
690
|
+
this.instances.set(type, provider);
|
|
691
|
+
}
|
|
692
|
+
return provider;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Creates a new provider instance without caching
|
|
696
|
+
* @param type Provider type
|
|
697
|
+
* @param storage Optional custom storage implementation
|
|
698
|
+
* @returns Authentication provider instance
|
|
699
|
+
*/
|
|
700
|
+
static createProvider(type, storage) {
|
|
701
|
+
const authStorage = storage || createAuthStorage();
|
|
702
|
+
switch (type) {
|
|
703
|
+
case "supabase":
|
|
704
|
+
return new SupabaseAuthProvider(authStorage);
|
|
705
|
+
case "firebase":
|
|
706
|
+
return new FirebaseAuthProvider(authStorage);
|
|
707
|
+
default:
|
|
708
|
+
throw new AuthError(
|
|
709
|
+
"CONFIGURATION_ERROR" /* CONFIGURATION_ERROR */,
|
|
710
|
+
`Unsupported authentication provider: ${type}. Supported providers: supabase, firebase`
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Detects provider type from environment variables
|
|
716
|
+
* @returns Detected provider type
|
|
717
|
+
*/
|
|
718
|
+
static detectProviderFromEnvironment() {
|
|
719
|
+
const config = getAuthConfig();
|
|
720
|
+
const hasSupabaseConfig = !!(config.supabaseUrl && config.supabaseAnonKey);
|
|
721
|
+
const hasFirebaseConfig = !!(config.firebaseApiKey && config.firebaseAuthDomain && config.firebaseProjectId);
|
|
722
|
+
const explicitProvider = this.getExplicitProvider();
|
|
723
|
+
if (explicitProvider && this.isValidProviderType(explicitProvider)) {
|
|
724
|
+
return explicitProvider;
|
|
725
|
+
}
|
|
726
|
+
if (hasSupabaseConfig && !hasFirebaseConfig) {
|
|
727
|
+
return "supabase";
|
|
728
|
+
}
|
|
729
|
+
if (hasFirebaseConfig && !hasSupabaseConfig) {
|
|
730
|
+
return "firebase";
|
|
731
|
+
}
|
|
732
|
+
if (hasSupabaseConfig && hasFirebaseConfig) {
|
|
733
|
+
console.warn(
|
|
734
|
+
"Both Supabase and Firebase configurations detected. Set AUTH_PROVIDER environment variable to explicitly choose a provider. Defaulting to Supabase."
|
|
735
|
+
);
|
|
736
|
+
return "supabase";
|
|
737
|
+
}
|
|
738
|
+
throw new AuthError(
|
|
739
|
+
"CONFIGURATION_ERROR" /* CONFIGURATION_ERROR */,
|
|
740
|
+
"No authentication provider configuration found. Please configure either Supabase or Firebase environment variables."
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Gets explicit provider from environment variables (platform-agnostic)
|
|
745
|
+
*/
|
|
746
|
+
static getExplicitProvider() {
|
|
747
|
+
var _a, _b;
|
|
748
|
+
if (typeof process !== "undefined" && process.env) {
|
|
749
|
+
return process.env.NEXT_PUBLIC_AUTH_PROVIDER || process.env.AUTH_PROVIDER;
|
|
750
|
+
}
|
|
751
|
+
try {
|
|
752
|
+
const Constants = __require("expo-constants").default;
|
|
753
|
+
return (_b = (_a = Constants.expoConfig) == null ? void 0 : _a.extra) == null ? void 0 : _b.authProvider;
|
|
754
|
+
} catch (error) {
|
|
755
|
+
}
|
|
756
|
+
try {
|
|
757
|
+
const Config = __require("react-native-config").default;
|
|
758
|
+
return Config.AUTH_PROVIDER;
|
|
759
|
+
} catch (error) {
|
|
760
|
+
}
|
|
761
|
+
return undefined;
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Validates if a string is a valid provider type
|
|
765
|
+
* @param type String to validate
|
|
766
|
+
* @returns True if valid provider type
|
|
767
|
+
*/
|
|
768
|
+
static isValidProviderType(type) {
|
|
769
|
+
return type === "supabase" || type === "firebase";
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Gets list of supported provider types
|
|
773
|
+
* @returns Array of supported provider types
|
|
774
|
+
*/
|
|
775
|
+
static getSupportedProviders() {
|
|
776
|
+
return ["supabase", "firebase"];
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* Checks if a provider type is supported
|
|
780
|
+
* @param type Provider type to check
|
|
781
|
+
* @returns True if supported
|
|
782
|
+
*/
|
|
783
|
+
static isProviderSupported(type) {
|
|
784
|
+
return this.isValidProviderType(type);
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Clears singleton instances (useful for testing)
|
|
788
|
+
*/
|
|
789
|
+
static clearInstances() {
|
|
790
|
+
this.instances.clear();
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* Gets current singleton instances (useful for debugging)
|
|
794
|
+
* @returns Map of current instances
|
|
795
|
+
*/
|
|
796
|
+
static getInstances() {
|
|
797
|
+
return new Map(this.instances);
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
AuthProviderFactory.instances = /* @__PURE__ */ new Map();
|
|
801
|
+
|
|
802
|
+
// src/index.ts
|
|
803
|
+
init_storage();
|
|
804
|
+
init_storage();
|
|
805
|
+
var createAuthStore = ({ authProvider }) => create((set) => ({
|
|
16
806
|
user: null,
|
|
17
807
|
loading: true,
|
|
18
808
|
error: null,
|
|
809
|
+
updateUser: (user) => set({ user }),
|
|
810
|
+
setLoading: (loading) => set({ loading }),
|
|
811
|
+
setError: (error) => set({ error }),
|
|
19
812
|
signIn: async (email, password) => {
|
|
813
|
+
set({ loading: true, error: null });
|
|
20
814
|
try {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
email,
|
|
24
|
-
password
|
|
25
|
-
});
|
|
26
|
-
if (error) throw error;
|
|
815
|
+
const user = await authProvider.signIn(email, password);
|
|
816
|
+
set({ user, loading: false });
|
|
27
817
|
} catch (error) {
|
|
28
|
-
set({ error });
|
|
29
|
-
|
|
30
|
-
set({ loading: false });
|
|
818
|
+
set({ error, loading: false });
|
|
819
|
+
throw error;
|
|
31
820
|
}
|
|
32
821
|
},
|
|
33
822
|
signUp: async (email, password) => {
|
|
823
|
+
set({ loading: true, error: null });
|
|
34
824
|
try {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
email,
|
|
38
|
-
password
|
|
39
|
-
});
|
|
40
|
-
if (error) throw error;
|
|
825
|
+
const user = await authProvider.signUp(email, password);
|
|
826
|
+
set({ user, loading: false });
|
|
41
827
|
} catch (error) {
|
|
42
|
-
set({ error });
|
|
43
|
-
|
|
44
|
-
set({ loading: false });
|
|
828
|
+
set({ error, loading: false });
|
|
829
|
+
throw error;
|
|
45
830
|
}
|
|
46
831
|
},
|
|
47
|
-
|
|
832
|
+
signInWithOAuth: async (provider, redirectTo) => {
|
|
833
|
+
set({ loading: true, error: null });
|
|
48
834
|
try {
|
|
49
|
-
|
|
50
|
-
const { error } = await supabase.auth.signOut();
|
|
51
|
-
if (error) throw error;
|
|
52
|
-
set({ user: null });
|
|
53
|
-
} catch (error) {
|
|
54
|
-
set({ error });
|
|
55
|
-
} finally {
|
|
835
|
+
await authProvider.signInWithOAuth(provider, redirectTo);
|
|
56
836
|
set({ loading: false });
|
|
837
|
+
} catch (error) {
|
|
838
|
+
set({ error, loading: false });
|
|
839
|
+
throw error;
|
|
57
840
|
}
|
|
58
841
|
},
|
|
59
|
-
|
|
842
|
+
signInWithMagicLink: async (email, redirectTo) => {
|
|
843
|
+
set({ loading: true, error: null });
|
|
60
844
|
try {
|
|
61
|
-
|
|
62
|
-
const { error } = await supabase.auth.resetPasswordForEmail(email);
|
|
63
|
-
if (error) throw error;
|
|
64
|
-
} catch (error) {
|
|
65
|
-
set({ error });
|
|
66
|
-
} finally {
|
|
845
|
+
await authProvider.signInWithMagicLink(email, redirectTo);
|
|
67
846
|
set({ loading: false });
|
|
847
|
+
} catch (error) {
|
|
848
|
+
set({ error, loading: false });
|
|
849
|
+
throw error;
|
|
68
850
|
}
|
|
69
851
|
},
|
|
70
|
-
|
|
852
|
+
signOut: async () => {
|
|
853
|
+
set({ loading: true, error: null });
|
|
71
854
|
try {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
provider,
|
|
75
|
-
options: {
|
|
76
|
-
redirectTo
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
if (error) throw error;
|
|
855
|
+
await authProvider.signOut();
|
|
856
|
+
set({ user: null, loading: false });
|
|
80
857
|
} catch (error) {
|
|
81
|
-
set({ error });
|
|
82
|
-
|
|
858
|
+
set({ error, loading: false });
|
|
859
|
+
throw error;
|
|
860
|
+
}
|
|
861
|
+
},
|
|
862
|
+
resetPassword: async (email) => {
|
|
863
|
+
set({ loading: true, error: null });
|
|
864
|
+
try {
|
|
865
|
+
await authProvider.resetPassword(email);
|
|
83
866
|
set({ loading: false });
|
|
867
|
+
} catch (error) {
|
|
868
|
+
set({ error, loading: false });
|
|
869
|
+
throw error;
|
|
84
870
|
}
|
|
85
871
|
},
|
|
86
|
-
|
|
872
|
+
getUser: async () => {
|
|
87
873
|
try {
|
|
88
|
-
|
|
89
|
-
const { error } = await supabase.auth.signInWithOtp({
|
|
90
|
-
email,
|
|
91
|
-
options: {
|
|
92
|
-
emailRedirectTo: redirectTo
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
if (error) throw error;
|
|
874
|
+
return await authProvider.getUser();
|
|
96
875
|
} catch (error) {
|
|
97
876
|
set({ error });
|
|
98
|
-
|
|
99
|
-
set({ loading: false });
|
|
877
|
+
throw error;
|
|
100
878
|
}
|
|
101
879
|
},
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
880
|
+
onAuthStateChange: (callback) => {
|
|
881
|
+
return authProvider.onAuthStateChange(callback);
|
|
882
|
+
}
|
|
105
883
|
}));
|
|
884
|
+
var AuthContext = createContext(null);
|
|
885
|
+
var AuthProvider = ({ children, providerType = "supabase", storage }) => {
|
|
886
|
+
const [authProvider, setAuthProvider] = useState(null);
|
|
887
|
+
const [useAuthStore, setUseAuthStore] = useState(null);
|
|
888
|
+
useEffect(() => {
|
|
889
|
+
const initializeProvider = async () => {
|
|
890
|
+
try {
|
|
891
|
+
const authStorage = storage || createAuthStorage();
|
|
892
|
+
const provider = await AuthProviderFactory.getProvider({
|
|
893
|
+
type: providerType,
|
|
894
|
+
validateConfig: true,
|
|
895
|
+
useSingleton: true,
|
|
896
|
+
storage: authStorage
|
|
897
|
+
});
|
|
898
|
+
setAuthProvider(provider);
|
|
899
|
+
setUseAuthStore(createAuthStore({ authProvider: provider }));
|
|
900
|
+
} catch (error) {
|
|
901
|
+
console.error("Failed to initialize auth provider:", error);
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
initializeProvider();
|
|
905
|
+
}, [providerType, storage]);
|
|
906
|
+
useEffect(() => {
|
|
907
|
+
if (!authProvider || !useAuthStore) return;
|
|
908
|
+
const subscriptionResult = authProvider.onAuthStateChange((event, session) => {
|
|
909
|
+
useAuthStore.getState().updateUser((session == null ? undefined : session.user) || null);
|
|
910
|
+
useAuthStore.getState().setLoading(false);
|
|
911
|
+
});
|
|
912
|
+
let unsubscribe;
|
|
913
|
+
if ("data" in subscriptionResult && subscriptionResult.data && "subscription" in subscriptionResult.data && typeof subscriptionResult.data.subscription === "object" && subscriptionResult.data.subscription !== null && "unsubscribe" in subscriptionResult.data.subscription && typeof subscriptionResult.data.subscription.unsubscribe === "function") {
|
|
914
|
+
unsubscribe = subscriptionResult.data.subscription.unsubscribe;
|
|
915
|
+
} else if ("data" in subscriptionResult && subscriptionResult.data && "unsubscribe" in subscriptionResult.data && typeof subscriptionResult.data.unsubscribe === "function") {
|
|
916
|
+
unsubscribe = subscriptionResult.data.unsubscribe;
|
|
917
|
+
} else if ("unsubscribe" in subscriptionResult && typeof subscriptionResult.unsubscribe === "function") {
|
|
918
|
+
unsubscribe = subscriptionResult.unsubscribe;
|
|
919
|
+
}
|
|
920
|
+
authProvider.getUser().then((user) => {
|
|
921
|
+
useAuthStore.getState().updateUser(user);
|
|
922
|
+
useAuthStore.getState().setLoading(false);
|
|
923
|
+
}).catch((error) => {
|
|
924
|
+
console.error("Failed to get initial user:", error);
|
|
925
|
+
useAuthStore.getState().setLoading(false);
|
|
926
|
+
});
|
|
927
|
+
return () => {
|
|
928
|
+
if (unsubscribe) {
|
|
929
|
+
unsubscribe();
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
}, [authProvider, useAuthStore]);
|
|
933
|
+
if (!useAuthStore) {
|
|
934
|
+
return /* @__PURE__ */ jsx("div", { children: "Loading authentication..." });
|
|
935
|
+
}
|
|
936
|
+
return /* @__PURE__ */ jsx(AuthContext.Provider, { value: useAuthStore.getState(), children });
|
|
937
|
+
};
|
|
106
938
|
|
|
107
939
|
// src/hooks/useAuth.ts
|
|
108
940
|
var useAuth = () => {
|
|
109
|
-
const store =
|
|
941
|
+
const store = useContext(AuthContext);
|
|
942
|
+
if (!store) {
|
|
943
|
+
throw new Error("useAuth must be used within an AuthProvider");
|
|
944
|
+
}
|
|
945
|
+
useEffect(() => {
|
|
946
|
+
return () => {
|
|
947
|
+
};
|
|
948
|
+
}, [store]);
|
|
949
|
+
return __spreadValues({}, store);
|
|
950
|
+
};
|
|
951
|
+
var useAuthForm = (options = {}) => {
|
|
952
|
+
const auth = useContext(AuthContext);
|
|
953
|
+
const [email, setEmail] = useState("");
|
|
954
|
+
const [password, setPassword] = useState("");
|
|
955
|
+
const [confirmPassword, setConfirmPassword] = useState("");
|
|
956
|
+
const [loading, setLoading] = useState(false);
|
|
957
|
+
const [error, setError] = useState(null);
|
|
958
|
+
const [message, setMessage] = useState(null);
|
|
959
|
+
if (!auth) {
|
|
960
|
+
throw new Error("useAuthForm must be used within AuthProvider");
|
|
961
|
+
}
|
|
962
|
+
const clearError = () => setError(null);
|
|
963
|
+
const clearMessage = () => setMessage(null);
|
|
964
|
+
const handleSignIn = async () => {
|
|
965
|
+
var _a, _b;
|
|
966
|
+
setLoading(true);
|
|
967
|
+
setError(null);
|
|
968
|
+
setMessage(null);
|
|
969
|
+
try {
|
|
970
|
+
await auth.signIn(email, password);
|
|
971
|
+
(_a = options.onSuccess) == null ? void 0 : _a.call(options);
|
|
972
|
+
} catch (err) {
|
|
973
|
+
const authError = err instanceof AuthError ? err : new AuthError("PROVIDER_ERROR" /* PROVIDER_ERROR */, err.message);
|
|
974
|
+
setError(authError.message);
|
|
975
|
+
(_b = options.onError) == null ? undefined : _b.call(options, authError);
|
|
976
|
+
} finally {
|
|
977
|
+
setLoading(false);
|
|
978
|
+
}
|
|
979
|
+
};
|
|
980
|
+
const handleSignUp = async () => {
|
|
981
|
+
var _a, _b;
|
|
982
|
+
if (password !== confirmPassword) {
|
|
983
|
+
setError("Passwords do not match");
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
setLoading(true);
|
|
987
|
+
setError(null);
|
|
988
|
+
setMessage(null);
|
|
989
|
+
try {
|
|
990
|
+
await auth.signUp(email, password);
|
|
991
|
+
setMessage("Check your email to confirm your account");
|
|
992
|
+
(_a = options.onSuccess) == null ? void 0 : _a.call(options);
|
|
993
|
+
} catch (err) {
|
|
994
|
+
const authError = err instanceof AuthError ? err : new AuthError("PROVIDER_ERROR" /* PROVIDER_ERROR */, err.message);
|
|
995
|
+
setError(authError.message);
|
|
996
|
+
(_b = options.onError) == null ? undefined : _b.call(options, authError);
|
|
997
|
+
} finally {
|
|
998
|
+
setLoading(false);
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
const handleOAuthSignIn = async (provider) => {
|
|
1002
|
+
var _a, _b;
|
|
1003
|
+
setLoading(true);
|
|
1004
|
+
setError(null);
|
|
1005
|
+
try {
|
|
1006
|
+
await auth.signInWithOAuth(provider, options.redirectUrl);
|
|
1007
|
+
(_a = options.onSuccess) == null ? void 0 : _a.call(options);
|
|
1008
|
+
} catch (err) {
|
|
1009
|
+
const authError = err instanceof AuthError ? err : new AuthError("PROVIDER_ERROR" /* PROVIDER_ERROR */, err.message);
|
|
1010
|
+
setError(authError.message);
|
|
1011
|
+
(_b = options.onError) == null ? undefined : _b.call(options, authError);
|
|
1012
|
+
} finally {
|
|
1013
|
+
setLoading(false);
|
|
1014
|
+
}
|
|
1015
|
+
};
|
|
1016
|
+
const handlePasswordReset = async () => {
|
|
1017
|
+
var _a;
|
|
1018
|
+
if (!email) {
|
|
1019
|
+
setError("Please enter your email address");
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
setLoading(true);
|
|
1023
|
+
setError(null);
|
|
1024
|
+
setMessage(null);
|
|
1025
|
+
try {
|
|
1026
|
+
await auth.resetPassword(email);
|
|
1027
|
+
setMessage("Password reset email sent");
|
|
1028
|
+
} catch (err) {
|
|
1029
|
+
const authError = err instanceof AuthError ? err : new AuthError("PROVIDER_ERROR" /* PROVIDER_ERROR */, err.message);
|
|
1030
|
+
setError(authError.message);
|
|
1031
|
+
(_a = options.onError) == null ? undefined : _a.call(options, authError);
|
|
1032
|
+
} finally {
|
|
1033
|
+
setLoading(false);
|
|
1034
|
+
}
|
|
1035
|
+
};
|
|
1036
|
+
const handleMagicLink = async () => {
|
|
1037
|
+
var _a;
|
|
1038
|
+
if (!email) {
|
|
1039
|
+
setError("Please enter your email address");
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
1042
|
+
setLoading(true);
|
|
1043
|
+
setError(null);
|
|
1044
|
+
setMessage(null);
|
|
1045
|
+
try {
|
|
1046
|
+
await auth.signInWithMagicLink(email, options.redirectUrl);
|
|
1047
|
+
setMessage("Magic link sent to your email");
|
|
1048
|
+
} catch (err) {
|
|
1049
|
+
const authError = err instanceof AuthError ? err : new AuthError("PROVIDER_ERROR" /* PROVIDER_ERROR */, err.message);
|
|
1050
|
+
setError(authError.message);
|
|
1051
|
+
(_a = options.onError) == null ? undefined : _a.call(options, authError);
|
|
1052
|
+
} finally {
|
|
1053
|
+
setLoading(false);
|
|
1054
|
+
}
|
|
1055
|
+
};
|
|
1056
|
+
return {
|
|
1057
|
+
// State
|
|
1058
|
+
email,
|
|
1059
|
+
password,
|
|
1060
|
+
confirmPassword,
|
|
1061
|
+
loading,
|
|
1062
|
+
error,
|
|
1063
|
+
message,
|
|
1064
|
+
// Actions
|
|
1065
|
+
setEmail,
|
|
1066
|
+
setPassword,
|
|
1067
|
+
setConfirmPassword,
|
|
1068
|
+
handleSignIn,
|
|
1069
|
+
handleSignUp,
|
|
1070
|
+
handleOAuthSignIn,
|
|
1071
|
+
handlePasswordReset,
|
|
1072
|
+
handleMagicLink,
|
|
1073
|
+
clearError,
|
|
1074
|
+
clearMessage
|
|
1075
|
+
};
|
|
1076
|
+
};
|
|
1077
|
+
var useProtectedRoute = (options = {}) => {
|
|
1078
|
+
const auth = useContext(AuthContext);
|
|
110
1079
|
useEffect(() => {
|
|
111
|
-
|
|
1080
|
+
if (!auth || auth.loading) return;
|
|
1081
|
+
const checkAuth = async () => {
|
|
1082
|
+
var _a, _b;
|
|
1083
|
+
const user = await auth.getUser();
|
|
1084
|
+
if (!user) {
|
|
1085
|
+
(_a = options.onUnauthenticated) == null ? undefined : _a.call(options);
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
if (options.requiredRoles && options.requiredRoles.length > 0) {
|
|
1089
|
+
const userRoles = user.roles || [];
|
|
1090
|
+
const hasRequiredRole = options.requiredRoles.some((role) => userRoles.includes(role));
|
|
1091
|
+
if (!hasRequiredRole) {
|
|
1092
|
+
(_b = options.onUnauthorized) == null ? undefined : _b.call(options);
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
};
|
|
1097
|
+
checkAuth();
|
|
1098
|
+
const unsubscribe = auth.onAuthStateChange((event, session) => {
|
|
112
1099
|
var _a;
|
|
113
|
-
|
|
114
|
-
|
|
1100
|
+
if (!(session == null ? undefined : session.user)) {
|
|
1101
|
+
(_a = options.onUnauthenticated) == null ? undefined : _a.call(options);
|
|
1102
|
+
}
|
|
115
1103
|
});
|
|
1104
|
+
return () => {
|
|
1105
|
+
var _a, _b;
|
|
1106
|
+
if (typeof unsubscribe === "function") {
|
|
1107
|
+
unsubscribe();
|
|
1108
|
+
} else if (unsubscribe && "data" in unsubscribe && ((_b = (_a = unsubscribe.data) == null ? undefined : _a.subscription) == null ? undefined : _b.unsubscribe)) {
|
|
1109
|
+
unsubscribe.data.subscription.unsubscribe();
|
|
1110
|
+
}
|
|
1111
|
+
};
|
|
1112
|
+
}, [auth, options]);
|
|
1113
|
+
return {
|
|
1114
|
+
user: auth == null ? undefined : auth.user,
|
|
1115
|
+
loading: auth == null ? undefined : auth.loading,
|
|
1116
|
+
isAuthenticated: !!(auth == null ? undefined : auth.user)
|
|
1117
|
+
};
|
|
1118
|
+
};
|
|
1119
|
+
function useRBAC() {
|
|
1120
|
+
const auth = useContext(AuthContext);
|
|
1121
|
+
if (!auth) throw new Error("AuthContext not provided");
|
|
1122
|
+
const { user } = auth;
|
|
1123
|
+
const checkPermission = (permission) => {
|
|
1124
|
+
var _a, _b, _c;
|
|
1125
|
+
const userRole = (_a = user == null ? undefined : user.metadata) == null ? undefined : _a.role;
|
|
1126
|
+
return (_c = (_b = userRole == null ? undefined : userRole.permissions) == null ? undefined : _b.includes(permission)) != null ? _c : false;
|
|
1127
|
+
};
|
|
1128
|
+
const hasRole = (role) => {
|
|
1129
|
+
var _a;
|
|
1130
|
+
const userRole = (_a = user == null ? undefined : user.metadata) == null ? undefined : _a.role;
|
|
1131
|
+
return (userRole == null ? undefined : userRole.role) === role;
|
|
1132
|
+
};
|
|
1133
|
+
return {
|
|
1134
|
+
checkPermission,
|
|
1135
|
+
hasRole
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
var createClient2 = () => {
|
|
1139
|
+
if (!process.env.NEXT_PUBLIC_SUPABASE_URL || !process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY) {
|
|
1140
|
+
throw new Error("Missing Supabase environment variables");
|
|
1141
|
+
}
|
|
1142
|
+
return createClientComponentClient();
|
|
1143
|
+
};
|
|
1144
|
+
var supabase = (() => {
|
|
1145
|
+
try {
|
|
1146
|
+
if (process.env.NEXT_PUBLIC_SUPABASE_URL && process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY) {
|
|
1147
|
+
return createClient2();
|
|
1148
|
+
}
|
|
1149
|
+
} catch (error) {
|
|
1150
|
+
console.warn("Supabase client not initialized: environment variables not available");
|
|
1151
|
+
}
|
|
1152
|
+
return null;
|
|
1153
|
+
})();
|
|
1154
|
+
|
|
1155
|
+
// src/hooks/use2FA.ts
|
|
1156
|
+
function use2FA() {
|
|
1157
|
+
const [loading, setLoading] = useState(false);
|
|
1158
|
+
const [error, setError] = useState(null);
|
|
1159
|
+
const setup2FA = async () => {
|
|
1160
|
+
if (!supabase) {
|
|
1161
|
+
throw new Error("Supabase client not initialized. Please check your environment variables.");
|
|
1162
|
+
}
|
|
1163
|
+
setLoading(true);
|
|
1164
|
+
setError(null);
|
|
1165
|
+
try {
|
|
1166
|
+
const { data, error: error2 } = await supabase.auth.mfa.enroll({
|
|
1167
|
+
factorType: "totp"
|
|
1168
|
+
});
|
|
1169
|
+
if (error2) throw error2;
|
|
1170
|
+
return data;
|
|
1171
|
+
} catch (err) {
|
|
1172
|
+
const error2 = err;
|
|
1173
|
+
setError(error2);
|
|
1174
|
+
throw error2;
|
|
1175
|
+
} finally {
|
|
1176
|
+
setLoading(false);
|
|
1177
|
+
}
|
|
1178
|
+
};
|
|
1179
|
+
const verify2FA = async (factorId, challengeId, code) => {
|
|
1180
|
+
if (!supabase) {
|
|
1181
|
+
throw new Error("Supabase client not initialized. Please check your environment variables.");
|
|
1182
|
+
}
|
|
1183
|
+
setLoading(true);
|
|
1184
|
+
setError(null);
|
|
1185
|
+
try {
|
|
1186
|
+
const { data, error: error2 } = await supabase.auth.mfa.verify({
|
|
1187
|
+
factorId,
|
|
1188
|
+
challengeId,
|
|
1189
|
+
code
|
|
1190
|
+
});
|
|
1191
|
+
if (error2) throw error2;
|
|
1192
|
+
return data;
|
|
1193
|
+
} catch (err) {
|
|
1194
|
+
const error2 = err;
|
|
1195
|
+
setError(error2);
|
|
1196
|
+
throw error2;
|
|
1197
|
+
} finally {
|
|
1198
|
+
setLoading(false);
|
|
1199
|
+
}
|
|
1200
|
+
};
|
|
1201
|
+
const unenroll2FA = async (factorId) => {
|
|
1202
|
+
if (!supabase) {
|
|
1203
|
+
throw new Error("Supabase client not initialized. Please check your environment variables.");
|
|
1204
|
+
}
|
|
1205
|
+
setLoading(true);
|
|
1206
|
+
setError(null);
|
|
1207
|
+
try {
|
|
1208
|
+
const { data, error: error2 } = await supabase.auth.mfa.unenroll({
|
|
1209
|
+
factorId
|
|
1210
|
+
});
|
|
1211
|
+
if (error2) throw error2;
|
|
1212
|
+
return data;
|
|
1213
|
+
} catch (err) {
|
|
1214
|
+
const error2 = err;
|
|
1215
|
+
setError(error2);
|
|
1216
|
+
throw error2;
|
|
1217
|
+
} finally {
|
|
1218
|
+
setLoading(false);
|
|
1219
|
+
}
|
|
1220
|
+
};
|
|
1221
|
+
return {
|
|
1222
|
+
setup2FA,
|
|
1223
|
+
verify2FA,
|
|
1224
|
+
unenroll2FA,
|
|
1225
|
+
loading,
|
|
1226
|
+
error
|
|
1227
|
+
};
|
|
1228
|
+
}
|
|
1229
|
+
function useRedirectUrl(defaultUrl = "/dashboard") {
|
|
1230
|
+
const searchParams = useSearchParams();
|
|
1231
|
+
return (searchParams == null ? undefined : searchParams.get("returnUrl")) || defaultUrl;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
// src/utils/authConfig.ts
|
|
1235
|
+
var defaultAuthConfig = {
|
|
1236
|
+
passwordRequirements: {
|
|
1237
|
+
minLength: 8,
|
|
1238
|
+
requireNumbers: true,
|
|
1239
|
+
requireSpecialChars: true,
|
|
1240
|
+
requireUppercase: true
|
|
1241
|
+
},
|
|
1242
|
+
maxLoginAttempts: 5,
|
|
1243
|
+
lockoutDuration: 15,
|
|
1244
|
+
// 15 minutes
|
|
1245
|
+
jwtExpiryTime: 3600,
|
|
1246
|
+
// 1 hour
|
|
1247
|
+
require2FA: false
|
|
1248
|
+
};
|
|
1249
|
+
|
|
1250
|
+
// src/utils/password.ts
|
|
1251
|
+
function validatePassword(password, config) {
|
|
1252
|
+
if (!config) return true;
|
|
1253
|
+
const { minLength, requireNumbers, requireSpecialChars, requireUppercase } = config;
|
|
1254
|
+
if (password.length < minLength) {
|
|
1255
|
+
throw new Error(`Password must be at least ${minLength} characters long`);
|
|
1256
|
+
}
|
|
1257
|
+
if (requireNumbers && !/\d/.test(password)) {
|
|
1258
|
+
throw new Error("Password must contain at least one number");
|
|
1259
|
+
}
|
|
1260
|
+
if (requireSpecialChars && !/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
|
|
1261
|
+
throw new Error("Password must contain at least one special character");
|
|
1262
|
+
}
|
|
1263
|
+
if (requireUppercase && !/[A-Z]/.test(password)) {
|
|
1264
|
+
throw new Error("Password must contain at least one uppercase letter");
|
|
1265
|
+
}
|
|
1266
|
+
return true;
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
// src/utils/validation.ts
|
|
1270
|
+
var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
1271
|
+
var ValidationUtils = class {
|
|
1272
|
+
/**
|
|
1273
|
+
* Validate email address format
|
|
1274
|
+
*/
|
|
1275
|
+
static validateEmail(email) {
|
|
1276
|
+
if (!email || typeof email !== "string") {
|
|
1277
|
+
throw new AuthError(
|
|
1278
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
1279
|
+
"Email is required and must be a string",
|
|
1280
|
+
null,
|
|
1281
|
+
{ field: "email", value: email }
|
|
1282
|
+
);
|
|
1283
|
+
}
|
|
1284
|
+
if (!EMAIL_REGEX.test(email.trim())) {
|
|
1285
|
+
throw new AuthError(
|
|
1286
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
1287
|
+
"Invalid email format",
|
|
1288
|
+
null,
|
|
1289
|
+
{ field: "email", value: email }
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
/**
|
|
1294
|
+
* Validate password strength
|
|
1295
|
+
*/
|
|
1296
|
+
static validatePassword(password, requirements) {
|
|
1297
|
+
if (!password || typeof password !== "string") {
|
|
1298
|
+
throw new AuthError(
|
|
1299
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
1300
|
+
"Password is required and must be a string",
|
|
1301
|
+
null,
|
|
1302
|
+
{ field: "password" }
|
|
1303
|
+
);
|
|
1304
|
+
}
|
|
116
1305
|
const {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
1306
|
+
minLength = 8,
|
|
1307
|
+
requireNumbers = true,
|
|
1308
|
+
requireSpecialChars = true,
|
|
1309
|
+
requireUppercase = true
|
|
1310
|
+
} = requirements || {};
|
|
1311
|
+
if (password.length < minLength) {
|
|
1312
|
+
throw new AuthError(
|
|
1313
|
+
"WEAK_PASSWORD" /* WEAK_PASSWORD */,
|
|
1314
|
+
`Password must be at least ${minLength} characters long`,
|
|
1315
|
+
null,
|
|
1316
|
+
{ field: "password", requirement: "minLength", expected: minLength, actual: password.length }
|
|
1317
|
+
);
|
|
1318
|
+
}
|
|
1319
|
+
if (requireNumbers && !/\d/.test(password)) {
|
|
1320
|
+
throw new AuthError(
|
|
1321
|
+
"WEAK_PASSWORD" /* WEAK_PASSWORD */,
|
|
1322
|
+
"Password must contain at least one number",
|
|
1323
|
+
null,
|
|
1324
|
+
{ field: "password", requirement: "numbers" }
|
|
1325
|
+
);
|
|
1326
|
+
}
|
|
1327
|
+
if (requireSpecialChars && !/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
|
|
1328
|
+
throw new AuthError(
|
|
1329
|
+
"WEAK_PASSWORD" /* WEAK_PASSWORD */,
|
|
1330
|
+
"Password must contain at least one special character",
|
|
1331
|
+
null,
|
|
1332
|
+
{ field: "password", requirement: "specialChars" }
|
|
1333
|
+
);
|
|
1334
|
+
}
|
|
1335
|
+
if (requireUppercase && !/[A-Z]/.test(password)) {
|
|
1336
|
+
throw new AuthError(
|
|
1337
|
+
"WEAK_PASSWORD" /* WEAK_PASSWORD */,
|
|
1338
|
+
"Password must contain at least one uppercase letter",
|
|
1339
|
+
null,
|
|
1340
|
+
{ field: "password", requirement: "uppercase" }
|
|
1341
|
+
);
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
/**
|
|
1345
|
+
* Validate OAuth provider
|
|
1346
|
+
*/
|
|
1347
|
+
static validateOAuthProvider(provider) {
|
|
1348
|
+
if (!provider || typeof provider !== "string") {
|
|
1349
|
+
throw new AuthError(
|
|
1350
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
1351
|
+
"OAuth provider is required and must be a string",
|
|
1352
|
+
null,
|
|
1353
|
+
{ field: "provider", value: provider }
|
|
1354
|
+
);
|
|
1355
|
+
}
|
|
1356
|
+
const validProviders = ["google", "github", "apple", "facebook", "twitter", "discord"];
|
|
1357
|
+
if (!validProviders.includes(provider.toLowerCase())) {
|
|
1358
|
+
throw new AuthError(
|
|
1359
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
1360
|
+
`Invalid OAuth provider: ${provider}. Supported providers: ${validProviders.join(", ")}`,
|
|
1361
|
+
null,
|
|
1362
|
+
{ field: "provider", value: provider, validProviders }
|
|
1363
|
+
);
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
/**
|
|
1367
|
+
* Validate URL format
|
|
1368
|
+
*/
|
|
1369
|
+
static validateUrl(url, fieldName = "url") {
|
|
1370
|
+
if (!url || typeof url !== "string") {
|
|
1371
|
+
throw new AuthError(
|
|
1372
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
1373
|
+
`${fieldName} is required and must be a string`,
|
|
1374
|
+
null,
|
|
1375
|
+
{ field: fieldName, value: url }
|
|
1376
|
+
);
|
|
1377
|
+
}
|
|
1378
|
+
try {
|
|
1379
|
+
new URL(url);
|
|
1380
|
+
} catch (error) {
|
|
1381
|
+
throw new AuthError(
|
|
1382
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
1383
|
+
`Invalid ${fieldName} format`,
|
|
1384
|
+
error,
|
|
1385
|
+
{ field: fieldName, value: url }
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
/**
|
|
1390
|
+
* Validate required string field
|
|
1391
|
+
*/
|
|
1392
|
+
static validateRequiredString(value, fieldName) {
|
|
1393
|
+
if (!value || typeof value !== "string" || value.trim().length === 0) {
|
|
1394
|
+
throw new AuthError(
|
|
1395
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
1396
|
+
`${fieldName} is required and must be a non-empty string`,
|
|
1397
|
+
null,
|
|
1398
|
+
{ field: fieldName, value }
|
|
1399
|
+
);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
/**
|
|
1403
|
+
* Sanitize email input
|
|
1404
|
+
*/
|
|
1405
|
+
static sanitizeEmail(email) {
|
|
1406
|
+
return (email == null ? undefined : email.trim().toLowerCase()) || "";
|
|
1407
|
+
}
|
|
1408
|
+
/**
|
|
1409
|
+
* Check if error is a validation error
|
|
1410
|
+
*/
|
|
1411
|
+
static isValidationError(error) {
|
|
1412
|
+
return error instanceof AuthError && (error.type === "VALIDATION_ERROR" /* VALIDATION_ERROR */ || error.type === "WEAK_PASSWORD" /* WEAK_PASSWORD */);
|
|
1413
|
+
}
|
|
125
1414
|
};
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
1415
|
+
function validateParams(validations) {
|
|
1416
|
+
return function(target, propertyName, descriptor) {
|
|
1417
|
+
const method = descriptor.value;
|
|
1418
|
+
descriptor.value = function(...args) {
|
|
1419
|
+
const paramNames = getParameterNames(method);
|
|
1420
|
+
paramNames.forEach((paramName, index) => {
|
|
1421
|
+
if (validations[paramName] && args[index] !== undefined) {
|
|
1422
|
+
validations[paramName](args[index]);
|
|
1423
|
+
}
|
|
1424
|
+
});
|
|
1425
|
+
return method.apply(this, args);
|
|
1426
|
+
};
|
|
1427
|
+
};
|
|
1428
|
+
}
|
|
1429
|
+
function getParameterNames(func) {
|
|
1430
|
+
const funcStr = func.toString();
|
|
1431
|
+
const match = funcStr.match(/\(([^)]*)\)/);
|
|
1432
|
+
if (!match) return [];
|
|
1433
|
+
return match[1].split(",").map((param) => param.trim().split(/\s+/)[0]).filter((param) => param.length > 0);
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
// src/utils/performance.ts
|
|
1437
|
+
function memoize(fn, keyGenerator) {
|
|
1438
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1439
|
+
return (...args) => {
|
|
1440
|
+
const key = keyGenerator ? keyGenerator(...args) : JSON.stringify(args);
|
|
1441
|
+
if (cache.has(key)) {
|
|
1442
|
+
return cache.get(key);
|
|
1443
|
+
}
|
|
1444
|
+
const result = fn(...args);
|
|
1445
|
+
cache.set(key, result);
|
|
1446
|
+
return result;
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
function debounce(fn, delay) {
|
|
1450
|
+
let timeoutId;
|
|
1451
|
+
return (...args) => {
|
|
1452
|
+
clearTimeout(timeoutId);
|
|
1453
|
+
timeoutId = setTimeout(() => fn(...args), delay);
|
|
1454
|
+
};
|
|
1455
|
+
}
|
|
1456
|
+
function throttle(fn, limit) {
|
|
1457
|
+
let inThrottle;
|
|
1458
|
+
return (...args) => {
|
|
1459
|
+
if (!inThrottle) {
|
|
1460
|
+
fn(...args);
|
|
1461
|
+
inThrottle = true;
|
|
1462
|
+
setTimeout(() => inThrottle = false, limit);
|
|
1463
|
+
}
|
|
1464
|
+
};
|
|
1465
|
+
}
|
|
1466
|
+
async function retryWithBackoff(fn, maxRetries = 3, baseDelay = 1e3, maxDelay = 1e4) {
|
|
1467
|
+
let lastError;
|
|
1468
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
1469
|
+
try {
|
|
1470
|
+
return await fn();
|
|
1471
|
+
} catch (error) {
|
|
1472
|
+
lastError = error;
|
|
1473
|
+
if (attempt === maxRetries) {
|
|
1474
|
+
throw lastError;
|
|
1475
|
+
}
|
|
1476
|
+
const delay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
|
|
1477
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
throw lastError;
|
|
1481
|
+
}
|
|
1482
|
+
var LRUCache = class {
|
|
1483
|
+
constructor(maxSize = 100) {
|
|
1484
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
1485
|
+
this.maxSize = maxSize;
|
|
1486
|
+
}
|
|
1487
|
+
get(key) {
|
|
1488
|
+
if (this.cache.has(key)) {
|
|
1489
|
+
const value = this.cache.get(key);
|
|
1490
|
+
this.cache.delete(key);
|
|
1491
|
+
this.cache.set(key, value);
|
|
1492
|
+
return value;
|
|
1493
|
+
}
|
|
1494
|
+
return undefined;
|
|
1495
|
+
}
|
|
1496
|
+
set(key, value) {
|
|
1497
|
+
if (this.cache.has(key)) {
|
|
1498
|
+
this.cache.delete(key);
|
|
1499
|
+
} else if (this.cache.size >= this.maxSize) {
|
|
1500
|
+
const firstKey = this.cache.keys().next().value;
|
|
1501
|
+
if (firstKey !== undefined) {
|
|
1502
|
+
this.cache.delete(firstKey);
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
this.cache.set(key, value);
|
|
1506
|
+
}
|
|
1507
|
+
has(key) {
|
|
1508
|
+
return this.cache.has(key);
|
|
1509
|
+
}
|
|
1510
|
+
clear() {
|
|
1511
|
+
this.cache.clear();
|
|
1512
|
+
}
|
|
1513
|
+
size() {
|
|
1514
|
+
return this.cache.size;
|
|
1515
|
+
}
|
|
130
1516
|
};
|
|
131
|
-
var
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
1517
|
+
var PerformanceMonitor = class {
|
|
1518
|
+
static start(label) {
|
|
1519
|
+
this.timers.set(label, performance.now());
|
|
1520
|
+
}
|
|
1521
|
+
static end(label) {
|
|
1522
|
+
const startTime = this.timers.get(label);
|
|
1523
|
+
if (!startTime) {
|
|
1524
|
+
console.warn(`Performance timer '${label}' was not started`);
|
|
1525
|
+
return 0;
|
|
1526
|
+
}
|
|
1527
|
+
const duration = performance.now() - startTime;
|
|
1528
|
+
this.timers.delete(label);
|
|
1529
|
+
return duration;
|
|
1530
|
+
}
|
|
1531
|
+
static measure(label, fn) {
|
|
1532
|
+
this.start(label);
|
|
1533
|
+
try {
|
|
1534
|
+
const result = fn();
|
|
1535
|
+
return result;
|
|
1536
|
+
} finally {
|
|
1537
|
+
const duration = this.end(label);
|
|
1538
|
+
console.debug(`${label} took ${duration.toFixed(2)}ms`);
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
static async measureAsync(label, fn) {
|
|
1542
|
+
this.start(label);
|
|
1543
|
+
try {
|
|
1544
|
+
const result = await fn();
|
|
1545
|
+
return result;
|
|
1546
|
+
} finally {
|
|
1547
|
+
const duration = this.end(label);
|
|
1548
|
+
console.debug(`${label} took ${duration.toFixed(2)}ms`);
|
|
1549
|
+
}
|
|
135
1550
|
}
|
|
136
|
-
return context;
|
|
137
1551
|
};
|
|
1552
|
+
PerformanceMonitor.timers = /* @__PURE__ */ new Map();
|
|
1553
|
+
|
|
1554
|
+
// src/utils/healthCheck.ts
|
|
1555
|
+
var HealthChecker = class {
|
|
1556
|
+
/**
|
|
1557
|
+
* Perform comprehensive system health check
|
|
1558
|
+
*/
|
|
1559
|
+
static async performHealthCheck() {
|
|
1560
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
1561
|
+
const checks = {
|
|
1562
|
+
configuration: await this.checkConfiguration(),
|
|
1563
|
+
provider: await this.checkProvider(),
|
|
1564
|
+
storage: await this.checkStorage()
|
|
1565
|
+
};
|
|
1566
|
+
const statuses = Object.values(checks).map((check) => check.status);
|
|
1567
|
+
let overall = "healthy";
|
|
1568
|
+
if (statuses.includes("error")) {
|
|
1569
|
+
overall = "error";
|
|
1570
|
+
} else if (statuses.includes("warning")) {
|
|
1571
|
+
overall = "warning";
|
|
1572
|
+
}
|
|
1573
|
+
return {
|
|
1574
|
+
overall,
|
|
1575
|
+
checks,
|
|
1576
|
+
timestamp
|
|
1577
|
+
};
|
|
1578
|
+
}
|
|
1579
|
+
/**
|
|
1580
|
+
* Check configuration validity
|
|
1581
|
+
*/
|
|
1582
|
+
static async checkConfiguration() {
|
|
1583
|
+
try {
|
|
1584
|
+
const config = getAuthConfig();
|
|
1585
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
1586
|
+
let providerType = null;
|
|
1587
|
+
if (config.supabaseUrl && config.supabaseAnonKey) {
|
|
1588
|
+
providerType = "supabase";
|
|
1589
|
+
} else if (config.firebaseApiKey && config.firebaseAuthDomain && config.firebaseProjectId) {
|
|
1590
|
+
providerType = "firebase";
|
|
1591
|
+
}
|
|
1592
|
+
if (!providerType) {
|
|
1593
|
+
return {
|
|
1594
|
+
status: "error",
|
|
1595
|
+
message: "No valid authentication provider configuration found",
|
|
1596
|
+
details: {
|
|
1597
|
+
hasSupabaseConfig: !!(config.supabaseUrl && config.supabaseAnonKey),
|
|
1598
|
+
hasFirebaseConfig: !!(config.firebaseApiKey && config.firebaseAuthDomain && config.firebaseProjectId)
|
|
1599
|
+
},
|
|
1600
|
+
timestamp
|
|
1601
|
+
};
|
|
1602
|
+
}
|
|
1603
|
+
if (providerType === "supabase") {
|
|
1604
|
+
if (!config.supabaseUrl || !config.supabaseAnonKey) {
|
|
1605
|
+
return {
|
|
1606
|
+
status: "error",
|
|
1607
|
+
message: "Missing Supabase configuration (URL or anonymous key)",
|
|
1608
|
+
details: {
|
|
1609
|
+
hasUrl: !!config.supabaseUrl,
|
|
1610
|
+
hasAnonKey: !!config.supabaseAnonKey
|
|
1611
|
+
},
|
|
1612
|
+
timestamp
|
|
1613
|
+
};
|
|
1614
|
+
}
|
|
1615
|
+
} else if (providerType === "firebase") {
|
|
1616
|
+
if (!config.firebaseApiKey || !config.firebaseAuthDomain || !config.firebaseProjectId) {
|
|
1617
|
+
return {
|
|
1618
|
+
status: "error",
|
|
1619
|
+
message: "Missing Firebase configuration (API key, auth domain, or project ID)",
|
|
1620
|
+
details: {
|
|
1621
|
+
hasApiKey: !!config.firebaseApiKey,
|
|
1622
|
+
hasAuthDomain: !!config.firebaseAuthDomain,
|
|
1623
|
+
hasProjectId: !!config.firebaseProjectId
|
|
1624
|
+
},
|
|
1625
|
+
timestamp
|
|
1626
|
+
};
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
return {
|
|
1630
|
+
status: "healthy",
|
|
1631
|
+
message: "Configuration is valid",
|
|
1632
|
+
details: {
|
|
1633
|
+
provider: providerType,
|
|
1634
|
+
hasRedirectUrl: !!config.redirectUrl
|
|
1635
|
+
},
|
|
1636
|
+
timestamp
|
|
1637
|
+
};
|
|
1638
|
+
} catch (error) {
|
|
1639
|
+
return {
|
|
1640
|
+
status: "error",
|
|
1641
|
+
message: `Configuration check failed: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1642
|
+
details: { error },
|
|
1643
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
/**
|
|
1648
|
+
* Check provider initialization
|
|
1649
|
+
*/
|
|
1650
|
+
static async checkProvider() {
|
|
1651
|
+
try {
|
|
1652
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
1653
|
+
const provider = await AuthProviderFactory.getProviderFromEnvironment();
|
|
1654
|
+
if (!provider) {
|
|
1655
|
+
return {
|
|
1656
|
+
status: "error",
|
|
1657
|
+
message: "Failed to initialize authentication provider",
|
|
1658
|
+
timestamp
|
|
1659
|
+
};
|
|
1660
|
+
}
|
|
1661
|
+
return {
|
|
1662
|
+
status: "healthy",
|
|
1663
|
+
message: "Authentication provider initialized successfully",
|
|
1664
|
+
details: { providerType: provider.constructor.name },
|
|
1665
|
+
timestamp
|
|
1666
|
+
};
|
|
1667
|
+
} catch (error) {
|
|
1668
|
+
return {
|
|
1669
|
+
status: "error",
|
|
1670
|
+
message: `Provider initialization failed: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1671
|
+
details: { error },
|
|
1672
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1673
|
+
};
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
/**
|
|
1677
|
+
* Check storage functionality
|
|
1678
|
+
*/
|
|
1679
|
+
static async checkStorage() {
|
|
1680
|
+
try {
|
|
1681
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
1682
|
+
const { createAuthStorage: createAuthStorage2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
|
|
1683
|
+
const storage = createAuthStorage2();
|
|
1684
|
+
const testKey = "health-check-test";
|
|
1685
|
+
const testValue = "test-value";
|
|
1686
|
+
await storage.setItem(testKey, testValue);
|
|
1687
|
+
const retrievedValue = await storage.getItem(testKey);
|
|
1688
|
+
await storage.removeItem(testKey);
|
|
1689
|
+
if (retrievedValue !== testValue) {
|
|
1690
|
+
return {
|
|
1691
|
+
status: "error",
|
|
1692
|
+
message: "Storage read/write test failed",
|
|
1693
|
+
details: { expected: testValue, actual: retrievedValue },
|
|
1694
|
+
timestamp
|
|
1695
|
+
};
|
|
1696
|
+
}
|
|
1697
|
+
return {
|
|
1698
|
+
status: "healthy",
|
|
1699
|
+
message: "Storage is functioning correctly",
|
|
1700
|
+
details: { storageType: storage.constructor.name },
|
|
1701
|
+
timestamp
|
|
1702
|
+
};
|
|
1703
|
+
} catch (error) {
|
|
1704
|
+
return {
|
|
1705
|
+
status: "error",
|
|
1706
|
+
message: `Storage check failed: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1707
|
+
details: { error },
|
|
1708
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1709
|
+
};
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
/**
|
|
1713
|
+
* Check network connectivity to authentication services
|
|
1714
|
+
*/
|
|
1715
|
+
static async checkNetworkConnectivity() {
|
|
1716
|
+
try {
|
|
1717
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
1718
|
+
const config = getAuthConfig();
|
|
1719
|
+
if (config.supabaseUrl && config.supabaseAnonKey) {
|
|
1720
|
+
const response = await fetch(`${config.supabaseUrl}/rest/v1/`, {
|
|
1721
|
+
method: "HEAD",
|
|
1722
|
+
headers: {
|
|
1723
|
+
"apikey": config.supabaseAnonKey
|
|
1724
|
+
}
|
|
1725
|
+
});
|
|
1726
|
+
if (!response.ok) {
|
|
1727
|
+
return {
|
|
1728
|
+
status: "warning",
|
|
1729
|
+
message: `Supabase connectivity issue: ${response.status} ${response.statusText}`,
|
|
1730
|
+
details: { status: response.status, statusText: response.statusText },
|
|
1731
|
+
timestamp
|
|
1732
|
+
};
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
return {
|
|
1736
|
+
status: "healthy",
|
|
1737
|
+
message: "Network connectivity is working",
|
|
1738
|
+
timestamp
|
|
1739
|
+
};
|
|
1740
|
+
} catch (error) {
|
|
1741
|
+
return {
|
|
1742
|
+
status: "warning",
|
|
1743
|
+
message: `Network connectivity check failed: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1744
|
+
details: { error },
|
|
1745
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
/**
|
|
1750
|
+
* Generate health check report
|
|
1751
|
+
*/
|
|
1752
|
+
static generateReport(healthCheck) {
|
|
1753
|
+
const { overall, checks, timestamp } = healthCheck;
|
|
1754
|
+
let report = `Authentication System Health Check Report
|
|
1755
|
+
`;
|
|
1756
|
+
report += `Generated: ${timestamp.toISOString()}
|
|
1757
|
+
`;
|
|
1758
|
+
report += `Overall Status: ${overall.toUpperCase()}
|
|
1759
|
+
|
|
1760
|
+
`;
|
|
1761
|
+
Object.entries(checks).forEach(([checkName, result]) => {
|
|
1762
|
+
report += `${checkName.toUpperCase()} CHECK:
|
|
1763
|
+
`;
|
|
1764
|
+
report += ` Status: ${result.status.toUpperCase()}
|
|
1765
|
+
`;
|
|
1766
|
+
report += ` Message: ${result.message}
|
|
1767
|
+
`;
|
|
1768
|
+
if (result.details) {
|
|
1769
|
+
report += ` Details: ${JSON.stringify(result.details, null, 2)}
|
|
1770
|
+
`;
|
|
1771
|
+
}
|
|
1772
|
+
report += `
|
|
1773
|
+
`;
|
|
1774
|
+
});
|
|
1775
|
+
return report;
|
|
1776
|
+
}
|
|
1777
|
+
/**
|
|
1778
|
+
* Quick health check for monitoring
|
|
1779
|
+
*/
|
|
1780
|
+
static async quickCheck() {
|
|
1781
|
+
try {
|
|
1782
|
+
const configCheck = await this.checkConfiguration();
|
|
1783
|
+
const providerCheck = await this.checkProvider();
|
|
1784
|
+
return configCheck.status !== "error" && providerCheck.status !== "error";
|
|
1785
|
+
} catch (error) {
|
|
1786
|
+
return false;
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
};
|
|
1790
|
+
var supabaseAdmin = null;
|
|
1791
|
+
var getSupabaseAdmin = () => {
|
|
1792
|
+
if (!supabaseAdmin) {
|
|
1793
|
+
if (!process.env.NEXT_PUBLIC_SUPABASE_URL || !process.env.SUPABASE_SERVICE_ROLE_KEY) {
|
|
1794
|
+
throw new Error("Missing required Supabase environment variables for admin client");
|
|
1795
|
+
}
|
|
1796
|
+
supabaseAdmin = createClient(
|
|
1797
|
+
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
|
1798
|
+
process.env.SUPABASE_SERVICE_ROLE_KEY
|
|
1799
|
+
);
|
|
1800
|
+
}
|
|
1801
|
+
return supabaseAdmin;
|
|
1802
|
+
};
|
|
1803
|
+
function withAuth(middleware, options = {}) {
|
|
1804
|
+
const {
|
|
1805
|
+
publicRoutes = ["/login", "/signup", "/reset-password"],
|
|
1806
|
+
loginRoute = "/login"
|
|
1807
|
+
} = options;
|
|
1808
|
+
return async function middlewareWithAuth(req) {
|
|
1809
|
+
const res = NextResponse.next();
|
|
1810
|
+
const supabase2 = createMiddlewareClient({ req, res });
|
|
1811
|
+
const {
|
|
1812
|
+
data: { session }
|
|
1813
|
+
} = await supabase2.auth.getSession();
|
|
1814
|
+
let user = session == null ? undefined : session.user;
|
|
1815
|
+
if (!user) {
|
|
1816
|
+
const authHeader = req.headers.get("authorization");
|
|
1817
|
+
if (authHeader == null ? undefined : authHeader.startsWith("Bearer ")) {
|
|
1818
|
+
const token = authHeader.substring(7);
|
|
1819
|
+
try {
|
|
1820
|
+
const admin = getSupabaseAdmin();
|
|
1821
|
+
const { data: { user: bearerUser } } = await admin.auth.getUser(token);
|
|
1822
|
+
user = bearerUser;
|
|
1823
|
+
} catch (error) {
|
|
1824
|
+
console.error("Bearer token verification failed:", error);
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
const isPublicRoute = publicRoutes.includes(req.nextUrl.pathname);
|
|
1829
|
+
const isLoginRoute = req.nextUrl.pathname === loginRoute;
|
|
1830
|
+
if (isPublicRoute) {
|
|
1831
|
+
if (user && isLoginRoute) {
|
|
1832
|
+
const returnUrl = req.nextUrl.searchParams.get("returnUrl");
|
|
1833
|
+
return NextResponse.redirect(new URL(returnUrl || "/dashboard", req.url));
|
|
1834
|
+
}
|
|
1835
|
+
return middleware(req);
|
|
1836
|
+
}
|
|
1837
|
+
if (!user) {
|
|
1838
|
+
const redirectUrl = new URL(loginRoute, req.url);
|
|
1839
|
+
redirectUrl.searchParams.set("returnUrl", req.nextUrl.pathname);
|
|
1840
|
+
return NextResponse.redirect(redirectUrl);
|
|
1841
|
+
}
|
|
1842
|
+
return middleware(req);
|
|
1843
|
+
};
|
|
1844
|
+
}
|
|
1845
|
+
async function handleEmailVerification(token) {
|
|
1846
|
+
const supabase2 = createServerComponentClient({ cookies });
|
|
1847
|
+
try {
|
|
1848
|
+
const { error } = await supabase2.auth.verifyOtp({
|
|
1849
|
+
token_hash: token,
|
|
1850
|
+
type: "email"
|
|
1851
|
+
});
|
|
1852
|
+
if (error) throw error;
|
|
1853
|
+
return { success: true };
|
|
1854
|
+
} catch (error) {
|
|
1855
|
+
return { success: false, error };
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
138
1858
|
|
|
139
|
-
export { AuthProvider,
|
|
1859
|
+
export { AuthContext, AuthError, AuthErrorType, AuthEvent, AuthProvider, AuthProviderFactory, FirebaseAuthProvider, HealthChecker, LRUCache, NativeAuthStorage, PerformanceMonitor, SupabaseAuthProvider, ValidationUtils, WebAuthStorage, createAuthStorage, createAuthStore, debounce, defaultAuthConfig, handleEmailVerification, memoize, retryWithBackoff, throttle, use2FA, useAuth, useAuthForm, useProtectedRoute, useRBAC, useRedirectUrl, validateParams, validatePassword, withAuth };
|
|
140
1860
|
//# sourceMappingURL=index.mjs.map
|
|
141
1861
|
//# sourceMappingURL=index.mjs.map
|