@yieldfabric/wallet 0.2.4 → 0.2.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
@@ -741,6 +741,9 @@ declare class AuthService {
741
741
  * Uses global lock to prevent concurrent refresh attempts
742
742
  */
743
743
  refreshAccessToken(targetChainId?: string): Promise<RefreshTokenResponse>;
744
+ /** The session another window renewed since this one read the refresh
745
+ * token `spent`, taken as this window's own; `null` when there is none. */
746
+ private adoptRenewedSession;
744
747
  /**
745
748
  * Perform the actual token refresh.
746
749
  *
package/dist/index.d.ts CHANGED
@@ -741,6 +741,9 @@ declare class AuthService {
741
741
  * Uses global lock to prevent concurrent refresh attempts
742
742
  */
743
743
  refreshAccessToken(targetChainId?: string): Promise<RefreshTokenResponse>;
744
+ /** The session another window renewed since this one read the refresh
745
+ * token `spent`, taken as this window's own; `null` when there is none. */
746
+ private adoptRenewedSession;
744
747
  /**
745
748
  * Perform the actual token refresh.
746
749
  *
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * Source review requires written authorization; see package LICENSE.md and NOTICE.md.
6
6
  * Runtime use requires a separate express license.
7
7
  */
8
- import React54, { createContext, lazy, useContext, useState, useEffect, useRef, useCallback, useMemo, Suspense, useId, Component } from 'react';
8
+ import React55, { createContext, lazy, useContext, useState, useEffect, useRef, useCallback, useMemo, Suspense, useId, Component } from 'react';
9
9
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
10
10
  import { AvererSdkProvider, useAvererWallet, AvererWebSdk } from '@averer/averer-websdk';
11
11
  import sha3, { keccak256 } from 'js-sha3';
@@ -1513,6 +1513,26 @@ var init_tokenStore = __esm({
1513
1513
  }
1514
1514
  });
1515
1515
 
1516
+ // src/core/crossTabRefresh.ts
1517
+ function withRefreshLock(renew, locks = globalThis.navigator?.locks) {
1518
+ if (!locks?.request) return renew();
1519
+ return locks.request(REFRESH_LOCK, renew);
1520
+ }
1521
+ function renewedElsewhere(spent, stored, chainId, now = Date.now()) {
1522
+ if (!stored.access || !stored.refresh || stored.refresh === spent) return false;
1523
+ const claims = decodeJwtPayload(stored.access);
1524
+ const exp = claims?.exp;
1525
+ return typeof exp === "number" && exp * 1e3 - now > LIVE_FOR_MS && claims?.default_chain_id === chainId;
1526
+ }
1527
+ var REFRESH_LOCK, LIVE_FOR_MS;
1528
+ var init_crossTabRefresh = __esm({
1529
+ "src/core/crossTabRefresh.ts"() {
1530
+ init_jwtPayload();
1531
+ REFRESH_LOCK = "yieldfabric-auth-refresh";
1532
+ LIVE_FOR_MS = 3e4;
1533
+ }
1534
+ });
1535
+
1516
1536
  // src/core/onboardingPlanSelectionStorage.ts
