@capxul/sdk-react 2.0.1 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,13 +24,17 @@ export function Providers({ children }: { children: React.ReactNode }) {
24
24
  expose the Core SDK identity actor without a parallel React state model.
25
25
  - `useCapxulSend` carries caller-owned invocation controls to that actor.
26
26
  - `useCapxulAuth` is the stable six-verb application facade.
27
+ - The provider restores Account readiness after a complete authenticated
28
+ session. Account and Organization readiness transitions refresh active
29
+ authenticated queries.
27
30
  - `CapxulAuthenticationController` and `CapxulOnboardingController` select
28
31
  app-owned slots and render no SDK-owned DOM. Supplying the onboarding
29
32
  controller's `recoveryOptions` factory lets a fresh actor resume account
30
33
  prerequisites before the stored Organization replay; a failed prerequisite
31
34
  returns the same manual replay instead of looping.
32
35
  - Rich-data hooks such as `useCapxulProfile`, `useCapxulOrgs`, members, roles,
33
- treasury, and money hooks remain TanStack Query projections.
36
+ treasury, and money hooks remain TanStack Query projections. Personal
37
+ holdings and activity reads start only after the Account is claimed.
34
38
 
35
39
  The packed npm package exposes `@capxul/sdk-react` and
36
40
  `@capxul/sdk-react/testing`. The workspace-only `@capxul/sdk-react/headless`
@@ -184,8 +184,11 @@ function createAuth(client, clearAuthenticatedQueries) {
184
184
  ok: false,
185
185
  reason: "INVALID_INPUT"
186
186
  };
187
- const completed = await completeProfile(submission.profileDetails, invocation);
188
- if (!completed.ok) return completed;
187
+ const current = runtime.snapshot();
188
+ if (current.phase !== "authenticated" || !current.profileComplete) {
189
+ const completed = await completeProfile(submission.profileDetails, invocation);
190
+ if (!completed.ok) return completed;
191
+ }
189
192
  const refreshed = await read(invocation);
190
193
  if (!refreshed.ok) return refreshed;
191
194
  const claimed = await reachClaimed(invocation);
@@ -257,6 +260,24 @@ function createAuth(client, clearAuthenticatedQueries) {
257
260
  return ensureAccount(invocation);
258
261
  }),
