@breeztech/breez-sdk-spark 0.20.0-dev1 → 0.21.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.
@@ -40,6 +40,16 @@ const RESERVATION_TIMEOUT_SECS = 300; // 5 minutes
40
40
  */
41
41
  const SPENT_MARKER_CLEANUP_THRESHOLD_MS = 5 * 60 * 1000; // 5 minutes
42
42
 
43
+ /**
44
+ * Leaves per INSERT when upserting a refreshed leaf set.
45
+ *
46
+ * A wallet can hold six figures of leaves, each serializing to a JSON blob
47
+ * carrying up to five transactions. Building that as a single statement
48
+ * materializes the whole set at once, which is the largest allocation in a
49
+ * refresh and lands at its very end.
50
+ */
51
+ const LEAF_UPSERT_CHUNK_SIZE = 1000;
52
+
43
53
  /**
44
54
  * Slim projection: only (id, value) for leaves the selection might use.
45
55
  * Includes all leaves with value <= $2 (covers exact-match + the small-leaf
@@ -1019,23 +1029,29 @@ class PostgresTreeStore {
1019
1029
 
1020
1030
  if (filtered.length === 0) return;
1021
1031
 
1022
- const ids = filtered.map((l) => l.id);
1023
- const statuses = filtered.map((l) => l.status);
1024
- const missingFlags = filtered.map(() => isMissingFromOperators);
1025
- const dataValues = filtered.map((l) => JSON.stringify(l));
1026
-
1027
- await client.query(
1028
- `INSERT INTO brz_tree_leaves (user_id, id, status, is_missing_from_operators, data, added_at)
1029
- SELECT $5, id, status, missing, data::jsonb, NOW()
1030
- FROM UNNEST($1::text[], $2::text[], $3::bool[], $4::text[])
1031
- AS t(id, status, missing, data)
1032
- ON CONFLICT (user_id, id) DO UPDATE SET
1033
- status = EXCLUDED.status,
1034
- is_missing_from_operators = EXCLUDED.is_missing_from_operators,
1035
- data = EXCLUDED.data,
1036
- added_at = NOW()`,
1037
- [ids, statuses, missingFlags, dataValues, this.identity]
1038
- );
1032
+ // All chunks run inside the caller's transaction, and NOW() is the
1033
+ // transaction timestamp, so every row still lands atomically with one
1034
+ // shared added_at.
1035
+ for (let i = 0; i < filtered.length; i += LEAF_UPSERT_CHUNK_SIZE) {
1036
+ const chunk = filtered.slice(i, i + LEAF_UPSERT_CHUNK_SIZE);
1037
+ const ids = chunk.map((l) => l.id);
1038
+ const statuses = chunk.map((l) => l.status);
1039
+ const missingFlags = chunk.map(() => isMissingFromOperators);
1040
+ const dataValues = chunk.map((l) => JSON.stringify(l));
1041
+
1042
+ await client.query(
1043
+ `INSERT INTO brz_tree_leaves (user_id, id, status, is_missing_from_operators, data, added_at)
1044
+ SELECT $5, id, status, missing, data::jsonb, NOW()
1045
+ FROM UNNEST($1::text[], $2::text[], $3::bool[], $4::text[])
1046
+ AS t(id, status, missing, data)
1047
+ ON CONFLICT (user_id, id) DO UPDATE SET
1048
+ status = EXCLUDED.status,
1049
+ is_missing_from_operators = EXCLUDED.is_missing_from_operators,
1050
+ data = EXCLUDED.data,
1051
+ added_at = NOW()`,
1052
+ [ids, statuses, missingFlags, dataValues, this.identity]
1053
+ );
1054
+ }
1039
1055
  }
1040
1056
 
1041
1057
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@breeztech/breez-sdk-spark",
3
- "version": "0.20.0-dev1",
3
+ "version": "0.21.0",
4
4
  "description": "Breez Spark SDK",
5
5
  "repository": "https://github.com/breez/spark-sdk",
6
6
  "author": "Breez <contact@breez.technology> (https://github.com/breez)",
@@ -89,7 +89,7 @@ interface WasmTokenOutputWithPrevOut {
89
89
  }
90
90
 
91
91
  interface WasmTokenOutputs {
92
- metadata: WasmTokenMetadata;
92
+ metadata: WasmTokenMetadata[];
93
93
  outputs: WasmTokenOutputWithPrevOut[];
94
94
  }
95
95
 
@@ -119,26 +119,23 @@ type WasmReservationTarget =
119
119
  | { type: 'maxOutputCount'; value: number };
120
120
 
121
121
  export interface TokenStore {
122
- setTokensOutputs: (tokenOutputs: WasmTokenOutputs[], refreshStartedAtMs: number) => Promise<void>;
122
+ setTokensOutputs: (tokenOutputs: WasmTokenOutputs, refreshStartedAtMs: number) => Promise<void>;
123
123
  listTokensOutputs: () => Promise<WasmTokenOutputsPerStatus[]>;
124
124
  getTokenBalances: () => Promise<WasmTokenBalance[]>;
125
125
  getTokenOutputs: (filter: WasmGetTokenOutputsFilter) => Promise<WasmTokenOutputsPerStatus>;
126
- updateTokenOutputs: (outputsToRemove: [string, number][], outputsToAdd: WasmTokenOutputs | null) => Promise<void>;
126
+ updateTokenOutputs: (outputsToRemove: [string, number][], outputsToAdd: WasmTokenOutputs) => Promise<void>;
127
127
  reserveTokenOutputs: (
128
- tokenIdentifier: string,
129
- target: WasmReservationTarget,
128
+ targets: [string, WasmReservationTarget][],
130
129
  purpose: string,
131
130
  preferredOutputs: WasmTokenOutputWithPrevOut[] | null,
132
131
  selectionStrategy: string | null
133
132
  ) => Promise<WasmTokenOutputsReservation>;
134
133
  selectTokenOutputs: (
135
- tokenIdentifier: string,
136
- target: WasmReservationTarget,
134
+ targets: [string, WasmReservationTarget][],
137
135
  preferredOutputs: WasmTokenOutputWithPrevOut[] | null,
138
136
  selectionStrategy: string | null
139
137
  ) => Promise<WasmTokenOutputs>;
140
138
  reserveTokenOutputsByOutpoints: (
141
- tokenIdentifier: string,
142
139
  outpoints: { prevTxHash: string; prevTxVout: number }[],
143
140
  purpose: string
144
141
  ) => Promise<WasmTokenOutputsReservation>;
@@ -147,6 +144,20 @@ export interface TokenStore {
147
144
  now: () => Promise<number>;
148
145
  }
149
146
 
147
+ /**
148
+ * A created credential, plus the PRF outputs when the browser evaluated
149
+ * them during the create ceremony. `seeds` is null when it did not, so
150
+ * the caller derives through `deriveSeeds`.
151
+ *
152
+ * Seeds returned here must equal what `deriveSeeds` returns for the same
153
+ * salts: the wallet is derived from them either way, so a mismatch means
154
+ * register and sign-in land on different wallets.
155
+ */
156
+ export interface CreatePasskeyOutput {
157
+ credential: PasskeyCredential;
158
+ seeds?: Uint8Array[] | null;
159
+ }
160
+
150
161
  /**
151
162
  * A passkey credential from `register` or `signIn`. `credentialId` is
152
163
  * always set. The attestation fields (`userId`, `aaguid`,
@@ -297,10 +308,14 @@ export interface PrfProvider {
297
308
  * `excludeCredentials` lists already-registered IDs; a match raises
298
309
  * `PasskeyAlreadyExistsError`.
299
310
  *
311
+ * Evaluating PRF for `salts` in the same ceremony returns the seeds on
312
+ * `seeds`, and the caller then needs no assertion. Return `seeds: null`
313
+ * when the authenticator evaluated none, or fewer than one per salt.
314
+ *
300
315
  * @throws `PasskeyAlreadyExistsError` when an entry in
301
316
  * `excludeCredentials` matches a credential already on the device.
302
317
  */
