bitcoin-decoder 0.1.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/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { DecodedData, Input } from './types';
2
- declare function decode(input: Input): DecodedData;
2
+ declare function decode(input: Input): Promise<DecodedData>;
3
3
  export { decode };
4
4
  export type { DecodedData, Destination, Metadata, Network, ParsedLNAddress, WellKnown } from './types';
5
5
  export { wellKnown } from './utils/lightning-address';
package/dist/index.js CHANGED
@@ -48,8 +48,8 @@ function decodeBolt12(input, offer) {
48
48
  metadata: parsedDestination.metadata
49
49
  };
50
50
  }
51
- function decodeLightningAddress(input) {
52
- const parsedDestination = lightningAddress(input);
51
+ async function decodeLightningAddress(input) {
52
+ const parsedDestination = await lightningAddress(input);
53
53
  const destination = toDestination(parsedDestination.destination);
54
54
  return {
55
55
  input,
@@ -58,8 +58,8 @@ function decodeLightningAddress(input) {
58
58
  network: 'unknown'
59
59
  };
60
60
  }
61
- function decodeLnurl(input) {
62
- const parsedDestination = lnurl(input);
61
+ async function decodeLnurl(input) {
62
+ const parsedDestination = await lnurl(input);
63
63
  const destination = toDestination(parsedDestination.destination);
64
64
  return {
65
65
  input,
@@ -78,8 +78,8 @@ function decodeArk(input) {
78
78
  network: getNetwork(input) || 'unknown'
79
79
  };
80
80
  }
81
- function decodeBip321(input) {
82
- const parsedDestinations = bip321(input);
81
+ async function decodeBip321(input) {
82
+ const parsedDestinations = await bip321(input);
83
83
  const first = parsedDestinations[0];
84
84
  if (!first) {
85
85
  throw new DecodeError(`No supported payment methods in BIP-321 URI: ${input}`, 'NO_PAYMENT_METHODS');
@@ -104,7 +104,7 @@ function decodeBitcoin(input) {
104
104
  network: getNetwork(input) || 'unknown'
105
105
  };
106
106
  }
107
- function decodeInput(input) {
107
+ async function decodeInput(input) {
108
108
  const lowerInput = input.toLowerCase();
109
109
  if (lowerInput.startsWith(BIP321_PREFIX)) {
110
110
  return decodeBip321(input);
@@ -119,13 +119,13 @@ function decodeInput(input) {
119
119
  return decodeBolt12(input, input);
120
120
  }
121
121
  if (lowerInput.startsWith(LNURL_PREFIX)) {
122
- return decodeLnurl(input);
122
+ return await decodeLnurl(input);
123
123
  }
124
124
  if (ARK_PREFIXES.some((prefix) => lowerInput.startsWith(prefix))) {
125
125
  return decodeArk(input);
126
126
  }
127
127
  if (input.includes('@')) {
128
- return decodeLightningAddress(input);
128
+ return await decodeLightningAddress(input);
129
129
  }
130
130
  if (BITCOIN_ADDRESS_PREFIXES.some((prefix) => lowerInput.startsWith(prefix))) {
131
131
  return decodeBitcoin(input);
@@ -149,9 +149,9 @@ function getErrorCode(error) {
149
149
  errorCode: 'UNKNOWN_FORMAT'
150
150
  };
151
151
  }
152
- function decode(input) {
152
+ async function decode(input) {
153
153
  try {
154
- return { valid: true, ...decodeInput(input) };
154
+ return { valid: true, ...(await decodeInput(input)) };
155
155
  }
156
156
  catch (error) {
157
157
  return { ...getErrorCode(error), input };
@@ -1,3 +1,3 @@
1
1
  import type { Input, ParsedDestination } from '../types';
2
- declare function bip321(input: Input): ParsedDestination[];
2
+ declare function bip321(input: Input): Promise<ParsedDestination[]>;
3
3
  export { bip321 };
@@ -3,6 +3,7 @@ import { ark } from './ark';
3
3
  import { bitcoin } from './bitcoin';
4
4
  import { bolt11 } from './bolt11';
5
5
  import { bolt12 } from './bolt12';
6
+ import { lightningAddress } from './lightning-address';
6
7
  const SATS_PER_BTC = 100_000_000;
7
8
  /** Priority order: Lightning (0) > Ark (1) > On-chain (2) */
8
9
  const PROTOCOL_PRIORITY = {
@@ -25,8 +26,11 @@ function getMetadata(result) {
25
26
  }
26
27
  return { amount, description };
27
28
  }
28
- function mapPaymentMethod(paymentMethod, metadata) {
29
+ async function mapPaymentMethod(paymentMethod, metadata) {
29
30
  if (paymentMethod.type === 'lightning') {
31
+ if (paymentMethod.value.includes('@')) {
32
+ return await lightningAddress(paymentMethod.value);
33
+ }
30
34
  return bolt11(paymentMethod.value);
31
35
  }
32
36
  if (paymentMethod.type === 'offer') {
@@ -38,19 +42,21 @@ function mapPaymentMethod(paymentMethod, metadata) {
38
42
  const parsed = bitcoin(paymentMethod.value);
39
43
  return { ...parsed, metadata };
40
44
  }
41
- function parse(result) {
45
+ async function parse(result) {
42
46
  const metadata = getMetadata(result);
43
- return result.paymentMethods
44
- .filter((method) => (method.valid || method.type === 'offer') &&
47
+ return await Promise.all(result.paymentMethods
48
+ .filter((method) => (method.valid ||
49
+ method.type === 'offer' ||
50
+ (method.type === 'lightning' && method.value.includes('@'))) &&
45
51
  isSupportedType(method.type))
46
52
  .sort((a, b) => PROTOCOL_PRIORITY[a.type] - PROTOCOL_PRIORITY[b.type])
47
- .map((method) => mapPaymentMethod(method, metadata));
53
+ .map((method) => mapPaymentMethod(method, metadata)));
48
54
  }
49
- function bip321(input) {
55
+ async function bip321(input) {
50
56
  const result = parseBIP321(input);
51
57
  if (!result.valid) {
52
58
  throw new Error(`Invalid BIP-321 URI: ${result.errors.join(', ')}`);
53
59
  }
54
- return parse(result);
60
+ return await parse(result);
55
61
  }
56
62
  export { bip321 };
@@ -1,5 +1,5 @@
1
1
  import type { Input, ParsedDestination, ParsedLNAddress, WellKnown } from '../types';
2
2
  declare function parse(input: Input): ParsedLNAddress;
3
- declare function lightningAddress(input: Input): ParsedDestination;
3
+ declare function lightningAddress(input: Input): Promise<ParsedDestination>;
4
4
  declare function wellKnown(lnaddress: string, needsParse?: boolean): Promise<WellKnown | false>;
5
5
  export { lightningAddress, parse, wellKnown };
@@ -13,8 +13,12 @@ function parse(input) {
13
13
  }
14
14
  return { username, domain };
15
15
  }
16
- function lightningAddress(input) {
17
- parse(input);
16
+ async function lightningAddress(input) {
17
+ const parsed = parse(input);
18
+ const result = await wellKnown(`${BASE_URL}${parsed.domain}/.well-known/lnurlp/${parsed.username}`, false);
19
+ if (!result) {
20
+ throw new DecodeError(`Lightning address not found: ${input}`, 'INVALID_LNADDRESS');
21
+ }
18
22
  return {
19
23
  destination: {
20
24
  value: input,
@@ -1,4 +1,4 @@
1
1
  import type { Input, ParsedDestination } from '../types';
2
2
  declare const LNURL_PREFIX = "lnurl";
3
- declare function lnurl(input: Input): ParsedDestination;
3
+ declare function lnurl(input: Input): Promise<ParsedDestination>;
4
4
  export { lnurl, LNURL_PREFIX };
@@ -1,7 +1,7 @@
1
1
  import { bech32 } from '@scure/base';
2
2
  import { DecodeError } from '../types';
3
3
  const LNURL_PREFIX = 'lnurl';
4
- function lnurl(input) {
4
+ async function lnurl(input) {
5
5
  let words;
6
6
  try {
7
7
  const decoded = bech32.decode(input, 2000);
@@ -21,6 +21,19 @@ function lnurl(input) {
21
21
  if (!url.startsWith('https://')) {
22
22
  throw new DecodeError('LNURL does not contain a valid URL', 'INVALID_LNURL');
23
23
  }
24
+ try {
25
+ const response = await fetch(url, { method: 'GET' });
26
+ const json = (await response.json());
27
+ if (!json.callback) {
28
+ throw new DecodeError('LNURL endpoint returned invalid response', 'INVALID_LNURL');
29
+ }
30
+ }
31
+ catch (error) {
32
+ if (error instanceof DecodeError) {
33
+ throw error;
34
+ }
35
+ throw new DecodeError(`LNURL endpoint unreachable: ${url}`, 'INVALID_LNURL');
36
+ }
24
37
  return {
25
38
  destination: {
26
39
  value: input,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bitcoin-decoder",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Decode bitcoin QR codes, URIs, and raw strings",
5
5
  "type": "module",
6
6
  "exports": {
@@ -52,13 +52,13 @@
52
52
  "license": "MIT",
53
53
  "repository": {
54
54
  "type": "git",
55
- "url": "https://github.com/Psycarlo/bitcoin-decode"
55
+ "url": "https://github.com/Psycarlo/bitcoin-decoder"
56
56
  },
57
57
  "bugs": {
58
58
  "email": "psycarlo1@gmail.com",
59
- "url": "https://github.com/Psycarlo/bitcoin-decode/issues"
59
+ "url": "https://github.com/Psycarlo/bitcoin-decoder/issues"
60
60
  },
61
- "homepage": "https://github.com/Psycarlo/bitcoin-decode#readme",
61
+ "homepage": "https://github.com/Psycarlo/bitcoin-decoder#readme",
62
62
  "workspaces": [
63
63
  "website"
64
64
  ]