1517
1537
  function readOnboardingPlanSelectionHint() {
1518
1538
  if (typeof window === "undefined") return null;
@@ -1592,6 +1612,7 @@ var init_authService = __esm({
1592
1612
  init_tokenManager();
1593
1613
  init_jwtClaims();
1594
1614
  init_tokenStore();
1615
+ init_crossTabRefresh();
1595
1616
  init_onboardingPlanSelectionStorage();
1596
1617
  isRefreshing = false;
1597
1618
  refreshPromise = null;
@@ -1778,19 +1799,23 @@ var init_authService = __esm({
1778
1799
  error.statusCode = 401;
1779
1800
  throw error;
1780
1801
  }
1802
+ const spent = this.refreshToken;
1781
1803
  isRefreshing = true;
1782
1804
  refreshOperation = { kind: "regular", chainId };
1783
- refreshPromise = this.performRefresh(chainId);
1805
+ refreshPromise = withRefreshLock(async () => this.adoptRenewedSession(chainId, spent) ?? this.performRefresh(chainId));
1784
1806
  const activePromise = refreshPromise;
1785
1807
  try {
1786
1808
  const result = await refreshPromise;
1787
1809
  return result;
1788
1810
  } catch (error) {
1789
1811
  switch (classifyAuthFailure(error)) {
1790
- case "auth":
1812
+ case "auth": {
1813
+ const adopted = this.adoptRenewedSession(chainId, spent);
1814
+ if (adopted) return adopted;
1791
1815
  console.warn("Authentication error during token refresh, clearing tokens");
1792
1816
  this.clearTokensFromStorage();
1793
1817
  break;
1818
+ }
1794
1819
  case "network":
1795
1820
  console.warn("Network error during token refresh, preserving tokens for retry");
1796
1821
  break;
@@ -1806,6 +1831,20 @@ var init_authService = __esm({
1806
1831
  }
1807
1832
  }
1808
1833
  }
1834
+ /** The session another window renewed since this one read the refresh
1835
+ * token `spent`, taken as this window's own; `null` when there is none. */
1836
+ adoptRenewedSession(chainId, spent) {
1837
+ const stored = { access: defaultTokenStore.getAccessToken(), refresh: defaultTokenStore.getRefreshToken() };
1838
+ if (!stored.access || !stored.refresh || !renewedElsewhere(spent, stored, chainId)) return null;
1839
+ this.saveTokensToStorage(stored.access, stored.refresh);
1840
+ const exp = decodeJwtPayload(stored.access)?.exp;
1841
+ return {
1842
+ access_token: stored.access,
1843
+ refresh_token: stored.refresh,
1844
+ token_type: "Bearer",
1845
+ expires_in: Math.max(0, Math.floor(exp - Date.now() / 1e3))
1846
+ };
1847
+ }
1809
1848
  /**
1810
1849
  * Perform the actual token refresh.
1811
1850
  *
@@ -9946,7 +9985,7 @@ function WizardProvider({
9946
9985
  const [planSelection, setPlanSelection] = useState(
9947
9986
  readOnboardingPlanSelectionHint
9948
9987
  );
9949
- const pendingSponsorshipRef = React54.useRef(
9988
+ const pendingSponsorshipRef = React55.useRef(
9950
9989
  pendingSponsorship
9951
9990
  );
9952
9991
  const stageSponsorship = useCallback((groupId, destination) => {
@@ -11160,8 +11199,8 @@ var DynamicCompleter = ({ sdk, action, onError }) => {
11160
11199
  const ctx = sdk.useDynamicContext();
11161
11200
  const wallet = ctx.primaryWallet;
11162
11201
  const dynamicUser = ctx.user;
11163
- const [done, setDone] = React54.useState(false);
11164
- React54.useEffect(() => {
11202
+ const [done, setDone] = React55.useState(false);
11203
+ React55.useEffect(() => {
11165
11204
  if (done || !wallet?.address) return;
11166
11205
  setDone(true);
11167
11206
  (async () => {
@@ -11586,8 +11625,8 @@ var KycFlow3 = ({ onComplete, onError, instanceId }) => {
11586
11625
  const settings = config?.kyc.settings[providerId];
11587
11626
  const publishableKey = settings?.publishable_key;
11588
11627
  const requiredForCompletion = settings?.required_for_completion ?? false;
11589
- const [stage, setStage] = React54.useState({ kind: "idle" });
11590
- React54.useEffect(() => {
11628
+ const [stage, setStage] = React55.useState({ kind: "idle" });
11629
+ React55.useEffect(() => {
11591
11630
  let cancelled = false;
11592
11631
  (async () => {
11593
11632
  try {
@@ -11611,7 +11650,7 @@ var KycFlow3 = ({ onComplete, onError, instanceId }) => {
11611
11650
  cancelled = true;
11612
11651
  };
11613
11652
  }, []);
11614
- React54.useEffect(() => {
11653
+ React55.useEffect(() => {
11615
11654
  if (stage.kind !== "pending-poll") return;
11616
11655
  let cancelled = false;
11617
11656
  const pollOnce = async () => {
@@ -11863,14 +11902,14 @@ function useIdentityStatusPoll(opts) {
11863
11902
  provider,
11864
11903
  credentialType
11865
11904
  } = opts;
11866
- const [stuckHint, setStuckHint] = React54.useState(false);
11867
- const onVerifiedRef = React54.useRef(onVerified);
11868
- const onRejectedRef = React54.useRef(onRejected);
11869
- React54.useEffect(() => {
11905
+ const [stuckHint, setStuckHint] = React55.useState(false);
11906
+ const onVerifiedRef = React55.useRef(onVerified);
11907
+ const onRejectedRef = React55.useRef(onRejected);
11908
+ React55.useEffect(() => {
11870
11909
  onVerifiedRef.current = onVerified;
11871
11910
  onRejectedRef.current = onRejected;
11872
11911
  }, [onVerified, onRejected]);
11873
- React54.useEffect(() => {
11912
+ React55.useEffect(() => {
11874
11913
  if (!active) {
11875
11914
  setStuckHint(false);
11876
11915
  return;
@@ -12008,12 +12047,12 @@ var KycFlow4 = ({ onComplete, onError, instanceId, subject }) => {
12008
12047
  const groupId = subject?.kind === "group" ? subject.id : void 0;
12009
12048
  const configuredLevel = config?.kyc.settings[providerId]?.level_name?.trim();
12010
12049
  const levelName = configuredLevel || "id-and-liveness";
12011
- const [token, setToken] = React54.useState(null);
12012
- const [stage, setStage] = React54.useState({ kind: "init" });
12013
- const [attempt, setAttempt] = React54.useState(0);
12014
- const submittedRef = React54.useRef(false);
12015
- const applicantIdRef = React54.useRef(void 0);
12016
- React54.useEffect(() => {
12050
+ const [token, setToken] = React55.useState(null);
12051
+ const [stage, setStage] = React55.useState({ kind: "init" });
12052
+ const [attempt, setAttempt] = React55.useState(0);
12053
+ const submittedRef = React55.useRef(false);
12054
+ const applicantIdRef = React55.useRef(void 0);
12055
+ React55.useEffect(() => {
12017
12056
  let cancelled = false;
12018
12057
  submittedRef.current = false;
12019
12058
  (async () => {
@@ -12328,6 +12367,47 @@ function OnboardingChooseMethod({ chrome } = {}) {
12328
12367
  /* @__PURE__ */ jsx("p", { className: "text-[10px] text-text-secondary text-center pt-2", children: messages.legal.agreementText })
12329
12368
  ] }) });
