@capxul/sdk-react 0.1.0-alpha.9 → 0.2.0-alpha.4

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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import { createContext, useContext, useSyncExternalStore, useMemo, useEffect, useState } from 'react';
3
- import { makeHttpTransport, createCapxulClient, CapxulError as CapxulError$1 } from '@capxul/sdk';
4
- import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';
2
+ import { createContext, useContext, useSyncExternalStore, useMemo, useEffect, useState, useRef, useCallback } from 'react';
3
+ import { makeHttpTransport, createCapxulClient, AuthService, CapxulError as CapxulError$1, SignerProvisioner } from '@capxul/sdk';
4
+ import { QueryClient, QueryClientProvider, useQuery, useMutation } from '@tanstack/react-query';
5
5
  import { jsx } from 'react/jsx-runtime';
6
6
  import { ConvexReactClient } from 'convex/react';
7
7
  import { CapxulError as CapxulError$2 } from '@capxul/sdk/errors';
@@ -10,6 +10,22 @@ import { getAddress } from 'viem';
10
10
  import { privateKeyToAccount } from 'viem/accounts';
11
11
 
12
12
  // src/provider.tsx
13
+ var AuthServiceContext = createContext(null);
14
+ function AuthServiceProvider({
15
+ authService,
16
+ children
17
+ }) {
18
+ return /* @__PURE__ */ jsx(AuthServiceContext.Provider, { value: authService, children });
19
+ }
20
+ function useAuthService() {
21
+ const authService = useContext(AuthServiceContext);
22
+ if (!authService) {
23
+ throw new Error(
24
+ "useAuthService() was called outside a <CapxulProvider>. Wrap your app in <CapxulProvider config={...}> before rendering hooks from @capxul/sdk-react."
25
+ );
26
+ }
27
+ return authService;
28
+ }
13
29
  var CapxulClientContext = createContext(null);
