@cero-base/cero 0.5.2 → 0.7.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/README.md +98 -6
- package/package.json +11 -4
- package/src/build/builtins.js +137 -0
- package/src/{builder.js → build/index.js} +40 -34
- package/src/build/schemas.js +162 -0
- package/src/extensions/handle-sync.js +32 -0
- package/src/extensions/index.js +2 -0
- package/src/extensions/profile-sync.js +30 -0
- package/src/handle/index.js +15 -51
- package/src/index.js +31 -10
- package/src/lib/constants.js +20 -0
- package/src/lib/internal.js +3 -0
- package/src/lib/operators.js +41 -2
- package/types/build/builtins.d.ts +88 -0
- package/types/build/schemas.d.ts +153 -0
- package/types/extensions/handle-sync.d.ts +22 -0
- package/types/extensions/index.d.ts +2 -0
- package/types/extensions/profile-sync.d.ts +21 -0
- package/types/handle/index.d.ts +1 -7
- package/types/index.d.ts +6 -1
- package/types/lib/constants.d.ts +14 -0
- package/types/lib/internal.d.ts +3 -0
- package/types/lib/operators.d.ts +13 -1
- package/src/CLAUDE.md +0 -3
- package/src/handle/CLAUDE.md +0 -3
- package/src/lib/CLAUDE.md +0 -3
- package/src/lib/builtins.js +0 -413
- package/types/lib/builtins.d.ts +0 -141
- /package/types/{builder.d.ts → build/index.d.ts} +0 -0
package/src/handle/index.js
CHANGED
|
@@ -11,6 +11,8 @@ import { Pairing } from '@cero-base/core/pairing'
|
|
|
11
11
|
import { toId } from '@cero-base/core/utils'
|
|
12
12
|
import { CeroError } from '@cero-base/core/errors'
|
|
13
13
|
|
|
14
|
+
import { NS, TIMEOUT } from '../lib/constants.js'
|
|
15
|
+
|
|
14
16
|
import { attachRefs } from '../lib/utils.js'
|
|
15
17
|
|
|
16
18
|
export { Ref } from '../lib/utils.js'
|
|
@@ -64,8 +66,6 @@ export { Ref } from '../lib/utils.js'
|
|
|
64
66
|
*
|
|
65
67
|
* @typedef {object} RecoverOpts
|
|
66
68
|
* @property {number} [timeout]
|
|
67
|
-
* @property {string | null} [name]
|
|
68
|
-
* @property {boolean} [isMobile]
|
|
69
69
|
*
|
|
70
70
|
* @typedef {object} HandleExtra
|
|
71
71
|
* @property {string | null} [name] Display name; set on child handles by the owner flow.
|
|
@@ -137,16 +137,9 @@ export class Handle extends ReadyResource {
|
|
|
137
137
|
await this.pair.ready()
|
|
138
138
|
}
|
|
139
139
|
attachRefs(this, this.store.refs)
|
|
140
|
-
if (!this.children) return
|
|
141
|
-
|
|
142
|
-
this._offUpdate = this.store.onUpdate(() => {
|
|
143
|
-
if (this.closing || this.closed) return
|
|
144
|
-
for (const c of this.children) this._syncMember(c).catch(this._onerror)
|
|
145
|
-
})
|
|
146
140
|
}
|
|
147
141
|
|
|
148
142
|
async _close() {
|
|
149
|
-
this._offUpdate?.()
|
|
150
143
|
if (this.children) {
|
|
151
144
|
for (const c of [...this.children]) await c.close()
|
|
152
145
|
this.children.clear()
|
|
@@ -214,9 +207,9 @@ export class Handle extends ReadyResource {
|
|
|
214
207
|
* @param {RecoverOpts} [opts]
|
|
215
208
|
* @returns {Promise<void>}
|
|
216
209
|
*/
|
|
217
|
-
async recover({ timeout =
|
|
210
|
+
async recover({ timeout = TIMEOUT } = {}) {
|
|
218
211
|
if (this.store.writable) return
|
|
219
|
-
await this.store.claim(
|
|
212
|
+
await this.store.claim()
|
|
220
213
|
await this.store.whenWritable({ timeout })
|
|
221
214
|
await this.store.bee.update()
|
|
222
215
|
}
|
|
@@ -281,9 +274,7 @@ export class Handle extends ReadyResource {
|
|
|
281
274
|
await this.store.call('add-writer', {
|
|
282
275
|
sig,
|
|
283
276
|
master: this.identity.publicKey,
|
|
284
|
-
writer: writerKey
|
|
285
|
-
name: name || null,
|
|
286
|
-
isMobile: false
|
|
277
|
+
writer: writerKey
|
|
287
278
|
})
|
|
288
279
|
await this.store.call('add-member', member)
|
|
289
280
|
})
|
|
@@ -316,7 +307,7 @@ export class Handle extends ReadyResource {
|
|
|
316
307
|
new Handle({
|
|
317
308
|
parent: this,
|
|
318
309
|
spec: pickHandle(this.spec, type),
|
|
319
|
-
namespace:
|
|
310
|
+
namespace: `${NS}/handle/${type}/${writer.id}`,
|
|
320
311
|
routes,
|
|
321
312
|
keyPair: writer
|
|
322
313
|
})
|
|
@@ -332,9 +323,7 @@ export class Handle extends ReadyResource {
|
|
|
332
323
|
await child.store.call('add-writer', {
|
|
333
324
|
master: this.identity.publicKey,
|
|
334
325
|
writer: writerKey,
|
|
335
|
-
sig: this.identity.sign(writerKey)
|
|
336
|
-
name,
|
|
337
|
-
isMobile: false
|
|
326
|
+
sig: this.identity.sign(writerKey)
|
|
338
327
|
})
|
|
339
328
|
await child.store.call('add-member', {
|
|
340
329
|
id: this.identity.id,
|
|
@@ -344,7 +333,6 @@ export class Handle extends ReadyResource {
|
|
|
344
333
|
createdAt: ts,
|
|
345
334
|
updatedAt: ts
|
|
346
335
|
})
|
|
347
|
-
if (name && child.profile) await child.store.set('profile', { name })
|
|
348
336
|
await this.store.call('add-handle', {
|
|
349
337
|
id,
|
|
350
338
|
type,
|
|
@@ -357,7 +345,7 @@ export class Handle extends ReadyResource {
|
|
|
357
345
|
|
|
358
346
|
if (accept !== false) this._wireAccept(child, { role })
|
|
359
347
|
this.children.add(child)
|
|
360
|
-
|
|
348
|
+
this.emit('handle', child, { name, role })
|
|
361
349
|
return child
|
|
362
350
|
}
|
|
363
351
|
|
|
@@ -372,7 +360,7 @@ export class Handle extends ReadyResource {
|
|
|
372
360
|
* @returns {Promise<Handle>}
|
|
373
361
|
*/
|
|
374
362
|
async _join(invite, type, { routes, timeout } = {}) {
|
|
375
|
-
const deadline = timeout ||
|
|
363
|
+
const deadline = timeout || TIMEOUT
|
|
376
364
|
|
|
377
365
|
// Idempotent: if the invite targets a handle we already have, return it —
|
|
378
366
|
// without pairing, so there's no waiting on a peer to confirm.
|
|
@@ -389,7 +377,7 @@ export class Handle extends ReadyResource {
|
|
|
389
377
|
await Handle.join(invite, {
|
|
390
378
|
parent: this,
|
|
391
379
|
spec: pickHandle(this.spec, type),
|
|
392
|
-
namespace:
|
|
380
|
+
namespace: `${NS}/handle/${type}/${randomNs()}`,
|
|
393
381
|
routes,
|
|
394
382
|
timeout
|
|
395
383
|
})
|
|
@@ -400,20 +388,19 @@ export class Handle extends ReadyResource {
|
|
|
400
388
|
const id = toId(child.store.key)
|
|
401
389
|
await this._saveKeyPair(id, child.store.keyPair)
|
|
402
390
|
|
|
403
|
-
const name = child.profile ? await waitForProfileName(child, deadline) : null
|
|
404
391
|
const ts = Date.now()
|
|
405
392
|
await this.store.call('add-handle', {
|
|
406
393
|
id,
|
|
407
394
|
type,
|
|
408
395
|
key: child.store.key,
|
|
409
396
|
encryptionKey: child.store.encryptionKey,
|
|
410
|
-
name,
|
|
397
|
+
name: null,
|
|
411
398
|
createdAt: ts,
|
|
412
399
|
updatedAt: ts
|
|
413
400
|
})
|
|
414
401
|
this._wireAccept(child)
|
|
415
402
|
this.children.add(child)
|
|
416
|
-
|
|
403
|
+
this.emit('handle', child, {})
|
|
417
404
|
return child
|
|
418
405
|
}
|
|
419
406
|
|
|
@@ -439,7 +426,7 @@ export class Handle extends ReadyResource {
|
|
|
439
426
|
const child = new Handle({
|
|
440
427
|
parent: this,
|
|
441
428
|
spec: pickHandle(this.spec, type),
|
|
442
|
-
namespace:
|
|
429
|
+
namespace: `${NS}/handle/${type}/${id}`,
|
|
443
430
|
key: data.key,
|
|
444
431
|
encryptionKey: data.encryptionKey,
|
|
445
432
|
keyPair: /** @type {KeyPair} */ (writer)
|
|
@@ -456,6 +443,7 @@ export class Handle extends ReadyResource {
|
|
|
456
443
|
}
|
|
457
444
|
this._wireAccept(child)
|
|
458
445
|
this.children.add(child)
|
|
446
|
+
this.emit('handle', child, {})
|
|
459
447
|
return child
|
|
460
448
|
}
|
|
461
449
|
|
|
@@ -503,7 +491,7 @@ export class Handle extends ReadyResource {
|
|
|
503
491
|
*/
|
|
504
492
|
static async join(
|
|
505
493
|
invite,
|
|
506
|
-
{ parent, network, identity, store, spec, namespace, routes, timeout =
|
|
494
|
+
{ parent, network, identity, store, spec, namespace, routes, timeout = TIMEOUT } = {}
|
|
507
495
|
) {
|
|
508
496
|
const net = network || parent?.network
|
|
509
497
|
const id = identity || parent?.identity
|
|
@@ -538,20 +526,6 @@ export class Handle extends ReadyResource {
|
|
|
538
526
|
})
|
|
539
527
|
}
|
|
540
528
|
|
|
541
|
-
async _syncMember(child) {
|
|
542
|
-
if (!child.store.writable) return
|
|
543
|
-
const { data: profile } = await this.store.get('profile')
|
|
544
|
-
if (!profile) return
|
|
545
|
-
const { data: existing } = await child.store.get('members', this.identity.id)
|
|
546
|
-
if (!existing) return
|
|
547
|
-
await child.store.call('set-member', {
|
|
548
|
-
...existing,
|
|
549
|
-
...profile,
|
|
550
|
-
id: existing.id,
|
|
551
|
-
updatedAt: Date.now()
|
|
552
|
-
})
|
|
553
|
-
}
|
|
554
|
-
|
|
555
529
|
/**
|
|
556
530
|
* @param {Handle} child
|
|
557
531
|
* @param {{ role?: string }} [opts]
|
|
@@ -601,13 +575,3 @@ function pickHandle(spec, type) {
|
|
|
601
575
|
function randomNs() {
|
|
602
576
|
return z32.encode(Identity.randomBytes(8))
|
|
603
577
|
}
|
|
604
|
-
|
|
605
|
-
async function waitForProfileName(child, timeout) {
|
|
606
|
-
const deadline = Date.now() + timeout
|
|
607
|
-
while (Date.now() < deadline) {
|
|
608
|
-
const { data } = await child.store.get('profile')
|
|
609
|
-
if (data?.name) return data.name
|
|
610
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
611
|
-
}
|
|
612
|
-
return null
|
|
613
|
-
}
|
package/src/index.js
CHANGED
|
@@ -8,12 +8,14 @@ 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 { put, set, get, del, count, watch, call, open } from './lib/operators.js'
|
|
11
|
+
import { put, set, get, del, count, watch, call, open, before, after } from './lib/operators.js'
|
|
12
12
|
import { peek } from './lib/peek.js'
|
|
13
13
|
import { t, schema } from './lib/spec.js'
|
|
14
|
+
import { FLUSH } from './lib/constants.js'
|
|
15
|
+
import { internal } from './lib/internal.js'
|
|
14
16
|
|
|
15
17
|
export { Handle, Ref, Local }
|
|
16
|
-
export { put, set, get, del, count, watch, call, open } from './lib/operators.js'
|
|
18
|
+
export { put, set, get, del, count, watch, call, open, before, after } from './lib/operators.js'
|
|
17
19
|
export { peek } from './lib/peek.js'
|
|
18
20
|
export { t, schema } from './lib/spec.js'
|
|
19
21
|
|
|
@@ -65,7 +67,7 @@ export async function cero(dir, spec, opts = {}) {
|
|
|
65
67
|
const network = new Network({ bootstrap: opts.bootstrap })
|
|
66
68
|
await network.ready()
|
|
67
69
|
const discovery = network.join(identity.topic)
|
|
68
|
-
await Promise.race([discovery.flush(), new Promise((r) => setTimeout(r,
|
|
70
|
+
await Promise.race([discovery.flush(), new Promise((r) => setTimeout(r, FLUSH))])
|
|
69
71
|
|
|
70
72
|
const me = new Handle({
|
|
71
73
|
storage,
|
|
@@ -109,12 +111,12 @@ export async function cero(dir, spec, opts = {}) {
|
|
|
109
111
|
})
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
|
-
if (opts.recovery)
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
if (opts.recovery) await me.recover({ timeout: opts.recoveryTimeout })
|
|
115
|
+
|
|
116
|
+
for (const ext of internal.extensions) {
|
|
117
|
+
const off = await ext.setup?.(me)
|
|
118
|
+
if (typeof off === 'function') me.once('close', off)
|
|
119
|
+
}
|
|
118
120
|
|
|
119
121
|
return me
|
|
120
122
|
}
|
|
@@ -154,7 +156,26 @@ export async function restore(me, phrase) {
|
|
|
154
156
|
})
|
|
155
157
|
}
|
|
156
158
|
|
|
157
|
-
Object.assign(cero, {
|
|
159
|
+
Object.assign(cero, {
|
|
160
|
+
t,
|
|
161
|
+
put,
|
|
162
|
+
set,
|
|
163
|
+
get,
|
|
164
|
+
del,
|
|
165
|
+
count,
|
|
166
|
+
watch,
|
|
167
|
+
call,
|
|
168
|
+
open,
|
|
169
|
+
before,
|
|
170
|
+
after,
|
|
171
|
+
peek,
|
|
172
|
+
restore,
|
|
173
|
+
schema
|
|
174
|
+
})
|
|
175
|
+
cero._internal = internal
|
|
176
|
+
// A bare function is shorthand for a behavior-only extension: `{ setup: fn }`.
|
|
177
|
+
cero.use = (...exts) =>
|
|
178
|
+
internal.extensions.push(...exts.map((e) => (typeof e === 'function' ? { setup: e } : e)))
|
|
158
179
|
|
|
159
180
|
async function resolveIdentity(opts, local) {
|
|
160
181
|
if (opts.identity) return opts.identity
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Shared cero constants.
|
|
2
|
+
|
|
3
|
+
export const NS = 'cero'
|
|
4
|
+
export const COUNTERS = 'counters'
|
|
5
|
+
|
|
6
|
+
// Writer-admission / pairing timeout (ms), and the initial discovery-flush wait (ms).
|
|
7
|
+
export const TIMEOUT = 30000
|
|
8
|
+
export const FLUSH = 500
|
|
9
|
+
|
|
10
|
+
// schema-DSL primitive → HyperDB type (used by the builder).
|
|
11
|
+
export const DB_TYPE = {
|
|
12
|
+
string: 'string',
|
|
13
|
+
uint: 'uint',
|
|
14
|
+
int: 'int',
|
|
15
|
+
bool: 'bool',
|
|
16
|
+
bytes: 'buffer',
|
|
17
|
+
json: 'json',
|
|
18
|
+
fixed32: 'fixed32',
|
|
19
|
+
fixed64: 'fixed64'
|
|
20
|
+
}
|
package/src/lib/operators.js
CHANGED
|
@@ -18,13 +18,15 @@ export const put = (ref, row) => ref.handle.store.put(ref.name, row)
|
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Upsert a row on `ref` — merges with the existing row and preserves
|
|
21
|
-
* `createdAt`.
|
|
21
|
+
* `createdAt`. Pass `{ upsert: false }` to update-only: a missing row is left
|
|
22
|
+
* untouched instead of created (atomic — never resurrects a deleted row).
|
|
22
23
|
*
|
|
23
24
|
* @param {Ref} ref
|
|
24
25
|
* @param {Record<string, any>} row
|
|
26
|
+
* @param {{ upsert?: boolean }} [opts]
|
|
25
27
|
* @returns {Promise<SingleResult>}
|
|
26
28
|
*/
|
|
27
|
-
export const set = (ref, row) => ref.handle.store.set(ref.name, row)
|
|
29
|
+
export const set = (ref, row, opts) => ref.handle.store.set(ref.name, row, opts)
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
32
|
* Delete a row by id (collection refs), or wipe the row (single refs).
|
|
@@ -53,6 +55,43 @@ export const count = (ref, q) => ref.handle.store.count(ref.name, q)
|
|
|
53
55
|
*/
|
|
54
56
|
export const call = (ref, d) => ref.handle.store.call(ref.name, d)
|
|
55
57
|
|
|
58
|
+
// Write ops per ref kind, for `before`/`after` subscriptions.
|
|
59
|
+
const WRITES = { single: ['set'], collection: ['put', 'set', 'del'] }
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Intercept writes to `ref` before they commit — `fn(ctx)` runs in-path
|
|
63
|
+
* (awaited). Return `false` to cancel the write, or mutate `ctx.row`.
|
|
64
|
+
* Returns an unsubscribe fn.
|
|
65
|
+
*
|
|
66
|
+
* @param {Ref} ref
|
|
67
|
+
* @param {(ctx: { op: string, name: string, row: any }) => any} fn
|
|
68
|
+
* @returns {() => void}
|
|
69
|
+
*/
|
|
70
|
+
export const before = (ref, fn) => {
|
|
71
|
+
const db = ref.handle.store
|
|
72
|
+
const ops = WRITES[ref.kind] || ['set']
|
|
73
|
+
const offs = ops.map((op) =>
|
|
74
|
+
db.before(op, (ctx) => (ctx.name === ref.name ? fn(ctx) : undefined))
|
|
75
|
+
)
|
|
76
|
+
return () => offs.forEach((off) => off())
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Subscribe to writes on `ref` — fires after each committed write,
|
|
81
|
+
* non-blocking (observe only). Returns an unsubscribe fn.
|
|
82
|
+
*
|
|
83
|
+
* @param {Ref} ref
|
|
84
|
+
* @param {(ctx: { op: string, name: string, row: any }) => void} fn
|
|
85
|
+
* @returns {() => void}
|
|
86
|
+
*/
|
|
87
|
+
export const after = (ref, fn) => {
|
|
88
|
+
const db = ref.handle.store
|
|
89
|
+
const ops = WRITES[ref.kind] || ['set']
|
|
90
|
+
const handler = (ctx) => ctx.name === ref.name && fn(ctx)
|
|
91
|
+
for (const op of ops) db.on(`after:${op}`, handler)
|
|
92
|
+
return () => ops.forEach((op) => db.off(`after:${op}`, handler))
|
|
93
|
+
}
|
|
94
|
+
|
|
56
95
|
// get/watch on a handle-kind ref list its rows from the `handles` collection
|
|
57
96
|
// filtered by type (handle types are stored there with their { id, key,
|
|
58
97
|
// encryptionKey, name }). Data-kind refs go straight to the store.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export namespace refs {
|
|
2
|
+
namespace main {
|
|
3
|
+
namespace members {
|
|
4
|
+
let type: string;
|
|
5
|
+
}
|
|
6
|
+
namespace devices {
|
|
7
|
+
let type_1: string;
|
|
8
|
+
export { type_1 as type };
|
|
9
|
+
}
|
|
10
|
+
namespace invites {
|
|
11
|
+
let type_2: string;
|
|
12
|
+
export { type_2 as type };
|
|
13
|
+
}
|
|
14
|
+
namespace handles {
|
|
15
|
+
let type_3: string;
|
|
16
|
+
export { type_3 as type };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
let local: {
|
|
20
|
+
master: {
|
|
21
|
+
type: string;
|
|
22
|
+
kind: string;
|
|
23
|
+
};
|
|
24
|
+
keypair: {
|
|
25
|
+
type: string;
|
|
26
|
+
kind: string;
|
|
27
|
+
};
|
|
28
|
+
'handle-keypairs': {
|
|
29
|
+
type: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function hyperdbType(prim: any): any;
|
|
34
|
+
export function builtinRefs(ns: any, scope: any): {
|
|
35
|
+
[k: string]: {
|
|
36
|
+
schema: string;
|
|
37
|
+
verb: any;
|
|
38
|
+
kind: any;
|
|
39
|
+
path: string[];
|
|
40
|
+
builtin: boolean;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
export function builtinTypes(scope: any, extend: any): {
|
|
44
|
+
name: string;
|
|
45
|
+
compact: boolean;
|
|
46
|
+
fields: {
|
|
47
|
+
name: string;
|
|
48
|
+
type: any;
|
|
49
|
+
required: boolean;
|
|
50
|
+
}[];
|
|
51
|
+
}[];
|
|
52
|
+
export function rpcTypes(): {
|
|
53
|
+
name: string;
|
|
54
|
+
compact: boolean;
|
|
55
|
+
fields: {
|
|
56
|
+
name: string;
|
|
57
|
+
type: any;
|
|
58
|
+
required: boolean;
|
|
59
|
+
}[];
|
|
60
|
+
}[];
|
|
61
|
+
export function builtinCollections(ns: any, scope: any): {
|
|
62
|
+
name: string;
|
|
63
|
+
schema: string;
|
|
64
|
+
key: string[];
|
|
65
|
+
}[];
|
|
66
|
+
export function builtinDispatches(ns: any): {
|
|
67
|
+
name: string;
|
|
68
|
+
requestType: string;
|
|
69
|
+
}[];
|
|
70
|
+
export function rpcCommands(ns: any): ({
|
|
71
|
+
name: string;
|
|
72
|
+
request: {
|
|
73
|
+
name: string;
|
|
74
|
+
};
|
|
75
|
+
response: {
|
|
76
|
+
name: string;
|
|
77
|
+
stream?: undefined;
|
|
78
|
+
};
|
|
79
|
+
} | {
|
|
80
|
+
name: string;
|
|
81
|
+
request: {
|
|
82
|
+
name: string;
|
|
83
|
+
};
|
|
84
|
+
response: {
|
|
85
|
+
name: string;
|
|
86
|
+
stream: boolean;
|
|
87
|
+
};
|
|
88
|
+
})[];
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
export const main: {
|
|
2
|
+
'del-by-id': {
|
|
3
|
+
id: import("@cero-base/core/schema").Prim;
|
|
4
|
+
};
|
|
5
|
+
writer: {
|
|
6
|
+
master: import("@cero-base/core/schema").Prim;
|
|
7
|
+
writer: import("@cero-base/core/schema").Prim;
|
|
8
|
+
sig: import("@cero-base/core/schema").Prim;
|
|
9
|
+
isIndexer: import("@cero-base/core/schema").Prim;
|
|
10
|
+
};
|
|
11
|
+
counter: {
|
|
12
|
+
name: import("@cero-base/core/schema").Prim;
|
|
13
|
+
value: import("@cero-base/core/schema").Prim;
|
|
14
|
+
};
|
|
15
|
+
member: {
|
|
16
|
+
id: import("@cero-base/core/schema").Prim;
|
|
17
|
+
key: import("@cero-base/core/schema").Prim;
|
|
18
|
+
role: import("@cero-base/core/schema").Prim;
|
|
19
|
+
name: import("@cero-base/core/schema").Prim;
|
|
20
|
+
createdAt: import("@cero-base/core/schema").Prim;
|
|
21
|
+
updatedAt: import("@cero-base/core/schema").Prim;
|
|
22
|
+
sig: import("@cero-base/core/schema").Prim;
|
|
23
|
+
index: import("@cero-base/core/schema").Prim;
|
|
24
|
+
};
|
|
25
|
+
device: {
|
|
26
|
+
id: import("@cero-base/core/schema").Prim;
|
|
27
|
+
memberId: import("@cero-base/core/schema").Prim;
|
|
28
|
+
name: import("@cero-base/core/schema").Prim;
|
|
29
|
+
isMobile: import("@cero-base/core/schema").Prim;
|
|
30
|
+
createdAt: import("@cero-base/core/schema").Prim;
|
|
31
|
+
updatedAt: import("@cero-base/core/schema").Prim;
|
|
32
|
+
index: import("@cero-base/core/schema").Prim;
|
|
33
|
+
};
|
|
34
|
+
invite: {
|
|
35
|
+
id: import("@cero-base/core/schema").Prim;
|
|
36
|
+
invite: import("@cero-base/core/schema").Prim;
|
|
37
|
+
publicKey: import("@cero-base/core/schema").Prim;
|
|
38
|
+
data: import("@cero-base/core/schema").Prim;
|
|
39
|
+
sig: import("@cero-base/core/schema").Prim;
|
|
40
|
+
role: import("@cero-base/core/schema").Prim;
|
|
41
|
+
expires: import("@cero-base/core/schema").Prim;
|
|
42
|
+
createdAt: import("@cero-base/core/schema").Prim;
|
|
43
|
+
index: import("@cero-base/core/schema").Prim;
|
|
44
|
+
};
|
|
45
|
+
handle: {
|
|
46
|
+
id: import("@cero-base/core/schema").Prim;
|
|
47
|
+
type: import("@cero-base/core/schema").Prim;
|
|
48
|
+
key: import("@cero-base/core/schema").Prim;
|
|
49
|
+
encryptionKey: import("@cero-base/core/schema").Prim;
|
|
50
|
+
name: import("@cero-base/core/schema").Prim;
|
|
51
|
+
createdAt: import("@cero-base/core/schema").Prim;
|
|
52
|
+
updatedAt: import("@cero-base/core/schema").Prim;
|
|
53
|
+
index: import("@cero-base/core/schema").Prim;
|
|
54
|
+
};
|
|
55
|
+
claim: {
|
|
56
|
+
identity: import("@cero-base/core/schema").Prim;
|
|
57
|
+
writer: import("@cero-base/core/schema").Prim;
|
|
58
|
+
sig: import("@cero-base/core/schema").Prim;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
export const local: {
|
|
62
|
+
master: {
|
|
63
|
+
seed: import("@cero-base/core/schema").Prim;
|
|
64
|
+
};
|
|
65
|
+
keypair: {
|
|
66
|
+
publicKey: import("@cero-base/core/schema").Prim;
|
|
67
|
+
secretKey: import("@cero-base/core/schema").Prim;
|
|
68
|
+
};
|
|
69
|
+
'handle-keypair': {
|
|
70
|
+
id: import("@cero-base/core/schema").Prim;
|
|
71
|
+
publicKey: import("@cero-base/core/schema").Prim;
|
|
72
|
+
secretKey: import("@cero-base/core/schema").Prim;
|
|
73
|
+
encryptionKey: import("@cero-base/core/schema").Prim;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
export const rpc: {
|
|
77
|
+
'req-empty': {
|
|
78
|
+
ok: import("@cero-base/core/schema").Prim;
|
|
79
|
+
};
|
|
80
|
+
'req-restore': {
|
|
81
|
+
phrase: import("@cero-base/core/schema").Prim;
|
|
82
|
+
};
|
|
83
|
+
'req-row': {
|
|
84
|
+
handle: import("@cero-base/core/schema").Prim;
|
|
85
|
+
ref: import("@cero-base/core/schema").Prim;
|
|
86
|
+
data: import("@cero-base/core/schema").Prim;
|
|
87
|
+
local: import("@cero-base/core/schema").Prim;
|
|
88
|
+
};
|
|
89
|
+
'req-id': {
|
|
90
|
+
handle: import("@cero-base/core/schema").Prim;
|
|
91
|
+
ref: import("@cero-base/core/schema").Prim;
|
|
92
|
+
id: import("@cero-base/core/schema").Prim;
|
|
93
|
+
local: import("@cero-base/core/schema").Prim;
|
|
94
|
+
};
|
|
95
|
+
'req-query': {
|
|
96
|
+
handle: import("@cero-base/core/schema").Prim;
|
|
97
|
+
ref: import("@cero-base/core/schema").Prim;
|
|
98
|
+
query: import("@cero-base/core/schema").Prim;
|
|
99
|
+
local: import("@cero-base/core/schema").Prim;
|
|
100
|
+
};
|
|
101
|
+
'req-call': {
|
|
102
|
+
handle: import("@cero-base/core/schema").Prim;
|
|
103
|
+
op: import("@cero-base/core/schema").Prim;
|
|
104
|
+
data: import("@cero-base/core/schema").Prim;
|
|
105
|
+
};
|
|
106
|
+
'req-invite': {
|
|
107
|
+
handle: import("@cero-base/core/schema").Prim;
|
|
108
|
+
role: import("@cero-base/core/schema").Prim;
|
|
109
|
+
};
|
|
110
|
+
'req-revoke': {
|
|
111
|
+
handle: import("@cero-base/core/schema").Prim;
|
|
112
|
+
invite: import("@cero-base/core/schema").Prim;
|
|
113
|
+
};
|
|
114
|
+
'req-join': {
|
|
115
|
+
parent: import("@cero-base/core/schema").Prim;
|
|
116
|
+
ref: import("@cero-base/core/schema").Prim;
|
|
117
|
+
invite: import("@cero-base/core/schema").Prim;
|
|
118
|
+
};
|
|
119
|
+
'req-open': {
|
|
120
|
+
parent: import("@cero-base/core/schema").Prim;
|
|
121
|
+
row: import("@cero-base/core/schema").Prim;
|
|
122
|
+
};
|
|
123
|
+
'req-handle': {
|
|
124
|
+
handle: import("@cero-base/core/schema").Prim;
|
|
125
|
+
};
|
|
126
|
+
'res-data': {
|
|
127
|
+
data: import("@cero-base/core/schema").Prim;
|
|
128
|
+
};
|
|
129
|
+
'res-rows': {
|
|
130
|
+
data: import("@cero-base/core/schema").Prim;
|
|
131
|
+
total: import("@cero-base/core/schema").Prim;
|
|
132
|
+
size: import("@cero-base/core/schema").Prim;
|
|
133
|
+
};
|
|
134
|
+
'res-count': {
|
|
135
|
+
count: import("@cero-base/core/schema").Prim;
|
|
136
|
+
};
|
|
137
|
+
'res-invite': {
|
|
138
|
+
invite: import("@cero-base/core/schema").Prim;
|
|
139
|
+
};
|
|
140
|
+
'res-handle': {
|
|
141
|
+
id: import("@cero-base/core/schema").Prim;
|
|
142
|
+
type: import("@cero-base/core/schema").Prim;
|
|
143
|
+
name: import("@cero-base/core/schema").Prim;
|
|
144
|
+
};
|
|
145
|
+
'res-identity': {
|
|
146
|
+
id: import("@cero-base/core/schema").Prim;
|
|
147
|
+
deviceId: import("@cero-base/core/schema").Prim;
|
|
148
|
+
phrase: import("@cero-base/core/schema").Prim;
|
|
149
|
+
};
|
|
150
|
+
'res-ok': {
|
|
151
|
+
ok: import("@cero-base/core/schema").Prim;
|
|
152
|
+
};
|
|
153
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mirror a child handle's `profile` (name + avatar) onto its row in the parent's
|
|
3
|
+
* `handles` list — so a handle list shows names + avatars without opening each
|
|
4
|
+
* one. Adds the synced `fields` to the `handle` builtin.
|
|
5
|
+
*
|
|
6
|
+
* On create it seeds the handle's `profile.name` from the open `{ name }`, then
|
|
7
|
+
* reflects the (app-owned) `profile` onto the row. Requires your handle types to
|
|
8
|
+
* declare a `profile` single — handles without one are left untouched.
|
|
9
|
+
*
|
|
10
|
+
* @param {{ fields?: Record<string, any> }} [opts]
|
|
11
|
+
*/
|
|
12
|
+
export function handleSync({ fields }?: {
|
|
13
|
+
fields?: Record<string, any>;
|
|
14
|
+
}): {
|
|
15
|
+
schema: {
|
|
16
|
+
handles: {
|
|
17
|
+
kind: "extend";
|
|
18
|
+
fields: Record<string, import("@cero-base/core/schema").Prim>;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
setup(me: any): void;
|
|
22
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mirror your `profile` onto your `member` row in every room. Declares a
|
|
3
|
+
* `profile` single (`name`, `avatar`, plus any extra `fields`) and mirrors them
|
|
4
|
+
* onto the `member` builtin, then publishes when you open/join a room and whenever
|
|
5
|
+
* your profile changes. An app may declare its own richer `profile` instead —
|
|
6
|
+
* the app schema wins.
|
|
7
|
+
*
|
|
8
|
+
* @param {{ fields?: Record<string, any> }} [opts]
|
|
9
|
+
*/
|
|
10
|
+
export function profileSync({ fields }?: {
|
|
11
|
+
fields?: Record<string, any>;
|
|
12
|
+
}): {
|
|
13
|
+
schema: {
|
|
14
|
+
profile: import("@cero-base/core/schema").TypeDef;
|
|
15
|
+
members: {
|
|
16
|
+
kind: "extend";
|
|
17
|
+
fields: Record<string, import("@cero-base/core/schema").Prim>;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
setup(me: any): void;
|
|
21
|
+
};
|
package/types/handle/index.d.ts
CHANGED
|
@@ -48,8 +48,6 @@ export { Ref } from "../lib/utils.js";
|
|
|
48
48
|
*
|
|
49
49
|
* @typedef {object} RecoverOpts
|
|
50
50
|
* @property {number} [timeout]
|
|
51
|
-
* @property {string | null} [name]
|
|
52
|
-
* @property {boolean} [isMobile]
|
|
53
51
|
*
|
|
54
52
|
* @typedef {object} HandleExtra
|
|
55
53
|
* @property {string | null} [name] Display name; set on child handles by the owner flow.
|
|
@@ -91,7 +89,6 @@ export class Handle extends ReadyResource {
|
|
|
91
89
|
store: Database;
|
|
92
90
|
pair: Pairing;
|
|
93
91
|
_wantsPair: boolean;
|
|
94
|
-
_offUpdate: () => void;
|
|
95
92
|
/** Canonical id — identity id for the root handle, store key for children. */
|
|
96
93
|
get id(): any;
|
|
97
94
|
/** This device's id + name. `null` on child handles. */
|
|
@@ -126,7 +123,7 @@ export class Handle extends ReadyResource {
|
|
|
126
123
|
* @param {RecoverOpts} [opts]
|
|
127
124
|
* @returns {Promise<void>}
|
|
128
125
|
*/
|
|
129
|
-
recover({ timeout
|
|
126
|
+
recover({ timeout }?: RecoverOpts): Promise<void>;
|
|
130
127
|
/**
|
|
131
128
|
* Mint a pairing invite for this handle.
|
|
132
129
|
*
|
|
@@ -205,7 +202,6 @@ export class Handle extends ReadyResource {
|
|
|
205
202
|
* @returns {Promise<void>}
|
|
206
203
|
*/
|
|
207
204
|
resume(): Promise<void>;
|
|
208
|
-
_syncMember(child: any): Promise<void>;
|
|
209
205
|
/**
|
|
210
206
|
* @param {Handle} child
|
|
211
207
|
* @param {{ role?: string }} [opts]
|
|
@@ -326,8 +322,6 @@ export type AcceptOpts = {
|
|
|
326
322
|
};
|
|
327
323
|
export type RecoverOpts = {
|
|
328
324
|
timeout?: number;
|
|
329
|
-
name?: string | null;
|
|
330
|
-
isMobile?: boolean;
|
|
331
325
|
};
|
|
332
326
|
export type HandleExtra = {
|
|
333
327
|
/**
|