@capxul/sdk-react 4.2.0 → 4.20.0-beta.1
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 +6 -4
- package/dist/{controllers-BPEhjKX9.mjs → controllers-DXmEHrnw.mjs} +172 -17
- package/dist/index.d.mts +74 -15
- package/dist/index.mjs +174 -63
- package/dist/testing/index.mjs +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -28,10 +28,12 @@ export function Providers({ children }: { children: React.ReactNode }) {
|
|
|
28
28
|
session. Account and Organization readiness transitions refresh active
|
|
29
29
|
authenticated queries.
|
|
30
30
|
- `CapxulAuthenticationController` and `CapxulOnboardingController` select
|
|
31
|
-
app-owned slots and render no SDK-owned DOM.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
app-owned slots and render no SDK-owned DOM. The onboarding controller keeps
|
|
32
|
+
no Organization submission: after a reload the Core SDK reads the pending
|
|
33
|
+
Organization from the backend and attaches it, so the app re-submits nothing.
|
|
34
|
+
A claimed identity with no Organization and no app-held form step reports
|
|
35
|
+
`organizationProgress` with `{ at: "loading", orgId: null }` until that
|
|
36
|
+
attach lands.
|
|
35
37
|
- Rich-data hooks such as `useCapxulProfile`, `useCapxulOrgs`, members, roles,
|
|
36
38
|
treasury, and money hooks remain TanStack Query projections. Personal
|
|
37
39
|
holdings and activity reads start only after the Account is claimed.
|
|
@@ -37,6 +37,24 @@ function useCapxulClientOrNull() {
|
|
|
37
37
|
}
|
|
38
38
|
//#endregion
|
|
39
39
|
//#region src/internal/reactivity-keys.ts
|
|
40
|
+
/**
|
|
41
|
+
* The account a read is answered FOR, as a key segment (#2007 R19).
|
|
42
|
+
*
|
|
43
|
+
* A read whose answer depends on who is asking belongs to the (scope, account)
|
|
44
|
+
* pair, not to the scope. Replacing one claimed account with another is not a
|
|
45
|
+
* state-label change. Keying is what
|
|
46
|
+
* makes the new person miss rather than read the previous person's answer.
|
|
47
|
+
* `undefined` while no account is claimed — no such read may run then anyway.
|
|
48
|
+
*/
|
|
49
|
+
function actingAccount(identity) {
|
|
50
|
+
return identity !== null && identity.phase === "authenticated" && identity.account.at === "claimed" ? identity.account.address : void 0;
|
|
51
|
+
}
|
|
52
|
+
/** Keep invalidation prefixes shared, but never share a personal result across accounts.
|
|
53
|
+
* Session reads also run before an Account is claimed (for example `orgs()`).
|
|
54
|
+
*/
|
|
55
|
+
function accountKey(key, identity) {
|
|
56
|
+
return [...key, actingAccount(identity) ?? (identity?.phase === "authenticated" ? identity.session.authUserId : null)];
|
|
57
|
+
}
|
|
40
58
|
const capxulKeys = {
|
|
41
59
|
root: ["capxul"],
|
|
42
60
|
profile: ["capxul", "profile"],
|
|
@@ -80,11 +98,12 @@ const capxulKeys = {
|
|
|
80
98
|
orgId ?? "pending",
|
|
81
99
|
"permissions"
|
|
82
100
|
],
|
|
83
|
-
orgMe: (orgId) => [
|
|
101
|
+
orgMe: (orgId, account) => [
|
|
84
102
|
"capxul",
|
|
85
103
|
"org",
|
|
86
104
|
orgId ?? "pending",
|
|
87
|
-
"me"
|
|
105
|
+
"me",
|
|
106
|
+
account ?? "pending"
|
|
88
107
|
],
|
|
89
108
|
orgLifecycle: (orgId) => [
|
|
90
109
|
"capxul",
|
|
@@ -151,10 +170,35 @@ const capxulKeys = {
|
|
|
151
170
|
]
|
|
152
171
|
};
|
|
153
172
|
//#endregion
|
|
154
|
-
//#region src/
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
173
|
+
//#region src/internal/invocation-controls.ts
|
|
174
|
+
/**
|
|
175
|
+
* Keep only the five public option fields, and only when they hold the right
|
|
176
|
+
* kind of value. A named action verb takes its attempt as an optional FIRST
|
|
177
|
+
* argument, so a screen that wires one straight to a DOM handler
|
|
178
|
+
* (`onClick={row.hide}`) hands us a React SyntheticEvent. That is not an
|
|
179
|
+
* attempt: it must reach neither the SDK call nor the callback echo.
|
|
180
|
+
*/
|
|
181
|
+
function toInvocationOptions(options) {
|
|
182
|
+
if (typeof options !== "object" || options === null) return void 0;
|
|
183
|
+
const attempt = {};
|
|
184
|
+
if (typeof options.correlationId === "string") attempt.correlationId = options.correlationId;
|
|
185
|
+
if (typeof options.journeyId === "string") attempt.journeyId = options.journeyId;
|
|
186
|
+
if (typeof options.timeoutMs === "number") attempt.timeoutMs = options.timeoutMs;
|
|
187
|
+
if (typeof options.deadlineMs === "number") attempt.deadlineMs = options.deadlineMs;
|
|
188
|
+
if (options.signal instanceof AbortSignal) attempt.signal = options.signal;
|
|
189
|
+
return Object.keys(attempt).length === 0 ? void 0 : attempt;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Map the public camel-case invocation options onto the Core SDK's control
|
|
193
|
+
* spelling. ONE definition, because the identity facade and every headless
|
|
194
|
+
* engine must hand the SDK the same shape: a caller that captured one user
|
|
195
|
+
* attempt before it started gets that attempt's `correlation_id`/`journey_id`
|
|
196
|
+
* on whichever operation it starts (#1960 R02).
|
|
197
|
+
*
|
|
198
|
+
* It creates no identifiers. An absent option stays absent, so an automatic
|
|
199
|
+
* read keeps its own invocation context instead of borrowing an attempt's.
|
|
200
|
+
*/
|
|
201
|
+
function toInvocationControls(options) {
|
|
158
202
|
if (options === void 0) return void 0;
|
|
159
203
|
return {
|
|
160
204
|
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
@@ -164,12 +208,16 @@ function controls(options) {
|
|
|
164
208
|
...options.journeyId === void 0 ? {} : { journey_id: options.journeyId }
|
|
165
209
|
};
|
|
166
210
|
}
|
|
211
|
+
//#endregion
|
|
212
|
+
//#region src/identity.tsx
|
|
213
|
+
const MISSING_IDENTITY_PROVIDER = Symbol("MISSING_IDENTITY_PROVIDER");
|
|
214
|
+
const IdentityContext = createContext(MISSING_IDENTITY_PROVIDER);
|
|
167
215
|
const failure = (result) => result.ok ? null : {
|
|
168
216
|
ok: false,
|
|
169
217
|
reason: result.refused
|
|
170
218
|
};
|
|
171
219
|
async function guarded(runtime, verb, options, run) {
|
|
172
|
-
const invocation =
|
|
220
|
+
const invocation = toInvocationControls(options);
|
|
173
221
|
try {
|
|
174
222
|
return await (runtime.runFacade?.(verb, invocation, run) ?? run(invocation));
|
|
175
223
|
} catch {
|
|
@@ -215,18 +263,102 @@ function normalizeOrganization(organization) {
|
|
|
215
263
|
return null;
|
|
216
264
|
}
|
|
217
265
|
}
|
|
266
|
+
/** The Organization id when its lane is already running or finished, else null. */
|
|
267
|
+
const runningOrganization = (state) => {
|
|
268
|
+
if (state.phase !== "authenticated" || state.account.at !== "claimed") return null;
|
|
269
|
+
const org = state.account.org;
|
|
270
|
+
return org !== null && (org.at === "loading" || org.at === "settingUp" || org.at === "ready") ? org.orgId : null;
|
|
271
|
+
};
|
|
272
|
+
/** A superseded session read waits at most this long for the winning read. */
|
|
273
|
+
const SESSION_SETTLE_LIMIT_MS = 3e4;
|
|
274
|
+
const accountInFlight = (state) => state.phase === "authenticated" && (state.account.at === "deriving" || state.account.at === "claiming");
|
|
218
275
|
function createAuth(client, clearAuthenticatedQueries) {
|
|
219
276
|
const runtime = client._internal.identity;
|
|
277
|
+
const settledSession = (invocation) => new Promise((resolve) => {
|
|
278
|
+
let done = false;
|
|
279
|
+
let stop = null;
|
|
280
|
+
let timer = null;
|
|
281
|
+
const onAbort = () => finish({
|
|
282
|
+
ok: false,
|
|
283
|
+
reason: "CANCELLED"
|
|
284
|
+
});
|
|
285
|
+
const finish = (result) => {
|
|
286
|
+
if (done) return;
|
|
287
|
+
done = true;
|
|
288
|
+
stop?.();
|
|
289
|
+
if (timer !== null) clearTimeout(timer);
|
|
290
|
+
invocation?.signal?.removeEventListener("abort", onAbort);
|
|
291
|
+
resolve(result);
|
|
292
|
+
};
|
|
293
|
+
if (invocation?.signal?.aborted) {
|
|
294
|
+
onAbort();
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
invocation?.signal?.addEventListener("abort", onAbort, { once: true });
|
|
298
|
+
const unsubscribe = runtime.subscribeTransitions((record) => {
|
|
299
|
+
if (record.slot !== "identity:session") return;
|
|
300
|
+
if (record.outcome === "applied" && record.event === "SessionRead") finish({ ok: true });
|
|
301
|
+
else if (record.outcome === "failed" || record.outcome === "cancelled") finish({
|
|
302
|
+
ok: false,
|
|
303
|
+
reason: record.error_code
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
if (done) {
|
|
307
|
+
unsubscribe();
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
stop = unsubscribe;
|
|
311
|
+
timer = setTimeout(() => finish({
|
|
312
|
+
ok: false,
|
|
313
|
+
reason: "UNKNOWN"
|
|
314
|
+
}), SESSION_SETTLE_LIMIT_MS);
|
|
315
|
+
});
|
|
220
316
|
const read = async (invocation) => {
|
|
221
317
|
const result = await runtime.send({ _tag: "ReadSession" }, invocation);
|
|
222
|
-
|
|
318
|
+
const refused = failure(result);
|
|
319
|
+
if (refused === null) return { ok: true };
|
|
320
|
+
return refused.reason === "SUPERSEDED" ? settledSession(invocation) : refused;
|
|
223
321
|
};
|
|
224
322
|
const ensureAccount = async (invocation) => {
|
|
225
323
|
const result = await runtime.send({ _tag: "EnsureAccount" }, invocation);
|
|
226
324
|
return failure(result) ?? { ok: true };
|
|
227
325
|
};
|
|
326
|
+
const settledAccount = (invocation) => new Promise((resolve) => {
|
|
327
|
+
let done = false;
|
|
328
|
+
let stop = null;
|
|
329
|
+
const onAbort = () => finish({
|
|
330
|
+
ok: false,
|
|
331
|
+
reason: "CANCELLED"
|
|
332
|
+
});
|
|
333
|
+
const finish = (result) => {
|
|
334
|
+
if (done) return;
|
|
335
|
+
done = true;
|
|
336
|
+
stop?.();
|
|
337
|
+
invocation?.signal?.removeEventListener("abort", onAbort);
|
|
338
|
+
resolve(result);
|
|
339
|
+
};
|
|
340
|
+
if (invocation?.signal?.aborted) {
|
|
341
|
+
onAbort();
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
invocation?.signal?.addEventListener("abort", onAbort, { once: true });
|
|
345
|
+
const unsubscribe = runtime.subscribe((state) => {
|
|
346
|
+
if (!accountInFlight(state)) finish({ ok: true });
|
|
347
|
+
});
|
|
348
|
+
if (done) {
|
|
349
|
+
unsubscribe();
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
stop = unsubscribe;
|
|
353
|
+
if (!accountInFlight(runtime.snapshot())) finish({ ok: true });
|
|
354
|
+
});
|
|
228
355
|
const reachClaimed = async (invocation) => {
|
|
229
356
|
let state = runtime.snapshot();
|
|
357
|
+
if (accountInFlight(state)) {
|
|
358
|
+
const settled = await settledAccount(invocation);
|
|
359
|
+
if (!settled.ok) return settled;
|
|
360
|
+
state = runtime.snapshot();
|
|
361
|
+
}
|
|
230
362
|
if (state.phase !== "authenticated" || state.account.at === "unknown") {
|
|
231
363
|
const result = await runtime.send({ _tag: "EnsureAccount" }, invocation);
|
|
232
364
|
const refused = failure(result);
|
|
@@ -238,6 +370,16 @@ function createAuth(client, clearAuthenticatedQueries) {
|
|
|
238
370
|
reason: "WRONG_STATE"
|
|
239
371
|
};
|
|
240
372
|
if (state.account.at === "claimed") return { ok: true };
|
|
373
|
+
if (accountInFlight(state)) {
|
|
374
|
+
const settled = await settledAccount(invocation);
|
|
375
|
+
if (!settled.ok) return settled;
|
|
376
|
+
state = runtime.snapshot();
|
|
377
|
+
if (state.phase !== "authenticated") return {
|
|
378
|
+
ok: false,
|
|
379
|
+
reason: "WRONG_STATE"
|
|
380
|
+
};
|
|
381
|
+
if (state.account.at === "claimed") return { ok: true };
|
|
382
|
+
}
|
|
241
383
|
const event = state.account.at === "failed" ? { _tag: "RetryAccount" } : state.account.at === "counterfactual" ? { _tag: "ClaimAccount" } : { _tag: "EnsureAccount" };
|
|
242
384
|
const result = await runtime.send(event, invocation);
|
|
243
385
|
const refused = failure(result);
|
|
@@ -258,13 +400,13 @@ function createAuth(client, clearAuthenticatedQueries) {
|
|
|
258
400
|
ok: false,
|
|
259
401
|
reason: "INVALID_INPUT"
|
|
260
402
|
};
|
|
403
|
+
const refreshed = await read(invocation);
|
|
404
|
+
if (!refreshed.ok) return refreshed;
|
|
261
405
|
const current = runtime.snapshot();
|
|
262
406
|
if (current.phase !== "authenticated" || !current.profileComplete) {
|
|
263
407
|
const completed = await runtime.completeProfile(submission.profileDetails, invocation);
|
|
264
408
|
if (!completed.ok) return completed;
|
|
265
409
|
}
|
|
266
|
-
const refreshed = await read(invocation);
|
|
267
|
-
if (!refreshed.ok) return refreshed;
|
|
268
410
|
const claimed = await reachClaimed(invocation);
|
|
269
411
|
return claimed.ok ? {
|
|
270
412
|
ok: true,
|
|
@@ -341,12 +483,13 @@ function createAuth(client, clearAuthenticatedQueries) {
|
|
|
341
483
|
}),
|
|
342
484
|
createOrganization: (submission, options) => guarded(runtime, "createOrganization", options, async (invocation) => {
|
|
343
485
|
const current = runtime.snapshot();
|
|
486
|
+
const running = runningOrganization(current);
|
|
487
|
+
if (running !== null) return {
|
|
488
|
+
ok: true,
|
|
489
|
+
orgId: running
|
|
490
|
+
};
|
|
344
491
|
if (current.phase === "authenticated" && current.account.at === "claimed") {
|
|
345
492
|
const org = current.account.org;
|
|
346
|
-
if (org !== null && (org.at === "loading" || org.at === "settingUp" || org.at === "ready")) return {
|
|
347
|
-
ok: true,
|
|
348
|
-
orgId: org.orgId
|
|
349
|
-
};
|
|
350
493
|
if (org?.at === "failed" && org.orgId !== null) {
|
|
351
494
|
if (!org.retryable) return {
|
|
352
495
|
ok: false,
|
|
@@ -361,6 +504,11 @@ function createAuth(client, clearAuthenticatedQueries) {
|
|
|
361
504
|
}
|
|
362
505
|
const prepared = await prepareOrganization(submission, invocation);
|
|
363
506
|
if (!prepared.ok) return prepared;
|
|
507
|
+
const opened = runningOrganization(runtime.snapshot());
|
|
508
|
+
if (opened !== null) return {
|
|
509
|
+
ok: true,
|
|
510
|
+
orgId: opened
|
|
511
|
+
};
|
|
364
512
|
const created = await runtime.send({
|
|
365
513
|
_tag: "CreateOrganization",
|
|
366
514
|
draft: prepared.organization
|
|
@@ -426,9 +574,16 @@ function CapxulIdentityProvider({ client, children }) {
|
|
|
426
574
|
}, [client, runtime]);
|
|
427
575
|
useEffect(() => {
|
|
428
576
|
if (runtime === null) return;
|
|
577
|
+
let previousAccount = actingAccount(runtime.snapshot());
|
|
429
578
|
return runtime.subscribeTransitions((record) => {
|
|
430
579
|
const state = runtime.snapshot();
|
|
431
|
-
|
|
580
|
+
const account = actingAccount(state);
|
|
581
|
+
const accountChanged = previousAccount !== void 0 && account !== void 0 && account !== previousAccount;
|
|
582
|
+
previousAccount = account;
|
|
583
|
+
if (record.outcome === "applied" && (record.from !== record.to || accountChanged) && (record.to === "authenticated:claimed" || record.to === "authenticated:claimed:ready")) queryClient.invalidateQueries({
|
|
584
|
+
queryKey: capxulKeys.root,
|
|
585
|
+
...accountChanged ? { refetchType: "none" } : {}
|
|
586
|
+
});
|
|
432
587
|
for (const listener of listeners.current) try {
|
|
433
588
|
listener(record, state);
|
|
434
589
|
} catch {
|
|
@@ -442,7 +597,7 @@ function CapxulIdentityProvider({ client, children }) {
|
|
|
442
597
|
}, []);
|
|
443
598
|
const value = useMemo(() => {
|
|
444
599
|
if (client === null || runtime === null) return null;
|
|
445
|
-
const send = (event, options) => runtime.send(event,
|
|
600
|
+
const send = (event, options) => runtime.send(event, toInvocationControls(options));
|
|
446
601
|
const clearAuthenticatedQueries = async () => {
|
|
447
602
|
await queryClient.cancelQueries({ queryKey: capxulKeys.root });
|
|
448
603
|
await queryClient.resetQueries({ queryKey: capxulKeys.root });
|
|
@@ -821,4 +976,4 @@ function organizationForm(props, state, auth, submitted) {
|
|
|
821
976
|
});
|
|
822
977
|
}
|
|
823
978
|
//#endregion
|
|
824
|
-
export { useCapxulAuth as a, useCapxulIdentityOrNull as c,
|
|
979
|
+
export { useCapxul as _, useCapxulAuth as a, useCapxulIdentityOrNull as c, toInvocationControls as d, toInvocationOptions as f, useCapxulClientOrNull as g, capxulKeys as h, entered as i, useCapxulSend as l, actingAccount as m, CapxulOnboardingController as n, useCapxulDestination as o, accountKey as p, CapxulProvider as r, useCapxulIdentity as s, CapxulAuthenticationController as t, useCapxulTransitions as u };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { A as entered, C as CreateOrganizationFailure, D as OrganizationDetails, E as InvocationOptions, F as useCapxulTransitions, M as useCapxulDestination, N as useCapxulIdentity, O as ProfileDetails, P as useCapxulSend, S as CapxulSend, T as Destination, _ as ReadyDestination, a as AuthenticationSlots, b as Slot, c as ControllerAction, d as OnboardingControllerProps, f as OrgFailure, g as ProfileSlotProps, h as PendingAuthState, i as AuthenticatedState, j as useCapxulAuth, k as SendResult, l as FaultedState, m as OtpPendingState, n as AccountProgress, o as CapxulAuthenticationController, p as OrgProgress, r as ActionResult, s as CapxulOnboardingController, t as AccountFailure, u as NavigationAction, v as RetryAction, w as CreateOrganizationSubmission, x as CapxulAuth, y as SignedOutState } from "./controllers-BWmKRFy6.mjs";
|
|
2
2
|
import { ReactNode, RefCallback } from "react";
|
|
3
3
|
import { QueryClient, UseMutationResult, UseQueryResult } from "@tanstack/react-query";
|
|
4
|
-
import { Account, AccountRequirement, ActivityAnnotation, ActivityAnnotationInput, ActivityDetail, ActivityKind, ActivityListParams, ActivityPage, ActivityPhase, ActivityRange, ActivityReference, ActorReference, AddressBookEntry, BudgetId, CapxulClient, CapxulError, CapxulResult, CapxulSigner, CreateOrgInput, CurrentHoldings, HostObservability, IdentityDestination, InviteMemberInput, MemberView, Money, MoneyParseErrorReason, OrgId, OrgView, OrganizationPaymentBatchInput, OrganizationPaymentInput, PartyId, Payment, PaymentDirection, PaymentDocumentRef, PaymentDocumentRender, PaymentStatus, PaymentTiming, PaymentType, PaymentsPayInput, PayrollGroupId, PayrollGroupInput, PayrollRunId, PayrollRunStatus, Permission, PermissionMethods, PermissionReadResult, Profile, RoleView, SubmittedPermissionExecution, isClaimed, isRestoring } from "@capxul/sdk";
|
|
4
|
+
import { Account, AccountRequirement, ActivityAnnotation, ActivityAnnotationInput, ActivityDetail, ActivityKind, ActivityListParams, ActivityPage, ActivityPhase, ActivityRange, ActivityReference, ActorReference, AddressBookEntry, BudgetId, CapxulClient, CapxulError, CapxulResult, CapxulSigner, CreateOrgInput, CurrentHoldings, HostObservability, IdentityDestination, IdentityState, InviteMemberInput, MemberView, Money, MoneyParseErrorReason, OrgId, OrgView, OrganizationPaymentBatchInput, OrganizationPaymentInput, PartyId, Payment, PaymentDirection, PaymentDocumentRef, PaymentDocumentRender, PaymentStatus, PaymentTiming, PaymentType, PaymentsPayInput, PayrollGroupId, PayrollGroupInput, PayrollRunId, PayrollRunStatus, Permission, PermissionMethods, PermissionReadResult, Profile, RoleView, SubmittedPermissionExecution, isClaimed, isRestoring } from "@capxul/sdk";
|
|
5
5
|
//#region src/provider.d.ts
|
|
6
6
|
type CapxulProviderSharedProps = {
|
|
7
7
|
/** Bring your own QueryClient; otherwise the provider creates one. */
|
|
@@ -200,12 +200,21 @@ type UseCapxulCreateOrgReturn = UseMutationResult<OrgView, CapxulError, CreateOr
|
|
|
200
200
|
declare function useCapxulCreateOrg(): UseCapxulCreateOrgReturn;
|
|
201
201
|
//#endregion
|
|
202
202
|
//#region src/hooks/use-capxul-invite-member.d.ts
|
|
203
|
+
/**
|
|
204
|
+
* R06 (#1964): `options` is the browser attempt the caller captured before the
|
|
205
|
+
* person pressed Send. It reaches the SDK operation unchanged, so the durable
|
|
206
|
+
* `org_invite_sent` and the later `org_invite_progressed` carry that attempt's
|
|
207
|
+
* correlation. Absent, the invitation keeps its own invocation context.
|
|
208
|
+
*/
|
|
209
|
+
type UseCapxulInviteMemberInput = InviteMemberInput & {
|
|
210
|
+
readonly options?: InvocationOptions;
|
|
211
|
+
};
|
|
203
212
|
/**
|
|
204
213
|
* Invite a member to an Organization by email. The hook uses the closed-over `orgId`.
|
|
205
214
|
* It binds directly to
|
|
206
215
|
* `capxul.org(orgId).invite(input)`. On success, invalidates the member list.
|
|
207
216
|
*/
|
|
208
|
-
type UseCapxulInviteMemberReturn = UseMutationResult<MemberView, CapxulError,
|
|
217
|
+
type UseCapxulInviteMemberReturn = UseMutationResult<MemberView, CapxulError, UseCapxulInviteMemberInput>;
|
|
209
218
|
declare function useCapxulInviteMember(orgId: OrgId | undefined): UseCapxulInviteMemberReturn;
|
|
210
219
|
//#endregion
|
|
211
220
|
//#region src/headless/journey/journey-state.d.ts
|
|
@@ -383,9 +392,9 @@ interface Contact {
|
|
|
383
392
|
interface ContactRow extends Contact {
|
|
384
393
|
/** Ours: one initials rule, not one copy per screen. */
|
|
385
394
|
readonly initials: string;
|
|
386
|
-
readonly rename: (name: string) => void;
|
|
387
|
-
readonly hide: () => void;
|
|
388
|
-
readonly unhide: () => void;
|
|
395
|
+
readonly rename: (name: string, options?: InvocationOptions) => void;
|
|
396
|
+
readonly hide: (options?: InvocationOptions) => void;
|
|
397
|
+
readonly unhide: (options?: InvocationOptions) => void;
|
|
389
398
|
}
|
|
390
399
|
/** ADR-0023 R1: refusal CODES, never sentences — the app owns the words. */
|
|
391
400
|
type ContactsRefusal = "loading" | "org-unavailable" | "unavailable";
|
|
@@ -421,7 +430,13 @@ interface ContactsListOptions {
|
|
|
421
430
|
interface ContactsAddSlice {
|
|
422
431
|
readonly value: string;
|
|
423
432
|
readonly change: (text: string) => void;
|
|
424
|
-
|
|
433
|
+
/**
|
|
434
|
+
* #1960 R02: hand it the options the screen captured BEFORE the click. The
|
|
435
|
+
* same snapshot reaches the SDK add call and comes back on `onAdded`/
|
|
436
|
+
* `onFailed`, so the UI observation and the operation share one identity even
|
|
437
|
+
* when the reply lands after an account switch. Omitted stays omitted.
|
|
438
|
+
*/
|
|
439
|
+
readonly submit: (options?: InvocationOptions) => void;
|
|
425
440
|
readonly isSubmitting: boolean;
|
|
426
441
|
readonly blocked: boolean;
|
|
427
442
|
readonly blockedReason: ContactsAddBlockedReason | null;
|
|
@@ -431,9 +446,14 @@ interface ContactsAddSlice {
|
|
|
431
446
|
//#region src/headless/contacts/contacts.d.ts
|
|
432
447
|
interface CapxulContactsProps {
|
|
433
448
|
readonly actor: ContactsActor;
|
|
434
|
-
|
|
449
|
+
/**
|
|
450
|
+
* `options` is exactly what the caller handed `.Add.submit` or a row verb, so
|
|
451
|
+
* the screen's own observation of the finished action can reuse the attempt
|
|
452
|
+
* identity the SDK operation ran under (#1960 R02).
|
|
453
|
+
*/
|
|
454
|
+
readonly onAdded: (contact: Contact, options?: InvocationOptions) => void;
|
|
435
455
|
/** ADR-0023 R1: the app maps `error.code` to its own copy; no SDK sentence. */
|
|
436
|
-
readonly onFailed: (error: CapxulError) => void;
|
|
456
|
+
readonly onFailed: (error: CapxulError, options?: InvocationOptions) => void;
|
|
437
457
|
readonly children: ReactNode;
|
|
438
458
|
}
|
|
439
459
|
declare function Root$6({ actor, onAdded, onFailed, children }: CapxulContactsProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -505,6 +525,7 @@ type SummaryWindow = "all" | "last30days" | ActivityRange;
|
|
|
505
525
|
* in its own words.
|
|
506
526
|
*/
|
|
507
527
|
interface ActivitySummarySlice {
|
|
528
|
+
readonly readWarning?: ActivityPage["readWarning"];
|
|
508
529
|
readonly currency: string | null;
|
|
509
530
|
readonly moneyIn: string | null;
|
|
510
531
|
readonly moneyOut: string | null;
|
|
@@ -541,11 +562,17 @@ interface ActivitySearchSlice {
|
|
|
541
562
|
readonly change: (text: string) => void;
|
|
542
563
|
}
|
|
543
564
|
interface ActivityRowsSlice {
|
|
565
|
+
readonly readWarning?: ActivityPage["readWarning"];
|
|
544
566
|
/** Already filtered and already searched. */
|
|
545
567
|
readonly rows: readonly ActivityRow[];
|
|
546
568
|
readonly isLoading: boolean;
|
|
547
569
|
readonly error: CapxulError | null;
|
|
548
|
-
|
|
570
|
+
/**
|
|
571
|
+
* #1960 R02: pass the options captured before the retry was selected and the
|
|
572
|
+
* re-read runs under the same attempt identity as the UI observation. Omit
|
|
573
|
+
* them and the read keeps its own invocation context.
|
|
574
|
+
*/
|
|
575
|
+
readonly retry: (options?: InvocationOptions) => void;
|
|
549
576
|
/** Server read time of the newest page, so the app can say which read is older. */
|
|
550
577
|
readonly observedAt: number | null;
|
|
551
578
|
}
|
|
@@ -583,13 +610,15 @@ interface ActivityDetailSlice {
|
|
|
583
610
|
readonly error: CapxulError | null;
|
|
584
611
|
}
|
|
585
612
|
interface CsvExport {
|
|
613
|
+
readonly readWarning?: ActivityPage["readWarning"];
|
|
586
614
|
readonly text: string;
|
|
587
615
|
readonly rowCount: number;
|
|
588
616
|
/** The 5,000-row ceiling was reached and rows were left unread. */
|
|
589
617
|
readonly truncated: boolean;
|
|
590
618
|
}
|
|
591
619
|
interface ActivityExportSlice {
|
|
592
|
-
|
|
620
|
+
/** Same contract as `retry`: the export's pages run under the caller's attempt. */
|
|
621
|
+
readonly toCsv: (options?: InvocationOptions) => Promise<CsvExport>;
|
|
593
622
|
readonly isExporting: boolean;
|
|
594
623
|
}
|
|
595
624
|
//#endregion
|
|
@@ -816,8 +845,19 @@ type DashboardScope = {
|
|
|
816
845
|
readonly orgId?: string;
|
|
817
846
|
};
|
|
818
847
|
type DashboardAccessPhase = "checking" | "error" | "redirect" | "granted";
|
|
848
|
+
/**
|
|
849
|
+
* Which of the three probes produced the error the screen is showing. The
|
|
850
|
+
* error code alone cannot say: a provider failure reads the same whether the
|
|
851
|
+
* session read, the membership list or the lifecycle read raised it, and a
|
|
852
|
+
* consumer that reports a displayed gate error has to keep those apart
|
|
853
|
+
* (#1963 R05-2). It names the SOURCE only; `retry` still re-runs every failed
|
|
854
|
+
* probe, exactly as before.
|
|
855
|
+
*/
|
|
856
|
+
type DashboardAccessProbe = "session" | "membership" | "lifecycle";
|
|
819
857
|
interface DashboardAccessErrorSlice {
|
|
820
858
|
readonly error: CapxulError;
|
|
859
|
+
/** The probe the surfaced error came from, in the frozen precedence order. */
|
|
860
|
+
readonly probe: DashboardAccessProbe;
|
|
821
861
|
/** Re-runs each failed probe. */
|
|
822
862
|
readonly retry: () => void;
|
|
823
863
|
}
|
|
@@ -836,6 +876,12 @@ declare function Checking({ children }: {
|
|
|
836
876
|
declare function DashboardError({ children }: {
|
|
837
877
|
readonly children: (slice: DashboardAccessErrorSlice) => ReactNode;
|
|
838
878
|
}): import("react/jsx-runtime").JSX.Element | null;
|
|
879
|
+
/**
|
|
880
|
+
* Hands the destination and draws nothing. Reaching this part is a REQUEST to
|
|
881
|
+
* navigate, never an arrival: the app may cancel or supersede it, so nothing
|
|
882
|
+
* here — and nothing a consumer hangs off it — may claim a completed redirect
|
|
883
|
+
* (#1963 R05-1). The destination page's own normalized pageview proves arrival.
|
|
884
|
+
*/
|
|
839
885
|
declare function Redirect({ children }: {
|
|
840
886
|
readonly children: (slice: DashboardAccessRedirectSlice) => ReactNode;
|
|
841
887
|
}): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -874,8 +920,14 @@ interface PayrollSummarySlice {
|
|
|
874
920
|
}
|
|
875
921
|
interface PayrollGroupsSlice {
|
|
876
922
|
readonly groups: readonly PayrollGroupRow[];
|
|
877
|
-
|
|
878
|
-
|
|
923
|
+
/**
|
|
924
|
+
* R13 (#1968): `options` is the browser attempt the caller captured before the
|
|
925
|
+
* employer pressed the button. It reaches the SDK operation unchanged, so the
|
|
926
|
+
* group's `ui_payroll_action_completed` and the durable `payroll_group_changed`
|
|
927
|
+
* share one correlation. Absent, the write keeps its own invocation context.
|
|
928
|
+
*/
|
|
929
|
+
readonly save: (input: PayrollGroupInput, options?: InvocationOptions) => Promise<CapxulResult<PayrollGroupRow>>;
|
|
930
|
+
readonly remove: (id: PayrollGroupId, options?: InvocationOptions) => Promise<CapxulResult<void>>;
|
|
879
931
|
readonly isSaving: boolean;
|
|
880
932
|
readonly isLoading: boolean;
|
|
881
933
|
readonly error: CapxulError | null;
|
|
@@ -967,7 +1019,14 @@ interface PayrollRunSummarySlice {
|
|
|
967
1019
|
interface PayrollRunActionsSlice {
|
|
968
1020
|
readonly recovery: "none" | "restoring" | "required" | "unavailable";
|
|
969
1021
|
readonly recoveryError: CapxulError | null;
|
|
970
|
-
|
|
1022
|
+
/**
|
|
1023
|
+
* R13 (#1968): `options` is the browser attempt captured before the employer
|
|
1024
|
+
* confirmed. It reaches `authorizeRun` unchanged, so the sheet's own
|
|
1025
|
+
* `ui_payroll_action_completed` and the durable `payroll_run_transitioned`
|
|
1026
|
+
* rows share one correlation. It is NEVER written into the persisted draft —
|
|
1027
|
+
* a restored run keeps its own identity, not a stale attempt's.
|
|
1028
|
+
*/
|
|
1029
|
+
readonly submit: (options?: InvocationOptions) => void;
|
|
971
1030
|
readonly isSubmitting: boolean;
|
|
972
1031
|
readonly blocked: boolean;
|
|
973
1032
|
readonly blockedReason: CapxulPayrollRunBlockedReason | null;
|
|
@@ -1036,7 +1095,7 @@ declare const capxulKeys: {
|
|
|
1036
1095
|
orgRoles: (orgId: OrgId | undefined) => readonly ["capxul", "org", "pending" | OrgId, "roles"];
|
|
1037
1096
|
orgTreasury: (orgId: OrgId | undefined) => readonly ["capxul", "org", "pending" | OrgId, "treasury"];
|
|
1038
1097
|
orgPermissions: (orgId: OrgId | undefined) => readonly ["capxul", "org", "pending" | OrgId, "permissions"];
|
|
1039
|
-
orgMe: (orgId: OrgId | undefined) => readonly ["capxul", "org", "pending" | OrgId, "me"];
|
|
1098
|
+
orgMe: (orgId: OrgId | undefined, account: string | undefined) => readonly ["capxul", "org", "pending" | OrgId, "me", string];
|
|
1040
1099
|
orgLifecycle: (orgId: OrgId | undefined) => readonly ["capxul", "org", "pending" | OrgId, "lifecycle"];
|
|
1041
1100
|
contacts: (scope: string) => readonly ["capxul", "contacts", string];
|
|
1042
1101
|
contactsList: (scope: string, includeHidden: boolean) => readonly ["capxul", "contacts", string, "all" | "visible"];
|
|
@@ -1051,4 +1110,4 @@ declare const capxulKeys: {
|
|
|
1051
1110
|
payment: (paymentId: string | undefined) => readonly ["capxul", "payments", string];
|
|
1052
1111
|
};
|
|
1053
1112
|
//#endregion
|
|
1054
|
-
export { type AccountFailure, type AccountProgress, type ActionResult, type ActivityDetailSlice, type ActivityExportSlice, type ActivityFilterValues, type ActivityFiltersSlice, type ActivityLoadMoreSlice, type ActivityReceipt, type ActivityRow, type ActivityRowsSlice, type ActivitySearchSlice, type ActivitySummarySlice, type AuthenticatedState, type AuthenticationSlots, type CanReason, CapxulActivity, type CapxulActivityProps, type CapxulAuth, CapxulAuthenticationController, type CapxulBootstrapState, type CapxulBootstrapStatus, CapxulContacts, type CapxulContactsProps, CapxulDashboardAccess, type CapxulDashboardAccessProps, CapxulOnboardingController, CapxulOrgMember, type CapxulOrgMemberProps, CapxulPayroll, type CapxulPayrollProps, CapxulPayrollRun, type CapxulPayrollRunBlockedReason, type CapxulPayrollRunProps, CapxulProvider, type CapxulProviderProps, type CapxulSend, CapxulSendMoney, type CapxulSendMoneyBlockedReason, type CapxulSendMoneyProps, type Contact, type ContactRelationship, type ContactRow, type ContactsActor, type ContactsAddBlockedReason, type ContactsAddError, type ContactsAddSlice, type ContactsListOptions, type ContactsListSlice, type ContactsRefusal, type ContactsSummarySlice, type ControllerAction, type CreateOrganizationFailure, type CreateOrganizationSubmission, type CsvExport, type DashboardAccessErrorSlice, type DashboardAccessPhase, type DashboardAccessRedirectSlice, type DashboardScope, type Destination, type FaultedState, type HandleAvailability, type ImageUploadInput, type ImageUploadTarget, type InvocationOptions, type NavigationAction, type OnboardingControllerProps, type OnboardingIntent, type OnboardingJourney, type OnboardingJourneyPosition, type OnboardingOrigin, type OnboardingStep, type OrgFailure, type OrgMemberAction, type OrgMemberCanSlice, type OrgMemberStanding, type OrgMemberStandingSlice, type OrgProgress, type OrganizationDetails, type OrganizationDraft, type OtpPendingState, type PayoutDraftChain, type PayoutDraftEntry, type PayrollGroupRow, type PayrollGroupsSlice, type PayrollRecipientOption, type PayrollRunActionsSlice, type PayrollRunAmountEntry, type PayrollRunAmountsSlice, type PayrollRunAssetSlice, type PayrollRunGroupOption, type PayrollRunPrefill, type PayrollRunRecipientsSlice, type PayrollRunStatus, type PayrollRunSummarySlice, type PayrollSummarySlice, type PendingAuthState, type ProfileDetails, type ProfileDraft, type ProfileSlotProps, type ReadyDestination, type RetryAction, type SendActor, type SendMoneyActionsSlice, type SendMoneyAmountSlice, type SendMoneyAssetError, type SendMoneyAssetOption, type SendMoneyAssetSlice, type SendMoneyRecipientSlice, type SendMoneyRecipientStatus, type SendMoneySourceError, type SendMoneySourceOption, type SendMoneySourceSlice, type SendResult, type SentPayment, type SentPayrollRun, type SignedOutState, type Slot, type SummaryWindow, type UseCapxulAccountBalanceOptions, type UseCapxulAccountBalanceReturn, type UseCapxulAccountFundReturn, type UseCapxulCreateCommitmentReturn, type UseCapxulCreateOrgReturn, type UseCapxulHandleAvailabilityReturn, type UseCapxulImageUploadReturn, type UseCapxulInviteMemberReturn, type UseCapxulOrgMembersOptions, type UseCapxulOrgMembersReturn, type UseCapxulOrgRolesOptions, type UseCapxulOrgRolesReturn, type UseCapxulOrgTreasuryOptions, type UseCapxulOrgTreasuryReturn, type UseCapxulOrgsReturn, type UseCapxulPayReturn, type UseCapxulPaymentReturn, type UseCapxulPaymentsReturn, type UseCapxulProfileReturn, type UseCapxulRedirectPaymentReturn, type UseCapxulUploadImageReturn, acknowledgeOnboardingDestination, activeOnboardingRecovery, capxulKeys, clearOnboardingJourney, currentOnboardingJourneyId, entered, invalidateOnboardingJourneyObservation, isClaimed, isRestoring, loadOnboardingJourney, onboardingJourneyPosition, saveOnboardingJourney, startOnboardingJourney, useCapxul, useCapxulAccountBalance, useCapxulAccountFund, useCapxulActivity, useCapxulActivityDetail, useCapxulAnnotateMovement, useCapxulAuth, useCapxulCancelPayment, useCapxulClaimPayment, useCapxulClientOrNull, useCapxulCreateCommitment, useCapxulCreateOrg, useCapxulDestination, useCapxulHandleAvailability, useCapxulHoldings, useCapxulIdentity, useCapxulImageUpload, useCapxulInviteMember, useCapxulOrgMembers, useCapxulOrgRoles, useCapxulOrgTreasury, useCapxulOrganizationPay, useCapxulOrganizationPayBatch, useCapxulOrgs, useCapxulPay, useCapxulPayment, useCapxulPayments, useCapxulPermission, useCapxulPermissionAssign, useCapxulPermissionChange, useCapxulPermissionCreate, useCapxulPermissionReplace, useCapxulPermissionRevoke, useCapxulPermissions, useCapxulProfile, useCapxulRedirectPayment, useCapxulSend, useCapxulTransitions, useCapxulUploadImage };
|
|
1113
|
+
export { type AccountFailure, type AccountProgress, type ActionResult, type ActivityDetailSlice, type ActivityExportSlice, type ActivityFilterValues, type ActivityFiltersSlice, type ActivityLoadMoreSlice, type ActivityReceipt, type ActivityRow, type ActivityRowsSlice, type ActivitySearchSlice, type ActivitySummarySlice, type AuthenticatedState, type AuthenticationSlots, type CanReason, CapxulActivity, type CapxulActivityProps, type CapxulAuth, CapxulAuthenticationController, type CapxulBootstrapState, type CapxulBootstrapStatus, CapxulContacts, type CapxulContactsProps, CapxulDashboardAccess, type CapxulDashboardAccessProps, CapxulOnboardingController, CapxulOrgMember, type CapxulOrgMemberProps, CapxulPayroll, type CapxulPayrollProps, CapxulPayrollRun, type CapxulPayrollRunBlockedReason, type CapxulPayrollRunProps, CapxulProvider, type CapxulProviderProps, type CapxulSend, CapxulSendMoney, type CapxulSendMoneyBlockedReason, type CapxulSendMoneyProps, type Contact, type ContactRelationship, type ContactRow, type ContactsActor, type ContactsAddBlockedReason, type ContactsAddError, type ContactsAddSlice, type ContactsListOptions, type ContactsListSlice, type ContactsRefusal, type ContactsSummarySlice, type ControllerAction, type CreateOrganizationFailure, type CreateOrganizationSubmission, type CsvExport, type DashboardAccessErrorSlice, type DashboardAccessPhase, type DashboardAccessProbe, type DashboardAccessRedirectSlice, type DashboardScope, type Destination, type FaultedState, type HandleAvailability, type ImageUploadInput, type ImageUploadTarget, type InvocationOptions, type NavigationAction, type OnboardingControllerProps, type OnboardingIntent, type OnboardingJourney, type OnboardingJourneyPosition, type OnboardingOrigin, type OnboardingStep, type OrgFailure, type OrgMemberAction, type OrgMemberCanSlice, type OrgMemberStanding, type OrgMemberStandingSlice, type OrgProgress, type OrganizationDetails, type OrganizationDraft, type OtpPendingState, type PayoutDraftChain, type PayoutDraftEntry, type PayrollGroupRow, type PayrollGroupsSlice, type PayrollRecipientOption, type PayrollRunActionsSlice, type PayrollRunAmountEntry, type PayrollRunAmountsSlice, type PayrollRunAssetSlice, type PayrollRunGroupOption, type PayrollRunPrefill, type PayrollRunRecipientsSlice, type PayrollRunStatus, type PayrollRunSummarySlice, type PayrollSummarySlice, type PendingAuthState, type ProfileDetails, type ProfileDraft, type ProfileSlotProps, type ReadyDestination, type RetryAction, type SendActor, type SendMoneyActionsSlice, type SendMoneyAmountSlice, type SendMoneyAssetError, type SendMoneyAssetOption, type SendMoneyAssetSlice, type SendMoneyRecipientSlice, type SendMoneyRecipientStatus, type SendMoneySourceError, type SendMoneySourceOption, type SendMoneySourceSlice, type SendResult, type SentPayment, type SentPayrollRun, type SignedOutState, type Slot, type SummaryWindow, type UseCapxulAccountBalanceOptions, type UseCapxulAccountBalanceReturn, type UseCapxulAccountFundReturn, type UseCapxulCreateCommitmentReturn, type UseCapxulCreateOrgReturn, type UseCapxulHandleAvailabilityReturn, type UseCapxulImageUploadReturn, type UseCapxulInviteMemberInput, type UseCapxulInviteMemberReturn, type UseCapxulOrgMembersOptions, type UseCapxulOrgMembersReturn, type UseCapxulOrgRolesOptions, type UseCapxulOrgRolesReturn, type UseCapxulOrgTreasuryOptions, type UseCapxulOrgTreasuryReturn, type UseCapxulOrgsReturn, type UseCapxulPayReturn, type UseCapxulPaymentReturn, type UseCapxulPaymentsReturn, type UseCapxulProfileReturn, type UseCapxulRedirectPaymentReturn, type UseCapxulUploadImageReturn, acknowledgeOnboardingDestination, activeOnboardingRecovery, capxulKeys, clearOnboardingJourney, currentOnboardingJourneyId, entered, invalidateOnboardingJourneyObservation, isClaimed, isRestoring, loadOnboardingJourney, onboardingJourneyPosition, saveOnboardingJourney, startOnboardingJourney, useCapxul, useCapxulAccountBalance, useCapxulAccountFund, useCapxulActivity, useCapxulActivityDetail, useCapxulAnnotateMovement, useCapxulAuth, useCapxulCancelPayment, useCapxulClaimPayment, useCapxulClientOrNull, useCapxulCreateCommitment, useCapxulCreateOrg, useCapxulDestination, useCapxulHandleAvailability, useCapxulHoldings, useCapxulIdentity, useCapxulImageUpload, useCapxulInviteMember, useCapxulOrgMembers, useCapxulOrgRoles, useCapxulOrgTreasury, useCapxulOrganizationPay, useCapxulOrganizationPayBatch, useCapxulOrgs, useCapxulPay, useCapxulPayment, useCapxulPayments, useCapxulPermission, useCapxulPermissionAssign, useCapxulPermissionChange, useCapxulPermissionCreate, useCapxulPermissionReplace, useCapxulPermissionRevoke, useCapxulPermissions, useCapxulProfile, useCapxulRedirectPayment, useCapxulSend, useCapxulTransitions, useCapxulUploadImage };
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { a as useCapxulAuth, c as useCapxulIdentityOrNull, d as
|
|
2
|
+
import { _ as useCapxul, a as useCapxulAuth, c as useCapxulIdentityOrNull, d as toInvocationControls, f as toInvocationOptions, g as useCapxulClientOrNull, h as capxulKeys, i as entered, l as useCapxulSend, m as actingAccount, n as CapxulOnboardingController, o as useCapxulDestination, p as accountKey, r as CapxulProvider, s as useCapxulIdentity, t as CapxulAuthenticationController, u as useCapxulTransitions } from "./controllers-DXmEHrnw.mjs";
|
|
3
3
|
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
4
4
|
import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
5
5
|
import { CAPXUL_OPERATIONS, CapxulError, EVM_ADDRESS_RE, Errors, HANDLE_RE, PAYMENT_DIRECTIONS, PAYMENT_STATUSES, fingerprintPaymentIntent, formatMoney, isCapxulError, isClaimed, isClaimed as isClaimed$1, isMoneyParseError, isRestoring, isRestoring as isRestoring$1, parseMoney, paymentPhase, resolveIdentityDestination, toEvmAddress, toPartyId } from "@capxul/sdk";
|
|
@@ -47,8 +47,9 @@ function useCapxulProfile() {
|
|
|
47
47
|
//#region src/hooks/use-capxul-account-balance.ts
|
|
48
48
|
function useCapxulAccountBalance(options) {
|
|
49
49
|
const client = useCapxulClientOrNull();
|
|
50
|
+
const identity = useCapxulIdentityOrNull();
|
|
50
51
|
return useQuery({
|
|
51
|
-
queryKey: capxulKeys.accountBalance,
|
|
52
|
+
queryKey: accountKey(capxulKeys.accountBalance, identity),
|
|
52
53
|
queryFn: async () => {
|
|
53
54
|
return unwrapCapxulResult(await requireBootstrappedClient(client, CAPXUL_OPERATIONS.accounts.read).accounts.read());
|
|
54
55
|
},
|
|
@@ -302,7 +303,7 @@ function useCapxulPayments(options) {
|
|
|
302
303
|
const client = useCapxulClientOrNull();
|
|
303
304
|
const identity = useCapxulIdentityOrNull();
|
|
304
305
|
return useQuery({
|
|
305
|
-
queryKey: capxulKeys.payments,
|
|
306
|
+
queryKey: accountKey(capxulKeys.payments, identity),
|
|
306
307
|
queryFn: async () => {
|
|
307
308
|
return unwrapCapxulResult(await requireBootstrappedClient(client, CAPXUL_OPERATIONS.payments.list).payments.list());
|
|
308
309
|
},
|
|
@@ -311,8 +312,9 @@ function useCapxulPayments(options) {
|
|
|
311
312
|
}
|
|
312
313
|
function useCapxulPayment(paymentId, options) {
|
|
313
314
|
const client = useCapxulClientOrNull();
|
|
315
|
+
const identity = useCapxulIdentityOrNull();
|
|
314
316
|
return useQuery({
|
|
315
|
-
queryKey: capxulKeys.payment(paymentId),
|
|
317
|
+
queryKey: accountKey(capxulKeys.payment(paymentId), identity),
|
|
316
318
|
queryFn: async () => {
|
|
317
319
|
if (paymentId === void 0) throw Errors.invalidInput("paymentId", "required for payments.get");
|
|
318
320
|
return unwrapCapxulResult(await requireBootstrappedClient(client, CAPXUL_OPERATIONS.payments.get).payments.get(paymentId));
|
|
@@ -430,7 +432,7 @@ function useCapxulActivity(params) {
|
|
|
430
432
|
const client = useCapxulClientOrNull();
|
|
431
433
|
const identity = useCapxulIdentityOrNull();
|
|
432
434
|
return useQuery({
|
|
433
|
-
queryKey: [...capxulKeys.activity, params ?? {}],
|
|
435
|
+
queryKey: accountKey([...capxulKeys.activity, params ?? {}], identity),
|
|
434
436
|
queryFn: async () => {
|
|
435
437
|
return unwrapCapxulResult(await requireBootstrappedClient(client, CAPXUL_OPERATIONS.activity.list).activity.list(params));
|
|
436
438
|
},
|
|
@@ -441,7 +443,7 @@ function useCapxulActivityDetail(reference, actor) {
|
|
|
441
443
|
const client = useCapxulClientOrNull();
|
|
442
444
|
const identity = useCapxulIdentityOrNull();
|
|
443
445
|
return useQuery({
|
|
444
|
-
queryKey: capxulKeys.activityDetail(reference, actor),
|
|
446
|
+
queryKey: accountKey(capxulKeys.activityDetail(reference, actor), identity),
|
|
445
447
|
queryFn: async () => {
|
|
446
448
|
if (reference === void 0) throw Errors.invalidInput("reference", "required for activity.get");
|
|
447
449
|
return unwrapCapxulResult(await requireBootstrappedClient(client, CAPXUL_OPERATIONS.activity.get).activity.get(reference, actor === void 0 ? void 0 : { actor }));
|
|
@@ -466,7 +468,7 @@ function useCapxulHoldings(params) {
|
|
|
466
468
|
const identity = useCapxulIdentityOrNull();
|
|
467
469
|
const actor = params?.actor;
|
|
468
470
|
return useQuery({
|
|
469
|
-
queryKey: capxulKeys.holdings(actor),
|
|
471
|
+
queryKey: accountKey(capxulKeys.holdings(actor), identity),
|
|
470
472
|
queryFn: async () => {
|
|
471
473
|
return unwrapCapxulResult(await requireBootstrappedClient(client, CAPXUL_OPERATIONS.holdings.current).holdings.current(actor === void 0 ? void 0 : { actor }));
|
|
472
474
|
},
|
|
@@ -477,8 +479,9 @@ function useCapxulHoldings(params) {
|
|
|
477
479
|
//#region src/hooks/use-capxul-orgs.ts
|
|
478
480
|
function useCapxulOrgs(options) {
|
|
479
481
|
const client = useCapxulClientOrNull();
|
|
482
|
+
const identity = useCapxulIdentityOrNull();
|
|
480
483
|
return useQuery({
|
|
481
|
-
queryKey: capxulKeys.orgs,
|
|
484
|
+
queryKey: accountKey(capxulKeys.orgs, identity),
|
|
482
485
|
queryFn: async () => {
|
|
483
486
|
return unwrapCapxulResult(await requireBootstrappedClient(client, "orgs").orgs());
|
|
484
487
|
},
|
|
@@ -517,9 +520,10 @@ function useCapxulOrgRoles(orgId, options) {
|
|
|
517
520
|
//#region src/hooks/use-capxul-org-treasury.ts
|
|
518
521
|
function useCapxulOrgTreasury(orgId, options) {
|
|
519
522
|
const client = useCapxulClientOrNull();
|
|
523
|
+
const identity = useCapxulIdentityOrNull();
|
|
520
524
|
const enabled = options?.enabled ?? true;
|
|
521
525
|
return useQuery({
|
|
522
|
-
queryKey: capxulKeys.orgTreasury(orgId),
|
|
526
|
+
queryKey: accountKey(capxulKeys.orgTreasury(orgId), identity),
|
|
523
527
|
queryFn: async () => {
|
|
524
528
|
if (orgId === void 0) throw Errors.invalidInput("orgId", "required for useCapxulOrgTreasury");
|
|
525
529
|
return unwrapCapxulResult(await requireBootstrappedClient(client, CAPXUL_OPERATIONS.org.treasury).org(orgId).treasury());
|
|
@@ -547,9 +551,9 @@ function useCapxulInviteMember(orgId) {
|
|
|
547
551
|
const client = useCapxulClientOrNull();
|
|
548
552
|
const queryClient = useQueryClient();
|
|
549
553
|
return useMutation({
|
|
550
|
-
mutationFn: async (input) => {
|
|
554
|
+
mutationFn: async ({ options, ...input }) => {
|
|
551
555
|
if (orgId === void 0) throw Errors.invalidInput("orgId", "required for useCapxulInviteMember");
|
|
552
|
-
return unwrapCapxulResult(await requireBootstrappedClient(client, CAPXUL_OPERATIONS.org.invite).org(orgId).invite(input));
|
|
556
|
+
return unwrapCapxulResult(await requireBootstrappedClient(client, CAPXUL_OPERATIONS.org.invite).org(orgId).invite(input, toInvocationControls(options)));
|
|
553
557
|
},
|
|
554
558
|
onSuccess: async () => {
|
|
555
559
|
if (orgId === void 0) return;
|
|
@@ -879,6 +883,8 @@ function useCapxulUploadImage() {
|
|
|
879
883
|
}
|
|
880
884
|
//#endregion
|
|
881
885
|
//#region src/headless/contacts/use-contacts.ts
|
|
886
|
+
/** One captured snapshot, or nothing — never a fabricated empty options object. */
|
|
887
|
+
const carry$1 = (options) => options === void 0 ? {} : { options };
|
|
882
888
|
function useContacts(input) {
|
|
883
889
|
const { actor, onAdded, onFailed } = input;
|
|
884
890
|
const client = useCapxulClientOrNull();
|
|
@@ -895,35 +901,40 @@ function useContacts(input) {
|
|
|
895
901
|
const writeMutate = useMutation({
|
|
896
902
|
mutationFn: async (command) => {
|
|
897
903
|
const target = requireBook(book, `addressBook.${command.kind}`);
|
|
904
|
+
const controls = toInvocationControls(command.options);
|
|
898
905
|
return unwrapCapxulResult(command.kind === "rename" ? await target.label({
|
|
899
906
|
entryId: command.id,
|
|
900
907
|
label: command.name
|
|
901
|
-
}) : command.kind === "hide" ? await target.hide(command.id) : await target.unhide(command.id));
|
|
908
|
+
}, controls) : command.kind === "hide" ? await target.hide(command.id, controls) : await target.unhide(command.id, controls));
|
|
902
909
|
},
|
|
903
910
|
onSettled: invalidate,
|
|
904
|
-
onError: onFailed
|
|
911
|
+
onError: (error, command) => onFailed(error, command.options)
|
|
905
912
|
}).mutate;
|
|
906
913
|
const [value, setValue] = useState("");
|
|
907
914
|
const [addError, setAddError] = useState(null);
|
|
908
915
|
const addContact = useMutation({
|
|
909
|
-
mutationFn: async (
|
|
916
|
+
mutationFn: async (command) => unwrapCapxulResult(await requireBook(book, CAPXUL_OPERATIONS.addressBook.add).add({ ref: command.ref }, toInvocationControls(command.options))),
|
|
910
917
|
onSettled: invalidate
|
|
911
918
|
});
|
|
912
919
|
const addMutate = addContact.mutate;
|
|
913
920
|
const blockedReason = refusal !== null ? "org-unavailable" : value.trim() === "" ? "empty" : null;
|
|
914
921
|
const submitGate = useRef(false);
|
|
915
|
-
const submit = useCallback(() => {
|
|
922
|
+
const submit = useCallback((options) => {
|
|
916
923
|
if (blockedReason !== null || submitGate.current) return;
|
|
924
|
+
const attempt = toInvocationOptions(options);
|
|
917
925
|
submitGate.current = true;
|
|
918
926
|
setAddError(null);
|
|
919
|
-
addMutate(
|
|
927
|
+
addMutate({
|
|
928
|
+
ref: refFromTypedText(value),
|
|
929
|
+
...carry$1(attempt)
|
|
930
|
+
}, {
|
|
920
931
|
onSuccess: (entry) => {
|
|
921
932
|
setValue("");
|
|
922
|
-
onAdded(toContact(entry));
|
|
933
|
+
onAdded(toContact(entry), attempt);
|
|
923
934
|
},
|
|
924
935
|
onError: (error) => {
|
|
925
936
|
setAddError(error.code === "INVALID_INPUT" ? "unresolved" : "failed");
|
|
926
|
-
onFailed(error);
|
|
937
|
+
onFailed(error, attempt);
|
|
927
938
|
},
|
|
928
939
|
onSettled: () => {
|
|
929
940
|
submitGate.current = false;
|
|
@@ -944,18 +955,21 @@ function useContacts(input) {
|
|
|
944
955
|
book,
|
|
945
956
|
scope,
|
|
946
957
|
refusal,
|
|
947
|
-
rename: useCallback((id, name) => writeMutate({
|
|
958
|
+
rename: useCallback((id, name, options) => writeMutate({
|
|
948
959
|
kind: "rename",
|
|
949
960
|
id,
|
|
950
|
-
name
|
|
961
|
+
name,
|
|
962
|
+
...carry$1(toInvocationOptions(options))
|
|
951
963
|
}), [writeMutate]),
|
|
952
|
-
hide: useCallback((id) => writeMutate({
|
|
964
|
+
hide: useCallback((id, options) => writeMutate({
|
|
953
965
|
kind: "hide",
|
|
954
|
-
id
|
|
966
|
+
id,
|
|
967
|
+
...carry$1(toInvocationOptions(options))
|
|
955
968
|
}), [writeMutate]),
|
|
956
|
-
unhide: useCallback((id) => writeMutate({
|
|
969
|
+
unhide: useCallback((id, options) => writeMutate({
|
|
957
970
|
kind: "unhide",
|
|
958
|
-
id
|
|
971
|
+
id,
|
|
972
|
+
...carry$1(toInvocationOptions(options))
|
|
959
973
|
}), [writeMutate]),
|
|
960
974
|
add: {
|
|
961
975
|
value,
|
|
@@ -973,10 +987,11 @@ function useContacts(input) {
|
|
|
973
987
|
* query key, so React Query issues ONE request for them.
|
|
974
988
|
*/
|
|
975
989
|
function useContactsList(engine, options) {
|
|
990
|
+
const identity = useCapxulIdentityOrNull();
|
|
976
991
|
const includeHidden = options.show === "all";
|
|
977
992
|
const { book, refusal } = engine;
|
|
978
993
|
const query = useQuery({
|
|
979
|
-
queryKey: capxulKeys.contactsList(engine.scope, includeHidden),
|
|
994
|
+
queryKey: accountKey(capxulKeys.contactsList(engine.scope, includeHidden), identity),
|
|
980
995
|
queryFn: async () => unwrapCapxulResult(await requireBook(book, CAPXUL_OPERATIONS.addressBook.list).list({ includeHidden })),
|
|
981
996
|
enabled: book !== null
|
|
982
997
|
});
|
|
@@ -989,9 +1004,9 @@ function useContactsList(engine, options) {
|
|
|
989
1004
|
if (entries === void 0) return [];
|
|
990
1005
|
return (limit === void 0 ? entries : entries.slice(0, limit)).map((entry) => Object.assign(toContact(entry), {
|
|
991
1006
|
initials: initialsOf(entry.label),
|
|
992
|
-
rename: (name) => rename(entry.id, name),
|
|
993
|
-
hide: () => hide(entry.id),
|
|
994
|
-
unhide: () => unhide(entry.id)
|
|
1007
|
+
rename: (name, attempt) => rename(entry.id, name, attempt),
|
|
1008
|
+
hide: (attempt) => hide(entry.id, attempt),
|
|
1009
|
+
unhide: (attempt) => unhide(entry.id, attempt)
|
|
995
1010
|
}));
|
|
996
1011
|
}, [
|
|
997
1012
|
entries,
|
|
@@ -1165,9 +1180,10 @@ function activityDetailKey(actor, reference) {
|
|
|
1165
1180
|
}
|
|
1166
1181
|
function useActivityDetail(reference, actor) {
|
|
1167
1182
|
const client = useCapxulClientOrNull();
|
|
1183
|
+
const identity = useCapxulIdentityOrNull();
|
|
1168
1184
|
const enabled = useActivityEnabled() && reference !== void 0;
|
|
1169
1185
|
const detail = useQuery({
|
|
1170
|
-
queryKey: capxulKeys.activityDetail(reference, actor),
|
|
1186
|
+
queryKey: accountKey(capxulKeys.activityDetail(reference, actor), identity),
|
|
1171
1187
|
queryFn: async () => {
|
|
1172
1188
|
if (reference === void 0) throw Errors.invalidInput("reference", "required for activity.get");
|
|
1173
1189
|
return unwrapCapxulResult(await requireBootstrappedClient(client, CAPXUL_OPERATIONS.activity.get).activity.get(reference, actor === void 0 ? void 0 : { actor }));
|
|
@@ -1322,10 +1338,11 @@ function useUtcDay(active) {
|
|
|
1322
1338
|
}
|
|
1323
1339
|
function useActivitySummary(actor, window) {
|
|
1324
1340
|
const client = useCapxulClientOrNull();
|
|
1341
|
+
const identity = useCapxulIdentityOrNull();
|
|
1325
1342
|
const enabled = useActivityEnabled();
|
|
1326
1343
|
const range = resolveWindow(window, useUtcDay(window === "last30days") * DAY_MS);
|
|
1327
1344
|
const summary = useQuery({
|
|
1328
|
-
queryKey: capxulKeys.activitySummary(actor, range),
|
|
1345
|
+
queryKey: accountKey(capxulKeys.activitySummary(actor, range), identity),
|
|
1329
1346
|
queryFn: async () => {
|
|
1330
1347
|
const params = {};
|
|
1331
1348
|
if (actor !== void 0) params.actor = actor;
|
|
@@ -1335,7 +1352,7 @@ function useActivitySummary(actor, window) {
|
|
|
1335
1352
|
enabled
|
|
1336
1353
|
});
|
|
1337
1354
|
const primary = useQuery({
|
|
1338
|
-
queryKey: [...capxulKeys.holdings(actor), "primary"],
|
|
1355
|
+
queryKey: accountKey([...capxulKeys.holdings(actor), "primary"], identity),
|
|
1339
1356
|
queryFn: async () => {
|
|
1340
1357
|
return unwrapCapxulResult(await requireBootstrappedClient(client, CAPXUL_OPERATIONS.holdings.primary).holdings.primary(actor === void 0 ? void 0 : { actor }));
|
|
1341
1358
|
},
|
|
@@ -1357,7 +1374,8 @@ function useActivitySummary(actor, window) {
|
|
|
1357
1374
|
pending: null,
|
|
1358
1375
|
count: summary.data?.count ?? 0,
|
|
1359
1376
|
isLoading,
|
|
1360
|
-
error: asCapxulError$1(summary.error)
|
|
1377
|
+
error: asCapxulError$1(summary.error),
|
|
1378
|
+
...summary.data?.readWarning === void 0 ? {} : { readWarning: summary.data.readWarning }
|
|
1361
1379
|
};
|
|
1362
1380
|
const display = (raw) => formatMoney({
|
|
1363
1381
|
currency: bucket.currency,
|
|
@@ -1372,7 +1390,8 @@ function useActivitySummary(actor, window) {
|
|
|
1372
1390
|
pending: display(bucket.pendingIn),
|
|
1373
1391
|
count: summary.data?.count ?? 0,
|
|
1374
1392
|
isLoading,
|
|
1375
|
-
error: asCapxulError$1(summary.error)
|
|
1393
|
+
error: asCapxulError$1(summary.error),
|
|
1394
|
+
...summary.data?.readWarning === void 0 ? {} : { readWarning: summary.data.readWarning }
|
|
1376
1395
|
};
|
|
1377
1396
|
}
|
|
1378
1397
|
//#endregion
|
|
@@ -1538,6 +1557,8 @@ function clampPageSize(pageSize) {
|
|
|
1538
1557
|
function useActivity(input) {
|
|
1539
1558
|
const { actor, pageSize } = input;
|
|
1540
1559
|
const client = useCapxulClientOrNull();
|
|
1560
|
+
const identity = useCapxulIdentityOrNull();
|
|
1561
|
+
const account = actingAccount(identity);
|
|
1541
1562
|
const enabled = useActivityEnabled();
|
|
1542
1563
|
const limit = clampPageSize(pageSize);
|
|
1543
1564
|
const warned = useRef(false);
|
|
@@ -1567,21 +1588,51 @@ function useActivity(input) {
|
|
|
1567
1588
|
if (filter !== void 0) params.filter = filter;
|
|
1568
1589
|
return params;
|
|
1569
1590
|
}, [actor, filter]);
|
|
1591
|
+
const selectedRetry = useRef(void 0);
|
|
1592
|
+
const takeSelectedRetry = useCallback(() => {
|
|
1593
|
+
const attempt = selectedRetry.current;
|
|
1594
|
+
selectedRetry.current = void 0;
|
|
1595
|
+
return toInvocationControls(attempt);
|
|
1596
|
+
}, []);
|
|
1570
1597
|
const query = useInfiniteQuery({
|
|
1571
|
-
queryKey: [
|
|
1598
|
+
queryKey: accountKey([
|
|
1572
1599
|
...capxulKeys.activity,
|
|
1573
1600
|
"list",
|
|
1574
1601
|
actor ?? "self",
|
|
1575
1602
|
limit,
|
|
1576
1603
|
filter ?? "none"
|
|
1577
|
-
],
|
|
1604
|
+
], identity),
|
|
1578
1605
|
queryFn: async ({ pageParam }) => {
|
|
1579
|
-
return unwrapCapxulResult(await requireBootstrappedClient(client, CAPXUL_OPERATIONS.activity.list).activity.list(listParams(pageParam, limit)));
|
|
1606
|
+
return unwrapCapxulResult(await requireBootstrappedClient(client, CAPXUL_OPERATIONS.activity.list).activity.list(listParams(pageParam, limit), takeSelectedRetry()));
|
|
1580
1607
|
},
|
|
1581
1608
|
initialPageParam: void 0,
|
|
1582
1609
|
getNextPageParam: (last) => last.cursor ?? void 0,
|
|
1583
1610
|
enabled
|
|
1584
1611
|
});
|
|
1612
|
+
const queryClient = useQueryClient();
|
|
1613
|
+
useEffect(() => {
|
|
1614
|
+
if (!enabled || client === null) return;
|
|
1615
|
+
let stop;
|
|
1616
|
+
let cancelled = false;
|
|
1617
|
+
client.activity.subscribe(() => {
|
|
1618
|
+
if (cancelled) return;
|
|
1619
|
+
queryClient.invalidateQueries({ queryKey: capxulKeys.activity });
|
|
1620
|
+
}, actor === void 0 ? void 0 : { actor }).then((result) => {
|
|
1621
|
+
if (!result.ok) return;
|
|
1622
|
+
if (cancelled) result.value();
|
|
1623
|
+
else stop = result.value;
|
|
1624
|
+
});
|
|
1625
|
+
return () => {
|
|
1626
|
+
cancelled = true;
|
|
1627
|
+
stop?.();
|
|
1628
|
+
};
|
|
1629
|
+
}, [
|
|
1630
|
+
account,
|
|
1631
|
+
actor,
|
|
1632
|
+
client,
|
|
1633
|
+
enabled,
|
|
1634
|
+
queryClient
|
|
1635
|
+
]);
|
|
1585
1636
|
const pages = query.data?.pages;
|
|
1586
1637
|
const rows = useMemo(() => {
|
|
1587
1638
|
return (pages?.flatMap((page) => page.items) ?? []).map((item) => toActivityRow(item, actor)).filter((row) => matchesSearch(row, searchText));
|
|
@@ -1624,21 +1675,25 @@ function useActivity(input) {
|
|
|
1624
1675
|
observerRef.current = observer;
|
|
1625
1676
|
}, [loadMore]);
|
|
1626
1677
|
const [isExporting, setIsExporting] = useState(false);
|
|
1627
|
-
const toCsv = useCallback(async () => {
|
|
1678
|
+
const toCsv = useCallback(async (options) => {
|
|
1628
1679
|
setIsExporting(true);
|
|
1680
|
+
const controls = toInvocationControls(toInvocationOptions(options));
|
|
1629
1681
|
try {
|
|
1630
1682
|
const bootstrapped = requireBootstrappedClient(client, CAPXUL_OPERATIONS.activity.list);
|
|
1631
1683
|
const items = [];
|
|
1684
|
+
let readWarning;
|
|
1632
1685
|
let cursor;
|
|
1633
1686
|
for (let page = 0; page < EXPORT_PAGE_CEILING; page += 1) {
|
|
1634
|
-
const result = unwrapCapxulResult(await bootstrapped.activity.list(listParams(cursor, EXPORT_PAGE_SIZE)));
|
|
1687
|
+
const result = unwrapCapxulResult(await bootstrapped.activity.list(listParams(cursor, EXPORT_PAGE_SIZE), controls));
|
|
1688
|
+
readWarning ??= result.readWarning;
|
|
1635
1689
|
items.push(...result.items);
|
|
1636
1690
|
cursor = result.cursor ?? void 0;
|
|
1637
1691
|
if (cursor === void 0) break;
|
|
1638
1692
|
}
|
|
1639
1693
|
return {
|
|
1640
1694
|
...buildCsv(items, actor, searchText),
|
|
1641
|
-
truncated: cursor !== void 0
|
|
1695
|
+
truncated: cursor !== void 0,
|
|
1696
|
+
...readWarning === void 0 ? {} : { readWarning }
|
|
1642
1697
|
};
|
|
1643
1698
|
} finally {
|
|
1644
1699
|
setIsExporting(false);
|
|
@@ -1654,9 +1709,19 @@ function useActivity(input) {
|
|
|
1654
1709
|
setDirection(void 0);
|
|
1655
1710
|
setStatus([]);
|
|
1656
1711
|
}, []);
|
|
1657
|
-
const retry = useCallback(() => {
|
|
1712
|
+
const retry = useCallback((options) => {
|
|
1713
|
+
selectedRetry.current = toInvocationOptions(options);
|
|
1658
1714
|
refetch();
|
|
1659
|
-
|
|
1715
|
+
queryClient.invalidateQueries({
|
|
1716
|
+
queryKey: capxulKeys.activitySummary(actor).slice(0, -1),
|
|
1717
|
+
predicate: (cached) => cached.queryKey.at(-1) === accountKey([], identity)[0]
|
|
1718
|
+
});
|
|
1719
|
+
}, [
|
|
1720
|
+
actor,
|
|
1721
|
+
identity,
|
|
1722
|
+
queryClient,
|
|
1723
|
+
refetch
|
|
1724
|
+
]);
|
|
1660
1725
|
return {
|
|
1661
1726
|
actor,
|
|
1662
1727
|
filters: {
|
|
@@ -1682,7 +1747,8 @@ function useActivity(input) {
|
|
|
1682
1747
|
isLoading: query.isLoading,
|
|
1683
1748
|
error: asCapxulError$1(query.error),
|
|
1684
1749
|
retry,
|
|
1685
|
-
observedAt: pages === void 0 ? null : pages[pages.length - 1]?.observedAt ?? null
|
|
1750
|
+
observedAt: pages === void 0 ? null : pages[pages.length - 1]?.observedAt ?? null,
|
|
1751
|
+
...pages?.some((page) => page.readWarning === "indexer-unavailable") ? { readWarning: "indexer-unavailable" } : {}
|
|
1686
1752
|
},
|
|
1687
1753
|
loadMore: {
|
|
1688
1754
|
hasMore: hasNextPage,
|
|
@@ -1744,11 +1810,12 @@ function DetailInstance({ actor, reference, children }) {
|
|
|
1744
1810
|
}
|
|
1745
1811
|
function Detail({ reference, children }) {
|
|
1746
1812
|
const { actor } = useActivityContext();
|
|
1813
|
+
const identity = useCapxulIdentityOrNull();
|
|
1747
1814
|
return /* @__PURE__ */ jsx(DetailInstance, {
|
|
1748
1815
|
actor,
|
|
1749
1816
|
reference,
|
|
1750
1817
|
children
|
|
1751
|
-
}, activityDetailKey(actor, reference));
|
|
1818
|
+
}, JSON.stringify(accountKey([activityDetailKey(actor, reference)], identity)));
|
|
1752
1819
|
}
|
|
1753
1820
|
function Export({ children }) {
|
|
1754
1821
|
return /* @__PURE__ */ jsx(Fragment, { children: children(useActivityContext().csv) });
|
|
@@ -1771,7 +1838,7 @@ function useOrgMeReading(orgId) {
|
|
|
1771
1838
|
const ready = client !== null && identity !== null && isClaimed$1(identity);
|
|
1772
1839
|
const mayStillOpen = client === null || identity === null || isRestoring$1(identity);
|
|
1773
1840
|
const query = useQuery({
|
|
1774
|
-
queryKey: capxulKeys.orgMe(orgId),
|
|
1841
|
+
queryKey: capxulKeys.orgMe(orgId, actingAccount(identity)),
|
|
1775
1842
|
queryFn: async () => {
|
|
1776
1843
|
return unwrapCapxulResult(await requireBootstrappedClient(client, CAPXUL_OPERATIONS.org.me).org(orgId).me());
|
|
1777
1844
|
},
|
|
@@ -2275,6 +2342,16 @@ function decidePhase(input) {
|
|
|
2275
2342
|
if (input.orgLaneSettled && input.destination !== null) return "redirect";
|
|
2276
2343
|
return "checking";
|
|
2277
2344
|
}
|
|
2345
|
+
/**
|
|
2346
|
+
* Which probe produced the surfaced error — the SAME precedence `error` itself
|
|
2347
|
+
* is chosen by, written once so the code and its source can never disagree.
|
|
2348
|
+
*/
|
|
2349
|
+
function probeOf(session, membership, lifecycle) {
|
|
2350
|
+
if (session !== null) return "session";
|
|
2351
|
+
if (membership !== null) return "membership";
|
|
2352
|
+
if (lifecycle !== null) return "lifecycle";
|
|
2353
|
+
return null;
|
|
2354
|
+
}
|
|
2278
2355
|
/** The engine — all the logic. NOT exported from the package barrel. */
|
|
2279
2356
|
function useDashboardAccess(scope) {
|
|
2280
2357
|
const client = useCapxulClientOrNull();
|
|
@@ -2311,6 +2388,7 @@ function useDashboardAccess(scope) {
|
|
|
2311
2388
|
lifecycle.refetch
|
|
2312
2389
|
]);
|
|
2313
2390
|
const error = sessionError ?? membershipError ?? lifecycleError;
|
|
2391
|
+
const probe = probeOf(sessionError, membershipError, lifecycleError);
|
|
2314
2392
|
const phase = decidePhase({
|
|
2315
2393
|
error,
|
|
2316
2394
|
settled: client !== null && identity !== null && !isRestoring$1(identity) && membershipsSettled && lifecycleSettled,
|
|
@@ -2321,11 +2399,13 @@ function useDashboardAccess(scope) {
|
|
|
2321
2399
|
return useMemo(() => ({
|
|
2322
2400
|
phase,
|
|
2323
2401
|
error,
|
|
2402
|
+
probe,
|
|
2324
2403
|
destination,
|
|
2325
2404
|
retry
|
|
2326
2405
|
}), [
|
|
2327
2406
|
phase,
|
|
2328
2407
|
error,
|
|
2408
|
+
probe,
|
|
2329
2409
|
destination,
|
|
2330
2410
|
retry
|
|
2331
2411
|
]);
|
|
@@ -2370,12 +2450,19 @@ function Checking({ children }) {
|
|
|
2370
2450
|
}
|
|
2371
2451
|
function DashboardError({ children }) {
|
|
2372
2452
|
const state = usePart("error");
|
|
2373
|
-
if (state === null || state.error === null) return null;
|
|
2453
|
+
if (state === null || state.error === null || state.probe === null) return null;
|
|
2374
2454
|
return /* @__PURE__ */ jsx(Fragment, { children: children({
|
|
2375
2455
|
error: state.error,
|
|
2456
|
+
probe: state.probe,
|
|
2376
2457
|
retry: state.retry
|
|
2377
2458
|
}) });
|
|
2378
2459
|
}
|
|
2460
|
+
/**
|
|
2461
|
+
* Hands the destination and draws nothing. Reaching this part is a REQUEST to
|
|
2462
|
+
* navigate, never an arrival: the app may cancel or supersede it, so nothing
|
|
2463
|
+
* here — and nothing a consumer hangs off it — may claim a completed redirect
|
|
2464
|
+
* (#1963 R05-1). The destination page's own normalized pageview proves arrival.
|
|
2465
|
+
*/
|
|
2379
2466
|
function Redirect({ children }) {
|
|
2380
2467
|
const state = usePart("redirect");
|
|
2381
2468
|
if (state === null || state.destination === null) return null;
|
|
@@ -2452,8 +2539,9 @@ function toRecipientOption(entry) {
|
|
|
2452
2539
|
*/
|
|
2453
2540
|
function useOrgRoster(orgId) {
|
|
2454
2541
|
const client = useCapxulClientOrNull();
|
|
2542
|
+
const identity = useCapxulIdentityOrNull();
|
|
2455
2543
|
const query = useQuery({
|
|
2456
|
-
queryKey: capxulKeys.contactsList(orgId ?? "pending", false),
|
|
2544
|
+
queryKey: accountKey(capxulKeys.contactsList(orgId ?? "pending", false), identity),
|
|
2457
2545
|
queryFn: async () => unwrapCapxulResult(await scopedClient(client, CAPXUL_OPERATIONS.org.addressBook.list, orgId).addressBook.list({ includeHidden: false })),
|
|
2458
2546
|
enabled: client !== null && orgId !== void 0
|
|
2459
2547
|
});
|
|
@@ -2474,16 +2562,18 @@ function useOrgRoster(orgId) {
|
|
|
2474
2562
|
}
|
|
2475
2563
|
function usePayrollGroups(orgId) {
|
|
2476
2564
|
const client = useCapxulClientOrNull();
|
|
2565
|
+
const identity = useCapxulIdentityOrNull();
|
|
2477
2566
|
return useQuery({
|
|
2478
|
-
queryKey: capxulKeys.payrollGroups(orgId),
|
|
2567
|
+
queryKey: accountKey(capxulKeys.payrollGroups(orgId), identity),
|
|
2479
2568
|
queryFn: async () => unwrapCapxulResult(await scopedClient(client, CAPXUL_OPERATIONS.org.payroll.groups.list, orgId).payroll.groups.list()),
|
|
2480
2569
|
enabled: client !== null && orgId !== void 0
|
|
2481
2570
|
});
|
|
2482
2571
|
}
|
|
2483
2572
|
function usePayrollRuns(orgId) {
|
|
2484
2573
|
const client = useCapxulClientOrNull();
|
|
2574
|
+
const identity = useCapxulIdentityOrNull();
|
|
2485
2575
|
return useQuery({
|
|
2486
|
-
queryKey: capxulKeys.payrollRuns(orgId),
|
|
2576
|
+
queryKey: accountKey(capxulKeys.payrollRuns(orgId), identity),
|
|
2487
2577
|
queryFn: async () => unwrapCapxulResult(await scopedClient(client, CAPXUL_OPERATIONS.org.payroll.runs, orgId).payroll.runs()),
|
|
2488
2578
|
enabled: client !== null && orgId !== void 0
|
|
2489
2579
|
});
|
|
@@ -2498,29 +2588,34 @@ function usePayrollRuns(orgId) {
|
|
|
2498
2588
|
*/
|
|
2499
2589
|
function useOrgTerms(orgId) {
|
|
2500
2590
|
const client = useCapxulClientOrNull();
|
|
2591
|
+
const identity = useCapxulIdentityOrNull();
|
|
2501
2592
|
return useQuery({
|
|
2502
|
-
queryKey: capxulKeys.payrollTerms(orgId),
|
|
2593
|
+
queryKey: accountKey(capxulKeys.payrollTerms(orgId), identity),
|
|
2503
2594
|
queryFn: async () => unwrapCapxulResult(await scopedClient(client, CAPXUL_OPERATIONS.org.payroll.terms, orgId).payroll.terms()),
|
|
2504
2595
|
enabled: client !== null && orgId !== void 0
|
|
2505
2596
|
});
|
|
2506
2597
|
}
|
|
2507
2598
|
function useOrgTreasury(orgId) {
|
|
2508
2599
|
const client = useCapxulClientOrNull();
|
|
2600
|
+
const identity = useCapxulIdentityOrNull();
|
|
2509
2601
|
return useQuery({
|
|
2510
|
-
queryKey: capxulKeys.orgTreasury(orgId),
|
|
2602
|
+
queryKey: accountKey(capxulKeys.orgTreasury(orgId), identity),
|
|
2511
2603
|
queryFn: async () => unwrapCapxulResult(await scopedClient(client, CAPXUL_OPERATIONS.org.treasury, orgId).treasury()),
|
|
2512
2604
|
enabled: client !== null && orgId !== void 0
|
|
2513
2605
|
});
|
|
2514
2606
|
}
|
|
2515
2607
|
/**
|
|
2516
2608
|
* The caller's own standing, read for its Budgets alone (ruling Q2 grades
|
|
2517
|
-
* them). Keyed as `CapxulOrgMember` keys it
|
|
2518
|
-
* `.Can` wrapper reads
|
|
2609
|
+
* them). Keyed as `CapxulOrgMember` keys it — Organization AND acting account
|
|
2610
|
+
* (#2007 R19) — so a payroll screen inside a `.Can` wrapper still reads
|
|
2611
|
+
* `org(id).me()` once, and an account replacement is a miss for both of them
|
|
2612
|
+
* rather than the previous person's Budgets for both.
|
|
2519
2613
|
*/
|
|
2520
2614
|
function useOrgMe(orgId) {
|
|
2521
2615
|
const client = useCapxulClientOrNull();
|
|
2616
|
+
const identity = useCapxulIdentityOrNull();
|
|
2522
2617
|
return useQuery({
|
|
2523
|
-
queryKey: capxulKeys.orgMe(orgId),
|
|
2618
|
+
queryKey: capxulKeys.orgMe(orgId, actingAccount(identity)),
|
|
2524
2619
|
queryFn: async () => unwrapCapxulResult(await scopedClient(client, CAPXUL_OPERATIONS.org.me, orgId).me()),
|
|
2525
2620
|
enabled: client !== null && orgId !== void 0
|
|
2526
2621
|
});
|
|
@@ -2539,6 +2634,14 @@ function scopedClient(client, method, orgId) {
|
|
|
2539
2634
|
//#region src/headless/payroll/use-payroll.ts
|
|
2540
2635
|
/** Money reads the same way everywhere on this screen: amount then code. */
|
|
2541
2636
|
const GRAMMAR$1 = { grammar: "code" };
|
|
2637
|
+
/**
|
|
2638
|
+
* One captured snapshot, or nothing — never a fabricated empty options object,
|
|
2639
|
+
* and never a DOM event a screen wired straight to `onClick`.
|
|
2640
|
+
*/
|
|
2641
|
+
function carry(options) {
|
|
2642
|
+
const attempt = toInvocationOptions(options);
|
|
2643
|
+
return attempt === void 0 ? {} : { options: attempt };
|
|
2644
|
+
}
|
|
2542
2645
|
function toPayrollGroupRow(group) {
|
|
2543
2646
|
const currency = new Set(group.members.map((member) => member.currency)).size === 1 ? group.members[0]?.currency : void 0;
|
|
2544
2647
|
return {
|
|
@@ -2578,16 +2681,17 @@ function usePayroll(orgId) {
|
|
|
2578
2681
|
const write = useMutation({
|
|
2579
2682
|
mutationFn: async (command) => {
|
|
2580
2683
|
const payroll = scopedClient(client, CAPXUL_OPERATIONS.org.payroll.groups[command.kind], orgId).payroll;
|
|
2684
|
+
const controls = toInvocationControls(command.options);
|
|
2581
2685
|
if (command.kind === "remove") {
|
|
2582
|
-
unwrapCapxulResult(await payroll.groups.remove(command.id));
|
|
2686
|
+
unwrapCapxulResult(await payroll.groups.remove(command.id, controls));
|
|
2583
2687
|
return null;
|
|
2584
2688
|
}
|
|
2585
|
-
return unwrapCapxulResult(await payroll.groups.save(command.input));
|
|
2689
|
+
return unwrapCapxulResult(await payroll.groups.save(command.input, controls));
|
|
2586
2690
|
},
|
|
2587
2691
|
onSettled: invalidate
|
|
2588
2692
|
});
|
|
2589
2693
|
const mutateAsync = write.mutateAsync;
|
|
2590
|
-
const save = useCallback(async (input) => {
|
|
2694
|
+
const save = useCallback(async (input, options) => {
|
|
2591
2695
|
const refusal = invalidGroup(input);
|
|
2592
2696
|
if (refusal !== null) return {
|
|
2593
2697
|
ok: false,
|
|
@@ -2596,7 +2700,8 @@ function usePayroll(orgId) {
|
|
|
2596
2700
|
try {
|
|
2597
2701
|
const saved = await mutateAsync({
|
|
2598
2702
|
kind: "save",
|
|
2599
|
-
input
|
|
2703
|
+
input,
|
|
2704
|
+
...carry(options)
|
|
2600
2705
|
});
|
|
2601
2706
|
return saved === null ? {
|
|
2602
2707
|
ok: false,
|
|
@@ -2612,11 +2717,12 @@ function usePayroll(orgId) {
|
|
|
2612
2717
|
};
|
|
2613
2718
|
}
|
|
2614
2719
|
}, [mutateAsync]);
|
|
2615
|
-
const remove = useCallback(async (id) => {
|
|
2720
|
+
const remove = useCallback(async (id, options) => {
|
|
2616
2721
|
try {
|
|
2617
2722
|
await mutateAsync({
|
|
2618
2723
|
kind: "remove",
|
|
2619
|
-
id
|
|
2724
|
+
id,
|
|
2725
|
+
...carry(options)
|
|
2620
2726
|
});
|
|
2621
2727
|
return {
|
|
2622
2728
|
ok: true,
|
|
@@ -3134,11 +3240,12 @@ function usePayrollRun(input) {
|
|
|
3134
3240
|
amountsParse: total !== null
|
|
3135
3241
|
});
|
|
3136
3242
|
const authorize = useMutation({
|
|
3137
|
-
mutationFn: async (candidate) => {
|
|
3243
|
+
mutationFn: async ({ candidate, options }) => {
|
|
3138
3244
|
if (candidate.scope !== currentScope.current) throw Errors.notAuthenticated();
|
|
3139
3245
|
return executeRunDraft(candidate, async (persisted, onRequestKey, onResolved) => {
|
|
3140
3246
|
if (candidate.scope === currentScope.current) setDraft(persisted);
|
|
3141
3247
|
return unwrapCapxulResult(await scopedClient(client, CAPXUL_OPERATIONS.org.payroll.authorizeRun, orgId).payroll.authorizeRun(persisted.input, {
|
|
3248
|
+
...toInvocationControls(options),
|
|
3142
3249
|
onResolved,
|
|
3143
3250
|
onRequestKey: (key) => {
|
|
3144
3251
|
if (candidate.scope !== currentScope.current) throw Errors.notAuthenticated();
|
|
@@ -3147,14 +3254,15 @@ function usePayrollRun(input) {
|
|
|
3147
3254
|
}));
|
|
3148
3255
|
});
|
|
3149
3256
|
},
|
|
3150
|
-
onSettled: (_run, _error, candidate) => {
|
|
3257
|
+
onSettled: (_run, _error, { candidate }) => {
|
|
3151
3258
|
queryClient.invalidateQueries({ queryKey: capxulKeys.payrollRuns(orgId) });
|
|
3152
3259
|
if (candidate.scope === currentScope.current) restoreDraft(candidate.scope);
|
|
3153
3260
|
}
|
|
3154
3261
|
});
|
|
3155
3262
|
const totalDisplay = total === null ? null : formatMoney(total, GRAMMAR);
|
|
3156
3263
|
const authorizeMutate = authorize.mutate;
|
|
3157
|
-
const submit = useCallback(() => {
|
|
3264
|
+
const submit = useCallback((options) => {
|
|
3265
|
+
const attempt = toInvocationOptions(options);
|
|
3158
3266
|
const permissionId = budgets[0]?.id;
|
|
3159
3267
|
if (blockedReason !== null || submitGate.current || draftBlocked || draftScope === null || assetMoney === null || selectedAsset === null) return;
|
|
3160
3268
|
if (permissionId === void 0 || totalDisplay === null || parsedAmounts === null) return;
|
|
@@ -3196,7 +3304,10 @@ function usePayrollRun(input) {
|
|
|
3196
3304
|
}
|
|
3197
3305
|
};
|
|
3198
3306
|
submitGate.current = true;
|
|
3199
|
-
authorizeMutate(
|
|
3307
|
+
authorizeMutate({
|
|
3308
|
+
candidate,
|
|
3309
|
+
...attempt === void 0 ? {} : { options: attempt }
|
|
3310
|
+
}, {
|
|
3200
3311
|
onSuccess: (run) => {
|
|
3201
3312
|
if (candidate.scope === currentScope.current) onRun({
|
|
3202
3313
|
id: run.id,
|
package/dist/testing/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as CapxulOnboardingController, r as CapxulProvider, t as CapxulAuthenticationController } from "../controllers-
|
|
1
|
+
import { n as CapxulOnboardingController, r as CapxulProvider, t as CapxulAuthenticationController } from "../controllers-DXmEHrnw.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": "4.
|
|
3
|
+
"version": "4.20.0-beta.1",
|
|
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": "4.
|
|
29
|
+
"@capxul/sdk": "4.20.0-beta.1"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@tanstack/react-query": "^5.66.9",
|