@capxul/sdk 4.2.0-rc.7 → 4.2.0-rc.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/dist/{OAuthBearerAuthClient-hPwtSpEf.mjs → OAuthBearerAuthClient-IB2W1Fzj.mjs} +104 -5
- package/dist/capxul-source.json +3 -3
- package/dist/index.d.mts +13 -1
- package/dist/index.mjs +2 -2
- package/dist/node/index.mjs +1 -1
- package/dist/{production-D-wB2nFa.mjs → production-216hsAKc.mjs} +510 -13
- package/dist/{production-B8BQj9l0.d.mts → production-Du4Vc7YD.d.mts} +130 -2
- package/dist/testing/index.d.mts +77 -2
- package/dist/testing/index.mjs +94 -3
- package/package.json +5 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as PayrollGroupId, A as AllowanceKey, B as ChainId, C as AuthCachePort, D as Account$1, Et as FailureMode, H as CurrencyCode, I as AuthSession, K as Email, L as AuthUserId, M as AnonymousDistinctId, N as AppId, Q as PaymentCommandId, R as BlockNumber, U as DocumentHash, V as CountryCode, W as DurationMs, X as OrgId, Y as Money, Z as PartyId, _ as Session$1, _t as CapxulErrorCode, at as RoleKey, b as AuthClientPort, bt as Failure, ct as TesterKind, d as AccountRequirement, et as PayrollRunId, g as Profile$1, gt as CapxulError, h as CapxulResult, i as CapxulSigner, it as PublishableKey, j as AllowedOrigin, k as Address$1, lt as TxHash, nt as PermissionId, ot as SessionToken, q as EpochMs, rt as Profile, s as SignerStatusStore, st as SmartAccount, tt as PermissionAssignmentId, u as AccountProviderSource, ut as WeiAmount, v as SmartAccount$1, vt as CapxulErrorDetails, x as CanSendOtpStatus, y as ClockPort, z as BudgetId } from "./OAuthBearerAuthClient-C-ip-z8M.mjs";
|
|
1
|
+
import { $ as PayrollGroupId, A as AllowanceKey, B as ChainId, C as AuthCachePort, D as Account$1, Et as FailureMode, F as AssetId, H as CurrencyCode, I as AuthSession, K as Email, L as AuthUserId, M as AnonymousDistinctId, N as AppId, Q as PaymentCommandId, R as BlockNumber, U as DocumentHash, V as CountryCode, W as DurationMs, X as OrgId, Y as Money, Z as PartyId, _ as Session$1, _t as CapxulErrorCode, at as RoleKey, b as AuthClientPort, bt as Failure, ct as TesterKind, d as AccountRequirement, et as PayrollRunId, g as Profile$1, gt as CapxulError, h as CapxulResult, i as CapxulSigner, it as PublishableKey, j as AllowedOrigin, k as Address$1, lt as TxHash, nt as PermissionId, ot as SessionToken, q as EpochMs, rt as Profile, s as SignerStatusStore, st as SmartAccount, tt as PermissionAssignmentId, u as AccountProviderSource, ut as WeiAmount, v as SmartAccount$1, vt as CapxulErrorDetails, x as CanSendOtpStatus, y as ClockPort, z as BudgetId } from "./OAuthBearerAuthClient-C-ip-z8M.mjs";
|
|
2
2
|
import { Hex } from "viem";
|
|
3
3
|
import { Context, Effect, Layer, Schema, Scope, Tracer } from "effect";
|
|
4
4
|
import { FunctionReference } from "convex/server";
|
|
@@ -284,7 +284,7 @@ interface TelemetryPort {
|
|
|
284
284
|
}
|
|
285
285
|
//#endregion
|
|
286
286
|
//#region ../observability/src/index.d.ts
|
|
287
|
-
declare const TELEMETRY_EVENT_NAMES: readonly ["auth_otp_requested", "auth_otp_delivered", "auth_otp_expired", "auth_verified", "auth_failed", "auth_signed_out", "onboarding_intent_selected", "onboarding_profile_submitted", "onboarding_organization_submitted", "onboarding_dashboard_reached", "provisioning_safe_created", "provisioning_safe_confirmed", "bootstrap_resolved", "bootstrap_failed", "member_activation_started", "member_activation_ready", "member_activation_failed", "organization_creation_started", "organization_creation_ready", "organization_creation_failed", "chain_upstream_fallback", "bundler_error", "receipt_pending", "operation_retried", "account_balance_read", "account_balance_failed", "faucet_requested", "faucet_confirmed", "faucet_failed", "org_create_started", "org_safe_created", "org_safe_confirmed", "org_roles_seeded", "org_created", "org_create_failed", "org_invite_sent", "org_invite_accepted", "org_invite_expired", "payment_initiated", "payment_settled", "payment_failed", "payment_verification_retry", "payment_lifecycle_transition", "quick_pay_external_address_acknowledged", "deposit_initiated", "deposit_settled", "permission_mirror_verification", "movement_scan_window", "movement_scan_checkpoint", "movement_scan_incident", "activity_annotation_saved", "ui_activity_action_completed", "contact_relationship_changed", "ui_contact_action_completed", "access_recovery_completed", "ui_access_step_completed", "org_invite_progressed", "invoice_issued", "invoice_request_transitioned", "ui_invoice_step_completed", "ui_treasury_step_completed", "ui_receive_step_completed", "payroll_group_changed", "payroll_run_transitioned", "ui_payroll_action_completed"];
|
|
287
|
+
declare const TELEMETRY_EVENT_NAMES: readonly ["auth_otp_requested", "auth_otp_delivered", "auth_otp_expired", "auth_verified", "auth_failed", "identity_refused", "auth_signed_out", "onboarding_intent_selected", "onboarding_profile_submitted", "onboarding_organization_submitted", "onboarding_dashboard_reached", "provisioning_safe_created", "provisioning_safe_confirmed", "bootstrap_resolved", "bootstrap_failed", "member_activation_started", "member_activation_ready", "member_activation_failed", "organization_creation_started", "organization_creation_ready", "organization_creation_failed", "chain_upstream_fallback", "bundler_error", "receipt_pending", "operation_retried", "account_balance_read", "account_balance_failed", "faucet_requested", "faucet_confirmed", "faucet_failed", "org_create_started", "org_safe_created", "org_safe_confirmed", "org_roles_seeded", "org_created", "org_create_failed", "org_invite_sent", "org_invite_accepted", "org_invite_expired", "payment_initiated", "payment_settled", "payment_failed", "payment_verification_retry", "payment_lifecycle_transition", "quick_pay_external_address_acknowledged", "deposit_initiated", "deposit_settled", "permission_mirror_verification", "movement_scan_window", "movement_scan_checkpoint", "movement_scan_incident", "activity_annotation_saved", "ui_activity_action_completed", "contact_relationship_changed", "ui_contact_action_completed", "access_recovery_completed", "ui_access_step_completed", "org_invite_progressed", "invoice_issued", "invoice_request_transitioned", "ui_invoice_step_completed", "ui_treasury_step_completed", "ui_receive_step_completed", "payroll_group_changed", "payroll_run_transitioned", "ui_payroll_action_completed"];
|
|
288
288
|
type TelemetryEventName = (typeof TELEMETRY_EVENT_NAMES)[number];
|
|
289
289
|
type TelemetryProps = Record<string, unknown>;
|
|
290
290
|
type TelemetryEvent = {
|
|
@@ -611,6 +611,10 @@ type BootstrapResolution = {
|
|
|
611
611
|
readonly siteBaseUrl: string;
|
|
612
612
|
readonly openfortPublishableKey: string;
|
|
613
613
|
readonly shieldPublishableKey: string;
|
|
614
|
+
/** Openfort third-party auth provider the signer presents; absent means better-auth. */
|
|
615
|
+
readonly openfortAuthProvider?: "better-auth" | "oidc";
|
|
616
|
+
/** Origin of the Ponder indexer the SDK reads directly; absent means no indexer reads. */
|
|
617
|
+
readonly indexerUrl?: string;
|
|
614
618
|
readonly engineeringTelemetry?: EngineeringTelemetryBootstrapPolicyV1;
|
|
615
619
|
};
|
|
616
620
|
type BootstrapErrorKind = "notAuthenticated" | "network" | "provider" | "malformedBody" | "invalidInput" | "rateLimited";
|
|
@@ -904,6 +908,118 @@ interface AccountReadPort {
|
|
|
904
908
|
fundFromFaucet(input: FundFromFaucetInput): Effect.Effect<FundFromFaucetResult, AccountReadError, never>;
|
|
905
909
|
}
|
|
906
910
|
//#endregion
|
|
911
|
+
//#region src/ports/indexer-read.d.ts
|
|
912
|
+
/**
|
|
913
|
+
* IndexerReadPort is the SDK's read seam onto the Ponder read model
|
|
914
|
+
* (`apps/indexer`). Ponder holds what the chain said; Convex holds what the
|
|
915
|
+
* user meant. Nothing here is copied into Convex, nothing waits for a
|
|
916
|
+
* finality tag, and no write path may read through this port.
|
|
917
|
+
*
|
|
918
|
+
* Every read is scoped to one Safe and one page. The indexer accepts only the
|
|
919
|
+
* exact compiled statements in `apps/indexer/src/queries.ts`, so the adapter
|
|
920
|
+
* that implements this port reproduces those statements byte for byte and the
|
|
921
|
+
* service refuses anything else with 403.
|
|
922
|
+
*/
|
|
923
|
+
/** One page of rows for one Safe. `offset` defaults to 0 (the first page). */
|
|
924
|
+
interface IndexerReadInput {
|
|
925
|
+
/** The Safe the caller owns. The indexer refuses a Safe outside the session claim. */
|
|
926
|
+
readonly safe: Address$1;
|
|
927
|
+
/** 1 to 1000 inclusive — the indexer's own bound. */
|
|
928
|
+
readonly limit: number;
|
|
929
|
+
readonly offset?: number;
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* The chain evidence every indexed row carries. `id` is the logical event id
|
|
933
|
+
* `chainId:txHash:transactionLogOrdinal`; it survives a reorg, so it is the
|
|
934
|
+
* key a Convex intent row stitches against.
|
|
935
|
+
*/
|
|
936
|
+
interface IndexerEventIdentity {
|
|
937
|
+
readonly id: string;
|
|
938
|
+
readonly chainId: ChainId;
|
|
939
|
+
readonly txHash: TxHash;
|
|
940
|
+
readonly transactionLogOrdinal: number;
|
|
941
|
+
readonly blockNumber: bigint;
|
|
942
|
+
readonly blockHash: string;
|
|
943
|
+
/** Block timestamp in epoch seconds. */
|
|
944
|
+
readonly timestamp: bigint;
|
|
945
|
+
}
|
|
946
|
+
interface IndexerTransferRow extends IndexerEventIdentity {
|
|
947
|
+
readonly assetId: AssetId;
|
|
948
|
+
readonly token: Address$1;
|
|
949
|
+
readonly from: Address$1;
|
|
950
|
+
readonly to: Address$1;
|
|
951
|
+
/**
|
|
952
|
+
* Raw token units, exact. This is an evidence boundary, so the row never
|
|
953
|
+
* carries Money or AssetAmount: the reader owns the asset's decimals.
|
|
954
|
+
*/
|
|
955
|
+
readonly amount: bigint;
|
|
956
|
+
}
|
|
957
|
+
interface IndexerPaymentRow extends IndexerEventIdentity {
|
|
958
|
+
readonly contract: Address$1;
|
|
959
|
+
/** The protocol settlement id a Convex Payment command stitches against. */
|
|
960
|
+
readonly settlementId: string;
|
|
961
|
+
readonly sender: Address$1;
|
|
962
|
+
readonly recipient: Address$1;
|
|
963
|
+
readonly assetId: AssetId;
|
|
964
|
+
readonly token: Address$1;
|
|
965
|
+
/** Raw token units, exact. */
|
|
966
|
+
readonly amount: bigint;
|
|
967
|
+
readonly kind: number;
|
|
968
|
+
readonly documentHash: string;
|
|
969
|
+
}
|
|
970
|
+
/** A row of the indexer's signed-transfer `balance` view. */
|
|
971
|
+
interface IndexerBalanceRow {
|
|
972
|
+
readonly chainId: ChainId;
|
|
973
|
+
readonly assetId: AssetId;
|
|
974
|
+
readonly address: Address$1;
|
|
975
|
+
/** Raw token units, exact. */
|
|
976
|
+
readonly amount: bigint;
|
|
977
|
+
}
|
|
978
|
+
/** One chain's sync position, from the indexer's native `/status` route. */
|
|
979
|
+
interface IndexerChainStatus {
|
|
980
|
+
readonly chain: string;
|
|
981
|
+
readonly chainId: ChainId;
|
|
982
|
+
readonly blockNumber: bigint;
|
|
983
|
+
/** Block timestamp in epoch seconds. Its age is the freshness label. */
|
|
984
|
+
readonly blockTimestamp: bigint;
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* The tables this seam reads today. P04 adds the authority rows (`safe`,
|
|
988
|
+
* `safe_event`, `roles_module`) and P05 adds `commitment`: each is one more
|
|
989
|
+
* entry here plus its statement and decoder.
|
|
990
|
+
*/
|
|
991
|
+
interface IndexerRowsByTable {
|
|
992
|
+
readonly transfer: readonly IndexerTransferRow[];
|
|
993
|
+
readonly payment: readonly IndexerPaymentRow[];
|
|
994
|
+
readonly balance: readonly IndexerBalanceRow[];
|
|
995
|
+
}
|
|
996
|
+
type IndexerTable = keyof IndexerRowsByTable;
|
|
997
|
+
declare const IndexerReadError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
998
|
+
readonly _tag: "IndexerReadError";
|
|
999
|
+
} & Readonly<A>;
|
|
1000
|
+
declare class IndexerReadError extends IndexerReadError_base<{
|
|
1001
|
+
readonly operation: string;
|
|
1002
|
+
readonly publicCode: CapxulErrorCode;
|
|
1003
|
+
readonly publicError: CapxulError;
|
|
1004
|
+
readonly cause: unknown;
|
|
1005
|
+
readonly details?: CapxulErrorDetails;
|
|
1006
|
+
}> {}
|
|
1007
|
+
interface IndexerReadPort {
|
|
1008
|
+
/** One page of rows, newest block first. An empty page is a value, not an error. */
|
|
1009
|
+
read<T extends IndexerTable>(table: T, input: IndexerReadInput): Effect.Effect<IndexerRowsByTable[T], IndexerReadError>;
|
|
1010
|
+
/**
|
|
1011
|
+
* The same page over the indexer's live stream. The first snapshot is
|
|
1012
|
+
* `loading`; each later snapshot carries the whole page again. The indexer
|
|
1013
|
+
* closes the stream on token expiry or revoked authority, which arrives as
|
|
1014
|
+
* one `error` snapshot — the caller re-reads with a refreshed token.
|
|
1015
|
+
*
|
|
1016
|
+
* @internal-use — substrate reactive transport, like `ConvexCallPort.subscribe`.
|
|
1017
|
+
*/
|
|
1018
|
+
subscribe<T extends IndexerTable>(table: T, input: IndexerReadInput, callback: (snapshot: Snapshot<IndexerRowsByTable[T]>) => void): Effect.Effect<Unsubscribe, IndexerReadError>;
|
|
1019
|
+
/** Sync position per chain. Unauthenticated: a stale index is not a refusal. */
|
|
1020
|
+
readonly status: Effect.Effect<readonly IndexerChainStatus[], IndexerReadError>;
|
|
1021
|
+
}
|
|
1022
|
+
//#endregion
|
|
907
1023
|
//#region src/flows/types.d.ts
|
|
908
1024
|
/** The runtime port bundle that `assembleCapxulClient` uses. */
|
|
909
1025
|
interface FlowPorts {
|
|
@@ -916,6 +1032,11 @@ interface FlowPorts {
|
|
|
916
1032
|
readonly clock: ClockPort;
|
|
917
1033
|
readonly telemetry: TelemetryPort;
|
|
918
1034
|
readonly convexCall: ConvexCallPort;
|
|
1035
|
+
/**
|
|
1036
|
+
* The Ponder read seam (P02). Optional: it is present only when the client
|
|
1037
|
+
* was given an indexer origin, and every existing flow works without it.
|
|
1038
|
+
*/
|
|
1039
|
+
readonly indexerRead?: IndexerReadPort;
|
|
919
1040
|
}
|
|
920
1041
|
/** Legacy method input retained by the imperative auth surface. */
|
|
921
1042
|
interface ExternalSigner {
|
|
@@ -2669,6 +2790,13 @@ interface CapxulClient {
|
|
|
2669
2790
|
* NOT on the public `client.accounts` surface.
|
|
2670
2791
|
*/
|
|
2671
2792
|
readonly accounts: AccountsFaucetMethods;
|
|
2793
|
+
/**
|
|
2794
|
+
* Ponder read seam (P02). Present only when the client was built with an
|
|
2795
|
+
* indexer origin, so every reader treats it as optional. Ponder holds what
|
|
2796
|
+
* the chain said; Convex holds what the user meant. Reads here never run
|
|
2797
|
+
* inside a write path and never wait for a finality tag.
|
|
2798
|
+
*/
|
|
2799
|
+
readonly indexer?: IndexerReadPort;
|
|
2672
2800
|
/** Quarantined Reference-harness evidence; never a product Organization method. */
|
|
2673
2801
|
readonly organizationSetup: OrganizationSetupProofMethods;
|
|
2674
2802
|
/** Product telemetry projection for internal composition and test harnesses. */
|
package/dist/testing/index.d.mts
CHANGED
|
@@ -1,10 +1,85 @@
|
|
|
1
1
|
import { h as CapxulResult } from "../OAuthBearerAuthClient-C-ip-z8M.mjs";
|
|
2
|
-
import { er as TelemetryEvent, f as CapxulClient, i as ObservationAdapter, n as ProductionSignerControls, nr as TelemetryIdentifyInput, pr as IdentityTransition, t as CapxulClientInput, tr as TelemetryGroupInput } from "../production-
|
|
2
|
+
import { er as TelemetryEvent, f as CapxulClient, i as ObservationAdapter, n as ProductionSignerControls, nr as TelemetryIdentifyInput, pr as IdentityTransition, t as CapxulClientInput, tr as TelemetryGroupInput } from "../production-Du4Vc7YD.mjs";
|
|
3
3
|
import { Effect, Layer } from "effect";
|
|
4
4
|
//#region src/testing/production-client.d.ts
|
|
5
5
|
/** Create the one production client with per-client controls at its signing boundaries. */
|
|
6
6
|
declare function createCapxulProductionTestClient(input: CapxulClientInput, controls: ProductionSignerControls): Promise<CapxulResult<CapxulClient>>;
|
|
7
7
|
//#endregion
|
|
8
|
+
//#region src/testing/signer-faults.d.ts
|
|
9
|
+
/**
|
|
10
|
+
* Which provider refusal to inject. The codes are the ones the SDK's own
|
|
11
|
+
* classifiers decode (`src/signer.ts`), so a fault reaches the public error
|
|
12
|
+
* contract through the real decode path rather than a shortcut.
|
|
13
|
+
*
|
|
14
|
+
* - `missing-signer` — Openfort's typed not-ready code. `openfortSignerNotReadyCode`
|
|
15
|
+
* decodes it, so the production recovery wrapper runs its single retry (A02).
|
|
16
|
+
* - `user-rejected` — the EIP-1193 4001 result. `signerFailure` decodes it to
|
|
17
|
+
* `SIGNER_REJECTED`, an expected refusal (A08).
|
|
18
|
+
* - `unexpected` — no provider code at all, so it stays an unexpected
|
|
19
|
+
* `PROVIDER_ERROR` (A09).
|
|
20
|
+
*/
|
|
21
|
+
type SignerFaultKind = "missing-signer" | "user-rejected" | "unexpected";
|
|
22
|
+
/** The value a controlled fault throws. Named so a test can assert its origin. */
|
|
23
|
+
declare class ControlledSignerFault extends Error {
|
|
24
|
+
readonly kind: SignerFaultKind;
|
|
25
|
+
/** Provider code the SDK classifiers read; absent for `unexpected`. */
|
|
26
|
+
readonly code: string | number | undefined;
|
|
27
|
+
constructor(kind: SignerFaultKind);
|
|
28
|
+
}
|
|
29
|
+
/** Build one fault value without the harness, for a caller that writes its own control. */
|
|
30
|
+
declare function signerFaultCause(kind: SignerFaultKind): ControlledSignerFault;
|
|
31
|
+
interface SignerFaultPlan {
|
|
32
|
+
/**
|
|
33
|
+
* Fault the next embedded signature ONCE, beneath the production recovery
|
|
34
|
+
* wrapper, then delegate every later call to the real signer. The address
|
|
35
|
+
* read and the readiness cycle still run first, so the fault lands at the
|
|
36
|
+
* actual final signing boundary after the prepared-command equality checks.
|
|
37
|
+
*/
|
|
38
|
+
readonly signOnce?: SignerFaultKind;
|
|
39
|
+
/**
|
|
40
|
+
* Call the production signer's own `resetSession()` ONCE, immediately before
|
|
41
|
+
* the next signature and after the command is prepared. The delegate then
|
|
42
|
+
* re-runs the real readiness cycle, so the configure request under test is
|
|
43
|
+
* the first one the browser observes after the `reset-session` record (A03).
|
|
44
|
+
*
|
|
45
|
+
* Throws when the composed signer owns no session — a silently skipped reset
|
|
46
|
+
* would leave the run looking green while proving nothing.
|
|
47
|
+
*/
|
|
48
|
+
readonly resetSessionBeforeNextSign?: boolean;
|
|
49
|
+
}
|
|
50
|
+
/** What the seam did. JSON-serializable, so a browser test can read it back. */
|
|
51
|
+
interface SignerSeamRecord {
|
|
52
|
+
readonly boundary: "reset-session" | "embedded-sign";
|
|
53
|
+
/** 1-based count of calls at that boundary. */
|
|
54
|
+
readonly attempt: number;
|
|
55
|
+
readonly hash?: string;
|
|
56
|
+
/** Present only on the call that actually threw. */
|
|
57
|
+
readonly fault?: SignerFaultKind;
|
|
58
|
+
readonly atMs: number;
|
|
59
|
+
}
|
|
60
|
+
interface ArmedSignerSeam {
|
|
61
|
+
/** Hand these to `createCapxulProductionTestClient`. */
|
|
62
|
+
readonly controls: ProductionSignerControls;
|
|
63
|
+
/** Oldest first. Empty until the client reaches a signing boundary. */
|
|
64
|
+
readonly records: () => readonly SignerSeamRecord[];
|
|
65
|
+
/** True once every armed one-shot has fired. */
|
|
66
|
+
readonly spent: () => boolean;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Arm one-shot faults on the production embedded signer.
|
|
70
|
+
*
|
|
71
|
+
* ```ts
|
|
72
|
+
* const seam = armSignerFaults({ signOnce: "user-rejected" });
|
|
73
|
+
* const client = await createCapxulProductionTestClient(input, seam.controls);
|
|
74
|
+
* const result = await client.org(orgId).permissions.create(command);
|
|
75
|
+
* // result.error.code === "SIGNER_REJECTED"; nothing was submitted.
|
|
76
|
+
* // seam.records() names the boundary that refused.
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* An empty plan installs no controls, which composes the ordinary client.
|
|
80
|
+
*/
|
|
81
|
+
declare function armSignerFaults(plan?: SignerFaultPlan): ArmedSignerSeam;
|
|
82
|
+
//#endregion
|
|
8
83
|
//#region src/testing/telemetry/RecordingTelemetryAdapter.d.ts
|
|
9
84
|
type RecordingTelemetryOperation = {
|
|
10
85
|
readonly type: "emit";
|
|
@@ -56,4 +131,4 @@ interface CapxulTestObservation {
|
|
|
56
131
|
*/
|
|
57
132
|
declare function createCapxulTestClient(options?: CreateCapxulTestClientOptions): CapxulTestClient;
|
|
58
133
|
//#endregion
|
|
59
|
-
export { CapxulTestClient, CapxulTestClock, CapxulTestObservation, CreateCapxulTestClientOptions, type ProductionSignerControls, SeedTestIdentityInput, createCapxulProductionTestClient, createCapxulTestClient };
|
|
134
|
+
export { type ArmedSignerSeam, CapxulTestClient, CapxulTestClock, CapxulTestObservation, ControlledSignerFault, CreateCapxulTestClientOptions, type ProductionSignerControls, SeedTestIdentityInput, type SignerFaultKind, type SignerFaultPlan, type SignerSeamRecord, armSignerFaults, createCapxulProductionTestClient, createCapxulTestClient, signerFaultCause };
|
package/dist/testing/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { D as fromWei, P as redactTelemetryEvent, a as smartAccountErrorFromCapxul, c as identityErrorFromCapxul, i as assembleCapxulClient, l as convexCallErrorFromCapxul, n as createCapxulClientWithSignerControls, o as accountReadErrorFromCapxul, s as wireChainId, u as bootstrapErrorFromCapxul, v as toWei } from "../production-
|
|
2
|
-
import {
|
|
1
|
+
import { D as fromWei, P as redactTelemetryEvent, a as smartAccountErrorFromCapxul, c as identityErrorFromCapxul, i as assembleCapxulClient, l as convexCallErrorFromCapxul, n as createCapxulClientWithSignerControls, o as accountReadErrorFromCapxul, s as wireChainId, u as bootstrapErrorFromCapxul, v as toWei } from "../production-216hsAKc.mjs";
|
|
2
|
+
import { G as toHandle, H as toEmail, I as toAuthUserId, K as toJwtToken, M as toAddress, N as toAllowedOrigin, P as toAppId, Q as toPublishableKey, R as toChainId, U as toEpochMs, V as toDurationMs, W as toEpochSeconds, d as authClientPortFromPromiseAdapter, et as toSessionToken, j as toAccountId, lt as Errors, n as readClockNow, q as toKycTier, r as InMemoryAuthCacheAdapter, rt as validateHandle, st as CapxulError, y as deriveCapxulSafeAddress, z as toCountryCode } from "../OAuthBearerAuthClient-IB2W1Fzj.mjs";
|
|
3
3
|
import { keccak256 } from "viem";
|
|
4
4
|
import { Effect, Result, Semaphore } from "effect";
|
|
5
5
|
import { getFunctionName } from "convex/server";
|
|
@@ -9,6 +9,97 @@ function createCapxulProductionTestClient(input, controls) {
|
|
|
9
9
|
return createCapxulClientWithSignerControls(input, controls);
|
|
10
10
|
}
|
|
11
11
|
//#endregion
|
|
12
|
+
//#region src/testing/signer-faults.ts
|
|
13
|
+
const FAULT_CODES = {
|
|
14
|
+
"missing-signer": "MISSING_SIGNER",
|
|
15
|
+
"user-rejected": 4001,
|
|
16
|
+
unexpected: void 0
|
|
17
|
+
};
|
|
18
|
+
/** The value a controlled fault throws. Named so a test can assert its origin. */
|
|
19
|
+
var ControlledSignerFault = class extends Error {
|
|
20
|
+
kind;
|
|
21
|
+
/** Provider code the SDK classifiers read; absent for `unexpected`. */
|
|
22
|
+
code;
|
|
23
|
+
constructor(kind) {
|
|
24
|
+
super(`controlled signer fault (${kind})`);
|
|
25
|
+
this.name = "ControlledSignerFault";
|
|
26
|
+
this.kind = kind;
|
|
27
|
+
this.code = FAULT_CODES[kind];
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
/** Build one fault value without the harness, for a caller that writes its own control. */
|
|
31
|
+
function signerFaultCause(kind) {
|
|
32
|
+
return new ControlledSignerFault(kind);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Arm one-shot faults on the production embedded signer.
|
|
36
|
+
*
|
|
37
|
+
* ```ts
|
|
38
|
+
* const seam = armSignerFaults({ signOnce: "user-rejected" });
|
|
39
|
+
* const client = await createCapxulProductionTestClient(input, seam.controls);
|
|
40
|
+
* const result = await client.org(orgId).permissions.create(command);
|
|
41
|
+
* // result.error.code === "SIGNER_REJECTED"; nothing was submitted.
|
|
42
|
+
* // seam.records() names the boundary that refused.
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* An empty plan installs no controls, which composes the ordinary client.
|
|
46
|
+
*/
|
|
47
|
+
function armSignerFaults(plan = {}) {
|
|
48
|
+
const records = [];
|
|
49
|
+
let pendingFault = plan.signOnce;
|
|
50
|
+
let pendingReset = plan.resetSessionBeforeNextSign === true;
|
|
51
|
+
let resetCalls = 0;
|
|
52
|
+
let embeddedCalls = 0;
|
|
53
|
+
function record(entry) {
|
|
54
|
+
records.push({
|
|
55
|
+
...entry,
|
|
56
|
+
atMs: Date.now()
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
const resetThenSign = async (hash, signer) => {
|
|
60
|
+
if (pendingReset) {
|
|
61
|
+
pendingReset = false;
|
|
62
|
+
resetCalls += 1;
|
|
63
|
+
if (signer.resetSession === void 0) throw new Error("armSignerFaults: resetSessionBeforeNextSign needs the embedded browser signer; this client composed a signer with no session");
|
|
64
|
+
signer.resetSession();
|
|
65
|
+
record({
|
|
66
|
+
boundary: "reset-session",
|
|
67
|
+
attempt: resetCalls,
|
|
68
|
+
hash
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return signer.signUserOpHash(hash);
|
|
72
|
+
};
|
|
73
|
+
const faultThenDelegate = async (hash, delegate) => {
|
|
74
|
+
embeddedCalls += 1;
|
|
75
|
+
const fault = pendingFault;
|
|
76
|
+
if (fault === void 0) {
|
|
77
|
+
record({
|
|
78
|
+
boundary: "embedded-sign",
|
|
79
|
+
attempt: embeddedCalls,
|
|
80
|
+
hash
|
|
81
|
+
});
|
|
82
|
+
return delegate(hash);
|
|
83
|
+
}
|
|
84
|
+
pendingFault = void 0;
|
|
85
|
+
record({
|
|
86
|
+
boundary: "embedded-sign",
|
|
87
|
+
attempt: embeddedCalls,
|
|
88
|
+
hash,
|
|
89
|
+
fault
|
|
90
|
+
});
|
|
91
|
+
throw signerFaultCause(fault);
|
|
92
|
+
};
|
|
93
|
+
return {
|
|
94
|
+
controls: {
|
|
95
|
+
...plan.resetSessionBeforeNextSign === true ? { signUserOpHash: resetThenSign } : {},
|
|
96
|
+
...plan.signOnce === void 0 ? {} : { signEmbeddedUserOpHash: faultThenDelegate }
|
|
97
|
+
},
|
|
98
|
+
records: () => records.slice(),
|
|
99
|
+
spent: () => pendingFault === void 0 && !pendingReset
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
12
103
|
//#region src/testing/account/InMemoryAccountReadAdapter.ts
|
|
13
104
|
var InMemoryAccountReadAdapter = class {
|
|
14
105
|
#deps;
|
|
@@ -915,4 +1006,4 @@ function createCapxulTestClient(options = {}) {
|
|
|
915
1006
|
};
|
|
916
1007
|
}
|
|
917
1008
|
//#endregion
|
|
918
|
-
export { createCapxulProductionTestClient, createCapxulTestClient };
|
|
1009
|
+
export { ControlledSignerFault, armSignerFaults, createCapxulProductionTestClient, createCapxulTestClient, signerFaultCause };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capxul/sdk",
|
|
3
|
-
"version": "4.2.0-rc.
|
|
3
|
+
"version": "4.2.0-rc.9",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/Xelmar-tech/infrastructure.git",
|
|
@@ -48,11 +48,11 @@
|
|
|
48
48
|
"vite-plus": "0.3.0",
|
|
49
49
|
"vitest": "4.1.11",
|
|
50
50
|
"@capxul/config": "0.3.0",
|
|
51
|
-
"@capxul/observability": "4.2.0-rc.
|
|
52
|
-
"@capxul/types": "0.3.0",
|
|
51
|
+
"@capxul/observability": "4.2.0-rc.9",
|
|
53
52
|
"@capxul/errors": "0.3.0",
|
|
54
|
-
"@capxul/
|
|
55
|
-
"@capxul/
|
|
53
|
+
"@capxul/wire": "0.7.0",
|
|
54
|
+
"@capxul/types": "0.3.0",
|
|
55
|
+
"@capxul/typescript-config": "0.0.0"
|
|
56
56
|
},
|
|
57
57
|
"_permissionlessPinReason": "permissionless.toSafeSmartAccount is pinned to 0.3.4 for live Safe deployment E2E. Counterfactual address fixtures captured 2026-05-17 in packages/backend/convex/_shared/__tests__/counterfactual.test.ts and packages/config/tests/safe.test.ts must be re-verified before upgrading.",
|
|
58
58
|
"scripts": {
|