14
30
  function CapxulClientProvider({
15
31
  client,
@@ -79,10 +95,16 @@ var Errors = {
79
95
  `Shield API error (${status}): ${detail}`,
80
96
  { details: { provider: "shield", status } }
81
97
  ),
82
- providerError: (provider, operation, cause) => new CapxulError(
83
- "PROVIDER_ERROR",
84
- `${provider} ${operation} failed: ${cause instanceof Error ? cause.message : String(cause)}`,
85
- { cause, details: { provider, operation } }
98
+ providerError: (provider, operation, cause) => (
99
+ // Public `message` is redacted to a fixed shape so provider-side
100
+ // exception text never leaks to the client. The original `cause`
101
+ // is preserved on `Error.cause` for server-side debugging via
102
+ // observability sinks (Sentry, console traces).
103
+ new CapxulError(
104
+ "PROVIDER_ERROR",
105
+ `Provider error: ${provider} ${operation}`,
106
+ { cause, details: { provider, operation } }
107
+ )
86
108
  ),
87
109
  invalidInput: (field, reason) => new CapxulError(
88
110
  "INVALID_INPUT",
@@ -147,7 +169,7 @@ function roleKeyFromLabel(label) {
147
169
  }
148
170
  roleKeyFromLabel("OWNER");
149
171
  roleKeyFromLabel("FINANCE_MANAGER");
150
- roleKeyFromLabel("TEAM_LEAD");
172
+ roleKeyFromLabel("PAYMENTS_OPERATOR");
151
173
 
152
174
  // src/config.ts
153
175
  function createCapxulConfig(input) {
@@ -286,7 +308,7 @@ function CapxulProvider({
286
308
  []
287
309
  );
288
310
  const effectiveClient = queryClient ?? defaultClient;
289
- return /* @__PURE__ */ jsx(QueryClientProvider, { client: effectiveClient, children: /* @__PURE__ */ jsx(CapxulTransportProvider, { transport: wiring.transport, children: /* @__PURE__ */ jsx(CapxulClientProvider, { client: wiring.client, children }) }) });
311
+ return /* @__PURE__ */ jsx(QueryClientProvider, { client: effectiveClient, children: /* @__PURE__ */ jsx(CapxulTransportProvider, { transport: wiring.transport, children: /* @__PURE__ */ jsx(CapxulClientProvider, { client: wiring.client, children: /* @__PURE__ */ jsx(AuthServiceProvider, { authService: wiring.authService, children }) }) }) });
290
312
  }
291
313
  function buildWiring(config, sessionStore) {
292
314
  const validated = createCapxulConfig(config);
@@ -295,7 +317,7 @@ function buildWiring(config, sessionStore) {
295
317
  const sdkConfig = {
296
318
  _transport: transport,
297
319
  publishableKey: validated.mode === "publishable-key" ? validated.publishableKey : void 0,
298
- data: dataClient ?? void 0,
320
+ _data: dataClient ?? void 0,
299
321
  auth: validated.mode === "build-time-urls" || validated.mode === "publishable-key" ? {
300
322
  // The auth client builds the BetterAuth root URL from this
301
323
  // value. Convex's `.cloud` URL is the wrong host (BetterAuth
@@ -305,29 +327,16 @@ function buildWiring(config, sessionStore) {
305
327
  // `core/auth.ts`'s `createTransportProvider` short-circuits
306
328
  // to the externally-injected `_transport` cache slot.
307
329
  baseUrl: transport.authBaseUrl,
308
- sessionStore,
309
- createDataClient: async (_session) => {
310
- dataClient.refreshAuth();
311
- return dataClient;
312
- }
330
+ sessionStore
313
331
  } : void 0
314
332
  };
315
333
  const client = createCapxulClient(sdkConfig);
316
- if (dataClient) {
317
- const originalSignOut = client.auth.signOut;
318
- Object.assign(client.auth, {
319
- signOut: async () => {
320
- const result = await originalSignOut();
321
- dataClient.refreshAuth();
322
- sdkConfig.data = dataClient;
323
- return result;
324
- }
325
- });
326
- }
334
+ const authService = new AuthService(sdkConfig);
327
335
  return {
328
336
  client,
329
337
  transport,
330
- dataClient
338
+ dataClient,
339
+ authService
331
340
  };
332
341
  }
333
342
  function createMemorySessionStore() {
@@ -436,11 +445,59 @@ function useAccount(accountId) {
436
445
  [capxul, accountId]
437
446
  );
438
447
  }
439
- function useOrganization(_organizationId) {
440
- return notImplementedQuery("useOrganization");
448
+ function useOrganization(organizationId) {
449
+ const capxul = useCapxul();
450
+ return useQuery({
451
+ queryKey: [capxul.id, "capxul", "organizations", organizationId],
452
+ queryFn: () => capxul.organizations.retrieve(organizationId).then(([error, data]) => {
453
+ if (error) {
454
+ throw error;
455
+ }
456
+ return data;
457
+ }).catch((cause) => {
458
+ if (cause instanceof CapxulError$1) {
459
+ throw cause;
460
+ }
461
+ throw new CapxulError$1({
462
+ code: "UNKNOWN",
463
+ message: "SDK read failed before returning a CapxulResult.",
464
+ cause
465
+ });
466
+ }),
467
+ staleTime: 3e4
468
+ });
441
469
  }
442
- function useMember(_args) {
443
- return notImplementedQuery("useMember");
470
+ function useMember(args) {
471
+ const capxul = useCapxul();
472
+ return useQuery({
473
+ queryKey: [
474
+ capxul.id,
475
+ "capxul",
476
+ "organizations",
477
+ args.organizationId,
478
+ "members",
479
+ args.memberId
480
+ ],
481
+ queryFn: () => capxul.organizations.members.retrieve({
482
+ organizationId: args.organizationId,
483
+ memberId: args.memberId
484
+ }).then(([error, data]) => {
485
+ if (error) {
486
+ throw error;
487
+ }
488
+ return data;
489
+ }).catch((cause) => {
490
+ if (cause instanceof CapxulError$1) {
491
+ throw cause;
492
+ }
493
+ throw new CapxulError$1({
494
+ code: "UNKNOWN",
495
+ message: "SDK read failed before returning a CapxulResult.",
496
+ cause
497
+ });
498
+ }),
499
+ staleTime: 3e4
500
+ });
444
501
  }
445
502
  function useSafe(safeId) {
446
503
  const capxul = useCapxul();
@@ -449,8 +506,33 @@ function useSafe(safeId) {
449
506
  [capxul, safeId]
450
507
  );
451
508
  }
452
- function useTreasury(_organizationId) {
453
- return notImplementedQuery("useTreasury");
509
+ function useTreasury(organizationId) {
510
+ const capxul = useCapxul();
511
+ return useQuery({
512
+ queryKey: [
513
+ capxul.id,
514
+ "capxul",
515
+ "organizations",
516
+ organizationId,
517
+ "treasury"
518
+ ],
519
+ queryFn: () => capxul.organizations.treasury.retrieve(organizationId).then(([error, data]) => {
520
+ if (error) {
521
+ throw error;
522
+ }
523
+ return data;
524
+ }).catch((cause) => {
525
+ if (cause instanceof CapxulError$1) {
526
+ throw cause;
527
+ }
528
+ throw new CapxulError$1({
529
+ code: "UNKNOWN",
530
+ message: "SDK read failed before returning a CapxulResult.",
531
+ cause
532
+ });
533
+ }),
534
+ staleTime: 3e4
535
+ });
454
536
  }
455
537
  function useApiKey(_args) {
456
538
  return notImplementedQuery("useApiKey");
@@ -458,9 +540,6 @@ function useApiKey(_args) {
458
540
  function useKycProfile(_accountId) {
459
541
  return notImplementedQuery("useKycProfile");
460
542
  }
461
- function useKybProfile(_organizationId) {
462
- return notImplementedQuery("useKybProfile");
463
- }
464
543
  function useExternalAccount(args) {
465
544
  const capxul = useCapxul();
466
545
  return useSdkQuery(
@@ -471,8 +550,12 @@ function useExternalAccount(args) {
471
550
  [capxul, args.ownerKind, args.ownerId, args.externalAccountId]
472
551
  );
473
552
  }
474
- function useSubAccount(_subAccountId) {
475
- return notImplementedQuery("useSubAccount");
553
+ function useSubAccount(subAccountId) {
554
+ const capxul = useCapxul();
555
+ return useSdkQuery(
556
+ () => capxul.subAccounts.retrieve(subAccountId),
557
+ [capxul, subAccountId]
558
+ );
476
559
  }
477
560
  function useVirtualAccount(_virtualAccountId) {
478
561
  return notImplementedQuery("useVirtualAccount");
@@ -480,8 +563,27 @@ function useVirtualAccount(_virtualAccountId) {
480
563
  function useVirtualCard(_virtualCardId) {
481
564
  return notImplementedQuery("useVirtualCard");
482
565
  }
483
- function usePayment(_paymentId) {
484
- return notImplementedQuery("usePayment");
566
+ function usePayment(paymentId) {
567
+ const capxul = useCapxul();
568
+ return useQuery({
569
+ queryKey: [capxul.id, "capxul", "payments", paymentId],
570
+ queryFn: () => capxul.payments.retrieve(paymentId).then(([error, data]) => {
571
+ if (error) {
572
+ throw error;
573
+ }
574
+ return data;
575
+ }).catch((cause) => {
576
+ if (cause instanceof CapxulError$1) {
577
+ throw cause;
578
+ }
579
+ throw new CapxulError$1({
580
+ code: "UNKNOWN",
581
+ message: "SDK read failed before returning a CapxulResult.",
582
+ cause
583
+ });
584
+ }),
585
+ staleTime: 3e4
586
+ });
485
587
  }
486
588
  function useTransfer(_transferId) {
487
589
  return notImplementedQuery("useTransfer");
@@ -493,25 +595,32 @@ function useTokenTransfer(args) {
493
595
  [capxul, args.txHash, args.logIndex, args.chainId]
494
596
  );
495
597
  }
496
- function useBalanceLedgerEntry(_args) {
497
- return notImplementedQuery("useBalanceLedgerEntry");
598
+ function useBalanceLedgerEntry(args) {
599
+ const capxul = useCapxul();
600
+ return useSdkQuery(
601
+ () => args.ownerKind === "account" ? capxul.accounts.balanceLedger.retrieve(args.entryId) : capxul.organizations.balanceLedger.retrieve({
602
+ organizationId: args.ownerId,
603
+ entryId: args.entryId
604
+ }),
605
+ [capxul, args.ownerKind, args.ownerId, args.entryId]
606
+ );
498
607
  }
499
608
  function useDocument(_documentId) {
500
609
  return notImplementedQuery("useDocument");
501
610
  }
502
611
  function useWithdrawal(withdrawalId) {
503
612
  const capxul = useCapxul();
504
- return useSdkQuery(() => capxul.withdrawals.retrieve(withdrawalId), [
505
- capxul,
506
- withdrawalId
507
- ]);
613
+ return useSdkQuery(
614
+ () => capxul.withdrawals.retrieve(withdrawalId),
615
+ [capxul, withdrawalId]
616
+ );
508
617
  }
509
618
  function useOperation(operationId) {
510
619
  const capxul = useCapxul();
511
- return useSdkQuery(() => capxul.operations.retrieve(operationId), [
512
- capxul,
513
- operationId
514
- ]);
620
+ return useSdkQuery(
621
+ () => capxul.operations.retrieve(operationId),
622
+ [capxul, operationId]
623
+ );
515
624
  }
516
625
  function useWebhookEndpoint(_endpointId) {
517
626
  return notImplementedQuery("useWebhookEndpoint");
@@ -519,13 +628,57 @@ function useWebhookEndpoint(_endpointId) {
519
628
  function useWebhookEvent(_eventId) {
520
629
  return notImplementedQuery("useWebhookEvent");
521
630
  }
522
-
523
- // src/hooks/list.ts
524
- function useOrganizations() {
525
- return notImplementedQuery("useOrganizations");
631
+ function useOrganizations(filters) {
632
+ const capxul = useCapxul();
633
+ return useQuery({
634
+ queryKey: [capxul.id, "capxul", "organizations", "list", filters],
635
+ queryFn: () => capxul.organizations.list(filters).then(([error, data]) => {
636
+ if (error) {
637
+ throw error;
638
+ }
639
+ return data;
640
+ }).catch((cause) => {
641
+ if (cause instanceof CapxulError$1) {
642
+ throw cause;
643
+ }
644
+ throw new CapxulError$1({
645
+ code: "UNKNOWN",
646
+ message: "SDK read failed before returning a CapxulResult.",
647
+ cause
648
+ });
649
+ }),
650
+ staleTime: 3e4
651
+ });
526
652
  }
527
- function useMembers(_organizationId) {
528
- return notImplementedQuery("useMembers");
653
+ function useMembers(organizationId, filters) {
654
+ const capxul = useCapxul();
655
+ return useQuery({
656
+ queryKey: [
657
+ capxul.id,
658
+ "capxul",
659
+ "organizations",
660
+ organizationId,
661
+ "members",
662
+ "list",
663
+ filters?.status
664
+ ],
665
+ queryFn: () => capxul.organizations.members.list({ organizationId, status: filters?.status }).then(([error, data]) => {
666
+ if (error) {
667
+ throw error;
668
+ }
669
+ return data;
670
+ }).catch((cause) => {
671
+ if (cause instanceof CapxulError$1) {
672
+ throw cause;
673
+ }
674
+ throw new CapxulError$1({
675
+ code: "UNKNOWN",
676
+ message: "SDK read failed before returning a CapxulResult.",
677
+ cause
678
+ });
679
+ }),
680
+ staleTime: 3e4
681
+ });
529
682
  }
530
683
  function useExternalAccounts(args) {
531
684
  const capxul = useCapxul();
@@ -536,8 +689,14 @@ function useExternalAccounts(args) {
536
689
  [capxul, args.ownerKind, args.ownerId]
537
690
  );
538
691
  }
539
- function useSubAccounts(_args) {
540
- return notImplementedQuery("useSubAccounts");
692
+ function useSubAccounts(args) {
693
+ const capxul = useCapxul();
694
+ return useSdkQuery(
695
+ () => args.ownerKind === "account" ? capxul.accounts.subAccounts.list({ accountId: args.ownerId }) : capxul.organizations.subAccounts.list({
696
+ organizationId: args.ownerId
697
+ }),
698
+ [capxul, args.ownerKind, args.ownerId]
699
+ );
541
700
  }
542
701
  function useVirtualAccounts(_filters) {
543
702
  return notImplementedQuery("useVirtualAccounts");
@@ -545,8 +704,27 @@ function useVirtualAccounts(_filters) {
545
704
  function useVirtualCards(_filters) {
546
705
  return notImplementedQuery("useVirtualCards");
547
706
  }
548
- function usePayments(_filters) {
549
- return notImplementedQuery("usePayments");
707
+ function usePayments(filters) {
708
+ const capxul = useCapxul();
709
+ return useQuery({
710
+ queryKey: [capxul.id, "capxul", "payments", "list", filters],
711
+ queryFn: () => capxul.payments.list(filters).then(([error, data]) => {
712
+ if (error) {
713
+ throw error;
714
+ }
715
+ return data;
716
+ }).catch((cause) => {
717
+ if (cause instanceof CapxulError$1) {
718
+ throw cause;
719
+ }
720
+ throw new CapxulError$1({
721
+ code: "UNKNOWN",
722
+ message: "SDK read failed before returning a CapxulResult.",
723
+ cause
724
+ });
725
+ }),
726
+ staleTime: 3e4
727
+ });
550
728
  }
551
729
  function useOrgPayments(_args) {
552
730
  return notImplementedQuery("useOrgPayments");
@@ -564,8 +742,34 @@ function useTokenTransfers(filters) {
564
742
  [capxul, filters?.limit, filters?.cursor, filters?.direction]
565
743
  );
566
744
  }
567
- function useBalanceLedger(_args) {
568
- return notImplementedQuery("useBalanceLedger");
745
+ function useBalanceLedger(args) {
746
+ const capxul = useCapxul();
747
+ return useSdkQuery(
748
+ () => args.ownerKind === "account" ? capxul.accounts.balanceLedger.list({
749
+ accountId: args.ownerId,
750
+ limit: args.limit,
751
+ cursor: args.cursor
752
+ }) : capxul.organizations.balanceLedger.list({
753
+ organizationId: args.ownerId,
754
+ limit: args.limit,
755
+ cursor: args.cursor
756
+ }),
757
+ [capxul, args.ownerKind, args.ownerId, args.limit, args.cursor]
758
+ );
759
+ }
760
+ function useAccountBalanceLedger(accountId, filters) {
761
+ const capxul = useCapxul();
762
+ return useSdkQuery(
763
+ () => capxul.accounts.balanceLedger.list({ accountId, ...filters }),
764
+ [capxul, accountId, filters?.limit, filters?.cursor]
765
+ );
766
+ }
767
+ function useOrgBalanceLedger(args) {
768
+ const capxul = useCapxul();
769
+ return useSdkQuery(
770
+ () => capxul.organizations.balanceLedger.list(args),
771
+ [capxul, args.organizationId, args.limit, args.cursor]
772
+ );
569
773
  }
570
774
  function useDocuments(_filters) {
571
775
  return notImplementedQuery("useDocuments");
@@ -593,17 +797,337 @@ function useApiKeys(_organizationId) {
593
797
  function useWebhookEndpoints() {
594
798
  return notImplementedQuery("useWebhookEndpoints");
595
799
  }
596
- function useAuthFlow() {
597
- const client = useCapxul();
598
- const machine = useMemo(() => client.flows.auth(), [client]);
599
- const [snapshot, send] = useActor(machine);
600
- return { snapshot, send };
800
+ function useInviteMember() {
801
+ const capxul = useCapxul();
802
+ return useMutation({
803
+ mutationFn: async (args) => {
804
+ const [error, data] = await capxul.organizations.members.invite(args);
805
+ if (error) throw error;
806
+ return data;
807
+ }
808
+ });
601
809
  }
602
- function useAuthBootstrapFlow() {
603
- const client = useCapxul();
604
- const machine = useMemo(() => client.flows.authBootstrap(), [client]);
605
- const [snapshot, send] = useActor(machine);
606
- return { snapshot, send };
810
+ function useAcceptInvitation() {
811
+ const capxul = useCapxul();
812
+ return useMutation({
813
+ mutationFn: async (args) => {
814
+ const [error, data] = await capxul.organizations.members.accept(args);
815
+ if (error) throw error;
816
+ return data;
817
+ }
818
+ });
819
+ }
820
+ function useUpdateMemberRole() {
821
+ const capxul = useCapxul();
822
+ return useMutation({
823
+ mutationFn: async (args) => {
824
+ const [error, data] = await capxul.organizations.members.updateRole(args);
825
+ if (error) throw error;
826
+ return data;
827
+ }
828
+ });
829
+ }
830
+ function useRevokeMember() {
831
+ const capxul = useCapxul();
832
+ return useMutation({
833
+ mutationFn: async (args) => {
834
+ const [error, data] = await capxul.organizations.members.revoke(args);
835
+ if (error) throw error;
836
+ return data;
837
+ }
838
+ });
839
+ }
840
+ function useRemoveMember() {
841
+ const capxul = useCapxul();
842
+ return useMutation({
843
+ mutationFn: async (args) => {
844
+ const [error, data] = await capxul.organizations.members.remove(args);
845
+ if (error) throw error;
846
+ return data;
847
+ }
848
+ });
849
+ }
850
+ function useResendInvitation() {
851
+ const capxul = useCapxul();
852
+ return useMutation({
853
+ mutationFn: async (args) => {
854
+ const [error, data] = await capxul.organizations.members.resend(args);
855
+ if (error) throw error;
856
+ return data;
857
+ }
858
+ });
859
+ }
860
+
861
+ // ../observability/src/debug-log.ts
862
+ function isDevelopmentBuild() {
863
+ if (typeof process === "undefined") {
864
+ return false;
865
+ }
866
+ return process.env?.NODE_ENV === "development" || process.env?.NODE_ENV === "test";
867
+ }
868
+ function debugLog(line) {
869
+ if (!isDevelopmentBuild()) return;
870
+ if (typeof globalThis !== "undefined" && "window" in globalThis && typeof console?.info === "function") {
871
+ console.info(line);
872
+ return;
873
+ }
874
+ if (typeof process !== "undefined" && typeof process.stderr?.write === "function") {
875
+ process.stderr.write(`${line}
876
+ `);
877
+ }
878
+ }
879
+ function formatDebugValue(value) {
880
+ if (value === void 0 || value === "") return "";
881
+ if (typeof value === "string") return value;
882
+ try {
883
+ return JSON.stringify(value);
884
+ } catch {
885
+ return String(value);
886
+ }
887
+ }
888
+ function track(...args) {
889
+ const [name, props] = args;
890
+ debugLog(`[TRACK] ${name} ${formatDebugValue(props ?? "")}`);
891
+ }
892
+ function formatDebugValue2(value) {
893
+ if (value === void 0 || value === "") return "";
894
+ if (typeof value === "string") return value;
895
+ try {
896
+ return JSON.stringify(value);
897
+ } catch {
898
+ return String(value);
899
+ }
900
+ }
901
+ function identify(userId, traits) {
902
+ debugLog(`[IDENTIFY] ${userId} ${formatDebugValue2(traits ?? "")}`);
903
+ }
904
+ function resetIdentity() {
905
+ }
906
+ function useAuth(options) {
907
+ const authService = useAuthService();
908
+ const signerProvisioner = useMemoizedSignerProvisioner();
909
+ const injectedSigner = options?.signer;
910
+ const [state, setState] = useState("idle");
911
+ const [user, setUser] = useState(null);
912
+ const [bootstrap, setBootstrap] = useState(
913
+ null
914
+ );
915
+ const bootstrapRef = useRef(null);
916
+ const [error, setError] = useState(null);
917
+ const signIn = useCallback(
918
+ async (email) => {
919
+ setState("sendingOtp");
920
+ setError(null);
921
+ try {
922
+ await authService.sendOtp(email);
923
+ track("auth_otp_requested", {
924
+ email_domain: emailDomain(email)
925
+ });
926
+ setState("awaitingOtp");
927
+ } catch (err) {
928
+ const wrapped = err instanceof Error ? err : new Error(String(err));
929
+ trackAuthFailure("otp_request", wrapped);
930
+ setError(wrapped);
931
+ setState("error");
932
+ throw wrapped;
933
+ }
934
+ },
935
+ [authService]
936
+ );
937
+ const verifyOtp = useCallback(
938
+ async (email, otp) => {
939
+ setState("awaitingOtp");
940
+ setError(null);
941
+ try {
942
+ const result = await authService.verifyOtp(email, otp);
943
+ if (result.kind === "existing_member") {
944
+ track("auth_otp_verified", {
945
+ email_domain: emailDomain(result.session.email),
946
+ branch: "existing_member"
947
+ });
948
+ const nextUser = {
949
+ account: result.account,
950
+ username: result.username,
951
+ safe: result.safe,
952
+ session: result.session
953
+ };
954
+ setUser(nextUser);
955
+ setBootstrap(null);
956
+ bootstrapRef.current = null;
957
+ identify(result.session.authUserId, {
958
+ auth_branch: "existing_member"
959
+ });
960
+ track("auth_session_ready", {
961
+ branch: "existing_member",
962
+ has_convex_jwt: typeof result.session.convexJwt === "string"
963
+ });
964
+ setState("authenticated");
965
+ return {
966
+ kind: "existing_member",
967
+ session: result.session,
968
+ user: nextUser
969
+ };
970
+ }
971
+ const nextBootstrap = {
972
+ bootstrapToken: result.bootstrapToken,
973
+ email: result.email,
974
+ reason: result.reason,
975
+ username: result.username,
976
+ session: result.session
977
+ };
978
+ setUser(null);
979
+ setBootstrap(nextBootstrap);
980
+ bootstrapRef.current = nextBootstrap;
981
+ track("auth_otp_verified", {
982
+ email_domain: emailDomain(result.session.email),
983
+ branch: "bootstrap_required"
984
+ });
985
+ track("auth_bootstrap_required", {
986
+ reason: result.reason,
987
+ has_suggested_username: result.username !== void 0,
988
+ has_convex_jwt: typeof result.session.convexJwt === "string"
989
+ });
990
+ setState("bootstrapRequired");
991
+ return {
992
+ kind: "bootstrap_required",
993
+ session: result.session,
994
+ bootstrap: nextBootstrap
995
+ };
996
+ } catch (err) {
997
+ const wrapped = err instanceof Error ? err : new Error(String(err));
998
+ trackAuthFailure("otp_verify", wrapped);
999
+ setError(wrapped);
1000
+ setState("error");
1001
+ throw wrapped;
1002
+ }
1003
+ },
1004
+ [authService]
1005
+ );
1006
+ const completeBootstrap = useCallback(
1007
+ async (username, signer) => {
1008
+ const pendingBootstrap = bootstrapRef.current;
1009
+ if (!pendingBootstrap) {
1010
+ const missing = new Error(
1011
+ "completeBootstrap requires a prior bootstrap_required OTP result."
1012
+ );
1013
+ track("auth_session_lost", { step: "complete_bootstrap" });
1014
+ setError(missing);
1015
+ setState("error");
1016
+ throw missing;
1017
+ }
1018
+ setError(null);
1019
+ track("auth_username_submitted", {
1020
+ has_suggested_username: pendingBootstrap.username !== void 0
1021
+ });
1022
+ setState("provisioningSigner");
1023
+ try {
1024
+ const signerKind = signer ? "provided" : injectedSigner ? "configured" : "generated";
1025
+ const selectedSigner = signer ?? injectedSigner ?? signerProvisioner.provision().signer;
1026
+ track("auth_signer_provisioned", { signer_kind: signerKind });
1027
+ setState("bootstrapping");
1028
+ const bootstrapResult = await authService.completeBootstrap(
1029
+ {
1030
+ bootstrapToken: pendingBootstrap.bootstrapToken,
1031
+ username
1032
+ },
1033
+ selectedSigner
1034
+ );
1035
+ const nextUser = {
1036
+ account: bootstrapResult.account,
1037
+ username: bootstrapResult.username,
1038
+ safe: bootstrapResult.safe,
1039
+ session: bootstrapResult.session
1040
+ };
1041
+ track("auth_safe_provisioned", {
1042
+ safe_status: bootstrapResult.safe.status
1043
+ });
1044
+ setUser(nextUser);
1045
+ setBootstrap(null);
1046
+ bootstrapRef.current = null;
1047
+ identify(bootstrapResult.session.authUserId, {
1048
+ auth_branch: "bootstrap_required"
1049
+ });
1050
+ track("auth_bootstrap_completed", {
1051
+ reason: pendingBootstrap.reason
1052
+ });
1053
+ track("auth_session_ready", {
1054
+ branch: "bootstrap_required",
1055
+ has_convex_jwt: typeof bootstrapResult.session.convexJwt === "string"
1056
+ });
1057
+ setState("authenticated");
1058
+ return nextUser;
1059
+ } catch (err) {
1060
+ const wrapped = err instanceof Error ? err : new Error(String(err));
1061
+ trackAuthFailure("complete_bootstrap", wrapped);
1062
+ setError(wrapped);
1063
+ setState("error");
1064
+ throw wrapped;
1065
+ }
1066
+ },
1067
+ [authService, injectedSigner, signerProvisioner]
1068
+ );
1069
+ const signOut = useCallback(async () => {
1070
+ setError(null);
1071
+ try {
1072
+ await authService.signOut();
1073
+ track("auth_signed_out");
1074
+ resetIdentity();
1075
+ setUser(null);
1076
+ setBootstrap(null);
1077
+ bootstrapRef.current = null;
1078
+ setState("idle");
1079
+ } catch (err) {
1080
+ const wrapped = err instanceof Error ? err : new Error(String(err));
1081
+ trackAuthFailure("sign_out", wrapped);
1082
+ setError(wrapped);
1083
+ setState("error");
1084
+ throw wrapped;
1085
+ }
1086
+ }, [authService]);
1087
+ return useMemo(
1088
+ () => ({
1089
+ state,
1090
+ user,
1091
+ bootstrap,
1092
+ error,
1093
+ signIn,
1094
+ verifyOtp,
1095
+ completeBootstrap,
1096
+ signOut
1097
+ }),
1098
+ [
1099
+ state,
1100
+ user,
1101
+ bootstrap,
1102
+ error,
1103
+ signIn,
1104
+ verifyOtp,
1105
+ completeBootstrap,
1106
+ signOut
1107
+ ]
1108
+ );
1109
+ }
1110
+ function useMemoizedSignerProvisioner() {
1111
+ const [provisioner] = useState(() => new SignerProvisioner());
1112
+ return provisioner;
1113
+ }
1114
+ function emailDomain(email) {
1115
+ const domain = email.split("@")[1]?.trim().toLowerCase();
1116
+ return domain && /^[a-z0-9.-]+$/.test(domain) ? domain : "unknown";
1117
+ }
1118
+ function trackAuthFailure(step, error) {
1119
+ const reason = errorCode(error);
1120
+ if (reason === "PERMISSION_DENIED" || reason === "AUTHZ_DENIED") {
1121
+ track("authz_denied", { step, reason });
1122
+ }
1123
+ track("auth_failed", {
1124
+ step,
1125
+ reason
1126
+ });
1127
+ }
1128
+ function errorCode(error) {
1129
+ const code = error.code;
1130
+ return typeof code === "string" && code.length > 0 ? code : error.name || "Error";
607
1131
  }
608
1132
  function useOnboardingFlow() {
609
1133
  const client = useCapxul();
@@ -658,10 +1182,6 @@ function localPrivateKeyConnector(options) {
658
1182
  "must be a 0x-prefixed 32-byte (64 hex chars) string."
659
1183
  );
660
1184
  }
661
- const safeAddress = validateAndNormalizeEvmAddress(
662
- "safeAddress",
663
- options.safeAddress
664
- );
665
1185
  const id = options.id ?? "local-private-key";
666
1186
  return {
667
1187
  id,
@@ -673,13 +1193,7 @@ function localPrivateKeyConnector(options) {
673
1193
  return {
674
1194
  connectorId: id,
675
1195
  connectorKind: "local-private-key",
676
- signerAddress: account.address,
677
- safeAddress,
678
- signerProvider: {
679
- kind: "local-private-key",
680
- signerAddress: account.address,
681
- safeAddress
682
- }
1196
+ signerAddress: account.address
683
1197
  };
684
1198
  }
685
1199
  };
@@ -713,4 +1227,4 @@ function validateAndNormalizeEvmAddress(field, raw) {
713
1227
  }
714
1228
  }
715
1229
 
716
- export { CapxulClientProvider, CapxulProvider, CapxulTransportProvider, createCapxulConfig, injectedConnector, localPrivateKeyConnector, useAccount, useApiKey, useApiKeys, useAuthBootstrapFlow, useAuthFlow, useBalanceLedger, useBalanceLedgerEntry, useCapxul, useCapxulStatus, useDocument, useDocuments, useExternalAccount, useExternalAccounts, useKybProfile, useKycProfile, useMe, useMember, useMembers, useOnboardingFlow, useOperation, useOrgDocuments, useOrgPayments, useOrgTransfers, useOrgWithdrawals, useOrganization, useOrganizations, usePayment, usePayments, useProvisioningFlow, useSafe, useSubAccount, useSubAccounts, useTokenTransfer, useTokenTransfers, useTransfer, useTransfers, useTreasury, useVirtualAccount, useVirtualAccounts, useVirtualCard, useVirtualCards, useWebhookEndpoint, useWebhookEndpoints, useWebhookEvent, useWithdrawal, useWithdrawals };
1230
+ export { CapxulClientProvider, CapxulProvider, CapxulTransportProvider, createCapxulConfig, injectedConnector, localPrivateKeyConnector, useAcceptInvitation, useAccount, useAccountBalanceLedger, useApiKey, useApiKeys, useAuth, useBalanceLedger, useBalanceLedgerEntry, useCapxul, useCapxulStatus, useDocument, useDocuments, useExternalAccount, useExternalAccounts, useInviteMember, useKycProfile, useMe, useMember, useMembers, useOnboardingFlow, useOperation, useOrgBalanceLedger, useOrgDocuments, useOrgPayments, useOrgTransfers, useOrgWithdrawals, useOrganization, useOrganizations, usePayment, usePayments, useProvisioningFlow, useRemoveMember, useResendInvitation, useRevokeMember, useSafe, useSubAccount, useSubAccounts, useTokenTransfer, useTokenTransfers, useTransfer, useTransfers, useTreasury, useUpdateMemberRole, useVirtualAccount, useVirtualAccounts, useVirtualCard, useVirtualCards, useWebhookEndpoint, useWebhookEndpoints, useWebhookEvent, useWithdrawal, useWithdrawals };