@capxul/sdk-react 0.1.0-alpha.6 → 0.1.0-alpha.9

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/CHANGELOG.md CHANGED
@@ -1,6 +1,25 @@
1
1
  # @capxul/sdk-react
2
2
 
3
- ## 0.1.0-alpha.6
3
+ ## 0.1.0-alpha.9
4
+
5
+ ### Minor Changes
6
+
7
+ - Add the canonical auth bootstrap flow.
8
+
9
+ `verifyOtp()` now resolves a verified email session into either an
10
+ `existing_member` identity or a `bootstrap_required` continuation. New and
11
+ incomplete members continue through `completeBootstrap()`, which validates a
12
+ server-issued bootstrap token, claims the username, provisions the account/Safe
13
+ through the backend bootstrap path, and returns the authenticated product
14
+ identity. The React SDK adds `useAuthBootstrapFlow()` as the typed first-run
15
+ flow wrapper.
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies
20
+ - @capxul/sdk@0.1.0-alpha.9
21
+
22
+ ## 0.1.0-alpha.8
4
23
 
5
24
  ### Minor Changes
6
25
 
@@ -32,21 +51,7 @@
32
51
  ### Patch Changes
33
52
 
34
53
  - Updated dependencies [57203a4]
35
- - @capxul/sdk@0.1.0-alpha.6
36
-
37
- ## 0.1.0-alpha.5
38
-
39
- ### Patch Changes
40
-
41
- - Widen the React peer dependency to `>=18.2.0 <20` so React 18-era Ink 5
42
- CLI apps can install `@capxul/sdk-react` without forcing React 19 into
43
- Ink's React reconciler. The provider and hooks only use React 18-compatible
44
- APIs (`createContext`, `useContext`, `useMemo`, `useEffect`, `useState`, and
45
- `useSyncExternalStore`), preserving React 19 compatibility while unblocking
46
- React 18 hosts.
47
-
48
- - Updated dependencies
49
- - @capxul/sdk@0.1.0-alpha.5
54
+ - @capxul/sdk@0.1.0-alpha.8
50
55
 
51
56
  ## 0.1.0-alpha.4
52
57
 
package/README.md CHANGED
@@ -40,7 +40,12 @@ import { CapxulProvider } from "@capxul/sdk-react";
40
40
 
