@bsv/overlay 0.1.14 → 0.1.16

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 (45) hide show
  1. package/dist/cjs/mod.js.map +1 -1
  2. package/dist/cjs/package.json +2 -2
  3. package/dist/cjs/src/Engine.js +83 -122
  4. package/dist/cjs/src/Engine.js.map +1 -1
  5. package/dist/cjs/src/SHIPAdvertisement.js +3 -0
  6. package/dist/cjs/src/SHIPAdvertisement.js.map +1 -0
  7. package/dist/cjs/src/SLAPAdvertisement.js +3 -0
  8. package/dist/cjs/src/SLAPAdvertisement.js.map +1 -0
  9. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  10. package/dist/esm/mod.js.map +1 -1
  11. package/dist/esm/src/Engine.js +86 -119
  12. package/dist/esm/src/Engine.js.map +1 -1
  13. package/dist/esm/src/SHIPAdvertisement.js +2 -0
  14. package/dist/esm/src/SHIPAdvertisement.js.map +1 -0
  15. package/dist/esm/src/SLAPAdvertisement.js +2 -0
  16. package/dist/esm/src/SLAPAdvertisement.js.map +1 -0
  17. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  18. package/dist/types/mod.d.ts +2 -6
  19. package/dist/types/mod.d.ts.map +1 -1
  20. package/dist/types/src/Advertiser.d.ts +1 -2
  21. package/dist/types/src/Advertiser.d.ts.map +1 -1
  22. package/dist/types/src/Engine.d.ts +27 -15
  23. package/dist/types/src/Engine.d.ts.map +1 -1
  24. package/dist/types/src/LookupService.d.ts +1 -3
  25. package/dist/types/src/LookupService.d.ts.map +1 -1
  26. package/dist/types/src/SHIPAdvertisement.d.ts +9 -0
  27. package/dist/types/src/SHIPAdvertisement.d.ts.map +1 -0
  28. package/dist/types/src/SLAPAdvertisement.d.ts +9 -0
  29. package/dist/types/src/SLAPAdvertisement.d.ts.map +1 -0
  30. package/dist/types/src/TopicManager.d.ts +1 -1
  31. package/dist/types/src/TopicManager.d.ts.map +1 -1
  32. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  33. package/docs/API.md +736 -212
  34. package/mod.ts +2 -6
  35. package/package.json +2 -2
  36. package/src/Advertiser.ts +1 -2
  37. package/src/Engine.ts +125 -132
  38. package/src/LookupService.ts +1 -3
  39. package/src/TopicManager.ts +1 -1
  40. package/src/__tests/Engine.test.ts +1 -5
  41. package/src/AdmittanceInstructions.ts +0 -14
  42. package/src/LookupAnswer.ts +0 -14
  43. package/src/LookupQuestion.ts +0 -15
  44. package/src/STEAK.ts +0 -10
  45. package/src/TaggedBEEF.ts +0 -10
package/mod.ts CHANGED
@@ -6,14 +6,10 @@ export type { TopicManager } from "./src/TopicManager.js"
6
6
  // Interfaces and structures
7
7
  export type { Storage, AppliedTransaction } from "./src/storage/Storage.js"
8
8
  export type { Output } from './src/Output.js'
9
- export type { AdmittanceInstructions } from './src/AdmittanceInstructions.js'
10
- export type { TaggedBEEF } from './src/TaggedBEEF.js'
11
- export type { STEAK } from './src/STEAK.js'
12
- export type { LookupQuestion } from './src/LookupQuestion.js'
9
+ export type { TaggedBEEF, STEAK, LookupQuestion, LookupAnswer, AdmittanceInstructions } from '@bsv/sdk'
13
10
  export type { LookupFormula } from './src/LookupFormula.js'
14
- export type { LookupAnswer } from './src/LookupAnswer.js'
15
11
  export type { Advertisement } from './src/Advertisement.js'
16
- export type { AdvertisementData } from './src/Advertiser.js'
12
+ export type { AdvertisementData, Advertiser } from './src/Advertiser.js'
17
13
 
