@cero-base/cero 0.8.9 → 1.0.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/README.md +88 -18
- package/package.json +20 -10
- package/src/build/builtins.js +10 -3
- package/src/build/index.js +24 -4
- package/src/build/schemas.js +20 -1
- package/src/handle/index.js +178 -69
- package/src/index.js +85 -64
- package/src/lib/constants.js +2 -1
- package/src/lib/operators.js +114 -53
- package/src/lib/peek.js +42 -0
- package/src/lib/utils.js +16 -3
- package/src/rpc/client.js +128 -14
- package/src/rpc/server.js +54 -7
- package/types/build/builtins.d.ts +5 -1
- package/types/build/index.d.ts +4 -21
- package/types/build/schemas.d.ts +19 -0
- package/types/handle/index.d.ts +49 -8
- package/types/index.d.ts +10 -5
- package/types/lib/constants.d.ts +1 -0
- package/types/lib/operators.d.ts +30 -10
- package/types/lib/peek.d.ts +10 -0
- package/types/lib/utils.d.ts +6 -3
- package/types/rpc/client.d.ts +3 -1
- package/types/rpc/server.d.ts +6 -5
package/src/rpc/server.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RPCServer, bindCodec } from '@cero-base/core/rpc'
|
|
2
2
|
import { CeroError } from '@cero-base/core/errors'
|
|
3
|
+
import { encodeId } from '@cero-base/core/blobs/codec'
|
|
3
4
|
|
|
4
5
|
import { cero, restore } from '../index.js'
|
|
5
6
|
import { put, set, get, del, count, watch, call } from '../lib/operators.js'
|
|
@@ -18,7 +19,6 @@ import { put, set, get, del, count, watch, call } from '../lib/operators.js'
|
|
|
18
19
|
* @typedef {object} Identity
|
|
19
20
|
* @property {string} id Long-lived cero identity id.
|
|
20
21
|
* @property {string} deviceId Per-device id (empty when no `local` spec).
|
|
21
|
-
* @property {string|null} phrase BIP39 recovery phrase for the identity.
|
|
22
22
|
*
|
|
23
23
|
* @typedef {{ ref: any, codec: any }} RefAndCodec
|
|
24
24
|
*
|
|
@@ -45,9 +45,19 @@ export class Server extends RPCServer {
|
|
|
45
45
|
this.opts = opts
|
|
46
46
|
this.me = null
|
|
47
47
|
this.handles = new Map()
|
|
48
|
+
/** @type {Map<string, Set<object>>} handle id → its open watch streams */
|
|
49
|
+
this._watchStreams = new Map()
|
|
48
50
|
this._wireInit()
|
|
49
51
|
}
|
|
50
52
|
|
|
53
|
+
/** End every watch stream bound to a handle (e.g. when it closes or leaves). */
|
|
54
|
+
_endWatches(handle) {
|
|
55
|
+
const set = this._watchStreams.get(handle)
|
|
56
|
+
if (!set) return
|
|
57
|
+
for (const s of set) s.destroy()
|
|
58
|
+
this._watchStreams.delete(handle)
|
|
59
|
+
}
|
|
60
|
+
|
|
51
61
|
/**
|
|
52
62
|
* Root cero id (null until `init` has run).
|
|
53
63
|
*
|
|
@@ -81,10 +91,12 @@ export class Server extends RPCServer {
|
|
|
81
91
|
if (this.me) throw new CeroError('CONFLICT', 'already initialized')
|
|
82
92
|
this.me = await cero(this.storage, this.spec, this.opts)
|
|
83
93
|
this.handles.set(this.me.id, this.me)
|
|
94
|
+
await this.me.fileServer.listen()
|
|
84
95
|
this._wireData()
|
|
85
96
|
this._wirePairing()
|
|
86
97
|
this._wireHandles()
|
|
87
98
|
this._wireRestore()
|
|
99
|
+
this._wireSeed()
|
|
88
100
|
return this._identity()
|
|
89
101
|
})
|
|
90
102
|
}
|
|
@@ -101,16 +113,28 @@ export class Server extends RPCServer {
|
|
|
101
113
|
|
|
102
114
|
/** Register the row-level RPC handlers (put/set/get/del/count/watch/call). */
|
|
103
115
|
_wireData() {
|
|
116
|
+
this.rpc.onAddFile(async ({ handle, data, name, type }) => {
|
|
117
|
+
const h = this._resolve(handle)
|
|
118
|
+
await h.blobs.ready()
|
|
119
|
+
const blobId = await h.blobs.put(data)
|
|
120
|
+
const id = encodeId(h.blobs.key, blobId, type || '')
|
|
121
|
+
const codec = h.spec.codec
|
|
122
|
+
await h.store.call('add-file', { id, name: name || null })
|
|
123
|
+
const { data: row } = await get(h.files, id)
|
|
124
|
+
return { data: codec.encodeRow(h.files.schema, row) }
|
|
125
|
+
})
|
|
126
|
+
|
|
104
127
|
this.rpc.onAddRow(async ({ handle, ref, data, local }) => {
|
|
105
128
|
const { ref: r, codec } = this._refOf(handle, ref, local)
|
|
106
129
|
const { data: row } = await put(r, codec.decodeRow(r.schema, data))
|
|
107
130
|
return { data: codec.encodeRow(r.schema, row) }
|
|
108
131
|
})
|
|
109
132
|
|
|
110
|
-
this.rpc.onSet(async ({ handle, ref, data, local }) => {
|
|
133
|
+
this.rpc.onSet(async ({ handle, ref, data, local, noUpsert }) => {
|
|
111
134
|
const { ref: r, codec } = this._refOf(handle, ref, local)
|
|
112
|
-
const
|
|
113
|
-
|
|
135
|
+
const result = await set(r, codec.decodeRow(r.schema, data), { upsert: !noUpsert })
|
|
136
|
+
// an update-only miss returns null — encode an empty row back
|
|
137
|
+
return { data: codec.encodeRow(r.schema, result?.data ?? null) }
|
|
114
138
|
})
|
|
115
139
|
|
|
116
140
|
this.rpc.onGet(async ({ handle, ref, query, local }) => {
|
|
@@ -147,7 +171,12 @@ export class Server extends RPCServer {
|
|
|
147
171
|
;({ ref: r, codec } = this._refOf(handle, ref, local))
|
|
148
172
|
live = watch(r, codec.decodeQuery(query))
|
|
149
173
|
} catch (err) {
|
|
150
|
-
|
|
174
|
+
// Forward the error to the client over the wire by destroying the
|
|
175
|
+
// underlying response stream with it (emits a CLOSE|ERROR frame). The
|
|
176
|
+
// local RPCStream's 'error' is swallowed so it doesn't crash the server.
|
|
177
|
+
stream.once('error', () => {})
|
|
178
|
+
stream.writeStream.destroy(err)
|
|
179
|
+
stream.destroy()
|
|
151
180
|
return
|
|
152
181
|
}
|
|
153
182
|
const onData = (snap) => {
|
|
@@ -157,10 +186,14 @@ export class Server extends RPCServer {
|
|
|
157
186
|
: codec.encodeRows(r.schema, snap.data)
|
|
158
187
|
stream.write({ data, total: snap.total ?? 0, size: snap.size ?? 0 })
|
|
159
188
|
}
|
|
189
|
+
let set = this._watchStreams.get(handle)
|
|
190
|
+
if (!set) this._watchStreams.set(handle, (set = new Set()))
|
|
191
|
+
set.add(stream)
|
|
160
192
|
live.on('data', onData)
|
|
161
193
|
stream.on('close', () => {
|
|
162
194
|
live.off('data', onData)
|
|
163
195
|
live.destroy()
|
|
196
|
+
this._watchStreams.get(handle)?.delete(stream)
|
|
164
197
|
})
|
|
165
198
|
})
|
|
166
199
|
|
|
@@ -201,7 +234,9 @@ export class Server extends RPCServer {
|
|
|
201
234
|
const parent = this._resolve(handle)
|
|
202
235
|
const info = parent.spec.meta.refs?.[ref] || parent.spec.handles?.[ref]
|
|
203
236
|
if (!info) throw CeroError.UNKNOWN('handle type', ref)
|
|
204
|
-
const
|
|
237
|
+
const wire = parent.spec.codec.decodeCreate(data) || {}
|
|
238
|
+
// routes can't cross the wire (functions) — both sides register them via define()
|
|
239
|
+
const opts = { name: wire.name, role: wire.role, accept: wire.noAccept ? false : undefined }
|
|
205
240
|
const child = await this.me._create(ref, opts)
|
|
206
241
|
const id = child.id
|
|
207
242
|
this.handles.set(id, child)
|
|
@@ -220,6 +255,7 @@ export class Server extends RPCServer {
|
|
|
220
255
|
this.rpc.onCloseHandle(async ({ handle }) => {
|
|
221
256
|
const h = this.handles.get(handle)
|
|
222
257
|
if (!h || h === this.me) return {}
|
|
258
|
+
this._endWatches(handle)
|
|
223
259
|
this.handles.delete(handle)
|
|
224
260
|
await h.close()
|
|
225
261
|
return {}
|
|
@@ -228,6 +264,7 @@ export class Server extends RPCServer {
|
|
|
228
264
|
this.rpc.onLeave(async ({ handle }) => {
|
|
229
265
|
const h = this.handles.get(handle)
|
|
230
266
|
if (!h || h === this.me) return {}
|
|
267
|
+
this._endWatches(handle)
|
|
231
268
|
await this.me.store.call('del-handle', { id: handle })
|
|
232
269
|
this.handles.delete(handle)
|
|
233
270
|
await h.close()
|
|
@@ -279,12 +316,22 @@ export class Server extends RPCServer {
|
|
|
279
316
|
* @returns {Identity}
|
|
280
317
|
*/
|
|
281
318
|
_identity() {
|
|
319
|
+
const fs = this.me.fileServer
|
|
282
320
|
return {
|
|
283
321
|
id: this.me.id,
|
|
284
322
|
deviceId: this.me.device?.id || '',
|
|
285
|
-
|
|
323
|
+
fileBase: `http://127.0.0.1:${fs.port}`,
|
|
324
|
+
fileToken: fs.server.token || ''
|
|
286
325
|
}
|
|
287
326
|
}
|
|
327
|
+
|
|
328
|
+
/** Wire the on-demand `seed` handler — surfaces the recovery phrase only when asked. */
|
|
329
|
+
_wireSeed() {
|
|
330
|
+
this.rpc.onSeed(async () => {
|
|
331
|
+
if (!this.me) throw new CeroError('NOT_READY', 'init')
|
|
332
|
+
return { phrase: this.me.identity.toPhrase() }
|
|
333
|
+
})
|
|
334
|
+
}
|
|
288
335
|
}
|
|
289
336
|
|
|
290
337
|
/**
|
|
@@ -15,6 +15,10 @@ export namespace refs {
|
|
|
15
15
|
let type_3: string;
|
|
16
16
|
export { type_3 as type };
|
|
17
17
|
}
|
|
18
|
+
namespace files {
|
|
19
|
+
let type_4: string;
|
|
20
|
+
export { type_4 as type };
|
|
21
|
+
}
|
|
18
22
|
}
|
|
19
23
|
let local: {
|
|
20
24
|
master: {
|
|
@@ -30,7 +34,7 @@ export namespace refs {
|
|
|
30
34
|
};
|
|
31
35
|
};
|
|
32
36
|
}
|
|
33
|
-
export function
|
|
37
|
+
export function getHyperdbType(prim: any): any;
|
|
34
38
|
export function builtinRefs(ns: any, scope: any): {
|
|
35
39
|
[k: string]: {
|
|
36
40
|
schema: string;
|
package/types/build/index.d.ts
CHANGED
|
@@ -1,24 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
* @typedef {object} BuildOpts
|
|
7
|
-
* @property {string} [ns] Namespace prefix for emitted schema ids. Defaults to `'cero'`.
|
|
8
|
-
*/
|
|
9
|
-
/**
|
|
10
|
-
* Compile a cero schema into wire-level artifacts and write them to disk.
|
|
11
|
-
*
|
|
12
|
-
* Emits a `main/` tree (schema + hyperdb + dispatch + rpc), a `local/` tree
|
|
13
|
-
* for per-device data, one `handles/<name>/` tree per child handle type, and
|
|
14
|
-
* an `index.js` that re-exports a ready-to-use `spec` object.
|
|
15
|
-
*
|
|
16
|
-
* @param {string} specDir Output directory.
|
|
17
|
-
* @param {SchemaInput} schema Either a `schema(...)` wrapper or its raw defs object.
|
|
18
|
-
* @param {BuildOpts} [opts]
|
|
19
|
-
* @returns {Promise<void>}
|
|
20
|
-
*/
|
|
21
|
-
export function build(specDir: string, schema: SchemaInput, { ns }?: BuildOpts): Promise<void>;
|
|
1
|
+
export function build(specDir: any, schema: any, { ns }?: {
|
|
2
|
+
ns?: string;
|
|
3
|
+
}): Promise<void>;
|
|
4
|
+
export { getHyperdbType } from "./builtins.js";
|
|
22
5
|
export type Schema = import("@cero-base/core/schema").Schema;
|
|
23
6
|
export type SchemaDefs = import("@cero-base/core/schema").SchemaDefs;
|
|
24
7
|
export type SchemaInput = Schema | (SchemaDefs & {
|
package/types/build/schemas.d.ts
CHANGED
|
@@ -52,6 +52,14 @@ export const main: {
|
|
|
52
52
|
updatedAt: import("@cero-base/core").Prim;
|
|
53
53
|
index: import("@cero-base/core").Prim;
|
|
54
54
|
};
|
|
55
|
+
file: {
|
|
56
|
+
id: import("@cero-base/core").Prim;
|
|
57
|
+
memberId: import("@cero-base/core").Prim;
|
|
58
|
+
name: import("@cero-base/core").Prim;
|
|
59
|
+
createdAt: import("@cero-base/core").Prim;
|
|
60
|
+
updatedAt: import("@cero-base/core").Prim;
|
|
61
|
+
index: import("@cero-base/core").Prim;
|
|
62
|
+
};
|
|
55
63
|
claim: {
|
|
56
64
|
identity: import("@cero-base/core").Prim;
|
|
57
65
|
writer: import("@cero-base/core").Prim;
|
|
@@ -85,6 +93,7 @@ export const rpc: {
|
|
|
85
93
|
ref: import("@cero-base/core").Prim;
|
|
86
94
|
data: import("@cero-base/core").Prim;
|
|
87
95
|
local: import("@cero-base/core").Prim;
|
|
96
|
+
noUpsert: import("@cero-base/core").Prim;
|
|
88
97
|
};
|
|
89
98
|
'req-id': {
|
|
90
99
|
handle: import("@cero-base/core").Prim;
|
|
@@ -142,9 +151,19 @@ export const rpc: {
|
|
|
142
151
|
type: import("@cero-base/core").Prim;
|
|
143
152
|
name: import("@cero-base/core").Prim;
|
|
144
153
|
};
|
|
154
|
+
'req-add-file': {
|
|
155
|
+
handle: import("@cero-base/core").Prim;
|
|
156
|
+
data: import("@cero-base/core").Prim;
|
|
157
|
+
name: import("@cero-base/core").Prim;
|
|
158
|
+
type: import("@cero-base/core").Prim;
|
|
159
|
+
};
|
|
145
160
|
'res-identity': {
|
|
146
161
|
id: import("@cero-base/core").Prim;
|
|
147
162
|
deviceId: import("@cero-base/core").Prim;
|
|
163
|
+
fileBase: import("@cero-base/core").Prim;
|
|
164
|
+
fileToken: import("@cero-base/core").Prim;
|
|
165
|
+
};
|
|
166
|
+
'res-seed': {
|
|
148
167
|
phrase: import("@cero-base/core").Prim;
|
|
149
168
|
};
|
|
150
169
|
'res-ok': {
|
package/types/handle/index.d.ts
CHANGED
|
@@ -43,7 +43,7 @@ export { Ref } from "../lib/utils.js";
|
|
|
43
43
|
* @property {number} [timeout]
|
|
44
44
|
*
|
|
45
45
|
* @typedef {object} AcceptOpts
|
|
46
|
-
* @property {string} [role] Role to grant the joining peer. Falls back to the invite's role, then `'
|
|
46
|
+
* @property {string} [role] Role to grant the joining peer. Falls back to the invite's role, then `'member'`.
|
|
47
47
|
* @property {string | null} [name]
|
|
48
48
|
*
|
|
49
49
|
* @typedef {object} RecoverOpts
|
|
@@ -55,6 +55,8 @@ export { Ref } from "../lib/utils.js";
|
|
|
55
55
|
* @property {import('../lib/utils.js').Ref} [members] `members` ref, attached dynamically when the schema declares one.
|
|
56
56
|
*
|
|
57
57
|
* @typedef {Handle & HandleExtra} Child A child handle plus its dynamically-attached refs.
|
|
58
|
+
*
|
|
59
|
+
* @typedef {Handle & Record<string, import('../lib/utils.js').Ref>} CeroHandle A handle with every schema ref reachable as a `Ref` property (e.g. `me.profile`, `room.messages`).
|
|
58
60
|
*/
|
|
59
61
|
/**
|
|
60
62
|
* A cero handle — a single writable database session attached to a swarm.
|
|
@@ -87,6 +89,9 @@ export class Handle extends ReadyResource {
|
|
|
87
89
|
_onerror: any;
|
|
88
90
|
children: Set<any>;
|
|
89
91
|
_loading: Map<any, any>;
|
|
92
|
+
_coreKeys: Map<any, any>;
|
|
93
|
+
_fileServer: FileServer;
|
|
94
|
+
_blobs: Blobs;
|
|
90
95
|
_owned: Set<any>;
|
|
91
96
|
store: Database;
|
|
92
97
|
pair: Pairing;
|
|
@@ -125,6 +130,40 @@ export class Handle extends ReadyResource {
|
|
|
125
130
|
on(event: string, fn: (...args: any[]) => void, opts?: {
|
|
126
131
|
signal?: AbortSignal;
|
|
127
132
|
}): this;
|
|
133
|
+
/** The top-most handle in the parent chain — itself for a root handle. */
|
|
134
|
+
get root(): this;
|
|
135
|
+
/**
|
|
136
|
+
* Lazily-built file server for this identity. Root-only — child handles
|
|
137
|
+
* reach it through `this.root.fileServer`.
|
|
138
|
+
*
|
|
139
|
+
* @returns {FileServer}
|
|
140
|
+
*/
|
|
141
|
+
get fileServer(): FileServer;
|
|
142
|
+
/**
|
|
143
|
+
* @param {Uint8Array} coreKey
|
|
144
|
+
* @param {object} info
|
|
145
|
+
* @returns {{ key: Uint8Array, encryptionKey: Uint8Array } | null}
|
|
146
|
+
*/
|
|
147
|
+
_resolveCore(coreKey: Uint8Array, info: object): {
|
|
148
|
+
key: Uint8Array;
|
|
149
|
+
encryptionKey: Uint8Array;
|
|
150
|
+
} | null;
|
|
151
|
+
/**
|
|
152
|
+
* Resolve a durable file id to an ephemeral download url via this identity's
|
|
153
|
+
* file server.
|
|
154
|
+
*
|
|
155
|
+
* @param {string} id
|
|
156
|
+
* @returns {string}
|
|
157
|
+
*/
|
|
158
|
+
getLink(id: string): string;
|
|
159
|
+
/**
|
|
160
|
+
* Lazily-built blob store for THIS handle's writing device. One core per
|
|
161
|
+
* writer, encrypted with the handle's encryptionKey and attached to the
|
|
162
|
+
* shared network for replication.
|
|
163
|
+
*
|
|
164
|
+
* @returns {Blobs}
|
|
165
|
+
*/
|
|
166
|
+
get blobs(): Blobs;
|
|
128
167
|
/** Canonical id — identity id for the root handle, store key for children. */
|
|
129
168
|
get id(): any;
|
|
130
169
|
/** This device's id + name. `null` on child handles. */
|
|
@@ -145,13 +184,9 @@ export class Handle extends ReadyResource {
|
|
|
145
184
|
* Claim writer capability on an existing database (paired-device flow).
|
|
146
185
|
* Forwards to `Database.claim`.
|
|
147
186
|
*
|
|
148
|
-
* @param {{ name?: string | null, isMobile?: boolean }} [opts]
|
|
149
187
|
* @returns {Promise<void>}
|
|
150
188
|
*/
|
|
151
|
-
claim(
|
|
152
|
-
name?: string | null;
|
|
153
|
-
isMobile?: boolean;
|
|
154
|
-
}): Promise<void>;
|
|
189
|
+
claim(): Promise<void>;
|
|
155
190
|
/**
|
|
156
191
|
* Claim + wait until this peer becomes a writer + bring the bee up to date.
|
|
157
192
|
* Used by `restore()` after wiping local state.
|
|
@@ -360,7 +395,7 @@ export type StaticJoinOpts = {
|
|
|
360
395
|
};
|
|
361
396
|
export type AcceptOpts = {
|
|
362
397
|
/**
|
|
363
|
-
* Role to grant the joining peer. Falls back to the invite's role, then `'
|
|
398
|
+
* Role to grant the joining peer. Falls back to the invite's role, then `'member'`.
|
|
364
399
|
*/
|
|
365
400
|
role?: string;
|
|
366
401
|
name?: string | null;
|
|
@@ -386,8 +421,14 @@ export type HandleExtra = {
|
|
|
386
421
|
* A child handle plus its dynamically-attached refs.
|
|
387
422
|
*/
|
|
388
423
|
export type Child = Handle & HandleExtra;
|
|
424
|
+
/**
|
|
425
|
+
* A handle with every schema ref reachable as a `Ref` property (e.g. `me.profile`, `room.messages`).
|
|
426
|
+
*/
|
|
427
|
+
export type CeroHandle = Handle & Record<string, import("../lib/utils.js").Ref>;
|
|
389
428
|
import ReadyResource from 'ready-resource';
|
|
429
|
+
import { FileServer } from '@cero-base/core/blobs/server';
|
|
430
|
+
import { Blobs } from '@cero-base/core/blobs';
|
|
390
431
|
import { Database } from '@cero-base/core/database';
|
|
391
432
|
import { Pairing } from '@cero-base/core/pairing';
|
|
392
|
-
import AbortController from 'abort-controller';
|
|
433
|
+
import AbortController from 'bare-abort-controller';
|
|
393
434
|
import { Identity } from '@cero-base/core/identity';
|
package/types/index.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('./handle/index.js').CeroHandle} CeroHandle
|
|
3
|
+
*/
|
|
1
4
|
/**
|
|
2
5
|
* @typedef {object} CeroOpts
|
|
3
6
|
* @property {Identity} [identity] Pre-resolved identity. If absent, derived from `seed`/`phrase` or generated.
|
|
@@ -22,9 +25,9 @@
|
|
|
22
25
|
* @param {string} dir Data directory.
|
|
23
26
|
* @param {any} spec Built spec — output of `cero/build`.
|
|
24
27
|
* @param {CeroOpts} [opts]
|
|
25
|
-
* @returns {Promise<
|
|
28
|
+
* @returns {Promise<CeroHandle>}
|
|
26
29
|
*/
|
|
27
|
-
export function cero(dir: string, spec: any, opts?: CeroOpts): Promise<
|
|
30
|
+
export function cero(dir: string, spec: any, opts?: CeroOpts): Promise<CeroHandle>;
|
|
28
31
|
export namespace cero {
|
|
29
32
|
export { t };
|
|
30
33
|
export { put };
|
|
@@ -55,6 +58,8 @@ export namespace cero {
|
|
|
55
58
|
* @returns {Promise<Handle>} Freshly restored root handle.
|
|
56
59
|
*/
|
|
57
60
|
export function restore(me: Handle, phrase: string): Promise<Handle>;
|
|
61
|
+
export { peek } from "./lib/peek.js";
|
|
62
|
+
export type CeroHandle = import("./handle/index.js").CeroHandle;
|
|
58
63
|
export type CeroOpts = {
|
|
59
64
|
/**
|
|
60
65
|
* Pre-resolved identity. If absent, derived from `seed`/`phrase` or generated.
|
|
@@ -112,7 +117,6 @@ export type CeroOpts = {
|
|
|
112
117
|
*/
|
|
113
118
|
recoveryTimeout?: number;
|
|
114
119
|
};
|
|
115
|
-
import { Handle } from './handle/index.js';
|
|
116
120
|
import { t } from './lib/spec.js';
|
|
117
121
|
import { put } from './lib/operators.js';
|
|
118
122
|
import { set } from './lib/operators.js';
|
|
@@ -124,14 +128,15 @@ import { call } from './lib/operators.js';
|
|
|
124
128
|
import { open } from './lib/operators.js';
|
|
125
129
|
import { before } from './lib/operators.js';
|
|
126
130
|
import { after } from './lib/operators.js';
|
|
127
|
-
import { peek } from './lib/
|
|
131
|
+
import { peek } from './lib/peek.js';
|
|
128
132
|
import { schema } from './lib/spec.js';
|
|
129
133
|
import { bind } from './lib/operators.js';
|
|
130
134
|
import { define } from './lib/operators.js';
|
|
131
135
|
import { internal } from './lib/internal.js';
|
|
136
|
+
import { Handle } from './handle/index.js';
|
|
132
137
|
import { Ref } from './handle/index.js';
|
|
133
138
|
import { Local } from './local/index.js';
|
|
134
139
|
import { Identity } from '@cero-base/core/identity';
|
|
135
140
|
export { Handle, Ref, Local };
|
|
136
|
-
export { put, set, get, del, count, watch, call, open, before, after, bind, define
|
|
141
|
+
export { put, set, get, del, count, watch, call, open, before, after, bind, define } from "./lib/operators.js";
|
|
137
142
|
export { t, schema } from "./lib/spec.js";
|
package/types/lib/constants.d.ts
CHANGED
package/types/lib/operators.d.ts
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* @typedef {import('./utils.js').Ref} Ref
|
|
3
|
+
* @typedef {import('../handle/index.js').CeroHandle} CeroHandle
|
|
4
|
+
* @typedef {{ data: any }} SingleResult
|
|
5
|
+
* @typedef {{ data: any[], total: number, size: number }} ListResult
|
|
6
|
+
* @typedef {{ data: any | null }} GetByIdResult
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Resolve a durable file id (+ optional name) to the read shape returned
|
|
10
|
+
* everywhere: `{ id, name?, type, size, url }`.
|
|
5
11
|
*
|
|
6
|
-
* @param {
|
|
7
|
-
* @param {
|
|
8
|
-
* @
|
|
12
|
+
* @param {object} handle
|
|
13
|
+
* @param {string} id
|
|
14
|
+
* @param {string} [name]
|
|
15
|
+
* @returns {{ id: string, type: string, size: number, url: string, name?: string }}
|
|
9
16
|
*/
|
|
10
|
-
export function
|
|
17
|
+
export function resolveFile(handle: object, id: string, name?: string): {
|
|
18
|
+
id: string;
|
|
19
|
+
type: string;
|
|
20
|
+
size: number;
|
|
21
|
+
url: string;
|
|
22
|
+
name?: string;
|
|
23
|
+
};
|
|
11
24
|
/**
|
|
12
25
|
* Put custom operators on `handle`, currying it as their first argument so
|
|
13
26
|
* `handle.ns.fn(args)` calls `fn(handle, args)`. `arg` is either:
|
|
@@ -32,7 +45,13 @@ export function bind(handle: any, arg: Record<string, any> | string | null): any
|
|
|
32
45
|
export function define(map: Record<string, any>): void;
|
|
33
46
|
/** Test seam: clear all registered operators. */
|
|
34
47
|
export function _clearDefined(): void;
|
|
35
|
-
export function put(ref: Ref, row: Record<string, any>): Promise<SingleResult
|
|
48
|
+
export function put(ref: Ref, row: Record<string, any>): Promise<SingleResult | {
|
|
49
|
+
id: string;
|
|
50
|
+
name?: string;
|
|
51
|
+
type: string;
|
|
52
|
+
size: number;
|
|
53
|
+
url: string;
|
|
54
|
+
}>;
|
|
36
55
|
export function set(ref: Ref, row: Record<string, any>, opts?: {
|
|
37
56
|
upsert?: boolean;
|
|
38
57
|
}): Promise<SingleResult>;
|
|
@@ -58,7 +77,7 @@ export function after(ref: Ref, fn: (ctx: {
|
|
|
58
77
|
export function get(ref: Ref, q?: string | Record<string, any>): Promise<SingleResult | ListResult | GetByIdResult>;
|
|
59
78
|
export function watch(ref: Ref, q?: Record<string, any>, opts?: {
|
|
60
79
|
signal?: AbortSignal;
|
|
61
|
-
}):
|
|
80
|
+
}): import("streamx").Readable;
|
|
62
81
|
export function open(ref: Ref, arg?: string | {
|
|
63
82
|
invite?: string;
|
|
64
83
|
id?: string;
|
|
@@ -66,8 +85,9 @@ export function open(ref: Ref, arg?: string | {
|
|
|
66
85
|
routes?: any;
|
|
67
86
|
role?: string;
|
|
68
87
|
accept?: boolean;
|
|
69
|
-
} | undefined): Promise<
|
|
88
|
+
} | undefined): Promise<CeroHandle>;
|
|
70
89
|
export type Ref = import("./utils.js").Ref;
|
|
90
|
+
export type CeroHandle = import("../handle/index.js").CeroHandle;
|
|
71
91
|
export type SingleResult = {
|
|
72
92
|
data: any;
|
|
73
93
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
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>;
|
package/types/lib/utils.d.ts
CHANGED
|
@@ -9,12 +9,15 @@
|
|
|
9
9
|
export function attachRefs(target: any, refs: Record<string, RefInfo>): void;
|
|
10
10
|
/**
|
|
11
11
|
* Run `cb` when `signal` aborts — or immediately if it already has. No-op
|
|
12
|
-
* without a signal. The listener removes itself on fire.
|
|
12
|
+
* without a signal. The listener removes itself on fire. Returns a disposer that
|
|
13
|
+
* detaches the listener early, so a manual unsubscribe doesn't leave it lingering
|
|
14
|
+
* on a long-lived signal.
|
|
13
15
|
*
|
|
14
|
-
* @param {AbortSignal}
|
|
16
|
+
* @param {AbortSignal | undefined} signal
|
|
15
17
|
* @param {() => void} cb
|
|
18
|
+
* @returns {(() => void) | undefined}
|
|
16
19
|
*/
|
|
17
|
-
export function onAbort(signal
|
|
20
|
+
export function onAbort(signal: AbortSignal | undefined, cb: () => void): (() => void) | undefined;
|
|
18
21
|
/**
|
|
19
22
|
* @typedef {'collection' | 'single' | 'action' | 'handle'} RefKind
|
|
20
23
|
* @typedef {{ kind?: string, schema?: string }} RefInfo
|
package/types/rpc/client.d.ts
CHANGED
|
@@ -60,9 +60,11 @@ export class Client extends RPCClient {
|
|
|
60
60
|
deviceId: any;
|
|
61
61
|
store: this;
|
|
62
62
|
local: LocalRefs;
|
|
63
|
+
_fileBase: any;
|
|
64
|
+
_fileToken: any;
|
|
63
65
|
identity: {
|
|
64
66
|
id: any;
|
|
65
|
-
toPhrase: () => any
|
|
67
|
+
toPhrase: () => Promise<any>;
|
|
66
68
|
};
|
|
67
69
|
/**
|
|
68
70
|
* Create a new child handle of the given type.
|
package/types/rpc/server.d.ts
CHANGED
|
@@ -20,7 +20,6 @@ export function serve(ipc: any, opts: ServerOpts): Promise<Server>;
|
|
|
20
20
|
* @typedef {object} Identity
|
|
21
21
|
* @property {string} id Long-lived cero identity id.
|
|
22
22
|
* @property {string} deviceId Per-device id (empty when no `local` spec).
|
|
23
|
-
* @property {string|null} phrase BIP39 recovery phrase for the identity.
|
|
24
23
|
*
|
|
25
24
|
* @typedef {{ ref: any, codec: any }} RefAndCodec
|
|
26
25
|
*
|
|
@@ -56,6 +55,10 @@ export class Server extends RPCServer {
|
|
|
56
55
|
};
|
|
57
56
|
me: any;
|
|
58
57
|
handles: Map<any, any>;
|
|
58
|
+
/** @type {Map<string, Set<object>>} handle id → its open watch streams */
|
|
59
|
+
_watchStreams: Map<string, Set<object>>;
|
|
60
|
+
/** End every watch stream bound to a handle (e.g. when it closes or leaves). */
|
|
61
|
+
_endWatches(handle: any): void;
|
|
59
62
|
/**
|
|
60
63
|
* Root cero id (null until `init` has run).
|
|
61
64
|
*
|
|
@@ -103,6 +106,8 @@ export class Server extends RPCServer {
|
|
|
103
106
|
* @returns {Identity}
|
|
104
107
|
*/
|
|
105
108
|
_identity(): Identity;
|
|
109
|
+
/** Wire the on-demand `seed` handler — surfaces the recovery phrase only when asked. */
|
|
110
|
+
_wireSeed(): void;
|
|
106
111
|
}
|
|
107
112
|
export type BaseRPCServer = import("@cero-base/core/rpc").RPCServer;
|
|
108
113
|
export type ServerOpts = {
|
|
@@ -137,10 +142,6 @@ export type Identity = {
|
|
|
137
142
|
* Per-device id (empty when no `local` spec).
|
|
138
143
|
*/
|
|
139
144
|
deviceId: string;
|
|
140
|
-
/**
|
|
141
|
-
* BIP39 recovery phrase for the identity.
|
|
142
|
-
*/
|
|
143
|
-
phrase: string | null;
|
|
144
145
|
};
|
|
145
146
|
export type RefAndCodec = {
|
|
146
147
|
ref: any;
|