303
- createPasskey?(excludeCredentials: Uint8Array[]): Promise<PasskeyCredential>;
318
+ createPasskey?(excludeCredentials: Uint8Array[], salts: string[]): Promise<CreatePasskeyOutput>;
304
319
 
305
320
  /**
306
321
  * Whether this provider can produce PRF outputs on the current
@@ -488,6 +503,17 @@ export interface AuthorizeTransferRequest {
488
503
  transfereePubkey: string;
489
504
  }
490
505
 
506
+ export interface BatchRecipient {
507
+ paymentRequest: string;
508
+ amount?: bigint;
509
+ tokenIdentifier?: string;
510
+ }
511
+
512
+ export interface BatchTotal {
513
+ tokenIdentifier?: string;
514
+ amount: bigint;
515
+ }
516
+
491
517
  export interface Bip21Details {
492
518
  amountSat?: number;
493
519
  assetId?: string;
@@ -585,6 +611,10 @@ export interface Bolt12OfferDetails {
585
611
  signingPubkey?: string;
586
612
  }
587
613
 
614
+ export interface BuildUnsignedBatchPackageRequest {
615
+ prepareResponse: PrepareSendBatchResponse;
616
+ }
617
+
588
618
  export interface BuildUnsignedLnurlPayPackageRequest {
589
619
  prepareResponse: PrepareLnurlPayResponse;
590
620
  }
@@ -1315,6 +1345,15 @@ export interface PrepareLnurlPayResponse {
1315
1345
  feePolicy: FeePolicy;
1316
1346
  }
1317
1347
 
1348
+ export interface PrepareSendBatchRequest {
1349
+ recipients: BatchRecipient[];
1350
+ }
1351
+
1352
+ export interface PrepareSendBatchResponse {
1353
+ recipients: ResolvedBatchRecipient[];
1354
+ totals: BatchTotal[];
1355
+ }
1356
+
1318
1357
  export interface PrepareSendPaymentRequest {
1319
1358
  paymentRequest: PaymentRequest;
1320
1359
  amount?: bigint;
@@ -1445,6 +1484,12 @@ export interface RegisterWebhookResponse {
1445
1484
  webhookId: string;
1446
1485
  }
1447
1486
 
1487
+ export interface ResolvedBatchRecipient {
1488
+ destination: BatchDestination;
1489
+ amount: bigint;
1490
+ tokenIdentifier?: string;
1491
+ }
1492
+
1448
1493
  export interface RestClient {
1449
1494
  getRequest(url: string, headers?: Record<string, string>): Promise<RestResponse>;
1450
1495
  postRequest(url: string, headers?: Record<string, string>, body?: string): Promise<RestResponse>;
@@ -1464,6 +1509,14 @@ export interface SecretBytes {
1464
1509
  bytes: number[];
1465
1510
  }
1466
1511
 
1512
+ export interface SendBatchRequest {
1513
+ prepareResponse: PrepareSendBatchResponse;
1514
+ }
1515
+
1516
+ export interface SendBatchResponse {
1517
+ payments: Payment[];
1518
+ }
1519
+
1467
1520
  export interface SendOnchainFeeQuote {
1468
1521
  id: string;
1469
1522
  expiresAt: number;
@@ -1822,6 +1875,8 @@ export type AssetFilter = { type: "bitcoin" } | { type: "token"; tokenIdentifier
1822
1875
 
1823
1876
  export type AutoOptimizationEvent = { type: "started"; totalRounds: number } | { type: "roundCompleted"; currentRound: number; totalRounds: number } | { type: "completed" } | { type: "cancelled" } | { type: "failed"; error: string } | { type: "skipped" };
1824
1877
 
1878
+ export type BatchDestination = { type: "sparkAddress"; address: string } | { type: "sparkInvoice"; invoiceDetails: SparkInvoiceDetails };
1879
+
1825
1880
  export type BitcoinNetwork = "bitcoin" | "testnet3" | "testnet4" | "signet" | "regtest";
1826
1881
 
1827
1882
  export type BuildTransferPackageOptions = { type: "bitcoinAddress"; confirmationSpeed: OnchainConfirmationSpeed } | { type: "bolt11Invoice"; preferSpark: boolean; completionTimeoutSecs?: number };
@@ -1906,7 +1961,7 @@ export type ProvisionalPaymentDetails = { type: "bitcoin"; withdrawalAddress: st
1906
1961
 
1907
1962
  export type PublishSignedLnurlPayResponse = { type: "swapCompleted" } | { type: "paymentSent"; response: LnurlPayResponse };
1908
1963
 
1909
- export type PublishSignedTransferPackageResponse = { type: "swapCompleted" } | { type: "paymentSent"; payment: Payment };
1964
+ export type PublishSignedTransferPackageResponse = { type: "swapCompleted" } | { type: "paymentSent"; payment: Payment } | { type: "paymentsSent"; payments: Payment[] };
1910
1965
 
1911
1966
  export type ReceivePaymentMethod = { type: "sparkAddress" } | { type: "sparkInvoice"; amount?: string; tokenIdentifier?: string; expiryTime?: number; description?: string; senderPublicKey?: string } | { type: "bitcoinAddress"; newAddress?: boolean } | { type: "bolt11Invoice"; description: string; amountSats?: number; expirySecs?: number; paymentHash?: string };
1912
1967
 
@@ -1944,7 +1999,7 @@ export type TransferTarget = { type: "spark"; address: string; sparkInvoice?: st
1944
1999
 
1945
2000
  export type UnilateralExitTxKind = "fanOut" | "node" | "refund" | "sweep";
1946
2001
 
1947
- export type UnsignedTransferPackage = { type: "swap"; prepareTransfer: ExternalPrepareTransferRequest; targetAmounts: number[]; amountSat: number; feeSat: number } | { type: "transfer"; prepareTransfer: ExternalPrepareTransferRequest; amountSat: number; feeSat: number; target: TransferTarget } | { type: "token"; prepareTokenTransaction: ExternalPrepareTokenTransactionRequest; tokenContext: number[]; tokenIdentifier: string; amount: string; fee: string; isSwap: boolean };
2002
+ export type UnsignedTransferPackage = { type: "swap"; prepareTransfer: ExternalPrepareTransferRequest; targetAmounts: number[]; amountSat: number; feeSat: number } | { type: "transfer"; prepareTransfer: ExternalPrepareTransferRequest; amountSat: number; feeSat: number; target: TransferTarget } | { type: "token"; prepareTokenTransaction: ExternalPrepareTokenTransactionRequest; tokenContext: number[]; tokenIdentifier: string; amount: string; fee: string; isSwap: boolean } | { type: "tokenBatch"; prepareTokenTransaction: ExternalPrepareTokenTransactionRequest; tokenContext: number[]; totals: BatchTotal[]; isSwap: boolean };
1948
2003
 
1949
2004
  export type UpdateDepositPayload = { type: "claimError"; error: DepositClaimError } | { type: "refund"; refundTxid: string; refundTx: string };
1950
2005
 
@@ -1979,6 +2034,7 @@ export class BreezSdk {
1979
2034
  addContact(request: AddContactRequest): Promise<Contact>;
1980
2035
  addEventListener(listener: EventListener): Promise<string>;
1981
2036
  authorizeLightningAddressTransfer(request: AuthorizeTransferRequest): Promise<TransferAuthorization>;
2037
+ buildUnsignedBatchPackage(request: BuildUnsignedBatchPackageRequest): Promise<UnsignedTransferPackage>;
1982
2038
  buildUnsignedLnurlPayPackage(request: BuildUnsignedLnurlPayPackageRequest): Promise<UnsignedTransferPackage>;
1983
2039
  buildUnsignedTransferPackage(request: BuildUnsignedTransferPackageRequest): Promise<UnsignedTransferPackage>;
1984
2040
  buyBitcoin(request: BuyBitcoinRequest): Promise<BuyBitcoinResponse>;
@@ -2010,6 +2066,7 @@ export class BreezSdk {
2010
2066
  optimizeLeaves(request: OptimizeLeavesRequest): Promise<OptimizeLeavesResponse>;
2011
2067
  parse(input: string): Promise<InputType>;
2012
2068
  prepareLnurlPay(request: PrepareLnurlPayRequest): Promise<PrepareLnurlPayResponse>;
2069
+ prepareSendBatch(request: PrepareSendBatchRequest): Promise<PrepareSendBatchResponse>;
2013
2070
  prepareSendPayment(request: PrepareSendPaymentRequest): Promise<PrepareSendPaymentResponse>;
2014
2071
  prepareUnilateralExit(request: PrepareUnilateralExitRequest): Promise<PrepareUnilateralExitResponse>;
2015
2072
  publishSignedLnurlPayPackage(request: PublishSignedLnurlPayPackageRequest): Promise<PublishSignedLnurlPayResponse>;
@@ -2021,6 +2078,7 @@ export class BreezSdk {
2021
2078
  registerLightningAddress(request: RegisterLightningAddressRequest): Promise<LightningAddressInfo>;
2022
2079
  registerWebhook(request: RegisterWebhookRequest): Promise<RegisterWebhookResponse>;
2023
2080
  removeEventListener(id: string): Promise<boolean>;
2081
+ sendBatch(request: SendBatchRequest): Promise<SendBatchResponse>;
2024
2082
  sendPayment(request: SendPaymentRequest): Promise<SendPaymentResponse>;
2025
2083
  signMessage(request: SignMessageRequest): Promise<SignMessageResponse>;
2026
2084
  syncWallet(request: SyncWalletRequest): Promise<SyncWalletResponse>;
@@ -2502,6 +2560,7 @@ export interface InitOutput {
2502
2560
  readonly breezsdk_addContact: (a: number, b: any) => any;
2503
2561
  readonly breezsdk_addEventListener: (a: number, b: any) => any;
2504
2562
  readonly breezsdk_authorizeLightningAddressTransfer: (a: number, b: any) => any;
2563
+ readonly breezsdk_buildUnsignedBatchPackage: (a: number, b: any) => any;
2505
2564
  readonly breezsdk_buildUnsignedLnurlPayPackage: (a: number, b: any) => any;
2506
2565
  readonly breezsdk_buildUnsignedTransferPackage: (a: number, b: any) => any;
2507
2566
  readonly breezsdk_buyBitcoin: (a: number, b: any) => any;
@@ -2533,6 +2592,7 @@ export interface InitOutput {
2533
2592
  readonly breezsdk_optimizeLeaves: (a: number, b: any) => any;
2534
2593
  readonly breezsdk_parse: (a: number, b: number, c: number) => any;
2535
2594
  readonly breezsdk_prepareLnurlPay: (a: number, b: any) => any;
2595
+ readonly breezsdk_prepareSendBatch: (a: number, b: any) => any;
2536
2596
  readonly breezsdk_prepareSendPayment: (a: number, b: any) => any;
2537
2597
  readonly breezsdk_prepareUnilateralExit: (a: number, b: any) => any;
2538
2598
  readonly breezsdk_publishSignedLnurlPayPackage: (a: number, b: any) => any;
@@ -2544,6 +2604,7 @@ export interface InitOutput {
2544
2604
  readonly breezsdk_registerLightningAddress: (a: number, b: any) => any;
2545
2605
  readonly breezsdk_registerWebhook: (a: number, b: any) => any;
2546
2606
  readonly breezsdk_removeEventListener: (a: number, b: number, c: number) => any;
2607
+ readonly breezsdk_sendBatch: (a: number, b: any) => any;
2547
2608
  readonly breezsdk_sendPayment: (a: number, b: any) => any;
2548
2609
  readonly breezsdk_signMessage: (a: number, b: any) => any;
2549
2610
  readonly breezsdk_syncWallet: (a: number, b: any) => any;
@@ -137,6 +137,14 @@ export class BreezSdk {
137
137
  const ret = wasm.breezsdk_authorizeLightningAddressTransfer(this.__wbg_ptr, request);
138
138
  return ret;
139
139
  }
140
+ /**
141
+ * @param {BuildUnsignedBatchPackageRequest} request
142
+ * @returns {Promise<UnsignedTransferPackage>}
143
+ */
144
+ buildUnsignedBatchPackage(request) {
145
+ const ret = wasm.breezsdk_buildUnsignedBatchPackage(this.__wbg_ptr, request);
146
+ return ret;
147
+ }
140
148
  /**
141
149
  * @param {BuildUnsignedLnurlPayPackageRequest} request
142
150
  * @returns {Promise<UnsignedTransferPackage>}
@@ -381,6 +389,14 @@ export class BreezSdk {
381
389
  const ret = wasm.breezsdk_prepareLnurlPay(this.__wbg_ptr, request);
382
390
  return ret;
383
391
  }
392
+ /**
393
+ * @param {PrepareSendBatchRequest} request
394
+ * @returns {Promise<PrepareSendBatchResponse>}
395
+ */
396
+ prepareSendBatch(request) {
397
+ const ret = wasm.breezsdk_prepareSendBatch(this.__wbg_ptr, request);
398
+ return ret;
399
+ }
384
400
  /**
385
401
  * @param {PrepareSendPaymentRequest} request
386
402
  * @returns {Promise<PrepareSendPaymentResponse>}
@@ -469,6 +485,14 @@ export class BreezSdk {
469
485
  const ret = wasm.breezsdk_removeEventListener(this.__wbg_ptr, ptr0, len0);
470
486
  return ret;
471
487
  }
488
+ /**
489
+ * @param {SendBatchRequest} request
490
+ * @returns {Promise<SendBatchResponse>}
491
+ */
492
+ sendBatch(request) {
493
+ const ret = wasm.breezsdk_sendBatch(this.__wbg_ptr, request);
494
+ return ret;
495
+ }
472
496
  /**
473
497
  * @param {SendPaymentRequest} request
474
498
  * @returns {Promise<SendPaymentResponse>}
@@ -2200,8 +2224,8 @@ function __wbg_get_imports() {
2200
2224
  const ret = createMysqlTreeStoreWithPool(arg0, getArrayU8FromWasm0(arg1, arg2), arg3, arg4, arg5 !== 0);
2201
2225
  return ret;
2202
2226
  }, arguments); },
2203
- __wbg_createPasskey_5ceae054474c582a: function() { return handleError(function (arg0, arg1) {
2204
- const ret = arg0.createPasskey(arg1);
2227
+ __wbg_createPasskey_37eb4d30fdaf2a3f: function() { return handleError(function (arg0, arg1, arg2) {
2228
+ const ret = arg0.createPasskey(arg1, arg2);
2205
2229
  return ret;
2206
2230
  }, arguments); },
2207
2231
  __wbg_createPostgresPool_3c396c7ab2f0eab2: function() { return handleError(function (arg0) {
@@ -3068,38 +3092,28 @@ function __wbg_get_imports() {
3068
3092
  const ret = module.require;
3069
3093
  return ret;
3070
3094
  }, arguments); },
3071
- __wbg_reserveTokenOutputsByOutpoints_a18be5f9fb4ab30a: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) {
3095
+ __wbg_reserveTokenOutputsByOutpoints_2b3aa01becdba378: function() { return handleError(function (arg0, arg1, arg2, arg3) {
3072
3096
  let deferred0_0;
3073
3097
  let deferred0_1;
3074
- let deferred1_0;
3075
- let deferred1_1;
3076
3098
  try {
3077
- deferred0_0 = arg1;
3078
- deferred0_1 = arg2;
3079
- deferred1_0 = arg4;
3080
- deferred1_1 = arg5;
3081
- const ret = arg0.reserveTokenOutputsByOutpoints(getStringFromWasm0(arg1, arg2), arg3, getStringFromWasm0(arg4, arg5));
3099
+ deferred0_0 = arg2;
3100
+ deferred0_1 = arg3;
3101
+ const ret = arg0.reserveTokenOutputsByOutpoints(arg1, getStringFromWasm0(arg2, arg3));
3082
3102
  return ret;
3083
3103
  } finally {
3084
3104
  wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
3085
- wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
3086
3105
  }
3087
3106
  }, arguments); },
3088
- __wbg_reserveTokenOutputs_233990fbd0ce963a: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) {
3107
+ __wbg_reserveTokenOutputs_17ba3b5fcc91b000: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) {
3089
3108
  let deferred0_0;
3090
3109
  let deferred0_1;
3091
- let deferred1_0;
3092
- let deferred1_1;
3093
3110
  try {
3094
- deferred0_0 = arg1;
3095
- deferred0_1 = arg2;
3096
- deferred1_0 = arg4;
3097
- deferred1_1 = arg5;
3098
- const ret = arg0.reserveTokenOutputs(getStringFromWasm0(arg1, arg2), arg3, getStringFromWasm0(arg4, arg5), arg6, arg7);
3111
+ deferred0_0 = arg2;
3112
+ deferred0_1 = arg3;
3113
+ const ret = arg0.reserveTokenOutputs(arg1, getStringFromWasm0(arg2, arg3), arg4, arg5);
3099
3114
  return ret;
3100
3115
  } finally {
3101
3116
  wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
3102
- wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
3103
3117
  }
3104
3118
  }, arguments); },
3105
3119
  __wbg_resolve_9feb5d906ca62419: function(arg0) {
@@ -3113,17 +3127,9 @@ function __wbg_get_imports() {
3113
3127
  const ret = SdkBuilder.__wrap(arg0);
3114
3128
  return ret;
3115
3129
  },
3116
- __wbg_selectTokenOutputs_450f20621013b14d: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) {
3117
- let deferred0_0;
3118
- let deferred0_1;
3119
- try {
3120
- deferred0_0 = arg1;
3121
- deferred0_1 = arg2;
3122
- const ret = arg0.selectTokenOutputs(getStringFromWasm0(arg1, arg2), arg3, arg4, arg5);
3123
- return ret;
3124
- } finally {
3125
- wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
3126
- }
3130
+ __wbg_selectTokenOutputs_378aebd65f866d1b: function() { return handleError(function (arg0, arg1, arg2, arg3) {
3131
+ const ret = arg0.selectTokenOutputs(arg1, arg2, arg3);
3132
+ return ret;
3127
3133
  }, arguments); },
3128
3134
  __wbg_send_0edb796d05cd3239: function() { return handleError(function (arg0, arg1, arg2) {
3129
3135
  arg0.send(getStringFromWasm0(arg1, arg2));
@@ -3578,27 +3584,27 @@ function __wbg_get_imports() {
3578
3584
  return ret;
3579
3585
  },
3580
3586
  __wbindgen_cast_0000000000000002: function(arg0, arg1) {
3581
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 389, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3587
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 392, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3582
3588
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h3120db8c4a8a92b2);
3583
3589
  return ret;
3584
3590
  },
3585
3591
  __wbindgen_cast_0000000000000003: function(arg0, arg1) {
3586
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("CloseEvent")], shim_idx: 389, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3592
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("CloseEvent")], shim_idx: 392, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3587
3593
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h3120db8c4a8a92b2_2);
3588
3594
  return ret;
3589
3595
  },
3590
3596
  __wbindgen_cast_0000000000000004: function(arg0, arg1) {
3591
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("ErrorEvent")], shim_idx: 389, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3597
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("ErrorEvent")], shim_idx: 392, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3592
3598
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h3120db8c4a8a92b2_3);
3593
3599
  return ret;
3594
3600
  },
3595
3601
  __wbindgen_cast_0000000000000005: function(arg0, arg1) {
3596
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 389, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3602
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 392, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3597
3603
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h3120db8c4a8a92b2_4);
3598
3604
  return ret;
3599
3605
  },
3600
3606
  __wbindgen_cast_0000000000000006: function(arg0, arg1) {
3601
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("MessageEvent")], shim_idx: 389, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3607
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("MessageEvent")], shim_idx: 392, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3602
3608
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h3120db8c4a8a92b2_5);
3603
3609
  return ret;
3604
3610
  },
@@ -3623,12 +3629,12 @@ function __wbg_get_imports() {
3623
3629
  return ret;
3624
3630
  },
3625
3631
  __wbindgen_cast_000000000000000b: function(arg0, arg1) {
3626
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 394, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3632
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 397, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3627
3633
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h1d6669a7b693932a);
3628
3634
  return ret;
3629
3635
  },
3630
3636
  __wbindgen_cast_000000000000000c: function(arg0, arg1) {
3631
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 425, ret: Unit, inner_ret: Some(Unit) }, mutable: false }) -> Externref`.
3637
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 427, ret: Unit, inner_ret: Some(Unit) }, mutable: false }) -> Externref`.
3632
3638
  const ret = makeClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h0fa3f876e31d2a3e);
3633
3639
  return ret;
3634
3640
  },
Binary file
@@ -21,6 +21,7 @@ export const bitcoinchainservicehandle_recommendedFees: (a: number) => any;
21
21
  export const breezsdk_addContact: (a: number, b: any) => any;
22
22
  export const breezsdk_addEventListener: (a: number, b: any) => any;
23
23
  export const breezsdk_authorizeLightningAddressTransfer: (a: number, b: any) => any;
24
+ export const breezsdk_buildUnsignedBatchPackage: (a: number, b: any) => any;
24
25
  export const breezsdk_buildUnsignedLnurlPayPackage: (a: number, b: any) => any;
25
26
  export const breezsdk_buildUnsignedTransferPackage: (a: number, b: any) => any;
26
27
  export const breezsdk_buyBitcoin: (a: number, b: any) => any;
@@ -52,6 +53,7 @@ export const breezsdk_lnurlWithdraw: (a: number, b: any) => any;
52
53
  export const breezsdk_optimizeLeaves: (a: number, b: any) => any;
53
54
  export const breezsdk_parse: (a: number, b: number, c: number) => any;
54
55
  export const breezsdk_prepareLnurlPay: (a: number, b: any) => any;
56
+ export const breezsdk_prepareSendBatch: (a: number, b: any) => any;
55
57
  export const breezsdk_prepareSendPayment: (a: number, b: any) => any;
56
58
  export const breezsdk_prepareUnilateralExit: (a: number, b: any) => any;
57
59
  export const breezsdk_publishSignedLnurlPayPackage: (a: number, b: any) => any;
@@ -63,6 +65,7 @@ export const breezsdk_refundPendingConversions: (a: number) => any;
63
65
  export const breezsdk_registerLightningAddress: (a: number, b: any) => any;
64
66
  export const breezsdk_registerWebhook: (a: number, b: any) => any;
65
67
  export const breezsdk_removeEventListener: (a: number, b: number, c: number) => any;
68
+ export const breezsdk_sendBatch: (a: number, b: any) => any;
66
69
  export const breezsdk_sendPayment: (a: number, b: any) => any;
67
70
  export const breezsdk_signMessage: (a: number, b: any) => any;
68
71
  export const breezsdk_syncWallet: (a: number, b: any) => any;
@@ -4,11 +4,18 @@ import type {
4
4
  PasskeyProviderOptions,
5
5
  PrfProvider,
6
6
  PasskeyCredential,
7
+ CreatePasskeyOutput,
7
8
  DeriveSeedsResult,
8
9
  DeriveSeedOptions
9
10
  } from '../breez_sdk_spark_wasm.js';
10
11
 
11
- export type { PasskeyCredential, DeriveSeedsResult, DeriveSeedOptions, PasskeyProviderOptions };
12
+ export type {
13
+ PasskeyCredential,
14
+ CreatePasskeyOutput,
15
+ DeriveSeedsResult,
16
+ DeriveSeedOptions,
17
+ PasskeyProviderOptions
18
+ };
12
19
 
13
20
  /**
14
21
  * Outcome of a domain-association check: whether `rpId` is a valid
@@ -135,7 +142,7 @@ export declare class PasskeyProvider {
135
142
  * `excludeCredentials` already exists on the device.
136
143
  * @throws If the user cancels or PRF is not supported.
137
144
  */
