@bsv/sdk 1.6.0 → 1.6.2

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 (28) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/dist/cjs/src/overlay-tools/LookupResolver.js +3 -12
  3. package/dist/cjs/src/overlay-tools/LookupResolver.js.map +1 -1
  4. package/dist/cjs/src/overlay-tools/SHIPBroadcaster.js +44 -8
  5. package/dist/cjs/src/overlay-tools/SHIPBroadcaster.js.map +1 -1
  6. package/dist/cjs/src/transaction/Transaction.js +1 -1
  7. package/dist/cjs/src/transaction/Transaction.js.map +1 -1
  8. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  9. package/dist/esm/src/overlay-tools/LookupResolver.js +3 -12
  10. package/dist/esm/src/overlay-tools/LookupResolver.js.map +1 -1
  11. package/dist/esm/src/overlay-tools/SHIPBroadcaster.js +21 -8
  12. package/dist/esm/src/overlay-tools/SHIPBroadcaster.js.map +1 -1
  13. package/dist/esm/src/transaction/Transaction.js +1 -1
  14. package/dist/esm/src/transaction/Transaction.js.map +1 -1
  15. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  16. package/dist/types/src/overlay-tools/LookupResolver.d.ts +1 -3
  17. package/dist/types/src/overlay-tools/LookupResolver.d.ts.map +1 -1
  18. package/dist/types/src/overlay-tools/SHIPBroadcaster.d.ts +1 -0
  19. package/dist/types/src/overlay-tools/SHIPBroadcaster.d.ts.map +1 -1
  20. package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
  21. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  22. package/dist/umd/bundle.js +1 -1
  23. package/package.json +1 -1
  24. package/src/overlay-tools/LookupResolver.ts +5 -18
  25. package/src/overlay-tools/SHIPBroadcaster.ts +21 -8
  26. package/src/overlay-tools/__tests/LookupResolver.test.ts +0 -112
  27. package/src/overlay-tools/__tests/SHIPBroadcaster.test.ts +2 -1
  28. package/src/transaction/Transaction.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/sdk",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "type": "module",
5
5
  "description": "BSV Blockchain Software Development Kit",
6
6
  "main": "dist/cjs/mod.js",
@@ -27,12 +27,9 @@ export type LookupAnswer =
27
27
  outputs: Array<{
28
28
  beef: number[]
29
29
  outputIndex: number
30
+ context?: number[]
30
31
  }>
31
32
  }
32
- | {
33
- type: 'freeform'
34
- result: unknown
35
- }
36
33
 
37
34
  /** Default SLAP trackers */
