@cero-base/cero 0.8.5 → 0.8.6
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 +47 -1
- package/package.json +6 -6
- package/src/handle/index.js +4 -0
- package/src/index.js +34 -5
- package/src/lib/operators.js +98 -0
- package/src/rpc/client.js +3 -0
- package/types/index.d.ts +1 -2
- package/types/lib/operators.d.ts +34 -0
- package/src/lib/peek.js +0 -36
- package/types/lib/peek.d.ts +0 -10
package/README.md
CHANGED
|
@@ -191,6 +191,52 @@ cero.after(me.profile, ({ row }) => {
|
|
|
191
191
|
|
|
192
192
|
`ctx` is `{ op, name, row }` (plus `result` in `after`).
|
|
193
193
|
|
|
194
|
+
## Custom operators
|
|
195
|
+
|
|
196
|
+
Your app's business logic lives as **custom operators** — plain functions whose first arg is the handle they act on, composing the built-ins. Because the built-ins resolve through the handle (a real DB on the core, an RPC proxy on the client), custom operators are symmetric over RPC for free.
|
|
197
|
+
|
|
198
|
+
```js
|
|
199
|
+
// guest.js — pure functions, one per export
|
|
200
|
+
import { put, del } from '@cero-base/cero'
|
|
201
|
+
import { ensureGuestId } from './ids.js'
|
|
202
|
+
|
|
203
|
+
export const create = (room, data) => put(room.guests, { ...data, id: ensureGuestId(data.id) })
|
|
204
|
+
export const remove = (room, id) => del(room.guests, id)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### `cero.define(map)`
|
|
208
|
+
|
|
209
|
+
Register custom operators by **scope**, once, and cero puts them on every matching handle — the root and each child as it opens, on both the core and the client. A **bare key** binds on the root handle; a key that names a **child-handle type** binds on each handle of that type:
|
|
210
|
+
|
|
211
|
+
```js
|
|
212
|
+
import * as user from './user.js'
|
|
213
|
+
import * as guest from './guest.js'
|
|
214
|
+
import * as station from './station.js'
|
|
215
|
+
|
|
216
|
+
cero.define({
|
|
217
|
+
user, // bound on the root → me.user.rename(…)
|
|
218
|
+
room: { guest, station } // bound on each room → room.guest.create(…)
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
const room = await cero.open(me.room, { id })
|
|
222
|
+
await room.guest.create({ name: 'Bob' }) // no binding at the call site
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
cero reads the spec to tell root namespaces from child-handle types, so there is no `root` wrapper. Call `cero.define(...)` once at startup — in the build/server process **and** the client — the same as extensions.
|
|
226
|
+
|
|
227
|
+
### `cero.bind(handle, map)`
|
|
228
|
+
|
|
229
|
+
The primitive `define` uses. Curry a handle onto a `{ ns: module }` map yourself — for a handle you opened manually, or to bind operators you don't want globally registered:
|
|
230
|
+
|
|
231
|
+
```js
|
|
232
|
+
import * as guest from './guest.js'
|
|
233
|
+
|
|
234
|
+
cero.bind(room, { guest })
|
|
235
|
+
await room.guest.create({ name: 'Bob' }) // → guest.create(room, …)
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Non-functions in the map are skipped; the handle is returned.
|
|
239
|
+
|
|
194
240
|
## Extensions
|
|
195
241
|
|
|
196
242
|
An extension bundles **schema** (build-time) with **behavior** (runtime). Register it with `cero.use()` — `build()` folds in its schema and `cero()` runs its `setup` once the handle is ready. cero core stays schema-agnostic; apps opt into the behaviors they want.
|
|
@@ -373,7 +419,7 @@ const remote = await connect(c, spec)
|
|
|
373
419
|
|
|
374
420
|
| Path | What you get |
|
|
375
421
|
| ---------------------------- | ------------------------------------------------------------------------ |
|
|
376
|
-
| `@cero-base/cero` | factory + operators + schema DSL
|
|
422
|
+
| `@cero-base/cero` | factory + operators + schema DSL + `define`/`bind` |
|
|
377
423
|
| `@cero-base/cero/client` | `connect(ipc, spec)` — talk to a cero running in another process |
|
|
378
424
|
| `@cero-base/cero/server` | `serve(ipc, { storage, spec })` — run + expose a cero over an IPC stream |
|
|
379
425
|
| `@cero-base/cero/build` | `build(specDir, schema)` — generate the on-disk spec |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cero-base/cero",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.6",
|
|
4
4
|
"description": "The ideal p2p API — everything is a handle, handles contain refs, refs contain rows.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -78,12 +78,12 @@
|
|
|
78
78
|
"test": "ls test/*.test.js | xargs -P1 -n1 brittle-node"
|
|
79
79
|
},
|
|
80
80
|
"dependencies": {
|
|
81
|
-
"@cero-base/core": "^0.8.
|
|
81
|
+
"@cero-base/core": "^0.8.6",
|
|
82
82
|
"b4a": "^1.8.1",
|
|
83
83
|
"bare-abort-controller": "^1.1.2",
|
|
84
|
-
"bare-crypto": "^1.
|
|
85
|
-
"bare-fs": "^4.7.
|
|
86
|
-
"bare-path": "^3.0.
|
|
84
|
+
"bare-crypto": "^1.14.1",
|
|
85
|
+
"bare-fs": "^4.7.2",
|
|
86
|
+
"bare-path": "^3.0.1",
|
|
87
87
|
"blind-pairing": "^2.3.1",
|
|
88
88
|
"compact-encoding": "^3.1.0",
|
|
89
89
|
"hrpc": "^4.3.0",
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"devDependencies": {
|
|
98
98
|
"@hyperswarm/testnet": "^3.1.4",
|
|
99
99
|
"brittle": "^4.0.0",
|
|
100
|
-
"typescript": "^
|
|
100
|
+
"typescript": "^6.0.3"
|
|
101
101
|
},
|
|
102
102
|
"license": "Apache-2.0"
|
|
103
103
|
}
|
package/src/handle/index.js
CHANGED
|
@@ -15,6 +15,7 @@ import { CeroError } from '@cero-base/core/errors'
|
|
|
15
15
|
import { NS, TIMEOUT } from '../lib/constants.js'
|
|
16
16
|
|
|
17
17
|
import { attachRefs, onAbort } from '../lib/utils.js'
|
|
18
|
+
import { bind } from '../lib/operators.js'
|
|
18
19
|
|
|
19
20
|
export { Ref } from '../lib/utils.js'
|
|
20
21
|
|
|
@@ -399,6 +400,7 @@ export class Handle extends ReadyResource {
|
|
|
399
400
|
})
|
|
400
401
|
|
|
401
402
|
if (accept !== false) this._wireAccept(child, { role })
|
|
403
|
+
bind(child, type)
|
|
402
404
|
this.children.add(child)
|
|
403
405
|
this.emit('handle', child, { name, role })
|
|
404
406
|
return child
|
|
@@ -454,6 +456,7 @@ export class Handle extends ReadyResource {
|
|
|
454
456
|
updatedAt: ts
|
|
455
457
|
})
|
|
456
458
|
this._wireAccept(child)
|
|
459
|
+
bind(child, type)
|
|
457
460
|
this.children.add(child)
|
|
458
461
|
this.emit('handle', child, {})
|
|
459
462
|
return child
|
|
@@ -517,6 +520,7 @@ export class Handle extends ReadyResource {
|
|
|
517
520
|
await this._saveKeyPair(id, writer)
|
|
518
521
|
}
|
|
519
522
|
this._wireAccept(child)
|
|
523
|
+
bind(child, type)
|
|
520
524
|
this.children.add(child)
|
|
521
525
|
this.emit('handle', child, {})
|
|
522
526
|
return child
|
package/src/index.js
CHANGED
|
@@ -8,15 +8,41 @@ import { CeroError } from '@cero-base/core/errors'
|
|
|
8
8
|
|
|
9
9
|
import { Handle, Ref } from './handle/index.js'
|
|
10
10
|
import { Local } from './local/index.js'
|
|
11
|
-
import {
|
|
12
|
-
|
|
11
|
+
import {
|
|
12
|
+
put,
|
|
13
|
+
set,
|
|
14
|
+
get,
|
|
15
|
+
del,
|
|
16
|
+
count,
|
|
17
|
+
watch,
|
|
18
|
+
call,
|
|
19
|
+
open,
|
|
20
|
+
before,
|
|
21
|
+
after,
|
|
22
|
+
bind,
|
|
23
|
+
define,
|
|
24
|
+
peek
|
|
25
|
+
} from './lib/operators.js'
|
|
13
26
|
import { t, schema } from './lib/spec.js'
|
|
14
27
|
import { FLUSH } from './lib/constants.js'
|
|
15
28
|
import { internal } from './lib/internal.js'
|
|
16
29
|
|
|
17
30
|
export { Handle, Ref, Local }
|
|
18
|
-
export {
|
|
19
|
-
|
|
31
|
+
export {
|
|
32
|
+
put,
|
|
33
|
+
set,
|
|
34
|
+
get,
|
|
35
|
+
del,
|
|
36
|
+
count,
|
|
37
|
+
watch,
|
|
38
|
+
call,
|
|
39
|
+
open,
|
|
40
|
+
before,
|
|
41
|
+
after,
|
|
42
|
+
bind,
|
|
43
|
+
define,
|
|
44
|
+
peek
|
|
45
|
+
} from './lib/operators.js'
|
|
20
46
|
export { t, schema } from './lib/spec.js'
|
|
21
47
|
|
|
22
48
|
/**
|
|
@@ -123,6 +149,7 @@ export async function cero(dir, spec, opts = {}) {
|
|
|
123
149
|
throw err
|
|
124
150
|
}
|
|
125
151
|
|
|
152
|
+
bind(me, null)
|
|
126
153
|
return me
|
|
127
154
|
}
|
|
128
155
|
|
|
@@ -175,7 +202,9 @@ Object.assign(cero, {
|
|
|
175
202
|
after,
|
|
176
203
|
peek,
|
|
177
204
|
restore,
|
|
178
|
-
schema
|
|
205
|
+
schema,
|
|
206
|
+
bind,
|
|
207
|
+
define
|
|
179
208
|
})
|
|
180
209
|
cero._internal = internal
|
|
181
210
|
// A bare function is shorthand for a behavior-only extension: `{ setup: fn }`.
|
package/src/lib/operators.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { Readable } from 'streamx'
|
|
2
|
+
import HypercoreStorage from 'hypercore-storage'
|
|
3
|
+
import Corestore from 'corestore'
|
|
4
|
+
|
|
5
|
+
import { CeroError } from '@cero-base/core/errors'
|
|
2
6
|
|
|
3
7
|
import { onAbort } from './utils.js'
|
|
8
|
+
import { Local } from '../local/index.js'
|
|
4
9
|
|
|
5
10
|
/**
|
|
6
11
|
* @typedef {import('./utils.js').Ref} Ref
|
|
@@ -186,3 +191,96 @@ export const open = (ref, arg) => {
|
|
|
186
191
|
if (arg && typeof arg.id === 'string') return ref.handle._load(ref.name, arg.id)
|
|
187
192
|
return ref.handle._create(ref.name, arg)
|
|
188
193
|
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Quickly check whether the on-disk directory at `dir` already holds an
|
|
197
|
+
* initialised cero identity (i.e. a stored master seed). Opens the local store
|
|
198
|
+
* read-only and closes everything before returning.
|
|
199
|
+
*
|
|
200
|
+
* @param {string} dir Cero data directory.
|
|
201
|
+
* @param {any} spec Built spec — same value passed to `cero(dir, spec)`.
|
|
202
|
+
* @returns {Promise<boolean>} `true` if a master seed exists on disk.
|
|
203
|
+
*/
|
|
204
|
+
export async function peek(dir, spec) {
|
|
205
|
+
if (typeof dir !== 'string' || !dir) throw CeroError.INVALID('dir must be a non-empty string')
|
|
206
|
+
if (!spec) throw CeroError.REQUIRED('spec')
|
|
207
|
+
|
|
208
|
+
const root = new HypercoreStorage(`${dir}/main`)
|
|
209
|
+
await root.ready()
|
|
210
|
+
const store = new Corestore(root, { manifestVersion: 2 })
|
|
211
|
+
await store.ready()
|
|
212
|
+
|
|
213
|
+
const local = new Local(null, spec, { store })
|
|
214
|
+
await local.ready()
|
|
215
|
+
try {
|
|
216
|
+
const { data } = await local.store.get('master')
|
|
217
|
+
return !!data?.seed
|
|
218
|
+
} finally {
|
|
219
|
+
await local.close()
|
|
220
|
+
await store.close()
|
|
221
|
+
await root.close()
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// ─── custom operators ──────────────────────────────────────────────────────
|
|
226
|
+
// App business logic lives as custom operators: pure functions whose first arg
|
|
227
|
+
// is the handle they act on, composed from the operators above. `define`
|
|
228
|
+
// registers them by scope; `bind` puts them on a handle — either an explicit
|
|
229
|
+
// `{ ns: module }` map, or (given a scope) the registered operators for that
|
|
230
|
+
// scope, which is how cero auto-binds the root and each child as it opens.
|
|
231
|
+
|
|
232
|
+
const registry = {}
|
|
233
|
+
|
|
234
|
+
// Curry `handle` as arg 0 of every function in `fns`, under `handle[ns]`.
|
|
235
|
+
function attach(handle, ns, fns) {
|
|
236
|
+
const bound = {}
|
|
237
|
+
for (const key of Object.keys(fns)) {
|
|
238
|
+
if (typeof fns[key] === 'function') bound[key] = (...args) => fns[key](handle, ...args)
|
|
239
|
+
}
|
|
240
|
+
handle[ns] = bound
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Put custom operators on `handle`, currying it as their first argument so
|
|
245
|
+
* `handle.ns.fn(args)` calls `fn(handle, args)`. `arg` is either:
|
|
246
|
+
* - a `{ ns: module }` map → bind exactly those, or
|
|
247
|
+
* - `null` → the registered root operators, or
|
|
248
|
+
* - a child-handle type → the registered operators for that type.
|
|
249
|
+
* The scope forms are how cero binds handles automatically; pass a map yourself
|
|
250
|
+
* for manual binding.
|
|
251
|
+
*
|
|
252
|
+
* @param {any} handle
|
|
253
|
+
* @param {Record<string, any> | string | null} arg
|
|
254
|
+
* @returns {any} handle
|
|
255
|
+
*/
|
|
256
|
+
export function bind(handle, arg) {
|
|
257
|
+
if (arg !== null && typeof arg !== 'string') {
|
|
258
|
+
for (const ns of Object.keys(arg)) attach(handle, ns, arg[ns])
|
|
259
|
+
return handle
|
|
260
|
+
}
|
|
261
|
+
const handles = handle.spec?.meta?.handles || {}
|
|
262
|
+
for (const ns of Object.keys(registry)) {
|
|
263
|
+
if (arg === null) {
|
|
264
|
+
if (!(ns in handles)) attach(handle, ns, registry[ns]) // bare root namespace
|
|
265
|
+
} else if (ns === arg) {
|
|
266
|
+
for (const k of Object.keys(registry[ns])) attach(handle, k, registry[ns][k]) // child group
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return handle
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Register custom operators by scope. A bare key binds on the root handle; a key
|
|
274
|
+
* that names a child-handle type binds on every handle of that type. Call once
|
|
275
|
+
* at startup, before `cero()` / `connect()`, in both processes.
|
|
276
|
+
*
|
|
277
|
+
* @param {Record<string, any>} map
|
|
278
|
+
*/
|
|
279
|
+
export function define(map) {
|
|
280
|
+
Object.assign(registry, map)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** Test seam: clear all registered operators. */
|
|
284
|
+
export function _clearDefined() {
|
|
285
|
+
for (const k of Object.keys(registry)) delete registry[k]
|
|
286
|
+
}
|
package/src/rpc/client.js
CHANGED
|
@@ -2,6 +2,7 @@ import { Readable } from 'streamx'
|
|
|
2
2
|
import { RPCClient, bindCodec } from '@cero-base/core/rpc'
|
|
3
3
|
|
|
4
4
|
import { attachRefs } from '../lib/utils.js'
|
|
5
|
+
import { bind } from '../lib/operators.js'
|
|
5
6
|
|
|
6
7
|
export { put, set, get, del, count, watch, call, open } from '../lib/operators.js'
|
|
7
8
|
|
|
@@ -298,6 +299,7 @@ export class Client extends RPCClient {
|
|
|
298
299
|
this.deviceId = deviceId || null
|
|
299
300
|
this.identity = { id, toPhrase: () => phrase || null }
|
|
300
301
|
attachRefs(this, /** @type {Spec} */ (this.spec).meta.refs)
|
|
302
|
+
bind(this, null)
|
|
301
303
|
if (/** @type {Spec} */ (this.spec).meta.local?.refs) this.local = new LocalRefs(this)
|
|
302
304
|
}
|
|
303
305
|
|
|
@@ -364,6 +366,7 @@ class Handle {
|
|
|
364
366
|
if (!this.spec.codec) bindCodec(this.spec)
|
|
365
367
|
this.store = this
|
|
366
368
|
attachRefs(this, this.spec.meta.refs)
|
|
369
|
+
bind(this, this.type)
|
|
367
370
|
}
|
|
368
371
|
|
|
369
372
|
/** Underlying RPC channel borrowed from the parent. */
|
package/types/index.d.ts
CHANGED
|
@@ -39,7 +39,6 @@ export namespace cero {
|
|
|
39
39
|
* @returns {Promise<Handle>} Freshly restored root handle.
|
|
40
40
|
*/
|
|
41
41
|
export function restore(me: Handle, phrase: string): Promise<Handle>;
|
|
42
|
-
export { peek } from "./lib/peek.js";
|
|
43
42
|
export type CeroOpts = {
|
|
44
43
|
/**
|
|
45
44
|
* Pre-resolved identity. If absent, derived from `seed`/`phrase` or generated.
|
|
@@ -103,5 +102,5 @@ import { Ref } from './handle/index.js';
|
|
|
103
102
|
import { Local } from './local/index.js';
|
|
104
103
|
import { Identity } from '@cero-base/core/identity';
|
|
105
104
|
export { Handle, Ref, Local };
|
|
106
|
-
export { put, set, get, del, count, watch, call, open, before, after } from "./lib/operators.js";
|
|
105
|
+
export { put, set, get, del, count, watch, call, open, before, after, bind, define, peek } from "./lib/operators.js";
|
|
107
106
|
export { t, schema } from "./lib/spec.js";
|
package/types/lib/operators.d.ts
CHANGED
|
@@ -1,3 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quickly check whether the on-disk directory at `dir` already holds an
|
|
3
|
+
* initialised cero identity (i.e. a stored master seed). Opens the local store
|
|
4
|
+
* read-only and closes everything before returning.
|
|
5
|
+
*
|
|
6
|
+
* @param {string} dir Cero data directory.
|
|
7
|
+
* @param {any} spec Built spec — same value passed to `cero(dir, spec)`.
|
|
8
|
+
* @returns {Promise<boolean>} `true` if a master seed exists on disk.
|
|
9
|
+
*/
|
|
10
|
+
export function peek(dir: string, spec: any): Promise<boolean>;
|
|
11
|
+
/**
|
|
12
|
+
* Put custom operators on `handle`, currying it as their first argument so
|
|
13
|
+
* `handle.ns.fn(args)` calls `fn(handle, args)`. `arg` is either:
|
|
14
|
+
* - a `{ ns: module }` map → bind exactly those, or
|
|
15
|
+
* - `null` → the registered root operators, or
|
|
16
|
+
* - a child-handle type → the registered operators for that type.
|
|
17
|
+
* The scope forms are how cero binds handles automatically; pass a map yourself
|
|
18
|
+
* for manual binding.
|
|
19
|
+
*
|
|
20
|
+
* @param {any} handle
|
|
21
|
+
* @param {Record<string, any> | string | null} arg
|
|
22
|
+
* @returns {any} handle
|
|
23
|
+
*/
|
|
24
|
+
export function bind(handle: any, arg: Record<string, any> | string | null): any;
|
|
25
|
+
/**
|
|
26
|
+
* Register custom operators by scope. A bare key binds on the root handle; a key
|
|
27
|
+
* that names a child-handle type binds on every handle of that type. Call once
|
|
28
|
+
* at startup, before `cero()` / `connect()`, in both processes.
|
|
29
|
+
*
|
|
30
|
+
* @param {Record<string, any>} map
|
|
31
|
+
*/
|
|
32
|
+
export function define(map: Record<string, any>): void;
|
|
33
|
+
/** Test seam: clear all registered operators. */
|
|
34
|
+
export function _clearDefined(): void;
|
|
1
35
|
export function put(ref: Ref, row: Record<string, any>): Promise<SingleResult>;
|
|
2
36
|
export function set(ref: Ref, row: Record<string, any>, opts?: {
|
|
3
37
|
upsert?: boolean;
|
package/src/lib/peek.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import HypercoreStorage from 'hypercore-storage'
|
|
2
|
-
import Corestore from 'corestore'
|
|
3
|
-
|
|
4
|
-
import { CeroError } from '@cero-base/core/errors'
|
|
5
|
-
|
|
6
|
-
import { Local } from '../local/index.js'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Quickly check whether the on-disk directory at `dir` already holds an
|
|
10
|
-
* initialised cero identity (i.e. a stored master seed). Opens the local
|
|
11
|
-
* store read-only and closes everything before returning.
|
|
12
|
-
*
|
|
13
|
-
* @param {string} dir Cero data directory.
|
|
14
|
-
* @param {any} spec Built spec — same value passed to `cero(dir, spec)`.
|
|
15
|
-
* @returns {Promise<boolean>} `true` if a master seed exists on disk.
|
|
16
|
-
*/
|
|
17
|
-
export async function peek(dir, spec) {
|
|
18
|
-
if (typeof dir !== 'string' || !dir) throw CeroError.INVALID('dir must be a non-empty string')
|
|
19
|
-
if (!spec) throw CeroError.REQUIRED('spec')
|
|
20
|
-
|
|
21
|
-
const root = new HypercoreStorage(`${dir}/main`)
|
|
22
|
-
await root.ready()
|
|
23
|
-
const store = new Corestore(root, { manifestVersion: 2 })
|
|
24
|
-
await store.ready()
|
|
25
|
-
|
|
26
|
-
const local = new Local(null, spec, { store })
|
|
27
|
-
await local.ready()
|
|
28
|
-
try {
|
|
29
|
-
const { data } = await local.store.get('master')
|
|
30
|
-
return !!data?.seed
|
|
31
|
-
} finally {
|
|
32
|
-
await local.close()
|
|
33
|
-
await store.close()
|
|
34
|
-
await root.close()
|
|
35
|
-
}
|
|
36
|
-
}
|
package/types/lib/peek.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Quickly check whether the on-disk directory at `dir` already holds an
|
|
3
|
-
* initialised cero identity (i.e. a stored master seed). Opens the local
|
|
4
|
-
* store read-only and closes everything before returning.
|
|
5
|
-
*
|
|
6
|
-
* @param {string} dir Cero data directory.
|
|
7
|
-
* @param {any} spec Built spec — same value passed to `cero(dir, spec)`.
|
|
8
|
-
* @returns {Promise<boolean>} `true` if a master seed exists on disk.
|
|
9
|
-
*/
|
|
10
|
-
export function peek(dir: string, spec: any): Promise<boolean>;
|