41
41
  export default function RootLayout({ children }) {
42
42
  return (
43
- <CapxulProvider publishableKey={process.env.NEXT_PUBLIC_CAPXUL_KEY!}>
43
+ <CapxulProvider
44
+ config={{
45
+ mode: "publishable-key",
46
+ publishableKey: process.env.NEXT_PUBLIC_CAPXUL_PUBLISHABLE_KEY!,
47
+ }}
48
+ >
44
49
  {children}
45
50
  </CapxulProvider>
46
51
  );
@@ -119,6 +124,21 @@ subscription against the transport singleton — only the components
119
124
  that actually call it re-render when state changes. The provider
120
125
  itself never re-renders.
121
126
 
127
+ ## Publishable-key proof status
128
+
129
+ The publishable-key path is runtime-proven where the repo can run it
130
+ without secrets:
131
+
132
+ | Surface | Runtime proof | Expected safe signal |
133
+ |---|---|---|
134
+ | Provider + `useMe()` | `corepack pnpm --filter @capxul/sdk-react check-types` plus the headless proof tests under `packages/sdk-react/ops/proof` | provider reaches `useCapxulStatus().status === "ready"` after one bootstrap request |
135
+ | Reference CLI mock | `corepack pnpm --filter @capxul/reference-cli build && node apps/reference-cli/dist/cli.js bootstrap probe --mock --json` | `ok:true`, `mode:"publishable-key"`, `bootstrapRequests:1`, `authRequests:1`, `keyLengthClass:"provided"` |
136
+ | Reference CLI live | same command without `--mock`, with `CAPXUL_REF_PUBLISHABLE_KEY` and optional `CAPXUL_REF_BOOTSTRAP_URL` set locally | success only when the key/origin/runtime are valid; otherwise sanitized SDK error JSON |
137
+
138
+ Do not paste or commit publishable keys, session tokens, Convex JWTs,
139
+ cookies, or provider payloads. Proof output reports only
140
+ `keyLengthClass`.
141
+
122
142
  ## Hooks catalogue
123
143
 
124
144
  | Surface | Hook |
package/dist/index.cjs CHANGED
@@ -110,7 +110,12 @@ var Errors = {
110
110
  "Idempotency key was already used for a different request",
111
111
  { details }
112
112
  ),
113
- emailDeliveryFailed: (detail) => new CapxulError("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`),
113
+ emailDeliveryFailed: (detail, details) => new CapxulError("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`, {
114
+ details
115
+ }),
116
+ rateLimited: (details) => new CapxulError("RATE_LIMITED", "Request was rate limited", {
117
+ details: { ...details }
118
+ }),
114
119
  internalError: (reason) => new CapxulError("INTERNAL_ERROR", `Internal error: ${reason}`),
115
120
  /**
116
121
  * Verification gate. Surfaced when a request hits a verification
@@ -217,6 +222,48 @@ function createReactDataClient(convexUrl, sessionStore) {
217
222
  }
218
223
  };
219
224
  }
225
+ function createLazyReactDataClient(transport, sessionStore, createClient = createReactDataClient) {
226
+ let client = null;
227
+ let initializeClient = null;
228
+ let closed = false;
229
+ function closedError() {
230
+ return new Error("Capxul React data client is closed");
231
+ }
232
+ async function getClient() {
233
+ if (closed) throw closedError();
234
+ if (client) return client;
235
+ initializeClient ??= (async () => {
236
+ const runtime = await transport.ensureRuntime();
237
+ if (closed) throw closedError();
238
+ const nextClient = createClient(runtime.convexUrl, sessionStore);
239
+ if (closed) {
240
+ nextClient.close();
241
+ throw closedError();
242
+ }
243
+ client = nextClient;
244
+ return nextClient;
245
+ })().catch((error) => {
246
+ if (!closed) {
247
+ initializeClient = null;
248
+ }
249
+ throw error;
250
+ });
251
+ return initializeClient;
252
+ }
253
+ return {
254
+ query: async (name, args) => (await getClient()).query(name, args),
255
+ mutation: async (name, args) => (await getClient()).mutation(name, args),
256
+ action: async (name, args) => (await getClient()).action?.(name, args),
257
+ refreshAuth: () => {
258
+ client?.refreshAuth();
259
+ },
260
+ close: () => {
261
+ closed = true;
262
+ client?.close();
263
+ client = null;
264
+ }
265
+ };
266
+ }
220
267
  function CapxulProvider({
221
268
  config,
222
269
  sessionStore,
@@ -246,12 +293,12 @@ function CapxulProvider({
246
293
  function buildWiring(config, sessionStore) {
247
294
  const validated = createCapxulConfig(config);
248
295
  const transport = sdk.makeHttpTransport(validated);
249
- const dataClient = validated.mode === "build-time-urls" ? createReactDataClient(validated.convexUrl, sessionStore) : null;
296
+ const dataClient = validated.mode === "build-time-urls" ? createReactDataClient(validated.convexUrl, sessionStore) : createLazyReactDataClient(transport, sessionStore);
250
297
  const sdkConfig = {
251
298
  _transport: transport,
252
299
  publishableKey: validated.mode === "publishable-key" ? validated.publishableKey : void 0,
253
300
  data: dataClient ?? void 0,
254
- auth: dataClient ? {
301
+ auth: validated.mode === "build-time-urls" || validated.mode === "publishable-key" ? {
255
302
  // The auth client builds the BetterAuth root URL from this
256
303
  // value. Convex's `.cloud` URL is the wrong host (BetterAuth
257
304
  // is mounted on the `.site` URL), but the build-time-urls
@@ -554,6 +601,12 @@ function useAuthFlow() {
554
601
  const [snapshot, send] = react$1.useActor(machine);
555
602
  return { snapshot, send };
556
603
  }
604
+ function useAuthBootstrapFlow() {
605
+ const client = useCapxul();
606
+ const machine = react.useMemo(() => client.flows.authBootstrap(), [client]);
607
+ const [snapshot, send] = react$1.useActor(machine);
608
+ return { snapshot, send };
609
+ }
557
610
  function useOnboardingFlow() {
558
611
  const client = useCapxul();
559
612
  const machine = react.useMemo(() => client.flows.onboarding(), [client]);
@@ -671,6 +724,7 @@ exports.localPrivateKeyConnector = localPrivateKeyConnector;
671
724
  exports.useAccount = useAccount;
672
725
  exports.useApiKey = useApiKey;
673
726
  exports.useApiKeys = useApiKeys;
727
+ exports.useAuthBootstrapFlow = useAuthBootstrapFlow;
674
728
  exports.useAuthFlow = useAuthFlow;
675
729
  exports.useBalanceLedger = useBalanceLedger;
676
730
  exports.useBalanceLedgerEntry = useBalanceLedgerEntry;
package/dist/index.d.cts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { ReactNode } from 'react';
2
+ import * as _capxul_sdk from '@capxul/sdk';
2
3
  import { HttpTransport, TransportState, BrowserCapxulConfig, AuthSessionStore, AccountId, OrganizationId, ApiKeyId, BalanceLedgerEntryId, ExternalAccountId, MemberId, Account, ApiKey, BalanceLedgerEntry, DocumentId, Document, ExternalAccount, KybProfile, KycProfile, CapxulError as CapxulError$1, Member, OperationId, Operation, Organization, PaymentId, Payment, SafeId, Safe, SubAccountId, SubAccount, TokenTransfer, TransferId, Transfer, Treasury, VirtualAccountId, VirtualAccount, VirtualCardId, VirtualCard, WebhookEndpointId, WebhookEndpoint, WebhookEventId, WebhookEvent, WithdrawalId, Withdrawal, List, TokenTransfersListInput, TokenTransfersListPage, LocalPrivateKeySignerProvider } from '@capxul/sdk';
3
- export { AuthFlowContext, AuthFlowEvent, BrowserCapxulConfig, OnboardingFlowContext, OnboardingFlowEvent, ProvisioningFlowContext, ProvisioningFlowEvent } from '@capxul/sdk';
4
+ export { AuthBootstrapFlowContext, AuthBootstrapFlowEvent, AuthFlowContext, AuthFlowEvent, BrowserCapxulConfig, OnboardingFlowContext, OnboardingFlowEvent, ProvisioningFlowContext, ProvisioningFlowEvent } from '@capxul/sdk';
4
5
  import { QueryClient, UseQueryResult } from '@tanstack/react-query';
5
6
  import { CapxulClient } from '@capxul/sdk/client';
6
7
  import { CapxulError } from '@capxul/sdk/errors';
@@ -444,10 +445,106 @@ declare function useApiKeys(_organizationId: OrganizationId): QueryResult<List<A
444
445
  */
445
446
  declare function useWebhookEndpoints(): QueryResult<List<WebhookEndpoint>>;
446
447
 
448
+ /**
449
+ * Lowercased, shape-validated email address. Brand prevents swapping
450
+ * with `phoneNumber`, `username`, or other string identifiers (per
451
+ * `CANON.md` §4.54 and `sdk-surface.md` §5h).
452
+ */
453
+ type Email = string & {
454
+ readonly __capxulEmailBrand: "Email";
455
+ };
456
+ /**
457
+ * Public Capxul username. 3–30 chars, letter-first, lowercased,
458
+ * remaining chars from `[a-z0-9_-]` (per `CANON.md` §4.54 and
459
+ * `sdk-surface.md` §5h). Constructor lowercases before validating so
460
+ * mixed-case input canonicalizes cleanly when the first char is a
461
+ * letter; purely invalid shapes (too short, illegal chars, digit-first)
462
+ * still throw.
463
+ */
464
+ type Username = string & {
465
+ readonly __capxulUsernameBrand: "Username";
466
+ };
467
+
447
468
  declare function useAuthFlow(): {
448
469
  readonly snapshot: xstate.MachineSnapshot<any, any, any, any, any, any, any, any>;
449
470
  readonly send: (event: any) => void;
450
471
  };
472
+ declare function useAuthBootstrapFlow(): {
473
+ readonly snapshot: xstate.MachineSnapshot<_capxul_sdk.AuthBootstrapFlowContext, {
474
+ readonly type: "ENTER_EMAIL";
475
+ readonly email: Email;
476
+ } | {
477
+ readonly type: "REQUEST_OTP";
478
+ } | {
479
+ readonly type: "ENTER_OTP";
480
+ readonly code: string;
481
+ } | {
482
+ readonly type: "VERIFY_OTP";
483
+ } | {
484
+ readonly type: "ENTER_USERNAME";
485
+ readonly username: Username;
486
+ } | {
487
+ readonly type: "ENTER_SIGNER_PROVIDER";
488
+ readonly signerProvider: _capxul_sdk.LocalPrivateKeySignerProvider;
489
+ } | {
490
+ readonly type: "COMPLETE_BOOTSTRAP";
491
+ } | {
492
+ readonly type: "BACK";
493
+ } | {
494
+ readonly type: "RESET";
495
+ } | {
496
+ readonly type: "SIGN_OUT";
497
+ }, {
498
+ [x: string]: xstate.ActorRefFromLogic<xstate.PromiseActorLogic<void, void, xstate.EventObject>> | xstate.ActorRefFromLogic<xstate.PromiseActorLogic<_capxul_sdk.CompleteBootstrapResult, {
499
+ bootstrapToken: _capxul_sdk.AuthBootstrapToken;
500
+ username: Username;
501
+ signerProvider: _capxul_sdk.LocalPrivateKeySignerProvider;
502
+ }, xstate.EventObject>> | xstate.ActorRefFromLogic<xstate.PromiseActorLogic<void, {
503
+ email: Email;
504
+ }, xstate.EventObject>> | xstate.ActorRefFromLogic<xstate.PromiseActorLogic<_capxul_sdk.VerifyOtpResult, {
505
+ email: Email;
506
+ code: string;
507
+ }, xstate.EventObject>> | undefined;
508
+ }, "email" | "error" | "bootstrap_required" | "authenticated" | "sending_otp" | "otp_requested" | "signing_out" | "verifying_otp" | "completing_bootstrap", string, xstate.NonReducibleUnknown, xstate.MetaObject, {
509
+ id: "authBootstrap";
510
+ states: {
511
+ readonly email: {};
512
+ readonly sending_otp: {};
513
+ readonly otp_requested: {};
514
+ readonly verifying_otp: {};
515
+ readonly bootstrap_required: {};
516
+ readonly completing_bootstrap: {};
517
+ readonly authenticated: {};
518
+ readonly signing_out: {};
519
+ readonly error: {};
520
+ };
521
+ }>;
522
+ readonly send: (event: {
523
+ readonly type: "ENTER_EMAIL";
524
+ readonly email: Email;
525
+ } | {
526
+ readonly type: "REQUEST_OTP";
527
+ } | {
528
+ readonly type: "ENTER_OTP";
529
+ readonly code: string;
530
+ } | {
531
+ readonly type: "VERIFY_OTP";
532
+ } | {
533
+ readonly type: "ENTER_USERNAME";
534
+ readonly username: Username;
535
+ } | {
536
+ readonly type: "ENTER_SIGNER_PROVIDER";
537
+ readonly signerProvider: _capxul_sdk.LocalPrivateKeySignerProvider;
538
+ } | {
539
+ readonly type: "COMPLETE_BOOTSTRAP";
540
+ } | {
541
+ readonly type: "BACK";
542
+ } | {
543
+ readonly type: "RESET";
544
+ } | {
545
+ readonly type: "SIGN_OUT";
546
+ }) => void;
547
+ };
451
548
  declare function useOnboardingFlow(): {
452
549
  readonly snapshot: xstate.MachineSnapshot<any, any, any, any, any, any, any, any>;
453
550
  readonly send: (event: any) => void;
@@ -538,4 +635,4 @@ declare function injectedConnector(options?: InjectedConnectorOptions): CapxulCo
538
635
  */
539
636
  declare function localPrivateKeyConnector(options: LocalPrivateKeyConnectorOptions): CapxulConnector;
540
637
 
541
- export { CapxulClientProvider, type CapxulClientProviderProps, type CapxulConnector, type CapxulConnectorKind, type CapxulConnectorSession, CapxulProvider, type CapxulProviderProps, CapxulTransportProvider, type CapxulTransportProviderProps, type DocumentsFilters, type InjectedConnectorOptions, type LocalPrivateKeyConnectorOptions, type OrgDocumentsFilters, type OrgScopedFilters, type OwnerRef, type OwnerScopedFilters, type PaginationFilters, type PaymentsFilters, type QueryResult, type TransfersFilters, type UseApiKeyArgs, type UseBalanceLedgerEntryArgs, type UseExternalAccountArgs, type UseMemberArgs, type UseTokenTransferArgs, type VirtualAccountsFilters, type VirtualCardsFilters, type WithdrawalsFilters, createCapxulConfig, injectedConnector, localPrivateKeyConnector, useAccount, useApiKey, useApiKeys, 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 };
638
+ export { CapxulClientProvider, type CapxulClientProviderProps, type CapxulConnector, type CapxulConnectorKind, type CapxulConnectorSession, CapxulProvider, type CapxulProviderProps, CapxulTransportProvider, type CapxulTransportProviderProps, type DocumentsFilters, type InjectedConnectorOptions, type LocalPrivateKeyConnectorOptions, type OrgDocumentsFilters, type OrgScopedFilters, type OwnerRef, type OwnerScopedFilters, type PaginationFilters, type PaymentsFilters, type QueryResult, type TransfersFilters, type UseApiKeyArgs, type UseBalanceLedgerEntryArgs, type UseExternalAccountArgs, type UseMemberArgs, type UseTokenTransferArgs, type VirtualAccountsFilters, type VirtualCardsFilters, type WithdrawalsFilters, 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 };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { ReactNode } from 'react';
2
+ import * as _capxul_sdk from '@capxul/sdk';
2
3
  import { HttpTransport, TransportState, BrowserCapxulConfig, AuthSessionStore, AccountId, OrganizationId, ApiKeyId, BalanceLedgerEntryId, ExternalAccountId, MemberId, Account, ApiKey, BalanceLedgerEntry, DocumentId, Document, ExternalAccount, KybProfile, KycProfile, CapxulError as CapxulError$1, Member, OperationId, Operation, Organization, PaymentId, Payment, SafeId, Safe, SubAccountId, SubAccount, TokenTransfer, TransferId, Transfer, Treasury, VirtualAccountId, VirtualAccount, VirtualCardId, VirtualCard, WebhookEndpointId, WebhookEndpoint, WebhookEventId, WebhookEvent, WithdrawalId, Withdrawal, List, TokenTransfersListInput, TokenTransfersListPage, LocalPrivateKeySignerProvider } from '@capxul/sdk';
3
- export { AuthFlowContext, AuthFlowEvent, BrowserCapxulConfig, OnboardingFlowContext, OnboardingFlowEvent, ProvisioningFlowContext, ProvisioningFlowEvent } from '@capxul/sdk';
4
+ export { AuthBootstrapFlowContext, AuthBootstrapFlowEvent, AuthFlowContext, AuthFlowEvent, BrowserCapxulConfig, OnboardingFlowContext, OnboardingFlowEvent, ProvisioningFlowContext, ProvisioningFlowEvent } from '@capxul/sdk';
4
5
  import { QueryClient, UseQueryResult } from '@tanstack/react-query';
5
6
  import { CapxulClient } from '@capxul/sdk/client';
6
7
  import { CapxulError } from '@capxul/sdk/errors';
@@ -444,10 +445,106 @@ declare function useApiKeys(_organizationId: OrganizationId): QueryResult<List<A
444
445
  */
445
446
  declare function useWebhookEndpoints(): QueryResult<List<WebhookEndpoint>>;
446
447
 
448
+ /**
449
+ * Lowercased, shape-validated email address. Brand prevents swapping
450
+ * with `phoneNumber`, `username`, or other string identifiers (per
451
+ * `CANON.md` §4.54 and `sdk-surface.md` §5h).
452
+ */
453
+ type Email = string & {
454
+ readonly __capxulEmailBrand: "Email";
455
+ };
456
+ /**
457
+ * Public Capxul username. 3–30 chars, letter-first, lowercased,
458
+ * remaining chars from `[a-z0-9_-]` (per `CANON.md` §4.54 and
459
+ * `sdk-surface.md` §5h). Constructor lowercases before validating so
460
+ * mixed-case input canonicalizes cleanly when the first char is a
461
+ * letter; purely invalid shapes (too short, illegal chars, digit-first)
462
+ * still throw.
463
+ */
464
+ type Username = string & {
465
+ readonly __capxulUsernameBrand: "Username";
466
+ };
467
+
447
468
  declare function useAuthFlow(): {
448
469
  readonly snapshot: xstate.MachineSnapshot<any, any, any, any, any, any, any, any>;
449
470
  readonly send: (event: any) => void;
450
471
  };
472
+ declare function useAuthBootstrapFlow(): {
473
+ readonly snapshot: xstate.MachineSnapshot<_capxul_sdk.AuthBootstrapFlowContext, {
474
+ readonly type: "ENTER_EMAIL";
475
+ readonly email: Email;
476
+ } | {
477
+ readonly type: "REQUEST_OTP";
478
+ } | {
479
+ readonly type: "ENTER_OTP";
480
+ readonly code: string;
481
+ } | {
482
+ readonly type: "VERIFY_OTP";
483
+ } | {
484
+ readonly type: "ENTER_USERNAME";
485
+ readonly username: Username;
486
+ } | {
487
+ readonly type: "ENTER_SIGNER_PROVIDER";
488
+ readonly signerProvider: _capxul_sdk.LocalPrivateKeySignerProvider;
489
+ } | {
490
+ readonly type: "COMPLETE_BOOTSTRAP";
491
+ } | {
492
+ readonly type: "BACK";
493
+ } | {
494
+ readonly type: "RESET";
495
+ } | {
496
+ readonly type: "SIGN_OUT";
497
+ }, {
498
+ [x: string]: xstate.ActorRefFromLogic<xstate.PromiseActorLogic<void, void, xstate.EventObject>> | xstate.ActorRefFromLogic<xstate.PromiseActorLogic<_capxul_sdk.CompleteBootstrapResult, {
499
+ bootstrapToken: _capxul_sdk.AuthBootstrapToken;
500
+ username: Username;
501
+ signerProvider: _capxul_sdk.LocalPrivateKeySignerProvider;
502
+ }, xstate.EventObject>> | xstate.ActorRefFromLogic<xstate.PromiseActorLogic<void, {
503
+ email: Email;
504
+ }, xstate.EventObject>> | xstate.ActorRefFromLogic<xstate.PromiseActorLogic<_capxul_sdk.VerifyOtpResult, {
505
+ email: Email;
506
+ code: string;
507
+ }, xstate.EventObject>> | undefined;
508
+ }, "email" | "error" | "bootstrap_required" | "authenticated" | "sending_otp" | "otp_requested" | "signing_out" | "verifying_otp" | "completing_bootstrap", string, xstate.NonReducibleUnknown, xstate.MetaObject, {
509
+ id: "authBootstrap";
510
+ states: {
511
+ readonly email: {};
512
+ readonly sending_otp: {};
513
+ readonly otp_requested: {};
514
+ readonly verifying_otp: {};
515
+ readonly bootstrap_required: {};
516
+ readonly completing_bootstrap: {};
517
+ readonly authenticated: {};
518
+ readonly signing_out: {};
519
+ readonly error: {};
520
+ };
521
+ }>;
522
+ readonly send: (event: {
523
+ readonly type: "ENTER_EMAIL";
524
+ readonly email: Email;
525
+ } | {
526
+ readonly type: "REQUEST_OTP";
527
+ } | {
528
+ readonly type: "ENTER_OTP";
529
+ readonly code: string;
530
+ } | {
531
+ readonly type: "VERIFY_OTP";
532
+ } | {
533
+ readonly type: "ENTER_USERNAME";
534
+ readonly username: Username;
535
+ } | {
536
+ readonly type: "ENTER_SIGNER_PROVIDER";
537
+ readonly signerProvider: _capxul_sdk.LocalPrivateKeySignerProvider;
538
+ } | {
539
+ readonly type: "COMPLETE_BOOTSTRAP";
540
+ } | {
541
+ readonly type: "BACK";
542
+ } | {
543
+ readonly type: "RESET";
544
+ } | {
545
+ readonly type: "SIGN_OUT";
546
+ }) => void;
547
+ };
451
548
  declare function useOnboardingFlow(): {
452
549
  readonly snapshot: xstate.MachineSnapshot<any, any, any, any, any, any, any, any>;
453
550
  readonly send: (event: any) => void;
@@ -538,4 +635,4 @@ declare function injectedConnector(options?: InjectedConnectorOptions): CapxulCo
538
635
  */
539
636
  declare function localPrivateKeyConnector(options: LocalPrivateKeyConnectorOptions): CapxulConnector;
540
637
 
541
- export { CapxulClientProvider, type CapxulClientProviderProps, type CapxulConnector, type CapxulConnectorKind, type CapxulConnectorSession, CapxulProvider, type CapxulProviderProps, CapxulTransportProvider, type CapxulTransportProviderProps, type DocumentsFilters, type InjectedConnectorOptions, type LocalPrivateKeyConnectorOptions, type OrgDocumentsFilters, type OrgScopedFilters, type OwnerRef, type OwnerScopedFilters, type PaginationFilters, type PaymentsFilters, type QueryResult, type TransfersFilters, type UseApiKeyArgs, type UseBalanceLedgerEntryArgs, type UseExternalAccountArgs, type UseMemberArgs, type UseTokenTransferArgs, type VirtualAccountsFilters, type VirtualCardsFilters, type WithdrawalsFilters, createCapxulConfig, injectedConnector, localPrivateKeyConnector, useAccount, useApiKey, useApiKeys, 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 };
638
+ export { CapxulClientProvider, type CapxulClientProviderProps, type CapxulConnector, type CapxulConnectorKind, type CapxulConnectorSession, CapxulProvider, type CapxulProviderProps, CapxulTransportProvider, type CapxulTransportProviderProps, type DocumentsFilters, type InjectedConnectorOptions, type LocalPrivateKeyConnectorOptions, type OrgDocumentsFilters, type OrgScopedFilters, type OwnerRef, type OwnerScopedFilters, type PaginationFilters, type PaymentsFilters, type QueryResult, type TransfersFilters, type UseApiKeyArgs, type UseBalanceLedgerEntryArgs, type UseExternalAccountArgs, type UseMemberArgs, type UseTokenTransferArgs, type VirtualAccountsFilters, type VirtualCardsFilters, type WithdrawalsFilters, 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 };
package/dist/index.js CHANGED
@@ -108,7 +108,12 @@ var Errors = {
108
108
  "Idempotency key was already used for a different request",
109
109
  { details }
110
110
  ),
111
- emailDeliveryFailed: (detail) => new CapxulError("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`),
111
+ emailDeliveryFailed: (detail, details) => new CapxulError("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`, {
112
+ details
113
+ }),
114
+ rateLimited: (details) => new CapxulError("RATE_LIMITED", "Request was rate limited", {
115
+ details: { ...details }
116
+ }),
112
117
  internalError: (reason) => new CapxulError("INTERNAL_ERROR", `Internal error: ${reason}`),
113
118
  /**
114
119
  * Verification gate. Surfaced when a request hits a verification
@@ -215,6 +220,48 @@ function createReactDataClient(convexUrl, sessionStore) {
215
220
  }
216
221
  };
217
222
  }
223
+ function createLazyReactDataClient(transport, sessionStore, createClient = createReactDataClient) {
224
+ let client = null;
225
+ let initializeClient = null;
226
+ let closed = false;
227
+ function closedError() {
228
+ return new Error("Capxul React data client is closed");
229
+ }
230
+ async function getClient() {
231
+ if (closed) throw closedError();
232
+ if (client) return client;
233
+ initializeClient ??= (async () => {
234
+ const runtime = await transport.ensureRuntime();
235
+ if (closed) throw closedError();
236
+ const nextClient = createClient(runtime.convexUrl, sessionStore);
237
+ if (closed) {
238
+ nextClient.close();
239
+ throw closedError();
240
+ }
241
+ client = nextClient;
242
+ return nextClient;
243
+ })().catch((error) => {
244
+ if (!closed) {
245
+ initializeClient = null;
246
+ }
247
+ throw error;
248
+ });
249
+ return initializeClient;
250
+ }
251
+ return {
252
+ query: async (name, args) => (await getClient()).query(name, args),
253
+ mutation: async (name, args) => (await getClient()).mutation(name, args),
254
+ action: async (name, args) => (await getClient()).action?.(name, args),
255
+ refreshAuth: () => {
256
+ client?.refreshAuth();
257
+ },
258
+ close: () => {
259
+ closed = true;
260
+ client?.close();
261
+ client = null;
262
+ }
263
+ };
264
+ }
218
265
  function CapxulProvider({
219
266
  config,
220
267
  sessionStore,
@@ -244,12 +291,12 @@ function CapxulProvider({
244
291
  function buildWiring(config, sessionStore) {
245
292
  const validated = createCapxulConfig(config);
246
293
  const transport = makeHttpTransport(validated);
247
- const dataClient = validated.mode === "build-time-urls" ? createReactDataClient(validated.convexUrl, sessionStore) : null;
294
+ const dataClient = validated.mode === "build-time-urls" ? createReactDataClient(validated.convexUrl, sessionStore) : createLazyReactDataClient(transport, sessionStore);
248
295
  const sdkConfig = {
249
296
  _transport: transport,
250
297
  publishableKey: validated.mode === "publishable-key" ? validated.publishableKey : void 0,
251
298
  data: dataClient ?? void 0,
252
- auth: dataClient ? {
299
+ auth: validated.mode === "build-time-urls" || validated.mode === "publishable-key" ? {
253
300
  // The auth client builds the BetterAuth root URL from this
254
301
  // value. Convex's `.cloud` URL is the wrong host (BetterAuth
255
302
  // is mounted on the `.site` URL), but the build-time-urls
@@ -552,6 +599,12 @@ function useAuthFlow() {
552
599
  const [snapshot, send] = useActor(machine);
553
600
  return { snapshot, send };
554
601
  }
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 };
607
+ }
555
608
  function useOnboardingFlow() {
556
609
  const client = useCapxul();
557
610
  const machine = useMemo(() => client.flows.onboarding(), [client]);
@@ -660,4 +713,4 @@ function validateAndNormalizeEvmAddress(field, raw) {
660
713
  }
661
714
  }
662
715
 
663
- export { CapxulClientProvider, CapxulProvider, CapxulTransportProvider, createCapxulConfig, injectedConnector, localPrivateKeyConnector, useAccount, useApiKey, useApiKeys, 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 };
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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capxul/sdk-react",
3
- "version": "0.1.0-alpha.6",
3
+ "version": "0.1.0-alpha.9",
4
4
  "description": "React provider + hooks for the @capxul/sdk headless client.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -46,13 +46,13 @@
46
46
  "access": "public"
47
47
  },
48
48
  "dependencies": {
49
- "@capxul/sdk": "0.1.0-alpha.6"
49
+ "@capxul/sdk": "0.1.0-alpha.9"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "@tanstack/react-query": "^5",
53
53
  "@xstate/react": "^5",
54
54
  "convex": ">=1.0.0",
55
- "react": ">=18.2.0 <20",
55
+ "react": ">=19.0.0",
56
56
  "viem": ">=2.0.0"
57
57
  },
58
58
  "devDependencies": {
@@ -70,8 +70,8 @@
70
70
  "typescript": "5.9.2",
71
71
  "viem": "2.47.10",
72
72
  "vitest": "^4.1.2",
73
- "@repo/config": "0.0.0",
74
73
  "@repo/observability": "0.0.0",
74
+ "@repo/config": "0.0.0",
75
75
  "@repo/platform-kernel": "0.0.0",
76
76
  "@repo/typescript-config": "0.0.0"
77
77
  },