azirid-react 0.10.1 → 0.10.3
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 +37 -4
- package/dist/index.cjs +16 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +16 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
88
|
-
onLogoutSuccess={() => console.log('Logged out')}
|
|
89
|
+
onAuthStateChange={() => router.refresh()}
|
|
89
90
|
onSessionExpired={() => (window.location.href = '/login')}
|
|
90
91
|
>
|
|
91
92
|
{children}
|
|
@@ -375,6 +376,8 @@ import { useBootstrap } from 'azirid-react'
|
|
|
375
376
|
const { bootstrap, isBootstrapping } = useBootstrap()
|
|
376
377
|
```
|
|
377
378
|
|
|
379
|
+
> **Note:** The automatic bootstrap on mount runs exactly once, even in React 18 Strict Mode (which double-mounts components in development). Hooks like `usePayphoneCheckout` and `<PayphoneCallback>` wait for bootstrap to complete before making authenticated requests.
|
|
380
|
+
|
|
378
381
|
### `useRefresh`
|
|
379
382
|
|
|
380
383
|
Manually refresh the access token.
|
|
@@ -717,6 +720,8 @@ The hook handles both phases automatically:
|
|
|
717
720
|
|
|
718
721
|
> **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
722
|
|
|
723
|
+
> **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.
|
|
724
|
+
|
|
720
725
|
### `usePayButton`
|
|
721
726
|
|
|
722
727
|
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 +931,7 @@ import { InvoiceList } from 'azirid-react'
|
|
|
926
931
|
|
|
927
932
|
#### `PayphoneCallback`
|
|
928
933
|
|
|
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.
|
|
934
|
+
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
935
|
|
|
931
936
|
```tsx
|
|
932
937
|
// app/payphone/callback/page.tsx
|
|
@@ -1294,9 +1299,10 @@ function createAccessClient(
|
|
|
1294
1299
|
| `publishableKey` | `string` | — | Publishable key (e.g. `pk_live_...`) |
|
|
1295
1300
|
| `tenantId` | `string` | — | Tenant ID for multi-tenant apps |
|
|
1296
1301
|
| `fetchOptions` | `Record<string, string>` | — | Extra headers to send with every request |
|
|
1297
|
-
| `autoBootstrap` | `boolean` | `true` | Auto-restore session on mount
|
|
1302
|
+
| `autoBootstrap` | `boolean` | `true` | Auto-restore session on mount. Runs once (safe in React 18 Strict Mode) |
|
|
1298
1303
|
| `refreshInterval` | `number` | `50000` | Token refresh interval in ms. `0` to disable |
|
|
1299
1304
|
| `sessionSyncUrl` | `string \| false` | auto | URL for session cookie sync. Auto-activates in dev mode. Pass `false` to disable |
|
|
1305
|
+
| `onAuthStateChange`| `() => void` | — | Called after login, signup, or logout. **In Next.js, pass `router.refresh()`** to sync server actions with updated cookies |
|
|
1300
1306
|
| `onLoginSuccess` | `(data) => void` | — | Called after successful login |
|
|
1301
1307
|
| `onSignupSuccess` | `(data) => void` | — | Called after successful signup |
|
|
1302
1308
|
| `onLogoutSuccess` | `() => void` | — | Called after logout |
|
|
@@ -1311,6 +1317,33 @@ function createAccessClient(
|
|
|
1311
1317
|
|
|
1312
1318
|
`azirid-react` supports **Next.js 14, 15, and 16+** with full compatibility for each version's API conventions.
|
|
1313
1319
|
|
|
1320
|
+
### Server Actions & `onAuthStateChange`
|
|
1321
|
+
|
|
1322
|
+
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:
|
|
1323
|
+
|
|
1324
|
+
```tsx
|
|
1325
|
+
'use client'
|
|
1326
|
+
import { useRouter } from 'next/navigation'
|
|
1327
|
+
import { AziridProvider } from 'azirid-react'
|
|
1328
|
+
|
|
1329
|
+
export function Providers({ children }: { children: React.ReactNode }) {
|
|
1330
|
+
const router = useRouter()
|
|
1331
|
+
|
|
1332
|
+
return (
|
|
1333
|
+
<AziridProvider
|
|
1334
|
+
publishableKey={process.env.NEXT_PUBLIC_AZIRID_PK!}
|
|
1335
|
+
onAuthStateChange={() => router.refresh()}
|
|
1336
|
+
>
|
|
1337
|
+
{children}
|
|
1338
|
+
</AziridProvider>
|
|
1339
|
+
)
|
|
1340
|
+
}
|
|
1341
|
+
```
|
|
1342
|
+
|
|
1343
|
+
**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.
|
|
1344
|
+
|
|
1345
|
+
> **Not using server actions?** (e.g. pure client-side SPA with Vite) — you can skip `onAuthStateChange`.
|
|
1346
|
+
|
|
1314
1347
|
### Proxy Route Handler (all versions)
|
|
1315
1348
|
|
|
1316
1349
|
Create the file `app/api/auth/[...path]/route.ts` — one line is all you need:
|
package/dist/index.cjs
CHANGED
|
@@ -768,9 +768,15 @@ function AziridProviderInner({
|
|
|
768
768
|
},
|
|
769
769
|
[client]
|
|
770
770
|
);
|
|
771
|
+
const bootstrapCalled = react.useRef(false);
|
|
771
772
|
react.useEffect(() => {
|
|
772
773
|
const autoBootstrap = props.autoBootstrap ?? true;
|
|
773
774
|
if (!autoBootstrap) return;
|
|
775
|
+
if (bootstrapCalled.current) {
|
|
776
|
+
setIsBootstrapping(false);
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
bootstrapCalled.current = true;
|
|
774
780
|
let cancelled = false;
|
|
775
781
|
async function bootstrap() {
|
|
776
782
|
setIsBootstrapping(true);
|
|
@@ -3011,6 +3017,7 @@ function usePayButton({
|
|
|
3011
3017
|
const [payphoneConfig, setPayphoneConfig] = react.useState(null);
|
|
3012
3018
|
const [currentError, setCurrentError] = react.useState(null);
|
|
3013
3019
|
const payphoneConfirmTriggered = react.useRef(false);
|
|
3020
|
+
const { isBootstrapping } = useAzirid();
|
|
3014
3021
|
const params = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : new URLSearchParams();
|
|
3015
3022
|
const callbackId = params.get("id");
|
|
3016
3023
|
const callbackClientTxId = params.get("clientTransactionId");
|
|
@@ -3093,12 +3100,12 @@ function usePayButton({
|
|
|
3093
3100
|
}
|
|
3094
3101
|
});
|
|
3095
3102
|
react.useEffect(() => {
|
|
3096
|
-
if (!isPayphoneCallback || payphoneConfirmTriggered.current) return;
|
|
3103
|
+
if (!isPayphoneCallback || payphoneConfirmTriggered.current || isBootstrapping) return;
|
|
3097
3104
|
payphoneConfirmTriggered.current = true;
|
|
3098
3105
|
setSelectedProvider("PAYPHONE");
|
|
3099
3106
|
setStatus("processing");
|
|
3100
3107
|
confirmPayphone({ id: Number(callbackId), clientTransactionId: callbackClientTxId });
|
|
3101
|
-
}, [isPayphoneCallback, callbackId, callbackClientTxId, confirmPayphone]);
|
|
3108
|
+
}, [isPayphoneCallback, isBootstrapping, callbackId, callbackClientTxId, confirmPayphone]);
|
|
3102
3109
|
const handleSdkError = react.useCallback(
|
|
3103
3110
|
(err) => {
|
|
3104
3111
|
setCurrentError(err);
|
|
@@ -3532,16 +3539,17 @@ function PayphoneCallback({ onSuccess, onError, className, style }) {
|
|
|
3532
3539
|
onSuccess,
|
|
3533
3540
|
onError
|
|
3534
3541
|
});
|
|
3542
|
+
const { isBootstrapping } = useAzirid();
|
|
3535
3543
|
const called = react.useRef(false);
|
|
3536
3544
|
react.useEffect(() => {
|
|
3537
|
-
if (called.current) return;
|
|
3545
|
+
if (called.current || isBootstrapping) return;
|
|
3538
3546
|
called.current = true;
|
|
3539
3547
|
const params = new URLSearchParams(window.location.search);
|
|
3540
3548
|
const id = params.get("id");
|
|
3541
3549
|
const clientTransactionId = params.get("clientTransactionId");
|
|
3542
3550
|
if (!id || !clientTransactionId) return;
|
|
3543
3551
|
mutate({ id: Number(id), clientTransactionId });
|
|
3544
|
-
}, [mutate]);
|
|
3552
|
+
}, [mutate, isBootstrapping]);
|
|
3545
3553
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { textAlign: "center", padding: "32px", ...style }, children: [
|
|
3546
3554
|
isPending && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3547
3555
|
/* @__PURE__ */ jsxRuntime.jsx("p", { style: textStyle, children: "Confirming your payment..." }),
|
|
@@ -4043,6 +4051,7 @@ function usePayphoneCheckout({
|
|
|
4043
4051
|
const [currentError, setCurrentError] = react.useState(null);
|
|
4044
4052
|
const checkoutTriggered = react.useRef(false);
|
|
4045
4053
|
const confirmTriggered = react.useRef(false);
|
|
4054
|
+
const { isBootstrapping } = useAzirid();
|
|
4046
4055
|
const params = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : new URLSearchParams();
|
|
4047
4056
|
const callbackId = params.get("id");
|
|
4048
4057
|
const callbackClientTxId = params.get("clientTransactionId");
|
|
@@ -4084,11 +4093,11 @@ function usePayphoneCheckout({
|
|
|
4084
4093
|
}
|
|
4085
4094
|
});
|
|
4086
4095
|
react.useEffect(() => {
|
|
4087
|
-
if (!isCallback || confirmTriggered.current) return;
|
|
4096
|
+
if (!isCallback || confirmTriggered.current || isBootstrapping) return;
|
|
4088
4097
|
confirmTriggered.current = true;
|
|
4089
4098
|
setStatus("confirming");
|
|
4090
4099
|
confirm({ id: Number(callbackId), clientTransactionId: callbackClientTxId });
|
|
4091
|
-
}, [isCallback, callbackId, callbackClientTxId, confirm]);
|
|
4100
|
+
}, [isCallback, isBootstrapping, callbackId, callbackClientTxId, confirm]);
|
|
4092
4101
|
const handleSdkError = react.useCallback(
|
|
4093
4102
|
(err) => {
|
|
4094
4103
|
setCurrentError(err);
|
|
@@ -4346,7 +4355,7 @@ function usePasswordToggle() {
|
|
|
4346
4355
|
}
|
|
4347
4356
|
|
|
4348
4357
|
// src/index.ts
|
|
4349
|
-
var SDK_VERSION = "0.10.
|
|
4358
|
+
var SDK_VERSION = "0.10.3";
|
|
4350
4359
|
|
|
4351
4360
|
exports.AuthForm = AuthForm;
|
|
4352
4361
|
exports.AziridProvider = AziridProvider;
|