superso-js-sdk 1.0.1 → 1.0.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.
@@ -1,5 +1,28 @@
1
1
  import { SupersoClient } from "../core/client";
2
- type AuthListener = (payload: any) => void;
2
+ export interface AuthUser {
3
+ id?: string;
4
+ email?: string;
5
+ phone?: string;
6
+ display_name?: string;
7
+ avatar_url?: string;
8
+ bio?: string;
9
+ [key: string]: any;
10
+ }
11
+ export interface AuthResponse {
12
+ token?: string;
13
+ refresh_token?: string;
14
+ user?: AuthUser;
15
+ message?: string;
16
+ [key: string]: any;
17
+ }
18
+ export type AuthListener = (payload: {
19
+ user?: AuthUser | null;
20
+ token?: string | null;
21
+ type?: string;
22
+ }) => void;
23
+ declare function parseJwt(token: string): any;
24
+ declare function isTokenExpired(token: string): boolean;
25
+ declare function saveSession(data: AuthResponse): void;
3
26
  export declare function clearSession(): void;
4
27
  export declare function getAccessToken(): string | null;
5
28
  export declare function getRefreshToken(): string | null;
@@ -9,13 +32,13 @@ export declare function register(client: SupersoClient, payload: {
9
32
  display_name?: string;
10
33
  email: string;
11
34
  password: string;
12
- }): Promise<any>;
35
+ }): Promise<AuthResponse>;
13
36
  export declare function login(client: SupersoClient, payload: {
14
37
  email: string;
15
38
  password: string;
16
- }): Promise<any>;
39
+ }): Promise<AuthResponse>;
17
40
  export declare function logout(client: SupersoClient): Promise<void>;
18
- export declare function refreshToken(client: SupersoClient): Promise<any>;
41
+ export declare function refreshToken(client: SupersoClient): Promise<AuthResponse>;
19
42
  export declare function restoreSession(client: SupersoClient): Promise<any>;
20
43
  export declare function getCurrentUser(client: SupersoClient): Promise<any>;