12330
12369
  }
12370
+ function FloatField({
12371
+ label,
12372
+ type,
12373
+ value,
12374
+ onChange,
12375
+ autoComplete,
12376
+ required,
12377
+ minLength,
12378
+ maxLength,
12379
+ adornment,
12380
+ disabled
12381
+ }) {
12382
+ const id = useId();
12383
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
12384
+ /* @__PURE__ */ jsx(
12385
+ "input",
12386
+ {
12387
+ id,
12388
+ type,
12389
+ required,
12390
+ minLength,
12391
+ maxLength,
12392
+ autoComplete,
12393
+ placeholder: " ",
12394
+ value,
12395
+ disabled,
12396
+ onChange: (e) => onChange(e.target.value),
12397
+ className: "\n peer w-full bg-transparent border-0 border-b border-border-default\n rounded-none px-0 pt-4 pb-1.5 text-[14px] text-text-primary\n focus:outline-none focus:border-border-strong transition-colors\n disabled:opacity-60 disabled:cursor-not-allowed\n "
12398
+ }
12399
+ ),
12400
+ /* @__PURE__ */ jsx(
12401
+ "label",
12402
+ {
12403
+ htmlFor: id,
12404
+ className: "\n absolute left-0 pointer-events-none transition-all duration-200\n text-[10px] text-text-secondary top-0\n peer-placeholder-shown:text-[13px] peer-placeholder-shown:top-4\n peer-focus:text-[10px] peer-focus:top-0 peer-focus:text-text-secondary\n ",
12405
+ children: label
12406
+ }
12407
+ ),
12408
+ adornment && /* @__PURE__ */ jsx("span", { className: "absolute right-0 top-4 pointer-events-none", children: adornment })
12409
+ ] });
12410
+ }
12331
12411
  init_authService();
