@capxul/sdk 0.1.0-alpha.4 → 0.1.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @capxul/sdk
2
2
 
3
+ ## 0.1.0-alpha.6
4
+
5
+ ### Minor Changes
6
+
7
+ - 57203a4: Withdrawals v1 W2 (#465) — public surface tightening + org-scope create
8
+ - `WithdrawalsCreateInput.destination` no longer accepts `kind`. The
9
+ backend now resolves the `external_account` row by FK and infers
10
+ the kind + rail server-side. Anything that doesn't route to
11
+ `chain_wallet` (or is chain_wallet but non-EVM in slice 1) returns
12
+ `VERIFICATION_REQUIRED` with `details.rail` + `details.currentKind`.
13
+ - `organizations.withdrawals.create` is now a real mutation (no
14
+ longer a `NOT_IMPLEMENTED` stub). Returns the `processing` row
15
+ only — Safe + Zodiac submission orchestration ships in W3+.
16
+ - `Errors.verificationRequired({ rail, currentKind })` factory
17
+ added; the `VERIFICATION_REQUIRED` code now broadens to cover
18
+ both KYC tier gates and unsupported withdrawal rails.
19
+
20
+ **Migration:** Remove `destination.kind` from any
21
+ `capxul.withdrawals.create({ destination: { kind, externalAccountId } })`
22
+ call sites. Pass only `externalAccountId`.
23
+
24
+ ## 0.1.0-alpha.5
25
+
26
+ ### Patch Changes
27
+
28
+ - Version sync with `@capxul/sdk-react@0.1.0-alpha.5`; no headless SDK runtime
29
+ changes.
30
+
3
31
  ## 0.1.0-alpha.4
4
32
 
5
33
  ### Minor Changes
package/README.md CHANGED
@@ -90,7 +90,7 @@ capxul.accounts // create, retrieve, list
90
90
  capxul.organizations // CRUD + members + payments + treasury
91
91
  capxul.payments // create, retrieve, list
92
92
  capxul.invoices // create, retrieve, list
93
- capxul.withdrawals // request, retrieve, list
93
+ capxul.withdrawals // create, retrieve, list
94
94
  capxul.documents // KYC uploads, invoices, receipts, tax forms
95
95
  capxul.flows.{auth, onboarding, provisioning} // XState v5 flows
96
96
  ```
@@ -2,7 +2,7 @@ import { Account as Account$1 } from 'viem';
2
2
  import { AnyStateMachine } from 'xstate';
3
3
  import { A as AccountId, S as SafeId, c as KycProfileId, b as ExternalAccountId, f as SubAccountId, d as OrganizationId, a as ApiKeyId, X as TimestampIso, D as DocumentId, O as OperationId, P as PaymentId, g as TransferId, k as WithdrawalId, W as WebhookEndpointId, j as WebhookEventId, M as MemberId, K as KybProfileId, V as VirtualAccountId, i as VirtualCardId } from './next-action-DkrwXYay.js';
4
4
  import { d as CapxulResult, C as CapxulError } from './errors-QHD5Tlok.js';
5
- import { A as Account, U as UserIdentifier, a as AccountLookupResult, S as Safe, i as KycProfile, E as ExternalAccount, L as List, v as SubAccount, B as BalanceLedgerEntry, b as ApiKey, D as Document, O as Operation, l as OperationStatus, k as Money, C as CreatePaymentResult, o as Payment, F as TransferEndpoint, f as CreateTransferResult, y as Transfer, g as CreateWithdrawalResult, _ as Withdrawal, Y as WebhookEndpoint, Z as WebhookEvent, n as Organization, J as Treasury, M as Member, K as KybProfile, V as VirtualAccount, Q as VirtualCard } from './types-75UokagF.js';
5
+ import { A as Account, U as UserIdentifier, a as AccountLookupResult, S as Safe, i as KycProfile, E as ExternalAccount, L as List, v as SubAccount, B as BalanceLedgerEntry, b as ApiKey, D as Document, O as Operation, l as OperationStatus, k as Money, C as CreatePaymentResult, o as Payment, F as TransferEndpoint, f as CreateTransferResult, y as Transfer, g as CreateWithdrawalResult, _ as Withdrawal, Y as WebhookEndpoint, Z as WebhookEvent, n as Organization, J as Treasury, M as Member, K as KybProfile, V as VirtualAccount, Q as VirtualCard } from './types-CYvLP5pP.js';
6
6
  import * as types from '@repo/api-contract/gen/types';
7
7
 
8
8
  /**
@@ -282,8 +282,20 @@ type OrgDocumentsClient = {
282
282
  * Per sdk-surface.md §1a, `external_account` is a reusable withdrawal
283
283
  * destination. `create` + `list` live under the owner's nested
284
284
  * namespace (Pattern A — `accounts.externalAccounts.*` or
285
- * `organizations.externalAccounts.*`). `retrieve` and `remove` work by
286
- * ID without scoping.
285
+ * `organizations.externalAccounts.*`). The top-level `retrieve` and
286
+ * `remove` keep PERSONAL-scope semantics — for org rows route via
287
+ * the `organizations.externalAccounts.*` namespace which carries
288
+ * `organizationId` end-to-end and pins the row's owner pair to
289
+ * prevent cross-org IDOR (revision 1, #464).
290
+ *
291
+ * Withdrawals v1 W1 (#464) wires these stubs through the
292
+ * `externalAccounts/{queries,mutations}` Convex domain. The wire shape
293
+ * matches OpenAPI: `{ object: "external_account", id, kind, status,
294
+ * ..., operation: { id, status, correlationId } }` — the trust-chain
295
+ * ids live under the canonical nested `operation: OperationSummary`
296
+ * envelope (revision 3, #464), matching Withdrawal / Payment /
297
+ * Transfer / Organization. The SDK rebrands `id` + the nested
298
+ * `operation` sub-ids at the read edge.
287
299
  */
288
300
 
289
301
  type RetrieveCodes$b = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
@@ -473,35 +485,25 @@ type OrgTransfersClient = {
473
485
 
474
486
  /**
475
487
  * Withdrawals domain — funds exit Capxul via an `external_account` per
476
- * sdk-surface.md §1a + §4.52 + withdrawal-orchestration.mdx (slice 1
477
- * of Withdrawals v1, #440).
478
- *
479
- * Slice 1 NOTE — transitional input shape:
480
- * Until the `external_accounts` resource lands (slice 1.x or v2), the
481
- * destination input includes a `kind` field so the backend + SDK can
482
- * route to the chain_wallet rail without a real external_accounts
483
- * lookup. When the resource lands, `kind` becomes optional / ignored
484
- * and the kind is inferred from the resolved row.
488
+ * sdk-surface.md §1a + §4.52 + withdrawal-orchestration.mdx.
485
489
  *
486
- * Slice 1 NOTE chain_wallet rail integration:
487
- * For evm destinations, the `externalAccountId` is treated as the
488
- * destination address (must start with `0x`) so the chain_wallet rail
489
- * can call `transferAsOwner` directly. For solana / starknet the SDK
490
- * accepts the create call but does NOT execute the rail submission
491
- * the row stays in `processing` until external_accounts lands. The
492
- * caller can transition it via `markFailed` if needed.
490
+ * Withdrawals v1 W2 (#465) refactor:
491
+ * - The `kind` shim on `destination` is GONE. The backend now resolves
492
+ * the destination row by FK and infers kind + rail. Anything that
493
+ * doesn't route to `chain_wallet` returns `VERIFICATION_REQUIRED`.
494
+ * - Org-scope `create` is now a real mutation (no longer a stub).
495
+ * Personal-scope keeps the on-chain submission tail; org-scope
496
+ * returns the `processing` row only Safe + Zodiac orchestration
497
+ * ships in W3+ (D6).
498
+ * - All raw `try/catch` blocks have been replaced with `tryCatch` from
499
+ * `@repo/observability`, mirroring `core/external-accounts.ts`
500
+ * (precedent D2).
493
501
  */
494
502
 
495
503
  type WithdrawalsCreateInput = {
496
504
  readonly amount: Money;
497
505
  readonly destination: {
498
506
  readonly externalAccountId: ExternalAccountId;
499
- /**
500
- * Slice 1 transitional field. Required until the
501
- * `external_accounts` resource lands; will become optional / ignored
502
- * when the resource is the source of truth for kind.
503
- */
504
- readonly kind: "evm" | "solana" | "starknet" | "bank" | "momo" | "card_payout";
505
507
  };
506
508
  readonly source?: {
507
509
  readonly subAccountId: SubAccountId;
@@ -514,6 +516,22 @@ type WithdrawalsListInput = {
514
516
  readonly limit?: number;
515
517
  readonly cursor?: string;
516
518
  };
519
+ /**
520
+ * Withdrawals v1 W4 (#467) — input for the reconciliation pipe.
521
+ * Caller passes the same `txHash` that `recordSubmitted` wrote; the
522
+ * backend cross-checks the value against the persisted operation row.
523
+ *
524
+ * `withdrawalId` accepts either the branded `WithdrawalId` or a raw
525
+ * string. `txHash` is a raw string at the SDK boundary — the backend
526
+ * re-validates the shape via `toTxHash` at the mutation handler (the
527
+ * SDK package is no longer coupled to `@repo/types`'s brand surface
528
+ * post the alpha-epic decoupling; see
529
+ * `packages/sdk/docs/internal/decoupling-prep.md`).
530
+ */
531
+ type WithdrawalsRecordCompletedInput = {
532
+ readonly withdrawalId: WithdrawalId | string;
533
+ readonly txHash: string;
534
+ };
517
535
  type OrgWithdrawalsCreateInput = WithdrawalsCreateInput & {
518
536
  readonly organizationId: OrganizationId;
519
537
  };
@@ -526,13 +544,35 @@ type OrgWithdrawalsListInput = {
526
544
  readonly limit?: number;
527
545
  readonly cursor?: string;
528
546
  };
529
- type CreateCodes$4 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT" | "INSUFFICIENT_BALANCE" | "IDEMPOTENCY_CONFLICT" | "KYC_REQUIRED" | "POLICY_DENIED" | "RATE_LIMITED" | "NETWORK_ERROR";
547
+ type CreateCodes$4 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT" | "INSUFFICIENT_BALANCE" | "IDEMPOTENCY_CONFLICT" | "KYC_REQUIRED" | "POLICY_DENIED" | "RATE_LIMITED" | "NETWORK_ERROR" | "NOT_FOUND" | "VERIFICATION_REQUIRED";
530
548
  type RetrieveCodes$7 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
531
549
  type ListCodes$6 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT";
550
+ /**
551
+ * Narrow code set for `recordCompleted`. Mirror of `recordSubmitted`'s
552
+ * code surface — the SDK does NOT export `recordSubmitted` publicly
553
+ * (the create signing tail invokes it), but the call shape is the
554
+ * reference. Per ADR 9, `recordCompleted` is exposed on personal-scope
555
+ * `WithdrawalsClient` ONLY.
556
+ */
557
+ type RecordCompletedCodes = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT" | "NOT_FOUND" | "NETWORK_ERROR" | "INTERNAL_ERROR";
532
558
  type WithdrawalsClient = {
533
559
  readonly create: (input: WithdrawalsCreateInput) => Promise<CapxulResult<CreateWithdrawalResult, CreateCodes$4>>;
534
560
  readonly retrieve: (withdrawalId: WithdrawalId) => Promise<CapxulResult<Withdrawal, RetrieveCodes$7>>;
535
561
  readonly list: (input?: WithdrawalsListInput) => Promise<CapxulResult<List<Withdrawal>, ListCodes$6>>;
562
+ /**
563
+ * Withdrawals v1 W4 (#467) — reconciliation pipe.
564
+ *
565
+ * Caller invokes this AFTER `withdrawals.create` resolves AND after
566
+ * the on-chain receipt confirms (e.g., via the harness's
567
+ * `chain.waitReceipt`). The mutation patches the withdrawal +
568
+ * execution + attempt + operation rows to terminal happy state and
569
+ * emits a single `operation.succeeded` outbox event joined to the
570
+ * original correlationId. Idempotent on already-`completed` rows.
571
+ *
572
+ * Personal-scope only — the org-scope client does NOT expose this
573
+ * method (mirror of `recordSubmitted`; see ADR 9 in #467).
574
+ */
575
+ readonly recordCompleted: (input: WithdrawalsRecordCompletedInput) => Promise<CapxulResult<null, RecordCompletedCodes>>;
536
576
  };
537
577
  type OrgWithdrawalsClient = {
538
578
  readonly create: (input: OrgWithdrawalsCreateInput) => Promise<CapxulResult<CreateWithdrawalResult, CreateCodes$4>>;
@@ -2,7 +2,7 @@ import { Account as Account$1 } from 'viem';
2
2
  import { AnyStateMachine } from 'xstate';
3
3
  import { A as AccountId, S as SafeId, c as KycProfileId, b as ExternalAccountId, f as SubAccountId, d as OrganizationId, a as ApiKeyId, X as TimestampIso, D as DocumentId, O as OperationId, P as PaymentId, g as TransferId, k as WithdrawalId, W as WebhookEndpointId, j as WebhookEventId, M as MemberId, K as KybProfileId, V as VirtualAccountId, i as VirtualCardId } from './next-action-DkrwXYay.cjs';
4
4
  import { d as CapxulResult, C as CapxulError } from './errors-GgKrSUKp.cjs';
5
- import { A as Account, U as UserIdentifier, a as AccountLookupResult, S as Safe, i as KycProfile, E as ExternalAccount, L as List, v as SubAccount, B as BalanceLedgerEntry, b as ApiKey, D as Document, O as Operation, l as OperationStatus, k as Money, C as CreatePaymentResult, o as Payment, F as TransferEndpoint, f as CreateTransferResult, y as Transfer, g as CreateWithdrawalResult, _ as Withdrawal, Y as WebhookEndpoint, Z as WebhookEvent, n as Organization, J as Treasury, M as Member, K as KybProfile, V as VirtualAccount, Q as VirtualCard } from './types-DVWojoy4.cjs';
5
+ import { A as Account, U as UserIdentifier, a as AccountLookupResult, S as Safe, i as KycProfile, E as ExternalAccount, L as List, v as SubAccount, B as BalanceLedgerEntry, b as ApiKey, D as Document, O as Operation, l as OperationStatus, k as Money, C as CreatePaymentResult, o as Payment, F as TransferEndpoint, f as CreateTransferResult, y as Transfer, g as CreateWithdrawalResult, _ as Withdrawal, Y as WebhookEndpoint, Z as WebhookEvent, n as Organization, J as Treasury, M as Member, K as KybProfile, V as VirtualAccount, Q as VirtualCard } from './types-X02RbQ2u.cjs';
6
6
  import * as types from '@repo/api-contract/gen/types';
7
7
 
8
8
  /**
@@ -282,8 +282,20 @@ type OrgDocumentsClient = {
282
282
  * Per sdk-surface.md §1a, `external_account` is a reusable withdrawal
283
283
  * destination. `create` + `list` live under the owner's nested
284
284
  * namespace (Pattern A — `accounts.externalAccounts.*` or
285
- * `organizations.externalAccounts.*`). `retrieve` and `remove` work by
286
- * ID without scoping.
285
+ * `organizations.externalAccounts.*`). The top-level `retrieve` and
286
+ * `remove` keep PERSONAL-scope semantics — for org rows route via
287
+ * the `organizations.externalAccounts.*` namespace which carries
288
+ * `organizationId` end-to-end and pins the row's owner pair to
289
+ * prevent cross-org IDOR (revision 1, #464).
290
+ *
291
+ * Withdrawals v1 W1 (#464) wires these stubs through the
292
+ * `externalAccounts/{queries,mutations}` Convex domain. The wire shape
293
+ * matches OpenAPI: `{ object: "external_account", id, kind, status,
294
+ * ..., operation: { id, status, correlationId } }` — the trust-chain
295
+ * ids live under the canonical nested `operation: OperationSummary`
296
+ * envelope (revision 3, #464), matching Withdrawal / Payment /
297
+ * Transfer / Organization. The SDK rebrands `id` + the nested
298
+ * `operation` sub-ids at the read edge.
287
299
  */
288
300
 
289
301
  type RetrieveCodes$b = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
@@ -473,35 +485,25 @@ type OrgTransfersClient = {
473
485
 
474
486
  /**
475
487
  * Withdrawals domain — funds exit Capxul via an `external_account` per
476
- * sdk-surface.md §1a + §4.52 + withdrawal-orchestration.mdx (slice 1
477
- * of Withdrawals v1, #440).
478
- *
479
- * Slice 1 NOTE — transitional input shape:
480
- * Until the `external_accounts` resource lands (slice 1.x or v2), the
481
- * destination input includes a `kind` field so the backend + SDK can
482
- * route to the chain_wallet rail without a real external_accounts
483
- * lookup. When the resource lands, `kind` becomes optional / ignored
484
- * and the kind is inferred from the resolved row.
488
+ * sdk-surface.md §1a + §4.52 + withdrawal-orchestration.mdx.
485
489
  *
486
- * Slice 1 NOTE chain_wallet rail integration:
487
- * For evm destinations, the `externalAccountId` is treated as the
488
- * destination address (must start with `0x`) so the chain_wallet rail
489
- * can call `transferAsOwner` directly. For solana / starknet the SDK
490
- * accepts the create call but does NOT execute the rail submission
491
- * the row stays in `processing` until external_accounts lands. The
492
- * caller can transition it via `markFailed` if needed.
490
+ * Withdrawals v1 W2 (#465) refactor:
491
+ * - The `kind` shim on `destination` is GONE. The backend now resolves
492
+ * the destination row by FK and infers kind + rail. Anything that
493
+ * doesn't route to `chain_wallet` returns `VERIFICATION_REQUIRED`.
494
+ * - Org-scope `create` is now a real mutation (no longer a stub).
495
+ * Personal-scope keeps the on-chain submission tail; org-scope
496
+ * returns the `processing` row only Safe + Zodiac orchestration
497
+ * ships in W3+ (D6).
498
+ * - All raw `try/catch` blocks have been replaced with `tryCatch` from
499
+ * `@repo/observability`, mirroring `core/external-accounts.ts`
500
+ * (precedent D2).
493
501
  */
494
502
 
495
503
  type WithdrawalsCreateInput = {
496
504
  readonly amount: Money;
497
505
  readonly destination: {
498
506
  readonly externalAccountId: ExternalAccountId;
499
- /**
500
- * Slice 1 transitional field. Required until the
501
- * `external_accounts` resource lands; will become optional / ignored
502
- * when the resource is the source of truth for kind.
503
- */
504
- readonly kind: "evm" | "solana" | "starknet" | "bank" | "momo" | "card_payout";
505
507
  };
506
508
  readonly source?: {
507
509
  readonly subAccountId: SubAccountId;
@@ -514,6 +516,22 @@ type WithdrawalsListInput = {
514
516
  readonly limit?: number;
515
517
  readonly cursor?: string;
516
518
  };
519
+ /**
520
+ * Withdrawals v1 W4 (#467) — input for the reconciliation pipe.
521
+ * Caller passes the same `txHash` that `recordSubmitted` wrote; the
522
+ * backend cross-checks the value against the persisted operation row.
523
+ *
524
+ * `withdrawalId` accepts either the branded `WithdrawalId` or a raw
525
+ * string. `txHash` is a raw string at the SDK boundary — the backend
526
+ * re-validates the shape via `toTxHash` at the mutation handler (the
527
+ * SDK package is no longer coupled to `@repo/types`'s brand surface
528
+ * post the alpha-epic decoupling; see
529
+ * `packages/sdk/docs/internal/decoupling-prep.md`).
530
+ */
531
+ type WithdrawalsRecordCompletedInput = {
532
+ readonly withdrawalId: WithdrawalId | string;
533
+ readonly txHash: string;
534
+ };
517
535
  type OrgWithdrawalsCreateInput = WithdrawalsCreateInput & {
518
536
  readonly organizationId: OrganizationId;
519
537
  };
@@ -526,13 +544,35 @@ type OrgWithdrawalsListInput = {
526
544
  readonly limit?: number;
527
545
  readonly cursor?: string;
528
546
  };
529
- type CreateCodes$4 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT" | "INSUFFICIENT_BALANCE" | "IDEMPOTENCY_CONFLICT" | "KYC_REQUIRED" | "POLICY_DENIED" | "RATE_LIMITED" | "NETWORK_ERROR";
547
+ type CreateCodes$4 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT" | "INSUFFICIENT_BALANCE" | "IDEMPOTENCY_CONFLICT" | "KYC_REQUIRED" | "POLICY_DENIED" | "RATE_LIMITED" | "NETWORK_ERROR" | "NOT_FOUND" | "VERIFICATION_REQUIRED";
530
548
  type RetrieveCodes$7 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "NOT_FOUND";
531
549
  type ListCodes$6 = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT";
550
+ /**
551
+ * Narrow code set for `recordCompleted`. Mirror of `recordSubmitted`'s
552
+ * code surface — the SDK does NOT export `recordSubmitted` publicly
553
+ * (the create signing tail invokes it), but the call shape is the
554
+ * reference. Per ADR 9, `recordCompleted` is exposed on personal-scope
555
+ * `WithdrawalsClient` ONLY.
556
+ */
557
+ type RecordCompletedCodes = "NOT_AUTHENTICATED" | "PERMISSION_DENIED" | "INVALID_INPUT" | "NOT_FOUND" | "NETWORK_ERROR" | "INTERNAL_ERROR";
532
558
  type WithdrawalsClient = {
533
559
  readonly create: (input: WithdrawalsCreateInput) => Promise<CapxulResult<CreateWithdrawalResult, CreateCodes$4>>;
534
560
  readonly retrieve: (withdrawalId: WithdrawalId) => Promise<CapxulResult<Withdrawal, RetrieveCodes$7>>;
535
561
  readonly list: (input?: WithdrawalsListInput) => Promise<CapxulResult<List<Withdrawal>, ListCodes$6>>;
562
+ /**
563
+ * Withdrawals v1 W4 (#467) — reconciliation pipe.
564
+ *
565
+ * Caller invokes this AFTER `withdrawals.create` resolves AND after
566
+ * the on-chain receipt confirms (e.g., via the harness's
567
+ * `chain.waitReceipt`). The mutation patches the withdrawal +
568
+ * execution + attempt + operation rows to terminal happy state and
569
+ * emits a single `operation.succeeded` outbox event joined to the
570
+ * original correlationId. Idempotent on already-`completed` rows.
571
+ *
572
+ * Personal-scope only — the org-scope client does NOT expose this
573
+ * method (mirror of `recordSubmitted`; see ADR 9 in #467).
574
+ */
575
+ readonly recordCompleted: (input: WithdrawalsRecordCompletedInput) => Promise<CapxulResult<null, RecordCompletedCodes>>;
536
576
  };
537
577
  type OrgWithdrawalsClient = {
538
578
  readonly create: (input: OrgWithdrawalsCreateInput) => Promise<CapxulResult<CreateWithdrawalResult, CreateCodes$4>>;