@bsv/sdk 2.1.5 → 2.1.6

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.
Files changed (30) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/dist/cjs/src/compat/Utxo.js +1 -1
  3. package/dist/cjs/src/compat/Utxo.js.map +1 -1
  4. package/dist/cjs/src/primitives/Hash.js +4 -2
  5. package/dist/cjs/src/primitives/Hash.js.map +1 -1
  6. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  7. package/dist/esm/src/compat/Utxo.js +1 -1
  8. package/dist/esm/src/compat/Utxo.js.map +1 -1
  9. package/dist/esm/src/primitives/Hash.js +4 -2
  10. package/dist/esm/src/primitives/Hash.js.map +1 -1
  11. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  12. package/dist/types/src/primitives/Hash.d.ts.map +1 -1
  13. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  14. package/dist/umd/bundle.js +1 -1
  15. package/package.json +1 -1
  16. package/src/compat/Utxo.ts +1 -1
  17. package/src/compat/__tests/Mnemonic.additional.test.ts +1 -1
  18. package/src/compat/__tests/Mnemonic.test.ts +1 -1
  19. package/src/overlay-tools/__tests/Historian.test.ts +1 -1
  20. package/src/overlay-tools/__tests/HostReputationTracker.additional.test.ts +1 -1
  21. package/src/primitives/Hash.ts +4 -2
  22. package/src/primitives/__tests/BigNumber.constructor.test.ts +1 -1
  23. package/src/primitives/__tests/DRBG.test.ts +4 -12
  24. package/src/primitives/__tests/Point.additional.test.ts +2 -2
  25. package/src/primitives/__tests/Point.test.ts +1 -1
  26. package/src/primitives/__tests/SymmetricKeyCompatibility.test.ts +4 -4
  27. package/src/registry/__tests/RegistryClient.additional.test.ts +4 -4
  28. package/src/registry/__tests/RegistryClient.test.ts +2 -2
  29. package/src/storage/__tests/StorageUploader.test.ts +7 -7
  30. package/src/transaction/__tests/Transaction.test.ts +3 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/sdk",
3
- "version": "2.1.5",
3
+ "version": "2.1.6",
4
4
  "type": "module",
5
5
  "description": "BSV Blockchain Software Development Kit",
6
6
  "main": "dist/cjs/mod.js",
@@ -44,7 +44,7 @@ export default function fromUtxo (
44
44
  }
