@bsv/overlay 0.6.0 → 0.6.1
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/cjs/package.json +3 -3
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/docs/API.md +13 -500
- package/docs/README.md +9 -3
- package/docs/Synchronization.md +203 -0
- package/docs/concepts/00-overview.md +85 -0
- package/docs/concepts/01-best-practices.md +202 -0
- package/docs/concepts/02-query-performance.md +345 -0
- package/docs/concepts/03-database-monitoring.md +211 -0
- package/docs/concepts/04-pagination-example.md +186 -0
- package/docs/concepts/05-recommendations-summary.md +158 -0
- package/docs/concepts/README.md +16 -0
- package/docs/examples/README.md +11 -1
- package/docs/examples/gs-wip.md +7 -1
- package/docs/internal/README.md +8 -1
- package/package.json +3 -3
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
## About
|
|
2
|
+
|
|
3
|
+
**GASP (Graph Aware Sync Protocol)** is the synchronization protocol overlay nodes use to replicate overlay-relevant transaction data between peers in a way that is **verifiable**, **complete**, and **bandwidth-efficient**. Instead of just sending raw TXIDs or copying a flat UTXO list, GASP reconciles **transaction graphs** by exchanging transactions/outputs with proof material and then **recursively requesting any missing input transactions** needed to validate what was received.
|
|
4
|
+
|
|
5
|
+
At a high level, GASP is built around:
|
|
6
|
+
|
|
7
|
+
- **Legitimacy:** Nodes only finalize data they can validate by anchoring it back to the blockchain (e.g., using merkle proofs / SPV-style verification).
|
|
8
|
+
- **Completeness:** If a transaction depends on other transactions, the protocol recursively fetches all required inputs so the end result isn’t partial or broken.
|
|
9
|
+
- **Efficiency:** Nodes only sync what they don’t have, reducing duplicates and bandwidth.
|
|
10
|
+
- **Redundancy / availability:** Multiple nodes can converge on the same overlay view over time, improving uptime and reducing single-host dependency.
|
|
11
|
+
|
|
12
|
+
## Importance
|
|
13
|
+
|
|
14
|
+
Overlays are useful because they let you track only the topic you care about. But once an overlay is distributed (multiple nodes serving the same topic), nodes need a path to **catch up** and **stay consistent** over time.
|
|
15
|
+
|
|
16
|
+
GASP matters because it gives you:
|
|
17
|
+
|
|
18
|
+
- **Redundancy and uptime:** If one overlay host goes offline, other synced hosts can still serve the same topic, reducing single points of failure.
|
|
19
|
+
- **Fast bootstrap:** A fresh node can synchronize overlay state from peers instead of re-ingesting all previous transactions from scratch.
|
|
20
|
+
- **Lower-trust sync (for correctness):** Peers exchange transactions with proofs and recursively prove inputs, so received data can be validated instead of trusted blindly. *(This doesn’t replace your auth policy; it reduces trust needed for correctness.)*
|
|
21
|
+
- **Scaling the ecosystem:** As more apps and topics exist, GASP enables horizontal growth (more hosts for the same topic) instead of centralizing into one massive indexer.
|
|
22
|
+
|
|
23
|
+
## How GASP Works
|
|
24
|
+
|
|
25
|
+
One party initiates sync by summarizing what it currently has, then the peer responds with what’s missing, and both sides iterate until they converge.
|
|
26
|
+
|
|
27
|
+
A typical flow looks like:
|
|
28
|
+
|
|
29
|
+
1) **Summarize local state**
|
|
30
|
+
The initiator summarizes known spendable outpoints (commonly via a Bloom filter over TXID+VOUT).
|
|
31
|
+
|
|
32
|
+
2) **Responder sends “missing” inventory**
|
|
33
|
+
The responder identifies items the initiator likely doesn’t have and returns inventory entries containing the output/transaction plus proof material (and optional metadata).
|
|
34
|
+
|
|
35
|
+
3) **Recursive completion**
|
|
36
|
+
If the initiator is missing any input transactions required to validate what it received, it requests them. This repeats recursively until the needed graph is complete.
|
|
37
|
+
|
|
38
|
+
4) **Verification + finalize**
|
|
39
|
+
Anything that can’t be validated/anchored is ignored rather than partially imported.
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
There are two main ways to activate and run GASP sync:
|
|
44
|
+
|
|
45
|
+
- **With CARS (cloud / managed):** Use CARS menus to enable sync options and deploy.
|
|
46
|
+
- **Without CARS (direct / self-managed):** Run your own Overlay Express server and trigger sync using the admin endpoints.
|
|
47
|
+
|
|
48
|
+
> **Important:** For GASP sync to work, *both* parties must have GASP enabled and must be configured to sync the same topic(s).
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
### With CARS
|
|
53
|
+
|
|
54
|
+
> If your project has a package.json script called `cars`, you can use `npm run cars`. Otherwise you typically run `cars` directly.
|
|
55
|
+
|
|
56
|
+
### Using CARS (high level)
|
|
57
|
+
|
|
58
|
+
- `npm run cars` *(or `cars`)*
|
|
59
|
+
- Manage Projects
|
|
60
|
+
- Edit Advanced Engine Config
|
|
61
|
+
- Choose correct CARS config
|
|
62
|
+
- Toggle `gaspSync`
|
|
63
|
+
- Edit `syncConfiguration`
|
|
64
|
+
- Add your topic manager name(s) (e.g. `tm_example`)
|
|
65
|
+
- Back → Done
|
|
66
|
+
- Back to main menu
|
|
67
|
+
- Build Artifact → Auto-create new release and upload latest artifact now
|
|
68
|
+
|
|
69
|
+
### Side notes
|
|
70
|
+
|
|
71
|
+
- Simply toggling `gaspSync` is not enough if your node is not “interested” in syncing your topic.
|
|
72
|
+
You must also ensure your topic manager name is included in `syncConfiguration` so the engine knows which topic(s) to sync.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### Without CARS
|
|
77
|
+
|
|
78
|
+
Without CARS, you run your own Overlay Express server and configure the overlay engine so it:
|
|
79
|
+
1) **discovers peers / publishes ads** (via an advertiser), and
|
|
80
|
+
2) knows **which topic managers to sync** (via `syncConfiguration`), and
|
|
81
|
+
3) has **GASP enabled**.
|
|
82
|
+
|
|
83
|
+
## Minimal engine config you must have
|
|
84
|
+
|
|
85
|
+
The most important lines are:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
server.configureEngineParams({
|
|
89
|
+
advertiser: wa,
|
|
90
|
+
syncConfiguration: {
|
|
91
|
+
'tm_plite': 'SHIP',
|
|
92
|
+
'tm_blockbeta': 'SHIP',
|
|
93
|
+
},
|
|
94
|
+
logTime: false,
|
|
95
|
+
logPrefix: '[OVERLAY] ',
|
|
96
|
+
throwOnBroadcastFailure: false,
|
|
97
|
+
suppressDefaultSyncAdvertisements: true,
|
|
98
|
+
})
|
|
99
|
+
// ^ tells the engine which topic(s) you want to sync, and the discovery mechanism to use (e.g. SHIP)
|
|
100
|
+
|
|
101
|
+
server.configureEnableGASPSync(true)
|
|
102
|
+
// ^ enables GASP sync in Overlay Express
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## **Overlay Express Setup Example**
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import { WalletAdvertiser } from '@bsv/overlay-discovery-services'
|
|
109
|
+
import OverlayExpress from '@bsv/overlay-express'
|
|
110
|
+
import { config } from 'dotenv'
|
|
111
|
+
import packageJson from '../package.json'
|
|
112
|
+
import PollrTopicManager from './services/pollroverlay/PollrTopicManager'
|
|
113
|
+
import PollrLookupServiceFactory from './services/pollroverlay/PollrLookupServiceFactory'
|
|
114
|
+
import ForumTopicManager from './services/blockitoverlay/ForumTopicManager'
|
|
115
|
+
import ForumLookupService from './services/blockitoverlay/ForumLookupServiceFactory'
|
|
116
|
+
|
|
117
|
+
config()
|
|
118
|
+
|
|
119
|
+
const main = async () => {
|
|
120
|
+
const server = new OverlayExpress(
|
|
121
|
+
process.env.NODE_NAME!,
|
|
122
|
+
process.env.SERVER_PRIVATE_KEY!,
|
|
123
|
+
process.env.HOSTING_URL!,
|
|
124
|
+
process.env.ADMIN_TOKEN! // your chosen admin token to use the admin API
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
const wa = new WalletAdvertiser(
|
|
128
|
+
process.env.NETWORK! as 'main' | 'test',
|
|
129
|
+
process.env.SERVER_PRIVATE_KEY!,
|
|
130
|
+
process.env.WALLET_STORAGE_URL!,
|
|
131
|
+
process.env.HOSTING_URL!
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
await wa.init()
|
|
135
|
+
|
|
136
|
+
server.configureEngineParams({
|
|
137
|
+
advertiser: wa,
|
|
138
|
+
syncConfiguration: {
|
|
139
|
+
'tm_plite': 'SHIP',
|
|
140
|
+
'tm_blockbeta': 'SHIP',
|
|
141
|
+
},
|
|
142
|
+
logTime: false,
|
|
143
|
+
logPrefix: '[OVERLAY] ',
|
|
144
|
+
throwOnBroadcastFailure: false,
|
|
145
|
+
suppressDefaultSyncAdvertisements: true,
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
server.configureArcApiKey(process.env.ARC_API_KEY!)
|
|
149
|
+
server.configurePort(8080)
|
|
150
|
+
|
|
151
|
+
await server.configureKnex(process.env.KNEX_URL!)
|
|
152
|
+
await server.configureMongo(process.env.MONGO_URL!)
|
|
153
|
+
|
|
154
|
+
server.configureTopicManager('tm_plite', new PollrTopicManager())
|
|
155
|
+
server.configureLookupServiceWithMongo('ls_plite', PollrLookupServiceFactory)
|
|
156
|
+
|
|
157
|
+
server.configureTopicManager('tm_blockbeta', new ForumTopicManager())
|
|
158
|
+
server.configureLookupServiceWithMongo('ls_blockbeta', ForumLookupService)
|
|
159
|
+
|
|
160
|
+
server.configureEnableGASPSync(true)
|
|
161
|
+
|
|
162
|
+
await server.configureEngine()
|
|
163
|
+
|
|
164
|
+
server.app.get('/version', (req, res) => res.json(packageJson))
|
|
165
|
+
|
|
166
|
+
await server.start()
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
main()
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
# **Validation**
|
|
173
|
+
|
|
174
|
+
A practical way to validate sync is to compare per-topic records in your SQL database before and after sync.
|
|
175
|
+
|
|
176
|
+
Example (adapt the table/query to your schema):
|
|
177
|
+
### **Before sync**
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
+-------------+----+
|
|
181
|
+
| topic | n |
|
|
182
|
+
+-------------+----+
|
|
183
|
+
| tm_plite | 2 |
|
|
184
|
+
| tm_blockbeta| 1 |
|
|
185
|
+
| tm_ship | 2 |
|
|
186
|
+
| tm_slap | 2 |
|
|
187
|
+
+-------------+----+
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### **After sync**
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
+-------------+------+
|
|
194
|
+
| topic | n |
|
|
195
|
+
+-------------+------+
|
|
196
|
+
| tm_plite | 10 |
|
|
197
|
+
| tm_blockbeta| 17 |
|
|
198
|
+
| tm_ship | 2177 |
|
|
199
|
+
| tm_slap | 2 |
|
|
200
|
+
+-------------+------+
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**What you’re looking for:** the topic(s) you care about (e.g. tm_plite, tm_blockbeta) should move toward the same counts/data across nodes after sync, and your lookup results for identical queries should converge as well.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Overlay Use and Optimization in the BSV Ecosystem
|
|
2
|
+
|
|
3
|
+
[🏠 Home](../README.md) | [📚 API](../API.md) | [💡 Concepts](./README.md) | [📖 Examples](../examples/README.md) | [⚙️ Internal](../internal/README.md)
|
|
4
|
+
|
|
5
|
+
**Navigation:** [Overview](./00-overview.md) | [Best Practices](./01-best-practices.md) | [Query Performance](./02-query-performance.md) | [Database Monitoring](./03-database-monitoring.md) | [Pagination Example](./04-pagination-example.md) | [Recommendations Summary](./05-recommendations-summary.md)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Introduction
|
|
10
|
+
|
|
11
|
+
Overlays are distributed application layers built on top of Bitcoin SV (BSV). They allow applications to publish structured data and then query it efficiently through **Lookup Services** and **Topic Managers**. This pattern enables developers to build scalable, high‑performance, privacy‑aware applications without needing to index or scan the entire blockchain themselves.
|
|
12
|
+
|
|
13
|
+
Applications such as **Convo Messenger**, **Tempo**, and **MetaMarket** use overlays to organize messages, content references, metadata, and other application‑specific data in a predictable and queryable way.
|
|
14
|
+
|
|
15
|
+
This documentation is written for **developers who want to build overlays for their own applications**. It explains how overlays work, what must be stored, how to structure queries, and how to keep overlay implementations efficient and maintainable.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Purpose of This Documentation
|
|
20
|
+
|
|
21
|
+
Developers implementing overlays commonly need guidance on:
|
|
22
|
+
|
|
23
|
+
* What data a Lookup Service should store
|
|
24
|
+
* How to design efficient queries for retrieving overlay data
|
|
25
|
+
* How to index and structure Lookup Service databases
|
|
26
|
+
* How to keep overlays healthy and performant as they scale
|
|
27
|
+
|
|
28
|
+
This documentation focuses on **practical guidance** that helps developers design overlays correctly and avoid common pitfalls. Examples from real applications—such as Convo Messenger—are used when relevant.
|
|
29
|
+
|
|
30
|
+
This documentation does **not** cover internal BSVA system design, Overlay Express internals, or future platform development proposals.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## What This Series Covers
|
|
35
|
+
|
|
36
|
+
Each document in this series focuses on a key aspect of overlay implementation.
|
|
37
|
+
|
|
38
|
+
### 1. Best Practices for Overlay Design
|
|
39
|
+
|
|
40
|
+
* What Lookup Services are required to store
|
|
41
|
+
* What additional metadata overlays often include
|
|
42
|
+
* What kinds of data should *not* be stored (e.g., large payloads)
|
|
43
|
+
* How to use UHRP references for external content
|
|
44
|
+
|
|
45
|
+
### 2. Query Optimization and Performance
|
|
46
|
+
|
|
47
|
+
* How to design efficient queries
|
|
48
|
+
* How to choose indexes for common access patterns
|
|
49
|
+
* How to avoid unbounded or slow query patterns
|
|
50
|
+
|
|
51
|
+
### 3. Monitoring and Debugging Overlays
|
|
52
|
+
|
|
53
|
+
* How to monitor your own overlay deployment
|
|
54
|
+
* How to inspect stored data safely
|
|
55
|
+
* How to track ingestion issues from your Topic Manager
|
|
56
|
+
|
|
57
|
+
### 4. Pagination and Practical Examples
|
|
58
|
+
|
|
59
|
+
* Why pagination is critical for performance
|
|
60
|
+
* How to implement pagination in Lookup Services and clients
|
|
61
|
+
* Examples drawn from live overlay behavior (e.g., Convo Messenger)
|
|
62
|
+
|
|
63
|
+
### 5. Summary of Recommendations
|
|
64
|
+
|
|
65
|
+
* A concise reference of best practices
|
|
66
|
+
* Quick reminders for developers building overlays
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Deliverables
|
|
71
|
+
|
|
72
|
+
This documentation includes:
|
|
73
|
+
|
|
74
|
+
* **Markdown files** that explain how to build, index, and monitor overlay implementations
|
|
75
|
+
* **Examples** demonstrating common patterns such as pagination and indexed lookup queries
|
|
76
|
+
* **Guidelines** that help ensure overlays remain scalable and consistent across different applications
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Next Steps
|
|
81
|
+
|
|
82
|
+
1. Read the general best practices for overlay storage (`01-best-practices.md`).
|
|
83
|
+
2. Review query performance and indexing fundamentals (`02-query-performance.md`).
|
|
84
|
+
3. Explore examples using Convo Messenger (`04-pagination-example.md`).
|
|
85
|
+
4. Refer to the summary document for quick reminders or cross-references.
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# Overlay Best Practices for Developers
|
|
2
|
+
|
|
3
|
+
[🏠 Home](../README.md) | [📚 API](../API.md) | [💡 Concepts](./README.md) | [📖 Examples](../examples/README.md) | [⚙️ Internal](../internal/README.md)
|
|
4
|
+
|
|
5
|
+
**Navigation:** [Overview](./00-overview.md) | [Best Practices](./01-best-practices.md) | [Query Performance](./02-query-performance.md) | [Database Monitoring](./03-database-monitoring.md) | [Pagination Example](./04-pagination-example.md) | [Recommendations Summary](./05-recommendations-summary.md)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
This document provides **best practices for designing and maintaining overlay services** in the BSV ecosystem. It focuses on the practical concerns of developers who are building their **own overlays**—not on BSVA internals or modifications to Overlay Express.
|
|
12
|
+
|
|
13
|
+
The goal is to help developers make consistent and scalable decisions when implementing **Topic Managers**, **Lookup Services**, and associated **MongoDB storage layers**. Examples reference **Convo Messenger**, but the principles apply to all overlay-based systems.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 1. Data Storage Principles
|
|
18
|
+
|
|
19
|
+
Overlay Lookup Services should store **small, structured metadata**, not entire payloads. The goal is fast, predictable querying.
|
|
20
|
+
|
|
21
|
+
### 1.1 Required Fields for Any Overlay
|
|
22
|
+
|
|
23
|
+
Every Lookup Service must store enough information to uniquely reference an on-chain output. This includes:
|
|
24
|
+
|
|
25
|
+
* **`txid`** — transaction ID containing the output
|
|
26
|
+
* **`outputIndex`** — index of the admitted output
|
|
27
|
+
* **`protocol`** — identifies which overlay protocol this entry belongs to
|
|
28
|
+
|
|
29
|
+
These fields ensure that applications can always locate the exact on-chain output referenced by the overlay.
|
|
30
|
+
|
|
31
|
+
### 1.2 Common Metadata Fields
|
|
32
|
+
|
|
33
|
+
In addition to required fields, overlays typically store small metadata extracted from PushDrop fields or derived from application logic.
|
|
34
|
+
|
|
35
|
+
Examples:
|
|
36
|
+
|
|
37
|
+
* **`timestamp` / `createdAt`** — when the message or record was created
|
|
38
|
+
* **`sender`** — sender's pubkey or DID
|
|
39
|
+
* **`threadId`** — group/thread identifier
|
|
40
|
+
* **`parentMessageId`** (optional) — for reply messages
|
|
41
|
+
* **reaction fields** (when applicable)
|
|
42
|
+
|
|
43
|
+
Example (Convo Messenger):
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
{
|
|
47
|
+
txid: "abc123...",
|
|
48
|
+
outputIndex: 0,
|
|
49
|
+
protocol: [2, "convo"],
|
|
50
|
+
threadId: "thread-xyz",
|
|
51
|
+
sender: "035a1b...",
|
|
52
|
+
createdAt: 1730000000000,
|
|
53
|
+
encryptedPayload: [...], // ciphertext array
|
|
54
|
+
header: [...], // CurvePoint header
|
|
55
|
+
uniqueId: "optional-value",
|
|
56
|
+
parentMessageId: "optional-parent-txid"
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Note:** Convo stores *encryptedPayload* and *header* because these remain small arrays needed by the client. Overlays must avoid storing anything large (e.g., full media files).
|
|
61
|
+
|
|
62
|
+
### 1.3 When to Use UHRP
|
|
63
|
+
|
|
64
|
+
If an overlay needs to handle large data (text bodies, images, files), Lookup Services should **only store a UHRP reference**:
|
|
65
|
+
|
|
66
|
+
* Never store full file contents
|
|
67
|
+
* Never store large plaintext or ciphertext blobs
|
|
68
|
+
* Let the client fetch large data from UHRP when needed
|
|
69
|
+
|
|
70
|
+
Lookup Services should remain lightweight.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 2. What Lookup Services Should *Not* Store
|
|
75
|
+
|
|
76
|
+
To maintain performance and predictable scaling, Lookup Services must avoid:
|
|
77
|
+
|
|
78
|
+
* Full PushDrop payloads or full scripts
|
|
79
|
+
* Large encrypted or plaintext message bodies
|
|
80
|
+
* Media files or binary attachments
|
|
81
|
+
* Identity certificates
|
|
82
|
+
* Redundant or duplicate on-chain data
|
|
83
|
+
|
|
84
|
+
**Rule of thumb:**
|
|
85
|
+
If it cannot be indexed efficiently, it does not belong in the Lookup DB.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 3. Structuring Lookup Queries
|
|
90
|
+
|
|
91
|
+
### 3.1 Use Indexed, Selective Fields
|
|
92
|
+
|
|
93
|
+
All queries should filter using indexed, selective fields such as:
|
|
94
|
+
|
|
95
|
+
* `threadId`
|
|
96
|
+
* `sender`
|
|
97
|
+
* `parentMessageId`
|
|
98
|
+
* `createdAt`
|
|
99
|
+
|
|
100
|
+
Examples from Convo’s actual Mongo indexes:
|
|
101
|
+
|
|
102
|
+
```js
|
|
103
|
+
db.convoMessages.createIndex({ threadId: 1 })
|
|
104
|
+
db.convoMessages.createIndex({ parentMessageId: 1 })
|
|
105
|
+
db.convoMessages.createIndex({ threadId: 1, createdAt: -1 })
|
|
106
|
+
db.convoReactions.createIndex({ threadId: 1 })
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 3.2 Use Pagination Everywhere
|
|
110
|
+
|
|
111
|
+
List endpoints must support:
|
|
112
|
+
|
|
113
|
+
* **`skip`** — starting offset
|
|
114
|
+
* **`limit`** — number of items
|
|
115
|
+
|
|
116
|
+
Typical defaults:
|
|
117
|
+
|
|
118
|
+
* `limit = 50`
|
|
119
|
+
* `skip = 0`
|
|
120
|
+
|
|
121
|
+
Example (Convo):
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
const messages = await this.storage.listThreadMessages(threadId, skip, limit)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 3.3 Avoid Expensive Query Patterns
|
|
128
|
+
|
|
129
|
+
Do **not**:
|
|
130
|
+
|
|
131
|
+
* Perform unbounded collection scans
|
|
132
|
+
* Query across all protocols
|
|
133
|
+
* Sort without an index
|
|
134
|
+
* Use `$regex` or `$text` filters
|
|
135
|
+
|
|
136
|
+
If complex queries are needed, break them into:
|
|
137
|
+
|
|
138
|
+
* Indexed filters
|
|
139
|
+
* Bounded pagination
|
|
140
|
+
* Incremental lookups
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 4. Topic Manager Best Practices
|
|
145
|
+
|
|
146
|
+
Topic Managers determine which outputs belong to your overlay. They must validate and parse data correctly.
|
|
147
|
+
|
|
148
|
+
Best practices:
|
|
149
|
+
|
|
150
|
+
1. **Validate admissible outputs** using PushDrop decoding.
|
|
151
|
+
2. **Store only necessary fields** extracted from PushDrop.
|
|
152
|
+
3. **Reject malformed or irrelevant outputs** early.
|
|
153
|
+
4. **Handle duplicate admissions** cleanly.
|
|
154
|
+
5. **Avoid heavy computation** inside the Topic Manager.
|
|
155
|
+
|
|
156
|
+
Example (Convo):
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
const decoded = PushDrop.decode(output.lockingScript)
|
|
160
|
+
const marker = Utils.toUTF8(fields[0])
|
|
161
|
+
const protocol = Utils.toUTF8(fields[1])
|
|
162
|
+
|
|
163
|
+
if (marker === 'convo' && protocol === 'tmconvo') {
|
|
164
|
+
admissibleOutputs.push(index)
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 5. Data Retention and Cleanup
|
|
171
|
+
|
|
172
|
+
Overlays accumulate data continuously. Without retention logic, performance may degrade.
|
|
173
|
+
|
|
174
|
+
Common retention approaches:
|
|
175
|
+
|
|
176
|
+
* Delete old entries if your application doesn’t need them
|
|
177
|
+
* Archive long-lived data to another collection
|
|
178
|
+
* Rebuild indexes periodically
|
|
179
|
+
* Limit history for ephemeral overlays
|
|
180
|
+
|
|
181
|
+
Retention periods depend on the app:
|
|
182
|
+
|
|
183
|
+
* **Convo Messenger:** often stores all messages indefinitely
|
|
184
|
+
* **Task-based overlays:** may delete resolved items after 30–90 days
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## 6. Summary of Recommendations
|
|
189
|
+
|
|
190
|
+
| Area | Recommendation |
|
|
191
|
+
| --------------- | ---------------------------------------------------------------- |
|
|
192
|
+
| Required Fields | Always store `txid`, `outputIndex`, and protocol ID. |
|
|
193
|
+
| Metadata | Store only small, queryable fields (e.g., `threadId`, `sender`). |
|
|
194
|
+
| Large Data | Use UHRP references instead of storing raw data. |
|
|
195
|
+
| Queries | Use selective, indexed fields. |
|
|
196
|
+
| Pagination | Always include `skip` and `limit` in list endpoints. |
|
|
197
|
+
| Topic Manager | Validate and parse overlay-specific outputs only. |
|
|
198
|
+
| Retention | Prune or archive data as needed. |
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
Next file: [`02-query-performance.md`](./02-query-performance.md) — how to design and optimize overlay queries.
|