38
35
  export const DEFAULT_SLAP_TRACKERS: string[] = [
@@ -200,13 +197,8 @@ export default class LookupResolver {
200
197
  }
201
198
 
202
199
  // Process the successful responses
203
- if (successfulResponses[0].type === 'freeform') {
204
- // Return the first freeform response
205
- return successfulResponses[0]
206
- }
207
-
208
200
  // Aggregate outputs from all successful responses
209
- const outputs = new Map<string, { beef: number[], outputIndex: number }>()
201
+ const outputs = new Map<string, { beef: number[], context?: number[], outputIndex: number }>()
210
202
 
211
203
  for (const response of successfulResponses) {
212
204
  if (response.type !== 'output-list') {
@@ -215,14 +207,9 @@ export default class LookupResolver {
215
207
  try {
216
208
  for (const output of response.outputs) {
217
209
  try {
218
- const txId: string = String(Transaction.fromBEEF(output.beef).id('hex'))
219
-
220
- if (txId !== '') { // ✅ Ensures `txId` is always a non-empty string
221
- const key = `${String(txId)}.${String(output.outputIndex)}`
222
- outputs.set(key, output)
223
- } else {
224
- console.warn('Invalid transaction ID:', txId)
225
- }
210
+ const txId: string = Transaction.fromBEEF(output.beef).id('hex') // !! This is STUPIDLY inefficient.
211
+ const key = `${txId}.${output.outputIndex}`
212
+ outputs.set(key, output)
226
213
  } catch {
227
214
  continue
228
215
  }
@@ -4,6 +4,7 @@ import {
4
4
  BroadcastFailure,
5
5
  Broadcaster
6
6
  } from '../transaction/index.js'
7
+ import * as Utils from '../primitives/utils.js'
7
8
  import LookupResolver from './LookupResolver.js'
8
9
  import OverlayAdminTokenTemplate from './OverlayAdminTokenTemplate.js'
9
10
 
@@ -16,6 +17,7 @@ import OverlayAdminTokenTemplate from './OverlayAdminTokenTemplate.js'
16
17
  export interface TaggedBEEF {
17
18
  beef: number[]
18
19
  topics: string[]
20
+ offChainValues?: number[]
19
21
  }
20
22
 
21
23
  /**
@@ -86,19 +88,30 @@ export class HTTPSOverlayBroadcastFacilitator implements OverlayBroadcastFacilit
86
88
  }
87
89
 
88
90
  async send (url: string, taggedBEEF: TaggedBEEF): Promise<STEAK> {
89
- console.log(url)
90
91
  if (!url.startsWith('https:') && !this.allowHTTP) {
91
92
  throw new Error(
92
93
  'HTTPS facilitator can only use URLs that start with "https:"'
93
94
  )
94
95
  }
96
+ const headers = {
97
+ 'Content-Type': 'application/octet-stream',
98
+ 'X-Topics': JSON.stringify(taggedBEEF.topics)
99
+ }
100
+ let body
101
+ if (Array.isArray(taggedBEEF.offChainValues)) {
102
+ headers['x-includes-off-chain-values'] = 'true'
103
+ const w = new Utils.Writer()
104
+ w.writeVarIntNum(taggedBEEF.beef.length)
105
+ w.write(taggedBEEF.beef)
106
+ w.write(taggedBEEF.offChainValues)
107
+ body = new Uint8Array(w.toArray())
108
+ } else {
109
+ body = new Uint8Array(taggedBEEF.beef)
110
+ }
95
111
  const response = await fetch(`${url}/submit`, {
96
112
  method: 'POST',
97
- headers: {
98
- 'Content-Type': 'application/octet-stream',
99
- 'X-Topics': JSON.stringify(taggedBEEF.topics)
100
- },
101
- body: new Uint8Array(taggedBEEF.beef)
113
+ headers,
114
+ body
102
115
  })
103
116
  if (response.ok) {
104
117
  return await response.json()
@@ -154,8 +167,8 @@ export default class TopicBroadcaster implements Broadcaster {
154
167
  async broadcast (
155
168
  tx: Transaction
156
169
  ): Promise<BroadcastResponse | BroadcastFailure> {
157
- console.log(tx)
158
170
  let beef: number[]
171
+ const offChainValues = tx.metadata.get('OffChainValues') as number[]
159
172
  try {
160
173
  beef = tx.toBEEF()
161
174
  } catch (error) {
@@ -164,7 +177,6 @@ export default class TopicBroadcaster implements Broadcaster {
164
177
  )
165
178
  }
166
179
  const interestedHosts = await this.findInterestedHosts()
167
- console.log(interestedHosts)
168
180
  if (Object.keys(interestedHosts).length === 0) {
169
181
  return {
170
182
  status: 'error',
@@ -177,6 +189,7 @@ export default class TopicBroadcaster implements Broadcaster {
177
189
  try {
178
190
  const steak = await this.facilitator.send(host, {
179
191
  beef,
192
+ offChainValues,
180
193
  topics: [...topics]
181
194
  })
182
195
  if (steak == null || Object.keys(steak).length === 0) {
@@ -620,118 +620,6 @@ describe('LookupResolver', () => {
620
620
  ])
621
621
  })
622
622
 
623
- it('should handle hosts returning different response types', async () => {
624
- const slapHostKey1 = new PrivateKey(42)
625
- const slapWallet1 = new CompletedProtoWallet(slapHostKey1)
626
- const slapLib1 = new OverlayAdminTokenTemplate(slapWallet1)
627
- const slapScript1 = await slapLib1.lock(
628
- 'SLAP',
629
- 'https://slaphost1.com',
630
- 'ls_foo'
631
- )
632
- const slapTx1 = new Transaction(
633
- 1,
634
- [],
635
- [
636
- {
637
- lockingScript: slapScript1,
638
- satoshis: 1
639
- }
640
- ],
641
- 0
642
- )
643
-
644
- const slapHostKey2 = new PrivateKey(43)
645
- const slapWallet2 = new CompletedProtoWallet(slapHostKey2)
646
- const slapLib2 = new OverlayAdminTokenTemplate(slapWallet2)
647
- const slapScript2 = await slapLib2.lock(
648
- 'SLAP',
649
- 'https://slaphost2.com',
650
- 'ls_foo'
651
- )
652
- const slapTx2 = new Transaction(
653
- 1,
654
- [],
655
- [
656
- {
657
- lockingScript: slapScript2,
658
- satoshis: 1
659
- }
660
- ],
661
- 0
662
- )
663
-
664
- // SLAP tracker returns two hosts
665
- mockFacilitator.lookup.mockReturnValueOnce({
666
- type: 'output-list',
667
- outputs: [
668
- { outputIndex: 0, beef: slapTx1.toBEEF() },
669
- { outputIndex: 0, beef: slapTx2.toBEEF() }
670
- ]
671
- })
672
-
673
- // First host returns 'freeform' response
674
- mockFacilitator.lookup.mockReturnValueOnce({
675
- type: 'freeform',
676
- result: { message: 'Freeform response from host1' }
677
- })
678
-
679
- // Second host returns 'output-list' response
680
- mockFacilitator.lookup.mockReturnValueOnce({
681
- type: 'output-list',
682
- outputs: [{ beef: sampleBeef3, outputIndex: 0 }]
683
- })
684
-
685
- const r = new LookupResolver({
686
- facilitator: mockFacilitator,
687
- slapTrackers: ['https://mock.slap']
688
- })
689
-
690
- const res = await r.query({
691
- service: 'ls_foo',
692
- query: { test: 1 }
693
- })
694
-
695
- // Since the first response is 'freeform', it should return that response
696
- expect(res).toEqual({
697
- type: 'freeform',
698
- result: { message: 'Freeform response from host1' }
699
- })
700
-
701
- expect(mockFacilitator.lookup.mock.calls).toEqual([
702
- [
703
- 'https://mock.slap',
704
- {
705
- service: 'ls_slap',
706
- query: {
707
- service: 'ls_foo'
708
- }
709
- },
710
- 5000
711
- ],
712
- [
713
- 'https://slaphost1.com',
714
- {
715
- service: 'ls_foo',
716
- query: {
717
- test: 1
718
- }
719
- },
720
- undefined
721
- ],
722
- [
723
- 'https://slaphost2.com',
724
- {
725
- service: 'ls_foo',
726
- query: {
727
- test: 1
728
- }
729
- },
730
- undefined
731
- ]
732
- ])
733
- })
734
-
735
623
  it('should ignore freeform responses when first response is output-list', async () => {
736
624
  const slapHostKey1 = new PrivateKey(42)
737
625
  const slapWallet1 = new CompletedProtoWallet(slapHostKey1)
@@ -253,7 +253,8 @@ describe('SHIPCast', () => {
253
253
  const testTx = {
254
254
  toBEEF: () => {
255
255
  throw new Error('Cannot serialize to BEEF')
256
- }
256
+ },
257
+ metadata: new Map()
257
258
  } as unknown as Transaction
258
259
 
259
260
  await expect(b.broadcast(testTx)).rejects.toThrow(
@@ -318,7 +318,7 @@ export default class Transaction {
318
318
  inputs: TransactionInput[] = [],
319
319
  outputs: TransactionOutput[] = [],
320
320
  lockTime: number = 0,
321
- metadata: Record<string, any> = {},
321
+ metadata: Record<string, any> = new Map(),
322
322
  merklePath?: MerklePath
323
323
  ) {
324
324
  this.version = version