12332
12412
  init_tokenManager();
12333
12413
  init_ProviderConfigContext();
@@ -12565,44 +12645,6 @@ function OnboardingEmailSignup({ chrome } = {}) {
12565
12645
  ] })
12566
12646
  ] }) });
12567
12647
  }
12568
- function FloatField({
12569
- label,
12570
- type,
12571
- value,
12572
- onChange,
12573
- autoComplete,
12574
- required,
12575
- minLength,
12576
- maxLength,
12577
- adornment,
12578
- disabled
12579
- }) {
12580
- return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
12581
- /* @__PURE__ */ jsx(
12582
- "input",
12583
- {
12584
- type,
12585
- required,
12586
- minLength,
12587
- maxLength,
12588
- autoComplete,
12589
- placeholder: " ",
12590
- value,
12591
- disabled,
12592
- onChange: (e) => onChange(e.target.value),
12593
- className: "\n peer w-full bg-transparent border-0 border-b border-border-default\n rounded-none px-0 pt-4 pb-1.5 text-[14px] text-text-primary\n focus:outline-none focus:border-border-strong transition-colors\n disabled:opacity-60 disabled:cursor-not-allowed\n "
12594
- }
12595
- ),
12596
- /* @__PURE__ */ jsx(
12597
- "span",
12598
- {
12599
- className: "\n absolute left-0 pointer-events-none transition-all duration-200\n text-[10px] text-text-secondary top-0\n peer-placeholder-shown:text-[13px] peer-placeholder-shown:top-4\n peer-focus:text-[10px] peer-focus:top-0 peer-focus:text-text-secondary\n ",
12600
- children: label
12601
- }
12602
- ),
12603
- adornment && /* @__PURE__ */ jsx("span", { className: "absolute right-0 top-4 pointer-events-none", children: adornment })
12604
- ] });
12605
- }
12606
12648
  init_authService();
12607
12649
  init_onboardingClient();
