azirid-react 0.10.0 → 0.10.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/README.md CHANGED
@@ -81,11 +81,12 @@ AZIRID_API_URL=http://localhost:3000
81
81
  import { AziridProvider } from 'azirid-react'
82
82
 
83
83
  export default function RootLayout({ children }: { children: React.ReactNode }) {
84
+ const router = useRouter()
85
+
84
86
  return (
85
87
  <AziridProvider
86
88
  publishableKey={process.env.NEXT_PUBLIC_AZIRID_PK!}
87
- onLoginSuccess={(data) => console.log('Logged in:', data.user)}
88
- onLogoutSuccess={() => console.log('Logged out')}
89
+ onAuthStateChange={() => router.refresh()}
89
90
  onSessionExpired={() => (window.location.href = '/login')}
90
91
  >
91
92
  {children}
@@ -717,6 +718,8 @@ The hook handles both phases automatically:
717
718
 
718
719
  > **Important:** The redirect URL after payment is configured in the **Payphone Developer dashboard** (not passed via code). Make sure your Response URL points to the page where `usePayphoneCheckout` or `<PayphoneCallback>` is rendered.
719
720
 
721
+ > **Session safety:** The confirmation request waits for the session bootstrap to complete before firing. This prevents 401 errors when Payphone redirects back and the page reloads — the SDK restores the session first, then confirms the payment.
722
+
720
723
  ### `usePayButton`
721
724
 
722
725
  Hook that returns **renderable components** and **state** for a complete payment flow. Supports all providers (Stripe, PayPal, Payphone, Manual Transfer, Nuvei). You control the layout.
@@ -926,7 +929,7 @@ import { InvoiceList } from 'azirid-react'
926
929
 
927
930
  #### `PayphoneCallback`
928
931
 
929
- Page component for handling Payphone payment callbacks. Reads `id` and `clientTransactionId` from URL query params automatically. Deploy this page at the **Response URL** configured in your Payphone Developer dashboard.
932
+ Page component for handling Payphone payment callbacks. Reads `id` and `clientTransactionId` from URL query params automatically. Deploy this page at the **Response URL** configured in your Payphone Developer dashboard. The component waits for the session bootstrap to complete before confirming, preventing 401 errors on page reload.
930
933
 
931
934
  ```tsx
932
935
  // app/payphone/callback/page.tsx
@@ -1297,6 +1300,7 @@ function createAccessClient(
1297
1300
  | `autoBootstrap` | `boolean` | `true` | Auto-restore session on mount |
1298
1301
  | `refreshInterval` | `number` | `50000` | Token refresh interval in ms. `0` to disable |
1299
1302
  | `sessionSyncUrl` | `string \| false` | auto | URL for session cookie sync. Auto-activates in dev mode. Pass `false` to disable |
1303
+ | `onAuthStateChange`| `() => void` | — | Called after login, signup, or logout. **In Next.js, pass `router.refresh()`** to sync server actions with updated cookies |
1300
1304
  | `onLoginSuccess` | `(data) => void` | — | Called after successful login |
1301
1305
  | `onSignupSuccess` | `(data) => void` | — | Called after successful signup |
1302
1306
  | `onLogoutSuccess` | `() => void` | — | Called after logout |
@@ -1311,6 +1315,33 @@ function createAccessClient(
1311
1315
 
1312
1316
  `azirid-react` supports **Next.js 14, 15, and 16+** with full compatibility for each version's API conventions.
1313
1317
 
1318
+ ### Server Actions & `onAuthStateChange`
1319
+
1320
+ If you use **server actions** or **server components** that read the session token (via `createServerAccess`), you **must** pass `onAuthStateChange` to keep server-side cookies in sync:
1321
+
1322
+ ```tsx
1323
+ 'use client'
1324
+ import { useRouter } from 'next/navigation'
1325
+ import { AziridProvider } from 'azirid-react'
1326
+
1327
+ export function Providers({ children }: { children: React.ReactNode }) {
1328
+ const router = useRouter()
1329
+
1330
+ return (
1331
+ <AziridProvider
1332
+ publishableKey={process.env.NEXT_PUBLIC_AZIRID_PK!}
1333
+ onAuthStateChange={() => router.refresh()}
1334
+ >
1335
+ {children}
1336
+ </AziridProvider>
1337
+ )
1338
+ }
1339
+ ```
1340
+
1341
+ **Why?** After login/signup/logout, azirid-react updates the `__session` cookie in the browser. But Next.js server actions keep using the old cookies until `router.refresh()` forces a new server request. Without this, server actions may return 401 after login.
1342
+
1343
+ > **Not using server actions?** (e.g. pure client-side SPA with Vite) — you can skip `onAuthStateChange`.
1344
+
1314
1345
  ### Proxy Route Handler (all versions)
1315
1346
 
1316
1347
  Create the file `app/api/auth/[...path]/route.ts` — one line is all you need:
package/dist/index.cjs CHANGED
@@ -604,6 +604,7 @@ function useAuthMutations(deps) {
604
604
  updateAccessToken(normalizeToken(data));
605
605
  saveSessionTokens(data);
606
606
  setError(null);
607
+ props.onAuthStateChange?.();
607
608
  props.onLoginSuccess?.(data);
608
609
  },
609
610
  onError: (err) => {
@@ -621,6 +622,7 @@ function useAuthMutations(deps) {
621
622
  updateAccessToken(normalizeToken(data));
622
623
  saveSessionTokens(data);
623
624
  setError(null);
625
+ props.onAuthStateChange?.();
624
626
  props.onSignupSuccess?.(data);
625
627
  },
626
628
  onError: (err) => {
@@ -634,6 +636,7 @@ function useAuthMutations(deps) {
634
636
  clearSession();
635
637
  setError(null);
636
638
  queryClient.clear();
639
+ props.onAuthStateChange?.();
637
640
  props.onLogoutSuccess?.();
638
641
  }
639
642
  });
@@ -3008,6 +3011,7 @@ function usePayButton({
3008
3011
  const [payphoneConfig, setPayphoneConfig] = react.useState(null);
3009
3012
  const [currentError, setCurrentError] = react.useState(null);
3010
3013
  const payphoneConfirmTriggered = react.useRef(false);
3014
+ const { isBootstrapping } = useAzirid();
3011
3015
  const params = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : new URLSearchParams();
3012
3016
  const callbackId = params.get("id");
3013
3017
  const callbackClientTxId = params.get("clientTransactionId");
@@ -3090,12 +3094,12 @@ function usePayButton({
3090
3094
  }
3091
3095
  });
3092
3096
  react.useEffect(() => {
3093
- if (!isPayphoneCallback || payphoneConfirmTriggered.current) return;
3097
+ if (!isPayphoneCallback || payphoneConfirmTriggered.current || isBootstrapping) return;
3094
3098
  payphoneConfirmTriggered.current = true;
3095
3099
  setSelectedProvider("PAYPHONE");
3096
3100
  setStatus("processing");
3097
3101
  confirmPayphone({ id: Number(callbackId), clientTransactionId: callbackClientTxId });
3098
- }, [isPayphoneCallback, callbackId, callbackClientTxId, confirmPayphone]);
3102
+ }, [isPayphoneCallback, isBootstrapping, callbackId, callbackClientTxId, confirmPayphone]);
3099
3103
  const handleSdkError = react.useCallback(
3100
3104
  (err) => {
3101
3105
  setCurrentError(err);
@@ -3529,16 +3533,17 @@ function PayphoneCallback({ onSuccess, onError, className, style }) {
3529
3533
  onSuccess,
3530
3534
  onError
3531
3535
  });
3536
+ const { isBootstrapping } = useAzirid();
3532
3537
  const called = react.useRef(false);
3533
3538
  react.useEffect(() => {
3534
- if (called.current) return;
3539
+ if (called.current || isBootstrapping) return;
3535
3540
  called.current = true;
3536
3541
  const params = new URLSearchParams(window.location.search);
3537
3542
  const id = params.get("id");
3538
3543
  const clientTransactionId = params.get("clientTransactionId");
3539
3544
  if (!id || !clientTransactionId) return;
3540
3545
  mutate({ id: Number(id), clientTransactionId });
3541
- }, [mutate]);
3546
+ }, [mutate, isBootstrapping]);
3542
3547
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { textAlign: "center", padding: "32px", ...style }, children: [
3543
3548
  isPending && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3544
3549
  /* @__PURE__ */ jsxRuntime.jsx("p", { style: textStyle, children: "Confirming your payment..." }),
@@ -4040,6 +4045,7 @@ function usePayphoneCheckout({
4040
4045
  const [currentError, setCurrentError] = react.useState(null);
4041
4046
  const checkoutTriggered = react.useRef(false);
4042
4047
  const confirmTriggered = react.useRef(false);
4048
+ const { isBootstrapping } = useAzirid();
4043
4049
  const params = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : new URLSearchParams();
4044
4050
  const callbackId = params.get("id");
4045
4051
  const callbackClientTxId = params.get("clientTransactionId");
@@ -4081,11 +4087,11 @@ function usePayphoneCheckout({
4081
4087
  }
4082
4088
  });
4083
4089
  react.useEffect(() => {
4084
- if (!isCallback || confirmTriggered.current) return;
4090
+ if (!isCallback || confirmTriggered.current || isBootstrapping) return;
4085
4091
  confirmTriggered.current = true;
4086
4092
  setStatus("confirming");
4087
4093
  confirm({ id: Number(callbackId), clientTransactionId: callbackClientTxId });
4088
- }, [isCallback, callbackId, callbackClientTxId, confirm]);
4094
+ }, [isCallback, isBootstrapping, callbackId, callbackClientTxId, confirm]);
4089
4095
  const handleSdkError = react.useCallback(
4090
4096
  (err) => {
4091
4097
  setCurrentError(err);
@@ -4343,7 +4349,7 @@ function usePasswordToggle() {
4343
4349
  }
4344
4350
 
4345
4351
  // src/index.ts
4346
- var SDK_VERSION = "0.10.0";
4352
+ var SDK_VERSION = "0.10.2";
4347
4353
 
4348
4354
  exports.AuthForm = AuthForm;
4349
4355
  exports.AziridProvider = AziridProvider;