@insforge/react 0.6.4 → 0.6.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.cts CHANGED
@@ -14,6 +14,10 @@ import '@insforge/sdk';
14
14
  import '@insforge/shared-schemas';
15
15
  import 'zod';
16
16
 
17
+ interface InitialAuthState {
18
+ user?: InsforgeUser | null;
19
+ userId?: string | null;
20
+ }
17
21
  interface InsforgeProviderProps {
18
22
  children: ReactNode;
19
23
  baseUrl: string;
@@ -25,6 +29,11 @@ interface InsforgeProviderProps {
25
29
  onAuthChange?: (user: InsforgeUser | null) => void;
26
30
  onSignIn?: (authToken: string) => Promise<void>;
27
31
  onSignOut?: () => Promise<void>;
32
+ /**
33
+ * Initial auth state from server (for SSR hydration)
34
+ * @internal - Not intended for public use, used by Next.js package
35
+ */
36
+ initialState?: InitialAuthState;
28
37
  }
29
38
  /**
30
39
  * Unified Insforge Provider - manages authentication state and configuration
@@ -64,7 +73,7 @@ interface InsforgeProviderProps {
64
73
  * </InsforgeProvider>
65
74
  * ```
66
75
  */
67
- declare function InsforgeProviderCore({ children, baseUrl, afterSignInUrl, onAuthChange, onSignIn, onSignOut, }: InsforgeProviderProps): react_jsx_runtime.JSX.Element;
76
+ declare function InsforgeProviderCore({ children, baseUrl, afterSignInUrl, onAuthChange, onSignIn, onSignOut, initialState, }: InsforgeProviderProps): react_jsx_runtime.JSX.Element;
68
77
  declare function InsforgeProvider(props: InsforgeProviderProps): react_jsx_runtime.JSX.Element;
69
78
  /**
70
79
  * Hook to access Insforge context
@@ -100,4 +109,4 @@ declare function getProviderConfig(provider: OAuthProvider): OAuthProviderConfig
100
109
  */
101
110
  declare function getAllProviderConfigs(): Partial<Record<OAuthProvider, OAuthProviderConfig>>;
102
111
 
103
- export { InsforgeProvider, InsforgeProviderCore, type InsforgeProviderProps, OAUTH_PROVIDER_CONFIG, OAuthProviderConfig, getAllProviderConfigs, getProviderConfig, useInsforge };
112
+ export { type InitialAuthState, InsforgeProvider, InsforgeProviderCore, type InsforgeProviderProps, OAUTH_PROVIDER_CONFIG, OAuthProviderConfig, getAllProviderConfigs, getProviderConfig, useInsforge };
package/dist/index.d.ts CHANGED
@@ -14,6 +14,10 @@ import '@insforge/sdk';
14
14
  import '@insforge/shared-schemas';
15
15
  import 'zod';
16
16
 
17
+ interface InitialAuthState {
18
+ user?: InsforgeUser | null;
19
+ userId?: string | null;
20
+ }
17
21
  interface InsforgeProviderProps {
18
22
  children: ReactNode;
19
23
  baseUrl: string;
@@ -25,6 +29,11 @@ interface InsforgeProviderProps {
25
29
  onAuthChange?: (user: InsforgeUser | null) => void;
26
30
  onSignIn?: (authToken: string) => Promise<void>;
27
31
  onSignOut?: () => Promise<void>;
32
+ /**
33
+ * Initial auth state from server (for SSR hydration)
34
+ * @internal - Not intended for public use, used by Next.js package
35
+ */
36
+ initialState?: InitialAuthState;
28
37
  }
29
38
  /**
30
39
  * Unified Insforge Provider - manages authentication state and configuration
@@ -64,7 +73,7 @@ interface InsforgeProviderProps {
64
73
  * </InsforgeProvider>
65
74
  * ```
66
75
  */
67
- declare function InsforgeProviderCore({ children, baseUrl, afterSignInUrl, onAuthChange, onSignIn, onSignOut, }: InsforgeProviderProps): react_jsx_runtime.JSX.Element;
76
+ declare function InsforgeProviderCore({ children, baseUrl, afterSignInUrl, onAuthChange, onSignIn, onSignOut, initialState, }: InsforgeProviderProps): react_jsx_runtime.JSX.Element;
68
77
  declare function InsforgeProvider(props: InsforgeProviderProps): react_jsx_runtime.JSX.Element;
69
78
  /**
70
79
  * Hook to access Insforge context
@@ -100,4 +109,4 @@ declare function getProviderConfig(provider: OAuthProvider): OAuthProviderConfig
100
109
  */
101
110
  declare function getAllProviderConfigs(): Partial<Record<OAuthProvider, OAuthProviderConfig>>;
102
111
 
103
- export { InsforgeProvider, InsforgeProviderCore, type InsforgeProviderProps, OAUTH_PROVIDER_CONFIG, OAuthProviderConfig, getAllProviderConfigs, getProviderConfig, useInsforge };
112
+ export { type InitialAuthState, InsforgeProvider, InsforgeProviderCore, type InsforgeProviderProps, OAUTH_PROVIDER_CONFIG, OAuthProviderConfig, getAllProviderConfigs, getProviderConfig, useInsforge };
package/dist/index.js CHANGED
@@ -67,7 +67,7 @@ var InsforgeManager = class _InsforgeManager {
67
67
  // Static private instance
68
68
  static instance = null;
69
69
  // State storage
70
- user = null;
70
+ user = void 0;
71
71
  isLoaded = false;
72
72
  isInitializing = false;
73
73
  sdk;
@@ -80,11 +80,8 @@ var InsforgeManager = class _InsforgeManager {
80
80
  constructor(config) {
81
81
  this.config = config;
82
82
  this.sdk = createClient({ baseUrl: config.baseUrl });
83
- const session = this.sdk.auth.getCurrentSession();
84
- if (!session.data?.session?.accessToken) {
85
- this.isLoaded = true;
86
- this.user = null;
87
- }
83
+ this.user = void 0;
84
+ this.isLoaded = false;
88
85
  }
89
86
  // Public access method (Singleton core)
90
87
  static getInstance(config) {
@@ -107,26 +104,36 @@ var InsforgeManager = class _InsforgeManager {
107
104
  this.config = { ...this.config, ...config };
108
105
  }
109
106
  // Public initialization method
107
+ // Following Clerk's pattern: Even if we have initialState (isLoaded=true from cookies),
108
+ // we still need to load full user data from SDK/API
110
109
  async initialize() {
111
- if (this.isLoaded) {
112
- return;
113
- }
114
110
  if (this.isInitializing) {
115
111
  return;
116
112
  }
117
113
  this.isInitializing = true;
118
114
  try {
119
- await this.loadAuthState();
115
+ const sessionResult = this.sdk.auth.getCurrentSession();
116
+ const hasToken = !!sessionResult.data?.session?.accessToken;
117
+ if (hasToken) {
118
+ await this.loadAuthState();
119
+ } else if (this.user === void 0) {
120
+ this.user = null;
121
+ this.isLoaded = true;
122
+ this.notifyListeners();
123
+ }
120
124
  } finally {
121
125
  this.isInitializing = false;
122
126
  }
123
127
  }
124
128
  // Get current state
125
129
  getState() {
130
+ const userId = this.user === void 0 ? void 0 : this.user === null ? null : this.user.id;
131
+ const isSignedIn = this.user === void 0 ? void 0 : this.user !== null;
126
132
  return {
127
133
  user: this.user,
134
+ userId,
128
135
  isLoaded: this.isLoaded,
129
- isSignedIn: !!this.user
136
+ isSignedIn
130
137
  };
131
138
  }
132
139
  // Subscription mechanism
@@ -139,6 +146,8 @@ var InsforgeManager = class _InsforgeManager {
139
146
  this.listeners.forEach((listener) => listener(state));
140
147
  }
141
148
  // Load auth state
149
+ // This loads the FULL user data from SDK (including complete profile)
150
+ // Called after hydration to get complete user information beyond what's in cookies
142
151
  async loadAuthState() {
143
152
  try {
144
153
  const sessionResult = this.sdk.auth.getCurrentSession();
@@ -161,6 +170,7 @@ var InsforgeManager = class _InsforgeManager {
161
170
  email: userResult.data.user.email,
162
171
  name: profile?.nickname || "",
163
172
  avatarUrl: profile?.avatarUrl || ""
173
+ // You can add more profile fields here as needed
164
174
  };
165
175
  this.user = userData;
166
176
  if (this.config.onAuthChange) {
@@ -421,6 +431,22 @@ var InsforgeManager = class _InsforgeManager {
421
431
  }
422
432
  this.notifyListeners();
423
433
  }
434
+ // Set initial state from server (for SSR hydration)
435
+ // This is ONLY basic user info from cookies, not full profile
436
+ // Following Clerk's pattern: initialState prevents hydration mismatch
437
+ // but full user data is still loaded via initialize()
438
+ setInitialState(initialState) {
439
+ if (this.user !== void 0) {
440
+ return;
441
+ }
442
+ if (initialState.userId) {
443
+ this.user = initialState.user ?? null;
444
+ } else {
445
+ this.user = null;
446
+ }
447
+ this.isLoaded = true;
448
+ this.notifyListeners();
449
+ }
424
450
  getConfig() {
425
451
  return this.config;
426
452
  }
@@ -461,7 +487,8 @@ function InsforgeProviderCore({
461
487
  afterSignInUrl = "/",
462
488
  onAuthChange,
463
489
  onSignIn,
464
- onSignOut
490
+ onSignOut,
491
+ initialState
465
492
  }) {
466
493
  const manager = useMemo(
467
494
  () => InsforgeManager.getInstance({
@@ -473,6 +500,12 @@ function InsforgeProviderCore({
473
500
  }),
474
501
  [baseUrl, afterSignInUrl, onAuthChange, onSignIn, onSignOut]
475
502
  );
503
+ if (initialState) {
504
+ const currentState = manager.getState();
505
+ if (currentState.userId === void 0 && initialState.userId !== void 0) {
506
+ manager.setInitialState(initialState);
507
+ }
508
+ }
476
509
  const [state, setState] = useState(() => manager.getState());
477
510
  useEffect(() => {
478
511
  const unsubscribe = manager.subscribe((newState) => {
@@ -492,6 +525,7 @@ function InsforgeProviderCore({
492
525
  () => ({
493
526
  // State from Manager
494
527
  user: state.user,
528
+ userId: state.userId,
495
529
  isLoaded: state.isLoaded,
496
530
  isSignedIn: state.isSignedIn,
497
531
  // Methods delegated to Manager
@@ -523,9 +557,10 @@ function useInsforge() {
523
557
  const context = useContext(InsforgeContext);
524
558
  if (!context) {
525
559
  return {
526
- user: null,
560
+ user: void 0,
561
+ userId: void 0,
527
562
  isLoaded: false,
528
- isSignedIn: false,
563
+ isSignedIn: void 0,
529
564
  setUser: () => {
530
565
  },
531
566
  signIn: () => Promise.resolve({ error: "SSR mode" }),
@@ -2505,16 +2540,16 @@ function Protect({
2505
2540
  condition,
2506
2541
  onRedirect
2507
2542
  }) {
2508
- const { isSignedIn, isLoaded, user } = useInsforge();
2543
+ const { userId, user } = useInsforge();
2509
2544
  const resolvedRedirectTo = useMemo(() => resolveAuthPath(redirectTo), [redirectTo]);
2510
2545
  useEffect(() => {
2511
- if (isLoaded && !isSignedIn) {
2546
+ if (userId === null) {
2512
2547
  if (onRedirect) {
2513
2548
  onRedirect(resolvedRedirectTo);
2514
2549
  } else {
2515
2550
  window.location.href = resolvedRedirectTo;
2516
2551
  }
2517
- } else if (isLoaded && isSignedIn && condition && user) {
2552
+ } else if (userId && condition && user) {
2518
2553
  if (!condition(user)) {
2519
2554
  if (onRedirect) {
2520
2555
  onRedirect(resolvedRedirectTo);
@@ -2523,11 +2558,11 @@ function Protect({
2523
2558
  }
2524
2559
  }
2525
2560
  }
2526
- }, [isLoaded, isSignedIn, resolvedRedirectTo, condition, user, onRedirect]);
2527
- if (!isLoaded) {
2561
+ }, [userId, resolvedRedirectTo, condition, user, onRedirect]);
2562
+ if (userId === void 0) {
2528
2563
  return fallback || /* @__PURE__ */ jsx("div", { className: "insforge-loading", children: "Loading..." });
2529
2564
  }
2530
- if (!isSignedIn) {
2565
+ if (userId === null) {
2531
2566
  return fallback || null;
2532
2567
  }
2533
2568
  if (condition && user && !condition(user)) {
@@ -2536,24 +2571,18 @@ function Protect({
2536
2571
  return /* @__PURE__ */ jsx(Fragment, { children });
2537
2572
  }
2538
2573
  function SignedIn({ children }) {
2539
- const { isSignedIn, isLoaded } = useInsforge();
2540
- if (!isLoaded) {
2541
- return null;
2574
+ const { userId } = useInsforge();
2575
+ if (userId) {
2576
+ return /* @__PURE__ */ jsx(Fragment, { children });
2542
2577
  }
2543
- if (!isSignedIn) {
2544
- return null;
2545
- }
2546
- return /* @__PURE__ */ jsx(Fragment, { children });
2578
+ return null;
2547
2579
  }
2548
2580
  function SignedOut({ children }) {
2549
- const { isSignedIn, isLoaded } = useInsforge();
2550
- if (!isLoaded) {
2551
- return null;
2581
+ const { userId } = useInsforge();
2582
+ if (userId === null) {
2583
+ return /* @__PURE__ */ jsx(Fragment, { children });
2552
2584
  }
2553
- if (isSignedIn) {
2554
- return null;
2555
- }
2556
- return /* @__PURE__ */ jsx(Fragment, { children });
2585
+ return null;
2557
2586
  }
2558
2587
  function SignInButton({ children, className }) {
2559
2588
  const { afterSignInUrl, baseUrl } = useInsforge();