@unicitylabs/sphere-sdk 0.13.3-dev.1 → 0.13.3-dev.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +4319 -3958
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +350 -766
- package/dist/core/index.d.ts +350 -766
- package/dist/core/index.js +4319 -3958
- 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/nodejs/index.d.cts +208 -208
- package/dist/impl/nodejs/index.d.ts +208 -208
- package/dist/impl/shared/wallet-api/index.d.cts +208 -208
- package/dist/impl/shared/wallet-api/index.d.ts +208 -208
- package/dist/index.cjs +4325 -3964
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +613 -1029
- package/dist/index.d.ts +613 -1029
- package/dist/index.js +4325 -3964
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/core/index.d.ts
CHANGED
|
@@ -927,6 +927,237 @@ interface TombstoneEntry {
|
|
|
927
927
|
timestamp: number;
|
|
928
928
|
}
|
|
929
929
|
|
|
930
|
+
/**
|
|
931
|
+
* transport/delivery-provider.ts — the `DeliveryProvider` port (sdk-changes S7,
|
|
932
|
+
* covenant §3.1-6).
|
|
933
|
+
*
|
|
934
|
+
* The seam that keeps the delivery rail swappable. In Unicity, a transfer —
|
|
935
|
+
* after certification — is just a file handoff, so the port is deliberately
|
|
936
|
+
* tiny: hand a finished token blob to a recipient, pull incoming deliveries,
|
|
937
|
+
* acknowledge them. `WalletApiMailboxProvider`
|
|
938
|
+
* (impl/shared/wallet-api/WalletApiMailboxProvider.ts) is the reference
|
|
939
|
+
* implementation; anything that can move a file can implement it (the port
|
|
940
|
+
* shape must not preclude the old Nostr transport or a future federated
|
|
941
|
+
* transport — neither is a deliverable here).
|
|
942
|
+
*
|
|
943
|
+
* Normative shapes (sdk-changes S7):
|
|
944
|
+
* - `DeliveryReceipt = { deliveryId }`
|
|
945
|
+
* - `IncomingDelivery = { deliveryId, transferId?, senderPubkey?, memo?,
|
|
946
|
+
* fetchBlob(), cursor }`
|
|
947
|
+
* - `deliveryId` is the **content-derived** entry id —
|
|
948
|
+
* `hex(SHA-256(tokenId bytes ‖ stateHash bytes))` — NEVER a server-assigned
|
|
949
|
+
* row id or seq (covenant §3.1-4; the contract suite asserts it). It is
|
|
950
|
+
* computed client-side ({@link computeDeliveryId}) and must equal the
|
|
951
|
+
* backend's `entry_id` (ARCHITECTURE §6).
|
|
952
|
+
* - **Custody is a composition-time property, not a per-call flag**:
|
|
953
|
+
* implementations take `custody: 'inventory' | 'external'` at construction
|
|
954
|
+
* and every ack sends the corresponding `intoInventory` — delivery-only
|
|
955
|
+
* safety must never depend on remembering an option at a call site.
|
|
956
|
+
* - Implementations MUST keep a **persistent `(tokenId, stateHash)` seen-set**
|
|
957
|
+
* for incoming deliveries: the recipient-side replay guard is part of the
|
|
958
|
+
* port contract, not a server promise (the recipient never trusts the
|
|
959
|
+
* backend — ARCHITECTURE §8.2). `deliveryId` is the canonical hash encoding
|
|
960
|
+
* of exactly that pair, so a persistent deliveryId set satisfies this.
|
|
961
|
+
*/
|
|
962
|
+
/** Receipt for a delivered blob. `deliveryId` is content-derived — see module doc. */
|
|
963
|
+
interface DeliveryReceipt {
|
|
964
|
+
deliveryId: string;
|
|
965
|
+
}
|
|
966
|
+
/** Options for {@link DeliveryProvider.deliver}. */
|
|
967
|
+
interface DeliverOptions {
|
|
968
|
+
/**
|
|
969
|
+
* The send's transferId (the E.3 intent id / realization seed). Recorded
|
|
970
|
+
* with the delivery so the recipient can group multi-token payments and the
|
|
971
|
+
* backend can evidence-check the sender's removals (ARCHITECTURE §5.3/§6).
|
|
972
|
+
*/
|
|
973
|
+
transferId: string;
|
|
974
|
+
/** Optional human memo. Implementations encrypt it client-side (S6). */
|
|
975
|
+
memo?: string;
|
|
976
|
+
/**
|
|
977
|
+
* The SENDER's own nametag (without a leading `@`), so the recipient can
|
|
978
|
+
* render the human identity instead of a raw pubkey ("Someone"). Bundled
|
|
979
|
+
* with the memo into ONE recipient-addressed (ECDH) `enc1.` envelope (S6) —
|
|
980
|
+
* the operator never sees it. Attached whenever the sender has a nametag OR
|
|
981
|
+
* a memo (so the nametag travels even on a memo-less transfer).
|
|
982
|
+
*/
|
|
983
|
+
senderNametag?: string;
|
|
984
|
+
}
|
|
985
|
+
/** One incoming delivery pulled from the feed. */
|
|
986
|
+
interface IncomingDelivery {
|
|
987
|
+
/** Content-derived id — `hex(SHA-256(tokenId bytes ‖ stateHash bytes))`. */
|
|
988
|
+
deliveryId: string;
|
|
989
|
+
/** The sender's transferId, when the transport carries it. */
|
|
990
|
+
transferId?: string;
|
|
991
|
+
/** The sender's pubkey, when the transport carries it. */
|
|
992
|
+
senderPubkey?: string;
|
|
993
|
+
/** Decrypted memo (S6), when present and decryptable. */
|
|
994
|
+
memo?: string;
|
|
995
|
+
/**
|
|
996
|
+
* The sender's nametag (without a leading `@`), decrypted from the same
|
|
997
|
+
* recipient-addressed delivery envelope as {@link memo} (S6). Lets the
|
|
998
|
+
* receiver render the human identity instead of a raw pubkey, with no
|
|
999
|
+
* Nostr/transport lookup. Absent when the envelope carried none or could
|
|
1000
|
+
* not be decrypted.
|
|
1001
|
+
*/
|
|
1002
|
+
senderNametag?: string;
|
|
1003
|
+
/** Fetch the finished token blob bytes (the encoded TokenBlob). */
|
|
1004
|
+
fetchBlob(): Promise<Uint8Array>;
|
|
1005
|
+
/** Transport-local resume cursor (opaque to callers). */
|
|
1006
|
+
cursor: string;
|
|
1007
|
+
}
|
|
1008
|
+
type DeliveryDisposition = 'claimed' | 'rejected';
|
|
1009
|
+
/**
|
|
1010
|
+
* The §9 wake streams a backend may nudge: `mailbox` (incoming deliveries),
|
|
1011
|
+
* `inventory` (owned-token set changed — e.g. a top-up or a claim on another
|
|
1012
|
+
* device), and `payment_requests` (a request created/answered). A wake on any
|
|
1013
|
+
* of these is a NUDGE — the consumer pulls that stream's cursor; correctness
|
|
1014
|
+
* never depends on the wake arriving (the poll backstop is the source of
|
|
1015
|
+
* truth).
|
|
1016
|
+
*/
|
|
1017
|
+
type WakeStream = 'inventory' | 'mailbox' | 'payment_requests';
|
|
1018
|
+
/**
|
|
1019
|
+
* True liveness of the realtime wake channel (§9), decoupled from sign-in
|
|
1020
|
+
* session state: `connecting`/`connected` — a socket is (being) established;
|
|
1021
|
+
* `reconnecting` — it dropped and is backing off to re-establish (the poll
|
|
1022
|
+
* backstop carries correctness meanwhile); `closed` — torn down intentionally.
|
|
1023
|
+
* The wake is a nudge, so this is informational for the frontend (a "live"
|
|
1024
|
+
* indicator) — never a correctness gate.
|
|
1025
|
+
*/
|
|
1026
|
+
type WakeChannelStatus = 'connecting' | 'connected' | 'reconnecting' | 'closed';
|
|
1027
|
+
/**
|
|
1028
|
+
* Custody mode (composition-time): `'inventory'` — acknowledged deliveries
|
|
1029
|
+
* enter the wallet-api inventory (the full wallet-api preset); `'external'` —
|
|
1030
|
+
* the app's own storage keeps custody and acks perform ZERO inventory writes
|
|
1031
|
+
* (the delivery-only preset, ARCHITECTURE §6 "delivery-only claim").
|
|
1032
|
+
*/
|
|
1033
|
+
type DeliveryCustody = 'inventory' | 'external';
|
|
1034
|
+
interface DeliveryProvider {
|
|
1035
|
+
/** Composition-time custody property — never a per-call flag (S7). */
|
|
1036
|
+
readonly custody: DeliveryCustody;
|
|
1037
|
+
/**
|
|
1038
|
+
* Bind the wallet identity (optional — implementations that authenticate or
|
|
1039
|
+
* encrypt per-wallet need it; mirrors `TokenStorageProvider.setIdentity`).
|
|
1040
|
+
*/
|
|
1041
|
+
setIdentity?(identity: {
|
|
1042
|
+
privateKey: string;
|
|
1043
|
+
chainPubkey: string;
|
|
1044
|
+
}): void;
|
|
1045
|
+
/**
|
|
1046
|
+
* #583 per-address client isolation: mint an INDEPENDENT delivery provider for
|
|
1047
|
+
* a different HD address, backed by its OWN authenticated client + wake socket
|
|
1048
|
+
* (mirrors `TokenStorageProvider.createForAddress`). Implementations that hold
|
|
1049
|
+
* a single mutable identity+session per instance (e.g. the wallet-api mailbox
|
|
1050
|
+
* over one `WalletApiClient`) provide this so `Sphere.switchToAddress` can give
|
|
1051
|
+
* each address its OWN delivery instance — an orphaned previous-address pump
|
|
1052
|
+
* then re-auths as ITS OWN owner (harmless) instead of driving a client that
|
|
1053
|
+
* was re-bound to the new owner. Stateless transports may omit it (the same
|
|
1054
|
+
* instance serves every address).
|
|
1055
|
+
*/
|
|
1056
|
+
createForAddress?(): DeliveryProvider;
|
|
1057
|
+
/**
|
|
1058
|
+
* Hand a finished token blob to a recipient. `recipientPubkey` is the
|
|
1059
|
+
* recipient's CHAIN pubkey (33-byte compressed secp256k1, hex) — the
|
|
1060
|
+
* canonical Unicity identity (ARCHITECTURE §4); transports that address
|
|
1061
|
+
* recipients differently resolve it themselves.
|
|
1062
|
+
*
|
|
1063
|
+
* MUST be idempotent per (token, state): re-delivering the same finished
|
|
1064
|
+
* blob — including after the recipient claimed — succeeds and returns the
|
|
1065
|
+
* same content-derived `deliveryId` (ARCHITECTURE §6 deposit idempotency).
|
|
1066
|
+
*/
|
|
1067
|
+
deliver(recipientPubkey: string, blob: Uint8Array, options: DeliverOptions): Promise<DeliveryReceipt>;
|
|
1068
|
+
/**
|
|
1069
|
+
* Pull-based feed of incoming deliveries since the given transport-local
|
|
1070
|
+
* cursor (or the provider's persisted cursor when omitted). Yields only
|
|
1071
|
+
* deliveries not yet in the persistent seen-set; completes when the feed is
|
|
1072
|
+
* drained — callers re-invoke on poll/wake. Feeds the existing
|
|
1073
|
+
* transport-agnostic `handleV2Transfer` (sdk-changes S3).
|
|
1074
|
+
*/
|
|
1075
|
+
incoming(sinceCursor?: string): AsyncIterable<IncomingDelivery>;
|
|
1076
|
+
/**
|
|
1077
|
+
* Acknowledge a delivery: `'claimed'` accepts it (with the provider's
|
|
1078
|
+
* composition-time custody), `'rejected'` marks it locally-unverifiable —
|
|
1079
|
+
* terminal for discovery only (the entry stays claimable server-side and
|
|
1080
|
+
* its blob is retained — ARCHITECTURE §6). Both record the delivery in the
|
|
1081
|
+
* persistent seen-set.
|
|
1082
|
+
*/
|
|
1083
|
+
ack(deliveryId: string, disposition: DeliveryDisposition): Promise<void>;
|
|
1084
|
+
/**
|
|
1085
|
+
* Optional batch acknowledge (#623): claim and reject whole pages of incoming deliveries in a
|
|
1086
|
+
* single request each, instead of one per entry — so draining a large inbox (a long-offline or
|
|
1087
|
+
* service wallet) doesn't fire thousands of writes and trip the per-owner rate limit. Same
|
|
1088
|
+
* semantics as {@link ack}: the seen-set records only entries that were acked successfully, so a
|
|
1089
|
+
* partial/failed batch is re-listed and re-processed (idempotent claim, §6). A provider that does
|
|
1090
|
+
* not implement it (e.g. the relay no-op) is driven via per-entry {@link ack}.
|
|
1091
|
+
*/
|
|
1092
|
+
ackBatch?(claimed: string[], rejected: string[]): Promise<void>;
|
|
1093
|
+
/**
|
|
1094
|
+
* Optional batch deliver (#699): hand N finished blobs to ONE recipient with a single deposit
|
|
1095
|
+
* request (and one upload-urls request) instead of N — a multi-source send then costs O(1)
|
|
1096
|
+
* against the backend's deposit rate limit regardless of fragmentation. Optional like
|
|
1097
|
+
* {@link ackBatch}: the port must not preclude the relay transport or a future federated one,
|
|
1098
|
+
* and neither has a batch primitive — callers probe and fall back to per-blob {@link deliver}.
|
|
1099
|
+
*
|
|
1100
|
+
* Semantically equivalent to awaiting {@link deliver} once per blob, in order:
|
|
1101
|
+
* - receipts return in REQUEST order; each `deliveryId` is the content-derived entry id
|
|
1102
|
+
* (covenant §3.1-4 — NEVER the batch endpoint's server-assigned seq);
|
|
1103
|
+
* - idempotent per (token, state) exactly like {@link deliver};
|
|
1104
|
+
* - `options` apply to every blob (one send = one transferId/memo/senderNametag);
|
|
1105
|
+
* - throws when ANY blob could not be deposited — blobs that DID land are absorbed
|
|
1106
|
+
* idempotently when the caller retries, batched or per-blob.
|
|
1107
|
+
*/
|
|
1108
|
+
deliverBatch?(recipientPubkey: string, blobs: Uint8Array[], options: DeliverOptions): Promise<DeliveryReceipt[]>;
|
|
1109
|
+
/**
|
|
1110
|
+
* Optional wake hook: `callback` fires with the {@link WakeStream} that was
|
|
1111
|
+
* nudged when new data may be available on it (e.g. a WS nudge — never a
|
|
1112
|
+
* correctness dependency, ARCHITECTURE §9). The wallet-api wake socket
|
|
1113
|
+
* multiplexes all three owner streams (`mailbox` | `inventory` |
|
|
1114
|
+
* `payment_requests`); the consumer routes each to that stream's pull.
|
|
1115
|
+
*
|
|
1116
|
+
* The underlying socket SELF-HEALS (§9): it reconnects with backoff on any
|
|
1117
|
+
* drop and a liveness watchdog force-reconnects a half-open socket. On every
|
|
1118
|
+
* (re)connect the consumer MUST run a full catch-up pull of every stream —
|
|
1119
|
+
* wakes missed while the socket was dead are not replayed — so `callback`
|
|
1120
|
+
* fires once for EACH stream on (re)connect (a synthetic catch-up nudge).
|
|
1121
|
+
* `onStatus` (optional) surfaces true socket liveness for the frontend,
|
|
1122
|
+
* decoupled from sign-in state. Returns an unsubscribe function.
|
|
1123
|
+
*/
|
|
1124
|
+
onWake?(callback: (stream: WakeStream) => void, onStatus?: (status: WakeChannelStatus) => void): () => void;
|
|
1125
|
+
/**
|
|
1126
|
+
* Late-bind the backend-true (tokenId, stateHash) derivation —
|
|
1127
|
+
* `ITokenEngine.deliveryKeys`. Compositions are engine-less (the engine is
|
|
1128
|
+
* built later); the module that owns both (PaymentsModule) binds this at
|
|
1129
|
+
* init. Implementations that derive ids (S7) MUST use it and fail loudly if
|
|
1130
|
+
* unbound; transports that don't derive may omit the method.
|
|
1131
|
+
*/
|
|
1132
|
+
bindDeliveryKeys?(derive: (blobBytes: Uint8Array) => Promise<{
|
|
1133
|
+
tokenId: string;
|
|
1134
|
+
stateHash: string;
|
|
1135
|
+
}>): void;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
/**
|
|
1139
|
+
* Receive + delivery: `receive()`, the `handleV2Transfer` receiver, the
|
|
1140
|
+
* PENDING_V2_DELIVERIES journal, the hoisted send delivery pass and the bounded
|
|
1141
|
+
* replay + poison budget. The token map and `save()` stay in PaymentsModule.
|
|
1142
|
+
*/
|
|
1143
|
+
|
|
1144
|
+
/**
|
|
1145
|
+
* @deprecated v2 transfers arrive as finished tokens — there is no finalization
|
|
1146
|
+
* phase. The options are accepted for backwards compatibility and ignored.
|
|
1147
|
+
*/
|
|
1148
|
+
interface ReceiveOptions {
|
|
1149
|
+
/** @deprecated Ignored — v2 tokens are stored confirmed on receipt. */
|
|
1150
|
+
finalize?: boolean;
|
|
1151
|
+
/** @deprecated Ignored. */
|
|
1152
|
+
timeout?: number;
|
|
1153
|
+
/** @deprecated Ignored. */
|
|
1154
|
+
pollInterval?: number;
|
|
1155
|
+
}
|
|
1156
|
+
interface ReceiveResult {
|
|
1157
|
+
/** Newly received incoming transfers. */
|
|
1158
|
+
transfers: IncomingTransfer[];
|
|
1159
|
+
}
|
|
1160
|
+
|
|
930
1161
|
/**
|
|
931
1162
|
* Transport Provider Interface
|
|
932
1163
|
* Platform-independent P2P messaging abstraction
|
|
@@ -1241,258 +1472,50 @@ interface IncomingBroadcast {
|
|
|
1241
1472
|
timestamp: number;
|
|
1242
1473
|
}
|
|
1243
1474
|
type BroadcastHandler = (broadcast: IncomingBroadcast) => void;
|
|
1244
|
-
type TransportEventType = 'transport:connected' | 'transport:disconnected' | 'transport:reconnecting' | 'transport:error' | 'transport:relay_added' | 'transport:relay_removed' | 'message:received' | 'message:sent' | 'transfer:received' | 'transfer:sent';
|
|
1245
|
-
interface TransportEvent {
|
|
1246
|
-
type: TransportEventType;
|
|
1247
|
-
timestamp: number;
|
|
1248
|
-
data?: unknown;
|
|
1249
|
-
error?: string;
|
|
1250
|
-
}
|
|
1251
|
-
type TransportEventCallback = (event: TransportEvent) => void;
|
|
1252
|
-
/**
|
|
1253
|
-
* Resolved peer identity information.
|
|
1254
|
-
* Returned by resolve methods — contains all public address formats for a peer.
|
|
1255
|
-
* The nametag field is optional (only present if a nametag is registered).
|
|
1256
|
-
*/
|
|
1257
|
-
interface PeerInfo {
|
|
1258
|
-
/** Nametag name (without @), if registered */
|
|
1259
|
-
nametag?: string;
|
|
1260
|
-
/** Transport-specific pubkey (for messaging/encryption) */
|
|
1261
|
-
transportPubkey: string;
|
|
1262
|
-
/** 33-byte compressed secp256k1 public key (for L3 chain) */
|
|
1263
|
-
chainPubkey: string;
|
|
1264
|
-
/** L3 DIRECT address (DIRECT://...) */
|
|
1265
|
-
directAddress: string;
|
|
1266
|
-
/** Event timestamp */
|
|
1267
|
-
timestamp: number;
|
|
1268
|
-
}
|
|
1269
|
-
interface IncomingReadReceipt {
|
|
1270
|
-
/** Transport-specific pubkey of the sender who read the message */
|
|
1271
|
-
senderTransportPubkey: string;
|
|
1272
|
-
/** Event ID of the message that was read */
|
|
1273
|
-
messageEventId: string;
|
|
1274
|
-
/** Timestamp */
|
|
1275
|
-
timestamp: number;
|
|
1276
|
-
}
|
|
1277
|
-
type ReadReceiptHandler = (receipt: IncomingReadReceipt) => void;
|
|
1278
|
-
interface IncomingTypingIndicator {
|
|
1279
|
-
/** Transport-specific pubkey of the sender who is typing */
|
|
1280
|
-
senderTransportPubkey: string;
|
|
1281
|
-
/** Sender's nametag (if known) */
|
|
1282
|
-
senderNametag?: string;
|
|
1283
|
-
/** Timestamp */
|
|
1284
|
-
timestamp: number;
|
|
1285
|
-
}
|
|
1286
|
-
type TypingIndicatorHandler = (indicator: IncomingTypingIndicator) => void;
|
|
1287
|
-
type ComposingHandler = (indicator: ComposingIndicator) => void;
|
|
1288
|
-
|
|
1289
|
-
/**
|
|
1290
|
-
* transport/delivery-provider.ts — the `DeliveryProvider` port (sdk-changes S7,
|
|
1291
|
-
* covenant §3.1-6).
|
|
1292
|
-
*
|
|
1293
|
-
* The seam that keeps the delivery rail swappable. In Unicity, a transfer —
|
|
1294
|
-
* after certification — is just a file handoff, so the port is deliberately
|
|
1295
|
-
* tiny: hand a finished token blob to a recipient, pull incoming deliveries,
|
|
1296
|
-
* acknowledge them. `WalletApiMailboxProvider`
|
|
1297
|
-
* (impl/shared/wallet-api/WalletApiMailboxProvider.ts) is the reference
|
|
1298
|
-
* implementation; anything that can move a file can implement it (the port
|
|
1299
|
-
* shape must not preclude the old Nostr transport or a future federated
|
|
1300
|
-
* transport — neither is a deliverable here).
|
|
1301
|
-
*
|
|
1302
|
-
* Normative shapes (sdk-changes S7):
|
|
1303
|
-
* - `DeliveryReceipt = { deliveryId }`
|
|
1304
|
-
* - `IncomingDelivery = { deliveryId, transferId?, senderPubkey?, memo?,
|
|
1305
|
-
* fetchBlob(), cursor }`
|
|
1306
|
-
* - `deliveryId` is the **content-derived** entry id —
|
|
1307
|
-
* `hex(SHA-256(tokenId bytes ‖ stateHash bytes))` — NEVER a server-assigned
|
|
1308
|
-
* row id or seq (covenant §3.1-4; the contract suite asserts it). It is
|
|
1309
|
-
* computed client-side ({@link computeDeliveryId}) and must equal the
|
|
1310
|
-
* backend's `entry_id` (ARCHITECTURE §6).
|
|
1311
|
-
* - **Custody is a composition-time property, not a per-call flag**:
|
|
1312
|
-
* implementations take `custody: 'inventory' | 'external'` at construction
|
|
1313
|
-
* and every ack sends the corresponding `intoInventory` — delivery-only
|
|
1314
|
-
* safety must never depend on remembering an option at a call site.
|
|
1315
|
-
* - Implementations MUST keep a **persistent `(tokenId, stateHash)` seen-set**
|
|
1316
|
-
* for incoming deliveries: the recipient-side replay guard is part of the
|
|
1317
|
-
* port contract, not a server promise (the recipient never trusts the
|
|
1318
|
-
* backend — ARCHITECTURE §8.2). `deliveryId` is the canonical hash encoding
|
|
1319
|
-
* of exactly that pair, so a persistent deliveryId set satisfies this.
|
|
1320
|
-
*/
|
|
1321
|
-
/** Receipt for a delivered blob. `deliveryId` is content-derived — see module doc. */
|
|
1322
|
-
interface DeliveryReceipt {
|
|
1323
|
-
deliveryId: string;
|
|
1324
|
-
}
|
|
1325
|
-
/** Options for {@link DeliveryProvider.deliver}. */
|
|
1326
|
-
interface DeliverOptions {
|
|
1327
|
-
/**
|
|
1328
|
-
* The send's transferId (the E.3 intent id / realization seed). Recorded
|
|
1329
|
-
* with the delivery so the recipient can group multi-token payments and the
|
|
1330
|
-
* backend can evidence-check the sender's removals (ARCHITECTURE §5.3/§6).
|
|
1331
|
-
*/
|
|
1332
|
-
transferId: string;
|
|
1333
|
-
/** Optional human memo. Implementations encrypt it client-side (S6). */
|
|
1334
|
-
memo?: string;
|
|
1335
|
-
/**
|
|
1336
|
-
* The SENDER's own nametag (without a leading `@`), so the recipient can
|
|
1337
|
-
* render the human identity instead of a raw pubkey ("Someone"). Bundled
|
|
1338
|
-
* with the memo into ONE recipient-addressed (ECDH) `enc1.` envelope (S6) —
|
|
1339
|
-
* the operator never sees it. Attached whenever the sender has a nametag OR
|
|
1340
|
-
* a memo (so the nametag travels even on a memo-less transfer).
|
|
1341
|
-
*/
|
|
1342
|
-
senderNametag?: string;
|
|
1343
|
-
}
|
|
1344
|
-
/** One incoming delivery pulled from the feed. */
|
|
1345
|
-
interface IncomingDelivery {
|
|
1346
|
-
/** Content-derived id — `hex(SHA-256(tokenId bytes ‖ stateHash bytes))`. */
|
|
1347
|
-
deliveryId: string;
|
|
1348
|
-
/** The sender's transferId, when the transport carries it. */
|
|
1349
|
-
transferId?: string;
|
|
1350
|
-
/** The sender's pubkey, when the transport carries it. */
|
|
1351
|
-
senderPubkey?: string;
|
|
1352
|
-
/** Decrypted memo (S6), when present and decryptable. */
|
|
1353
|
-
memo?: string;
|
|
1354
|
-
/**
|
|
1355
|
-
* The sender's nametag (without a leading `@`), decrypted from the same
|
|
1356
|
-
* recipient-addressed delivery envelope as {@link memo} (S6). Lets the
|
|
1357
|
-
* receiver render the human identity instead of a raw pubkey, with no
|
|
1358
|
-
* Nostr/transport lookup. Absent when the envelope carried none or could
|
|
1359
|
-
* not be decrypted.
|
|
1360
|
-
*/
|
|
1361
|
-
senderNametag?: string;
|
|
1362
|
-
/** Fetch the finished token blob bytes (the encoded TokenBlob). */
|
|
1363
|
-
fetchBlob(): Promise<Uint8Array>;
|
|
1364
|
-
/** Transport-local resume cursor (opaque to callers). */
|
|
1365
|
-
cursor: string;
|
|
1366
|
-
}
|
|
1367
|
-
type DeliveryDisposition = 'claimed' | 'rejected';
|
|
1368
|
-
/**
|
|
1369
|
-
* The §9 wake streams a backend may nudge: `mailbox` (incoming deliveries),
|
|
1370
|
-
* `inventory` (owned-token set changed — e.g. a top-up or a claim on another
|
|
1371
|
-
* device), and `payment_requests` (a request created/answered). A wake on any
|
|
1372
|
-
* of these is a NUDGE — the consumer pulls that stream's cursor; correctness
|
|
1373
|
-
* never depends on the wake arriving (the poll backstop is the source of
|
|
1374
|
-
* truth).
|
|
1375
|
-
*/
|
|
1376
|
-
type WakeStream = 'inventory' | 'mailbox' | 'payment_requests';
|
|
1377
|
-
/**
|
|
1378
|
-
* True liveness of the realtime wake channel (§9), decoupled from sign-in
|
|
1379
|
-
* session state: `connecting`/`connected` — a socket is (being) established;
|
|
1380
|
-
* `reconnecting` — it dropped and is backing off to re-establish (the poll
|
|
1381
|
-
* backstop carries correctness meanwhile); `closed` — torn down intentionally.
|
|
1382
|
-
* The wake is a nudge, so this is informational for the frontend (a "live"
|
|
1383
|
-
* indicator) — never a correctness gate.
|
|
1384
|
-
*/
|
|
1385
|
-
type WakeChannelStatus = 'connecting' | 'connected' | 'reconnecting' | 'closed';
|
|
1475
|
+
type TransportEventType = 'transport:connected' | 'transport:disconnected' | 'transport:reconnecting' | 'transport:error' | 'transport:relay_added' | 'transport:relay_removed' | 'message:received' | 'message:sent' | 'transfer:received' | 'transfer:sent';
|
|
1476
|
+
interface TransportEvent {
|
|
1477
|
+
type: TransportEventType;
|
|
1478
|
+
timestamp: number;
|
|
1479
|
+
data?: unknown;
|
|
1480
|
+
error?: string;
|
|
1481
|
+
}
|
|
1482
|
+
type TransportEventCallback = (event: TransportEvent) => void;
|
|
1386
1483
|
/**
|
|
1387
|
-
*
|
|
1388
|
-
*
|
|
1389
|
-
*
|
|
1390
|
-
* (the delivery-only preset, ARCHITECTURE §6 "delivery-only claim").
|
|
1484
|
+
* Resolved peer identity information.
|
|
1485
|
+
* Returned by resolve methods — contains all public address formats for a peer.
|
|
1486
|
+
* The nametag field is optional (only present if a nametag is registered).
|
|
1391
1487
|
*/
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
/**
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
* recipients differently resolve it themselves.
|
|
1421
|
-
*
|
|
1422
|
-
* MUST be idempotent per (token, state): re-delivering the same finished
|
|
1423
|
-
* blob — including after the recipient claimed — succeeds and returns the
|
|
1424
|
-
* same content-derived `deliveryId` (ARCHITECTURE §6 deposit idempotency).
|
|
1425
|
-
*/
|
|
1426
|
-
deliver(recipientPubkey: string, blob: Uint8Array, options: DeliverOptions): Promise<DeliveryReceipt>;
|
|
1427
|
-
/**
|
|
1428
|
-
* Pull-based feed of incoming deliveries since the given transport-local
|
|
1429
|
-
* cursor (or the provider's persisted cursor when omitted). Yields only
|
|
1430
|
-
* deliveries not yet in the persistent seen-set; completes when the feed is
|
|
1431
|
-
* drained — callers re-invoke on poll/wake. Feeds the existing
|
|
1432
|
-
* transport-agnostic `handleV2Transfer` (sdk-changes S3).
|
|
1433
|
-
*/
|
|
1434
|
-
incoming(sinceCursor?: string): AsyncIterable<IncomingDelivery>;
|
|
1435
|
-
/**
|
|
1436
|
-
* Acknowledge a delivery: `'claimed'` accepts it (with the provider's
|
|
1437
|
-
* composition-time custody), `'rejected'` marks it locally-unverifiable —
|
|
1438
|
-
* terminal for discovery only (the entry stays claimable server-side and
|
|
1439
|
-
* its blob is retained — ARCHITECTURE §6). Both record the delivery in the
|
|
1440
|
-
* persistent seen-set.
|
|
1441
|
-
*/
|
|
1442
|
-
ack(deliveryId: string, disposition: DeliveryDisposition): Promise<void>;
|
|
1443
|
-
/**
|
|
1444
|
-
* Optional batch acknowledge (#623): claim and reject whole pages of incoming deliveries in a
|
|
1445
|
-
* single request each, instead of one per entry — so draining a large inbox (a long-offline or
|
|
1446
|
-
* service wallet) doesn't fire thousands of writes and trip the per-owner rate limit. Same
|
|
1447
|
-
* semantics as {@link ack}: the seen-set records only entries that were acked successfully, so a
|
|
1448
|
-
* partial/failed batch is re-listed and re-processed (idempotent claim, §6). A provider that does
|
|
1449
|
-
* not implement it (e.g. the relay no-op) is driven via per-entry {@link ack}.
|
|
1450
|
-
*/
|
|
1451
|
-
ackBatch?(claimed: string[], rejected: string[]): Promise<void>;
|
|
1452
|
-
/**
|
|
1453
|
-
* Optional batch deliver (#699): hand N finished blobs to ONE recipient with a single deposit
|
|
1454
|
-
* request (and one upload-urls request) instead of N — a multi-source send then costs O(1)
|
|
1455
|
-
* against the backend's deposit rate limit regardless of fragmentation. Optional like
|
|
1456
|
-
* {@link ackBatch}: the port must not preclude the relay transport or a future federated one,
|
|
1457
|
-
* and neither has a batch primitive — callers probe and fall back to per-blob {@link deliver}.
|
|
1458
|
-
*
|
|
1459
|
-
* Semantically equivalent to awaiting {@link deliver} once per blob, in order:
|
|
1460
|
-
* - receipts return in REQUEST order; each `deliveryId` is the content-derived entry id
|
|
1461
|
-
* (covenant §3.1-4 — NEVER the batch endpoint's server-assigned seq);
|
|
1462
|
-
* - idempotent per (token, state) exactly like {@link deliver};
|
|
1463
|
-
* - `options` apply to every blob (one send = one transferId/memo/senderNametag);
|
|
1464
|
-
* - throws when ANY blob could not be deposited — blobs that DID land are absorbed
|
|
1465
|
-
* idempotently when the caller retries, batched or per-blob.
|
|
1466
|
-
*/
|
|
1467
|
-
deliverBatch?(recipientPubkey: string, blobs: Uint8Array[], options: DeliverOptions): Promise<DeliveryReceipt[]>;
|
|
1468
|
-
/**
|
|
1469
|
-
* Optional wake hook: `callback` fires with the {@link WakeStream} that was
|
|
1470
|
-
* nudged when new data may be available on it (e.g. a WS nudge — never a
|
|
1471
|
-
* correctness dependency, ARCHITECTURE §9). The wallet-api wake socket
|
|
1472
|
-
* multiplexes all three owner streams (`mailbox` | `inventory` |
|
|
1473
|
-
* `payment_requests`); the consumer routes each to that stream's pull.
|
|
1474
|
-
*
|
|
1475
|
-
* The underlying socket SELF-HEALS (§9): it reconnects with backoff on any
|
|
1476
|
-
* drop and a liveness watchdog force-reconnects a half-open socket. On every
|
|
1477
|
-
* (re)connect the consumer MUST run a full catch-up pull of every stream —
|
|
1478
|
-
* wakes missed while the socket was dead are not replayed — so `callback`
|
|
1479
|
-
* fires once for EACH stream on (re)connect (a synthetic catch-up nudge).
|
|
1480
|
-
* `onStatus` (optional) surfaces true socket liveness for the frontend,
|
|
1481
|
-
* decoupled from sign-in state. Returns an unsubscribe function.
|
|
1482
|
-
*/
|
|
1483
|
-
onWake?(callback: (stream: WakeStream) => void, onStatus?: (status: WakeChannelStatus) => void): () => void;
|
|
1484
|
-
/**
|
|
1485
|
-
* Late-bind the backend-true (tokenId, stateHash) derivation —
|
|
1486
|
-
* `ITokenEngine.deliveryKeys`. Compositions are engine-less (the engine is
|
|
1487
|
-
* built later); the module that owns both (PaymentsModule) binds this at
|
|
1488
|
-
* init. Implementations that derive ids (S7) MUST use it and fail loudly if
|
|
1489
|
-
* unbound; transports that don't derive may omit the method.
|
|
1490
|
-
*/
|
|
1491
|
-
bindDeliveryKeys?(derive: (blobBytes: Uint8Array) => Promise<{
|
|
1492
|
-
tokenId: string;
|
|
1493
|
-
stateHash: string;
|
|
1494
|
-
}>): void;
|
|
1488
|
+
interface PeerInfo {
|
|
1489
|
+
/** Nametag name (without @), if registered */
|
|
1490
|
+
nametag?: string;
|
|
1491
|
+
/** Transport-specific pubkey (for messaging/encryption) */
|
|
1492
|
+
transportPubkey: string;
|
|
1493
|
+
/** 33-byte compressed secp256k1 public key (for L3 chain) */
|
|
1494
|
+
chainPubkey: string;
|
|
1495
|
+
/** L3 DIRECT address (DIRECT://...) */
|
|
1496
|
+
directAddress: string;
|
|
1497
|
+
/** Event timestamp */
|
|
1498
|
+
timestamp: number;
|
|
1499
|
+
}
|
|
1500
|
+
interface IncomingReadReceipt {
|
|
1501
|
+
/** Transport-specific pubkey of the sender who read the message */
|
|
1502
|
+
senderTransportPubkey: string;
|
|
1503
|
+
/** Event ID of the message that was read */
|
|
1504
|
+
messageEventId: string;
|
|
1505
|
+
/** Timestamp */
|
|
1506
|
+
timestamp: number;
|
|
1507
|
+
}
|
|
1508
|
+
type ReadReceiptHandler = (receipt: IncomingReadReceipt) => void;
|
|
1509
|
+
interface IncomingTypingIndicator {
|
|
1510
|
+
/** Transport-specific pubkey of the sender who is typing */
|
|
1511
|
+
senderTransportPubkey: string;
|
|
1512
|
+
/** Sender's nametag (if known) */
|
|
1513
|
+
senderNametag?: string;
|
|
1514
|
+
/** Timestamp */
|
|
1515
|
+
timestamp: number;
|
|
1495
1516
|
}
|
|
1517
|
+
type TypingIndicatorHandler = (indicator: IncomingTypingIndicator) => void;
|
|
1518
|
+
type ComposingHandler = (indicator: ComposingIndicator) => void;
|
|
1496
1519
|
|
|
1497
1520
|
/**
|
|
1498
1521
|
* WebSocket Abstraction
|
|
@@ -1940,22 +1963,6 @@ interface PriceProvider {
|
|
|
1940
1963
|
* Single source of truth: {@link HistoryRecord} in `storage/storage-provider.ts`.
|
|
1941
1964
|
*/
|
|
1942
1965
|
type TransactionHistoryEntry = HistoryRecord;
|
|
1943
|
-
/**
|
|
1944
|
-
* @deprecated v2 transfers arrive as finished tokens — there is no finalization
|
|
1945
|
-
* phase. The options are accepted for backwards compatibility and ignored.
|
|
1946
|
-
*/
|
|
1947
|
-
interface ReceiveOptions {
|
|
1948
|
-
/** @deprecated Ignored — v2 tokens are stored confirmed on receipt. */
|
|
1949
|
-
finalize?: boolean;
|
|
1950
|
-
/** @deprecated Ignored. */
|
|
1951
|
-
timeout?: number;
|
|
1952
|
-
/** @deprecated Ignored. */
|
|
1953
|
-
pollInterval?: number;
|
|
1954
|
-
}
|
|
1955
|
-
interface ReceiveResult {
|
|
1956
|
-
/** Newly received incoming transfers. */
|
|
1957
|
-
transfers: IncomingTransfer[];
|
|
1958
|
-
}
|
|
1959
1966
|
interface PaymentsModuleConfig {
|
|
1960
1967
|
/** Auto-sync after operations */
|
|
1961
1968
|
autoSync?: boolean;
|
|
@@ -2189,15 +2196,17 @@ declare class PaymentsModule {
|
|
|
2189
2196
|
private readonly moduleConfig;
|
|
2190
2197
|
private deps;
|
|
2191
2198
|
private tokens;
|
|
2192
|
-
private tombstones;
|
|
2193
|
-
private tombstoneKeySet;
|
|
2194
|
-
private _historyCache;
|
|
2195
2199
|
private nametags;
|
|
2196
|
-
|
|
2197
|
-
private
|
|
2198
|
-
|
|
2199
|
-
private
|
|
2200
|
-
|
|
2200
|
+
/** Inventory reads: balances/assets, the token accessors, tombstones, validate(). */
|
|
2201
|
+
private readonly inventory;
|
|
2202
|
+
/** Payment requests (incoming + outgoing, the S4 pump, the #441 journal). */
|
|
2203
|
+
private readonly requests;
|
|
2204
|
+
/** Transaction history (the cache, the dedupKey rules, the §10 server log). */
|
|
2205
|
+
private readonly history;
|
|
2206
|
+
/** E.3/E.4 intent resume (the sign-in replay of OPEN send intents). */
|
|
2207
|
+
private readonly intents;
|
|
2208
|
+
/** Receive + delivery (receive(), the v2 receiver, the journal, the replay budget). */
|
|
2209
|
+
private readonly deliveries;
|
|
2201
2210
|
/** The single delivery seam — an injected provider or the transport adapter. */
|
|
2202
2211
|
private delivery;
|
|
2203
2212
|
/** Set only when a provider was INJECTED — gates the incoming pump (S3). */
|
|
@@ -2214,35 +2223,6 @@ declare class PaymentsModule {
|
|
|
2214
2223
|
/** S6 field-encryption key (intent payloads, history memos) — per identity. */
|
|
2215
2224
|
private fieldEncryptionKey;
|
|
2216
2225
|
private checkpointStore;
|
|
2217
|
-
private prPollTimer;
|
|
2218
|
-
/** Coalesces concurrent payment-request pump runs. */
|
|
2219
|
-
private prPumpInFlight;
|
|
2220
|
-
/**
|
|
2221
|
-
* Set after the once-per-session full incoming hydration (#556): the surfaced
|
|
2222
|
-
* incoming list is in-memory only, so on a fresh engine the CURRENT state of
|
|
2223
|
-
* ALL incoming requests — open AND resolved (paid/declined/expired) — must be
|
|
2224
|
-
* rebuilt from a `role=incoming&since=0` pull, not just the still-open ones.
|
|
2225
|
-
* A status-filtered bootstrap (the pre-#556 `status=open` scan) dropped
|
|
2226
|
-
* requests resolved in a PRIOR session, so the payer reopened and the
|
|
2227
|
-
* 'Paid Successfully' request was gone (twin of #521/#549).
|
|
2228
|
-
*/
|
|
2229
|
-
private prBootstrapped;
|
|
2230
|
-
/**
|
|
2231
|
-
* #441 deferred-paid journal (durable, per network+identity): links a payment
|
|
2232
|
-
* request to the in-flight transfer of a possibly-committed pay so the request
|
|
2233
|
-
* is held NON-payable ('settling') until that transfer completes (→ 'paid',
|
|
2234
|
-
* server told) or aborts (→ payable, journal cleared). Keyed by request wire id
|
|
2235
|
-
* (== requestId for wallet-api-surfaced requests). The in-memory Map is the
|
|
2236
|
-
* synchronous source of truth used by the reload re-apply seam; it is
|
|
2237
|
-
* single-flight loaded and every read-modify-write is serialized through a tail
|
|
2238
|
-
* promise (the #679/#680 lesson: an unserialized RMW drops entries under
|
|
2239
|
-
* concurrency = a re-payable request = the double-pay this fix prevents).
|
|
2240
|
-
*/
|
|
2241
|
-
private settlingJournal;
|
|
2242
|
-
private settlingJournalLoad;
|
|
2243
|
-
private settlingJournalWrite;
|
|
2244
|
-
/** #441: guard overlapping resume reconciles (resumeOpenIntents has 2 fire-and-forget call sites). */
|
|
2245
|
-
private reconcileInFlight;
|
|
2246
2226
|
private loadedPromise;
|
|
2247
2227
|
private loaded;
|
|
2248
2228
|
/**
|
|
@@ -2259,20 +2239,6 @@ declare class PaymentsModule {
|
|
|
2259
2239
|
private loadInFlightOwner;
|
|
2260
2240
|
private loadRerunRequested;
|
|
2261
2241
|
private loadRerunTimer;
|
|
2262
|
-
/**
|
|
2263
|
-
* Owner (chainPubkey) whose server history hydration last completed —
|
|
2264
|
-
* enables the #642 incremental fast path in {@link hydrateHistoryFromServer}.
|
|
2265
|
-
* Reset on re-init (address switch). `serverSeenHistoryKeys` holds only
|
|
2266
|
-
* dedupKeys actually PULLED from the server (never locally-POSTed ones), so
|
|
2267
|
-
* the incremental stop condition can't be masked by our own fresh POSTs;
|
|
2268
|
-
* `incrementalHistoryPulls` forces a periodic full re-pull to bound the
|
|
2269
|
-
* staleness window if server keyset order ever diverges from arrival order.
|
|
2270
|
-
* `hydrationEpoch` guards a pull racing a same-owner re-init.
|
|
2271
|
-
*/
|
|
2272
|
-
private historyHydratedFor;
|
|
2273
|
-
private serverSeenHistoryKeys;
|
|
2274
|
-
private incrementalHistoryPulls;
|
|
2275
|
-
private hydrationEpoch;
|
|
2276
2242
|
private inventoryDebounceTimer;
|
|
2277
2243
|
private static readonly SYNC_DEBOUNCE_MS;
|
|
2278
2244
|
/** Quiet-then-escalate logging for the background wallet-api pumps (#630). */
|
|
@@ -2283,43 +2249,45 @@ declare class PaymentsModule {
|
|
|
2283
2249
|
private tokenChangeCallbacks;
|
|
2284
2250
|
private readonly reservationLedger;
|
|
2285
2251
|
private readonly spendPlanner;
|
|
2286
|
-
/**
|
|
2287
|
-
* Per-request single-flight for {@link payPaymentRequest}. The pay flow flips the request to
|
|
2288
|
-
* 'accepted' before it awaits send(), and the status guard re-admits 'accepted' (intended for a
|
|
2289
|
-
* sequential retry-after-failure) — so a concurrent double-tap / second session would otherwise
|
|
2290
|
-
* enter send() a second time and DOUBLE-PAY (each send picks a different token; the reservation
|
|
2291
|
-
* ledger is coin-scoped, not request-scoped). Concurrent calls for the same requestId coalesce
|
|
2292
|
-
* onto the first in-flight pay; the entry is cleared when it settles, so a later retry is unaffected.
|
|
2293
|
-
*/
|
|
2294
|
-
private readonly payInFlight;
|
|
2295
2252
|
private spendQueue;
|
|
2296
2253
|
/** Cache of parsed SdkToken data for synchronous queue re-evaluation */
|
|
2297
2254
|
private readonly parsedTokenCache;
|
|
2255
|
+
constructor(config?: PaymentsModuleConfig);
|
|
2298
2256
|
/**
|
|
2299
|
-
*
|
|
2300
|
-
*
|
|
2301
|
-
*
|
|
2257
|
+
* The narrow seam {@link TokenView} reaches back through. Live getters for
|
|
2258
|
+
* `deps` and `priceProvider` (both swapped on {@link initialize}); the token
|
|
2259
|
+
* map is handed over as a READ-ONLY view, so the inventory view never becomes
|
|
2260
|
+
* a second writer of it.
|
|
2302
2261
|
*/
|
|
2303
|
-
private
|
|
2304
|
-
/** Deferral window for recipient-quota (429) deliveries (#621). Overridable in tests. */
|
|
2305
|
-
private deliveryDeferralMs;
|
|
2262
|
+
private tokenViewHost;
|
|
2306
2263
|
/**
|
|
2307
|
-
*
|
|
2308
|
-
*
|
|
2309
|
-
*
|
|
2310
|
-
* `
|
|
2311
|
-
* delaying poison surfacing). Only one pass runs per module instance at a time.
|
|
2264
|
+
* The narrow seam {@link Delivery} reaches back through. Live getters for
|
|
2265
|
+
* `deps` and `delivery` (both swapped on every {@link initialize}); the token
|
|
2266
|
+
* map is handed over as a READ-ONLY view and written only by the module's own
|
|
2267
|
+
* `storeEngineToken`, so delivery never becomes a second writer.
|
|
2312
2268
|
*/
|
|
2313
|
-
private
|
|
2269
|
+
private deliveryHost;
|
|
2314
2270
|
/**
|
|
2315
|
-
*
|
|
2316
|
-
*
|
|
2317
|
-
*
|
|
2318
|
-
* clobber a newly-saved undelivered entry and lose it — defeating the crash-
|
|
2319
|
-
* safety guarantee. A promise-chain mutex makes each whole RMW atomic.
|
|
2271
|
+
* The narrow seam {@link PaymentRequests} reaches back through. Live getters,
|
|
2272
|
+
* not a snapshot: `deps` is swapped on every {@link initialize} (address
|
|
2273
|
+
* switch) and the feature must always observe the CURRENT one.
|
|
2320
2274
|
*/
|
|
2321
|
-
private
|
|
2322
|
-
|
|
2275
|
+
private paymentRequestsHost;
|
|
2276
|
+
/**
|
|
2277
|
+
* The narrow seam {@link TransferHistory} reaches back through. Live getter
|
|
2278
|
+
* for `deps` (swapped on every {@link initialize}); the rest are thunks onto
|
|
2279
|
+
* the module's own private helpers — history never touches the token map or
|
|
2280
|
+
* `save()`.
|
|
2281
|
+
*/
|
|
2282
|
+
private transferHistoryHost;
|
|
2283
|
+
/**
|
|
2284
|
+
* The narrow seam {@link IntentResume} reaches back through. Live getters for
|
|
2285
|
+
* `deps` and `delivery` (both swapped on every {@link initialize}); the rest
|
|
2286
|
+
* are thunks onto the module's own helpers. The token map is READ through
|
|
2287
|
+
* `getHeldToken` and written only by the module's `removeToken` /
|
|
2288
|
+
* `storeEngineToken` — resume never becomes a second writer.
|
|
2289
|
+
*/
|
|
2290
|
+
private intentResumeHost;
|
|
2323
2291
|
/**
|
|
2324
2292
|
* Get the current module configuration.
|
|
2325
2293
|
*
|
|
@@ -2642,141 +2610,40 @@ declare class PaymentsModule {
|
|
|
2642
2610
|
* fetched only when a token is selected to be spent.
|
|
2643
2611
|
*/
|
|
2644
2612
|
private mergeLazyInventory;
|
|
2645
|
-
/**
|
|
2646
|
-
* Send a payment request to someone
|
|
2647
|
-
* @param recipientPubkeyOrNametag - Recipient's pubkey or @nametag
|
|
2648
|
-
* @param request - Payment request details
|
|
2649
|
-
* @returns Result with event ID
|
|
2650
|
-
*/
|
|
2613
|
+
/** Send a payment request to someone. @see PaymentRequests.sendPaymentRequest */
|
|
2651
2614
|
sendPaymentRequest(recipientPubkeyOrNametag: string, request: Omit<PaymentRequest, 'id' | 'createdAt'>): Promise<PaymentRequestResult>;
|
|
2652
|
-
/**
|
|
2653
|
-
* S4: create the request via wallet-api (§16). The payer is addressed by
|
|
2654
|
-
* CHAIN pubkey (the canonical identity); the memo is S6-encrypted client-
|
|
2655
|
-
* side BEFORE it leaves the device (§8.3) — the operator stores ciphertext.
|
|
2656
|
-
* Mirrors the transport path's no-throw contract: failures (including the
|
|
2657
|
-
* §5.5 per-payer cap → 429) come back as `{ success: false, error }`.
|
|
2658
|
-
*/
|
|
2659
|
-
private sendWalletApiPaymentRequest;
|
|
2660
|
-
/**
|
|
2661
|
-
* Subscribe to incoming payment requests
|
|
2662
|
-
* @param handler - Handler function for incoming requests
|
|
2663
|
-
* @returns Unsubscribe function
|
|
2664
|
-
*/
|
|
2615
|
+
/** Subscribe to incoming payment requests. @see PaymentRequests.onPaymentRequest */
|
|
2665
2616
|
onPaymentRequest(handler: PaymentRequestHandler): () => void;
|
|
2666
|
-
/**
|
|
2667
|
-
* Get all payment requests
|
|
2668
|
-
* @param filter - Optional status filter
|
|
2669
|
-
*/
|
|
2617
|
+
/** Get all payment requests. @see PaymentRequests.getPaymentRequests */
|
|
2670
2618
|
getPaymentRequests(filter?: {
|
|
2671
2619
|
status?: PaymentRequestStatus;
|
|
2672
2620
|
}): IncomingPaymentRequest[];
|
|
2673
|
-
/**
|
|
2674
|
-
* Get the count of payment requests with status `'pending'`.
|
|
2675
|
-
*
|
|
2676
|
-
* @returns Number of pending incoming payment requests.
|
|
2677
|
-
*/
|
|
2621
|
+
/** Count of incoming payment requests with status `'pending'`. @see PaymentRequests.getPendingPaymentRequestsCount */
|
|
2678
2622
|
getPendingPaymentRequestsCount(): number;
|
|
2679
|
-
/**
|
|
2680
|
-
* Accept a payment request and notify the requester.
|
|
2681
|
-
*
|
|
2682
|
-
* Marks the request as `'accepted'` and sends a response via transport.
|
|
2683
|
-
* The caller should subsequently call {@link send} to fulfill the payment.
|
|
2684
|
-
*
|
|
2685
|
-
* @param requestId - ID of the incoming payment request to accept.
|
|
2686
|
-
*/
|
|
2687
|
-
acceptPaymentRequest(requestId: string): Promise<void>;
|
|
2688
|
-
/**
|
|
2689
|
-
* Reject a payment request and notify the requester.
|
|
2690
|
-
*
|
|
2691
|
-
* On the wallet-api path (S4) the respond IS the state change — it is
|
|
2692
|
-
* confirmed server-side (`action: 'declined'`, §16) before the local status
|
|
2693
|
-
* flips, and a server rejection (403/409) propagates to the caller. The
|
|
2694
|
-
* transport path is best-effort and never throws.
|
|
2695
|
-
*
|
|
2696
|
-
* @param requestId - ID of the incoming payment request to reject.
|
|
2697
|
-
*/
|
|
2623
|
+
/** Reject a payment request and notify the requester. @see PaymentRequests.rejectPaymentRequest */
|
|
2698
2624
|
rejectPaymentRequest(requestId: string): Promise<void>;
|
|
2699
|
-
/**
|
|
2700
|
-
* Mark a payment request as paid (local status update only).
|
|
2701
|
-
*
|
|
2702
|
-
* Typically called after a successful {@link send} to record that the
|
|
2703
|
-
* request has been fulfilled.
|
|
2704
|
-
*
|
|
2705
|
-
* @param requestId - ID of the incoming payment request to mark as paid.
|
|
2706
|
-
*/
|
|
2707
|
-
markPaymentRequestPaid(requestId: string): void;
|
|
2708
|
-
/**
|
|
2709
|
-
* Remove resolved incoming payment requests from memory.
|
|
2710
|
-
*
|
|
2711
|
-
* Keeps requests with status `'pending'` OR `'settling'` (#441). A `'settling'`
|
|
2712
|
-
* request is UNRESOLVED — its linked transfer is still in-flight — so evicting
|
|
2713
|
-
* it would drop the in-memory hold that keeps it non-payable until the journal
|
|
2714
|
-
* re-surfaces it. Only terminal statuses (`'paid'`/`'rejected'`/`'expired'`)
|
|
2715
|
-
* are removed.
|
|
2716
|
-
*/
|
|
2625
|
+
/** Remove resolved incoming payment requests from memory. @see PaymentRequests.clearProcessedPaymentRequests */
|
|
2717
2626
|
clearProcessedPaymentRequests(): void;
|
|
2718
|
-
/**
|
|
2719
|
-
* Remove a specific incoming payment request by ID.
|
|
2720
|
-
*
|
|
2721
|
-
* @param requestId - ID of the payment request to remove.
|
|
2722
|
-
*/
|
|
2627
|
+
/** Remove a specific incoming payment request by ID. @see PaymentRequests.removePaymentRequest */
|
|
2723
2628
|
removePaymentRequest(requestId: string): void;
|
|
2724
|
-
/**
|
|
2725
|
-
* Pay a payment request directly
|
|
2726
|
-
* Convenience method that accepts, sends, and marks as paid
|
|
2727
|
-
*/
|
|
2629
|
+
/** Pay a payment request directly. @see PaymentRequests.payPaymentRequest */
|
|
2728
2630
|
payPaymentRequest(requestId: string, memo?: string): Promise<TransferResult>;
|
|
2729
|
-
|
|
2730
|
-
private updatePaymentRequestStatus;
|
|
2731
|
-
/**
|
|
2732
|
-
* Get outgoing payment requests
|
|
2733
|
-
* @param filter - Optional status filter
|
|
2734
|
-
*/
|
|
2631
|
+
/** Get outgoing payment requests. @see PaymentRequests.getOutgoingPaymentRequests */
|
|
2735
2632
|
getOutgoingPaymentRequests(filter?: {
|
|
2736
2633
|
status?: PaymentRequestStatus;
|
|
2737
2634
|
}): OutgoingPaymentRequest[];
|
|
2738
|
-
/**
|
|
2739
|
-
* Subscribe to payment request responses (for outgoing requests)
|
|
2740
|
-
* @param handler - Handler function for incoming responses
|
|
2741
|
-
* @returns Unsubscribe function
|
|
2742
|
-
*/
|
|
2635
|
+
/** Subscribe to payment request responses. @see PaymentRequests.onPaymentRequestResponse */
|
|
2743
2636
|
onPaymentRequestResponse(handler: PaymentRequestResponseHandler): () => void;
|
|
2744
|
-
/**
|
|
2745
|
-
* Wait for a response to a payment request
|
|
2746
|
-
* @param requestId - The outgoing request ID to wait for
|
|
2747
|
-
* @param timeoutMs - Timeout in milliseconds (default: 60000)
|
|
2748
|
-
* @returns Promise that resolves with the response or rejects on timeout
|
|
2749
|
-
*/
|
|
2637
|
+
/** Wait for a response to a payment request. @see PaymentRequests.waitForPaymentResponse */
|
|
2750
2638
|
waitForPaymentResponse(requestId: string, timeoutMs?: number): Promise<PaymentRequestResponse>;
|
|
2751
|
-
/**
|
|
2752
|
-
* Cancel an active {@link waitForPaymentResponse} call.
|
|
2753
|
-
*
|
|
2754
|
-
* The pending promise is rejected with a `'Cancelled'` error.
|
|
2755
|
-
*
|
|
2756
|
-
* @param requestId - The outgoing request ID whose wait should be cancelled.
|
|
2757
|
-
*/
|
|
2639
|
+
/** Cancel an active {@link waitForPaymentResponse} call. @see PaymentRequests.cancelWaitForPaymentResponse */
|
|
2758
2640
|
cancelWaitForPaymentResponse(requestId: string): void;
|
|
2759
|
-
/**
|
|
2760
|
-
* Remove an outgoing payment request and cancel any pending wait.
|
|
2761
|
-
*
|
|
2762
|
-
* @param requestId - ID of the outgoing request to remove.
|
|
2763
|
-
*/
|
|
2641
|
+
/** Remove an outgoing payment request and cancel any pending wait. @see PaymentRequests.removeOutgoingPaymentRequest */
|
|
2764
2642
|
removeOutgoingPaymentRequest(requestId: string): void;
|
|
2765
|
-
/**
|
|
2766
|
-
* Remove all outgoing payment requests that are `'paid'`, `'rejected'`, or `'expired'`.
|
|
2767
|
-
*/
|
|
2643
|
+
/** Remove all `'paid'`/`'rejected'`/`'expired'` outgoing requests. @see PaymentRequests.clearCompletedOutgoingPaymentRequests */
|
|
2768
2644
|
clearCompletedOutgoingPaymentRequests(): void;
|
|
2769
|
-
/**
|
|
2770
|
-
|
|
2771
|
-
* shared by the transport subscription and the wallet-api outgoing refresh
|
|
2772
|
-
* (S4): update the matched outgoing request, resolve any
|
|
2773
|
-
* {@link waitForPaymentResponse} waiter, emit the event, run the handlers.
|
|
2774
|
-
*/
|
|
2775
|
-
private dispatchPaymentRequestResponse;
|
|
2776
|
-
/**
|
|
2777
|
-
* Send a response to a payment request (used internally by accept/reject/pay methods)
|
|
2778
|
-
*/
|
|
2779
|
-
private sendPaymentRequestResponse;
|
|
2645
|
+
/** Pull the wallet-api payment-request streams now (S4). @see PaymentRequests.syncPaymentRequests */
|
|
2646
|
+
syncPaymentRequests(): Promise<void>;
|
|
2780
2647
|
/**
|
|
2781
2648
|
* Fetch and process pending incoming transfers from the transport layer.
|
|
2782
2649
|
*
|
|
@@ -2790,6 +2657,7 @@ declare class PaymentsModule {
|
|
|
2790
2657
|
* @param _options - Deprecated; the v1 finalization options are ignored.
|
|
2791
2658
|
* @param callback - Optional callback invoked for each newly received transfer
|
|
2792
2659
|
* @returns ReceiveResult with the newly received transfers
|
|
2660
|
+
* @see Delivery.receive
|
|
2793
2661
|
*/
|
|
2794
2662
|
receive(_options?: ReceiveOptions, callback?: (transfer: IncomingTransfer) => void): Promise<ReceiveResult>;
|
|
2795
2663
|
/**
|
|
@@ -2799,6 +2667,8 @@ declare class PaymentsModule {
|
|
|
2799
2667
|
/**
|
|
2800
2668
|
* Get total portfolio value in USD.
|
|
2801
2669
|
* Returns null if PriceProvider is not configured.
|
|
2670
|
+
*
|
|
2671
|
+
* @see TokenView.getFiatBalance
|
|
2802
2672
|
*/
|
|
2803
2673
|
getFiatBalance(): Promise<number | null>;
|
|
2804
2674
|
/**
|
|
@@ -2816,6 +2686,7 @@ declare class PaymentsModule {
|
|
|
2816
2686
|
*
|
|
2817
2687
|
* @param coinId - Optional coin ID to filter by (e.g. hex string). When omitted, all coin types are returned.
|
|
2818
2688
|
* @returns Array of balance summaries (synchronous — no await needed).
|
|
2689
|
+
* @see TokenView.getBalance
|
|
2819
2690
|
*/
|
|
2820
2691
|
getBalance(coinId?: string): Asset[];
|
|
2821
2692
|
/**
|
|
@@ -2824,22 +2695,10 @@ declare class PaymentsModule {
|
|
|
2824
2695
|
* (`'transferring'`) tokens are reported only in the `transferring*` fields
|
|
2825
2696
|
* and excluded from `totalAmount` (#517 item 3). Fiat value derives from
|
|
2826
2697
|
* `totalAmount`, so it likewise excludes in-flight value.
|
|
2827
|
-
*/
|
|
2828
|
-
getAssets(coinId?: string): Promise<Asset[]>;
|
|
2829
|
-
/**
|
|
2830
|
-
* Aggregate tokens by coinId with confirmed/unconfirmed/transferring breakdown.
|
|
2831
|
-
* Excludes tokens with status 'spent' or 'invalid'.
|
|
2832
2698
|
*
|
|
2833
|
-
*
|
|
2834
|
-
* send, so they are NOT counted as spendable: they are tracked in their own
|
|
2835
|
-
* `transferring*` fields and excluded from `totalAmount`/`unconfirmedAmount`.
|
|
2836
|
-
* Counting them as balance would show the user value they cannot spend (the
|
|
2837
|
-
* #517 incident follow-up).
|
|
2699
|
+
* @see TokenView.getAssets
|
|
2838
2700
|
*/
|
|
2839
|
-
|
|
2840
|
-
/** Fold one token into its coin's running totals (see {@link aggregateTokens}). */
|
|
2841
|
-
private accumulateToken;
|
|
2842
|
-
private newAssetAccumulator;
|
|
2701
|
+
getAssets(coinId?: string): Promise<Asset[]>;
|
|
2843
2702
|
/**
|
|
2844
2703
|
* Get all tokens, optionally filtered by coin type and/or status.
|
|
2845
2704
|
*
|
|
@@ -2847,6 +2706,7 @@ declare class PaymentsModule {
|
|
|
2847
2706
|
* @param filter.coinId - Return only tokens of this coin type.
|
|
2848
2707
|
* @param filter.status - Return only tokens with this status (e.g. `'submitted'` for unconfirmed).
|
|
2849
2708
|
* @returns Array of matching {@link Token} objects (synchronous).
|
|
2709
|
+
* @see TokenView.getTokens
|
|
2850
2710
|
*/
|
|
2851
2711
|
getTokens(filter?: {
|
|
2852
2712
|
coinId?: string;
|
|
@@ -2857,6 +2717,7 @@ declare class PaymentsModule {
|
|
|
2857
2717
|
*
|
|
2858
2718
|
* @param id - The local UUID assigned when the token was added.
|
|
2859
2719
|
* @returns The token, or `undefined` if not found.
|
|
2720
|
+
* @see TokenView.getToken
|
|
2860
2721
|
*/
|
|
2861
2722
|
getToken(id: string): Token | undefined;
|
|
2862
2723
|
/**
|
|
@@ -2914,6 +2775,7 @@ declare class PaymentsModule {
|
|
|
2914
2775
|
* token state from being re-added (e.g. via Nostr re-delivery).
|
|
2915
2776
|
*
|
|
2916
2777
|
* @returns A shallow copy of the tombstone array.
|
|
2778
|
+
* @see TokenView.getTombstones
|
|
2917
2779
|
*/
|
|
2918
2780
|
getTombstones(): TombstoneEntry[];
|
|
2919
2781
|
/**
|
|
@@ -2923,36 +2785,23 @@ declare class PaymentsModule {
|
|
|
2923
2785
|
* @param tokenId - The genesis token ID.
|
|
2924
2786
|
* @param stateHash - The state hash of the token version to check.
|
|
2925
2787
|
* @returns `true` if the exact combination has been tombstoned.
|
|
2788
|
+
* @see TokenView.isStateTombstoned
|
|
2926
2789
|
*/
|
|
2927
2790
|
isStateTombstoned(tokenId: string, stateHash: string): boolean;
|
|
2928
|
-
private rebuildTombstoneKeySet;
|
|
2929
|
-
/**
|
|
2930
|
-
* Merge tombstones received from a remote sync source.
|
|
2931
|
-
*
|
|
2932
|
-
* Any local token whose `(tokenId, stateHash)` matches a remote tombstone is
|
|
2933
|
-
* removed. The remote tombstones are then added to the local set (union merge).
|
|
2934
|
-
*
|
|
2935
|
-
* @param remoteTombstones - Tombstone entries from the remote source.
|
|
2936
|
-
* @returns Number of local tokens that were removed.
|
|
2937
|
-
*/
|
|
2938
|
-
mergeTombstones(remoteTombstones: TombstoneEntry[]): Promise<number>;
|
|
2939
2791
|
/**
|
|
2940
2792
|
* Remove tombstones older than `maxAge` and cap the list at 100 entries.
|
|
2941
2793
|
*
|
|
2942
2794
|
* @param maxAge - Maximum age in milliseconds (default: 30 days).
|
|
2795
|
+
* @see TokenView.pruneTombstones
|
|
2943
2796
|
*/
|
|
2944
2797
|
pruneTombstones(maxAge?: number): Promise<void>;
|
|
2945
2798
|
/**
|
|
2946
2799
|
* Get the transaction history sorted newest-first.
|
|
2947
2800
|
*
|
|
2948
2801
|
* @returns Array of {@link TransactionHistoryEntry} objects in descending timestamp order.
|
|
2802
|
+
* @see TransferHistory.getHistory
|
|
2949
2803
|
*/
|
|
2950
2804
|
getHistory(): TransactionHistoryEntry[];
|
|
2951
|
-
/**
|
|
2952
|
-
* Best-effort resolve sender's DIRECT address and nametag from their transport pubkey.
|
|
2953
|
-
* Returns empty object if transport doesn't support resolution or lookup fails.
|
|
2954
|
-
*/
|
|
2955
|
-
private resolveSenderInfo;
|
|
2956
2805
|
/**
|
|
2957
2806
|
* Append an entry to the transaction history.
|
|
2958
2807
|
*
|
|
@@ -2961,56 +2810,15 @@ declare class PaymentsModule {
|
|
|
2961
2810
|
* Duplicate entries with the same `dedupKey` are silently ignored (upsert).
|
|
2962
2811
|
*
|
|
2963
2812
|
* @param entry - History entry fields (without `id` and `dedupKey`).
|
|
2813
|
+
* @see TransferHistory.addToHistory
|
|
2964
2814
|
*/
|
|
2965
2815
|
addToHistory(entry: Omit<TransactionHistoryEntry, 'id' | 'dedupKey'>): Promise<void>;
|
|
2966
2816
|
/**
|
|
2967
2817
|
* Load history into the in-memory cache.
|
|
2968
2818
|
*
|
|
2969
|
-
*
|
|
2970
|
-
* durable §10 history log lives on the SERVER — the thin storage provider
|
|
2971
|
-
* keeps none — so the cache is rebuilt from `walletApi.listHistory()`. The
|
|
2972
|
-
* twin of the #521 inventory reload bug: `_historyCache` is process-lifetime,
|
|
2973
|
-
* so a reload (tab refresh) must re-pull it or render an empty history.
|
|
2974
|
-
* Compositions WITHOUT `walletApi` keep the legacy local path below.
|
|
2819
|
+
* @see TransferHistory.loadHistory
|
|
2975
2820
|
*/
|
|
2976
2821
|
loadHistory(): Promise<void>;
|
|
2977
|
-
/**
|
|
2978
|
-
* Rebuild `_historyCache` from the server's §10 history log (the wallet-api
|
|
2979
|
-
* composition). Pages newest-first via the keyset cursor until `more:false`
|
|
2980
|
-
* or the page cap; dedups by `dedupKey` (a hydrate-then-receive in the same
|
|
2981
|
-
* session must not double-list). The S6 `memo` / `counterpartyNametag`
|
|
2982
|
-
* envelopes are decrypted with the owner's own field key on the way in.
|
|
2983
|
-
*
|
|
2984
|
-
* #642 incremental fast path: after one completed hydration for this owner,
|
|
2985
|
-
* later pulls stop at the first non-empty page holding nothing new — the
|
|
2986
|
-
* §10 log is append-only (newest-first keyset), so everything past a fully
|
|
2987
|
-
* known page is already cached. The steady-state 30s inventory resync then
|
|
2988
|
-
* costs ONE history page instead of a full re-pagination (which on a wallet
|
|
2989
|
-
* whose history overflows the page cap was 100 pages, every tick, forever).
|
|
2990
|
-
*
|
|
2991
|
-
* Best-effort, like the §10 history POST: history is untrusted DISPLAY data,
|
|
2992
|
-
* so a backend outage during hydration must NEVER fail `load()` (the money
|
|
2993
|
-
* path) — the in-session cache is left intact and the pull retries next load.
|
|
2994
|
-
*/
|
|
2995
|
-
private hydrateHistoryFromServer;
|
|
2996
|
-
/**
|
|
2997
|
-
* Map one §16 history wire record onto the display
|
|
2998
|
-
* {@link TransactionHistoryEntry}. `counterpartyNametag` lands on the role-
|
|
2999
|
-
* appropriate field (sender for RECEIVED, recipient otherwise); the S6 memo +
|
|
3000
|
-
* nametag envelopes decrypt under THIS wallet's field key (self-scoped at
|
|
3001
|
-
* rest — §8.3), surfaced as absent if they don't decrypt rather than as
|
|
3002
|
-
* ciphertext (same rule as mailbox/payment-request memos).
|
|
3003
|
-
*/
|
|
3004
|
-
private historyEntryFromWire;
|
|
3005
|
-
/** S6 field decrypt that surfaces an undecryptable envelope as absent (§8.3). */
|
|
3006
|
-
private tryDecryptField;
|
|
3007
|
-
/**
|
|
3008
|
-
* Import history entries from remote TXF data into local store.
|
|
3009
|
-
* Delegates to the local TokenStorageProvider's importHistoryEntries() for
|
|
3010
|
-
* persistent storage, with in-memory fallback.
|
|
3011
|
-
* Reused by both load() (initial IPFS fetch) and _doSync() (merge result).
|
|
3012
|
-
*/
|
|
3013
|
-
private importRemoteHistoryEntries;
|
|
3014
2822
|
/**
|
|
3015
2823
|
* Get the first local token storage provider (for history operations).
|
|
3016
2824
|
*/
|
|
@@ -3133,6 +2941,7 @@ declare class PaymentsModule {
|
|
|
3133
2941
|
* Tokens that fail validation or are detected as spent are marked `'invalid'`.
|
|
3134
2942
|
*
|
|
3135
2943
|
* @returns Object with arrays of valid and invalid tokens.
|
|
2944
|
+
* @see TokenView.validate
|
|
3136
2945
|
*/
|
|
3137
2946
|
validate(): Promise<{
|
|
3138
2947
|
valid: Token[];
|
|
@@ -3147,17 +2956,6 @@ declare class PaymentsModule {
|
|
|
3147
2956
|
* Uses pre-resolved PeerInfo if available, otherwise resolves via transport.
|
|
3148
2957
|
*/
|
|
3149
2958
|
private resolveTransportPubkey;
|
|
3150
|
-
/**
|
|
3151
|
-
* v2 engine transfer (sender-driven): the sender handed us a FINISHED token.
|
|
3152
|
-
* Decode the blob, dedup by the genesis-stable token id, store it as a
|
|
3153
|
-
* confirmed token, and emit/record the receipt. No commitment / inclusion-proof
|
|
3154
|
-
* / finalization round-trip (contrast the v1 sourceToken+transferTx path).
|
|
3155
|
-
*
|
|
3156
|
-
* Transport-agnostic (sdk-changes S3): fed by the relay push subscription
|
|
3157
|
-
* AND by the delivery port's incoming pump — the returned verdict lets the
|
|
3158
|
-
* pump map outcomes onto `ack('claimed' | 'rejected')`.
|
|
3159
|
-
*/
|
|
3160
|
-
private handleV2Transfer;
|
|
3161
2959
|
private teardownDeliveryPump;
|
|
3162
2960
|
/**
|
|
3163
2961
|
* Route a §9 wake nudge to the matching stream's pull. The wake is
|
|
@@ -3221,158 +3019,16 @@ declare class PaymentsModule {
|
|
|
3221
3019
|
* ack for a provider without it (e.g. the relay no-op).
|
|
3222
3020
|
*/
|
|
3223
3021
|
private flushIncomingAcks;
|
|
3224
|
-
/**
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
private readPrCursorState;
|
|
3229
|
-
private persistPrCursorState;
|
|
3230
|
-
private prSettlingKey;
|
|
3231
|
-
/**
|
|
3232
|
-
* Single-flight load: concurrent callers (the pump's reload re-apply, resume's
|
|
3233
|
-
* reconcile, a live pay catch) share ONE storage.get + ONE Map instance so a
|
|
3234
|
-
* lazy read never overwrites another context's in-memory mutation.
|
|
3235
|
-
*/
|
|
3236
|
-
private ensureSettlingJournalLoaded;
|
|
3237
|
-
/**
|
|
3238
|
-
* Serialize every read-modify-write through a tail-promise chain so two
|
|
3239
|
-
* concurrent mutations can't lose an entry (the #679/#680 mutex lesson — a
|
|
3240
|
-
* dropped entry is a re-payable request is a double-pay). `fn` returns true
|
|
3241
|
-
* when the Map changed and must be persisted.
|
|
3242
|
-
*/
|
|
3243
|
-
private mutateSettlingJournal;
|
|
3244
|
-
/**
|
|
3245
|
-
* #441: link a request to its in-flight transfer. `committed` marks a
|
|
3246
|
-
* DEFINITE spend whose anchor intent is soft-aborted and will NOT resume-
|
|
3247
|
-
* complete — a `PartialSendConflictError` (≥1 leg already delivered). The
|
|
3248
|
-
* reconcile must resolve such a link 'paid' and NEVER revert it to payable
|
|
3249
|
-
* (re-paying the full amount would double-pay the delivered leg). A
|
|
3250
|
-
* non-`committed` link is a keep-open outcome that resume may still complete
|
|
3251
|
-
* OR abort (e.g. CERTIFICATION_UNCONFIRMED losing to a foreign tx delivers
|
|
3252
|
-
* nothing) — those DO revert to payable on abort.
|
|
3253
|
-
*/
|
|
3254
|
-
private journalSettling;
|
|
3255
|
-
private clearSettling;
|
|
3256
|
-
/**
|
|
3257
|
-
* Pull the wallet-api payment-request streams now (S4): drains the payer's
|
|
3258
|
-
* incoming `?since=<seq>` stream (gap-free — §9/§16) into the existing
|
|
3259
|
-
* handler/event surface and refreshes outgoing requests still awaiting a
|
|
3260
|
-
* response. The poll interval and `load()` call this automatically; it is
|
|
3261
|
-
* public for explicit fetch-now flows (mirrors {@link receive}). A no-op in
|
|
3262
|
-
* compositions without the wallet-api payment-request capability — there
|
|
3263
|
-
* the Nostr subscription is push-based.
|
|
3264
|
-
*/
|
|
3265
|
-
syncPaymentRequests(): Promise<void>;
|
|
3266
|
-
/** Coalesces concurrent pump runs (poll + wake + load can overlap). */
|
|
3267
|
-
private pumpPaymentRequests;
|
|
3268
|
-
private doPumpPaymentRequests;
|
|
3269
|
-
/**
|
|
3270
|
-
* Drain the payer's gap-free `?since=<seq>` stream (§9/§16), mirroring the
|
|
3271
|
-
* mailbox-cursor pattern: the persisted `{cursor, syncEpoch}` is the resume
|
|
3272
|
-
* point; a `syncEpoch` change (server restore — §5.4) voids cursor
|
|
3273
|
-
* continuity, so the tail re-pulls from 0 and the id-dedup in
|
|
3274
|
-
* {@link surfaceIncomingPaymentRequest} absorbs the replays.
|
|
3275
|
-
*
|
|
3276
|
-
* Because the surfaced list is in-memory only, each session FIRST runs one
|
|
3277
|
-
* full incoming hydration from `since=0` with NO status filter (#556 —
|
|
3278
|
-
* mirrors {@link hydrateHistoryFromServer}): a fresh engine rebuilds the
|
|
3279
|
-
* CURRENT state of ALL incoming requests — open AND resolved — so a request
|
|
3280
|
-
* paid/declined/expired in a PRIOR session is still present (with its
|
|
3281
|
-
* resolved status) instead of vanishing once the cursor advanced past it.
|
|
3282
|
-
* Hydration NEVER fires the new-incoming handlers/events for resolved
|
|
3283
|
-
* requests — only `open` ones notify (the status-aware
|
|
3284
|
-
* {@link surfaceIncomingPaymentRequest}) — so reopening can't spam stale
|
|
3285
|
-
* 'new request' notifications. After hydration the `since`-cursor delta poll
|
|
3286
|
-
* picks up live updates from the resume point.
|
|
3287
|
-
*/
|
|
3288
|
-
private pumpIncomingPaymentRequests;
|
|
3289
|
-
/**
|
|
3290
|
-
* Decrypt a payment-request's recipient-addressed memo envelope into
|
|
3291
|
-
* `{ memo, senderNametag }` (the requester's message + nametag). The key is
|
|
3292
|
-
* the ECDH shared secret between THIS wallet (the payer) and the requester's
|
|
3293
|
-
* chain pubkey (`wire.fromPubkey`) — symmetric with the requester's
|
|
3294
|
-
* create-time derivation. Returns an empty bundle (and logs at debug) on any
|
|
3295
|
-
* absence/failure so the incoming view never wedges on an unreadable memo
|
|
3296
|
-
* (PR twin of #546/#547).
|
|
3297
|
-
*/
|
|
3298
|
-
private decryptPaymentRequestMemo;
|
|
3299
|
-
/** §16 wire status → the public {@link PaymentRequestStatus} display status. */
|
|
3300
|
-
private static readonly PR_WIRE_STATUS;
|
|
3301
|
-
/** Terminal local statuses: a re-surfaced wire may advance a request INTO one, never out of it. */
|
|
3302
|
-
private static readonly PR_TERMINAL;
|
|
3303
|
-
/**
|
|
3304
|
-
* Map a §16 wire request onto the public {@link IncomingPaymentRequest}
|
|
3305
|
-
* surface, deduped by id (the in-memory id-dedup doubles as the replay guard
|
|
3306
|
-
* for cursor resets). Requests of EVERY status are surfaced so a reloaded
|
|
3307
|
-
* thin wallet rebuilds the CURRENT state of its incoming view (#556) — open
|
|
3308
|
-
* ones land as actionable `pending`, resolved ones carry their paid/declined
|
|
3309
|
-
* (→ `rejected`)/expired status. Only `open` requests fire the new-incoming
|
|
3310
|
-
* event + handlers; resolved requests are folded into the list silently, so a
|
|
3311
|
-
* reload (or a `syncEpoch` re-pull) never re-notifies for already-resolved
|
|
3312
|
-
* requests. Multi-asset requests surface their first asset (the module's
|
|
3313
|
-
* request surface is single-asset; module-created requests always are).
|
|
3314
|
-
*/
|
|
3315
|
-
private surfaceIncomingPaymentRequest;
|
|
3316
|
-
/**
|
|
3317
|
-
* Outgoing requests are a `?before=` backfill view (§16 — newest-first, no
|
|
3318
|
-
* gap-free tail): refresh only while something local still awaits a
|
|
3319
|
-
* response, paging until every pending id is resolved or the view drains.
|
|
3320
|
-
*/
|
|
3321
|
-
private refreshOutgoingPaymentRequests;
|
|
3322
|
-
/** Fold a server-side status change into the outgoing surface (responses + expiry). */
|
|
3323
|
-
private applyOutgoingPaymentRequestState;
|
|
3324
|
-
/**
|
|
3325
|
-
* E.3 resume: list this wallet's OPEN intents (server-side — any device),
|
|
3326
|
-
* decrypt each payload, and re-run the engine with the SAME transferId and
|
|
3327
|
-
* inputs — deterministic realization yields byte-identical transactions, so
|
|
3328
|
-
* an interrupted transfer completes instead of failing (proof fetch →
|
|
3329
|
-
* match-verify → apply, Part E). Called at sign-in (S4).
|
|
3022
|
+
/**
|
|
3023
|
+
* E.3 resume of this wallet's OPEN send intents.
|
|
3024
|
+
*
|
|
3025
|
+
* @see IntentResume.resumeOpenIntents
|
|
3330
3026
|
*/
|
|
3331
3027
|
resumeOpenIntents(): Promise<{
|
|
3332
3028
|
resumed: string[];
|
|
3333
3029
|
conflicted: string[];
|
|
3334
3030
|
failed: string[];
|
|
3335
3031
|
}>;
|
|
3336
|
-
/**
|
|
3337
|
-
* #441: resolve every journaled settling payment request against a resume
|
|
3338
|
-
* outcome. Completed → send the deferred 'paid' response (server now told) and
|
|
3339
|
-
* resolve 'paid'. Aborted (nothing delivered) → clear journal, return to
|
|
3340
|
-
* payable. Still open → leave it. For an id accounted for by NONE of those
|
|
3341
|
-
* (a crash between resume-complete and the local write), consult the server
|
|
3342
|
-
* `listIntents('aborted')` authority: aborted → payable; else → paid (a
|
|
3343
|
-
* completed row the server GC'd). Direction-of-error is deliberate: the only
|
|
3344
|
-
* residual false-paid is a transfer that aborted server-side AND whose local
|
|
3345
|
-
* 'aborted' write was lost AND whose server aborted-row was later GC'd — it is
|
|
3346
|
-
* treated as paid, erring toward PAID-NEVER-RE-PAYABLE (no double-pay), the
|
|
3347
|
-
* invariant this fix exists to protect.
|
|
3348
|
-
*/
|
|
3349
|
-
private reconcileSettlingPaymentRequests;
|
|
3350
|
-
/** #441: the linked transfer completed — tell the server 'paid' and resolve 'paid'. */
|
|
3351
|
-
private resolveSettledPaid;
|
|
3352
|
-
/** #441: the linked transfer aborted — nothing was paid; clear the link and return to payable. */
|
|
3353
|
-
private revertSettlingToPayable;
|
|
3354
|
-
/**
|
|
3355
|
-
* Re-run one intent end-to-end: getToken (works for tombstoned rows — §5.3
|
|
3356
|
-
* recovery surface), engine re-run under the original transferId, journaled
|
|
3357
|
-
* delivery, the single §7 apply (inventory custody only), uniform close,
|
|
3358
|
-
* and the SENT history record (dedupKey'd by transferId — idempotent).
|
|
3359
|
-
*/
|
|
3360
|
-
private resumeIntent;
|
|
3361
|
-
/**
|
|
3362
|
-
* A resumed split that produced no output: a lost source means the leg delivered
|
|
3363
|
-
* nothing (returns false), and every checkpoint failure keeps the intent open by
|
|
3364
|
-
* throwing. There is no path here that records the spend.
|
|
3365
|
-
*/
|
|
3366
|
-
private classifyResumeSplitFailure;
|
|
3367
|
-
/**
|
|
3368
|
-
* Drop the local records of the sources a resume consumed (present when
|
|
3369
|
-
* resuming on the originating device). M7: each removal carries the LOCAL state
|
|
3370
|
-
* we spent, so a source a concurrent claim reactivated to a NEW state (a
|
|
3371
|
-
* self-send round-trip) is KEPT, not destroyed.
|
|
3372
|
-
*/
|
|
3373
|
-
private dropResumedSources;
|
|
3374
|
-
/** §10: the SENT record — same dedupKey as the original attempt, so a resume after the history POST is a server-side no-op. */
|
|
3375
|
-
private recordResumedSentHistory;
|
|
3376
3032
|
/**
|
|
3377
3033
|
* Persist the token state to every (non-disabled) token storage provider.
|
|
3378
3034
|
*
|
|
@@ -3388,77 +3044,6 @@ declare class PaymentsModule {
|
|
|
3388
3044
|
* behavior.
|
|
3389
3045
|
*/
|
|
3390
3046
|
private save;
|
|
3391
|
-
private loadPendingV2Deliveries;
|
|
3392
|
-
/**
|
|
3393
|
-
* #621: journaled finished blobs for an intent, keyed by op position. opIndex when present,
|
|
3394
|
-
* else positional among the intent's entries (legacy entries journaled in op order). Resume
|
|
3395
|
-
* uses this to re-deliver an already-certified op instead of re-running the engine on its spent source.
|
|
3396
|
-
*/
|
|
3397
|
-
private journaledByOp;
|
|
3398
|
-
/** #517: run a journal read-modify-write atomically against all other journal mutations. */
|
|
3399
|
-
private withJournalLock;
|
|
3400
|
-
private savePendingV2Delivery;
|
|
3401
|
-
private removePendingV2Delivery;
|
|
3402
|
-
/**
|
|
3403
|
-
* The hoisted send delivery pass (#699): hand a send's journaled committed
|
|
3404
|
-
* blobs to ONE recipient — a single deliverBatch call when the port offers
|
|
3405
|
-
* it and there is more than one blob, else per-blob deliver at the
|
|
3406
|
-
* certification fan-out width. Returns true iff every blob was delivered
|
|
3407
|
-
* (deferred blobs stay journaled). Never throws (§3.1).
|
|
3408
|
-
*/
|
|
3409
|
-
private deliverCommittedBlobs;
|
|
3410
|
-
/**
|
|
3411
|
-
* Batch sibling of {@link tryDeliver}: success clears every journal entry;
|
|
3412
|
-
* ANY failure keeps them ALL journaled (the deposit is idempotent by
|
|
3413
|
-
* content-derived entry_id, so a replay absorbs entries that already
|
|
3414
|
-
* landed). Never throws.
|
|
3415
|
-
*/
|
|
3416
|
-
private tryDeliverBatch;
|
|
3417
|
-
/**
|
|
3418
|
-
* Per-blob fallback (a batch-less port, or a single blob), chunked at
|
|
3419
|
-
* MAX_SEND_OPERATION_CONCURRENCY so the pass keeps the certification
|
|
3420
|
-
* fan-out era's delivery width. Never throws.
|
|
3421
|
-
*/
|
|
3422
|
-
private deliverPerBlob;
|
|
3423
|
-
/**
|
|
3424
|
-
* Covenant §3.1 (#621): once the source is certified on-chain, a delivery failure must NEVER
|
|
3425
|
-
* fail the sender. Recipient-side conditions (a full mailbox / 429 from a never-claiming recipient)
|
|
3426
|
-
* and transient delivery-infra failures (5xx/network) both leave the finished blob JOURNALED for
|
|
3427
|
-
* (re-)delivery — the send resolves as delivery-pending and the sender moves on. The blob is already
|
|
3428
|
-
* journaled (savePendingV2Delivery ran before this); on success we clear the journal, on any failure
|
|
3429
|
-
* we keep it. Returns true if delivered, false if deferred. Never throws.
|
|
3430
|
-
*/
|
|
3431
|
-
private tryDeliver;
|
|
3432
|
-
/**
|
|
3433
|
-
* Replay journaled finished-but-undelivered v2 blobs (kicked from load())
|
|
3434
|
-
* through the delivery port (sdk-changes S3). Idempotent end to end: the
|
|
3435
|
-
* mailbox deposit is idempotent by the content-derived entry_id — it succeeds
|
|
3436
|
-
* even after the recipient claimed (§6) — and the relay path's recipient
|
|
3437
|
-
* dedups by the genesis-stable token id.
|
|
3438
|
-
*
|
|
3439
|
-
* #517 item 1: instead of a silent unbounded fire-and-forget, each entry is
|
|
3440
|
-
* retried with bounded exponential backoff, its cumulative failed-attempt
|
|
3441
|
-
* count is journaled across loads, and an entry that exhausts
|
|
3442
|
-
* {@link MAX_DELIVERY_REPLAY_ATTEMPTS} is SURFACED as poison
|
|
3443
|
-
* (`delivery:undeliverable`) and left journaled but no longer auto-retried —
|
|
3444
|
-
* so a journaled blob never sits undelivered invisibly.
|
|
3445
|
-
*/
|
|
3446
|
-
private replayPendingV2Deliveries;
|
|
3447
|
-
/** Replay a single journaled entry: backoff retries → success/removal, or → bounded poison. */
|
|
3448
|
-
private replayOneDelivery;
|
|
3449
|
-
/**
|
|
3450
|
-
* §3.1 (#621): defer a recipient-quota (429) delivery — keep it journaled, never poison it (it
|
|
3451
|
-
* self-heals when the recipient claims), and retry no sooner than the deferral window. Surfaced
|
|
3452
|
-
* distinctly (delivery:deferred) so a UI can show "recipient's mailbox is full — will retry".
|
|
3453
|
-
*/
|
|
3454
|
-
private deferDelivery;
|
|
3455
|
-
/** One delivery with in-pass exponential backoff; throws the last error if all attempts fail. */
|
|
3456
|
-
private attemptDeliveryWithBackoff;
|
|
3457
|
-
/** Mark a journal entry poison (keep it, stop retrying) and surface it (#517 item 1). */
|
|
3458
|
-
private markDeliveryPoison;
|
|
3459
|
-
private bumpDeliveryAttempts;
|
|
3460
|
-
/** Mutate one journaled entry in place (keyed by tokenBlob) and persist. No-op if gone. */
|
|
3461
|
-
private updatePendingV2Delivery;
|
|
3462
3047
|
private createStorageData;
|
|
3463
3048
|
private loadFromStorageData;
|
|
3464
3049
|
/**
|
|
@@ -4872,7 +4457,7 @@ interface IncomingTransfer {
|
|
|
4872
4457
|
readonly memo?: string;
|
|
4873
4458
|
readonly receivedAt: number;
|
|
4874
4459
|
}
|
|
4875
|
-
type PaymentRequestStatus = 'pending' | '
|
|
4460
|
+
type PaymentRequestStatus = 'pending' | 'rejected' | 'paid' | 'expired' | 'settling';
|
|
4876
4461
|
/**
|
|
4877
4462
|
* Outgoing payment request (requesting payment from someone)
|
|
4878
4463
|
*/
|
|
@@ -4931,7 +4516,7 @@ type PaymentRequestHandler = (request: IncomingPaymentRequest) => void;
|
|
|
4931
4516
|
/**
|
|
4932
4517
|
* Response type for payment requests
|
|
4933
4518
|
*/
|
|
4934
|
-
type PaymentRequestResponseType = '
|
|
4519
|
+
type PaymentRequestResponseType = 'rejected' | 'paid';
|
|
4935
4520
|
/**
|
|
4936
4521
|
* Outgoing payment request (we sent to someone)
|
|
4937
4522
|
*/
|
|
@@ -5033,7 +4618,7 @@ interface TrackedAddress extends TrackedAddressEntry {
|
|
|
5033
4618
|
/** Primary nametag (from nametag cache, without @ prefix) */
|
|
5034
4619
|
readonly nametag?: string;
|
|
5035
4620
|
}
|
|
5036
|
-
type SphereEventType = 'transfer:incoming' | 'transfer:confirmed' | 'transfer:failed' | 'transfer:delivery_pending' | 'transfer:invalid' | 'payment_request:incoming' | 'payment_request:
|
|
4621
|
+
type SphereEventType = 'transfer:incoming' | 'transfer:confirmed' | 'transfer:failed' | 'transfer:delivery_pending' | 'transfer:invalid' | 'payment_request:incoming' | 'payment_request:rejected' | 'payment_request:paid' | 'payment_request:expired' | 'payment_request:settling' | 'payment_request:response' | 'message:dm' | 'message:read' | 'message:typing' | 'composing:started' | 'message:broadcast' | 'sync:started' | 'sync:completed' | 'sync:error' | 'storage:degraded' | 'inventory:conflict' | 'split:checkpoint-stuck' | 'send:partial-remainder' | 'delivery:undeliverable' | 'delivery:deferred' | 'walletapi:session' | 'realtime:status' | 'connection:changed' | 'nametag:registered' | 'nametag:recovered' | 'identity:changed' | 'address:activated' | 'address:hidden' | 'address:unhidden' | 'sync:remote-update' | 'groupchat:message' | 'groupchat:joined' | 'groupchat:left' | 'groupchat:kicked' | 'groupchat:group_deleted' | 'groupchat:updated' | 'groupchat:connection' | 'groupchat:ready' | 'communications:ready' | 'history:updated' | 'invoice:created' | 'invoice:payment' | 'invoice:asset_covered' | 'invoice:target_covered' | 'invoice:covered' | 'invoice:closed' | 'invoice:cancelled' | 'invoice:expired' | 'invoice:unknown_reference' | 'invoice:overpayment' | 'invoice:irrelevant' | 'invoice:auto_returned' | 'invoice:auto_return_failed' | 'invoice:return_received' | 'invoice:over_refund_warning' | 'invoice:receipt_sent' | 'invoice:receipt_received' | 'invoice:cancellation_sent' | 'invoice:cancellation_received' | 'swap:proposal_received' | 'swap:proposed' | 'swap:accepted' | 'swap:rejected' | 'swap:announced' | 'swap:deposit_sent' | 'swap:deposit_confirmed' | 'swap:deposits_covered' | 'swap:concluding' | 'swap:payout_received' | 'swap:completed' | 'swap:cancelled' | 'swap:failed' | 'swap:deposit_returned' | 'swap:bounce_received';
|
|
5037
4622
|
interface SphereEventMap {
|
|
5038
4623
|
'transfer:incoming': IncomingTransfer;
|
|
5039
4624
|
'transfer:confirmed': TransferResult;
|
|
@@ -5056,7 +4641,6 @@ interface SphereEventMap {
|
|
|
5056
4641
|
reason: string;
|
|
5057
4642
|
};
|
|
5058
4643
|
'payment_request:incoming': IncomingPaymentRequest;
|
|
5059
|
-
'payment_request:accepted': IncomingPaymentRequest;
|
|
5060
4644
|
'payment_request:rejected': IncomingPaymentRequest;
|
|
5061
4645
|
'payment_request:paid': IncomingPaymentRequest;
|
|
5062
4646
|
'payment_request:expired': IncomingPaymentRequest;
|