@bsv/overlay 2.0.2 → 2.0.3

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/README.md CHANGED
@@ -23,243 +23,123 @@ The Overlay Services Engine enables dynamic tracking and management of UTXO-base
23
23
 
24
24
  ## Getting Started
25
25
 
26
+ ### Choose the Right Package
27
+
28
+ Most application developers should start with the higher-level deployment tools:
29
+
30
+ - [`@bsv/overlay-express`](https://github.com/bsv-blockchain/overlay-express): opinionated Express wrapper for running overlay nodes with HTTP routes, health checks, storage configuration, SHIP/SLAP discovery, and GASP synchronization.
31
+ - [`@bsv/lars`](https://github.com/bsv-blockchain/lars): local runtime for BSV application projects that use `deployment-info.json`.
32
+ - [`@bsv/cars-cli`](https://github.com/bsv-blockchain/cars-cli): cloud deployment workflow for the same `deployment-info.json` project structure.
33
+
34
+ Use this package, `@bsv/overlay`, when you need direct control over the Overlay Services Engine itself, such as custom storage, custom broadcasting, or a non-Express host.
35
+
26
36
  ### Installation
27
37
 
28
- You'll usually want to wrap the Engine within an HTTP server. To get set up with Express, create a new project and install everything you'll need:
38
+ For direct engine integration, install the engine with the current BSV TypeScript SDK:
29
39
 
30
40
  ```
31
- npm i express body-parser @bsv/sdk @bsv/overlay hello-services knex
41
+ npm i @bsv/overlay @bsv/sdk knex
32
42
  ```
33
43
 
34
44
  ### Basic Usage
35
45
 
36
- In your server's main file, you can set everything up. Create a new Engine to run the overlay services you want, then expose some routes over HTTP. For example:
37
-
38
- ```js
39
- const express = require('express')
40
- const bodyparser = require('body-parser')
41
- const { Engine, KnexStorage, HelloTopicManager, HelloLookupService, HelloStorageEngine } = require('@bsv/overlay')
42
- import { WhatsOnChain, NodejsHttpClient, ARC, ArcConfig, MerklePath } from '@bsv/sdk'
43
- // Populate a Knexfile with your database credentials
44
- const knex = require('knex')(require('../knexfile.js'))
45
- const app = express()
46
- app.use(bodyparser.json({ limit: '1gb', type: 'application/json' }))
47
-
48
- const engine = new Engine(
49
- {
50
- hello: new HelloTopicManager(),
51
- },
52
- {
53
- hello: new HelloLookupService({
54
- storageEngine: new HelloStorageEngine({
55
- knex
56
- })
57
- }),
58
- },
59
- new KnexStorageEngine({
60
- knex
61
- }),
62
- new CombinatorialChainTracker([
63
- new WhatsOnChain(
64
- NODE_ENV === 'production' ? 'main' : 'test',
65
- {
66
- httpClient: new NodejsHttpClient(https)
67
- })
68
- ]),
69
- HOSTING_DOMAIN as string,
70
- SHIP_TRACKERS,
71
- SLAP_TRACKERS,
72
- new ARC('https://arc.taal.com', arcConfig)
73
- )
74
-
75
- // This allows the API to be used everywhere when CORS is enforced
76
- app.use((req, res, next) => {
77
- res.header('Access-Control-Allow-Origin', '*')
78
- res.header('Access-Control-Allow-Headers', '*')
79
- res.header('Access-Control-Allow-Methods', '*')
80
- res.header('Access-Control-Expose-Headers', '*')
81
- res.header('Access-Control-Allow-Private-Network', 'true')
82
- if (req.method === 'OPTIONS') {
83
- res.sendStatus(200)
84
- } else {
85
- next()
86
- }
87
- })
88
-
89
- // Serve a static documentstion site, if you have one.
90
- app.use(express.static('public'))
91
-
92
- // List hosted topic managers and lookup services
93
- app.get(`/listTopicManagers`, async (req, res) => {
94
- try {
95
- const result = await engine.listTopicManagers()
96
- return res.status(200).json(result)
97
- } catch (error) {
98
- return res.status(400).json({
99
- status: 'error',
100
- code: error.code,
101
- description: error.message
102
- })
103
- }
104
- })
105
- app.get(`/listLookupServiceProviders`, async (req, res) => {
106
- try {
107
- const result = await engine.listLookupServiceProviders()
108
- return res.status(200).json(result)
109
- } catch (error) {
110
- return res.status(400).json({
111
- status: 'error',
112
- code: error.code,
113
- description: error.message
114
- })
115
- }
116
- })
117
-
118
- // Host documentation for the services
119
- app.get(`/getDocumentationForTopicManager`, async (req, res) => {
120
- try {
121
- const result = await engine.getDocumentationForTopicManger(req.query.manager)
122
- return res.status(200).json(result)
123
- } catch (error) {
124
- return res.status(400).json({
125
- status: 'error',
126
- code: error.code,
127
- description: error.message
128
- })
129
- }
130
- })
131
- app.get(`/getDocumentationForLookupServiceProvider`, async (req, res) => {
132
- try {
133
- const result = await engine.getDocumentationForLookupServiceProvider(req.query.lookupServices)
134
- return res.status(200).json(result)
135
- } catch (error) {
136
- return res.status(400).json({
137
- status: 'error',
138
- code: error.code,
139
- description: error.message
140
- })
141
- }
142
- })
143
-
144
- // Submit transactions and facilitate lookup requests
145
- app.post(`/submit`, async (req, res) => {
146
- try {
147
- // Parse out the topics and construct the tagged BEEF
148
- const topics = JSON.parse(req.headers['x-topics'] as string)
149
- const taggedBEEF: TaggedBEEF = {
150
- beef: Array.from(req.body as number[]),
151
- topics
46
+ Create an `Engine` with topic managers, lookup services, a storage implementation, and a chain tracker. The example below uses minimal in-memory stubs so the shape is clear. Production services should use durable storage, a real chain tracker, and a broadcaster appropriate for the target network.
47
+
48
+ ```ts
49
+ import {
50
+ Engine,
51
+ type AdmittanceInstructions,
52
+ type LookupFormula,
53
+ type LookupQuestion,
54
+ type Output,
55
+ type Storage,
56
+ type TopicManager,
57
+ type LookupService
58
+ } from '@bsv/overlay'
59
+
60
+ const topicManager: TopicManager = {
61
+ async identifyAdmissibleOutputs (): Promise<AdmittanceInstructions> {
62
+ return {
63
+ outputsToAdmit: [],
64
+ coinsToRetain: []
152
65
  }
153
-
154
- // Using a callback function, we can just return once our steak is ready
155
- // instead of having to wait for all the broadcasts to occur.
156
- await engine.submit(taggedBEEF, (steak: STEAK) => {
157
- return res.status(200).json(steak)
158
- })
159
- } catch (error) {
160
- return res.status(400).json({
161
- status: 'error',
162
- code: error.code,
163
- description: error.message
164
- })
165
- }
166
- })
167
- app.post(`/lookup`, async (req, res) => {
168
- try {
169
- const result = await engine.lookup(req.body)
170
- return res.status(200).json(result)
171
- } catch (error) {
172
- return res.status(400).json({
173
- status: 'error',
174
- code: error.code,
175
- description: error.message
176
- })
177
- }
178
- })
179
-
180
- app.post('/arc-ingest', (req, res) => {
181
- (async () => {
182
- try {
183
- const merklePath = MerklePath.fromHex(req.body.merklePath)
184
- await engine.handleNewMerkleProof(req.body.txid, merklePath, req.body.blockHeight)
185
- return res.status(200).json({ status: 'success', message: 'transaction status updated' })
186
- } catch (error) {
187
- console.error(error)
188
- return res.status(400).json({
189
- status: 'error',
190
- message: error instanceof Error ? error.message : 'An unknown error occurred'
191
- })
66
+ },
67
+ async getDocumentation () {
68
+ return 'Admits outputs for the example topic.'
69
+ },
70
+ async getMetaData () {
71
+ return {
72
+ name: 'Example Topic Manager',
73
+ shortDescription: 'Example topic manager',
74
+ iconURL: '',
75
+ version: '1.0.0',
76
+ informationURL: ''
192
77
  }
193
- })().catch(() => {
194
- res.status(500).json({
195
- status: 'error',
196
- message: 'Unexpected error'
197
- })
198
- })
199
- })
200
-
201
- app.post('/requestSyncResponse', (req, res) => {
202
- (async () => {
203
- try {
204
- const topic = req.headers['x-bsv-topic'] as string
205
- const response = await engine.provideForeignSyncResponse(req.body, topic)
206
- return res.status(200).json(response)
207
- } catch (error) {
208
- console.error(error)
209
- return res.status(400).json({
210
- status: 'error',
211
- message: error instanceof Error ? error.message : 'An unknown error occurred'
212
- })
78
+ }
79
+ }
80
+
81
+ const lookupService: LookupService = {
82
+ async outputAdmittedByTopic (): Promise<void> {},
83
+ async outputSpent (): Promise<void> {},
84
+ async outputEvicted (): Promise<void> {},
85
+ async lookup (_question: LookupQuestion): Promise<LookupFormula> {
86
+ return {
87
+ type: 'formula',
88
+ outpoints: []
213
89
  }
214
- })().catch(() => {
215
- res.status(500).json({
216
- status: 'error',
217
- message: 'Unexpected error'
218
- })
219
- })
220
- })
221
-
222
- app.post('/requestForeignGASPNode', (req, res) => {
223
- (async () => {
224
- try {
225
- console.log(req.body)
226
- const { graphID, txid, outputIndex, metadata } = req.body
227
- const response = await engine.provideForeignGASPNode(graphID, txid, outputIndex)
228
- return res.status(200).json(response)
229
- } catch (error) {
230
- console.error(error)
231
- return res.status(400).json({
232
- status: 'error',
233
- message: error instanceof Error ? error.message : 'An unknown error occurred'
234
- })
90
+ },
91
+ async getDocumentation () {
92
+ return 'Looks up outputs admitted by the example topic.'
93
+ },
94
+ async getMetaData () {
95
+ return {
96
+ name: 'Example Lookup Service',
97
+ shortDescription: 'Example lookup service',
98
+ iconURL: '',
99
+ version: '1.0.0',
100
+ informationURL: ''
235
101
  }
236
- })().catch(() => {
237
- res.status(500).json({
238
- status: 'error',
239
- message: 'Unexpected error'
240
- })
241
- })
242
- })
243
-
244
- // 404, all other routes are not found.
245
- app.use((req, res) => {
246
- console.log('404', req.url)
247
- res.status(404).json({
248
- status: 'error',
249
- code: 'ERR_ROUTE_NOT_FOUND',
250
- description: 'Route not found.'
251
- })
252
- })
253
-
254
- // Start your Engines!
255
- app.listen(8080, () => {
256
- console.log('BSV Overlay Services Engine is listening on port', 8080)
257
- })
102
+ }
103
+ }
104
+
105
+ const storage: Storage = {
106
+ async findOutput (): Promise<Output | null> { return null },
107
+ async findOutputsForTransaction (): Promise<Output[]> { return [] },
108
+ async findOutputsForTopic (): Promise<Output[]> { return [] },
109
+ async findUTXOHistory (): Promise<Output[]> { return [] },
110
+ async insertOutput (): Promise<void> {},
111
+ async updateConsumedBy (): Promise<void> {},
112
+ async updateTransactionBEEF (): Promise<void> {},
113
+ async deleteOutput (): Promise<void> {},
114
+ async startGASPSync (): Promise<void> {},
115
+ async updateLastInteraction (): Promise<void> {},
116
+ async getLastInteraction (): Promise<Date | null> { return null },
117
+ async getSyncState (): Promise<unknown> { return undefined },
118
+ async setSyncState (): Promise<void> {}
119
+ }
120
+
121
+ const engine = new Engine(
122
+ { tm_example: topicManager },
123
+ { ls_example: lookupService },
124
+ storage,
125
+ 'scripts only',
126
+ 'https://example-overlay.example',
127
+ [],
128
+ [],
129
+ undefined,
130
+ undefined,
131
+ { tm_example: false }
132
+ )
133
+
134
+ const topics = await engine.listTopicManagers()
135
+ const services = await engine.listLookupServiceProviders()
258
136
  ```
259
137
 
260
- For more detailed tutorials and examples, check out the [full documentation](#documentation).
138
+ For deployable HTTP examples, use [`@bsv/overlay-express`](https://github.com/bsv-blockchain/overlay-express) and [`overlay-express-examples`](https://github.com/bsv-blockchain/overlay-express-examples). For local and cloud application runtime workflows, use LARS and CARS with the BRC-102 `deployment-info.json` project structure.
139
+
140
+ For lower-level engine examples, check out the [full documentation](#documentation).
261
141
 
262
- The Overlay Services Engine is also richly documented with code-level annotations. This should show up well within editors like VSCode.
142
+ The Overlay Services Engine is also richly documented with code-level annotations. This should show up well within editors like VSCode.
263
143
 
264
144
  <!-- ## Documentation
265
145
 
@@ -271,10 +151,10 @@ The Overlay Services Engine is also richly documented with code-level annotation
271
151
  - History management and state tracking
272
152
  - Lookup Services
273
153
  - Storage engine abstractions
274
- - [WIP] Examples, HTTP wrapper and Docs
275
- - [WIP] Arc Proof Acquisition
276
- - [WIP] Distributed Overlay Availability Advertisements
277
- - [WIP] Federated Transaction Synchronization
154
+ - Examples, HTTP wrapper, and docs through `@bsv/overlay-express`
155
+ - ARC callback handling through overlay hosts
156
+ - Distributed overlay availability advertisements with SHIP and SLAP
157
+ - Federated transaction synchronization with GASP
278
158
 
279
159
  ## Contribution Guidelines
280
160
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/overlay",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
4
  "type": "commonjs",
5
5
  "description": "BSV Blockchain Overlay Services Engine",
6
6
  "files": [
@@ -49,7 +49,7 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "@bsv/gasp": "^1.2.2",
52
- "@bsv/sdk": "^2.0.4",
52
+ "@bsv/sdk": "^2.0.14",
53
53
  "knex": "^3.1.0"
54
54
  }
55
55
  }