@qntx/spark 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{index-DISbAuPB.d.mts → index-rHuqmVV3.d.mts} +9 -2
- package/dist/index.d.mts +9 -1
- package/dist/index.mjs +85 -8
- package/dist/server.d.mts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -66,7 +66,7 @@ and amount; that retry either returns the committed transaction's hash or broadc
|
|
|
66
66
|
those inputs once. Retrying without it would select different outputs and pay twice.
|
|
67
67
|
|
|
68
68
|
Offline receive: once a transfer commits, the sender cannot cancel it and its expiry does not
|
|
69
|
-
return it — `transfers.claim`/`claimPending` can pick it up at any later time.
|
|
69
|
+
return it — `transfers.claim(transferId)`/`claimPending` can pick it up at any later time.
|
|
70
70
|
|
|
71
71
|
Unilateral exit: each pre-signed transaction carries a hard deadline — once its parent confirms
|
|
72
72
|
and its relative timelock passes, it must confirm within 50 blocks; otherwise the operators'
|
|
@@ -463,8 +463,15 @@ type SparkClient = {
|
|
|
463
463
|
}>;
|
|
464
464
|
readonly transferId?: string;
|
|
465
465
|
}) => Promise<SparkTransfer>;
|
|
466
|
-
/**
|
|
467
|
-
|
|
466
|
+
/**
|
|
467
|
+
* Claims the transfer `transferId` once it becomes claimable and returns the new leaves —
|
|
468
|
+
* re-querying the coordinator between retries the way upstream `TransferService.claimTransfer`
|
|
469
|
+
* does (five attempts, 1/2/4/8 s). `[]` means this identity's receiver leg already completed. A
|
|
470
|
+
* terminal status (`EXPIRED`, `RETURNED`, …) throws immediately; `signal` aborts the waits.
|
|
471
|
+
*/
|
|
472
|
+
readonly claim: (transferId: string, options?: {
|
|
473
|
+
readonly signal?: AbortSignal;
|
|
474
|
+
}) => Promise<ReadonlyArray<SparkLeaf>>;
|
|
468
475
|
/**
|
|
469
476
|
* Claims every pending incoming transfer; returns the new leaves plus one failure entry per
|
|
470
477
|
* transfer that could not be claimed — a single poisoned transfer does not abort the rest. A
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as SparkTokenBroadcastError, i as SparkRequestError, n as SparkError, r as SparkInputError, t as SparkCryptoError } from "./index-D1fBaHTa.mjs";
|
|
2
2
|
import { a as sparkNetworkConfig, i as SparkOperatorConfig, n as SparkNetwork, r as SparkNetworkConfig } from "./lightning-address-CRULmi9v.mjs";
|
|
3
3
|
import { i as isExpired, n as Bolt11Network, r as decodeBolt11, t as Bolt11Invoice } from "./bolt11-DsNTTS_O.mjs";
|
|
4
|
-
import { A as CooperativeExitStatus, C as exitTransactions, D as CooperativeExitQuote, E as createMemorySparkStore, F as UnusedDepositAddress, I as SparkLeaf, L as SparkEvent, M as StaticDepositClaim, N as StaticDepositRefund, O as CooperativeExitResult, P as StaticDepositUtxo, S as ExitTransaction, T as SparkStore, _ as LightningSendStatus, a as createSparkClient, b as LightningInvoice, c as buildCpfpChild, d as SparkTokenBalance, f as SparkTokenOutput, g as LightningSendOutcome, h as LightningReceiveStatus, i as SparkInvoiceStatus, j as MIN_STATIC_REFUND_FEE_SATS, k as CooperativeExitSpeed, l as SparkTransfer, m as SparkWalletSettings, n as SparkClient, o as StaticDepositClaimResult, p as SparkTokenOutputStatus, r as SparkClientOptions, s as FundingInput, t as ClaimPendingResult, u as SparkTransferLeaf, v as LightningSendStatusRequest, w as SparkExitChain, x as WatchtowerExitedLeaf, y as LightningPayment } from "./index-
|
|
4
|
+
import { A as CooperativeExitStatus, C as exitTransactions, D as CooperativeExitQuote, E as createMemorySparkStore, F as UnusedDepositAddress, I as SparkLeaf, L as SparkEvent, M as StaticDepositClaim, N as StaticDepositRefund, O as CooperativeExitResult, P as StaticDepositUtxo, S as ExitTransaction, T as SparkStore, _ as LightningSendStatus, a as createSparkClient, b as LightningInvoice, c as buildCpfpChild, d as SparkTokenBalance, f as SparkTokenOutput, g as LightningSendOutcome, h as LightningReceiveStatus, i as SparkInvoiceStatus, j as MIN_STATIC_REFUND_FEE_SATS, k as CooperativeExitSpeed, l as SparkTransfer, m as SparkWalletSettings, n as SparkClient, o as StaticDepositClaimResult, p as SparkTokenOutputStatus, r as SparkClientOptions, s as FundingInput, t as ClaimPendingResult, u as SparkTransferLeaf, v as LightningSendStatusRequest, w as SparkExitChain, x as WatchtowerExitedLeaf, y as LightningPayment } from "./index-rHuqmVV3.mjs";
|
|
5
5
|
import { n as EPHEMERAL_ANCHOR_SCRIPT, t as addressToScript, v as SparkSigner } from "./transactions-DjTZU8ev.mjs";
|
|
6
6
|
//#region src/core/invoice.d.ts
|
|
7
7
|
/** Payment carried by a Spark invoice: satoshis or BTKN tokens. */
|
|
@@ -68,6 +68,14 @@ export declare function encodeTokenIdentifier(tokenIdentifier: Uint8Array, netwo
|
|
|
68
68
|
*/
|
|
69
69
|
export declare function decodeTokenIdentifier(text: string): SparkTokenIdentifierData;
|
|
70
70
|
//#endregion
|
|
71
|
+
//#region src/core/uuid.d.ts
|
|
72
|
+
/**
|
|
73
|
+
* UUIDv7 (RFC 9562 §5.7): 48-bit millisecond timestamp, then 74 random bits with the version (0111)
|
|
74
|
+
* and variant (10) fields applied. Randomness and the clock are injected so the function stays
|
|
75
|
+
* platform-neutral and deterministic under test.
|
|
76
|
+
*/
|
|
77
|
+
export declare function uuidv7(random: (length: number) => Uint8Array, now?: () => number): string;
|
|
78
|
+
//#endregion
|
|
71
79
|
//#region src/invoice/create.d.ts
|
|
72
80
|
type InvoiceOptions = {
|
|
73
81
|
readonly signer: SparkSigner;
|
package/dist/index.mjs
CHANGED
|
@@ -3586,6 +3586,16 @@ const CLAIMABLE_TRANSFER_STATUSES = [
|
|
|
3586
3586
|
"RECEIVER_KEY_TWEAKED",
|
|
3587
3587
|
"RECEIVER_REFUND_SIGNED"
|
|
3588
3588
|
];
|
|
3589
|
+
/**
|
|
3590
|
+
* Whole-transfer statuses where the sender leg has not finished: the transfer will become claimable
|
|
3591
|
+
* (or terminal) later, so a receiver claim must wait and re-query rather than fail.
|
|
3592
|
+
*/
|
|
3593
|
+
const TRANSIENT_TRANSFER_STATUSES = [
|
|
3594
|
+
"SENDER_INITIATED",
|
|
3595
|
+
"SENDER_KEY_TWEAK_PENDING",
|
|
3596
|
+
"SENDER_INITIATED_COORDINATOR",
|
|
3597
|
+
"APPLYING_SENDER_KEY_TWEAK"
|
|
3598
|
+
];
|
|
3589
3599
|
function millis(timestamp) {
|
|
3590
3600
|
if (timestamp === void 0) return;
|
|
3591
3601
|
return timestampDate(timestamp).getTime();
|
|
@@ -4190,6 +4200,67 @@ async function claimTransfer(options) {
|
|
|
4190
4200
|
if (response.transfer === void 0) throw new SparkError("claimTransfer: coordinator returned no transfer");
|
|
4191
4201
|
return verifyClaimedLeaves(receiverLeaves(response.transfer.leaves, receiverId));
|
|
4192
4202
|
}
|
|
4203
|
+
/** Upstream `DEFAULT_RETRY_CONFIG`: five attempts, 1 s base, doubling — 1/2/4/8 s between tries. */
|
|
4204
|
+
const CLAIM_RETRY_DELAYS_MS = [
|
|
4205
|
+
1e3,
|
|
4206
|
+
2e3,
|
|
4207
|
+
4e3,
|
|
4208
|
+
8e3
|
|
4209
|
+
];
|
|
4210
|
+
/** Resolves after `ms` — injected so tests control the pace — or rejects promptly on abort. */
|
|
4211
|
+
async function abortableWait(ms, sleep, signal) {
|
|
4212
|
+
if (signal === void 0) {
|
|
4213
|
+
await sleep(ms);
|
|
4214
|
+
return;
|
|
4215
|
+
}
|
|
4216
|
+
if (signal.aborted) throw new SparkRequestError("claim aborted", { code: "canceled" });
|
|
4217
|
+
let onAbort;
|
|
4218
|
+
const aborted = new Promise((_resolve, reject) => {
|
|
4219
|
+
onAbort = () => {
|
|
4220
|
+
reject(new SparkRequestError("claim aborted", { code: "canceled" }));
|
|
4221
|
+
};
|
|
4222
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
4223
|
+
});
|
|
4224
|
+
try {
|
|
4225
|
+
await Promise.race([sleep(ms), aborted]);
|
|
4226
|
+
} finally {
|
|
4227
|
+
if (onAbort !== void 0) signal.removeEventListener("abort", onAbort);
|
|
4228
|
+
}
|
|
4229
|
+
}
|
|
4230
|
+
/**
|
|
4231
|
+
* Receiver claim by transfer id (upstream `TransferService.claimTransfer` with `withRetry` and
|
|
4232
|
+
* re-query). Every attempt re-queries the transfer: a receiver-leg-complete row returns `[]`, a
|
|
4233
|
+
* claimable one is claimed through the caller's `claim` (which serializes the claim plus its chain
|
|
4234
|
+
* store under the client leaf lock), a still-transient status waits and retries, and a terminal or
|
|
4235
|
+
* unrecognized status fails immediately — retrying `EXPIRED`/`RETURNED` can only burn the budget. A
|
|
4236
|
+
* transfer absent from the coordinator's index is treated as transient: the receive event can land
|
|
4237
|
+
* seconds before the SSP marks the transfer claimable.
|
|
4238
|
+
*/
|
|
4239
|
+
async function claimByTransferId(options) {
|
|
4240
|
+
const { spark, signer, network, transferId, sleep, signal, claim } = options;
|
|
4241
|
+
const self = await signer.identityPublicKey();
|
|
4242
|
+
for (let attempt = 0;; attempt += 1) {
|
|
4243
|
+
if (signal?.aborted === true) throw new SparkRequestError("claim aborted", { code: "canceled" });
|
|
4244
|
+
const [row] = await queryTransfersByIds({
|
|
4245
|
+
spark,
|
|
4246
|
+
transferIds: [transferId],
|
|
4247
|
+
network
|
|
4248
|
+
});
|
|
4249
|
+
const transfer = row === void 0 ? void 0 : mapTransfer(row);
|
|
4250
|
+
if (transfer !== void 0) {
|
|
4251
|
+
if (isReceiverLegComplete(transfer, self)) return [];
|
|
4252
|
+
if (CLAIMABLE_TRANSFER_STATUSES.includes(transfer.status)) try {
|
|
4253
|
+
return await claim(transfer);
|
|
4254
|
+
} catch (error) {
|
|
4255
|
+
if (!(error instanceof SparkRequestError) || error.code !== "already_exists") throw error;
|
|
4256
|
+
}
|
|
4257
|
+
else if (!TRANSIENT_TRANSFER_STATUSES.includes(transfer.status)) throw new SparkInputError(`claim: transfer ${transferId} status ${transfer.status} is not claimable`);
|
|
4258
|
+
}
|
|
4259
|
+
const delay = CLAIM_RETRY_DELAYS_MS[attempt];
|
|
4260
|
+
if (delay === void 0) throw new SparkRequestError(`claim: transfer ${transferId} did not become claimable`, { code: "deadline_exceeded" });
|
|
4261
|
+
await abortableWait(delay, sleep, signal);
|
|
4262
|
+
}
|
|
4263
|
+
}
|
|
4193
4264
|
//#endregion
|
|
4194
4265
|
//#region src/transfer/send.ts
|
|
4195
4266
|
/**
|
|
@@ -5842,13 +5913,19 @@ function createTransfers(context) {
|
|
|
5842
5913
|
})),
|
|
5843
5914
|
...sendOptions.transferId === void 0 ? {} : { transferId: sendOptions.transferId }
|
|
5844
5915
|
}),
|
|
5845
|
-
claim: async (
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
}
|
|
5850
|
-
|
|
5851
|
-
|
|
5916
|
+
claim: async (transferId, claimOptions) => claimByTransferId({
|
|
5917
|
+
...context.transferCoordinator,
|
|
5918
|
+
transferId,
|
|
5919
|
+
sleep: context.sleep ?? defaultSleep,
|
|
5920
|
+
...claimOptions?.signal === void 0 ? {} : { signal: claimOptions.signal },
|
|
5921
|
+
claim: async (transfer) => context.leafLock.run(async () => {
|
|
5922
|
+
const claimed = await claimTransfer({
|
|
5923
|
+
...context.transferCoordinator,
|
|
5924
|
+
transfer
|
|
5925
|
+
});
|
|
5926
|
+
await context.storeChainsFor(claimed);
|
|
5927
|
+
return claimed;
|
|
5928
|
+
})
|
|
5852
5929
|
}),
|
|
5853
5930
|
claimPending: async () => {
|
|
5854
5931
|
const pending = await queryPendingTransfers({
|
|
@@ -7328,4 +7405,4 @@ function createMemorySparkStore() {
|
|
|
7328
7405
|
};
|
|
7329
7406
|
}
|
|
7330
7407
|
//#endregion
|
|
7331
|
-
export { EPHEMERAL_ANCHOR_SCRIPT, MIN_STATIC_REFUND_FEE_SATS, SparkCryptoError, SparkError, SparkInputError, SparkRequestError, SparkTokenBroadcastError, addressToScript, buildCpfpChild, createMemorySparkStore, createSatsInvoice, createSparkClient, createTokensInvoice, decodeBolt11, decodeSparkAddress, decodeTokenIdentifier, encodeSparkAddress, encodeTokenIdentifier, exitTransactions, isExpired, parseSparkInvoice, sparkNetworkConfig, verifySparkAddressSignature };
|
|
7408
|
+
export { EPHEMERAL_ANCHOR_SCRIPT, MIN_STATIC_REFUND_FEE_SATS, SparkCryptoError, SparkError, SparkInputError, SparkRequestError, SparkTokenBroadcastError, addressToScript, buildCpfpChild, createMemorySparkStore, createSatsInvoice, createSparkClient, createTokensInvoice, decodeBolt11, decodeSparkAddress, decodeTokenIdentifier, encodeSparkAddress, encodeTokenIdentifier, exitTransactions, isExpired, parseSparkInvoice, sparkNetworkConfig, uuidv7, verifySparkAddressSignature };
|
package/dist/server.d.mts
CHANGED