45
45
  ): TransactionInput {
46
46
  const sourceTransaction = new Transaction(0, [], [], 0)
47
- sourceTransaction.outputs = Array(utxo.vout + 1).fill(null)
47
+ sourceTransaction.outputs = new Array(utxo.vout + 1).fill(null)
48
48
  sourceTransaction.outputs[utxo.vout] = {
49
49
  satoshis: utxo.satoshis,
50
50
  lockingScript: LockingScript.fromHex(utxo.script)
@@ -15,7 +15,7 @@ describe('Mnemonic – additional coverage', () => {
15
15
  })
16
16
 
17
17
  it('uses 128 bits when bits is NaN', () => {
18
- const m = new Mnemonic().fromRandom(NaN)
18
+ const m = new Mnemonic().fromRandom(Number.NaN)
19
19
  expect(m.mnemonic.split(' ')).toHaveLength(12)
20
20
  })
21
21
 
@@ -41,7 +41,7 @@ describe('Mnemonic', function () {
41
41
  m = new Mnemonic().fromRandom(128)
42
42
  expect(m.check()).toEqual(true)
43
43
 
44
- const entropy = Array(32)
44
+ const entropy = new Array(32)
45
45
  entropy.fill(0)
46
46
  m = new Mnemonic().fromEntropy(entropy)
47
47
  expect(m.check()).toEqual(true)
@@ -34,7 +34,7 @@ function makeMockTx(txid: string, outputs: any[] = [], inputs: any[] = []): MTx
34
34
 
35
35
  function makeMockOutput(scriptHex?: string): TransactionOutput {
36
36
  const hex = scriptHex || '76a914' // Default to P2PKH prefix if no script provided
37
- const scriptArray = hex.match(/.{2}/g)?.map(byte => parseInt(byte, 16)) || [0x76, 0xa9, 0x14]
37
+ const scriptArray = hex.match(/.{2}/g)?.map(byte => Number.parseInt(byte, 16)) || [0x76, 0xa9, 0x14]
38
38
 
39
39
  return {
40
40
  satoshis: 1,
@@ -93,7 +93,7 @@ describe('HostReputationTracker – additional coverage', () => {
93
93
 
94
94
  it('treats NaN latency as DEFAULT_LATENCY_MS (1500)', () => {
95
95
  const t = new HostReputationTracker()
96
- t.recordSuccess('https://host.com', NaN)
96
+ t.recordSuccess('https://host.com', Number.NaN)
97
97
  const snap = t.snapshot('https://host.com')!
98
98
  expect(snap.avgLatencyMs).toBe(1500)
99
99
  })
@@ -261,8 +261,10 @@ function appendUtf8CodeUnit (msg: string, i: number, out: number[]): number {
261
261
 
262
262
  function utf8StringToArray (msg: string): number[] {
263
263
  const res: number[] = []
264
- for (let i = 0; i < msg.length; i++) {
265
- i = appendUtf8CodeUnit(msg, i, res)
264
+ let i = 0
265
+ while (i < msg.length) {
266
+ const lastConsumed = appendUtf8CodeUnit(msg, i, res)
267
+ i = lastConsumed + 1
266
268
  }
267
269
  return res
268
270
  }
@@ -52,7 +52,7 @@ describe('BN.js/Constructor', () => {
52
52
  it('should accept base-16 with spaces', () => {
53
53
  const num = 'a89c e5af8724 c0a23e0e 0ff77500'
54
54
  expect(new BigNumber(num, 16).toString(16)).toEqual(
55
- num.replace(/ /g, '')
55
+ num.replaceAll(' ', '')
56
56
  )
57
57
  })
58
58
 
@@ -34,36 +34,28 @@ describe('DRBG', () => {
34
34
  const entropy = new Array(31).fill(0x01)
35
35
  const nonce = new Array(32).fill(0x02)
36
36
 
37
- expect(() => {
38
- new DRBG(entropy, nonce)
39
- }).toThrow('Entropy must be exactly 32 bytes (256 bits)')
37
+ expect(() => new DRBG(entropy, nonce)).toThrow('Entropy must be exactly 32 bytes (256 bits)')
40
38
  })
41
39
 
42
40
  it('throws if entropy is longer than 32 bytes', () => {
43
41
  const entropy = new Array(33).fill(0x01)
44
42
  const nonce = new Array(32).fill(0x02)
45
43
 
46
- expect(() => {
47
- new DRBG(entropy, nonce)
48
- }).toThrow('Entropy must be exactly 32 bytes (256 bits)')
44
+ expect(() => new DRBG(entropy, nonce)).toThrow('Entropy must be exactly 32 bytes (256 bits)')
49
45
  })
50
46
 
51
47
  it('throws if nonce is shorter than 32 bytes', () => {
52
48
  const entropy = new Array(32).fill(0x01)
53
49
  const nonce = new Array(31).fill(0x02)
54
50
 
55
- expect(() => {
56
- new DRBG(entropy, nonce)
57
- }).toThrow('Nonce must be exactly 32 bytes (256 bits)')
51
+ expect(() => new DRBG(entropy, nonce)).toThrow('Nonce must be exactly 32 bytes (256 bits)')
58
52
  })
59
53
 
60
54
  it('throws if nonce is longer than 32 bytes', () => {
61
55
  const entropy = new Array(32).fill(0x01)
62
56
  const nonce = new Array(33).fill(0x02)
63
57
 
64
- expect(() => {
65
- new DRBG(entropy, nonce)
66
- }).toThrow('Nonce must be exactly 32 bytes (256 bits)')
58
+ expect(() => new DRBG(entropy, nonce)).toThrow('Nonce must be exactly 32 bytes (256 bits)')
67
59
  })
68
60
 
69
61
  it('accepts both hex strings and number[] inputs equivalently', () => {
@@ -118,7 +118,7 @@ describe('Point – additional coverage', () => {
118
118
  })
119
119
 
120
120
  it('throws for unknown format', () => {
121
- const der = [0x05, ...Array(32).fill(0x01)]
121
+ const der = [0x05, ...new Array(32).fill(0x01)]
122
122
  expect(() => Point.fromDER(der)).toThrow('Unknown point format')
123
123
  })
124
124
  })
@@ -147,7 +147,7 @@ describe('Point – additional coverage', () => {
147
147
  it('fromX accepts number', () => {
148
148
  // Use a valid x value that has a square root mod p
149
149
  const g = G.mul(new BigNumber(7))
150
- const xNum = parseInt(g.getX().toString(16).slice(-4), 16)
150
+ const xNum = Number.parseInt(g.getX().toString(16).slice(-4), 16)
151
151
  // fromX with a number, may produce a point
152
152
  const p = Point.fromX(g.getX(), true)
153
153
  expect(p.validate()).toBe(true)
@@ -40,7 +40,7 @@ describe('Point.fromJSON / fromDER / fromX curve validation (TOB-24)', () => {
40
40
  it('rejects invalid compressed points in fromDER', () => {
41
41
  // 0x02 is a valid compressed prefix, but x = 0 gives y^2 = 7,
42
42
  // which has no square root mod p on secp256k1 → invalid point.
43
- const der = [0x02, ...Array(32).fill(0x00)]
43
+ const der = [0x02, ...new Array(32).fill(0x00)]
44
44
  expect(() => Point.fromDER(der)).toThrow(/Invalid point/)
45
45
  })
46
46
 
@@ -37,7 +37,7 @@ describe('Cross-SDK Compatibility Tests', () => {
37
37
  // Convert hex to byte array
38
38
  const ciphertext: number[] = []
39
39
  for (let i = 0; i < ciphertextHex.length; i += 2) {
40
- ciphertext.push(parseInt(ciphertextHex.slice(i, i + 2), 16))
40
+ ciphertext.push(Number.parseInt(ciphertextHex.slice(i, i + 2), 16))
41
41
  }
42
42
 
43
43
  // Decrypt using TypeScript SDK
@@ -83,7 +83,7 @@ describe('Cross-SDK Compatibility Tests', () => {
83
83
  // Convert hex to byte array
84
84
  const ciphertext: number[] = []
85
85
  for (let i = 0; i < ciphertextHex.length; i += 2) {
86
- ciphertext.push(parseInt(ciphertextHex.slice(i, i + 2), 16))
86
+ ciphertext.push(Number.parseInt(ciphertextHex.slice(i, i + 2), 16))
87
87
  }
88
88
 
89
89
  // Decrypt using TypeScript SDK
@@ -127,7 +127,7 @@ describe('Cross-SDK Compatibility Tests', () => {
127
127
  // Test TypeScript decrypting Go ciphertext
128
128
  const goCiphertextBytes: number[] = []
129
129
  for (let i = 0; i < goCiphertext.length; i += 2) {
130
- goCiphertextBytes.push(parseInt(goCiphertext.substr(i, 2), 16))
130
+ goCiphertextBytes.push(Number.parseInt(goCiphertext.substr(i, 2), 16))
131
131
  }
132
132
 
133
133
  const goDecrypted = symKey.decrypt(goCiphertextBytes, 'utf8')
@@ -136,7 +136,7 @@ describe('Cross-SDK Compatibility Tests', () => {
136
136
  // Test TypeScript decrypting TypeScript ciphertext (sanity check)
137
137
  const tsCiphertextBytes: number[] = []
138
138
  for (let i = 0; i < tsCiphertext.length; i += 2) {
139
- tsCiphertextBytes.push(parseInt(tsCiphertext.substr(i, 2), 16))
139
+ tsCiphertextBytes.push(Number.parseInt(tsCiphertext.substr(i, 2), 16))
140
140
  }
141
141
 
142
142
  const tsDecrypted = symKey.decrypt(tsCiphertextBytes, 'utf8')
@@ -77,10 +77,10 @@ jest.mock('../../transaction/index.js', () => ({
77
77
  jest.mock('../../primitives/index.js', () => ({
78
78
  Utils: {
79
79
  toArray: jest.fn().mockImplementation((str: string) =>
80
- Array.from(str).map((c) => c.charCodeAt(0))
80
+ Array.from(str).map((c) => c.codePointAt(0))
81
81
  ),
82
82
  toUTF8: jest.fn().mockImplementation((arr: number[] | string) => {
83
- if (Array.isArray(arr)) return arr.map((n) => String.fromCharCode(n)).join('')
83
+ if (Array.isArray(arr)) return arr.map((n) => String.fromCodePoint(n)).join('')
84
84
  return arr
85
85
  })
86
86
  }
@@ -628,7 +628,7 @@ describe('RegistryClient.resolve – protocol and certificate parsing', () => {
628
628
  // protocol has 7 fields: protocolID, name, iconURL, description, docURL, operator, sig
629
629
  ;(PushDrop.decode as jest.Mock).mockReturnValueOnce({
630
630
  fields: [
631
- Array.from('[1,"proto"]').map((c) => c.charCodeAt(0)), // protocolID JSON
631
+ Array.from('[1,"proto"]').map((c) => c.codePointAt(0)), // protocolID JSON
632
632
  [110, 97, 109, 101], // 'name'
633
633
  [105, 99, 111, 110], // 'icon'
634
634
  [100, 101, 115, 99], // 'desc'
@@ -658,7 +658,7 @@ describe('RegistryClient.resolve – protocol and certificate parsing', () => {
658
658
  [105, 99, 111, 110], // 'icon'
659
659
  [100, 101, 115, 99], // 'desc'
660
660
  [100, 111, 99], // 'doc'
661
- Array.from(fieldsJSON).map((c) => c.charCodeAt(0)), // fieldsJSON
661
+ Array.from(fieldsJSON).map((c) => c.codePointAt(0)), // fieldsJSON
662
662
  [111, 112], // 'op' - operator
663
663
  [115, 105, 103] // signature
664
664
  ]
@@ -82,11 +82,11 @@ jest.mock('../../primitives/index.js', () => {
82
82
  return {
83
83
  Utils: {
84
84
  toArray: jest.fn().mockImplementation((str: string) =>
85
- Array.from(str).map((c) => c.charCodeAt(0))
85
+ Array.from(str).map((c) => c.codePointAt(0))
86
86
  ),
87
87
  toUTF8: jest.fn().mockImplementation((arr: number[] | string) => {
88
88
  if (Array.isArray(arr)) {
89
- return arr.map((n) => String.fromCharCode(n)).join('')
89
+ return arr.map((n) => String.fromCodePoint(n)).join('')
90
90
  }
91
91
  return arr
92
92
  })
@@ -376,7 +376,7 @@ describe('StorageUploader — multi-provider behavior', () => {
376
376
  })
377
377
 
378
378
  // All three quotes requested (up to 2 * resilienceLevel = 4 allowed, but we only have 3 hosts).
379
- expect(quoteCalls.sort()).toEqual([
379
+ expect(quoteCalls.sort((a, b) => a.localeCompare(b))).toEqual([
380
380
  'https://a.example/quote',
381
381
  'https://b.example/quote',
382
382
  'https://c.example/quote'
@@ -611,7 +611,7 @@ describe('StorageUploader — multi-provider behavior', () => {
611
611
  })
612
612
 
613
613
  // Only the first batch of 4 quote requests should have been issued.
614
- expect(quoteCalls.sort()).toEqual([
614
+ expect(quoteCalls.sort((a, b) => a.localeCompare(b))).toEqual([
615
615
  'https://h1.example/quote',
616
616
  'https://h2.example/quote',
617
617
  'https://h3.example/quote',
@@ -649,7 +649,7 @@ describe('StorageUploader — multi-provider behavior', () => {
649
649
  retentionPeriod: 60
650
650
  })
651
651
 
652
- expect(quoteCalls.sort()).toEqual([
652
+ expect(quoteCalls.sort((a, b) => a.localeCompare(b))).toEqual([
653
653
  'https://h1.example/quote',
654
654
  'https://h2.example/quote',
655
655
  'https://h3.example/quote',
@@ -696,7 +696,7 @@ describe('StorageUploader — multi-provider behavior', () => {
696
696
 
697
697
  // First batch queried h1-h4 (4 hosts), second batch queried only h5
698
698
  // (1 host, the exact remainder). Hosts h6-h8 are never contacted.
699
- expect(quoteCalls.sort()).toEqual([
699
+ expect(quoteCalls.sort((a, b) => a.localeCompare(b))).toEqual([
700
700
  'https://h1.example/quote',
701
701
  'https://h2.example/quote',
702
702
  'https://h3.example/quote',
@@ -763,7 +763,7 @@ describe('StorageUploader — multi-host findFile / listUploads / renewFile', ()
763
763
 
764
764
  const result = await uploader.findFile('uhrp://x')
765
765
 
766
- expect(calls.sort()).toEqual([
766
+ expect(calls.sort((a, b) => a.localeCompare(b))).toEqual([
767
767
  'https://a.example/find?uhrpUrl=uhrp%3A%2F%2Fx',
768
768
  'https://b.example/find?uhrpUrl=uhrp%3A%2F%2Fx',
769
769
  'https://c.example/find?uhrpUrl=uhrp%3A%2F%2Fx'
@@ -843,7 +843,7 @@ describe('StorageUploader — multi-host findFile / listUploads / renewFile', ()
843
843
  const listing = await uploader.listUploads()
844
844
  const byUrl = Object.fromEntries(listing.map((e: any) => [e.uhrpUrl, e]))
845
845
 
846
- expect(Object.keys(byUrl).sort()).toEqual(['uhrp://one', 'uhrp://shared', 'uhrp://two'])
846
+ expect(Object.keys(byUrl).sort((a, b) => a.localeCompare(b))).toEqual(['uhrp://one', 'uhrp://shared', 'uhrp://two'])
847
847
  expect(byUrl['uhrp://shared'].expiryTime).toBe(300) // longest wins
848
848
  expect(byUrl['uhrp://shared'].hostedBy.sort()).toEqual(['https://a.example', 'https://b.example'])
849
849
  expect(byUrl['uhrp://one'].hostedBy).toEqual(['https://a.example'])
@@ -1026,7 +1026,7 @@ describe('StorageUploader — multi-host findFile / listUploads / renewFile', ()
1026
1026
  hostedBy: ['https://a.example', 'https://c.example']
1027
1027
  })
1028
1028
 
1029
- expect(calls.sort()).toEqual([
1029
+ expect(calls.sort((a, b) => a.localeCompare(b))).toEqual([
1030
1030
  'https://a.example/renew',
1031
1031
  'https://c.example/renew'
1032
1032
  ])
@@ -703,7 +703,7 @@ describe('Transaction', () => {
703
703
  sequence: 0xffffffff
704
704
  }
705
705
  ],
706
- Array(21)
706
+ new Array(21)
707
707
  .fill(null)
708
708
  .map(() => ({
709
709
  lockingScript: p2pkh.lock(publicKeyHash),
@@ -1508,7 +1508,7 @@ describe('Transaction', () => {
1508
1508
 
1509
1509
  tx.addInput({
1510
1510
  sourceTXID: txid,
1511
- sourceOutputIndex: parseInt(voutStr),
1511
+ sourceOutputIndex: Number.parseInt(voutStr),
1512
1512
  unlockingScript
1513
1513
  })
1514
1514
  }
@@ -1553,7 +1553,7 @@ describe('Transaction', () => {
1553
1553
  for (const [index, spend] of Object.entries(args.spends)) {
1554
1554
  tx.addInput({
1555
1555
  sourceTXID: '00'.repeat(32),
1556
- sourceOutputIndex: parseInt(index),
1556
+ sourceOutputIndex: Number.parseInt(index),
1557
1557
  unlockingScript: Script.fromHex((spend as any).unlockingScript)
1558
1558
  })
1559
1559
  }