259
262
  createOrganization: (submission, options) => guarded(runtime, "createOrganization", options, async (invocation) => {
263
+ const current = runtime.snapshot();
264
+ if (current.phase === "authenticated" && current.account.at === "claimed") {
265
+ const org = current.account.org;
266
+ if (org !== null && (org.at === "loading" || org.at === "settingUp" || org.at === "ready")) return {
267
+ ok: true,
268
+ orgId: org.orgId
269
+ };
270
+ if (org?.at === "failed" && org.orgId !== null) {
271
+ if (!org.retryable) return {
272
+ ok: false,
273
+ reason: org.failure.code
274
+ };
275
+ return failure(await runtime.send({ _tag: "RetryOrganization" }, invocation)) ?? {
276
+ ok: true,
277
+ orgId: org.orgId
278
+ };
279
+ }
280
+ }
260
281
  const prepared = await prepareOrganization(submission, invocation);
261
282
  if (!prepared.ok) return prepared;
262
283
  const created = await runtime.send({
@@ -291,20 +312,37 @@ function CapxulIdentityProvider({ client, children }) {
291
312
  const runtime = client?._internal.identity ?? null;
292
313
  const listeners = useRef(/* @__PURE__ */ new Set());
293
314
  useEffect(() => {
294
- if (client === null) return;
295
- Promise.resolve().then(() => client.auth.getSession()).catch(() => void 0);
296
- }, [client]);
315
+ if (client === null || runtime === null) return;
316
+ const controller = new AbortController();
317
+ let active = true;
318
+ Promise.resolve().then(async () => {
319
+ const restored = await client.auth.getSession({ signal: controller.signal });
320
+ if (!active || !restored.ok) return;
321
+ let state = runtime.snapshot();
322
+ if (state.phase === "authenticated" && state.account.at === "unknown") {
323
+ await runtime.send({ _tag: "ReadSession" }, { signal: controller.signal });
324
+ if (!active) return;
325
+ state = runtime.snapshot();
326
+ }
327
+ if (state.phase === "authenticated" && state.profileComplete && state.account.at === "unknown") await runtime.send({ _tag: "EnsureAccount" }, { signal: controller.signal });
328
+ }).catch(() => void 0);
329
+ return () => {
330
+ active = false;
331
+ controller.abort();
332
+ };
333
+ }, [client, runtime]);
297
334
  useEffect(() => {
298
335
  if (runtime === null) return;
299
336
  return runtime.subscribeTransitions((record) => {
300
337
  const state = runtime.snapshot();
338
+ if (record.outcome === "applied" && record.from !== record.to && (record.to === "authenticated:claimed" || record.to === "authenticated:claimed:ready")) queryClient.invalidateQueries({ queryKey: capxulKeys.root });
301
339
  for (const listener of listeners.current) try {
302
340
  listener(record, state);
303
341
  } catch {
304
342
  listeners.current.delete(listener);
305
343
  }
306
344
  });
307
- }, [runtime]);
345
+ }, [queryClient, runtime]);
308
346
  const addTransitionListener = useCallback((listener) => {
309
347
  listeners.current.add(listener);
310
348
  return () => listeners.current.delete(listener);
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { a as useCapxulAuth, c as useCapxulIdentityOrNull, d as capxulKeys, f as useCapxulClientOrNull, i as entered, l as useCapxulSend, n as CapxulOnboardingController, o as useCapxulDestination, p as useCapxul, r as CapxulProvider, s as useCapxulIdentity, t as CapxulAuthenticationController, u as useCapxulTransitions } from "./controllers--rna89ya.mjs";
2
+ import { a as useCapxulAuth, c as useCapxulIdentityOrNull, d as capxulKeys, f as useCapxulClientOrNull, i as entered, l as useCapxulSend, n as CapxulOnboardingController, o as useCapxulDestination, p as useCapxul, r as CapxulProvider, s as useCapxulIdentity, t as CapxulAuthenticationController, u as useCapxulTransitions } from "./controllers-DeXOe2mR.mjs";
3
3
  import { useEffect, useState } from "react";
4
4
  import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
5
5
  //#region ../errors/src/errors.ts
@@ -425,17 +425,19 @@ function useCapxulPermission(orgId, permissionId) {
425
425
  //#region src/hooks/use-capxul-activity.ts
426
426
  function useCapxulActivity(params) {
427
427
  const client = useCapxulClientOrNull();
428
+ const identity = useCapxulIdentityOrNull();
428
429
  return useQuery({
429
430
  queryKey: [...capxulKeys.activity, params ?? {}],
430
431
  queryFn: async () => {
431
432
  const bootstrapped = requireBootstrappedClient(client, "activity.list");
432
433
  return unwrapCapxulResult(await bootstrapped.activity.list(params), bootstrapped._internal.telemetry);
433
434
  },
434
- enabled: client !== null
435
+ enabled: client !== null && identity?.phase === "authenticated" && identity.account.at === "claimed"
435
436
  });
436
437
  }
437
438
  function useCapxulActivityDetail(reference) {
438
439
  const client = useCapxulClientOrNull();
440
+ const identity = useCapxulIdentityOrNull();
439
441
  return useQuery({
440
442
  queryKey: capxulKeys.activityDetail(reference?.kind ?? "payment", reference?.id),
441
443
  queryFn: async () => {
@@ -443,7 +445,7 @@ function useCapxulActivityDetail(reference) {
443
445
  const bootstrapped = requireBootstrappedClient(client, "activity.get");
444
446
  return unwrapCapxulResult(await bootstrapped.activity.get(reference), bootstrapped._internal.telemetry);
445
447
  },
446
- enabled: client !== null && reference !== void 0
448
+ enabled: client !== null && reference !== void 0 && identity?.phase === "authenticated" && identity.account.at === "claimed"
447
449
  });
448
450
  }
449
451
  function useCapxulAnnotateMovement() {
@@ -461,13 +463,14 @@ function useCapxulAnnotateMovement() {
461
463
  //#region src/hooks/use-capxul-holdings.ts
462
464
  function useCapxulHoldings() {
463
465
  const client = useCapxulClientOrNull();
466
+ const identity = useCapxulIdentityOrNull();
464
467
  return useQuery({
465
468
  queryKey: capxulKeys.holdings,
466
469
  queryFn: async () => {
467
470
  const bootstrapped = requireBootstrappedClient(client, "holdings.current");
468
471
  return unwrapCapxulResult(await bootstrapped.holdings.current(), bootstrapped._internal.telemetry);
469
472
  },
470
- enabled: client !== null
473
+ enabled: client !== null && identity?.phase === "authenticated" && identity.account.at === "claimed"
471
474
  });
472
475
  }
473
476
  //#endregion
@@ -1,4 +1,4 @@
1
- import { n as CapxulOnboardingController, r as CapxulProvider, t as CapxulAuthenticationController } from "../controllers--rna89ya.mjs";
1
+ import { n as CapxulOnboardingController, r as CapxulProvider, t as CapxulAuthenticationController } from "../controllers-DeXOe2mR.mjs";
2
2
  import "react";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  import { createCapxulTestClient } from "@capxul/sdk/testing";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capxul/sdk-react",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/Xelmar-tech/infrastructure.git",
@@ -26,7 +26,7 @@
26
26
  "access": "public"
27
27
  },
28
28
  "dependencies": {
29
- "@capxul/sdk": "2.0.1"
29
+ "@capxul/sdk": "2.0.2"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@tanstack/react-query": "^5.66.9",
@@ -43,8 +43,8 @@
43
43
  "vite-plus": "0.1.23",
44
44
  "vitest": "npm:@voidzero-dev/vite-plus-test@0.1.23",
45
45
  "@capxul/types": "0.1.0",
46
- "@capxul/errors": "0.0.1",
47
- "@capxul/typescript-config": "0.0.0"
46
+ "@capxul/typescript-config": "0.0.0",
47
+ "@capxul/errors": "0.0.1"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "@tanstack/react-query": "^5.66.9",