18
14
  // The Knex storage system
19
15
  export { KnexStorage } from './src/storage/knex/KnexStorage.js'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/overlay",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "type": "module",
5
5
  "description": "BSV Blockchain Overlay Services Engine",
6
6
  "main": "dist/cjs/mod.js",
@@ -73,7 +73,7 @@
73
73
  },
74
74
  "dependencies": {
75
75
  "@bsv/gasp": "^0.1.2",
76
- "@bsv/sdk": "^1.1.24",
76
+ "@bsv/sdk": "^1.2.3",
77
77
  "knex": "^3.1.0"
78
78
  }
79
79
  }
package/src/Advertiser.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { Script } from '@bsv/sdk'
1
+ import { Script, TaggedBEEF } from '@bsv/sdk'
2
2
  import { Advertisement } from './Advertisement.js'
3
- import { TaggedBEEF } from './TaggedBEEF.js'
4
3
 
5
4
  export interface AdvertisementData {
6
5
  protocol: 'SHIP' | 'SLAP'
package/src/Engine.ts CHANGED
@@ -1,24 +1,33 @@
1
1
  import { TopicManager } from './TopicManager.js'
2
2
  import { LookupService } from './LookupService.js'
3
3
  import { Storage } from './storage/Storage.js'
4
- import type { AdmittanceInstructions } from './AdmittanceInstructions.js'
5
4
  import type { Output } from './Output.js'
6
- import { TaggedBEEF } from './TaggedBEEF.js'
7
- import { STEAK } from './STEAK.js'
8
- import { LookupQuestion } from './LookupQuestion.js'
9
- import { LookupAnswer } from './LookupAnswer.js'
10
5
  import { LookupFormula } from './LookupFormula.js'
11
- import { Transaction, ChainTracker, MerklePath, Broadcaster, isBroadcastFailure } from '@bsv/sdk'
6
+ import {
7
+ Transaction,
8
+ ChainTracker,
9
+ MerklePath,
10
+ Broadcaster,
11
+ isBroadcastFailure,
12
+ TaggedBEEF, STEAK,
13
+ LookupQuestion,
14
+ LookupAnswer,
15
+ AdmittanceInstructions,
16
+ SHIPBroadcaster,
17
+ HTTPSOverlayBroadcastFacilitator,
18
+ LookupResolver,
19
+ LookupResolverConfig,
20
+ OverlayBroadcastFacilitator
21
+ } from '@bsv/sdk'
12
22
  import { AdvertisementData, Advertiser } from './Advertiser.js'
13
23
  import { GASP, GASPInitialRequest, GASPInitialResponse, GASPNode } from '@bsv/gasp'
14
24
  import { SyncConfiguration } from './SyncConfiguration.js'
15
- import { Advertisement } from './Advertisement.js'
16
25
  import { OverlayGASPRemote } from './GASP/OverlayGASPRemote.js'
17
26
  import { OverlayGASPStorage } from './GASP/OverlayGASPStorage.js'
18
27
  import { URL } from "url"
19
28
 
20
29
  /**
21
- * Am engine for running BSV Overlay Services (topic managers and lookup services).
30
+ * An engine for running BSV Overlay Services (topic managers and lookup services).
22
31
  */
23
32
  export class Engine {
24
33
  /**
@@ -30,12 +39,14 @@ export class Engine {
30
39
  * @param {string} [hostingURL] - The URL this engine is hosted at. Required if going to support peer-discovery with an advertiser.
31
40
  * @param {Broadcaster} [Broadcaster] - broadcaster used for broadcasting the incoming transaction
32
41
  * @param {Advertiser} [Advertiser] - handles SHIP and SLAP advertisements for peer-discovery
33
- * @param {string} shipTrackers - SHIP domains we know to bootstrap the system
34
- * @param {string} slapTrackers - SLAP domains we know to bootstrap the system
42
+ * @param {string[]} shipTrackers - SHIP domains we know to bootstrap the system
43
+ * @param {string[]} slapTrackers - SLAP domains we know to bootstrap the system
35
44
  * @param {SyncConfiguration} syncConfiguration — Configuration object describing historical synchronization of topics.
36
45
  * @param {boolean} logTime - Enables / disables the timing logs for various operations in the Overlay submit route.
37
46
  * @param {string} logPrefix - Supports overriding the log prefix with a custom string.
38
47
  * @param {boolean} throwOnBroadcastFailure - Enables / disables throwing an error when a transaction broadcast failure is detected.
48
+ * @param {OverlayBroadcastFacilitator} overlayBroadcastFacilitator - Facilitator for propagation to other Overlay Services.
49
+ * @param {typeof console} logger - The place where log entries are written.
39
50
  */
40
51
  constructor(
41
52
  public managers: { [key: string]: TopicManager },
@@ -50,7 +61,9 @@ export class Engine {
50
61
  public syncConfiguration?: SyncConfiguration,
51
62
  public logTime = false,
52
63
  public logPrefix = '[OVERLAY_ENGINE] ',
53
- public throwOnBroadcastFailure = false
64
+ public throwOnBroadcastFailure = false,
65
+ public overlayBroadcastFacilitator: OverlayBroadcastFacilitator = new HTTPSOverlayBroadcastFacilitator(),
66
+ public logger: typeof console = console
54
67
  ) {
55
68
  // To encourage synchronization of overlay services, the SHIP sync strategy is used by default for all overlay topics, except for 'tm_ship' and 'tm_slap'.
56
69
  // For these two topics, any existing trackers are combined with the provided shipTrackers and slapTrackers omitting any duplicates.
@@ -87,13 +100,13 @@ export class Engine {
87
100
  // Helper functions for logging timings
88
101
  private startTime(label: string): void {
89
102
  if (this.logTime) {
90
- console.time(`${this.logPrefix} ${label}`)
103
+ this.logger.time(`${this.logPrefix} ${label}`)
91
104
  }
92
105
  }
93
106
 
94
107
  private endTime(label: string): void {
95
108
  if (this.logTime) {
96
- console.timeEnd(`${this.logPrefix} ${label}`)
109
+ this.logger.timeEnd(`${this.logPrefix} ${label}`)
97
110
  }
98
111
  }
99
112
 
@@ -125,7 +138,6 @@ export class Engine {
125
138
  this.endTime(`chainTracker_${txid.substring(0, 10)}`)
126
139
 
127
140
  const steak: STEAK = {}
128
- let admissibleOutputs: AdmittanceInstructions = { outputsToAdmit: [], coinsToRetain: [] }
129
141
  const previousCoins: number[] = []
130
142
 
131
143
  // Parallelize the topic processing
@@ -169,15 +181,16 @@ export class Engine {
169
181
  try {
170
182
  await l.outputSpent?.(output.txid, output.outputIndex, topic)
171
183
  } catch (error) {
172
- console.error('Error in lookup service for outputSpent:', error)
184
+ this.logger.error('Error in lookup service for outputSpent:', error)
173
185
  }
174
186
  }))
175
187
  } catch (error) {
176
- console.error('Error marking UTXO as spent:', error)
188
+ this.logger.error('Error marking UTXO as spent:', error)
177
189
  }
178
190
  }
179
191
  })
