Updates
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
# Changelog
|
||||
|
||||
## [0.2.0] - 2026-05-20
|
||||
|
||||
### Added
|
||||
- Real Hyperswarm + Protomux v3 wiring via `../_shared/p2p-bare.js` (where applicable)
|
||||
- 2-node integration test under `real_tests/integration/`
|
||||
|
||||
### Changed
|
||||
- Protomux v3: `createChannel` + `addMessage` + `channel.open()`
|
||||
|
||||
## [0.1.1] - 2026-05-20
|
||||
|
||||
### Fixed
|
||||
- Migrated tests from `bare-test` to `brittle` / `brittle-bare`
|
||||
- `hypercore-crypto` for keyPair, sign, verify, hash
|
||||
- `bare-process/global` and `bare-process` v4 imports
|
||||
- Background timers opt-in (`enableBackgroundTimers`, `enableGossip`) for clean test exit
|
||||
|
||||
@@ -129,3 +129,12 @@ See `examples/basic-usage.js`
|
||||
Apache-2.0
|
||||
|
||||
**Developed autonomously by Holepunch Development Agent — 2026-05-20**
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npx brittle-bare test/test.js
|
||||
```
|
||||
|
||||
See [DEVELOPMENT.md](../../DEVELOPMENT.md) and [CHANGELOG.md](CHANGELOG.md).
|
||||
|
||||
@@ -83,3 +83,30 @@ interface TemporalEvent {
|
||||
See `examples/basic-usage.js` and integration with other hyper-p2p-* modules.
|
||||
|
||||
All methods are production-ready with comprehensive error handling and Bare runtime safety.
|
||||
|
||||
## P2P and runtime options
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `topic` | `string` \| `Buffer` | `null` | Hyperswarm discovery topic. Hex (64 chars) or string (hashed via `hypercore-crypto`). P2P is active when set. |
|
||||
| `keyPair` | `KeyPair` | random | Ed25519 key pair (`hypercore-crypto.keyPair()`). |
|
||||
|
||||
### Runtime flags (test exit)
|
||||
|
||||
| Option | Modules | Default | Description |
|
||||
|--------|---------|---------|-------------|
|
||||
| `enableBackgroundTimers` | oracle, reputation | `false` | Enables periodic cleanup/decay/gossip timers. Keep `false` in unit tests so the process exits. |
|
||||
| `enableGossip` | causal-consensus | `false` | Enables gossip interval + Protomux proposal fan-out when `topic` is also set. |
|
||||
|
||||
### Protomux
|
||||
|
||||
Wire format uses **Protomux v3** (`createChannel` → `addMessage` → `open`) via [`../_shared/p2p-bare.js`](../_shared/p2p-bare.js).
|
||||
|
||||
### Testing
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npx brittle-bare test/test.js
|
||||
```
|
||||
|
||||
Integration (2-node): [`../../real_tests/integration/`](../../real_tests/integration/) — see [DEVELOPMENT.md](../../DEVELOPMENT.md).
|
||||
|
||||
@@ -77,3 +77,9 @@ flowchart LR
|
||||
- Metrics exposed for observability (inserts, queries, prunes, eventCount).
|
||||
|
||||
This architecture makes `hyper-p2p-temporal-index` a foundational building block for time-aware decentralized applications: IoT telemetry, audit logs, chat history, financial tick data, and agent memory in the Bare/Pear ecosystem.
|
||||
|
||||
### Diagram legend (P2P)
|
||||
|
||||
- **Solid arrows** — implemented Hyperswarm / Protomux paths in `index.js`
|
||||
- **Dashed arrows** — optional hooks (set `topic`, `enableGossip`, or pass external `hyperbee` / `swarm`)
|
||||
- **Library-only** — no swarm required for core API (vector-clock, capabilities core)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
require('bare-process/global')
|
||||
const EventEmitter = require('bare-events')
|
||||
const crypto = require('bare-crypto')
|
||||
const timers = require('bare-timers')
|
||||
@@ -49,7 +50,28 @@ class HyperP2PTemporalIndex extends EventEmitter {
|
||||
this._pruneTimer = null
|
||||
this._metrics = { inserts: 0, queries: 0, prunes: 0, signed: 0 }
|
||||
|
||||
this._p2pTopic = options.topic || null
|
||||
this._startPruneLoop()
|
||||
if (this._p2pTopic) {
|
||||
this._initP2P().catch((err) => this.emit('error', err))
|
||||
}
|
||||
}
|
||||
|
||||
async _initP2P () {
|
||||
const PROTO = 'hyper-p2p-temporal-index/v1'
|
||||
const { initModuleSwarm } = require('../_shared/p2p-bare.js')
|
||||
const self = this
|
||||
await initModuleSwarm(this, {
|
||||
keyPair: this.options.keyPair || require('hypercore-crypto').keyPair(),
|
||||
topic: this._p2pTopic,
|
||||
protocol: PROTO,
|
||||
onmessage (data) {
|
||||
if (data && data.type === 'event' && data.event) {
|
||||
self.events.set(data.event.id, data.event)
|
||||
self.emit('event-replicated', data.event)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
_normalizeId (id) {
|
||||
@@ -78,7 +100,7 @@ class HyperP2PTemporalIndex extends EventEmitter {
|
||||
|
||||
_signEvent (event) {
|
||||
if (!this.options.enableSigning) return event
|
||||
const keyPair = this.options.keyPair || crypto.keyPair()
|
||||
const keyPair = this.options.keyPair || require('hypercore-crypto').keyPair()
|
||||
const dataToSign = b4a.from(JSON.stringify({
|
||||
id: event.id,
|
||||
timestamp: event.timestamp,
|
||||
@@ -86,7 +108,7 @@ class HyperP2PTemporalIndex extends EventEmitter {
|
||||
metadata: event.metadata,
|
||||
vectorClock: event.vectorClock
|
||||
}))
|
||||
const signature = crypto.sign(dataToSign, keyPair.secretKey)
|
||||
const signature = require('hypercore-crypto').sign(dataToSign, keyPair.secretKey)
|
||||
event.signature = b4a.toString(signature, 'base64')
|
||||
event.issuer = b4a.toString(keyPair.publicKey, 'hex')
|
||||
this._metrics.signed++
|
||||
@@ -105,7 +127,7 @@ class HyperP2PTemporalIndex extends EventEmitter {
|
||||
}))
|
||||
const sig = b4a.from(event.signature, 'base64')
|
||||
const pub = publicKey || b4a.from(event.issuer, 'hex')
|
||||
return crypto.verify(dataToVerify, sig, pub)
|
||||
return require('hypercore-crypto').verify(dataToVerify, sig, pub)
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
@@ -152,6 +174,11 @@ class HyperP2PTemporalIndex extends EventEmitter {
|
||||
await this._persistToHyperbee(event, buckets)
|
||||
}
|
||||
|
||||
if (this.swarm) {
|
||||
const { gossipSend } = require('../_shared/p2p-bare.js')
|
||||
gossipSend(this, { type: 'event', event })
|
||||
}
|
||||
|
||||
this.emit('insert', event)
|
||||
this.emit('event', { type: 'insert', event })
|
||||
|
||||
@@ -255,10 +282,15 @@ class HyperP2PTemporalIndex extends EventEmitter {
|
||||
let bestDiff = Infinity
|
||||
|
||||
for (const [id, ev] of this.events) {
|
||||
const diff = Math.abs(ev.timestamp - targetTime)
|
||||
if (direction === 'before' && ev.timestamp > targetTime) continue
|
||||
if (direction === 'after' && ev.timestamp < targetTime) continue
|
||||
|
||||
const diff = direction === 'before'
|
||||
? targetTime - ev.timestamp
|
||||
: direction === 'after'
|
||||
? ev.timestamp - targetTime
|
||||
: Math.abs(ev.timestamp - targetTime)
|
||||
|
||||
if (diff < bestDiff) {
|
||||
bestDiff = diff
|
||||
best = ev
|
||||
|
||||
+1810
File diff suppressed because it is too large
Load Diff
@@ -38,11 +38,12 @@
|
||||
},
|
||||
"homepage": "https://github.com/holepunchto/hyper-p2p-temporal-index",
|
||||
"dependencies": {
|
||||
"bare-events": "^2.0.0",
|
||||
"bare-crypto": "^1.0.0",
|
||||
"bare-timers": "^1.0.0",
|
||||
"bare-process": "^1.0.0",
|
||||
"b4a": "^1.6.0"
|
||||
"bare-events": "^2.8.0",
|
||||
"bare-crypto": "^1.9.0",
|
||||
"bare-timers": "^2.0.0",
|
||||
"bare-process": "^4.4.0",
|
||||
"b4a": "^1.6.7",
|
||||
"hypercore-crypto": "^3.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"hyperbee": "^2.0.0",
|
||||
@@ -51,7 +52,7 @@
|
||||
"bare": ">=1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bare-test": "^1.0.0"
|
||||
"brittle": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"bare": ">=1.0.0"
|
||||
@@ -59,5 +60,34 @@
|
||||
"pear": {
|
||||
"name": "hyper-p2p-temporal-index",
|
||||
"type": "module"
|
||||
},
|
||||
"imports": {
|
||||
"process": {
|
||||
"bare": "bare-process",
|
||||
"default": "process"
|
||||
},
|
||||
"crypto": {
|
||||
"bare": "bare-crypto",
|
||||
"default": "crypto"
|
||||
},
|
||||
"path": {
|
||||
"bare": "bare-path",
|
||||
"default": "path"
|
||||
},
|
||||
"fs": {
|
||||
"bare": "bare-fs",
|
||||
"default": "fs"
|
||||
},
|
||||
"timers": {
|
||||
"bare": "bare-timers",
|
||||
"default": "timers"
|
||||
},
|
||||
"events": {
|
||||
"bare": "bare-events",
|
||||
"default": "events"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "brittle-bare test/test.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const test = require('bare-test')
|
||||
require('bare-process/global')
|
||||
const test = require('brittle')
|
||||
const HyperP2PTemporalIndex = require('../index.js')
|
||||
const crypto = require('bare-crypto')
|
||||
const b4a = require('b4a')
|
||||
@@ -40,7 +41,7 @@ test('hyper-p2p-temporal-index - nearest query and expiry/prune', async (t) => {
|
||||
const now = Date.now()
|
||||
|
||||
const ev1 = await index.insertEvent({ v: 1 }, { timestamp: now - 200 })
|
||||
const ev2 = await index.insertEvent({ v: 2 }, { timestamp: now })
|
||||
const ev2 = await index.insertEvent({ v: 2 }, { timestamp: now - 100 })
|
||||
|
||||
const nearest = await index.queryNearest(now - 50, { direction: 'before' })
|
||||
t.ok(nearest, 'found nearest before')
|
||||
|
||||
Reference in New Issue
Block a user