thunder-bridge 2.2.1 → 3.0.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/dist/nwc.js CHANGED
@@ -349,8 +349,6 @@ function asBuffer(bytes) {
349
349
  }
350
350
 
351
351
  // ../core/sealed.ts
352
- var VERSION = "v2";
353
- var UNPADDED_VERSION = "v1";
354
352
  var PURPOSE_VERSION = "v3";
355
353
  var IV_BYTES = 12;
356
354
  var MIN_SECRET_CHARS = 32;
@@ -358,15 +356,6 @@ var MAX_PLAIN_BYTES = 3e3;
358
356
  var SIZE_CLASSES = [256, 1024, MAX_PLAIN_BYTES];
359
357
  var END_OF_TEXT = 128;
360
358
  var INFO = "thunder-bridge/sealed";
361
- async function seal(secret, plaintext, paymentHash) {
362
- return await sealUnder(
363
- await keyFor(secret, INFO),
364
- plaintext,
365
- crypto.getRandomValues(new Uint8Array(IV_BYTES)),
366
- VERSION,
367
- boundTo(paymentHash)
368
- );
369
- }
370
359
  async function sealFor(purpose, secret, plaintext, { stable = false } = {}) {
371
360
  return await sealUnder(
372
361
  await keyFor(secret, `${INFO}/${purpose}`),
@@ -376,16 +365,6 @@ async function sealFor(purpose, secret, plaintext, { stable = false } = {}) {
376
365
  new TextEncoder().encode(PURPOSE_VERSION)
377
366
  );
378
367
  }
379
- async function unsealFor(purpose, secret, sealed) {
380
- if (!sealed.startsWith(`${PURPOSE_VERSION}.`)) {
381
- return await unseal(secret, sealed);
382
- }
383
- return await opened(
384
- await keyFor(secret, `${INFO}/${purpose}`),
385
- sealed.slice(PURPOSE_VERSION.length + 1),
386
- new TextEncoder().encode(PURPOSE_VERSION)
387
- );
388
- }
389
368
  async function nonceOf(secret, plaintext) {
390
369
  const derived = await hmacHex(secret, `sealed-nonce|${plaintext}`);
391
370
  const nonce = new Uint8Array(IV_BYTES);
@@ -404,48 +383,11 @@ async function sealUnder(key, plaintext, iv, version, additionalData) {
404
383
  joined2.set(cipher, iv.length);
405
384
  return `${version}.${toBase64Url(joined2)}`;
406
385
  }
407
- async function unseal(secret, sealed, paymentHash) {
408
- const key = await keyFor(secret, INFO);
409
- const padded2 = sealed.startsWith(`${VERSION}.`);
410
- const unbound = !padded2 && sealed.startsWith(`${UNPADDED_VERSION}.`);
411
- if (!padded2 && (!unbound || paymentHash !== void 0)) {
412
- return null;
413
- }
414
- return await opened(
415
- key,
416
- sealed.slice(VERSION.length + 1),
417
- padded2 ? boundTo(paymentHash) : void 0
418
- );
419
- }
420
- async function opened(key, encoded, additionalData) {
421
- const joined2 = fromBase64Url(encoded);
422
- if (joined2 === null || joined2.length <= IV_BYTES) {
423
- return null;
424
- }
425
- try {
426
- const body = new Uint8Array(
427
- await crypto.subtle.decrypt(
428
- { name: "AES-GCM", iv: joined2.slice(0, IV_BYTES), additionalData },
429
- key,
430
- joined2.slice(IV_BYTES)
431
- )
432
- );
433
- const text = additionalData === void 0 ? body : unpad(body);
434
- return text === null ? null : new TextDecoder().decode(text);
435
- } catch {
436
- return null;
437
- }
438
- }
439
386
  function refuseAWeakSecret(secret) {
440
387
  if (secret.length < MIN_SECRET_CHARS) {
441
388
  throw new Error(`the sealing secret needs ${MIN_SECRET_CHARS} characters of randomness`);
442
389
  }
443
390
  }
444
- function boundTo(paymentHash) {
445
- return new TextEncoder().encode(
446
- paymentHash === void 0 ? VERSION : `${VERSION}|${paymentHash.toLowerCase()}`
447
- );
448
- }
449
391
  function padToClass(plaintext) {
450
392
  const text = new TextEncoder().encode(plaintext);
451
393
  const size = SIZE_CLASSES.find((limit) => text.length <= limit);
@@ -457,10 +399,6 @@ function padToClass(plaintext) {
457
399
  body[text.length] = END_OF_TEXT;
458
400
  return body;
459
401
  }
460
- function unpad(body) {
461
- const end = body.lastIndexOf(END_OF_TEXT);
462
- return end === -1 ? null : body.subarray(0, end);
463
- }
464
402
  async function keyFor(secret, info) {
465
403
  refuseAWeakSecret(secret);
466
404
  const material = await crypto.subtle.importKey(
@@ -490,21 +428,6 @@ function toBase64Url(bytes) {
490
428
  }
491
429
  return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
492
430
  }
493
- function fromBase64Url(text) {
494
- if (text.length === 0 || !/^[A-Za-z0-9_-]+$/.test(text)) {
495
- return null;
496
- }
497
- try {
498
- const binary = atob(text.replace(/-/g, "+").replace(/_/g, "/"));
499
- const bytes = new Uint8Array(binary.length);
500
- for (let at = 0; at < bytes.length; at++) {
501
- bytes[at] = binary.charCodeAt(at);
502
- }
503
- return bytes;
504
- } catch {
505
- return null;
506
- }
507
- }
508
431
 
509
432
  // src/nostr.ts
510
433
  import { chacha20 } from "@noble/ciphers/chacha.js";
@@ -661,274 +584,6 @@ function fromBase64(text) {
661
584
  return bytes;
662
585
  }
663
586
 
664
- // src/qr.ts
665
- import { encode } from "uqr";
666
- function toLightningUri(destination) {
667
- const scanned = isLnAddress(destination) ? destination : destination.toUpperCase();
668
- return `LIGHTNING:${scanned}`;
669
- }
670
- function isLnAddress(destination) {
671
- const at = destination.indexOf("@");
672
- return at > 0 && destination.slice(at + 1).includes(".");
673
- }
674
-
675
- // src/errors.ts
676
- var AmountError = class extends Error {
677
- /**
678
- * Whether a failure is one of these, without asking whether it is this exact
679
- * class. Every entry point carries its own copy of the class, so a price
680
- * refused inside `thunder-bridge/price` is not `instanceof` the `AmountError`
681
- * imported from `thunder-bridge`. The name and the code are the same in every
682
- * copy, so this holds where `instanceof` does not
683
- */
684
- static is(failure) {
685
- return failure instanceof Error && failure.name === "AmountError" && "code" in failure;
686
- }
687
- code;
688
- constructor(code, detail) {
689
- super(`${code}: ${detail}`);
690
- this.name = "AmountError";
691
- this.code = code;
692
- }
693
- };
694
-
695
- // src/currency.ts
696
- var ISO_4217_MINOR_UNITS = {
697
- BHD: 3,
698
- BIF: 0,
699
- CLP: 0,
700
- CZK: 2,
701
- DJF: 0,
702
- EUR: 2,
703
- GBP: 2,
704
- ISK: 0,
705
- IQD: 3,
706
- JOD: 3,
707
- JPY: 0,
708
- KRW: 0,
709
- KWD: 3,
710
- LYD: 3,
711
- OMR: 3,
712
- PLN: 2,
713
- PYG: 0,
714
- RWF: 0,
715
- TND: 3,
716
- UGX: 0,
717
- USD: 2,
718
- VND: 0,
719
- VUV: 0,
720
- XAF: 0,
721
- XOF: 0,
722
- XPF: 0
723
- };
724
- function minorUnitsOf(currency) {
725
- const digits = ISO_4217_MINOR_UNITS[currency.toUpperCase()];
726
- if (digits === void 0) {
727
- throw new AmountError(
728
- "unknown-currency",
729
- `${currency.toUpperCase()} is not a currency this knows the ISO 4217 minor unit of`
730
- );
731
- }
732
- return digits;
733
- }
734
- function minorScaleOf(currency) {
735
- return 10 ** minorUnitsOf(currency);
736
- }
737
-
738
- // src/price.ts
739
- var MSAT_PER_BTC2 = 1e11;
740
- var BASIS_POINTS = 1e4;
741
- var DEFAULT_HOLD_SECS = 60;
742
- var DEFAULT_MIN_VENUES = 2;
743
- var DEFAULT_MAX_SPREAD_BPS = 200;
744
- var MILLIS = 1e3;
745
- function coinbase(baseUrl = "https://api.coinbase.com") {
746
- return async (currency) => {
747
- const asked = currency.toUpperCase();
748
- const answer = await asJson(`${baseUrl}/v2/prices/BTC-${asked}/spot`, "coinbase");
749
- const quoted = answer.data;
750
- if (quoted?.currency !== asked) {
751
- throw new Error(`coinbase quoted ${quoted?.currency} when asked for ${asked}`);
752
- }
753
- return asMinor(quoted.amount, "coinbase", asked);
754
- };
755
- }
756
- function kraken(baseUrl = "https://api.kraken.com") {
757
- return async (currency) => {
758
- const asked = currency.toUpperCase();
759
- const answer = await asJson(`${baseUrl}/0/public/Ticker?pair=XBT${asked}`, "kraken");
760
- if (answer.error?.length) {
761
- throw new Error(`kraken refused XBT${asked}: ${answer.error[0]}`);
762
- }
763
- const pairs = Object.values(answer.result ?? {});
764
- if (pairs.length !== 1) {
765
- throw new Error(`kraken answered ${pairs.length} pairs for XBT${asked}`);
766
- }
767
- return asMinor(pairs[0]?.c?.[0], "kraken", asked);
768
- };
769
- }
770
- function bitstamp(baseUrl = "https://www.bitstamp.net") {
771
- return async (currency) => {
772
- const pair = `btc${currency.toLowerCase()}`;
773
- const answer = await asJson(`${baseUrl}/api/v2/ticker/${pair}/`, "bitstamp");
774
- if (Array.isArray(answer)) {
775
- throw new Error(`bitstamp has no ${pair} pair`);
776
- }
777
- return asMinor(answer.last, "bitstamp", currency);
778
- };
779
- }
780
- function coinmate(baseUrl = "https://coinmate.io") {
781
- return async (currency) => {
782
- const pair = `BTC_${currency.toUpperCase()}`;
783
- const answer = await asJson(`${baseUrl}/api/ticker?currencyPair=${pair}`, "coinmate");
784
- if (answer.error !== false) {
785
- throw new Error(`coinmate refused ${pair}: ${answer.errorMessage ?? "no reason"}`);
786
- }
787
- return asMinor(answer.data?.last, "coinmate", currency);
788
- };
789
- }
790
- function medianOf(tickers = [coinbase(), kraken(), bitstamp(), coinmate()], options = {}) {
791
- const holdFor = (options.holdForSecs ?? DEFAULT_HOLD_SECS) * MILLIS;
792
- const minVenues = options.minVenues ?? DEFAULT_MIN_VENUES;
793
- const maxSpread = options.maxSpreadBps ?? DEFAULT_MAX_SPREAD_BPS;
794
- const held = /* @__PURE__ */ new Map();
795
- return async (currency) => {
796
- const asked = currency.toUpperCase();
797
- const remembered = held.get(asked);
798
- if (remembered && Date.now() - remembered.at < holdFor) {
799
- return remembered.price;
800
- }
801
- const answers = await Promise.allSettled(tickers.map((ticker) => ticker(asked)));
802
- const quoted = answers.filter((answer) => answer.status === "fulfilled").map((answer) => answer.value).sort((one, other) => one - other);
803
- if (quoted.length < minVenues) {
804
- throw new Error(
805
- `${quoted.length} of ${tickers.length} venues quoted ${asked}, ${minVenues} wanted: ${refusals(answers)}`
806
- );
807
- }
808
- const spread = spreadBpsOf(quoted);
809
- if (spread > maxSpread) {
810
- throw new Error(
811
- `venues disagree on ${asked} by ${Math.round(spread)} bps, more than the ${maxSpread} allowed: ${quoted.join(", ")}`
812
- );
813
- }
814
- const price = middleOf(quoted);
815
- held.set(asked, { at: Date.now(), price });
816
- return price;
817
- };
818
- }
819
- function msatFor(amountMinor, priceMinorPerBtc, options = {}) {
820
- if (!Number.isInteger(amountMinor) || amountMinor <= 0) {
821
- throw new Error("amountMinor must be a whole number of minor units above zero");
822
- }
823
- if (!Number.isFinite(priceMinorPerBtc) || priceMinorPerBtc <= 0) {
824
- throw new Error(`${priceMinorPerBtc} is not a usable price`);
825
- }
826
- const spreadBps = options.spreadBps ?? 0;
827
- if (!Number.isInteger(spreadBps) || spreadBps < 0) {
828
- throw new Error("spreadBps must be a whole number of basis points, none or more");
829
- }
830
- const wanted = BigInt(amountMinor) * BigInt(MSAT_PER_BTC2) * BigInt(BASIS_POINTS + spreadBps);
831
- const per = BigInt(Math.round(priceMinorPerBtc)) * BigInt(BASIS_POINTS);
832
- const msat2 = (wanted + per - 1n) / per;
833
- if (msat2 > BigInt(Number.MAX_SAFE_INTEGER)) {
834
- throw new Error(`${amountMinor} at ${priceMinorPerBtc} is more millisatoshi than exist`);
835
- }
836
- return Number(msat2);
837
- }
838
- async function asJson(url, venue) {
839
- const answer = await fetch(url, { headers: { accept: "application/json" } });
840
- if (!answer.ok) {
841
- throw new Error(`${venue} answered ${answer.status}`);
842
- }
843
- return answer.json();
844
- }
845
- function asMinor(quoted, venue, currency) {
846
- const major = Number(quoted);
847
- if (!Number.isFinite(major) || major <= 0) {
848
- throw new Error(`${venue} quoted ${String(quoted)} for ${currency.toUpperCase()}`);
849
- }
850
- return Math.round(major * minorScaleOf(currency));
851
- }
852
- function spreadBpsOf(sorted) {
853
- const lowest = sorted[0] ?? 0;
854
- const highest = sorted[sorted.length - 1] ?? 0;
855
- return lowest === 0 ? Number.POSITIVE_INFINITY : (highest - lowest) / lowest * BASIS_POINTS;
856
- }
857
- function middleOf(sorted) {
858
- const middle = Math.floor(sorted.length / 2);
859
- if (sorted.length % 2 === 1) {
860
- return sorted[middle] ?? 0;
861
- }
862
- return Math.round(((sorted[middle - 1] ?? 0) + (sorted[middle] ?? 0)) / 2);
863
- }
864
- function refusals(answers) {
865
- return answers.filter((answer) => answer.status === "rejected").map(
866
- (answer) => answer.reason instanceof Error ? answer.reason.message : String(answer.reason)
867
- ).join("; ");
868
- }
869
-
870
- // src/amount.ts
871
- var MSAT_PER_SAT = 1e3;
872
- var MAX_SATS = Math.floor(Number.MAX_SAFE_INTEGER / MSAT_PER_SAT);
873
- function msat(exact) {
874
- if (!Number.isSafeInteger(exact) || exact < 1) {
875
- throw new AmountError(
876
- "not-whole-millisatoshi",
877
- `${exact} is not a payable count of millisatoshi`
878
- );
879
- }
880
- return exact;
881
- }
882
- async function amountNow(amount) {
883
- return typeof amount === "function" ? msat(await amount()) : msat(amount);
884
- }
885
-
886
- // ../core/ed25519.ts
887
- var PKCS8_HEADER = hexToBytes("302e020100300506032b657004220420");
888
- var SMALL_ORDER = [
889
- "00".repeat(32),
890
- `01${"00".repeat(31)}`,
891
- "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05",
892
- "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a",
893
- `ec${"ff".repeat(30)}7f`,
894
- `ed${"ff".repeat(30)}7f`,
895
- `ee${"ff".repeat(30)}7f`
896
- ];
897
-
898
- // src/webhook.ts
899
- var VERIFY_CHALLENGE = "verify-challenge";
900
- async function answerVerifyChallenge(request) {
901
- if (request.method !== "POST") {
902
- return null;
903
- }
904
- const nonce = nonceOf2(await request.clone().text(), VERIFY_CHALLENGE);
905
- return nonce === null ? null : answered(nonce);
906
- }
907
- function answered(nonce) {
908
- return new Response(JSON.stringify({ nonce }), {
909
- headers: { "content-type": "application/json" }
910
- });
911
- }
912
- function nonceOf2(text, type) {
913
- try {
914
- const said = JSON.parse(text);
915
- if (said["type"] !== type || typeof said["nonce"] !== "string") {
916
- return null;
917
- }
918
- return said["nonce"];
919
- } catch {
920
- return null;
921
- }
922
- }
923
-
924
- // src/rail.ts
925
- async function msatForOrder(order, amount, rate) {
926
- if (amount !== void 0) {
927
- return await amountNow(amount(order));
928
- }
929
- return msat(msatFor(order.amountMinor, await (rate ?? medianOf())(order.currency)));
930
- }
931
-
932
587
  // src/nwc.ts
933
588
  var REQUEST_KIND = 23194;
934
589
  var RESPONSE_KIND = 23195;
@@ -937,7 +592,6 @@ var SCHEME = "nostr+walletconnect:";
937
592
  var HEX_32_BYTES = /^[0-9a-f]{64}$/i;
938
593
  var DEFAULT_ASK_TIMEOUT_MS = 1e4;
939
594
  var PAY_TIMEOUT_MS = 9e4;
940
- var DEFAULT_POLL_EVERY_SECS = 5;
941
595
  var HASH = "h";
942
596
  var REFUSAL_BY_CODE = {
943
597
  INSUFFICIENT_BALANCE: "amount-not-accepted",
@@ -963,13 +617,13 @@ function nwcConnection(uri) {
963
617
  return { walletPubkey: walletPubkey.toLowerCase(), relays, secret: secret.toLowerCase() };
964
618
  }
965
619
  async function nwcInvoice(connection, amountMsat, description, timeoutMs = DEFAULT_ASK_TIMEOUT_MS) {
966
- const answered2 = await askWallet(
620
+ const answered = await askWallet(
967
621
  connection,
968
622
  "make_invoice",
969
623
  { amount: amountMsat, description },
970
624
  timeoutMs
971
625
  );
972
- const bolt11 = String(answered2.invoice ?? "");
626
+ const bolt11 = String(answered.invoice ?? "");
973
627
  const issued = decodeInvoice(bolt11);
974
628
  if (issued.paymentHash === null || issued.expiresAt === null) {
975
629
  throw new WalletRefused("invoice-refused", "the nwc wallet issued an invoice we cannot decode");
@@ -983,7 +637,7 @@ async function nwcInvoice(connection, amountMsat, description, timeoutMs = DEFAU
983
637
  return { bolt11, paymentHash: issued.paymentHash, expiresAt: issued.expiresAt };
984
638
  }
985
639
  async function nwcHoldInvoice(connection, held, timeoutMs = DEFAULT_ASK_TIMEOUT_MS) {
986
- const answered2 = await askWallet(
640
+ const answered = await askWallet(
987
641
  connection,
988
642
  "make_hold_invoice",
989
643
  {
@@ -995,7 +649,7 @@ async function nwcHoldInvoice(connection, held, timeoutMs = DEFAULT_ASK_TIMEOUT_
995
649
  },
996
650
  timeoutMs
997
651
  );
998
- const bolt11 = String(answered2.invoice ?? "");
652
+ const bolt11 = String(answered.invoice ?? "");
999
653
  const issued = decodeInvoice(bolt11);
1000
654
  if (issued.paymentHash === null || issued.expiresAt === null) {
1001
655
  throw new WalletRefused("invoice-refused", "the nwc wallet held an invoice we cannot decode");
@@ -1015,13 +669,13 @@ async function nwcHoldInvoice(connection, held, timeoutMs = DEFAULT_ASK_TIMEOUT_
1015
669
  return { bolt11, paymentHash: issued.paymentHash, expiresAt: issued.expiresAt };
1016
670
  }
1017
671
  async function nwcSettlement(connection, paymentHash, timeoutMs = DEFAULT_ASK_TIMEOUT_MS) {
1018
- const answered2 = await askWallet(
672
+ const answered = await askWallet(
1019
673
  connection,
1020
674
  "lookup_invoice",
1021
675
  { payment_hash: paymentHash },
1022
676
  timeoutMs
1023
677
  );
1024
- const preimage = answered2.preimage;
678
+ const preimage = answered.preimage;
1025
679
  if (typeof preimage !== "string" || preimage.length === 0) {
1026
680
  return null;
1027
681
  }
@@ -1035,39 +689,13 @@ async function nwcPay(connection, bolt11, timeoutMs = PAY_TIMEOUT_MS) {
1035
689
  if (owed.paymentHash === null) {
1036
690
  throw new WalletRefused("invoice-refused", "the invoice to pay carries no payment hash");
1037
691
  }
1038
- const answered2 = await askWallet(connection, "pay_invoice", { invoice: bolt11 }, timeoutMs);
1039
- const preimage = answered2.preimage;
692
+ const answered = await askWallet(connection, "pay_invoice", { invoice: bolt11 }, timeoutMs);
693
+ const preimage = answered.preimage;
1040
694
  if (typeof preimage !== "string" || !preimageMatchesHash(preimage, owed.paymentHash)) {
1041
695
  throw new Error(`the nwc wallet paid and returned no preimage hashing to ${owed.paymentHash}`);
1042
696
  }
1043
697
  return preimage;
1044
698
  }
1045
- function nwcVerifyEndpoint(config) {
1046
- const paced = {
1047
- "cache-control": `max-age=${config.pollEverySecs ?? DEFAULT_POLL_EVERY_SECS}`
1048
- };
1049
- return async (request) => {
1050
- const consented = await answerVerifyChallenge(request);
1051
- if (consented !== null) {
1052
- return consented;
1053
- }
1054
- const sealed = new URL(request.url).searchParams.get(HASH);
1055
- if (sealed === null) {
1056
- return Response.json({ settled: false }, { status: 400 });
1057
- }
1058
- const paymentHash = await unsealFor("nwc-verify", config.secret, sealed);
1059
- if (paymentHash === null) {
1060
- return Response.json({ settled: false }, { status: 403 });
1061
- }
1062
- const preimage = await nwcSettlement(config.connection, paymentHash, config.askTimeoutMs).catch(
1063
- () => void 0
1064
- );
1065
- if (preimage === void 0) {
1066
- return Response.json({ settled: false }, { status: 502 });
1067
- }
1068
- return Response.json({ settled: preimage !== null, preimage }, { headers: paced });
1069
- };
1070
- }
1071
699
  async function nwcVerifyUrl(endpoint, paymentHash, secret) {
1072
700
  const sealed = new URL(endpoint);
1073
701
  sealed.searchParams.set(HASH, await sealFor("nwc-verify", secret, paymentHash));
@@ -1117,7 +745,7 @@ async function overFirstRelayThatAnswers(connection, request, timeoutMs) {
1117
745
  throw new WalletRefused("unreachable", `no nwc relay answered: ${String(lastFailure)}`);
1118
746
  }
1119
747
  function overRelay(relay, connection, request, deadline) {
1120
- return new Promise((resolve2, reject) => {
748
+ return new Promise((resolve, reject) => {
1121
749
  const socket = new WebSocket(relay);
1122
750
  const subscription = request.id.slice(0, 16);
1123
751
  const expired = () => {
@@ -1161,7 +789,7 @@ function overRelay(relay, connection, request, deadline) {
1161
789
  return;
1162
790
  }
1163
791
  close();
1164
- resolve2(answer);
792
+ resolve(answer);
1165
793
  });
1166
794
  });
1167
795
  }
@@ -1207,52 +835,12 @@ function isSecureRelay(relay) {
1207
835
  return false;
1208
836
  }
1209
837
  }
1210
- function nwcRail(gateway, config) {
1211
- return async (order) => {
1212
- const invoice = await nwcInvoice(
1213
- config.connection,
1214
- await msatForOrder(order, config.amount, config.rate),
1215
- config.description?.(order) ?? order.reference
1216
- );
1217
- const watched = await gateway.watch({
1218
- paymentHash: invoice.paymentHash,
1219
- verifyUrl: await nwcVerifyUrl(
1220
- config.verifyThrough.endpoint,
1221
- invoice.paymentHash,
1222
- config.verifyThrough.secret
1223
- ),
1224
- expiresAt: invoice.expiresAt,
1225
- trigger: config.trigger,
1226
- replay: config.replay,
1227
- sealed: config.sealed ? await seal(
1228
- config.sealed.secret,
1229
- JSON.stringify(config.sealed.data(order)),
1230
- invoice.paymentHash
1231
- ) : void 0,
1232
- webhookUrl: config.webhookUrl
1233
- });
1234
- return {
1235
- id: watched.id,
1236
- paymentHash: invoice.paymentHash,
1237
- rail: config.name ?? "lightning",
1238
- scan: invoice.bolt11,
1239
- qr: toLightningUri(invoice.bolt11),
1240
- expiresAt: invoice.expiresAt
1241
- };
1242
- };
1243
- }
1244
-
1245
- // src/entry/nwc.ts
1246
- var nwcRail2 = nwcRail;
1247
- var nwcVerifyEndpoint2 = nwcVerifyEndpoint;
1248
838
  export {
1249
839
  askWallet,
1250
840
  nwcConnection,
1251
841
  nwcHoldInvoice,
1252
842
  nwcInvoice,
1253
843
  nwcPay,
1254
- nwcRail2 as nwcRail,
1255
844
  nwcSettlement,
1256
- nwcVerifyEndpoint2 as nwcVerifyEndpoint,
1257
845
  nwcVerifyUrl
1258
846
  };
package/openapi.yaml CHANGED
@@ -2,7 +2,7 @@ openapi: 3.1.0
2
2
 
3
3
  info:
4
4
  title: thunder-bridge, the endpoint your own service serves
5
- version: 2.2.1
5
+ version: 3.0.0
6
6
  license:
7
7
  name: MIT
8
8
  identifier: MIT
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "thunder-bridge",
3
- "version": "2.2.1",
4
- "description": "Trustless JavaScript client for the Thunder Bridge Lightning payment gateway. Proves the invoice came from your own wallet before the payer sees it.",
3
+ "version": "3.0.0",
4
+ "description": "Take Bitcoin Lightning and bank payments in JavaScript, paid straight into your own wallet or account. No node to run, no custodian, and every payment proven rather than taken on the gateway's word.",
5
5
  "author": "i-am-fatik",
6
6
  "homepage": "https://agora.gripe/en/tools/thunder-bridge",
7
7
  "repository": {
@@ -111,6 +111,11 @@
111
111
  "bitcoin",
112
112
  "lnurl",
113
113
  "lud-21",
114
+ "lightning-address",
115
+ "nwc",
116
+ "bank-transfer",
117
+ "non-custodial",
118
+ "payment-gateway",
114
119
  "trustless",
115
120
  "payments",
116
121
  "websocket"
@@ -120,6 +125,7 @@
120
125
  "@noble/ciphers": "2.4.0",
121
126
  "@noble/curves": "2.4.0",
122
127
  "@noble/hashes": "2.4.0",
128
+ "structured-headers": "2.1.0",
123
129
  "uqr": "^0.1.3"
124
130
  },
125
131
  "overrides": {