@cero-base/cero 1.18.2 → 2.0.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.
Files changed (44) hide show
  1. package/README.md +38 -644
  2. package/package.json +16 -12
  3. package/src/build/index.js +21 -50
  4. package/src/build/internal.js +121 -0
  5. package/src/build/schemas.js +2 -8
  6. package/src/extensions/handle-sync.js +3 -10
  7. package/src/extensions/index.js +6 -0
  8. package/src/extensions/profile-sync.js +0 -5
  9. package/src/handle/index.js +255 -300
  10. package/src/index.js +65 -112
  11. package/src/lib/bluetooth.js +25 -56
  12. package/src/lib/constants.js +0 -15
  13. package/src/lib/operators.js +24 -74
  14. package/src/lib/peek.js +4 -8
  15. package/src/lib/refs.js +46 -0
  16. package/src/lib/spec.js +2 -3
  17. package/src/local/index.js +4 -5
  18. package/src/rpc/client.js +27 -39
  19. package/src/rpc/index.js +3 -3
  20. package/src/rpc/server.js +29 -40
  21. package/types/build/index.d.ts +19 -7
  22. package/types/build/internal.d.ts +78 -0
  23. package/types/build/schemas.d.ts +3 -3
  24. package/types/extensions/handle-sync.d.ts +4 -9
  25. package/types/extensions/index.d.ts +24 -2
  26. package/types/extensions/profile-sync.d.ts +2 -6
  27. package/types/handle/index.d.ts +218 -254
  28. package/types/index.d.ts +78 -102
  29. package/types/lib/bluetooth.d.ts +24 -46
  30. package/types/lib/constants.d.ts +5 -16
  31. package/types/lib/operators.d.ts +49 -77
  32. package/types/lib/peek.d.ts +3 -4
  33. package/types/lib/refs.d.ts +36 -0
  34. package/types/lib/spec.d.ts +5 -1
  35. package/types/local/index.d.ts +24 -23
  36. package/types/rpc/client.d.ts +107 -127
  37. package/types/rpc/index.d.ts +7 -2
  38. package/types/rpc/server.d.ts +62 -76
  39. package/src/build/builtins.js +0 -174
  40. package/src/lib/internal.js +0 -9
  41. package/src/lib/utils.js +0 -67
  42. package/types/build/builtins.d.ts +0 -100
  43. package/types/lib/internal.d.ts +0 -24
  44. package/types/lib/utils.d.ts +0 -55
package/src/index.js CHANGED
@@ -2,6 +2,7 @@ import Hypercore from 'hypercore'
2
2
  import HypercoreStorage from 'hypercore-storage'
3
3
  import Corestore from 'corestore'
4
4
  import safetyCatch from 'safety-catch'
5
+ import c from 'compact-encoding'
5
6
  import fs from 'fs'
6
7
 
7
8
  import { Identity } from '@cero-base/core/identity'
@@ -29,8 +30,8 @@ import {
29
30
  } from './lib/operators.js'
30
31
  import { peek } from './lib/peek.js'
31
32
  import { t, schema } from './lib/spec.js'
32
- import { FLUSH } from './lib/constants.js'
33
- import { internal } from './lib/internal.js'
33
+ import { FLUSH, TIMEOUT } from './lib/constants.js'
34
+ import { registry } from './extensions/index.js'
34
35
 
35
36
  export { Handle, Ref, Local }