180
192
 
193
+ let admissibleOutputs: AdmittanceInstructions = { outputsToAdmit: [], coinsToRetain: [] }
181
194
  // Determine which outputs are admissible
182
195
  const admissibleOutputsPromise = (async () => {
183
196
  try {
@@ -215,25 +228,27 @@ export class Engine {
215
228
  onSteakReady(steak)
216
229
  }
217
230
 
231
+ // Update storage and notify lookup services
218
232
  for (const topic of taggedBEEF.topics) {
219
233
  // Keep track of which outputs to admit, mark as stale, or retain
234
+ const admissibleOutputs = steak[topic]
220
235
  const outputsToAdmit: number[] = admissibleOutputs.outputsToAdmit
221
- const staleCoins: Array<{
236
+ const outputsConsumed: Array<{
222
237
  txid: string
223
238
  outputIndex: number
224
239
  }> = []
225
- const outputsConsumed: Array<{
240
+
241
+ const outputsToMarkStale: Array<{
226
242
  txid: string
227
243
  outputIndex: number
228
244
  }> = []
229
245
 
230
- // Find which outputs should not be retained and mark them as stale
231
- // For each of the previous UTXOs, if the the UTXO was not included in the list of UTXOs identified for retention, then it will be marked as stale.
246
+ // For each of the previous UTXOs, if the UTXO was not included in the list of UTXOs identified for retention, then it will be marked as stale.
232
247
  for (const inputIndex of previousCoins) {
233
248
  const previousTXID = tx.inputs[inputIndex].sourceTXID || tx.inputs[inputIndex].sourceTransaction?.id('hex') as string
234
249
  const previousOutputIndex = tx.inputs[inputIndex].sourceOutputIndex
235
250
  if (!admissibleOutputs.coinsToRetain.includes(inputIndex)) {
236
- staleCoins.push({
251
+ outputsToMarkStale.push({
237
252
  txid: previousTXID,
238
253
  outputIndex: previousOutputIndex
239
254
  })
@@ -247,7 +262,7 @@ export class Engine {
247
262
 
248
263
  // Remove stale outputs recursively
249
264
  this.startTime(`lookForStaleOutputs_${txid.substring(0, 10)}`)
250
- await Promise.all(staleCoins.map(async coin => {
265
+ await Promise.all(outputsToMarkStale.map(async coin => {
251
266
  const output = await this.storage.findOutput(coin.txid, coin.outputIndex, topic)
252
267
  if (output !== undefined && output !== null) {
253
268
  await this.deleteUTXODeep(output)
@@ -302,110 +317,74 @@ export class Engine {
302
317
  }
303
318
 
304
319
  this.startTime(`transactionPropagation_${txid.substring(0, 10)}`)
305
- // Propagate transaction to other nodes according to synchronization agreements
306
- // 1. Find nodes that host the topics associated with admissable outputs
307
- // We want to figure out which topics we actually care about (because their associated outputs were admitted)
308
- // AND if the topic was not admitted we want to remove it from the list of topics we care about.
309
320
  const relevantTopics = taggedBEEF.topics.filter(topic =>
310
321
  steak[topic] !== undefined && steak[topic].outputsToAdmit.length !== 0
311
322
  )
312
323
 
313
- // TODO: Cache ship/slap lookup with expiry (every 5min)
314
324
  if (relevantTopics.length > 0) {
315
- // Find all SHIP advertisements for the topics we care about
316
- const domainToTopicsMap = new Map<string, Set<string>>()
317
- for (const topic of relevantTopics) {
318
- try {
319
- // Handle custom lookup service answers
320
- const lookupAnswer = await this.lookup({
321
- service: 'ls_ship',
322
- query: {
323
- topic
324
- }
325
- })
326
-
327
- // Lookup will currently always return type output-list
328
- if (lookupAnswer.type === 'output-list') {
329
- const shipAdvertisements: Advertisement[] = []
330
- lookupAnswer.outputs.forEach(output => {
331
- try {
332
- // Parse out the advertisements using the provided parser
333
- const tx = Transaction.fromBEEF(output.beef)
334
- const advertisement = this.advertiser?.parseAdvertisement(tx.outputs[output.outputIndex].lockingScript)
335
- if (advertisement !== undefined && advertisement !== null && advertisement.protocol === 'SHIP') {
336
- shipAdvertisements.push(advertisement)
337
- }
338
- } catch (error) {
339
- console.error('Failed to parse advertisement output:', error)
340
- }
341
- })
342
- if (shipAdvertisements.length > 0) {
343
- shipAdvertisements.forEach((advertisement: Advertisement) => {
344
- if (!domainToTopicsMap.has(advertisement.domain)) {
345
- domainToTopicsMap.set(advertisement.domain, new Set<string>())
346
- }
347
- domainToTopicsMap.get(advertisement.domain)?.add(topic)
348
- })
349
- }
350
- }
351
- } catch (error) {
352
- console.error(`Error looking up topic ${String(topic)}:`, error)
325
+ // Create a SHIPBroadcaster instance
326
+ let customBroadcasterConfig
327
+ if (this.slapTrackers) {
328
+ // Custom SLAP trackers warrant a custom broadcaster config
329
+ const resolverConfig: LookupResolverConfig = {
330
+ slapTrackers: this.slapTrackers
331
+ }
332
+ customBroadcasterConfig = {
333
+ resolver: new LookupResolver(resolverConfig)
353
334
  }
354
335
  }
336
+ const shipBroadcaster = new SHIPBroadcaster(relevantTopics, customBroadcasterConfig)
355
337
 
356
- const broadcastPromises: Array<Promise<Response>> = []
357
-
358
- // Make sure we gossip to the shipTrackers we know about.
359
- if (this.shipTrackers !== undefined && this.shipTrackers.length !== 0 && relevantTopics.includes('tm_ship')) {
360
- this.shipTrackers.forEach(tracker => {
361
- if (domainToTopicsMap.get(tracker) !== undefined) {
362
- domainToTopicsMap.get(tracker)?.add('tm_ship')
363
- } else {
364
- domainToTopicsMap.set(tracker, new Set(['tm_ship']))
365
- }
366
- })
338
+ try {
339
+ await shipBroadcaster.broadcast(tx)
340
+ } catch (error) {
341
+ this.logger.error('Error during broadcasting:', error)
367
342
  }
368
343
 
369
- // Make sure we gossip to the slapTrackers we know about.
370
- if (this.slapTrackers !== undefined && this.slapTrackers.length !== 0 && relevantTopics.includes('tm_slap')) {
371
- this.slapTrackers.forEach(tracker => {
372
- if (domainToTopicsMap.get(tracker) !== undefined) {
373
- domainToTopicsMap.get(tracker)?.add('tm_slap')
374
- } else {
375
- domainToTopicsMap.set(tracker, new Set<string>(['tm_slap']))
344
+ // Handle shipTrackers for 'tm_ship' topic
345
+ if (this.shipTrackers && this.shipTrackers.length > 0 && relevantTopics.includes('tm_ship')) {
346
+ const taggedBEEFForShip = {
347
+ beef: taggedBEEF.beef,
348
+ topics: ['tm_ship']
349
+ }
350
+ const facilitator = this.overlayBroadcastFacilitator
351
+
352
+ const sendPromises = this.shipTrackers.map(async tracker => {
353
+ try {
354
+ await facilitator.send(tracker, taggedBEEFForShip)
355
+ } catch (error) {
356
+ this.logger.error(`Error sending to shipTracker ${tracker}:`, error)
376
357
  }
377
358
  })
359
+ await Promise.all(sendPromises)
378
360
  }
379
361
 
380
- // Note: We are depending on window.fetch, this may not be ideal for the long term.
381
- for (const [domain, topics] of domainToTopicsMap.entries()) {
382
- if (domain !== this.hostingURL) {
383
- const promise = fetch(`${String(domain)}/submit`, {
384
- method: 'POST',
385
- headers: {
386
- 'Content-Type': 'application/octet-stream',
387
- 'X-Topics': JSON.stringify(Array.from(topics))
388
- },
389
- body: new Uint8Array(taggedBEEF.beef)
390
- })
391
- broadcastPromises.push(promise)
362
+ // Handle slapTrackers for 'tm_slap' topic
363
+ if (this.slapTrackers && this.slapTrackers.length > 0 && relevantTopics.includes('tm_slap')) {
364
+ const taggedBEEFForSlap = {
365
+ beef: taggedBEEF.beef,
366
+ topics: ['tm_slap']
392
367
  }
393
- }
368
+ const facilitator = new HTTPSOverlayBroadcastFacilitator()
394
369
 
395
- try {
396
- await Promise.all(broadcastPromises)
397
- } catch (error) {
398
- console.error('Error during broadcasting:', error)
370
+ const sendPromises = this.slapTrackers.map(async tracker => {
371
+ try {
372
+ await facilitator.send(tracker, taggedBEEFForSlap)
373
+ } catch (error) {
374
+ this.logger.error(`Error sending to slapTracker ${tracker}:`, error)
375
+ }
376
+ })
377
+ await Promise.all(sendPromises)
399
378
  }
400
379
  }
401
- this.endTime(`transactionPropgation_${txid.substring(0, 10)}`)
380
+ this.endTime(`transactionPropagation_${txid.substring(0, 10)}`)
402
381
 
403
382
  // Immediately return from the function without waiting for the promises to resolve.
404
383
  return steak
405
384
  }
406
385
 
407
386
  /**
408
- * Submit a lookup question to the Overlay Services Engine, and receive bakc a Lookup Answer
387
+ * Submit a lookup question to the Overlay Services Engine, and receive back a Lookup Answer
409
388
  * @param LookupQuestion — The question to ask the Overlay Services Engine
410
389
  * @returns The answer to the question
411
390
  */
@@ -486,11 +465,8 @@ export class Engine {
486
465
  const requiredSHIPAdvertisements = new Set(configuredTopics)
487
466
  const requiredSLAPAdvertisements = new Set(configuredServices)
488
467
 
489
- const existingTopics = new Set(currentSHIPAdvertisements.map(ad => ad.topicOrService))
490
- const existingServices = new Set(currentSLAPAdvertisements.map(ad => ad.topicOrService))
491
-
492
- const shipsToCreate = Array.from(requiredSHIPAdvertisements).filter(topicOrService => !existingTopics.has(topicOrService))
493
- const slapsToCreate = Array.from(requiredSLAPAdvertisements).filter(topicOrService => !existingServices.has(topicOrService))
468
+ const shipsToCreate = Array.from(requiredSHIPAdvertisements).filter(topicOrService => !currentSHIPAdvertisements.some(x => x.topicOrService === topicOrService && x.domain === this.hostingURL))
469
+ const slapsToCreate = Array.from(requiredSLAPAdvertisements).filter(topicOrService => !currentSLAPAdvertisements.some(x => x.topicOrService === topicOrService && x.domain === this.hostingURL))
494
470
  const shipsToRevoke = currentSHIPAdvertisements.filter(ad => !requiredSHIPAdvertisements.has(ad.topicOrService))
495
471
  const slapsToRevoke = currentSLAPAdvertisements.filter(ad => !requiredSLAPAdvertisements.has(ad.topicOrService))
496
472
 
@@ -511,7 +487,7 @@ export class Engine {
511
487
  await this.submit(taggedBEEF)
512
488
  }
513
489
  } catch (error) {
514
- console.error('Failed to create SHIP advertisement:', error)
490
+ this.logger.error('Failed to create SHIP advertisement:', error)
515
491
  }
516
492
 
517
493
  // Revoke all advertisements to revoke
@@ -521,7 +497,7 @@ export class Engine {
521
497
  await this.submit(taggedBEEF)
522
498
  }
523
499
  } catch (error) {
524
- console.error('Failed to revoke SHIP/SLAP advertisements:', error)
500
+ this.logger.error('Failed to revoke SHIP/SLAP advertisements:', error)
525
501
  }
526
502
  }
527
503
 
@@ -568,7 +544,7 @@ export class Engine {
568
544
  endpointSet.add(advertisement.domain)
569
545
  }
570
546
  } catch (error) {
571
- console.error('Failed to parse advertisement output:', error)
547
+ this.logger.error('Failed to parse advertisement output:', error)
572
548
  }
573
549
  })
574
550
 
@@ -770,7 +746,7 @@ export class Engine {
770
746
  } catch (e) {
771
747
  // Handle any errors that occurred
772
748
  // Note: Test this!
773
- console.error(`Error retrieving UTXO history: ${e} `)
749
+ this.logger.error(`Error retrieving UTXO history: ${e} `)
774
750
  // return []
775
751
  throw new Error(`Error retrieving UTXO history: ${e} `)
776
752
  }
@@ -916,19 +892,51 @@ export class Engine {
916
892
  /**
917
893
  * Find a list of supported topic managers
918
894
  * @public
919
- * @returns {Promise<string[]>} - array of supported topic managers
895
+ * @returns {Promise<Record<string, { name: string; shortDescription: string; iconURL?: string; version?: string; informationURL?: string; }>>} - Supported topic managers and their metadata
920
896
  */
921
- async listTopicManagers(): Promise<string[]> {
922
- return Object.keys(this.managers)
897
+ async listTopicManagers(): Promise<Record<string, {
898
+ name: string;
899
+ shortDescription: string;
900
+ iconURL?: string;
901
+ version?: string;
902
+ informationURL?: string;
903
+ }>> {
904
+ let result: Record<string, {
905
+ name: string;
906
+ shortDescription: string;
907
+ iconURL?: string;
908
+ version?: string;
909
+ informationURL?: string;
910
+ }> = {}
911
+ for (let t in this.managers) {
912
+ result[t] = await this.managers[t].getMetaData()
913
+ }
914
+ return result
923
915
  }
924
916
 
925
917
  /**
926
918
  * Find a list of supported lookup services
927
919
  * @public
928
- * @returns {Promise<string[]>} - array of supported lookup services
920
+ * @returns {Promise<Record<string, { name: string; shortDescription: string; iconURL?: string; version?: string; informationURL?: string; }>>} - Supported lookup services and their metadata
929
921
  */
930
- async listLookupServiceProviders(): Promise<string[]> {
931
- return Object.keys(this.lookupServices)
922
+ async listLookupServices(): Promise<Record<string, {
923
+ name: string;
924
+ shortDescription: string;
925
+ iconURL?: string;
926
+ version?: string;
927
+ informationURL?: string;
928
+ }>> {
929
+ let result: Record<string, {
930
+ name: string;
931
+ shortDescription: string;
932
+ iconURL?: string;
933
+ version?: string;
934
+ informationURL?: string;
935
+ }> = {}
936
+ for (let t in this.lookupServices) {
937
+ result[t] = await this.lookupServices[t].getMetaData()
938
+ }
939
+ return result
932
940
  }
933
941
 
934
942
  /**
@@ -1005,18 +1013,3 @@ export class Engine {
1005
1013
  }
1006
1014
  }
1007
1015
  }
1008
-
1009
- //////////
1010
- // OTHER FILES
1011
- //////////
1012
-
1013
- /*
1014
- There is currently a bug with the test runner that prevents importing and using files that export variables other than type definitions within implementation files that are not directly imported themselves.
1015
- Thus, all non-type exports have been moved to Engine.
1016
- */
1017
-
1018
- // TODO: fix bug with imports that break tests. -----[GASP/OverlayGASPRemote.ts]-----
1019
-
1020
-
1021
-
1022
- // TODO: fix bug with imports that break tests. -----[GASP/OverlayGASPStorage.ts]-----
@@ -1,7 +1,5 @@
1
- import { LookupQuestion } from './LookupQuestion.js'
2
1
  import { LookupFormula } from './LookupFormula.js'
3
- import { LookupAnswer } from './LookupAnswer.js'
4
- import { Script } from '@bsv/sdk'
2
+ import { LookupQuestion, LookupAnswer, Script } from '@bsv/sdk'
5
3
 
6
4
  /**
7
5
  * Defines a Lookup Service interface to be implemented for specific use-cases
@@ -1,4 +1,4 @@
1
- import { AdmittanceInstructions } from './AdmittanceInstructions.js'
1
+ import { AdmittanceInstructions } from '@bsv/sdk'
2
2
 
3
3
  /**
4
4
  * Defines a Topic Manager interface that can be implemented for specific use-cases
@@ -2,12 +2,10 @@
2
2
  import { Engine } from '../../dist/cjs/src/Engine'
3
3
  import { LookupService } from '../LookupService'
4
4
  import { TopicManager } from '../TopicManager'
5
- import { AdmittanceInstructions } from '../AdmittanceInstructions'
6
5
  import { Storage } from '../storage/Storage'
7
- import { Transaction, Utils } from '@bsv/sdk'
6
+ import { Transaction, Utils, TaggedBEEF, AdmittanceInstructions } from '@bsv/sdk'
8
7
  import { Output } from '../Output'
9
8
  import { SyncConfiguration } from '../SyncConfiguration'
10
- import { TaggedBEEF } from '../TaggedBEEF.js'
11
9
  import { Advertiser } from '../Advertiser.js'
12
10
 
13
11
  const mockChainTracker = {
@@ -118,8 +116,6 @@ describe('BSV Overlay Services Engine', () => {
118
116
  // Verify that Advertiser methods are NOT called
119
117
  expect(mockAdvertiser.createAdvertisements).not.toHaveBeenCalled()
120
118
  expect(mockAdvertiser.findAllAdvertisements).not.toHaveBeenCalledWith('SHIP') // Assuming 'SHIP' is expected
121
-
122
- console.log('Got past', url)
123
119
  }
124
120
  })
125
121
 
@@ -1,14 +0,0 @@
1
- /**
2
- * Instructs the Overlay Services Engine about which outputs to admit and which previous outputs to retain. Returned by a Topic Manager.
3
- */
4
- export type AdmittanceInstructions = {
5
- /**
6
- * The indices of all admissable outputs into the managed topic from the provided transaction.
7
- */
8
- outputsToAdmit: number[]
9
-
10
- /**
11
- * The indices of all inputs from the provided transaction which spend previously-admitted outputs that should be retained for historical record-keeping.
12
- */
13
- coinsToRetain: number[]
14
- }
@@ -1,14 +0,0 @@
1
- /**
2
- * How the Overlay Services Engine responds to a Lookup Question.
3
- * It may comprise either an output list or a freeform response from the Lookup Service.
4
- */
5
- export type LookupAnswer = {
6
- type: 'output-list'
7
- outputs: Array<{
8
- beef: number[]
9
- outputIndex: number
10
- }>
11
- } | {
12
- type: 'freeform'
13
- result: unknown
14
- }
@@ -1,15 +0,0 @@
1
- /**
2
- * The question asked to the Overlay Services Engine when a consumer of state wishes to look up information.
3
- */
4
- export type LookupQuestion = {
5
- /**
6
- * The identifier for a Lookup Service which the person asking the question wishes to use.
7
- */
8
- service: string
9
-
10
- /**
11
- * The query which will be forwarded to the Lookup Service.
12
- * Its type depends on that prescribed by the Lookup Service employed.
13
- */
14
- query: unknown
15
- }
package/src/STEAK.ts DELETED
@@ -1,10 +0,0 @@
1
- import { AdmittanceInstructions } from './AdmittanceInstructions.js'
2
-
3
- /**
4
- * Submitted Transaction Execution AcKnowledgment
5
- *
6
- * @description
7
- * Comprises the topics where a transaction was submitted, and for each one, the output indices for the UTXOs newly admitted into the topics, and the coins retained.
8
- * An object whose keys are topic names and whose values are topical admittance instructions denoting the state of the submitted transaction with respect to the associated topic.
9
- */
10
- export type STEAK = Record<string, AdmittanceInstructions>
package/src/TaggedBEEF.ts DELETED
@@ -1,10 +0,0 @@
1
- /**
2
- * Tagged BEEF
3
- *
4
- * @description
5
- * Tagged BEEF ([Background Evaluation Extended Format](https://brc.dev/62)) structure. Comprises a transaction, its SPV information, and the overlay topics where its inclusion is requested.
6
- */
7
- export type TaggedBEEF = {
8
- beef: number[]
9
- topics: string[]
10
- }