21
44
  export declare function updateProfile(client: SupersoClient, data: {
@@ -63,4 +86,9 @@ export declare function verifyMagicLink(client: SupersoClient, payload: {
63
86
  export declare function getSessions(client: SupersoClient): Promise<any>;
64
87
  export declare function revokeSession(client: SupersoClient, sessionId: string): Promise<any>;
65
88
  export declare function revokeOtherSessions(client: SupersoClient): Promise<any>;
66
- export {};
89
+ export declare function signInWithGoogle(client: SupersoClient): Promise<any>;
90
+ export declare function signInWithFacebook(client: SupersoClient, options: {
91
+ appId: string;
92
+ redirectUri?: string;
93
+ }): Promise<any>;
94
+ export { saveSession, parseJwt, isTokenExpired, };
package/dist/auth/auth.js CHANGED
@@ -1,19 +1,43 @@
1
- // ================================
1
+ // ========================================
2
2
  // CONSTANTS
3
- // ================================
3
+ // ========================================
4
4
  const ACCESS_TOKEN_KEY = "superso_access_token";
5
5
  const REFRESH_TOKEN_KEY = "superso_refresh_token";
6
6
  const USER_KEY = "superso_auth_user";
7
+ const FACEBOOK_STATE_KEY = "superso_fb_state";
8
+ // ========================================
9
+ // HELPERS
10
+ // ========================================
11
+ function isBrowser() {
12
+ return (typeof window !==
13
+ "undefined");
14
+ }
15
+ function safeLocalStorage() {
16
+ if (!isBrowser())
17
+ return null;
18
+ return localStorage;
19
+ }
20
+ // ========================================
21
+ // AUTH LISTENERS
22
+ // ========================================
7
23
  const listeners = new Set();
8
24
  function emitAuth(payload) {
9
- listeners.forEach((callback) => callback(payload));
25
+ listeners.forEach((callback) => {
26
+ try {
27
+ callback(payload);
28
+ }
29
+ catch (error) {
30
+ console.error("Auth listener error:", error);
31
+ }
32
+ });
10
33
  }
11
- // ================================
34
+ // ========================================
12
35
  // JWT HELPERS
13
- // ================================
36
+ // ========================================
14
37
  function parseJwt(token) {
15
38
  try {
16
- return JSON.parse(atob(token.split(".")[1]));
39
+ const payload = token.split(".")[1];
40
+ return JSON.parse(atob(payload));
17
41
  }
18
42
  catch (_a) {
19
43
  return null;
@@ -28,42 +52,59 @@ function isTokenExpired(token) {
28
52
  1000 -
29
53
  5 * 60 * 1000);
30
54
  }
31
- // ================================
55
+ // ========================================
32
56
  // SESSION HELPERS
33
- // ================================
57
+ // ========================================
34
58
  function saveSession(data) {
59
+ const storage = safeLocalStorage();
60
+ if (!storage)
61
+ return;
35
62
  const token = data === null || data === void 0 ? void 0 : data.token;
36
63
  const refreshToken = data === null || data === void 0 ? void 0 : data.refresh_token;
37
64
  const user = data === null || data === void 0 ? void 0 : data.user;
38
65
  if (token) {
39
- localStorage.setItem(ACCESS_TOKEN_KEY, token);
66
+ storage.setItem(ACCESS_TOKEN_KEY, token);
40
67
  }
41
68
  if (refreshToken) {
42
- localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken);
69
+ storage.setItem(REFRESH_TOKEN_KEY, refreshToken);
43
70
  }
44
71
  if (user) {
45
- localStorage.setItem(USER_KEY, JSON.stringify(user));
72
+ storage.setItem(USER_KEY, JSON.stringify(user));
46
73
  }
47
74
  emitAuth({
48
75
  user,
76
+ token,
49
77
  });
50
78
  }
51
79
  export function clearSession() {
52
- localStorage.removeItem(ACCESS_TOKEN_KEY);
53
- localStorage.removeItem(REFRESH_TOKEN_KEY);
54
- localStorage.removeItem(USER_KEY);
80
+ const storage = safeLocalStorage();
81
+ if (!storage)
82
+ return;
83
+ storage.removeItem(ACCESS_TOKEN_KEY);
84
+ storage.removeItem(REFRESH_TOKEN_KEY);
85
+ storage.removeItem(USER_KEY);
55
86
  emitAuth({
56
87
  user: null,
88
+ token: null,
57
89
  });
58
90
  }
59
91
  export function getAccessToken() {
60
- return localStorage.getItem(ACCESS_TOKEN_KEY);
92
+ const storage = safeLocalStorage();
93
+ if (!storage)
94
+ return null;
95
+ return storage.getItem(ACCESS_TOKEN_KEY);
61
96
  }
62
97
  export function getRefreshToken() {
63
- return localStorage.getItem(REFRESH_TOKEN_KEY);
98
+ const storage = safeLocalStorage();
99
+ if (!storage)
100
+ return null;
101
+ return storage.getItem(REFRESH_TOKEN_KEY);
64
102
  }
65
103
  export function getStoredUser() {
66
- const raw = localStorage.getItem(USER_KEY);
104
+ const storage = safeLocalStorage();
105
+ if (!storage)
106
+ return null;
107
+ const raw = storage.getItem(USER_KEY);
67
108
  if (!raw)
68
109
  return null;
69
110
  try {
@@ -73,21 +114,51 @@ export function getStoredUser() {
73
114
  return null;
74
115
  }
75
116
  }
76
- // ================================
117
+ // ========================================
118
+ // GOOGLE SDK LOADER
119
+ // ========================================
120
+ async function loadGoogleSdk() {
121
+ if (!isBrowser())
122
+ return;
123
+ if (window.google) {
124
+ return;
125
+ }
126
+ return new Promise((resolve, reject) => {
127
+ const existing = document.getElementById("superso-google-sdk");
128
+ if (existing) {
129
+ resolve(true);
130
+ return;
131
+ }
132
+ const script = document.createElement("script");
133
+ script.id =
134
+ "superso-google-sdk";
135
+ script.src =
136
+ "https://accounts.google.com/gsi/client";
137
+ script.async = true;
138
+ script.defer = true;
139
+ script.onload =
140
+ () => resolve(true);
141
+ script.onerror =
142
+ () => reject(new Error("Failed to load Google SDK"));
143
+ document.body.appendChild(script);
144
+ });
145
+ }
146
+ // ========================================
77
147
  // CORE REQUEST
78
- // ================================
148
+ // ========================================
79
149
  async function request(client, endpoint, method = "GET", body = null, auth = false) {
80
150
  let token = getAccessToken();
81
- // auto refresh
151
+ // auto refresh token
82
152
  if (auth &&
83
153
  token &&
84
154
  isTokenExpired(token)) {
85
155
  try {
86
156
  const refreshed = await refreshToken(client);
87
157
  token =
88
- refreshed === null || refreshed === void 0 ? void 0 : refreshed.token;
158
+ (refreshed === null || refreshed === void 0 ? void 0 : refreshed.token) || null;
89
159
  }
90
- catch (_a) {
160
+ catch (error) {
161
+ console.error("Token refresh failed:", error);
91
162
  clearSession();
92
163
  }
93
164
  }
@@ -95,14 +166,15 @@ async function request(client, endpoint, method = "GET", body = null, auth = fal
95
166
  "Content-Type": "application/json",
96
167
  "X-Superso-Project-Key": client.apiKey,
97
168
  };
98
- if (auth && token) {
99
- headers["Authorization"] =
169
+ if (auth &&
170
+ token) {
171
+ headers.Authorization =
100
172
  `Bearer ${token}`;
101
173
  }
102
174
  const response = await fetch(`${client.baseUrl}/api/project/${client.projectId}${endpoint}`, {
103
175
  method,
104
176
  headers,
105
- body: body
177
+ body: body !== null
106
178
  ? JSON.stringify(body)
107
179
  : undefined,
108
180
  });
@@ -111,86 +183,94 @@ async function request(client, endpoint, method = "GET", body = null, auth = fal
111
183
  data =
112
184
  await response.json();
113
185
  }
114
- catch (_b) {
186
+ catch (_a) {
115
187
  data = {};
116
188
  }
117
189
  if (!response.ok) {
118
190
  throw new Error((data === null || data === void 0 ? void 0 : data.message) ||
191
+ (data === null || data === void 0 ? void 0 : data.error) ||
119
192
  "Request failed");
120
193
  }
121
194
  return data;
122
195
  }
123
- // ================================
196
+ // ========================================
124
197
  // AUTH STATE
125
- // ================================
198
+ // ========================================
126
199
  export function onAuthChange(callback) {
127
200
  listeners.add(callback);
128
201
  return () => {
129
202
  listeners.delete(callback);
130
203
  };
131
204
  }
132
- // ================================
133
- // MULTI TAB AUTH SYNC
134
- // ================================
135
- window.addEventListener("storage", (event) => {
136
- if (event.key ===
137
- ACCESS_TOKEN_KEY) {
138
- emitAuth({
139
- user: getStoredUser(),
140
- });
141
- }
142
- });
143
- // ================================
205
+ // ========================================
206
+ // MULTI TAB SYNC
207
+ // ========================================
208
+ if (isBrowser()) {
209
+ window.addEventListener("storage", (event) => {
210
+ if (event.key ===
211
+ ACCESS_TOKEN_KEY ||
212
+ event.key ===
213
+ USER_KEY) {
214
+ emitAuth({
215
+ user: getStoredUser(),
216
+ token: getAccessToken(),
217
+ });
218
+ }
219
+ });
220
+ }
221
+ // ========================================
144
222
  // REGISTER
145
- // ================================
223
+ // ========================================
146
224
  export async function register(client, payload) {
147
- const res = await request(client, "/auth/register", "POST", payload);
148
- if (res === null || res === void 0 ? void 0 : res.token) {
149
- saveSession(res);
225
+ const result = await request(client, "/auth/register", "POST", payload);
226
+ if (result === null || result === void 0 ? void 0 : result.token) {
227
+ saveSession(result);
150
228
  }
151
- return res;
229
+ return result;
152
230
  }
153
- // ================================
231
+ // ========================================
154
232
  // LOGIN
155
- // ================================
233
+ // ========================================
156
234
  export async function login(client, payload) {
157
- const res = await request(client, "/auth/login", "POST", payload);
158
- saveSession(res);
159
- return res;
235
+ const result = await request(client, "/auth/login", "POST", payload);
236
+ saveSession(result);
237
+ return result;
160
238
  }
161
- // ================================
239
+ // ========================================
162
240
  // LOGOUT
163
- // ================================
241
+ // ========================================
164
242
  export async function logout(client) {
165
243
  try {
166
244
  await request(client, "/auth/logout", "POST", {
167
245
  refresh_token: getRefreshToken(),
168
246
  }, true);
169
247
  }
170
- catch (_a) { }
248
+ catch (error) {
249
+ console.error(error);
250
+ }
171
251
  clearSession();
172
252
  }
173
- // ================================
253
+ // ========================================
174
254
  // REFRESH TOKEN
175
- // ================================
255
+ // ========================================
176
256
  export async function refreshToken(client) {
177
257
  const refresh_token = getRefreshToken();
178
258
  if (!refresh_token) {
179
259
  throw new Error("Missing refresh token");
180
260
  }
181
- const res = await request(client, "/auth/refresh-token", "POST", {
261
+ const result = await request(client, "/auth/refresh-token", "POST", {
182
262
  refresh_token,
183
263
  });
184
- saveSession(res);
264
+ saveSession(result);
185
265
  emitAuth({
186
266
  type: "token_rotated",
187
- token: res === null || res === void 0 ? void 0 : res.token,
267
+ token: result === null || result === void 0 ? void 0 : result.token,
188
268
  });
189
- return res;
269
+ return result;
190
270
  }
191
- // ================================
271
+ // ========================================
192
272
  // RESTORE SESSION
193
- // ================================
273
+ // ========================================
194
274
  export async function restoreSession(client) {
195
275
  const token = getAccessToken();
196
276
  if (!token)
@@ -206,74 +286,83 @@ export async function restoreSession(client) {
206
286
  });
207
287
  return me;
208
288
  }
209
- catch (_a) {
289
+ catch (error) {
290
+ console.error(error);
210
291
  clearSession();
211
292
  return null;
212
293
  }
213
294
  }
214
- // ================================
295
+ // ========================================
215
296
  // CURRENT USER
216
- // ================================
297
+ // ========================================
217
298
  export async function getCurrentUser(client) {
218
299
  return await request(client, "/auth/user/me", "GET", null, true);
219
300
  }
220
- // ================================
301
+ // ========================================
221
302
  // UPDATE PROFILE
222
- // ================================
303
+ // ========================================
223
304
  export async function updateProfile(client, data) {
224
- return await request(client, "/auth/user/profile", "PUT", data, true);
305
+ const result = await request(client, "/auth/user/profile", "PUT", data, true);
306
+ if (result === null || result === void 0 ? void 0 : result.user) {
307
+ const storage = safeLocalStorage();
308
+ storage === null || storage === void 0 ? void 0 : storage.setItem(USER_KEY, JSON.stringify(result.user));
309
+ emitAuth({
310
+ user: result.user,
311
+ });
312
+ }
313
+ return result;
225
314
  }
226
- // ================================
315
+ // ========================================
227
316
  // CHANGE PASSWORD
228
- // ================================
317
+ // ========================================
229
318
  export async function changePassword(client, data) {
230
319
  return await request(client, "/auth/user/change-password", "POST", data, true);
231
320
  }
232
- // ================================
321
+ // ========================================
233
322
  // CHANGE EMAIL
234
- // ================================
323
+ // ========================================
235
324
  export async function changeEmail(client, data) {
236
325
  return await request(client, "/auth/user/change-email", "POST", data, true);
237
326
  }
238
- // ================================
327
+ // ========================================
239
328
  // OTP LOGIN
240
- // ================================
329
+ // ========================================
241
330
  export async function sendOtpLogin(client, payload) {
242
331
  return await request(client, "/auth/otp-login", "POST", payload);
243
332
  }
244
- // ================================
333
+ // ========================================
245
334
  // VERIFY EMAIL
246
- // ================================
335
+ // ========================================
247
336
  export async function verifyEmail(client, payload) {
248
337
  return await request(client, "/auth/verify-email", "POST", payload);
249
338
  }
250
- // ================================
339
+ // ========================================
251
340
  // VERIFY PHONE
252
- // ================================
341
+ // ========================================
253
342
  export async function verifyPhone(client, payload) {
254
343
  return await request(client, "/auth/verify-phone", "POST", payload);
255
344
  }
256
- // ================================
345
+ // ========================================
257
346
  // PASSWORD RESET
258
- // ================================
347
+ // ========================================
259
348
  export async function sendPasswordReset(client, payload) {
260
349
  return await request(client, "/auth/send-reset", "POST", payload);
261
350
  }
262
351
  export async function confirmPasswordReset(client, payload) {
263
352
  return await request(client, "/auth/confirm-reset", "POST", payload);
264
353
  }
265
- // ================================
354
+ // ========================================
266
355
  // MAGIC LINK
267
- // ================================
356
+ // ========================================
268
357
  export async function sendMagicLink(client, payload) {
269
358
  return await request(client, "/auth/magic-link/send", "POST", payload);
270
359
  }
271
360
  export async function verifyMagicLink(client, payload) {
272
361
  return await request(client, "/auth/magic-link/verify", "POST", payload);
273
362
  }
274
- // ================================
363
+ // ========================================
275
364
  // SESSIONS
276
- // ================================
365
+ // ========================================
277
366
  export async function getSessions(client) {
278
367
  return await request(client, "/auth/user/sessions", "GET", null, true);
279
368
  }
@@ -283,3 +372,114 @@ export async function revokeSession(client, sessionId) {
283
372
  export async function revokeOtherSessions(client) {
284
373
  return await request(client, "/auth/user/sessions", "DELETE", null, true);
285
374
  }
375
+ // ========================================
376
+ // GOOGLE LOGIN
377
+ // ========================================
378
+ export async function signInWithGoogle(client) {
379
+ await loadGoogleSdk();
380
+ const config = await request(client, "/auth/providers/google/config", "GET");
381
+ const googleClientId = config === null || config === void 0 ? void 0 : config.client_id;
382
+ if (!googleClientId) {
383
+ throw new Error("Google auth not configured");
384
+ }
385
+ return new Promise((resolve, reject) => {
386
+ const google = window.google;
387
+ if (!google) {
388
+ reject(new Error("Google SDK not loaded"));
389
+ return;
390
+ }
391
+ google.accounts.id.initialize({
392
+ client_id: googleClientId,
393
+ callback: async (credentialResponse) => {
394
+ try {
395
+ const result = await request(client, "/auth/providers/google/credential", "POST", {
396
+ credential: credentialResponse.credential,
397
+ });
398
+ saveSession(result);
399
+ resolve(result);
400
+ }
401
+ catch (error) {
402
+ reject(error);
403
+ }
404
+ },
405
+ });
406
+ google.accounts.id.prompt();
407
+ });
408
+ }
409
+ // ========================================
410
+ // FACEBOOK LOGIN
411
+ // ========================================
412
+ export async function signInWithFacebook(client, options) {
413
+ if (!isBrowser()) {
414
+ throw new Error("Browser environment required");
415
+ }
416
+ const appId = options === null || options === void 0 ? void 0 : options.appId;
417
+ if (!appId) {
418
+ throw new Error("Facebook App ID required");
419
+ }
420
+ const redirectUri = (options === null || options === void 0 ? void 0 : options.redirectUri) ||
421
+ window.location.origin;
422
+ const state = crypto.randomUUID();
423
+ localStorage.setItem(FACEBOOK_STATE_KEY, state);
424
+ const authUrl = `https://www.facebook.com/v19.0/dialog/oauth` +
425
+ `?client_id=${appId}` +
426
+ `&redirect_uri=${encodeURIComponent(redirectUri)}` +
427
+ `&scope=email,public_profile` +
428
+ `&response_type=token` +
429
+ `&state=${state}`;
430
+ const popup = window.open(authUrl, "facebook-login", "width=600,height=700");
431
+ return new Promise((resolve, reject) => {
432
+ let stopped = false;
433
+ const stop = () => {
434
+ if (stopped)
435
+ return;
436
+ stopped =
437
+ true;
438
+ clearInterval(interval);
439
+ };
440
+ const interval = setInterval(async () => {
441
+ try {
442
+ if (!popup ||
443
+ popup.closed) {
444
+ stop();
445
+ reject(new Error("Facebook login cancelled"));
446
+ return;
447
+ }
448
+ const hash = popup.location
449
+ .hash;
450
+ if (hash &&
451
+ hash.includes("access_token")) {
452
+ stop();
453
+ const params = new URLSearchParams(hash.replace("#", ""));
454
+ const accessToken = params.get("access_token");
455
+ const returnedState = params.get("state");
456
+ const savedState = localStorage.getItem(FACEBOOK_STATE_KEY);
457
+ if (returnedState !==
458
+ savedState) {
459
+ popup.close();
460
+ reject(new Error("Invalid Facebook state"));
461
+ return;
462
+ }
463
+ popup.close();
464
+ localStorage.removeItem(FACEBOOK_STATE_KEY);
465
+ const result = await request(client, "/auth/providers/facebook/login", "POST", {
466
+ access_token: accessToken,
467
+ });
468
+ saveSession(result);
469
+ resolve(result);
470
+ }
471
+ }
472
+ catch (_a) { }
473
+ }, 1000);
474
+ setTimeout(() => {
475
+ stop();
476
+ reject(new Error("Facebook login timeout"));
477
+ }, 1000 *
478
+ 60 *
479
+ 5);
480
+ });
481
+ }
482
+ // ========================================
483
+ // EXPORTS
484
+ // ========================================
485
+ export { saveSession, parseJwt, isTokenExpired, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "superso-js-sdk",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Official Superso JavaScript SDK",
5
5
 
6
6
  "type": "module",