@cero-base/core 1.14.1 → 1.15.0
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/package.json +2 -2
- package/src/database/index.js +39 -11
- package/src/network/index.js +13 -1
- package/types/database/index.d.ts +1 -0
- package/types/network/index.d.ts +7 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cero-base/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"description": "cero p2p primitives — identity, storage, network, database, blobs, rpc, pairing.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -136,7 +136,7 @@
|
|
|
136
136
|
},
|
|
137
137
|
"dependencies": {
|
|
138
138
|
"@hyperswarm/secret-stream": "^6.9.1",
|
|
139
|
-
"autobee": "2.0.0-rc.
|
|
139
|
+
"autobee": "2.0.0-rc.26",
|
|
140
140
|
"autobee-encryption": "0.1.3",
|
|
141
141
|
"b4a": "^1.8.1",
|
|
142
142
|
"bare-crypto": "^1.15.3",
|
package/src/database/index.js
CHANGED
|
@@ -186,6 +186,26 @@ export class Database extends ReadyResource {
|
|
|
186
186
|
optimistic: true,
|
|
187
187
|
wakeup: wakeup || undefined,
|
|
188
188
|
open: (b) => HyperDB.bee2(b, this.spec.database, { autoUpdate: true }),
|
|
189
|
+
// without this hook autobee trusts EVERY fast-forward candidate, so a
|
|
190
|
+
// removed device could serve a stale or forked head and we would boot
|
|
191
|
+
// onto it. A head is only worth following if its writer is still a
|
|
192
|
+
// device — decided against the reference view autobee hands us (its own
|
|
193
|
+
// state at the point of the decision), never the live view. Untrusted
|
|
194
|
+
// heads are then skipped outright: mostRecentTrusted stays unset because
|
|
195
|
+
// no cero row records another writer's oplog length to fall back to.
|
|
196
|
+
isTrusted: async (writer, view) => {
|
|
197
|
+
try {
|
|
198
|
+
if (await view.get(`@${this.ns}/devices`, { id: toId(writer) })) return true
|
|
199
|
+
// before any device record exists (a boot's genesis-era reference)
|
|
200
|
+
// only the genesis writer may vouch — its core IS the db key, and
|
|
201
|
+
// its signatures are unforgeable. Anyone else stays refused: an
|
|
202
|
+
// empty view is exactly the window an ex-member would target.
|
|
203
|
+
const any = await view.find(`@${this.ns}/devices`, { limit: 1 }).toArray()
|
|
204
|
+
return any.length === 0 && !!this.key && b4a.equals(writer, this.key)
|
|
205
|
+
} catch {
|
|
206
|
+
return false
|
|
207
|
+
}
|
|
208
|
+
},
|
|
189
209
|
apply: async (nodes, view, host) => {
|
|
190
210
|
// envelope handling lives here, once: unwrap every node and skip ops
|
|
191
211
|
// from a newer app version (deterministic — they stay in the log), so
|
|
@@ -218,6 +238,12 @@ export class Database extends ReadyResource {
|
|
|
218
238
|
}
|
|
219
239
|
})
|
|
220
240
|
|
|
241
|
+
// swarm BEFORE boot when the key is known: replication is live while the
|
|
242
|
+
// bee opens, so the boot (and a future fast-forward boot) has peers to
|
|
243
|
+
// pull from instead of opening cold and waiting for discovery
|
|
244
|
+
const known = !!this.key
|
|
245
|
+
if (this.network && known) this._joinSwarm(bee, crypto.discoveryKey(this.key))
|
|
246
|
+
|
|
221
247
|
await bee.ready()
|
|
222
248
|
// assigned before the first update: apply-time hooks (_onEpoch's save,
|
|
223
249
|
// _onFuture) dereference this.bee and must never see it null mid-drain
|
|
@@ -252,17 +278,19 @@ export class Database extends ReadyResource {
|
|
|
252
278
|
// without a listener autobee escalates apply/view errors to a process crash
|
|
253
279
|
bee.on('error', this._onerror)
|
|
254
280
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
281
|
+
// a fresh db has no key until boot mints it — join once it exists
|
|
282
|
+
if (this.network && !known) this._joinSwarm(bee, bee.discoveryKey)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// a writer swap re-opens the bee on the SAME topic — join first so the old
|
|
286
|
+
// session's destroy is a refcounted detach, not a DHT unannounce round-trip
|
|
287
|
+
_joinSwarm(bee, discoveryKey) {
|
|
288
|
+
this.network.attach(bee)
|
|
289
|
+
const prev = this._discovery
|
|
290
|
+
this._discovery = this.network.join(discoveryKey, {
|
|
291
|
+
mode: this.passive ? PASSIVE : ACTIVE
|
|
292
|
+
})
|
|
293
|
+
if (prev) prev.destroy().catch(safetyCatch)
|
|
266
294
|
}
|
|
267
295
|
|
|
268
296
|
/**
|
package/src/network/index.js
CHANGED
|
@@ -24,6 +24,7 @@ export function channelTopic(topic, channel) {
|
|
|
24
24
|
* @property {Array<{ host: string, port: number }>} [bootstrap] Custom DHT bootstrap nodes.
|
|
25
25
|
* @property {(remotePublicKey: Uint8Array, payload: any) => boolean} [firewall] Incoming-connection filter.
|
|
26
26
|
* @property {Uint8Array[]} [relayThrough] Relay public keys to tunnel through.
|
|
27
|
+
* @property {number[]} [backoffs] Reconnect backoff tiers in ms; the default escalates to ~10min, far too slow for local nets.
|
|
27
28
|
* @property {string} [channel] Optional network-isolation label; only same-channel peers meet.
|
|
28
29
|
* @property {any} [store] Corestore; required for mirrors (blind peers replicate its cores).
|
|
29
30
|
* @property {Array<string | Uint8Array>} [mirrors] Blind-peer public keys; each attached room/blob core is mirrored through them for offline sync.
|
|
@@ -37,12 +38,22 @@ export function channelTopic(topic, channel) {
|
|
|
37
38
|
*/
|
|
38
39
|
export class Network extends ReadyResource {
|
|
39
40
|
/** @param {NetworkOpts} [opts] */
|
|
40
|
-
constructor({
|
|
41
|
+
constructor({
|
|
42
|
+
identity,
|
|
43
|
+
bootstrap,
|
|
44
|
+
firewall,
|
|
45
|
+
relayThrough,
|
|
46
|
+
backoffs,
|
|
47
|
+
channel,
|
|
48
|
+
store,
|
|
49
|
+
mirrors
|
|
50
|
+
} = {}) {
|
|
41
51
|
super()
|
|
42
52
|
this.identity = identity || null
|
|
43
53
|
this.bootstrap = bootstrap || null
|
|
44
54
|
this.firewall = firewall || null
|
|
45
55
|
this.relayThrough = relayThrough || null
|
|
56
|
+
this.backoffs = backoffs || null
|
|
46
57
|
this.channel = channel || null
|
|
47
58
|
this.store = store || null
|
|
48
59
|
this.mirrors = (mirrors || []).map((k) => (typeof k === 'string' ? decodeKey(k) : k))
|
|
@@ -168,6 +179,7 @@ export class Network extends ReadyResource {
|
|
|
168
179
|
if (this.bootstrap) opts.bootstrap = this.bootstrap
|
|
169
180
|
if (this.firewall) opts.firewall = this.firewall
|
|
170
181
|
if (this.relayThrough) opts.relayThrough = this.relayThrough
|
|
182
|
+
if (this.backoffs) opts.backoffs = this.backoffs
|
|
171
183
|
|
|
172
184
|
const swarm = (this._swarm = new Hyperswarm(opts))
|
|
173
185
|
swarm.on('connection', (stream, info) => {
|
|
@@ -94,6 +94,7 @@ export class Database extends ReadyResource {
|
|
|
94
94
|
_discovery: import("../network/discovery.js").Discovery;
|
|
95
95
|
/** Open the underlying autobee, wire dispatcher + apply, attach to network. */
|
|
96
96
|
openBee(): Promise<void>;
|
|
97
|
+
_joinSwarm(bee: any, discoveryKey: any): void;
|
|
97
98
|
/**
|
|
98
99
|
* Flip announce mode at runtime — passive stays reachable (server) but
|
|
99
100
|
* stops actively looking (client). Cheap; use it to demote idle rooms.
|
package/types/network/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export function channelTopic(topic: any, channel: any): any;
|
|
|
5
5
|
* @property {Array<{ host: string, port: number }>} [bootstrap] Custom DHT bootstrap nodes.
|
|
6
6
|
* @property {(remotePublicKey: Uint8Array, payload: any) => boolean} [firewall] Incoming-connection filter.
|
|
7
7
|
* @property {Uint8Array[]} [relayThrough] Relay public keys to tunnel through.
|
|
8
|
+
* @property {number[]} [backoffs] Reconnect backoff tiers in ms; the default escalates to ~10min, far too slow for local nets.
|
|
8
9
|
* @property {string} [channel] Optional network-isolation label; only same-channel peers meet.
|
|
9
10
|
* @property {any} [store] Corestore; required for mirrors (blind peers replicate its cores).
|
|
10
11
|
* @property {Array<string | Uint8Array>} [mirrors] Blind-peer public keys; each attached room/blob core is mirrored through them for offline sync.
|
|
@@ -17,7 +18,7 @@ export function channelTopic(topic: any, channel: any): any;
|
|
|
17
18
|
*/
|
|
18
19
|
export class Network extends ReadyResource {
|
|
19
20
|
/** @param {NetworkOpts} [opts] */
|
|
20
|
-
constructor({ identity, bootstrap, firewall, relayThrough, channel, store, mirrors }?: NetworkOpts);
|
|
21
|
+
constructor({ identity, bootstrap, firewall, relayThrough, backoffs, channel, store, mirrors }?: NetworkOpts);
|
|
21
22
|
identity: import("../index.js").Identity;
|
|
22
23
|
bootstrap: {
|
|
23
24
|
host: string;
|
|
@@ -25,6 +26,7 @@ export class Network extends ReadyResource {
|
|
|
25
26
|
}[];
|
|
26
27
|
firewall: (remotePublicKey: Uint8Array, payload: any) => boolean;
|
|
27
28
|
relayThrough: Uint8Array<ArrayBufferLike>[];
|
|
29
|
+
backoffs: number[];
|
|
28
30
|
channel: string;
|
|
29
31
|
store: any;
|
|
30
32
|
mirrors: any[];
|
|
@@ -152,6 +154,10 @@ export type NetworkOpts = {
|
|
|
152
154
|
* Relay public keys to tunnel through.
|
|
153
155
|
*/
|
|
154
156
|
relayThrough?: Uint8Array[];
|
|
157
|
+
/**
|
|
158
|
+
* Reconnect backoff tiers in ms; the default escalates to ~10min, far too slow for local nets.
|
|
159
|
+
*/
|
|
160
|
+
backoffs?: number[];
|
|
155
161
|
/**
|
|
156
162
|
* Optional network-isolation label; only same-channel peers meet.
|
|
157
163
|
*/
|