@unicitylabs/sphere-sdk 0.14.0-dev.5 → 0.14.0-dev.7
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/connect/index.cjs +1 -1
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.js +1 -1
- package/dist/connect/index.js.map +1 -1
- package/dist/core/index.cjs +713 -252
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +111 -87
- package/dist/core/index.d.ts +111 -87
- package/dist/core/index.js +713 -252
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/connect/index.cjs +1 -1
- package/dist/impl/browser/connect/index.cjs.map +1 -1
- package/dist/impl/browser/connect/index.js +1 -1
- package/dist/impl/browser/connect/index.js.map +1 -1
- package/dist/impl/wallet-api-v2/index.cjs +45 -5
- package/dist/impl/wallet-api-v2/index.cjs.map +1 -1
- package/dist/impl/wallet-api-v2/index.d.cts +26 -2
- package/dist/impl/wallet-api-v2/index.d.ts +26 -2
- package/dist/impl/wallet-api-v2/index.js +45 -5
- package/dist/impl/wallet-api-v2/index.js.map +1 -1
- package/dist/index.cjs +713 -252
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +112 -88
- package/dist/index.d.ts +112 -88
- package/dist/index.js +713 -252
- package/dist/index.js.map +1 -1
- package/dist/modules/payments-v2/index.cjs +634 -228
- package/dist/modules/payments-v2/index.cjs.map +1 -1
- package/dist/modules/payments-v2/index.d.cts +112 -20
- package/dist/modules/payments-v2/index.d.ts +112 -20
- package/dist/modules/payments-v2/index.js +631 -228
- package/dist/modules/payments-v2/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -547,6 +547,25 @@ interface PaymentsRequestsApi {
|
|
|
547
547
|
decline(id: string): Promise<void>;
|
|
548
548
|
dismissProcessed(): void;
|
|
549
549
|
}
|
|
550
|
+
/**
|
|
551
|
+
* A pending-transfers row, derived ON READ from the §6 stores (intent backstop
|
|
552
|
+
* + delivery journal + shortfalls) — never a cached mirror. kind 'shortfall' =
|
|
553
|
+
* a completed partial (#690) whose `amount` is the remainder still owed;
|
|
554
|
+
* legs.certified counts journaled legs (certified, delivery still owed).
|
|
555
|
+
*/
|
|
556
|
+
interface PendingTransfer {
|
|
557
|
+
transferId: string;
|
|
558
|
+
kind: 'open' | 'shortfall';
|
|
559
|
+
recipient: string;
|
|
560
|
+
coinId: string;
|
|
561
|
+
amount: string;
|
|
562
|
+
legs: {
|
|
563
|
+
certified: number;
|
|
564
|
+
total: number;
|
|
565
|
+
};
|
|
566
|
+
deliveryPending: boolean;
|
|
567
|
+
createdAt: number;
|
|
568
|
+
}
|
|
550
569
|
interface PaymentsV2 {
|
|
551
570
|
assets(coinId?: string): Promise<Asset[]>;
|
|
552
571
|
tokens(filter?: {
|
|
@@ -561,6 +580,8 @@ interface PaymentsV2 {
|
|
|
561
580
|
receive(): Promise<{
|
|
562
581
|
transfers: IncomingTransfer[];
|
|
563
582
|
}>;
|
|
583
|
+
pendingTransfers(): Promise<PendingTransfer[]>;
|
|
584
|
+
resumeNow(): Promise<void>;
|
|
564
585
|
readonly requests: PaymentsRequestsApi;
|
|
565
586
|
}
|
|
566
587
|
interface PaymentsV2Events {
|
|
@@ -572,7 +593,8 @@ interface PaymentsV2Events {
|
|
|
572
593
|
detail?: string;
|
|
573
594
|
};
|
|
574
595
|
'inventory:updated': Record<string, never>;
|
|
575
|
-
|
|
596
|
+
/** The just-recorded entry, client-shaped (the same mapping history() serves). */
|
|
597
|
+
'history:updated': HistoryEntry;
|
|
576
598
|
'payment_request:incoming': PaymentRequestView;
|
|
577
599
|
'payment_request:updated': {
|
|
578
600
|
id: string;
|
|
@@ -645,6 +667,14 @@ interface DeliveryPort {
|
|
|
645
667
|
deliver(recipientPubkey: string, blob: Uint8Array, options: DeliverOptions): Promise<DeliveryReceipt>;
|
|
646
668
|
deliverBatch?(recipientPubkey: string, blobs: Uint8Array[], options: DeliverOptions): Promise<DeliveryReceipt[]>;
|
|
647
669
|
incoming(sinceCursor?: string): AsyncIterable<IncomingDelivery>;
|
|
670
|
+
/**
|
|
671
|
+
* The syncEpoch of the most recent incoming() page — updated per page, null
|
|
672
|
+
* before the first. §5.7 restore self-detection: the mailbox page is the
|
|
673
|
+
* honest epoch source, so Receive voids its (cursor, epoch) continuity on a
|
|
674
|
+
* mismatch even when the wake socket missed a server restore. (Pinned by the
|
|
675
|
+
* S7 contract suite; wallet-api#119's S7 text carries the same sentence.)
|
|
676
|
+
*/
|
|
677
|
+
incomingEpoch(): string | null;
|
|
648
678
|
ack(deliveryId: string, disposition: 'claimed' | 'rejected', reason?: 'invalid' | 'not-owned' | 'storage-rejected' | 'other'): Promise<void>;
|
|
649
679
|
onWake?(cb: () => void): () => void;
|
|
650
680
|
}
|
|
@@ -739,6 +769,8 @@ declare const STORE_KEYS: {
|
|
|
739
769
|
readonly settlingLinks: "settling";
|
|
740
770
|
readonly streamCursor: (s: StreamName) => string;
|
|
741
771
|
readonly epochLatch: "epoch-latch";
|
|
772
|
+
readonly suspectedSpent: "suspected-spent";
|
|
773
|
+
readonly knownSpends: "known-spends";
|
|
742
774
|
};
|
|
743
775
|
|
|
744
776
|
type RequestWireStatus = 'open' | 'paid' | 'declined' | 'expired';
|
|
@@ -826,6 +858,7 @@ declare class Requests implements PaymentsRequestsApi {
|
|
|
826
858
|
private now;
|
|
827
859
|
private ensureJournalLoaded;
|
|
828
860
|
private mutateJournal;
|
|
861
|
+
/** Idempotent for a same-transferId re-write: committed only ratchets up, createdAt kept. */
|
|
829
862
|
private writeLink;
|
|
830
863
|
private clearLink;
|
|
831
864
|
drainIncoming(): Promise<void>;
|
|
@@ -845,6 +878,18 @@ declare class Requests implements PaymentsRequestsApi {
|
|
|
845
878
|
}>;
|
|
846
879
|
pay(id: string): Promise<TransferResult>;
|
|
847
880
|
private payInner;
|
|
881
|
+
/**
|
|
882
|
+
* THE settlement invariant (#441 + the failed-respond P1): a settling link is
|
|
883
|
+
* removed ONLY by (a) a CONFIRMED paid respond — a 2xx, or the 409
|
|
884
|
+
* already-resolved absorb — or (b) a proven clean pre-commit failure
|
|
885
|
+
* (revertPayable). Nothing else removes one: not a network error, not a 5xx,
|
|
886
|
+
* not a reload. Every path that binds a request to a transfer outcome funnels
|
|
887
|
+
* through here — pay()'s clean success (respond now), pay()'s
|
|
888
|
+
* possibly-committed throw (respond deferred), and reconcile's deferred arms
|
|
889
|
+
* — so a failed respond always leaves the link + 'settling' and the next
|
|
890
|
+
* reconcile pass (the committed-link override) retries the respond.
|
|
891
|
+
*/
|
|
892
|
+
private settle;
|
|
848
893
|
/** 'paid' respond leg: 409 = already resolved = idempotent success; other errors defer. */
|
|
849
894
|
private respondPaid;
|
|
850
895
|
decline(id: string): Promise<void>;
|
|
@@ -852,7 +897,9 @@ declare class Requests implements PaymentsRequestsApi {
|
|
|
852
897
|
reconcile(outcomes: ResumeOutcomes): Promise<void>;
|
|
853
898
|
private doReconcile;
|
|
854
899
|
private reconcileUnaccounted;
|
|
900
|
+
/** Deferred paid: the ONE settlement path again — a failed respond keeps the link. */
|
|
855
901
|
private resolvePaid;
|
|
902
|
+
/** Removal cause (b): a PROVEN clean outcome (pre-commit failure / server-aborted). */
|
|
856
903
|
private revertPayable;
|
|
857
904
|
}
|
|
858
905
|
|
|
@@ -899,6 +946,8 @@ interface PriceReader {
|
|
|
899
946
|
getPrices(tokenNames: string[]): Promise<Map<string, PriceQuote>>;
|
|
900
947
|
}
|
|
901
948
|
|
|
949
|
+
declare const ATTENTION_RESEED_REJECTED = "intent:reseed-rejected";
|
|
950
|
+
|
|
902
951
|
/**
|
|
903
952
|
* F13 makes `mint(params, { transferId, opIndex })` idempotent-recoverable — a
|
|
904
953
|
* same-seed re-CALL recovers the existing certification via the E.2 probe
|
|
@@ -919,6 +968,28 @@ interface FacadeSession {
|
|
|
919
968
|
start(): Promise<void>;
|
|
920
969
|
stop(): Promise<void>;
|
|
921
970
|
subscribeStream(stream: 'inventory' | 'mailbox' | 'payment_requests', handler: () => void): () => void;
|
|
971
|
+
/** §5.1: the latched server syncEpoch ('' before first server contact). */
|
|
972
|
+
currentEpoch(): string;
|
|
973
|
+
/**
|
|
974
|
+
* §5.1 restore hook — REQUIRED so an unwired restore protocol is a COMPILE
|
|
975
|
+
* ERROR: handlers run and are AWAITED on a syncEpoch change BEFORE any
|
|
976
|
+
* stream nudge resumes. The facade registers handleEpochChange here.
|
|
977
|
+
*/
|
|
978
|
+
subscribeEpochChange(handler: (epoch: string) => Promise<void>): () => void;
|
|
979
|
+
/**
|
|
980
|
+
* Optional connection-status feed (same wiring pattern as the streams; the
|
|
981
|
+
* emission point is the session's existing `connection:status` transition).
|
|
982
|
+
* The facade's heartbeat resets its backoff on a 'connected' recovery.
|
|
983
|
+
*/
|
|
984
|
+
subscribeStatus?(handler: (status: 'connected' | 'degraded' | 'offline') => void): () => void;
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* §5.1/§6 restore surface of the checkpoint store: re-POST the slot's cached
|
|
988
|
+
* encrypt-once ciphertext byte-identical after a server restore (insert-once,
|
|
989
|
+
* first-write-wins server-side). Returns false when no ciphertext is cached.
|
|
990
|
+
*/
|
|
991
|
+
interface CheckpointReseeder {
|
|
992
|
+
reseedCheckpoint(transferId: string, opIndex: number): Promise<boolean>;
|
|
922
993
|
}
|
|
923
994
|
interface IntentWireLike {
|
|
924
995
|
transferId: string;
|
|
@@ -937,7 +1008,8 @@ interface PaymentsFacadeDeps {
|
|
|
937
1008
|
client: FacadeClient;
|
|
938
1009
|
storagePort: StoragePort;
|
|
939
1010
|
deliveryPort: DeliveryPort;
|
|
940
|
-
|
|
1011
|
+
/** Reseeder REQUIRED: the restore protocol re-POSTs cached ciphertexts (§5.1). */
|
|
1012
|
+
checkpointStore: SplitCheckpointStore & CheckpointReseeder;
|
|
941
1013
|
/** Initial engine source; setEngine() swaps what FUTURE operations snapshot. */
|
|
942
1014
|
engineRef: () => ITokenEngine;
|
|
943
1015
|
kv: ScopedKV;
|
|
@@ -953,7 +1025,8 @@ interface PaymentsFacadeDeps {
|
|
|
953
1025
|
ownPubkey: string;
|
|
954
1026
|
ownNametag?: () => string | undefined;
|
|
955
1027
|
requestMemo: RequestMemoCodec;
|
|
956
|
-
|
|
1028
|
+
/** REQUIRED (§5.1): reads the session's current epoch — never a default. */
|
|
1029
|
+
syncEpoch: () => string;
|
|
957
1030
|
now?: () => number;
|
|
958
1031
|
newId?: () => string;
|
|
959
1032
|
workBudget?: number;
|
|
@@ -975,11 +1048,20 @@ declare class PaymentsFacade implements PaymentsV2 {
|
|
|
975
1048
|
private readonly receiveLoop;
|
|
976
1049
|
private readonly heldStates;
|
|
977
1050
|
private readonly ownPubkeyBytes;
|
|
1051
|
+
private readonly restoreDeps;
|
|
978
1052
|
readonly requests: Requests;
|
|
979
1053
|
private currentEngine;
|
|
980
1054
|
private readonly pendingOps;
|
|
981
1055
|
private unsubscribers;
|
|
982
1056
|
private started;
|
|
1057
|
+
private readonly heartbeat;
|
|
1058
|
+
private readonly converger;
|
|
1059
|
+
/** Resume single-flight (§7): ticks, start() and resumeNow() coalesce onto ONE pass. */
|
|
1060
|
+
private readonly resumeFlight;
|
|
1061
|
+
/** §5.1/§7: restore + convergence passes SERIALIZE here. */
|
|
1062
|
+
private readonly passChain;
|
|
1063
|
+
/** §7 ownership: ids with an in-process machine attempt — the pass never adopts one. */
|
|
1064
|
+
private readonly activeMoneyOps;
|
|
983
1065
|
constructor(deps: PaymentsFacadeDeps);
|
|
984
1066
|
start(): Promise<void>;
|
|
985
1067
|
/** §7 same-address restart gate: resolves only after in-flight ops settle. */
|
|
@@ -994,26 +1076,36 @@ declare class PaymentsFacade implements PaymentsV2 {
|
|
|
994
1076
|
before?: string;
|
|
995
1077
|
limit?: number;
|
|
996
1078
|
}): Promise<HistoryPage>;
|
|
1079
|
+
/** §4 pending-transfers UI surface — derived on read, never cached (convergence.ts). */
|
|
1080
|
+
pendingTransfers(): Promise<PendingTransfer[]>;
|
|
997
1081
|
send(request: SendRequest): Promise<TransferResult>;
|
|
998
1082
|
receive(): Promise<{
|
|
999
1083
|
transfers: IncomingTransfer[];
|
|
1000
1084
|
}>;
|
|
1001
1085
|
mint(coinId: string, amount: bigint): Promise<MintResult>;
|
|
1086
|
+
resumeNow(): Promise<void>;
|
|
1087
|
+
/** §5.1 restore — awaited by the session latch BEFORE streams resume; never coalesced onto a pre-restore pass. */
|
|
1088
|
+
handleEpochChange(_newEpoch: string): Promise<void>;
|
|
1089
|
+
/** One single-flighted pass + its reschedule: concurrent callers coalesce. */
|
|
1090
|
+
private runConvergencePass;
|
|
1091
|
+
private convergeBody;
|
|
1092
|
+
private nowMs;
|
|
1093
|
+
/** The ONE place a send() outcome is shaped: success emits in finishSend, a
|
|
1094
|
+
* CLEAN rejection emits `transfer:updated{status:'failed'}` here (§4). */
|
|
1095
|
+
private sendOutcome;
|
|
1096
|
+
/** Only a CLEAN failure (nothing certified, classifyError 'other') is 'failed'.
|
|
1097
|
+
* Keep-open/partial/conflict outcomes are pending/converging — labelling them
|
|
1098
|
+
* 'failed' invites a dApp re-send, i.e. a double-pay (#631/#676). */
|
|
1099
|
+
private emitCleanFailure;
|
|
1002
1100
|
private sendWithPolicy;
|
|
1003
1101
|
/** §5.6 cross-network deposit trap: refused BEFORE any reserve/certification. */
|
|
1004
1102
|
private requireSameNetworkRecipient;
|
|
1005
1103
|
private runAttempt;
|
|
1006
|
-
/**
|
|
1007
|
-
*
|
|
1008
|
-
* the machine BEFORE complete). Accumulate the settled set, then re-plan ONLY
|
|
1009
|
-
* the remainder under a NEW transferId — never the full amount.
|
|
1010
|
-
*/
|
|
1104
|
+
/** Partial (#677/#690): shortfall already durable (machine wrote it BEFORE
|
|
1105
|
+
* complete); accumulate settled, re-plan ONLY the remainder, NEW transferId. */
|
|
1011
1106
|
private consumePartial;
|
|
1012
|
-
/**
|
|
1013
|
-
*
|
|
1014
|
-
* backstop still 'open' (committed>0) → converge via the same machine's
|
|
1015
|
-
* resumeIntent; clean conflict with a demoted source → bounded full re-plan.
|
|
1016
|
-
*/
|
|
1107
|
+
/** Failure disposition: possibly-committed → rethrow UNWRAPPED; backstop
|
|
1108
|
+
* 'open' → converge via resumeIntent; clean demoted conflict → full re-plan. */
|
|
1017
1109
|
private disposeFailedAttempt;
|
|
1018
1110
|
/** #677/#690: ≥1 leg committed — the SAME machine, resumed in-process, converges it. */
|
|
1019
1111
|
private convergePartial;
|
|
@@ -1033,28 +1125,28 @@ declare class PaymentsFacade implements PaymentsV2 {
|
|
|
1033
1125
|
private refreshThenRelease;
|
|
1034
1126
|
private accumulate;
|
|
1035
1127
|
private finishSend;
|
|
1036
|
-
/**
|
|
1037
|
-
* With nothing delivered the error passes UNWRAPPED (identity + cause kept);
|
|
1038
|
-
* after ≥1 delivered leg EVERY failure surfaces as PartialSendConflictError
|
|
1039
|
-
* over the accumulated settled set — never bare, never a full-amount retry.
|
|
1040
|
-
*/
|
|
1128
|
+
/** Nothing delivered → UNWRAPPED; after ≥1 delivered leg every failure surfaces as PartialSendConflictError over the settled set. */
|
|
1041
1129
|
private partialize;
|
|
1042
1130
|
/** #441: possibly-committed errors must carry the transferId for the settling journal. */
|
|
1043
1131
|
private stampTransferId;
|
|
1044
1132
|
private softAbort;
|
|
1045
1133
|
private mintInner;
|
|
1134
|
+
private mintUnderJournal;
|
|
1046
1135
|
private finalizeMint;
|
|
1136
|
+
/** @returns how many journal entries were RESOLVED (cleared) — heartbeat progress. */
|
|
1047
1137
|
private replayMints;
|
|
1048
1138
|
private replayMint;
|
|
1049
1139
|
private mintParams;
|
|
1050
1140
|
private tokenInServerInventory;
|
|
1051
1141
|
private engine;
|
|
1052
1142
|
private newId;
|
|
1053
|
-
private runResume;
|
|
1054
1143
|
private seedHeldStates;
|
|
1055
1144
|
private toUiToken;
|
|
1056
1145
|
private track;
|
|
1057
1146
|
private trackTail;
|
|
1058
1147
|
}
|
|
1059
1148
|
|
|
1060
|
-
|
|
1149
|
+
declare const HEARTBEAT_SEED_MS = 5000;
|
|
1150
|
+
declare const HEARTBEAT_CAP_MS = 120000;
|
|
1151
|
+
|
|
1152
|
+
export { ATTENTION_MINT_UNRESOLVED, ATTENTION_RESEED_REJECTED, type ApplyDeltaResult, type CheckpointReseeder, type DeliverOptions, type DeliveryJournalEntry, type DeliveryPort, type DeliveryReceipt, type DeterministicMintCapable, type FacadeClient, type FacadeSession, HEARTBEAT_CAP_MS, HEARTBEAT_SEED_MS, type HistoryEntry, type HistoryPage, type IncomingDelivery, type IntentBackstopEntry, type IntentPayload, type InventoryAsset, type InventoryItem, type InventoryPage, MAX_RESELECT, type MintJournalEntry, type MintResult, type OpOutcome, type OutcomeClass, type PaymentRequestStatus, type PaymentRequestView, PaymentsFacade, type PaymentsFacadeDeps, type PaymentsRequestsApi, type PaymentsV2, type PaymentsV2Events, type PendingTransfer, type PlannedOp, type RecipientInfo, STORE_KEYS, type ScopedKV, type SendRequest, type SettlingLink, type ShortfallEntry, type StoragePort, type StreamCursor, type StreamName, createScopedKV, supportsDeterministicMint };
|
|
@@ -547,6 +547,25 @@ interface PaymentsRequestsApi {
|
|
|
547
547
|
decline(id: string): Promise<void>;
|
|
548
548
|
dismissProcessed(): void;
|
|
549
549
|
}
|
|
550
|
+
/**
|
|
551
|
+
* A pending-transfers row, derived ON READ from the §6 stores (intent backstop
|
|
552
|
+
* + delivery journal + shortfalls) — never a cached mirror. kind 'shortfall' =
|
|
553
|
+
* a completed partial (#690) whose `amount` is the remainder still owed;
|
|
554
|
+
* legs.certified counts journaled legs (certified, delivery still owed).
|
|
555
|
+
*/
|
|
556
|
+
interface PendingTransfer {
|
|
557
|
+
transferId: string;
|
|
558
|
+
kind: 'open' | 'shortfall';
|
|
559
|
+
recipient: string;
|
|
560
|
+
coinId: string;
|
|
561
|
+
amount: string;
|
|
562
|
+
legs: {
|
|
563
|
+
certified: number;
|
|
564
|
+
total: number;
|
|
565
|
+
};
|
|
566
|
+
deliveryPending: boolean;
|
|
567
|
+
createdAt: number;
|
|
568
|
+
}
|
|
550
569
|
interface PaymentsV2 {
|
|
551
570
|
assets(coinId?: string): Promise<Asset[]>;
|
|
552
571
|
tokens(filter?: {
|
|
@@ -561,6 +580,8 @@ interface PaymentsV2 {
|
|
|
561
580
|
receive(): Promise<{
|
|
562
581
|
transfers: IncomingTransfer[];
|
|
563
582
|
}>;
|
|
583
|
+
pendingTransfers(): Promise<PendingTransfer[]>;
|
|
584
|
+
resumeNow(): Promise<void>;
|
|
564
585
|
readonly requests: PaymentsRequestsApi;
|
|
565
586
|
}
|
|
566
587
|
interface PaymentsV2Events {
|
|
@@ -572,7 +593,8 @@ interface PaymentsV2Events {
|
|
|
572
593
|
detail?: string;
|
|
573
594
|
};
|
|
574
595
|
'inventory:updated': Record<string, never>;
|
|
575
|
-
|
|
596
|
+
/** The just-recorded entry, client-shaped (the same mapping history() serves). */
|
|
597
|
+
'history:updated': HistoryEntry;
|
|
576
598
|
'payment_request:incoming': PaymentRequestView;
|
|
577
599
|
'payment_request:updated': {
|
|
578
600
|
id: string;
|
|
@@ -645,6 +667,14 @@ interface DeliveryPort {
|
|
|
645
667
|
deliver(recipientPubkey: string, blob: Uint8Array, options: DeliverOptions): Promise<DeliveryReceipt>;
|
|
646
668
|
deliverBatch?(recipientPubkey: string, blobs: Uint8Array[], options: DeliverOptions): Promise<DeliveryReceipt[]>;
|
|
647
669
|
incoming(sinceCursor?: string): AsyncIterable<IncomingDelivery>;
|
|
670
|
+
/**
|
|
671
|
+
* The syncEpoch of the most recent incoming() page — updated per page, null
|
|
672
|
+
* before the first. §5.7 restore self-detection: the mailbox page is the
|
|
673
|
+
* honest epoch source, so Receive voids its (cursor, epoch) continuity on a
|
|
674
|
+
* mismatch even when the wake socket missed a server restore. (Pinned by the
|
|
675
|
+
* S7 contract suite; wallet-api#119's S7 text carries the same sentence.)
|
|
676
|
+
*/
|
|
677
|
+
incomingEpoch(): string | null;
|
|
648
678
|
ack(deliveryId: string, disposition: 'claimed' | 'rejected', reason?: 'invalid' | 'not-owned' | 'storage-rejected' | 'other'): Promise<void>;
|
|
649
679
|
onWake?(cb: () => void): () => void;
|
|
650
680
|
}
|
|
@@ -739,6 +769,8 @@ declare const STORE_KEYS: {
|
|
|
739
769
|
readonly settlingLinks: "settling";
|
|
740
770
|
readonly streamCursor: (s: StreamName) => string;
|
|
741
771
|
readonly epochLatch: "epoch-latch";
|
|
772
|
+
readonly suspectedSpent: "suspected-spent";
|
|
773
|
+
readonly knownSpends: "known-spends";
|
|
742
774
|
};
|
|
743
775
|
|
|
744
776
|
type RequestWireStatus = 'open' | 'paid' | 'declined' | 'expired';
|
|
@@ -826,6 +858,7 @@ declare class Requests implements PaymentsRequestsApi {
|
|
|
826
858
|
private now;
|
|
827
859
|
private ensureJournalLoaded;
|
|
828
860
|
private mutateJournal;
|
|
861
|
+
/** Idempotent for a same-transferId re-write: committed only ratchets up, createdAt kept. */
|
|
829
862
|
private writeLink;
|
|
830
863
|
private clearLink;
|
|
831
864
|
drainIncoming(): Promise<void>;
|
|
@@ -845,6 +878,18 @@ declare class Requests implements PaymentsRequestsApi {
|
|
|
845
878
|
}>;
|
|
846
879
|
pay(id: string): Promise<TransferResult>;
|
|
847
880
|
private payInner;
|
|
881
|
+
/**
|
|
882
|
+
* THE settlement invariant (#441 + the failed-respond P1): a settling link is
|
|
883
|
+
* removed ONLY by (a) a CONFIRMED paid respond — a 2xx, or the 409
|
|
884
|
+
* already-resolved absorb — or (b) a proven clean pre-commit failure
|
|
885
|
+
* (revertPayable). Nothing else removes one: not a network error, not a 5xx,
|
|
886
|
+
* not a reload. Every path that binds a request to a transfer outcome funnels
|
|
887
|
+
* through here — pay()'s clean success (respond now), pay()'s
|
|
888
|
+
* possibly-committed throw (respond deferred), and reconcile's deferred arms
|
|
889
|
+
* — so a failed respond always leaves the link + 'settling' and the next
|
|
890
|
+
* reconcile pass (the committed-link override) retries the respond.
|
|
891
|
+
*/
|
|
892
|
+
private settle;
|
|
848
893
|
/** 'paid' respond leg: 409 = already resolved = idempotent success; other errors defer. */
|
|
849
894
|
private respondPaid;
|
|
850
895
|
decline(id: string): Promise<void>;
|
|
@@ -852,7 +897,9 @@ declare class Requests implements PaymentsRequestsApi {
|
|
|
852
897
|
reconcile(outcomes: ResumeOutcomes): Promise<void>;
|
|
853
898
|
private doReconcile;
|
|
854
899
|
private reconcileUnaccounted;
|
|
900
|
+
/** Deferred paid: the ONE settlement path again — a failed respond keeps the link. */
|
|
855
901
|
private resolvePaid;
|
|
902
|
+
/** Removal cause (b): a PROVEN clean outcome (pre-commit failure / server-aborted). */
|
|
856
903
|
private revertPayable;
|
|
857
904
|
}
|
|
858
905
|
|
|
@@ -899,6 +946,8 @@ interface PriceReader {
|
|
|
899
946
|
getPrices(tokenNames: string[]): Promise<Map<string, PriceQuote>>;
|
|
900
947
|
}
|
|
901
948
|
|
|
949
|
+
declare const ATTENTION_RESEED_REJECTED = "intent:reseed-rejected";
|
|
950
|
+
|
|
902
951
|
/**
|
|
903
952
|
* F13 makes `mint(params, { transferId, opIndex })` idempotent-recoverable — a
|
|
904
953
|
* same-seed re-CALL recovers the existing certification via the E.2 probe
|
|
@@ -919,6 +968,28 @@ interface FacadeSession {
|
|
|
919
968
|
start(): Promise<void>;
|
|
920
969
|
stop(): Promise<void>;
|
|
921
970
|
subscribeStream(stream: 'inventory' | 'mailbox' | 'payment_requests', handler: () => void): () => void;
|
|
971
|
+
/** §5.1: the latched server syncEpoch ('' before first server contact). */
|
|
972
|
+
currentEpoch(): string;
|
|
973
|
+
/**
|
|
974
|
+
* §5.1 restore hook — REQUIRED so an unwired restore protocol is a COMPILE
|
|
975
|
+
* ERROR: handlers run and are AWAITED on a syncEpoch change BEFORE any
|
|
976
|
+
* stream nudge resumes. The facade registers handleEpochChange here.
|
|
977
|
+
*/
|
|
978
|
+
subscribeEpochChange(handler: (epoch: string) => Promise<void>): () => void;
|
|
979
|
+
/**
|
|
980
|
+
* Optional connection-status feed (same wiring pattern as the streams; the
|
|
981
|
+
* emission point is the session's existing `connection:status` transition).
|
|
982
|
+
* The facade's heartbeat resets its backoff on a 'connected' recovery.
|
|
983
|
+
*/
|
|
984
|
+
subscribeStatus?(handler: (status: 'connected' | 'degraded' | 'offline') => void): () => void;
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* §5.1/§6 restore surface of the checkpoint store: re-POST the slot's cached
|
|
988
|
+
* encrypt-once ciphertext byte-identical after a server restore (insert-once,
|
|
989
|
+
* first-write-wins server-side). Returns false when no ciphertext is cached.
|
|
990
|
+
*/
|
|
991
|
+
interface CheckpointReseeder {
|
|
992
|
+
reseedCheckpoint(transferId: string, opIndex: number): Promise<boolean>;
|
|
922
993
|
}
|
|
923
994
|
interface IntentWireLike {
|
|
924
995
|
transferId: string;
|
|
@@ -937,7 +1008,8 @@ interface PaymentsFacadeDeps {
|
|
|
937
1008
|
client: FacadeClient;
|
|
938
1009
|
storagePort: StoragePort;
|
|
939
1010
|
deliveryPort: DeliveryPort;
|
|
940
|
-
|
|
1011
|
+
/** Reseeder REQUIRED: the restore protocol re-POSTs cached ciphertexts (§5.1). */
|
|
1012
|
+
checkpointStore: SplitCheckpointStore & CheckpointReseeder;
|
|
941
1013
|
/** Initial engine source; setEngine() swaps what FUTURE operations snapshot. */
|
|
942
1014
|
engineRef: () => ITokenEngine;
|
|
943
1015
|
kv: ScopedKV;
|
|
@@ -953,7 +1025,8 @@ interface PaymentsFacadeDeps {
|
|
|
953
1025
|
ownPubkey: string;
|
|
954
1026
|
ownNametag?: () => string | undefined;
|
|
955
1027
|
requestMemo: RequestMemoCodec;
|
|
956
|
-
|
|
1028
|
+
/** REQUIRED (§5.1): reads the session's current epoch — never a default. */
|
|
1029
|
+
syncEpoch: () => string;
|
|
957
1030
|
now?: () => number;
|
|
958
1031
|
newId?: () => string;
|
|
959
1032
|
workBudget?: number;
|
|
@@ -975,11 +1048,20 @@ declare class PaymentsFacade implements PaymentsV2 {
|
|
|
975
1048
|
private readonly receiveLoop;
|
|
976
1049
|
private readonly heldStates;
|
|
977
1050
|
private readonly ownPubkeyBytes;
|
|
1051
|
+
private readonly restoreDeps;
|
|
978
1052
|
readonly requests: Requests;
|
|
979
1053
|
private currentEngine;
|
|
980
1054
|
private readonly pendingOps;
|
|
981
1055
|
private unsubscribers;
|
|
982
1056
|
private started;
|
|
1057
|
+
private readonly heartbeat;
|
|
1058
|
+
private readonly converger;
|
|
1059
|
+
/** Resume single-flight (§7): ticks, start() and resumeNow() coalesce onto ONE pass. */
|
|
1060
|
+
private readonly resumeFlight;
|
|
1061
|
+
/** §5.1/§7: restore + convergence passes SERIALIZE here. */
|
|
1062
|
+
private readonly passChain;
|
|
1063
|
+
/** §7 ownership: ids with an in-process machine attempt — the pass never adopts one. */
|
|
1064
|
+
private readonly activeMoneyOps;
|
|
983
1065
|
constructor(deps: PaymentsFacadeDeps);
|
|
984
1066
|
start(): Promise<void>;
|
|
985
1067
|
/** §7 same-address restart gate: resolves only after in-flight ops settle. */
|
|
@@ -994,26 +1076,36 @@ declare class PaymentsFacade implements PaymentsV2 {
|
|
|
994
1076
|
before?: string;
|
|
995
1077
|
limit?: number;
|
|
996
1078
|
}): Promise<HistoryPage>;
|
|
1079
|
+
/** §4 pending-transfers UI surface — derived on read, never cached (convergence.ts). */
|
|
1080
|
+
pendingTransfers(): Promise<PendingTransfer[]>;
|
|
997
1081
|
send(request: SendRequest): Promise<TransferResult>;
|
|
998
1082
|
receive(): Promise<{
|
|
999
1083
|
transfers: IncomingTransfer[];
|
|
1000
1084
|
}>;
|
|
1001
1085
|
mint(coinId: string, amount: bigint): Promise<MintResult>;
|
|
1086
|
+
resumeNow(): Promise<void>;
|
|
1087
|
+
/** §5.1 restore — awaited by the session latch BEFORE streams resume; never coalesced onto a pre-restore pass. */
|
|
1088
|
+
handleEpochChange(_newEpoch: string): Promise<void>;
|
|
1089
|
+
/** One single-flighted pass + its reschedule: concurrent callers coalesce. */
|
|
1090
|
+
private runConvergencePass;
|
|
1091
|
+
private convergeBody;
|
|
1092
|
+
private nowMs;
|
|
1093
|
+
/** The ONE place a send() outcome is shaped: success emits in finishSend, a
|
|
1094
|
+
* CLEAN rejection emits `transfer:updated{status:'failed'}` here (§4). */
|
|
1095
|
+
private sendOutcome;
|
|
1096
|
+
/** Only a CLEAN failure (nothing certified, classifyError 'other') is 'failed'.
|
|
1097
|
+
* Keep-open/partial/conflict outcomes are pending/converging — labelling them
|
|
1098
|
+
* 'failed' invites a dApp re-send, i.e. a double-pay (#631/#676). */
|
|
1099
|
+
private emitCleanFailure;
|
|
1002
1100
|
private sendWithPolicy;
|
|
1003
1101
|
/** §5.6 cross-network deposit trap: refused BEFORE any reserve/certification. */
|
|
1004
1102
|
private requireSameNetworkRecipient;
|
|
1005
1103
|
private runAttempt;
|
|
1006
|
-
/**
|
|
1007
|
-
*
|
|
1008
|
-
* the machine BEFORE complete). Accumulate the settled set, then re-plan ONLY
|
|
1009
|
-
* the remainder under a NEW transferId — never the full amount.
|
|
1010
|
-
*/
|
|
1104
|
+
/** Partial (#677/#690): shortfall already durable (machine wrote it BEFORE
|
|
1105
|
+
* complete); accumulate settled, re-plan ONLY the remainder, NEW transferId. */
|
|
1011
1106
|
private consumePartial;
|
|
1012
|
-
/**
|
|
1013
|
-
*
|
|
1014
|
-
* backstop still 'open' (committed>0) → converge via the same machine's
|
|
1015
|
-
* resumeIntent; clean conflict with a demoted source → bounded full re-plan.
|
|
1016
|
-
*/
|
|
1107
|
+
/** Failure disposition: possibly-committed → rethrow UNWRAPPED; backstop
|
|
1108
|
+
* 'open' → converge via resumeIntent; clean demoted conflict → full re-plan. */
|
|
1017
1109
|
private disposeFailedAttempt;
|
|
1018
1110
|
/** #677/#690: ≥1 leg committed — the SAME machine, resumed in-process, converges it. */
|
|
1019
1111
|
private convergePartial;
|
|
@@ -1033,28 +1125,28 @@ declare class PaymentsFacade implements PaymentsV2 {
|
|
|
1033
1125
|
private refreshThenRelease;
|
|
1034
1126
|
private accumulate;
|
|
1035
1127
|
private finishSend;
|
|
1036
|
-
/**
|
|
1037
|
-
* With nothing delivered the error passes UNWRAPPED (identity + cause kept);
|
|
1038
|
-
* after ≥1 delivered leg EVERY failure surfaces as PartialSendConflictError
|
|
1039
|
-
* over the accumulated settled set — never bare, never a full-amount retry.
|
|
1040
|
-
*/
|
|
1128
|
+
/** Nothing delivered → UNWRAPPED; after ≥1 delivered leg every failure surfaces as PartialSendConflictError over the settled set. */
|
|
1041
1129
|
private partialize;
|
|
1042
1130
|
/** #441: possibly-committed errors must carry the transferId for the settling journal. */
|
|
1043
1131
|
private stampTransferId;
|
|
1044
1132
|
private softAbort;
|
|
1045
1133
|
private mintInner;
|
|
1134
|
+
private mintUnderJournal;
|
|
1046
1135
|
private finalizeMint;
|
|
1136
|
+
/** @returns how many journal entries were RESOLVED (cleared) — heartbeat progress. */
|
|
1047
1137
|
private replayMints;
|
|
1048
1138
|
private replayMint;
|
|
1049
1139
|
private mintParams;
|
|
1050
1140
|
private tokenInServerInventory;
|
|
1051
1141
|
private engine;
|
|
1052
1142
|
private newId;
|
|
1053
|
-
private runResume;
|
|
1054
1143
|
private seedHeldStates;
|
|
1055
1144
|
private toUiToken;
|
|
1056
1145
|
private track;
|
|
1057
1146
|
private trackTail;
|
|
1058
1147
|
}
|
|
1059
1148
|
|
|
1060
|
-
|
|
1149
|
+
declare const HEARTBEAT_SEED_MS = 5000;
|
|
1150
|
+
declare const HEARTBEAT_CAP_MS = 120000;
|
|
1151
|
+
|
|
1152
|
+
export { ATTENTION_MINT_UNRESOLVED, ATTENTION_RESEED_REJECTED, type ApplyDeltaResult, type CheckpointReseeder, type DeliverOptions, type DeliveryJournalEntry, type DeliveryPort, type DeliveryReceipt, type DeterministicMintCapable, type FacadeClient, type FacadeSession, HEARTBEAT_CAP_MS, HEARTBEAT_SEED_MS, type HistoryEntry, type HistoryPage, type IncomingDelivery, type IntentBackstopEntry, type IntentPayload, type InventoryAsset, type InventoryItem, type InventoryPage, MAX_RESELECT, type MintJournalEntry, type MintResult, type OpOutcome, type OutcomeClass, type PaymentRequestStatus, type PaymentRequestView, PaymentsFacade, type PaymentsFacadeDeps, type PaymentsRequestsApi, type PaymentsV2, type PaymentsV2Events, type PendingTransfer, type PlannedOp, type RecipientInfo, STORE_KEYS, type ScopedKV, type SendRequest, type SettlingLink, type ShortfallEntry, type StoragePort, type StreamCursor, type StreamName, createScopedKV, supportsDeterministicMint };
|