@insforge/sdk 1.0.1-refresh.4 → 1.0.1-refresh.6
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/index.d.mts +14 -8
- package/dist/index.d.ts +14 -8
- package/dist/index.js +81 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +81 -21
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -146,8 +146,9 @@ interface SessionStorageStrategy {
|
|
|
146
146
|
* Secure Session Storage Strategy
|
|
147
147
|
*
|
|
148
148
|
* Stores access token in memory only (cleared on page refresh).
|
|
149
|
-
* Refresh token is stored in httpOnly cookie by the backend.
|
|
150
|
-
* The `isAuthenticated` cookie is set by the
|
|
149
|
+
* Refresh token is stored in httpOnly cookie by the backend (on backend domain).
|
|
150
|
+
* The `isAuthenticated` cookie is set by the SDK on the frontend domain to signal
|
|
151
|
+
* that a secure session exists and token refresh should be attempted on page reload.
|
|
151
152
|
*
|
|
152
153
|
* Security benefits:
|
|
153
154
|
* - Access token not accessible to XSS attacks (in memory only)
|
|
@@ -281,12 +282,17 @@ declare class Auth {
|
|
|
281
282
|
private database;
|
|
282
283
|
constructor(http: HttpClient, tokenManager: TokenManager);
|
|
283
284
|
/**
|
|
284
|
-
*
|
|
285
|
+
* Set the isAuthenticated cookie flag on the frontend domain
|
|
286
|
+
* This is managed by SDK, not backend, to work in cross-origin scenarios
|
|
285
287
|
*/
|
|
286
|
-
private
|
|
288
|
+
private setAuthenticatedCookie;
|
|
289
|
+
/**
|
|
290
|
+
* Clear the isAuthenticated cookie flag from the frontend domain
|
|
291
|
+
*/
|
|
292
|
+
private clearAuthenticatedCookie;
|
|
287
293
|
/**
|
|
288
294
|
* Switch to SecureSessionStorage (cookie-based auth)
|
|
289
|
-
* Called when
|
|
295
|
+
* Called when backend returns sessionMode: 'secure'
|
|
290
296
|
* @internal
|
|
291
297
|
*/
|
|
292
298
|
_switchToSecureStorage(): void;
|
|
@@ -297,11 +303,11 @@ declare class Auth {
|
|
|
297
303
|
*/
|
|
298
304
|
_switchToLocalStorage(): void;
|
|
299
305
|
/**
|
|
300
|
-
* Detect storage strategy
|
|
301
|
-
*
|
|
306
|
+
* Detect storage strategy based on backend response
|
|
307
|
+
* @param sessionMode - The sessionMode returned by backend ('secure' or undefined)
|
|
302
308
|
* @internal
|
|
303
309
|
*/
|
|
304
|
-
private
|
|
310
|
+
private _detectStorageFromResponse;
|
|
305
311
|
/**
|
|
306
312
|
* Automatically detect and handle OAuth callback parameters in the URL
|
|
307
313
|
* This runs on initialization to seamlessly complete the OAuth flow
|
package/dist/index.d.ts
CHANGED
|
@@ -146,8 +146,9 @@ interface SessionStorageStrategy {
|
|
|
146
146
|
* Secure Session Storage Strategy
|
|
147
147
|
*
|
|
148
148
|
* Stores access token in memory only (cleared on page refresh).
|
|
149
|
-
* Refresh token is stored in httpOnly cookie by the backend.
|
|
150
|
-
* The `isAuthenticated` cookie is set by the
|
|
149
|
+
* Refresh token is stored in httpOnly cookie by the backend (on backend domain).
|
|
150
|
+
* The `isAuthenticated` cookie is set by the SDK on the frontend domain to signal
|
|
151
|
+
* that a secure session exists and token refresh should be attempted on page reload.
|
|
151
152
|
*
|
|
152
153
|
* Security benefits:
|
|
153
154
|
* - Access token not accessible to XSS attacks (in memory only)
|
|
@@ -281,12 +282,17 @@ declare class Auth {
|
|
|
281
282
|
private database;
|
|
282
283
|
constructor(http: HttpClient, tokenManager: TokenManager);
|
|
283
284
|
/**
|
|
284
|
-
*
|
|
285
|
+
* Set the isAuthenticated cookie flag on the frontend domain
|
|
286
|
+
* This is managed by SDK, not backend, to work in cross-origin scenarios
|
|
285
287
|
*/
|
|
286
|
-
private
|
|
288
|
+
private setAuthenticatedCookie;
|
|
289
|
+
/**
|
|
290
|
+
* Clear the isAuthenticated cookie flag from the frontend domain
|
|
291
|
+
*/
|
|
292
|
+
private clearAuthenticatedCookie;
|
|
287
293
|
/**
|
|
288
294
|
* Switch to SecureSessionStorage (cookie-based auth)
|
|
289
|
-
* Called when
|
|
295
|
+
* Called when backend returns sessionMode: 'secure'
|
|
290
296
|
* @internal
|
|
291
297
|
*/
|
|
292
298
|
_switchToSecureStorage(): void;
|
|
@@ -297,11 +303,11 @@ declare class Auth {
|
|
|
297
303
|
*/
|
|
298
304
|
_switchToLocalStorage(): void;
|
|
299
305
|
/**
|
|
300
|
-
* Detect storage strategy
|
|
301
|
-
*
|
|
306
|
+
* Detect storage strategy based on backend response
|
|
307
|
+
* @param sessionMode - The sessionMode returned by backend ('secure' or undefined)
|
|
302
308
|
* @internal
|
|
303
309
|
*/
|
|
304
|
-
private
|
|
310
|
+
private _detectStorageFromResponse;
|
|
305
311
|
/**
|
|
306
312
|
* Automatically detect and handle OAuth callback parameters in the URL
|
|
307
313
|
* This runs on initialization to seamlessly complete the OAuth flow
|
package/dist/index.js
CHANGED
|
@@ -267,7 +267,7 @@ var SecureSessionStorage = class {
|
|
|
267
267
|
if (this.accessToken) return false;
|
|
268
268
|
return this.hasAuthFlag();
|
|
269
269
|
}
|
|
270
|
-
// --- Private: Auth Flag Cookie Detection (
|
|
270
|
+
// --- Private: Auth Flag Cookie Detection (SDK-managed on frontend domain) ---
|
|
271
271
|
hasAuthFlag() {
|
|
272
272
|
if (typeof document === "undefined") return false;
|
|
273
273
|
return document.cookie.split(";").some(
|
|
@@ -531,27 +531,41 @@ var Auth = class {
|
|
|
531
531
|
this.detectAuthCallback();
|
|
532
532
|
}
|
|
533
533
|
/**
|
|
534
|
-
*
|
|
534
|
+
* Set the isAuthenticated cookie flag on the frontend domain
|
|
535
|
+
* This is managed by SDK, not backend, to work in cross-origin scenarios
|
|
535
536
|
*/
|
|
536
|
-
|
|
537
|
-
if (typeof document === "undefined") return
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
537
|
+
setAuthenticatedCookie() {
|
|
538
|
+
if (typeof document === "undefined") return;
|
|
539
|
+
const maxAge = 7 * 24 * 60 * 60;
|
|
540
|
+
document.cookie = `${AUTH_FLAG_COOKIE}=true; path=/; max-age=${maxAge}; SameSite=Lax`;
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Clear the isAuthenticated cookie flag from the frontend domain
|
|
544
|
+
*/
|
|
545
|
+
clearAuthenticatedCookie() {
|
|
546
|
+
if (typeof document === "undefined") return;
|
|
547
|
+
document.cookie = `${AUTH_FLAG_COOKIE}=; path=/; max-age=0; SameSite=Lax`;
|
|
541
548
|
}
|
|
542
549
|
/**
|
|
543
550
|
* Switch to SecureSessionStorage (cookie-based auth)
|
|
544
|
-
* Called when
|
|
551
|
+
* Called when backend returns sessionMode: 'secure'
|
|
545
552
|
* @internal
|
|
546
553
|
*/
|
|
547
554
|
_switchToSecureStorage() {
|
|
548
|
-
|
|
555
|
+
console.log("[InsForge:Auth] _switchToSecureStorage() called, current strategy:", this.tokenManager.getStrategyId());
|
|
556
|
+
if (this.tokenManager.getStrategyId() === "secure") {
|
|
557
|
+
console.log("[InsForge:Auth] _switchToSecureStorage() - already in secure mode, skipping");
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
549
560
|
const currentSession = this.tokenManager.getSession();
|
|
550
561
|
this.tokenManager.setStrategy(new SecureSessionStorage());
|
|
551
562
|
if (typeof localStorage !== "undefined") {
|
|
563
|
+
console.log("[InsForge:Auth] _switchToSecureStorage() - clearing localStorage");
|
|
552
564
|
localStorage.removeItem(TOKEN_KEY);
|
|
553
565
|
localStorage.removeItem(USER_KEY);
|
|
554
566
|
}
|
|
567
|
+
console.log("[InsForge:Auth] _switchToSecureStorage() - setting isAuthenticated cookie");
|
|
568
|
+
this.setAuthenticatedCookie();
|
|
555
569
|
if (currentSession) {
|
|
556
570
|
this.tokenManager.saveSession(currentSession);
|
|
557
571
|
}
|
|
@@ -565,17 +579,19 @@ var Auth = class {
|
|
|
565
579
|
if (this.tokenManager.getStrategyId() === "local") return;
|
|
566
580
|
const currentSession = this.tokenManager.getSession();
|
|
567
581
|
this.tokenManager.setStrategy(new LocalSessionStorage());
|
|
582
|
+
this.clearAuthenticatedCookie();
|
|
568
583
|
if (currentSession) {
|
|
569
584
|
this.tokenManager.saveSession(currentSession);
|
|
570
585
|
}
|
|
571
586
|
}
|
|
572
587
|
/**
|
|
573
|
-
* Detect storage strategy
|
|
574
|
-
*
|
|
588
|
+
* Detect storage strategy based on backend response
|
|
589
|
+
* @param sessionMode - The sessionMode returned by backend ('secure' or undefined)
|
|
575
590
|
* @internal
|
|
576
591
|
*/
|
|
577
|
-
|
|
578
|
-
|
|
592
|
+
_detectStorageFromResponse(sessionMode) {
|
|
593
|
+
console.log("[InsForge:Auth] _detectStorageFromResponse() - sessionMode:", sessionMode);
|
|
594
|
+
if (sessionMode === "secure") {
|
|
579
595
|
this._switchToSecureStorage();
|
|
580
596
|
}
|
|
581
597
|
}
|
|
@@ -592,8 +608,9 @@ var Auth = class {
|
|
|
592
608
|
const userId = params.get("user_id");
|
|
593
609
|
const email = params.get("email");
|
|
594
610
|
const name = params.get("name");
|
|
611
|
+
const sessionMode = params.get("session_mode");
|
|
595
612
|
if (accessToken && userId && email) {
|
|
596
|
-
this.
|
|
613
|
+
this._detectStorageFromResponse(sessionMode || void 0);
|
|
597
614
|
const session = {
|
|
598
615
|
accessToken,
|
|
599
616
|
user: {
|
|
@@ -614,6 +631,7 @@ var Auth = class {
|
|
|
614
631
|
url.searchParams.delete("user_id");
|
|
615
632
|
url.searchParams.delete("email");
|
|
616
633
|
url.searchParams.delete("name");
|
|
634
|
+
url.searchParams.delete("session_mode");
|
|
617
635
|
if (params.has("error")) {
|
|
618
636
|
url.searchParams.delete("error");
|
|
619
637
|
}
|
|
@@ -629,6 +647,8 @@ var Auth = class {
|
|
|
629
647
|
async signUp(request) {
|
|
630
648
|
try {
|
|
631
649
|
const response = await this.http.post("/api/auth/users", request);
|
|
650
|
+
const sessionMode = response.sessionMode;
|
|
651
|
+
this._detectStorageFromResponse(sessionMode);
|
|
632
652
|
if (response.accessToken && response.user) {
|
|
633
653
|
const session = {
|
|
634
654
|
accessToken: response.accessToken,
|
|
@@ -638,7 +658,6 @@ var Auth = class {
|
|
|
638
658
|
this.tokenManager.saveSession(session);
|
|
639
659
|
}
|
|
640
660
|
this.http.setAuthToken(response.accessToken);
|
|
641
|
-
this._detectStorageAfterAuth();
|
|
642
661
|
}
|
|
643
662
|
return {
|
|
644
663
|
data: response,
|
|
@@ -664,6 +683,8 @@ var Auth = class {
|
|
|
664
683
|
async signInWithPassword(request) {
|
|
665
684
|
try {
|
|
666
685
|
const response = await this.http.post("/api/auth/sessions", request);
|
|
686
|
+
const sessionMode = response.sessionMode;
|
|
687
|
+
this._detectStorageFromResponse(sessionMode);
|
|
667
688
|
const session = {
|
|
668
689
|
accessToken: response.accessToken || "",
|
|
669
690
|
user: response.user || {
|
|
@@ -679,7 +700,6 @@ var Auth = class {
|
|
|
679
700
|
this.tokenManager.saveSession(session);
|
|
680
701
|
}
|
|
681
702
|
this.http.setAuthToken(response.accessToken || "");
|
|
682
|
-
this._detectStorageAfterAuth();
|
|
683
703
|
return {
|
|
684
704
|
data: response,
|
|
685
705
|
error: null
|
|
@@ -737,17 +757,25 @@ var Auth = class {
|
|
|
737
757
|
* In modern mode, also calls backend to clear the refresh token cookie
|
|
738
758
|
*/
|
|
739
759
|
async signOut() {
|
|
760
|
+
console.log("[InsForge:Auth] signOut() called");
|
|
761
|
+
console.log("[InsForge:Auth] signOut() stack trace:", new Error().stack);
|
|
740
762
|
try {
|
|
741
763
|
if (this.tokenManager.getStrategyId() === "secure") {
|
|
764
|
+
console.log("[InsForge:Auth] signOut() - calling backend /api/auth/logout");
|
|
742
765
|
try {
|
|
743
766
|
await this.http.post("/api/auth/logout");
|
|
744
|
-
|
|
767
|
+
console.log("[InsForge:Auth] signOut() - backend logout successful");
|
|
768
|
+
} catch (e) {
|
|
769
|
+
console.log("[InsForge:Auth] signOut() - backend logout failed (ignored):", e);
|
|
745
770
|
}
|
|
746
771
|
}
|
|
747
772
|
this.tokenManager.clearSession();
|
|
748
773
|
this.http.setAuthToken(null);
|
|
774
|
+
this.clearAuthenticatedCookie();
|
|
775
|
+
console.log("[InsForge:Auth] signOut() - completed");
|
|
749
776
|
return { error: null };
|
|
750
777
|
} catch (error) {
|
|
778
|
+
console.error("[InsForge:Auth] signOut() - error:", error);
|
|
751
779
|
return {
|
|
752
780
|
error: new InsForgeError(
|
|
753
781
|
"Failed to sign out",
|
|
@@ -764,16 +792,20 @@ var Auth = class {
|
|
|
764
792
|
* @returns New access token or throws an error
|
|
765
793
|
*/
|
|
766
794
|
async refreshToken() {
|
|
795
|
+
console.log("[InsForge:Auth] refreshToken() called");
|
|
767
796
|
try {
|
|
768
797
|
const response = await this.http.post(
|
|
769
798
|
"/api/auth/refresh"
|
|
770
799
|
);
|
|
800
|
+
console.log("[InsForge:Auth] refreshToken() - response received, hasAccessToken:", !!response.accessToken);
|
|
771
801
|
if (response.accessToken) {
|
|
802
|
+
this._detectStorageFromResponse(response.sessionMode);
|
|
772
803
|
this.tokenManager.setAccessToken(response.accessToken);
|
|
773
804
|
this.http.setAuthToken(response.accessToken);
|
|
774
805
|
if (response.user) {
|
|
775
806
|
this.tokenManager.setUser(response.user);
|
|
776
807
|
}
|
|
808
|
+
console.log("[InsForge:Auth] refreshToken() - success");
|
|
777
809
|
return response.accessToken;
|
|
778
810
|
}
|
|
779
811
|
throw new InsForgeError(
|
|
@@ -782,10 +814,13 @@ var Auth = class {
|
|
|
782
814
|
"REFRESH_FAILED"
|
|
783
815
|
);
|
|
784
816
|
} catch (error) {
|
|
817
|
+
console.error("[InsForge:Auth] refreshToken() - error:", error);
|
|
785
818
|
if (error instanceof InsForgeError) {
|
|
786
819
|
if (error.statusCode === 401 || error.statusCode === 403) {
|
|
820
|
+
console.log("[InsForge:Auth] refreshToken() - clearing session due to 401/403");
|
|
787
821
|
this.tokenManager.clearSession();
|
|
788
822
|
this.http.setAuthToken(null);
|
|
823
|
+
this.clearAuthenticatedCookie();
|
|
789
824
|
}
|
|
790
825
|
throw error;
|
|
791
826
|
}
|
|
@@ -841,12 +876,17 @@ var Auth = class {
|
|
|
841
876
|
* to refresh the session if no access token is available (e.g., after page reload).
|
|
842
877
|
*/
|
|
843
878
|
async getCurrentUser() {
|
|
879
|
+
console.log("[InsForge:Auth] getCurrentUser() called");
|
|
844
880
|
try {
|
|
845
881
|
let accessToken = this.tokenManager.getAccessToken();
|
|
846
|
-
|
|
882
|
+
const shouldRefresh = this.tokenManager.shouldAttemptRefresh();
|
|
883
|
+
console.log("[InsForge:Auth] getCurrentUser() - hasAccessToken:", !!accessToken, "shouldAttemptRefresh:", shouldRefresh);
|
|
884
|
+
if (!accessToken && shouldRefresh) {
|
|
885
|
+
console.log("[InsForge:Auth] getCurrentUser() - attempting refresh");
|
|
847
886
|
try {
|
|
848
887
|
accessToken = await this.refreshToken();
|
|
849
888
|
} catch (error) {
|
|
889
|
+
console.log("[InsForge:Auth] getCurrentUser() - refresh failed:", error);
|
|
850
890
|
if (error instanceof InsForgeError && (error.statusCode === 401 || error.statusCode === 403)) {
|
|
851
891
|
return { data: null, error };
|
|
852
892
|
}
|
|
@@ -854,14 +894,17 @@ var Auth = class {
|
|
|
854
894
|
}
|
|
855
895
|
}
|
|
856
896
|
if (!accessToken) {
|
|
897
|
+
console.log("[InsForge:Auth] getCurrentUser() - no access token, returning null");
|
|
857
898
|
return { data: null, error: null };
|
|
858
899
|
}
|
|
859
900
|
this.http.setAuthToken(accessToken);
|
|
901
|
+
console.log("[InsForge:Auth] getCurrentUser() - fetching user from API");
|
|
860
902
|
const authResponse = await this.http.get("/api/auth/sessions/current");
|
|
861
903
|
const { data: profile, error: profileError } = await this.database.from("users").select("*").eq("id", authResponse.user.id).single();
|
|
862
904
|
if (profileError && profileError.code !== "PGRST116") {
|
|
863
905
|
return { data: null, error: profileError };
|
|
864
906
|
}
|
|
907
|
+
console.log("[InsForge:Auth] getCurrentUser() - success");
|
|
865
908
|
return {
|
|
866
909
|
data: {
|
|
867
910
|
user: authResponse.user,
|
|
@@ -870,8 +913,12 @@ var Auth = class {
|
|
|
870
913
|
error: null
|
|
871
914
|
};
|
|
872
915
|
} catch (error) {
|
|
916
|
+
console.error("[InsForge:Auth] getCurrentUser() - catch error:", error);
|
|
873
917
|
if (error instanceof InsForgeError && error.statusCode === 401) {
|
|
874
|
-
|
|
918
|
+
console.log("[InsForge:Auth] getCurrentUser() - 401 error, clearing local session only (NOT calling signOut)");
|
|
919
|
+
this.tokenManager.clearSession();
|
|
920
|
+
this.http.setAuthToken(null);
|
|
921
|
+
this.clearAuthenticatedCookie();
|
|
875
922
|
return { data: null, error: null };
|
|
876
923
|
}
|
|
877
924
|
if (error instanceof InsForgeError) {
|
|
@@ -1119,6 +1166,8 @@ var Auth = class {
|
|
|
1119
1166
|
"/api/auth/email/verify",
|
|
1120
1167
|
request
|
|
1121
1168
|
);
|
|
1169
|
+
const sessionMode = response.sessionMode;
|
|
1170
|
+
this._detectStorageFromResponse(sessionMode);
|
|
1122
1171
|
if (response.accessToken) {
|
|
1123
1172
|
const session = {
|
|
1124
1173
|
accessToken: response.accessToken,
|
|
@@ -1677,9 +1726,14 @@ function hasAuthenticatedCookie() {
|
|
|
1677
1726
|
}
|
|
1678
1727
|
var InsForgeClient = class {
|
|
1679
1728
|
constructor(config = {}) {
|
|
1729
|
+
console.log("[InsForge:Client] Initializing SDK");
|
|
1680
1730
|
this.http = new HttpClient(config);
|
|
1681
1731
|
this.tokenManager = new TokenManager(config.storage);
|
|
1682
|
-
|
|
1732
|
+
const hasAuthCookie = hasAuthenticatedCookie();
|
|
1733
|
+
console.log("[InsForge:Client] hasAuthenticatedCookie:", hasAuthCookie);
|
|
1734
|
+
console.log("[InsForge:Client] document.cookie:", typeof document !== "undefined" ? document.cookie : "N/A (SSR)");
|
|
1735
|
+
if (hasAuthCookie) {
|
|
1736
|
+
console.log("[InsForge:Client] Switching to SecureSessionStorage");
|
|
1683
1737
|
this.tokenManager.setStrategy(new SecureSessionStorage());
|
|
1684
1738
|
}
|
|
1685
1739
|
if (config.edgeFunctionToken) {
|
|
@@ -1691,25 +1745,31 @@ var InsForgeClient = class {
|
|
|
1691
1745
|
});
|
|
1692
1746
|
}
|
|
1693
1747
|
this.http.setRefreshCallback(async () => {
|
|
1748
|
+
console.log("[InsForge:Client] HTTP 401 refresh callback triggered");
|
|
1694
1749
|
try {
|
|
1695
1750
|
return await this.auth.refreshToken();
|
|
1696
|
-
} catch {
|
|
1751
|
+
} catch (e) {
|
|
1752
|
+
console.log("[InsForge:Client] Refresh callback failed:", e);
|
|
1697
1753
|
if (this.tokenManager.getStrategyId() === "secure") {
|
|
1754
|
+
console.log("[InsForge:Client] Falling back to LocalSessionStorage");
|
|
1698
1755
|
this.auth._switchToLocalStorage();
|
|
1699
1756
|
}
|
|
1700
1757
|
return null;
|
|
1701
1758
|
}
|
|
1702
1759
|
});
|
|
1703
1760
|
const existingSession = this.tokenManager.getSession();
|
|
1761
|
+
console.log("[InsForge:Client] existingSession:", !!existingSession, "strategyId:", this.tokenManager.getStrategyId());
|
|
1704
1762
|
if (existingSession?.accessToken) {
|
|
1705
1763
|
this.http.setAuthToken(existingSession.accessToken);
|
|
1706
1764
|
} else if (this.tokenManager.getStrategyId() === "secure") {
|
|
1765
|
+
console.log("[InsForge:Client] Secure mode, no session in memory - will refresh on first API call");
|
|
1707
1766
|
}
|
|
1708
1767
|
this.auth = new Auth(this.http, this.tokenManager);
|
|
1709
1768
|
this.database = new Database(this.http, this.tokenManager);
|
|
1710
1769
|
this.storage = new Storage(this.http);
|
|
1711
1770
|
this.ai = new AI(this.http);
|
|
1712
1771
|
this.functions = new Functions(this.http);
|
|
1772
|
+
console.log("[InsForge:Client] SDK initialized");
|
|
1713
1773
|
}
|
|
1714
1774
|
/**
|
|
1715
1775
|
* Get the underlying HTTP client for custom requests
|