138
- createPasskey(excludeCredentials?: Uint8Array[]): Promise<PasskeyCredential>;
145
+ createPasskey(excludeCredentials?: Uint8Array[], salts?: string[]): Promise<CreatePasskeyOutput>;
139
146
 
140
147
  /**
141
148
  * Check if a PRF-capable passkey is available on this device.
@@ -259,12 +259,19 @@ export class PasskeyProvider {
259
259
  * `excludeCredentials` (already-registered IDs) to surface a repeat
260
260
  * registration as `PasskeyAlreadyExistsError`.
261
261
  *
262
+ * Asking the create ceremony to evaluate PRF for `salts` removes the
263
+ * assertion that would otherwise follow it, so registration costs one
264
+ * prompt instead of two. Browsers that acknowledge PRF without
265
+ * evaluating return `seeds: null` and the caller derives as before.
266
+ *
262
267
  * @param {Uint8Array[]} [excludeCredentials]
263
- * @returns {Promise<PasskeyCredential>} `aaguid`/`backupEligible`
264
- * are null on browsers without `getAuthenticatorData()`.
268
+ * @param {string[]} [salts] Salts to evaluate during the ceremony.
269
+ * @returns {Promise<CreatePasskeyOutput>} `aaguid`/`backupEligible`
270
+ * are null on browsers without `getAuthenticatorData()`. `seeds` is
271
+ * null unless the browser returned one output per salt.
265
272
  */