36
37
  export {
@@ -68,21 +69,18 @@ export { t, schema } from './lib/spec.js'
68
69
  * @property {number[]} [backoffs] Swarm reconnect backoff tiers in ms (testing/tuning).
69
70
  * @property {string} [channel] Optional network-isolation label; only same-channel peers connect.
70
71
  * @property {Array<string | Uint8Array>} [mirrors] Blind-peer public keys. Rooms and files are mirrored through them so peers sync even when never online at the same time. Mirrors hold only encrypted blocks — they never read your data.
71
- * @property {Uint8Array} [key] Pre-existing database key (skip bootstrap).
72
+ * @property {Uint8Array} [key] Existing database key to recover into, skipping the pointer lookup.
72
73
  * @property {Uint8Array} [encryptionKey] Pre-existing encryption key.
73
74
  * @property {Record<string, Function>} [routes] Custom RPC routes for the database dispatcher.
74
75
  * @property {(err: any) => void} [onerror] Background-task error handler.
75
- * @property {boolean} [recovery] Recovery flow wipe local state and re-claim a writer slot.
76
- * @property {number} [recoveryTimeout] Max wait for peer data + writer capability during recovery.
76
+ * @property {number} [recoveryTimeout] Max wait to find another device and be admitted, in ms. Defaults to 30000.
77
77
  * @property {Uint8Array} [storageKey] 32-byte key encrypting local key material (master seed, device keypairs) at rest. Source it from the OS keychain — cero never stores it.
78
78
  * @property {boolean} [extensions] `false` disables the bundled extensions (profileSync, handleSync) for this instance. Build with `{ extensions: false }` too so the spec matches.
79
79
  * @property {boolean | { autoStart?: boolean, backend?: any, maxOutbound?: number, maxInbound?: number, pipe?: 'l2cap' | 'gatt' }} [bluetooth] `true` enables nearby (Bluetooth) sync via `me.bluetooth` (auto-started). `{ autoStart: false }` creates the facade without starting the radio — the app calls `me.bluetooth.start()`/`stop()` (user toggle). `backend` injects a bare-bluetooth-shaped backend (tests). `maxOutbound`/`maxInbound` cap concurrent outbound links and inbound sessions. `pipe` picks the data pipe — `'l2cap'` (default, faster) or `'gatt'`; both peers must match. Absent backend on an unsupported host → `me.bluetooth.state === 'unsupported'`.
80
80
  */
81
81
 
82
82
  /**
83
- * Open (or create) a cero handle at `dir`. Sets up storage, network and
84
- * identity, then returns a ready root `Handle` with all schema refs
85
- * attached as properties.
83
+ * Open (or create) a cero handle at `dir`.
86
84
  *
87
85
  * @param {string} dir Data directory.
88
86
  * @param {any} spec Built spec — output of `cero/build`.
@@ -99,9 +97,7 @@ export async function cero(dir, spec, opts = {}) {
99
97
  let network = null
100
98
  let discovery = null
101
99
  let me = null
102
- // Any failure during open (bad phrase, network/bootstrap error, recovery
103
- // timeout, extension setup) must close whatever opened — else the corestore
104
- // lock leaks and a retry in the same process hits locked storage.
100
+ // any failure during open must close what opened, or the storage lock leaks
105
101
  try {
106
102
  await storage.ready()
107
103
  await fs.promises.chmod(`${dir}/main`, 0o700)
@@ -115,10 +111,11 @@ export async function cero(dir, spec, opts = {}) {
115
111
 
116
112
  const { identity, fresh } = await resolveIdentity(opts, local)
117
113
  const writer = local ? (await local.store.get('keypair')).data : null
114
+ // a supplied identity on a device with no writer recovers; only a cero-minted identity creates
115
+ const recovering = !writer && (!!opts.key || !fresh)
116
+ const timeout = opts.recoveryTimeout || TIMEOUT
118
117
 
119
- // Channel stamp: a storage remembers its channel; reopening it under a different channel
120
- // including no channel at all, which would silently rejoin the global network — is a
121
- // misconfiguration that could leak data across networks, so reject it.
118
+ // a storage remembers its channel; reopening under another would silently rejoin the global network
122
119
  if (local) {
123
120
  const stored = (await local.store.get('environment')).data?.channel ?? null
124
121
  const wanted = opts.channel ?? null
@@ -136,10 +133,21 @@ export async function cero(dir, spec, opts = {}) {
136
133
  })
137
134
  await network.ready()
138
135
  discovery = network.join(identity.topic)
139
- // a freshly minted identity has no peers yet flushing the announce
140
- // before proceeding only delays first onboarding
136
+ // a fresh identity has no peers yet, flushing the announce would only delay onboarding
141
137
  if (!fresh) await Promise.race([discovery.flush(), new Promise((r) => setTimeout(r, FLUSH))])
142
138
 
139
+ // the pointer core: identity-signed, written once by the creating device, holds the root key
140
+ const manifest = pointerManifest(store, identity)
141
+ const pointer = store.get(
142
+ !writer && !recovering
143
+ ? { keyPair: { publicKey: identity.publicKey, secretKey: identity.secretKey }, manifest }
144
+ : { key: Hypercore.key(manifest) }
145
+ )
146
+ await pointer.ready()
147
+ network.attach(pointer)
148
+
149
+ const key = opts.key || (recovering ? await readPointer(pointer, timeout) : undefined)
150
+
143
151
  me = new Handle({
144
152
  storage,
145
153
  store,
@@ -151,57 +159,31 @@ export async function cero(dir, spec, opts = {}) {
151
159
  opts,
152
160
  dir,
153
161
  routes: opts.routes,
154
- key: opts.key,
162
+ key,
155
163
  encryptionKey: opts.encryptionKey,
156
164
  keyPair: writer ? { publicKey: writer.publicKey, secretKey: writer.secretKey } : undefined,
157
165
  pair: false
158
166
  })
159
167
  await me.ready()
168
+ me.once('close', () => {
169
+ network.detach(pointer)
170
+ pointer.close().catch(safetyCatch)
171
+ })
160
172
 
161
- // a supplied or stored identity may already have history elsewhere —
162
- // authoring genesis twice forks the seed-derived writer core (a writable
163
- // core has one author, ever). Ask the peers directly with a plain session
164
- // on the genesis core: the base never replicates an empty local core.
165
- // Offline reuse is undetectable — this catches the reachable-peer case.
166
- if (!writer && !opts.key && !opts.recovery && !fresh) {
167
- const genesis = store.get({
168
- key: Hypercore.key({
169
- version: store.manifestVersion,
170
- signers: [{ publicKey: identity.publicKey }]
171
- })
172
- })
173
- await genesis.ready()
174
- network.attach(genesis)
175
- try {
176
- const until = Date.now() + 1500
177
- while (Date.now() < until) {
178
- if (genesis.length > 0 || genesis.peers.some((p) => p.remoteLength > 0)) {
179
- throw CeroError.CONFLICT('identity already has history — open with { recovery: true }')
180
- }
181
- await new Promise((r) => setTimeout(r, 100))
182
- }
183
- } finally {
184
- network.detach(genesis)
185
- await genesis.close()
186
- }
187
- }
188
- // decided by the stored writer and the caller's intent, never by the local
189
- // core's length: a same-identity device opens on the genesis core, which
190
- // fills with the first device's blocks as soon as a peer connects
191
- if (!writer && (!opts.key || opts.recovery)) {
173
+ if (!writer) {
192
174
  const result = await me.bootstrap({
193
175
  name: opts.name || null,
194
176
  isMobile: opts.isMobile === true,
195
- recovering: opts.recovery === true,
196
- ...(opts.recoveryTimeout ? { timeout: opts.recoveryTimeout } : {})
177
+ recovering,
178
+ timeout
197
179
  })
198
- if (local && result?.writer) {
180
+ if (local) {
199
181
  await local.store.set('keypair', {
200
182
  publicKey: result.writer.publicKey,
201
183
  secretKey: result.writer.secretKey
202
184
  })
203
185
  }
204
- if (!opts.recovery) {
186
+ if (!recovering) {
205
187
  const ts = Date.now()
206
188
  await me.store.call('add-member', {
207
189
  id: identity.id,
@@ -211,29 +193,20 @@ export async function cero(dir, spec, opts = {}) {
211
193
  createdAt: ts,
212
194
  updatedAt: ts
213
195
  })
196
+ if (pointer.length === 0) await pointer.append(c.encode(c.fixed32, me.store.key))
214
197
  }
215
198
  }
216
- if (opts.recovery) await me.recover({ timeout: opts.recoveryTimeout })
217
199
 
218
- for (const ext of internal.extensions) {
200
+ for (const ext of registry) {
219
201
  if (ext.bundled && opts.extensions === false) continue
220
202
  const off = await ext.setup?.(me)
221
203
  if (typeof off === 'function') me.once('close', off)
222
204
  }
223
205
 
224
206
  if (opts.bluetooth) {
225
- // `true` defaults; `{ autoStart, backend }` options. A bare backend
226
- // object (pre-1.3 shape, has Central/Server) is still accepted.
227
- const bt =
228
- opts.bluetooth === true
229
- ? {}
230
- : opts.bluetooth.Central
231
- ? { backend: opts.bluetooth }
232
- : opts.bluetooth
207
+ const bt = opts.bluetooth === true ? {} : opts.bluetooth
233
208
  me.bluetooth = new Bluetooth(me, {
234
- // pass the backend through untouched: `|| null` turned an omitted
235
- // backend (= lazy-load bare-bluetooth) into an explicit null
236
- // (= disabled), leaving BLE 'unsupported' on every platform
209
+ // an omitted backend lazy-loads bare-bluetooth, null disables it
237
210
  backend: bt.backend,
238
211
  autoStart: bt.autoStart !== false,
239
212
  maxOutbound: bt.maxOutbound,
@@ -247,8 +220,7 @@ export async function cero(dir, spec, opts = {}) {
247
220
  bind(me, null)
248
221
  return me
249
222
  } catch (err) {
250
- // once the root Handle exists it owns (and closes) everything; before that,
251
- // tear the raw resources down in reverse order.
223
+ // before the root Handle exists, tear the raw resources down in reverse order
252
224
  if (me) await me.close().catch(safetyCatch)
253
225
  else {
254
226
  await discovery?.destroy().catch(safetyCatch)
@@ -262,9 +234,7 @@ export async function cero(dir, spec, opts = {}) {
262
234
  }
263
235
 
264
236
  /**
265
- * Restore a cero instance from a mnemonic phrase. Closes the running
266
- * instance, wipes the on-disk `main/` tree and re-opens with `recovery: true`
267
- * so the writer slot is re-claimed.
237
+ * Restore a cero instance from a mnemonic phrase.
268
238
  *
269
239
  * @param {Handle} me Existing root handle to restore.
270
240
  * @param {string} phrase BIP-39 mnemonic phrase.
@@ -274,48 +244,23 @@ export async function restore(me, phrase) {
274
244
  if (!me?._dir) throw CeroError.INVALID('me must be a cero instance')
275
245
  if (!phrase || typeof phrase !== 'string') throw CeroError.INVALID('phrase must be a string')
276
246
 
277
- // Already this identity? Nothing to restore — return the running instance.
278
247
  const current = await Identity.fromSeed(Identity.toSeed(phrase))
279
248
  if (current.id === me.identity.id) return me
280
249
 
281
- const { _dir: dir, spec, _opts: opts } = me
282
- // channel must carry over — without it the recovered instance rejoins the
283
- // global identity topic and never meets its channeled peers (recovery timeout).
250
+ // everything carries over except the identity, the channel above all
284
251
  const {
285
- name,
286
- bootstrap,
287
- isMobile,
288
- onerror,
289
- routes,
290
- recoveryTimeout,
291
- channel,
292
- mirrors,
293
- storageKey,
294
- extensions
295
- } = opts
252
+ _dir: dir,
253
+ spec,
254
+ _opts: { seed, identity, key, keyPair, ...opts }
255
+ } = me
296
256
 
297
257
  await me.close()
298
258
  await fs.promises.rm(`${dir}/main`, { recursive: true, force: true })
299
259
 
300
- return cero(dir, spec, {
301
- name,
302
- bootstrap,
303
- isMobile,
304
- onerror,
305
- routes,
306
- recoveryTimeout,
307
- channel,
308
- mirrors,
309
- storageKey,
310
- extensions,
311
- phrase,
312
- recovery: true
313
- })
260
+ return cero(dir, spec, { ...opts, phrase })
314
261
  }
315
262
 
316
- // Facade: expose the operators + helpers as properties on `cero` too, so both
317
- // `import { define }` and `cero.define(...)` work. Explicit assignments (not
318
- // `Object.assign`) so tsc reflects them onto the `cero` namespace in the .d.ts.
263
+ // the facade: cero.put and import { put } are the same function
319
264
  cero.t = t
320
265
  cero.put = put
321
266
  cero.set = set
@@ -334,18 +279,26 @@ cero.restore = restore
334
279
  cero.schema = schema
335
280
  cero.bind = bind
336
281
  cero.define = define
337
- // test-only escape hatch (cross-package tests reset/seed the registry)
338
- cero._internal = internal
339
- // A bare function is shorthand for a behavior-only extension: `{ setup: fn }`.
340
- // Accepts both `use(a, b)` and `use([a, b])` (and a mix) for easier composition.
341
- // A named extension replaces any registered one with the same name — so
342
- // `use(profileSync({ fields }))` reconfigures the bundled default instead of
343
- // doubling it.
282
+ // test-only
283
+ cero._registry = registry
284
+ // a bare function is shorthand for { setup }; a named extension replaces one of the same name
344
285
  cero.use = (...exts) => {
345
286
  for (const e of exts.flat().map((e) => (typeof e === 'function' ? { setup: e } : e))) {
346
- const i = e.name ? internal.extensions.findIndex((x) => x.name === e.name) : -1
347
- if (i >= 0) internal.extensions[i] = e
348
- else internal.extensions.push(e)
287
+ const i = e.name ? registry.findIndex((x) => x.name === e.name) : -1
288
+ if (i >= 0) registry[i] = e
289
+ else registry.push(e)
290
+ }
291
+ }
292
+
293
+ function pointerManifest(store, identity) {
294
+ return { version: store.manifestVersion, signers: [{ publicKey: identity.publicKey }] }
295
+ }
296
+
297
+ async function readPointer(pointer, timeout) {
298
+ try {
299
+ return c.decode(c.fixed32, await pointer.get(0, { timeout }))
300
+ } catch {
301
+ throw CeroError.TIMED_OUT('recovery: finding a device of this identity')
349
302
  }
350
303
  }
351
304
 
@@ -8,19 +8,8 @@ import { Pairing } from '@cero-base/core/pairing'
8
8
  import { Invite } from '@cero-base/core/invite'
9
9
 
10
10
  /**
11
- * `me.bluetooth` — the app-facing surface for nearby (Bluetooth) sync, a thin
12
- * facade over ble-swarm. Bluetooth only changes how peers meet and carry
13
- * bytes; capability-gated replication still decides what syncs. Discovery is
14
- * one topic-derived service UUID at a time (tag `cero-ble`) — the data service
15
- * sits on a fixed per-tag UUID, so switching topics only retunes the radio.
16
- *
17
- * ```js
18
- * const me = await cero(dir, spec, { channel, bluetooth: true })
19
- * me.bluetooth.state // 'unsupported' | 'unauthorized' | 'off' | 'waiting' | 'starting' | 'on'
20
- * await me.bluetooth.start()
21
- * me.bluetooth.peers // Map of live BLE links
22
- * me.bluetooth.on('update', () => {})
23
- * ```
11
+ * `me.bluetooth` — the app-facing surface for nearby (Bluetooth) sync, a thin facade over
12
+ * ble-swarm.
24
13
  *
25
14
  * @extends ReadyResource
26
15
  */
@@ -43,14 +32,11 @@ export class Bluetooth extends ReadyResource {
43
32
  this._restorePending = false
44
33
 
45
34
  const identity = handle.identity
46
- // the mesh topic: one per channel, or a fixed global topic when
47
- // channelless — any nearby cero device links (global nearby; strangers
48
- // still sync zero bytes, replication is capability-gated)
35
+ // one mesh topic per channel, or a global one when channelless; strangers still sync nothing
49
36
  this._topic = crypto.hash(b4a.from(handle.network.channel || 'cero-ble'))
50
37
  this.swarm = new BluetoothSwarm({
51
38
  backend,
52
- // injected links authenticate with the same long-lived identity as the
53
- // swarm, so one person reached over Wi-Fi and BLE dedupes to one peer
39
+ // the swarm identity, so one person over Wi-Fi and BLE dedupes to one peer
54
40
  keyPair: { publicKey: identity.publicKey, secretKey: identity.secretKey },
55
41
  topic: this._topic,
56
42
  tag: 'cero-ble',
@@ -59,9 +45,7 @@ export class Bluetooth extends ReadyResource {
59
45
  maxInbound
60
46
  })
61
47
  this.swarm.on('update', () => {
62
- // an ended rendezvous retunes back to the mesh only once its links
63
- // drain — retuning drops links, and the pairing link still carries
64
- // the joiner's initial replication
48
+ // retune to the mesh only once the pairing link's initial replication drained
65
49
  if (this._restorePending && this.swarm.peers.size === 0) {
66
50
  this._restorePending = false
67
51
  this.swarm.setTopic(this._topic).catch(safetyCatch)
@@ -69,7 +53,6 @@ export class Bluetooth extends ReadyResource {
69
53
  this.emit('update')
70
54
  })
71
55
  this.swarm.on('connection', (conn) => {
72
- // the same treatment as any transport: wakeup, replication, pairing
73
56
  this._handle.network.inject(conn)
74
57
  })
75
58
  }
@@ -88,6 +71,11 @@ export class Bluetooth extends ReadyResource {
88
71
  if (this._autoStart) await this.start()
89
72
  }
90
73
 
74
+ async _close() {
75
+ this._clearAnnounce()
76
+ await this.swarm.destroy()
77
+ }
78
+
91
79
  /**
92
80
  * Begin advertising + scanning. Idempotent; no-op when unsupported.
93
81
  *
@@ -98,34 +86,20 @@ export class Bluetooth extends ReadyResource {
98
86
  }
99
87
 
100
88
  /**
101
- * Stop advertising/scanning and drop links; open invite rendezvous end with
102
- * the radio. Idempotent. Local data and the rest of the network (DHT) are
103
- * untouched.
89
+ * Stop advertising/scanning and drop links; open invite rendezvous end with the radio.
104
90
  *
105
91
  * @returns {Promise<void>}
106
92
  */
107
93
  async stop() {
108
94
  this._clearAnnounce()
109
95
  await this.swarm.stop()
110
- // while stopped setTopic just sticks the next start() is back on the
111
- // mesh. A start() + announce() that landed during the await wins.
96
+ // while stopped setTopic sticks; a start() + announce() during the await wins
112
97
  if (!this._announce) await this.swarm.setTopic(this._topic)
113
98
  }
114
99
 
115
100
  /**
116
- * Offline join rendezvous: retune the radio to the invite-derived topic so
117
- * holder and joiner find each other with zero DHT. One topic at a time —
118
- * announcing a new invite replaces the previous rendezvous. Returns a stop
119
- * function — closing the QR must stop the rendezvous so a photographed
120
- * invite doesn't stay an ambient discovery beacon (admission itself is
121
- * always gated by blind-pairing verifying the invite). The retune back to
122
- * the mesh topic waits for live links to drain: the link a join just
123
- * established survives and carries the joiner's initial replication.
124
- * Auto-stops at the invite's expiry, on `stop()`, and on close.
125
- *
126
- * Only active while nearby sync is on: before `start()` (and after `stop()`)
127
- * this is a no-op — the user controls the radio, and a join must not touch
128
- * Bluetooth (OS permissions, GATT server) they never enabled.
101
+ * Offline join rendezvous: retune the radio to the invite-derived topic so holder and
102
+ * joiner find each other with zero DHT.
129
103
  *
130
104
  * @param {string} invite Z32 invite string.
131
105
  * @returns {() => void}
@@ -161,20 +135,6 @@ export class Bluetooth extends ReadyResource {
161
135
  }
162
136
  }
163
137
 
164
- _stopAnnounce() {
165
- this._clearAnnounce()
166
- if (this.swarm.peers.size > 0) this._restorePending = true
167
- else this.swarm.setTopic(this._topic).catch(safetyCatch)
168
- }
169
-
170
- _clearAnnounce() {
171
- const e = this._announce
172
- if (!e) return
173
- if (e.timer) clearTimeout(e.timer)
174
- this._announce = null
175
- this._restorePending = false
176
- }
177
-
178
138
  /**
179
139
  * Host-lifecycle pause (app backgrounded): radio down, user intent kept.
180
140
  *
@@ -193,8 +153,17 @@ export class Bluetooth extends ReadyResource {
193
153
  await this.swarm.resume()
194
154
  }
195
155
 
196
- async _close() {
156
+ _stopAnnounce() {
197
157
  this._clearAnnounce()
198
- await this.swarm.destroy()
158
+ if (this.swarm.peers.size > 0) this._restorePending = true
159
+ else this.swarm.setTopic(this._topic).catch(safetyCatch)
160
+ }
161
+
162
+ _clearAnnounce() {
163
+ const e = this._announce
164
+ if (!e) return
165
+ if (e.timer) clearTimeout(e.timer)
166
+ this._announce = null
167
+ this._restorePending = false
199
168
  }
200
169
  }
@@ -1,5 +1,3 @@
1
- // Shared cero constants.
2
-
3
1
  export const NS = 'cero'
4
2
  export const COUNTERS = 'counters'
5
3
  export const EPOCHS = 'epochs'
@@ -7,16 +5,3 @@ export const EPOCHS = 'epochs'
7
5
  // Writer-admission / pairing timeout (ms), and the initial discovery-flush wait (ms).
8
6
  export const TIMEOUT = 30000
9
7
  export const FLUSH = 500
10
-
11
- // schema-DSL primitive → HyperDB type (used by the builder).
12
- export const DB_TYPE = {
13
- string: 'string',
14
- uint: 'uint',
15
- int: 'int',
16
- bool: 'bool',
17
- bytes: 'buffer',
18
- json: 'json',
19
- fixed32: 'fixed32',
20
- fixed64: 'fixed64',
21
- file: 'string'
22
- }