12608
12650
  function EmailVerify({ chrome } = {}) {
@@ -12763,7 +12805,7 @@ function EmailVerify({ chrome } = {}) {
12763
12805
  /* @__PURE__ */ jsx(ProgressRail, { phase, verified: !!status?.verified || phase === "success" }),
12764
12806
  phase === "loading" && !status ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border-default bg-surface-alt/70 p-4 text-center text-[12px] text-text-secondary", children: "Checking email status..." }) : phase === "success" ? /* @__PURE__ */ jsx(SuccessPanel, { notice }) : status?.is_synthetic ? /* @__PURE__ */ jsxs("form", { onSubmit: submitRealEmail, className: "space-y-4", children: [
12765
12807
  /* @__PURE__ */ jsx(
12766
- FloatField2,
12808
+ FloatField,
12767
12809
  {
12768
12810
  label: "Email",
12769
12811
  type: "email",
@@ -12886,38 +12928,6 @@ function CodeField({
12886
12928
  }
12887
12929
  );
12888
12930
  }
12889
- function FloatField2({
12890
- label,
12891
- type,
12892
- value,
12893
- onChange,
12894
- autoComplete,
12895
- disabled,
12896
- required
12897
- }) {
12898
- return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
12899
- /* @__PURE__ */ jsx(
12900
- "input",
12901
- {
12902
- type,
12903
- required,
12904
- autoComplete,
12905
- placeholder: " ",
12906
- value,
12907
- disabled,
12908
- onChange: (e) => onChange(e.target.value),
12909
- className: "\n peer w-full bg-transparent border-0 border-b border-border-default\n rounded-none px-0 pt-4 pb-1.5 text-[14px] text-text-primary\n focus:outline-none focus:border-border-strong transition-colors\n disabled:opacity-60\n "
12910
- }
12911
- ),
12912
- /* @__PURE__ */ jsx(
12913
- "span",
12914
- {
12915
- className: "\n absolute left-0 pointer-events-none transition-all duration-200\n text-[10px] text-text-secondary top-0\n peer-placeholder-shown:text-[13px] peer-placeholder-shown:top-4\n peer-focus:text-[10px] peer-focus:top-0 peer-focus:text-text-secondary\n ",
12916
- children: label
12917
- }
12918
- )
12919
- ] });
12920
- }
12921
12931
  function friendlyEmailError(err, action) {
12922
12932
  const message = err instanceof Error ? err.message : String(err);
12923
12933
  if (message.includes("email delivery unavailable") || message.includes("503")) {
@@ -16008,7 +16018,7 @@ function Field({
16008
16018
  value,
16009
16019
  copyable
16010
16020
  }) {
16011
- const [copied, setCopied] = React54.useState(false);
16021
+ const [copied, setCopied] = React55.useState(false);
16012
16022
  return /* @__PURE__ */ jsxs("div", { children: [
16013
16023
  /* @__PURE__ */ jsx("p", { className: "text-[10px] uppercase tracking-wider text-text-secondary", children: label }),
16014
16024
  /* @__PURE__ */ jsxs("div", { className: "mt-0.5 flex items-center gap-2", children: [
@@ -16072,14 +16082,14 @@ var STAGE_COPY = {
16072
16082
  not_applicable: { title: "Finishing up", body: "" }
16073
16083
  };
16074
16084
  var AccountOpeningPanel = ({ onContinue, continueLabel = "Continue" }) => {
16075
- const [status, setStatus] = React54.useState(null);
16076
- const [impatient, setImpatient] = React54.useState(false);
16077
- const activationStarted = React54.useRef(false);
16078
- const onContinueRef = React54.useRef(onContinue);
16079
- React54.useEffect(() => {
16085
+ const [status, setStatus] = React55.useState(null);
16086
+ const [impatient, setImpatient] = React55.useState(false);
16087
+ const activationStarted = React55.useRef(false);
16088
+ const onContinueRef = React55.useRef(onContinue);
16089
+ React55.useEffect(() => {
16080
16090
  onContinueRef.current = onContinue;
16081
16091
  }, [onContinue]);
16082
- React54.useEffect(() => {
16092
+ React55.useEffect(() => {
16083
16093
  let cancelled = false;
16084
16094
  let timer;
16085
16095
  const startedAt = Date.now();
@@ -17417,7 +17427,7 @@ function WizardRouter({
17417
17427
  identityRequired && primaryKycVerifiesEmail(config)
17418
17428
  );
17419
17429
  const hostOwnsSponsorshipConsent = sponsorshipConsent === "host";
17420
- React54.useEffect(() => {
17430
+ React55.useEffect(() => {
17421
17431
  if (hostOwnsSponsorshipConsent && pendingSponsorship) {
17422
17432
  discardSponsorship();
17423
17433
  }
@@ -17633,7 +17643,7 @@ function builtinProviderDisplayName(id) {
17633
17643
  }
17634
17644
  }
17635
17645
  function useProviderDisplayName(config) {
17636
- return React54.useCallback(
17646
+ return React55.useCallback(
17637
17647
  (id) => {
17638
17648
  const labelled = config?.kyc?.settings?.[id]?.label ?? config?.auth?.settings?.[id]?.label;
17639
17649
  const trimmed = typeof labelled === "string" ? labelled.trim() : "";
@@ -17969,7 +17979,7 @@ var OnboardingPolicySection = ({
17969
17979
  )
17970
17980
  ] }) }) : /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
17971
17981
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-2.5 gap-y-1.5 rounded-lg border border-primary/20 bg-primary/[0.04] px-3.5 py-2.5", children: [
17972
- journeySteps.map((step, i) => /* @__PURE__ */ jsxs(React54.Fragment, { children: [
17982
+ journeySteps.map((step, i) => /* @__PURE__ */ jsxs(React55.Fragment, { children: [
17973
17983
  i > 0 && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "text-[12px] text-text-muted/60", children: "\u203A" }),
17974
17984
  /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
17975
17985
  /* @__PURE__ */ jsx("span", { className: "flex h-4 w-4 items-center justify-center rounded-full bg-primary/20 text-[9px] font-bold text-primary", children: i + 1 }),
@@ -21157,11 +21167,11 @@ var SaveButton = ({ onClick, busy, disabled, saved = false, classNames }) => /*
21157
21167
  );
21158
21168
  function useSavedFlash(ms = 1800) {
21159
21169
  const [saved, setSaved] = useState(false);
21160
- const timer = React54.useRef(null);
21170
+ const timer = React55.useRef(null);
21161
21171
  useEffect(() => () => {
21162
21172
  if (timer.current) clearTimeout(timer.current);
21163
21173
  }, []);
21164
- const flash = React54.useCallback(() => {
21174
+ const flash = React55.useCallback(() => {
21165
21175
  setSaved(true);
21166
21176
  if (timer.current) clearTimeout(timer.current);
21167
21177
  timer.current = setTimeout(() => setSaved(false), ms);
@@ -24914,17 +24924,17 @@ function ActiveEnvironmentBadge({
24914
24924
  configuredTestChains
24915
24925
  );
24916
24926
  const canChoose = Boolean(activeChainId && options.length > 1);
24917
- const [busyChainId, setBusyChainId] = React54.useState(null);
24918
- const [pendingLiveChainId, setPendingLiveChainId] = React54.useState(null);
24919
- const [error, setError] = React54.useState(null);
24920
- const switchingRef = React54.useRef(false);
24921
- const confirmLiveRef = React54.useRef(null);
24922
- const liveWarningId = React54.useId();
24927
+ const [busyChainId, setBusyChainId] = React55.useState(null);
24928
+ const [pendingLiveChainId, setPendingLiveChainId] = React55.useState(null);
24929
+ const [error, setError] = React55.useState(null);
24930
+ const switchingRef = React55.useRef(false);
24931
+ const confirmLiveRef = React55.useRef(null);
24932
+ const liveWarningId = React55.useId();
24923
24933
  const label = modeLabel(environment.mode);
24924
24934
  const modeCounts = { test: 0, live: 0, unknown: 0 };
24925
24935
  for (const option of options) modeCounts[option.mode] += 1;
24926
24936
  const pendingLive = options.find((option) => option.chainId === pendingLiveChainId) ?? null;
24927
- React54.useEffect(() => {
24937
+ React55.useEffect(() => {
24928
24938
  if (pendingLiveChainId) confirmLiveRef.current?.focus();
24929
24939
  }, [pendingLiveChainId]);
24930
24940
  async function switchTo(option) {
@@ -25684,7 +25694,7 @@ function WalletMenu({
25684
25694
  const secondaryItems = items.filter((item) => item.placement === "secondary");
25685
25695
  const activeActor = actors.find((actor) => actor.active) ?? actors[0];
25686
25696
  const userName = identity.name ?? "You";
25687
- const renderCard = (cardItems) => /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-[24px] border border-border-light bg-raised shadow-sm", children: cardItems.map((item, index) => /* @__PURE__ */ jsxs(React54.Fragment, { children: [
25697
+ const renderCard = (cardItems) => /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-[24px] border border-border-light bg-raised shadow-sm", children: cardItems.map((item, index) => /* @__PURE__ */ jsxs(React55.Fragment, { children: [
25688
25698
  index > 0 && /* @__PURE__ */ jsx("div", { className: "mx-4 border-t border-border-light" }),
25689
25699
  /* @__PURE__ */ jsx(
25690
25700
  WalletMenuRow,
@@ -25934,7 +25944,7 @@ function ActorsPane({
25934
25944
  error && /* @__PURE__ */ jsx(ErrorBanner, { children: error }),
25935
25945
  /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-[22px] border border-border-light bg-raised", children: actors.map((actor, index) => {
25936
25946
  const ActorIcon = actor.icon;
25937
- return /* @__PURE__ */ jsxs(React54.Fragment, { children: [
25947
+ return /* @__PURE__ */ jsxs(React55.Fragment, { children: [
25938
25948
  index > 0 && /* @__PURE__ */ jsx("div", { className: "mx-4 border-t border-border-light" }),
25939
25949
  /* @__PURE__ */ jsxs(
25940
25950
  "button",
@@ -27929,8 +27939,9 @@ var BillingCenter = ({ dense = false }) => {
27929
27939
  setLoadError(null);
27930
27940
  try {
27931
27941
  const s = await billingService.getMyBilling();
27942
+ setNotConfigured(s === null);
27932
27943
  if (s === null) {
27933
- setNotConfigured(true);
27944
+ setSummary(null);
27934
27945
  } else {
27935
27946
  setSummary(s);
27936
27947
  setItems(s.recent_line_items);
@@ -27944,7 +27955,7 @@ var BillingCenter = ({ dense = false }) => {
27944
27955
  }, []);
27945
27956
  useEffect(() => {
27946
27957
  void load();
27947
- void billingService.getGasPricing().then(setPricing);
27958
+ void billingService.getGasPricing().then(setPricing).catch(() => setPricing(null));
27948
27959
  }, [load]);
27949
27960
  useEffect(() => {
27950
27961
  const reloadAfterCheckout = () => void load();
@@ -27989,18 +28000,6 @@ var BillingCenter = ({ dense = false }) => {
27989
28000
  }
27990
28001
  }, [load]);
27991
28002
  const outerClass = dense ? "px-1 py-2" : "mx-auto max-w-5xl px-4 py-6";
27992
- if (notConfigured) {
27993
- return /* @__PURE__ */ jsxs("div", { className: outerClass, children: [
27994
- !dense && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
27995
- /* @__PURE__ */ jsxs("h1", { className: "text-lg font-semibold text-text-primary max-sm:sr-only", children: [
27996
- "Usage & billing",
27997
- !isLiveMode() && paymentsUrlMap() && /* @__PURE__ */ jsx("span", { className: "ml-2 align-middle inline-flex items-center px-2 py-0.5 rounded-full text-[10px] font-semibold uppercase tracking-wider bg-amber-500/15 text-amber-600 ring-1 ring-amber-500/40", children: "Test mode" })
27998
- ] }),
27999
- /* @__PURE__ */ jsx("p", { className: "text-sm text-text-muted", children: "Metered AI and on-chain usage." })
28000
- ] }),
28001
- /* @__PURE__ */ jsx("div", { className: `${CARD} px-4 py-10 text-center text-[13px] text-text-muted`, children: "Billing is not enabled on this deployment." })
28002
- ] });
28003
- }
28004
28003
  const totals = summary?.period_totals ?? [];
28005
28004
  const payableTotal = totals.reduce((acc, t) => acc + t.amount_usd_micros, 0);
28006
28005
  const personalTotal = summary?.spend?.period_usd_micros ?? payableTotal;
@@ -28076,6 +28075,18 @@ var BillingCenter = ({ dense = false }) => {
28076
28075
  const creditExhausted = prepaidCreditsEnabled && creditPlanId != null && creditBalanceMicros <= 0;
28077
28076
  const creditLow = prepaidCreditsEnabled && creditPlanId != null && creditBalanceMicros > 0 && creditGrantMicros != null && creditBalanceMicros < creditGrantMicros * 0.15;
28078
28077
  const recoveryAction = summary ? billingRecoveryAction(summary) : null;
28078
+ if (notConfigured) {
28079
+ return /* @__PURE__ */ jsxs("div", { className: outerClass, children: [
28080
+ !dense && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
28081
+ /* @__PURE__ */ jsxs("h1", { className: "text-lg font-semibold text-text-primary max-sm:sr-only", children: [
28082
+ "Usage & billing",
28083
+ !isLiveMode() && paymentsUrlMap() && /* @__PURE__ */ jsx("span", { className: "ml-2 align-middle inline-flex items-center px-2 py-0.5 rounded-full text-[10px] font-semibold uppercase tracking-wider bg-amber-500/15 text-amber-600 ring-1 ring-amber-500/40", children: "Test mode" })
28084
+ ] }),
28085
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-text-muted", children: "Metered AI and on-chain usage." })
28086
+ ] }),
28087
+ /* @__PURE__ */ jsx("div", { className: `${CARD} px-4 py-10 text-center text-[13px] text-text-muted`, children: "Billing is not enabled on this deployment." })
28088
+ ] });
28089
+ }
28079
28090
  return /* @__PURE__ */ jsxs("div", { className: outerClass, children: [
28080
28091
  !dense && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
28081
28092
  /* @__PURE__ */ jsxs("h1", { className: "text-lg font-semibold text-text-primary max-sm:sr-only", children: [
@@ -29757,25 +29768,25 @@ function BusinessVerificationSection({
29757
29768
  initialStatus
29758
29769
  }) {
29759
29770
  const { config } = useProviderConfig();
29760
- const [status, setStatus] = React54.useState(initialStatus ?? "not_required");
29761
- const [flowInstance, setFlowInstance] = React54.useState(null);
29762
- const [error, setError] = React54.useState(null);
29763
- const [busy, setBusy] = React54.useState(false);
29764
- const kybInstances = React54.useMemo(
29771
+ const [status, setStatus] = React55.useState(initialStatus ?? "not_required");
29772
+ const [flowInstance, setFlowInstance] = React55.useState(null);
29773
+ const [error, setError] = React55.useState(null);
29774
+ const [busy, setBusy] = React55.useState(false);
29775
+ const kybInstances = React55.useMemo(
29765
29776
  () => (config?.kyc.enabled ?? []).filter(
29766
29777
  (id) => config?.kyc.settings[id]?.subject === "group"
29767
29778
  ),
29768
29779
  [config]
29769
29780
  );
29770
29781
  const entityDefault = config?.kyc.entity_default_profile ?? null;
29771
- const refreshStatus = React54.useCallback(async () => {
29782
+ const refreshStatus = React55.useCallback(async () => {
29772
29783
  try {
29773
29784
  const s = await getIdentityStatus({ groupId });
29774
29785
  setStatus(s.status === "unverified" ? "unverified" : s.status);
29775
29786
  } catch {
29776
29787
  }
29777
29788
  }, [groupId]);
29778
- React54.useEffect(() => {
29789
+ React55.useEffect(() => {
29779
29790
  if (initialStatus !== void 0) setStatus(initialStatus);
29780
29791
  }, [initialStatus]);
29781
29792
  const startFlow = async (bindFirst) => {
@@ -30963,7 +30974,7 @@ var IncomingPaymentsInbox = ({
30963
30974
  ...hookOptions
30964
30975
  }) => {
30965
30976
  const inbox = useIncomingPayments(hookOptions);
30966
- const allPayments = React54.useMemo(
30977
+ const allPayments = React55.useMemo(
30967
30978
  () => [
30968
30979
  ...inbox.payments,
30969
30980
  ...inbox.contracts.flatMap((c) => c.payments ?? [])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yieldfabric/wallet",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "Reusable YieldFabric wallet — login, signing, profile, and key management",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "author": "YieldFabric Technologies Ltd",
@@ -55,7 +55,7 @@
55
55
  "build": "tsup",
56
56
  "dev": "tsup --watch",
57
57
  "clean": "rm -rf dist",
58
- "test:owned-group": "tsup --config tests/tsup.config.ts && node --test tests/ownedGroupSession.test.mjs tests/metaTransactionDigest.test.mjs tests/ownedGroupAuthorization.test.mjs tests/groupOwnershipRelationships.test.mjs tests/ownedGroupDelegationService.test.mjs tests/ownedGroupKeySelection.test.mjs tests/websocketAuthentication.test.mjs tests/withDeadline.test.mjs tests/onboardingCache.test.mjs tests/authFailure.test.mjs tests/jsonEventStream.test.mjs",
58
+ "test:owned-group": "tsup --config tests/tsup.config.ts && node --test tests/ownedGroupSession.test.mjs tests/metaTransactionDigest.test.mjs tests/ownedGroupAuthorization.test.mjs tests/groupOwnershipRelationships.test.mjs tests/ownedGroupDelegationService.test.mjs tests/ownedGroupKeySelection.test.mjs tests/websocketAuthentication.test.mjs tests/withDeadline.test.mjs tests/onboardingCache.test.mjs tests/authFailure.test.mjs tests/jsonEventStream.test.mjs tests/crossTabRefresh.test.mjs tests/twoWindowsRefresh.test.mjs",
59
59
  "typecheck": "tsc --noEmit",
60
60
  "prepublishOnly": "npm run clean && npm run build"
61
61
  },
@@ -112,6 +112,6 @@
112
112
  "axios": "1.20.0",
113
113
  "uuid": "11.1.1",
114
114
  "esbuild": "0.28.1",
115
- "sharp": "0.35.4"
115
+ "sharp": "0.35.5"
116
116
  }
117
117
  }