266
- async createPasskey(excludeCredentials = []) {
267
- return await this._registerCredential(excludeCredentials);
273
+ async createPasskey(excludeCredentials = [], salts = []) {
274
+ return await this._registerCredential(excludeCredentials, salts);
268
275
  }
269
276
 
270
277
  /**
@@ -504,10 +511,12 @@ export class PasskeyProvider {
504
511
  * @param {Uint8Array[]} [excludeCredentials=[]] - Already-registered
505
512
  * IDs; a match makes the authenticator refuse, preventing a
506
513
  * duplicate registration on the same device.
507
- * @returns {Promise<{ credentialId: Uint8Array, userId: Uint8Array, aaguid: Uint8Array | null, backupEligible: boolean | null }>}
514
+ * @param {string[]} [salts=[]] - Salts to evaluate during the create
515
+ * ceremony; omit to register without deriving.
516
+ * @returns {Promise<{ credential: { credentialId: Uint8Array, userId: Uint8Array, aaguid: Uint8Array | null, backupEligible: boolean | null }, seeds: Uint8Array[] | null }>}
508
517
  * @private
509
518
  */
510
- async _registerCredential(excludeCredentials = []) {
519
+ async _registerCredential(excludeCredentials = [], salts = []) {
511
520
  // Fresh per-call user.id: reusing one across creates on the same
512
521
  // rpId silently overwrites the prior credential on some
513
522
  // authenticators. (WebAuthn requires 1 to 64 bytes.)
@@ -540,7 +549,18 @@ export class PasskeyProvider {
540
549
  authenticatorSelection,
541
550
  // Explicit so future security review can't read it as ambient.
542
551
  attestation: 'none',
543
- extensions: { prf: {} },
552
+ extensions: {
553
+ prf: salts.length > 0
554
+ ? {
555
+ eval: {
556
+ first: new TextEncoder().encode(salts[0]),
557
+ ...(salts.length > 1
558
+ ? { second: new TextEncoder().encode(salts[1]) }
559
+ : {}),
560
+ },
561
+ }
562
+ : {},
563
+ },
544
564
  };
545
565
 
546
566
  if (Array.isArray(this.hints) && this.hints.length > 0) {
@@ -599,12 +619,30 @@ export class PasskeyProvider {
599
619
  );
600
620
  }
601
621
 
622
+ // Only usable as a complete set: a browser that drops the second
623
+ // output leaves a partial derive, which is no derive at all, so
624
+ // fall back to the assertion path rather than half-deriving.
625
+ let seeds = null;
626
+ const results = extensionResults.prf.results;
627
+ if (salts.length > 0 && results && results.first) {
628
+ const collected = [new Uint8Array(results.first)];
629
+ if (results.second) {
630
+ collected.push(new Uint8Array(results.second));
631
+ }
632
+ if (collected.length === salts.length) {
633
+ seeds = collected;
634
+ }
635
+ }
636
+
602
637
  const meta = extractRegistrationMetadata(credential);
603
638
  return {
604
- credentialId: new Uint8Array(credential.rawId),
605
- userId: resolvedUserId,
606
- aaguid: meta ? meta.aaguid : null,
607
- backupEligible: meta ? meta.backupEligible : null,
639
+ credential: {
640
+ credentialId: new Uint8Array(credential.rawId),
641
+ userId: resolvedUserId,
642
+ aaguid: meta ? meta.aaguid : null,
643
+ backupEligible: meta ? meta.backupEligible : null,
644
+ },
645
+ seeds,
608
646
  };
609
647
  }
610
648