@dexterai/x402 1.5.1 → 1.5.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.
@@ -613,19 +613,11 @@ function createX402Client(config) {
613
613
  return null;
614
614
  }
615
615
  const accessPassJwt = passResponse.headers.get("ACCESS-PASS");
616
- if (!accessPassJwt) {
617
- return passResponse;
616
+ if (accessPassJwt) {
617
+ cachePass(url, accessPassJwt);
618
+ log("Access pass purchased and cached");
618
619
  }
619
- cachePass(url, accessPassJwt);
620
- log("Access pass purchased and cached");
621
- const retryResponse = await customFetch(input, {
622
- ...init,
623
- headers: {
624
- ...init?.headers || {},
625
- "Authorization": `Bearer ${accessPassJwt}`
626
- }
627
- });
628
- return retryResponse;
620
+ return passResponse;
629
621
  }
630
622
  async function x402Fetch(input, init) {
631
623
  const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
@@ -1050,7 +1042,7 @@ function useX402Payment(config) {
1050
1042
  }
1051
1043
 
1052
1044
  // src/react/useAccessPass.ts
1053
- import { useState as useState2, useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2 } from "react";
1045
+ import { useState as useState2, useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useRef } from "react";
1054
1046
  function useAccessPass(config) {
1055
1047
  const {
1056
1048
  wallets: walletSet,
@@ -1061,13 +1053,43 @@ function useAccessPass(config) {
1061
1053
  autoConnect = true,
1062
1054
  verbose = false
1063
1055
  } = config;
1056
+ const storageKey = `x402-access-pass:${resourceUrl}`;
1057
+ function loadPersistedPass() {
1058
+ if (typeof sessionStorage === "undefined") return null;
1059
+ try {
1060
+ const stored = sessionStorage.getItem(storageKey);
1061
+ if (!stored) return null;
1062
+ const parsed = JSON.parse(stored);
1063
+ if (new Date(parsed.expiresAt).getTime() <= Date.now()) {
1064
+ sessionStorage.removeItem(storageKey);
1065
+ return null;
1066
+ }
1067
+ return parsed;
1068
+ } catch {
1069
+ return null;
1070
+ }
1071
+ }
1072
+ function persistPass(jwt, tier, expiresAt) {
1073
+ if (typeof sessionStorage === "undefined") return;
1074
+ try {
1075
+ sessionStorage.setItem(storageKey, JSON.stringify({ jwt, tier, expiresAt }));
1076
+ } catch {
1077
+ }
1078
+ }
1079
+ const persisted = loadPersistedPass();
1064
1080
  const [tiers, setTiers] = useState2(null);
1065
1081
  const [customRatePerHour, setCustomRatePerHour] = useState2(null);
1066
1082
  const [isLoadingTiers, setIsLoadingTiers] = useState2(false);
1067
- const [passJwt, setPassJwt] = useState2(null);
1068
- const [passInfo, setPassInfo] = useState2(null);
1083
+ const [passJwt, setPassJwt] = useState2(persisted?.jwt || null);
1084
+ const [passInfo, setPassInfo] = useState2(
1085
+ persisted ? { tier: persisted.tier, expiresAt: persisted.expiresAt } : null
1086
+ );
1069
1087
  const [isPurchasing, setIsPurchasing] = useState2(false);
1070
1088
  const [purchaseError, setPurchaseError] = useState2(null);
1089
+ const passJwtRef = useRef(passJwt);
1090
+ useEffect2(() => {
1091
+ passJwtRef.current = passJwt;
1092
+ }, [passJwt]);
1071
1093
  const log = useCallback2((...args) => {
1072
1094
  if (verbose) console.log("[useAccessPass]", ...args);
1073
1095
  }, [verbose]);
@@ -1134,25 +1156,31 @@ function useAccessPass(config) {
1134
1156
  else if (durationSeconds) url += (url.includes("?") ? "&" : "?") + `duration=${durationSeconds}`;
1135
1157
  const res = await client.fetch(url, { method: "POST" });
1136
1158
  const jwt = res.headers.get("ACCESS-PASS");
1159
+ log("ACCESS-PASS header:", jwt ? "found" : "NOT FOUND");
1137
1160
  if (jwt) {
1138
1161
  setPassJwt(jwt);
1162
+ let passTier = tier || "unknown";
1163
+ let passExpiresAt = "";
1139
1164
  try {
1140
1165
  const body = await res.json();
1141
- setPassInfo({
1142
- tier: body.accessPass?.tier || tier || "unknown",
1143
- expiresAt: body.accessPass?.expiresAt || ""
1144
- });
1166
+ passTier = body.accessPass?.tier || passTier;
1167
+ passExpiresAt = body.accessPass?.expiresAt || "";
1145
1168
  } catch {
1146
- const parts = jwt.split(".");
1147
- if (parts.length === 3) {
1148
- const payload = JSON.parse(atob(parts[1].replace(/-/g, "+").replace(/_/g, "/")));
1149
- setPassInfo({
1150
- tier: payload.tier || tier || "unknown",
1151
- expiresAt: new Date(payload.exp * 1e3).toISOString()
1152
- });
1169
+ }
1170
+ if (!passExpiresAt) {
1171
+ try {
1172
+ const parts = jwt.split(".");
1173
+ if (parts.length === 3) {
1174
+ const payload = JSON.parse(atob(parts[1].replace(/-/g, "+").replace(/_/g, "/")));
1175
+ passTier = payload.tier || passTier;
1176
+ passExpiresAt = new Date(payload.exp * 1e3).toISOString();
1177
+ }
1178
+ } catch {
1153
1179
  }
1154
1180
  }
1155
- log("Pass purchased:", tier);
1181
+ setPassInfo({ tier: passTier, expiresAt: passExpiresAt });
1182
+ persistPass(jwt, passTier, passExpiresAt);
1183
+ log("Pass purchased and persisted:", passTier, passExpiresAt);
1156
1184
  }
1157
1185
  } catch (err) {
1158
1186
  const error = err instanceof Error ? err : new Error(String(err));
@@ -1164,17 +1192,33 @@ function useAccessPass(config) {
1164
1192
  }, [resourceUrl, client, log]);
1165
1193
  const fetchWithPass = useCallback2(async (path, init) => {
1166
1194
  const url = path.startsWith("http") ? path : `${resourceUrl.replace(/\/$/, "")}${path.startsWith("/") ? "" : "/"}${path}`;
1167
- if (isPassValid && pass) {
1168
- return fetch(url, {
1169
- ...init,
1170
- headers: {
1171
- ...init?.headers || {},
1172
- "Authorization": `Bearer ${pass.jwt}`
1195
+ const currentJwt = passJwtRef.current;
1196
+ if (currentJwt) {
1197
+ try {
1198
+ const parts = currentJwt.split(".");
1199
+ if (parts.length === 3) {
1200
+ const payload = JSON.parse(atob(parts[1].replace(/-/g, "+").replace(/_/g, "/")));
1201
+ if (payload.exp && payload.exp > Date.now() / 1e3) {
1202
+ return fetch(url, {
1203
+ ...init,
1204
+ headers: {
1205
+ ...init?.headers || {},
1206
+ "Authorization": `Bearer ${currentJwt}`
1207
+ }
1208
+ });
1209
+ }
1173
1210
  }
1174
- });
1211
+ } catch {
1212
+ }
1213
+ setPassJwt(null);
1214
+ setPassInfo(null);
1215
+ try {
1216
+ sessionStorage.removeItem(storageKey);
1217
+ } catch {
1218
+ }
1175
1219
  }
1176
1220
  return client.fetch(url, init);
1177
- }, [resourceUrl, isPassValid, pass, client]);
1221
+ }, [resourceUrl, client, storageKey]);
1178
1222
  return {
1179
1223
  tiers,
1180
1224
  customRatePerHour,