@cero-base/cero 2.0.0 → 2.1.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/package.json +2 -2
- package/src/build/index.js +45 -14
- package/src/build/internal.js +4 -2
- package/src/build/schemas.js +4 -3
- package/src/extensions/handle-sync.js +0 -1
- package/src/extensions/index.js +82 -2
- package/src/extensions/profile-sync.js +15 -11
- package/src/handle/index.js +52 -21
- package/src/index.js +12 -38
- package/src/lib/operators.js +19 -68
- package/src/lib/refs.js +8 -3
- package/src/rpc/client.js +34 -43
- package/src/rpc/server.js +22 -9
- package/types/build/index.d.ts +11 -1
- package/types/build/schemas.d.ts +4 -3
- package/types/extensions/handle-sync.d.ts +0 -1
- package/types/extensions/index.d.ts +83 -3
- package/types/extensions/profile-sync.d.ts +0 -1
- package/types/handle/index.d.ts +11 -11
- package/types/index.d.ts +19 -11
- package/types/lib/operators.d.ts +18 -43
- package/types/lib/refs.d.ts +4 -2
- package/types/rpc/client.d.ts +19 -8
- package/types/rpc/server.d.ts +1 -1
package/src/lib/operators.js
CHANGED
|
@@ -7,6 +7,7 @@ import { onAbort } from '@cero-base/core/utils'
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @typedef {import('./refs.js').Ref} Ref
|
|
10
|
+
* @typedef {import('@cero-base/core/database').HookContext} HookContext
|
|
10
11
|
* @typedef {import('../handle/index.js').CeroHandle} CeroHandle
|
|
11
12
|
* @typedef {{ data: any }} SingleResult
|
|
12
13
|
* @typedef {{ data: any[], total: number, size: number }} ListResult
|
|
@@ -75,17 +76,6 @@ export function del(ref, id) {
|
|
|
75
76
|
return ref.handle.store.del(ref.name, id)
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
/**
|
|
79
|
-
* Count rows on `ref`, optionally filtered.
|
|
80
|
-
*
|
|
81
|
-
* @param {Ref} ref
|
|
82
|
-
* @param {Record<string, any>} [q]
|
|
83
|
-
* @returns {Promise<{ data: number }>}
|
|
84
|
-
*/
|
|
85
|
-
export function count(ref, q) {
|
|
86
|
-
return ref.handle.store.count(ref.name, q)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
79
|
/**
|
|
90
80
|
* Invoke an `action`-kind ref (a custom mutation declared in the schema).
|
|
91
81
|
*
|
|
@@ -100,14 +90,22 @@ export function call(ref, d) {
|
|
|
100
90
|
const WRITES = { single: ['set'], collection: ['put', 'set', 'del'] }
|
|
101
91
|
|
|
102
92
|
/**
|
|
103
|
-
*
|
|
93
|
+
* Rule that runs before a write to `ref` lands — at apply, on every peer, inside the op's
|
|
94
|
+
* transaction. Return `false` to refuse it: the writer's own call rejects with `REFUSED`.
|
|
95
|
+
* `ctx` is `{ op, name, row, existing, id, memberId, role, get, put, set, del }`; mutate
|
|
96
|
+
* `ctx.row` to rewrite what is stored. `op` is the op as it applies, so an upsert on a
|
|
97
|
+
* collection is a `put`. The four operators on `ctx` read and write the room as it stands at
|
|
98
|
+
* this op, inside the transaction. Must be deterministic — read only `ctx`, never a clock or
|
|
99
|
+
* local state — and registered before any op applies, in the process that owns the data. The
|
|
100
|
+
* imported operators throw inside a hook; use the ones on `ctx`. Not available over RPC.
|
|
104
101
|
*
|
|
105
102
|
* @param {Ref} ref
|
|
106
|
-
* @param {(ctx:
|
|
103
|
+
* @param {(ctx: HookContext) => unknown} fn
|
|
107
104
|
* @param {{ signal?: AbortSignal }} [opts]
|
|
108
105
|
* @returns {() => void}
|
|
109
106
|
*/
|
|
110
107
|
export function before(ref, fn, opts) {
|
|
108
|
+
if (ref.type) return ref.handle._hookType(before, ref, fn, opts)
|
|
111
109
|
const db = ref.handle.store
|
|
112
110
|
const ops = WRITES[ref.kind] || ['set']
|
|
113
111
|
const offs = ops.map((op) =>
|
|
@@ -123,22 +121,24 @@ export function before(ref, fn, opts) {
|
|
|
123
121
|
}
|
|
124
122
|
|
|
125
123
|
/**
|
|
126
|
-
*
|
|
127
|
-
*
|
|
124
|
+
* Rule that runs after a write to `ref` lands — at apply, on every peer, inside the op's
|
|
125
|
+
* transaction. Write derived rows through `ctx.put` / `ctx.set` / `ctx.del`; a throw refuses
|
|
126
|
+
* the whole op. Same `ctx` and the same determinism and registration rules as `before`. Use
|
|
127
|
+
* `changes(ref)` instead to observe writes locally.
|
|
128
128
|
*
|
|
129
129
|
* @param {Ref} ref
|
|
130
|
-
* @param {(ctx:
|
|
130
|
+
* @param {(ctx: HookContext) => unknown} fn
|
|
131
131
|
* @param {{ signal?: AbortSignal }} [opts]
|
|
132
132
|
* @returns {() => void}
|
|
133
133
|
*/
|
|
134
134
|
export function after(ref, fn, opts) {
|
|
135
|
+
if (ref.type) return ref.handle._hookType(after, ref, fn, opts)
|
|
135
136
|
const db = ref.handle.store
|
|
136
137
|
const ops = WRITES[ref.kind] || ['set']
|
|
137
|
-
const
|
|
138
|
-
for (const op of ops) db.on(`after:${op}`, handler)
|
|
138
|
+
const offs = ops.map((op) => db.after(op, (ctx) => (ctx.name === ref.name ? fn(ctx) : undefined)))
|
|
139
139
|
let stopAbort
|
|
140
140
|
const off = () => {
|
|
141
|
-
|
|
141
|
+
offs.forEach((unsub) => unsub())
|
|
142
142
|
stopAbort?.()
|
|
143
143
|
}
|
|
144
144
|
stopAbort = onAbort(opts?.signal, off)
|
|
@@ -333,52 +333,3 @@ export function open(ref, arg) {
|
|
|
333
333
|
export function rotate(handle) {
|
|
334
334
|
return handle.store.rotate()
|
|
335
335
|
}
|
|
336
|
-
|
|
337
|
-
const registry = {}
|
|
338
|
-
|
|
339
|
-
function attach(handle, ns, fns) {
|
|
340
|
-
const bound = {}
|
|
341
|
-
for (const key of Object.keys(fns)) {
|
|
342
|
-
if (typeof fns[key] === 'function') bound[key] = (...args) => fns[key](handle, ...args)
|
|
343
|
-
}
|
|
344
|
-
handle[ns] = bound
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Put custom operators on `handle`, currying it as their first argument so
|
|
349
|
-
* `handle.ns.fn(args)` calls `fn(handle, args)`.
|
|
350
|
-
*
|
|
351
|
-
* @param {any} handle
|
|
352
|
-
* @param {Record<string, any> | string | null} arg
|
|
353
|
-
* @returns {any} handle
|
|
354
|
-
*/
|
|
355
|
-
export function bind(handle, arg) {
|
|
356
|
-
if (arg !== null && typeof arg !== 'string') {
|
|
357
|
-
for (const ns of Object.keys(arg)) attach(handle, ns, arg[ns])
|
|
358
|
-
return handle
|
|
359
|
-
}
|
|
360
|
-
const handles = handle.spec?.meta?.handles || {}
|
|
361
|
-
for (const ns of Object.keys(registry)) {
|
|
362
|
-
if (arg === null) {
|
|
363
|
-
if (!(ns in handles)) attach(handle, ns, registry[ns]) // bare root namespace
|
|
364
|
-
} else if (ns === arg) {
|
|
365
|
-
for (const k of Object.keys(registry[ns])) attach(handle, k, registry[ns][k]) // child group
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
return handle
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* Register custom operators by scope. A bare key binds on the root handle; a key that
|
|
373
|
-
* names a child-handle type binds on every handle of that type.
|
|
374
|
-
*
|
|
375
|
-
* @param {Record<string, any>} map
|
|
376
|
-
*/
|
|
377
|
-
export function define(map) {
|
|
378
|
-
Object.assign(registry, map)
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/** Test seam: clear all registered operators. */
|
|
382
|
-
export function _clearDefined() {
|
|
383
|
-
for (const k of Object.keys(registry)) delete registry[k]
|
|
384
|
-
}
|
package/src/lib/refs.js
CHANGED
|
@@ -18,11 +18,12 @@ export class Ref {
|
|
|
18
18
|
* @param {string} kind Ref kind: `'collection'`, `'single'`, `'action'`, or `'handle'`.
|
|
19
19
|
* @param {string | null} [schema] Fully-qualified schema id, if any.
|
|
20
20
|
*/
|
|
21
|
-
constructor(handle, name, kind, schema = null) {
|
|
21
|
+
constructor(handle, name, kind, schema = null, type = null) {
|
|
22
22
|
this.handle = handle
|
|
23
23
|
this.name = name
|
|
24
24
|
this.kind = kind
|
|
25
25
|
this.schema = schema
|
|
26
|
+
this.type = type
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
/**
|
|
@@ -31,8 +32,9 @@ export class Ref {
|
|
|
31
32
|
*
|
|
32
33
|
* @param {any} target
|
|
33
34
|
* @param {Record<string, RefInfo>} refs
|
|
35
|
+
* @param {Record<string, any>} [handles] The handle types, so `target.room.notes` names every room's notes.
|
|
34
36
|
*/
|
|
35
|
-
static attach(target, refs) {
|
|
37
|
+
static attach(target, refs, handles) {
|
|
36
38
|
for (const [name, info] of Object.entries(refs || {})) {
|
|
37
39
|
// a ref named like a reserved member must fail loud, not overwrite it
|
|
38
40
|
if (name in target) {
|
|
@@ -40,7 +42,10 @@ export class Ref {
|
|
|
40
42
|
`schema ref '${name}' collides with a reserved ${target.constructor?.name || 'handle'} member — rename it`
|
|
41
43
|
)
|
|
42
44
|
}
|
|
43
|
-
target[name] = new Ref(target, name, info.kind, info.schema)
|
|
45
|
+
const ref = (target[name] = new Ref(target, name, info.kind, info.schema))
|
|
46
|
+
for (const [sub, i] of Object.entries(handles?.[name]?.meta?.refs || {})) {
|
|
47
|
+
ref[sub] = new Ref(target, sub, i.kind, i.schema, name)
|
|
48
|
+
}
|
|
44
49
|
}
|
|
45
50
|
}
|
|
46
51
|
}
|
package/src/rpc/client.js
CHANGED
|
@@ -5,23 +5,11 @@ import z32 from 'z32'
|
|
|
5
5
|
import { decodeId } from '@cero-base/core/blobs/codec'
|
|
6
6
|
|
|
7
7
|
import { Ref } from '../lib/refs.js'
|
|
8
|
-
import {
|
|
9
|
-
put,
|
|
10
|
-
set,
|
|
11
|
-
get,
|
|
12
|
-
del,
|
|
13
|
-
count,
|
|
14
|
-
watch,
|
|
15
|
-
changes,
|
|
16
|
-
call,
|
|
17
|
-
open,
|
|
18
|
-
rotate,
|
|
19
|
-
bind,
|
|
20
|
-
define
|
|
21
|
-
} from '../lib/operators.js'
|
|
8
|
+
import { put, set, get, del, watch, changes, call, open, rotate } from '../lib/operators.js'
|
|
22
9
|
import { t, schema } from '../lib/spec.js'
|
|
10
|
+
import { operatorsOf, bind } from '../extensions/index.js'
|
|
23
11
|
|
|
24
|
-
export { put, set, get, del,
|
|
12
|
+
export { put, set, get, del, watch, changes, call, open, rotate, t, schema }
|
|
25
13
|
|
|
26
14
|
/**
|
|
27
15
|
* @typedef {import('@cero-base/core/rpc').RPCClient} BaseRPCClient
|
|
@@ -252,24 +240,6 @@ const operators = {
|
|
|
252
240
|
await this.rpc.del({ handle: this.id, ref: name, id, local: this._local })
|
|
253
241
|
},
|
|
254
242
|
|
|
255
|
-
/**
|
|
256
|
-
* Count matching rows.
|
|
257
|
-
*
|
|
258
|
-
* @param {string} name
|
|
259
|
-
* @param {Record<string, any>} [query]
|
|
260
|
-
* @returns {Promise<{ data: number }>}
|
|
261
|
-
*/
|
|
262
|
-
async count(name, query) {
|
|
263
|
-
const codec = this._codec()
|
|
264
|
-
const res = await this.rpc.count({
|
|
265
|
-
handle: this.id,
|
|
266
|
-
ref: name,
|
|
267
|
-
query: codec.encodeQuery(query),
|
|
268
|
-
local: this._local
|
|
269
|
-
})
|
|
270
|
-
return { data: res.count }
|
|
271
|
-
},
|
|
272
|
-
|
|
273
243
|
/**
|
|
274
244
|
* Live snapshot stream. Re-emits the latest `get()` shape on every
|
|
275
245
|
* underlying mutation. Destroy the stream to stop watching.
|
|
@@ -409,6 +379,16 @@ const operators = {
|
|
|
409
379
|
async rotate() {
|
|
410
380
|
const { epoch } = await this.rpc.rotate({ handle: this.id })
|
|
411
381
|
return { epoch }
|
|
382
|
+
},
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* `true` ranks this handle as just updated on the server, `false` takes it off the swarm.
|
|
386
|
+
*
|
|
387
|
+
* @param {boolean} active
|
|
388
|
+
* @returns {Promise<void>}
|
|
389
|
+
*/
|
|
390
|
+
async setActive(active) {
|
|
391
|
+
await this.rpc.setActive({ handle: this.id, active })
|
|
412
392
|
}
|
|
413
393
|
}
|
|
414
394
|
|
|
@@ -464,11 +444,13 @@ export class Client extends RPCClient {
|
|
|
464
444
|
/**
|
|
465
445
|
* @param {any} ipc Framed IPC stream (must be writable).
|
|
466
446
|
* @param {Spec} spec Compiled cero spec (schema + rpc + handles).
|
|
447
|
+
* @param {{ operators?: Record<string, any> }} [opts] The operators to bind, instead of the ones the spec carries.
|
|
467
448
|
*/
|
|
468
|
-
constructor(ipc, spec) {
|
|
449
|
+
constructor(ipc, spec, opts = {}) {
|
|
469
450
|
super(ipc, spec)
|
|
470
451
|
if (spec.local?.schema && !spec.local.codec) bindCodec(spec.local)
|
|
471
452
|
Object.assign(this, operators)
|
|
453
|
+
this.operators = operatorsOf(spec, opts.operators)
|
|
472
454
|
this.id = null
|
|
473
455
|
this.deviceId = null
|
|
474
456
|
this.store = this
|
|
@@ -484,10 +466,20 @@ export class Client extends RPCClient {
|
|
|
484
466
|
this._fileToken = fileToken || ''
|
|
485
467
|
this.identity = { id, toPhrase: async () => (await this.rpc.seed({})).phrase || null }
|
|
486
468
|
Ref.attach(this, /** @type {Spec} */ (this.spec).meta.refs)
|
|
487
|
-
bind(this, null)
|
|
469
|
+
bind(this, null, this.operators)
|
|
488
470
|
if (/** @type {Spec} */ (this.spec).meta.local?.refs) this.local = new LocalRefs(this)
|
|
489
471
|
}
|
|
490
472
|
|
|
473
|
+
/** Pause networking and storage on the server. Idempotent. */
|
|
474
|
+
async suspend() {
|
|
475
|
+
await this.rpc.suspend({})
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/** Resume a suspended server. Idempotent. */
|
|
479
|
+
async resume() {
|
|
480
|
+
await this.rpc.resume({})
|
|
481
|
+
}
|
|
482
|
+
|
|
491
483
|
/**
|
|
492
484
|
* Create a new child handle of the given type.
|
|
493
485
|
*
|
|
@@ -553,7 +545,7 @@ class Handle {
|
|
|
553
545
|
if (!this.spec.codec) bindCodec(this.spec)
|
|
554
546
|
this.store = this
|
|
555
547
|
Ref.attach(this, this.spec.meta.refs)
|
|
556
|
-
bind(this, this.type)
|
|
548
|
+
bind(this, this.type, parent.operators)
|
|
557
549
|
}
|
|
558
550
|
|
|
559
551
|
/** Underlying RPC channel borrowed from the parent. */
|
|
@@ -577,10 +569,11 @@ class Handle {
|
|
|
577
569
|
*
|
|
578
570
|
* @param {any} ipc
|
|
579
571
|
* @param {object} spec
|
|
572
|
+
* @param {{ operators?: Record<string, any> }} [opts]
|
|
580
573
|
* @returns {Promise<Client>}
|
|
581
574
|
*/
|
|
582
|
-
export async function connect(ipc, spec) {
|
|
583
|
-
const client = new Client(ipc, spec)
|
|
575
|
+
export async function connect(ipc, spec, opts) {
|
|
576
|
+
const client = new Client(ipc, spec, opts)
|
|
584
577
|
await client.ready()
|
|
585
578
|
return client
|
|
586
579
|
}
|
|
@@ -591,10 +584,11 @@ export async function connect(ipc, spec) {
|
|
|
591
584
|
*
|
|
592
585
|
* @param {any} ipc Framed IPC duplex stream.
|
|
593
586
|
* @param {any} spec Built cero spec.
|
|
587
|
+
* @param {{ operators?: Record<string, any> }} [opts]
|
|
594
588
|
* @returns {Promise<Client>}
|
|
595
589
|
*/
|
|
596
|
-
export function cero(ipc, spec) {
|
|
597
|
-
return connect(ipc, spec)
|
|
590
|
+
export function cero(ipc, spec, opts) {
|
|
591
|
+
return connect(ipc, spec, opts)
|
|
598
592
|
}
|
|
599
593
|
cero.connect = connect
|
|
600
594
|
cero.restore = restore
|
|
@@ -603,12 +597,9 @@ cero.put = put
|
|
|
603
597
|
cero.set = set
|
|
604
598
|
cero.get = get
|
|
605
599
|
cero.del = del
|
|
606
|
-
cero.count = count
|
|
607
600
|
cero.watch = watch
|
|
608
601
|
cero.changes = changes
|
|
609
602
|
cero.call = call
|
|
610
603
|
cero.open = open
|
|
611
604
|
cero.rotate = rotate
|
|
612
|
-
cero.bind = bind
|
|
613
|
-
cero.define = define
|
|
614
605
|
cero.schema = schema
|
package/src/rpc/server.js
CHANGED
|
@@ -5,7 +5,7 @@ import { CeroError } from '@cero-base/core/errors'
|
|
|
5
5
|
import { encodeId } from '@cero-base/core/blobs/codec'
|
|
6
6
|
|
|
7
7
|
import { cero, restore } from '../index.js'
|
|
8
|
-
import { put, set, get, del,
|
|
8
|
+
import { put, set, get, del, watch, changes, call } from '../lib/operators.js'
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @typedef {import('@cero-base/core/rpc').RPCServer} BaseRPCServer
|
|
@@ -89,7 +89,11 @@ export class Server extends RPCServer {
|
|
|
89
89
|
/** Wire the `init` handler that lazily constructs the root cero handle. */
|
|
90
90
|
_wireInit() {
|
|
91
91
|
this.rpc.onInit(async () => {
|
|
92
|
-
|
|
92
|
+
// a reloaded UI is a new client on the same worker: it re-attaches, its old streams end
|
|
93
|
+
if (this.me) {
|
|
94
|
+
for (const handle of this._watchStreams.keys()) this._endWatches(handle)
|
|
95
|
+
return this._identity()
|
|
96
|
+
}
|
|
93
97
|
this.me = await cero(this.storage, this.spec, this.opts)
|
|
94
98
|
this.handles.set(this.me.id, this.me)
|
|
95
99
|
await this.me.fileServer.listen()
|
|
@@ -112,7 +116,7 @@ export class Server extends RPCServer {
|
|
|
112
116
|
})
|
|
113
117
|
}
|
|
114
118
|
|
|
115
|
-
/** Register the row-level RPC handlers (put/set/get/del/
|
|
119
|
+
/** Register the row-level RPC handlers (put/set/get/del/watch/call). */
|
|
116
120
|
_wireData() {
|
|
117
121
|
this.rpc.onAddFile(async ({ handle, data, name, type }) => {
|
|
118
122
|
const h = this._resolve(handle)
|
|
@@ -161,12 +165,6 @@ export class Server extends RPCServer {
|
|
|
161
165
|
return {}
|
|
162
166
|
})
|
|
163
167
|
|
|
164
|
-
this.rpc.onCount(async ({ handle, ref, query, local }) => {
|
|
165
|
-
const { ref: r, codec } = this._refOf(handle, ref, local)
|
|
166
|
-
const { data } = await count(r, codec.decodeQuery(query))
|
|
167
|
-
return { count: data }
|
|
168
|
-
})
|
|
169
|
-
|
|
170
168
|
this.rpc.onWatch((stream) => {
|
|
171
169
|
const { handle, ref, query, local } = stream.data
|
|
172
170
|
let r, codec, live
|
|
@@ -280,6 +278,21 @@ export class Server extends RPCServer {
|
|
|
280
278
|
return { epoch }
|
|
281
279
|
})
|
|
282
280
|
|
|
281
|
+
this.rpc.onSetActive(({ handle, active }) => {
|
|
282
|
+
this._resolve(handle).setActive(active)
|
|
283
|
+
return {}
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
this.rpc.onSuspend(async () => {
|
|
287
|
+
await this.me.suspend()
|
|
288
|
+
return {}
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
this.rpc.onResume(async () => {
|
|
292
|
+
await this.me.resume()
|
|
293
|
+
return {}
|
|
294
|
+
})
|
|
295
|
+
|
|
283
296
|
this.rpc.onJoin(async ({ parent, ref, invite }) => {
|
|
284
297
|
if (this._resolve(parent) !== this.me) throw CeroError.UNSUPPORTED('nested handles')
|
|
285
298
|
const child = await this.me._join(invite, ref)
|
package/types/build/index.d.ts
CHANGED
|
@@ -8,6 +8,14 @@ export type BuildOpts = {
|
|
|
8
8
|
* Namespace prefix for emitted schema ids. Defaults to `'cero'`.
|
|
9
9
|
*/
|
|
10
10
|
ns?: string;
|
|
11
|
+
/**
|
|
12
|
+
* The extensions to fold in. A module specifier, relative to `specDir`, is imported here for its `extensions` export and written into the spec, so every process runs the same list. A list is folded in only. The bundled two by default, `[]` for none.
|
|
13
|
+
*/
|
|
14
|
+
extensions?: string | import('../extensions/index.js').Extension[];
|
|
15
|
+
/**
|
|
16
|
+
* A module specifier, relative to `specDir`, written into the spec for its `operators` export, so every process binds the same map.
|
|
17
|
+
*/
|
|
18
|
+
operators?: string;
|
|
11
19
|
};
|
|
12
20
|
/**
|
|
13
21
|
* @typedef {import('@cero-base/core/schema').Schema} Schema
|
|
@@ -16,6 +24,8 @@ export type BuildOpts = {
|
|
|
16
24
|
*
|
|
17
25
|
* @typedef {object} BuildOpts
|
|
18
26
|
* @property {string} [ns] Namespace prefix for emitted schema ids. Defaults to `'cero'`.
|
|
27
|
+
* @property {string | import('../extensions/index.js').Extension[]} [extensions] The extensions to fold in. A module specifier, relative to `specDir`, is imported here for its `extensions` export and written into the spec, so every process runs the same list. A list is folded in only. The bundled two by default, `[]` for none.
|
|
28
|
+
* @property {string} [operators] A module specifier, relative to `specDir`, written into the spec for its `operators` export, so every process binds the same map.
|
|
19
29
|
*/
|
|
20
30
|
/**
|
|
21
31
|
* Compile a cero schema into wire-level artifacts and write them to disk.
|
|
@@ -25,4 +35,4 @@ export type BuildOpts = {
|
|
|
25
35
|
* @param {BuildOpts} [opts]
|
|
26
36
|
* @returns {Promise<void>}
|
|
27
37
|
*/
|
|
28
|
-
export declare function build(specDir: string, schema: SchemaInput, { ns, extensions }?: BuildOpts): Promise<void>;
|
|
38
|
+
export declare function build(specDir: string, schema: SchemaInput, { ns, extensions, operators }?: BuildOpts): Promise<void>;
|
package/types/build/schemas.d.ts
CHANGED
|
@@ -151,6 +151,10 @@ export declare const rpc: {
|
|
|
151
151
|
'req-handle': {
|
|
152
152
|
handle: import("@cero-base/core").Prim;
|
|
153
153
|
};
|
|
154
|
+
'req-set-active': {
|
|
155
|
+
handle: import("@cero-base/core").Prim;
|
|
156
|
+
active: import("@cero-base/core").Prim;
|
|
157
|
+
};
|
|
154
158
|
'res-data': {
|
|
155
159
|
data: import("@cero-base/core").Prim;
|
|
156
160
|
};
|
|
@@ -163,9 +167,6 @@ export declare const rpc: {
|
|
|
163
167
|
changes: import("@cero-base/core").Prim;
|
|
164
168
|
reset: import("@cero-base/core").Prim;
|
|
165
169
|
};
|
|
166
|
-
'res-count': {
|
|
167
|
-
count: import("@cero-base/core").Prim;
|
|
168
|
-
};
|
|
169
170
|
'res-invite': {
|
|
170
171
|
invite: import("@cero-base/core").Prim;
|
|
171
172
|
};
|
|
@@ -1,8 +1,63 @@
|
|
|
1
|
+
import { t, schema } from '../lib/spec.js';
|
|
2
|
+
import * as operators from '../lib/operators.js';
|
|
1
3
|
export * from './profile-sync.js';
|
|
2
4
|
export * from './handle-sync.js';
|
|
3
|
-
export
|
|
5
|
+
export { t, schema };
|
|
6
|
+
export declare const put: typeof operators.put, set: typeof operators.set, get: typeof operators.get, del: typeof operators.del, watch: typeof operators.watch, changes: typeof operators.changes, call: typeof operators.call, open: typeof operators.open, rotate: typeof operators.rotate, before: typeof operators.before, after: typeof operators.after;
|
|
7
|
+
export declare const cero: {
|
|
8
|
+
t: {
|
|
9
|
+
string: import("@cero-base/core").Prim;
|
|
10
|
+
uint: import("@cero-base/core").Prim;
|
|
11
|
+
int: import("@cero-base/core").Prim;
|
|
12
|
+
bool: import("@cero-base/core").Prim;
|
|
13
|
+
bytes: import("@cero-base/core").Prim;
|
|
14
|
+
json: import("@cero-base/core").Prim;
|
|
15
|
+
fixed32: import("@cero-base/core").Prim;
|
|
16
|
+
fixed64: import("@cero-base/core").Prim;
|
|
17
|
+
file: import("@cero-base/core").Prim;
|
|
18
|
+
required: (marker: import("@cero-base/core").Prim) => import("@cero-base/core").Prim;
|
|
19
|
+
single(fields: Record<string, import("@cero-base/core").Prim>): import("@cero-base/core").TypeDef;
|
|
20
|
+
collection(fields: Record<string, import("@cero-base/core").Prim>, opts?: {
|
|
21
|
+
indexes?: Record<string, string[]>;
|
|
22
|
+
own?: boolean;
|
|
23
|
+
}): import("@cero-base/core").TypeDef;
|
|
24
|
+
action(fields: Record<string, import("@cero-base/core").Prim>): import("@cero-base/core").TypeDef;
|
|
25
|
+
extend(fields: Record<string, import("@cero-base/core").Prim>): {
|
|
26
|
+
kind: 'extend';
|
|
27
|
+
fields: Record<string, import("@cero-base/core").Prim>;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
schema: typeof schema;
|
|
31
|
+
put: typeof operators.put;
|
|
32
|
+
set: typeof operators.set;
|
|
33
|
+
get: typeof operators.get;
|
|
34
|
+
del: typeof operators.del;
|
|
35
|
+
watch: typeof operators.watch;
|
|
36
|
+
changes: typeof operators.changes;
|
|
37
|
+
call: typeof operators.call;
|
|
38
|
+
open: typeof operators.open;
|
|
39
|
+
rotate: typeof operators.rotate;
|
|
40
|
+
before: typeof operators.before;
|
|
41
|
+
after: typeof operators.after;
|
|
42
|
+
};
|
|
43
|
+
export type Extension = {
|
|
44
|
+
/**
|
|
45
|
+
* Refs to add, or `t.extend` on a builtin, nested by handle type like the app schema.
|
|
46
|
+
*/
|
|
47
|
+
schema?: Record<string, any>;
|
|
48
|
+
/**
|
|
49
|
+
* Runs once the root is ready; a returned function runs on close.
|
|
50
|
+
*/
|
|
51
|
+
setup?: (me: any) => any;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* @typedef {object} Extension
|
|
55
|
+
* @property {Record<string, any>} [schema] Refs to add, or `t.extend` on a builtin, nested by handle type like the app schema.
|
|
56
|
+
* @property {(me: any) => any} [setup] Runs once the root is ready; a returned function runs on close.
|
|
57
|
+
*/
|
|
58
|
+
/** The two every app gets unless its build names a list. */
|
|
59
|
+
export declare const bundled: ({
|
|
4
60
|
name: string;
|
|
5
|
-
bundled: boolean;
|
|
6
61
|
schema: {
|
|
7
62
|
profile: import("@cero-base/core").TypeDef;
|
|
8
63
|
members: {
|
|
@@ -13,7 +68,6 @@ export declare const registry: ({
|
|
|
13
68
|
setup(me: any): void;
|
|
14
69
|
} | {
|
|
15
70
|
name: string;
|
|
16
|
-
bundled: boolean;
|
|
17
71
|
schema: {
|
|
18
72
|
handles: {
|
|
19
73
|
kind: 'extend';
|
|
@@ -22,3 +76,29 @@ export declare const registry: ({
|
|
|
22
76
|
};
|
|
23
77
|
setup(me: any): void;
|
|
24
78
|
})[];
|
|
79
|
+
/**
|
|
80
|
+
* The extensions a spec carries, else the bundled two. A bare function is `{ setup }`.
|
|
81
|
+
*
|
|
82
|
+
* @param {any} spec
|
|
83
|
+
* @param {Array<any>} [override]
|
|
84
|
+
* @returns {Extension[]}
|
|
85
|
+
*/
|
|
86
|
+
export declare function extensionsOf(spec: any, override?: Array<any>): Extension[];
|
|
87
|
+
/**
|
|
88
|
+
* The operators a spec carries: functions taking the handle first, keyed by namespace, a
|
|
89
|
+
* key naming a handle type holding that type's namespaces.
|
|
90
|
+
*
|
|
91
|
+
* @param {any} spec
|
|
92
|
+
* @param {Record<string, any>} [override]
|
|
93
|
+
* @returns {Record<string, any>}
|
|
94
|
+
*/
|
|
95
|
+
export declare function operatorsOf(spec: any, override?: Record<string, any>): Record<string, any>;
|
|
96
|
+
/**
|
|
97
|
+
* Put the operators for `handle` on it: the root when `type` is null, else a child of `type`.
|
|
98
|
+
*
|
|
99
|
+
* @param {any} handle
|
|
100
|
+
* @param {string | null} type
|
|
101
|
+
* @param {Record<string, any>} operators
|
|
102
|
+
* @returns {any} handle
|
|
103
|
+
*/
|
|
104
|
+
export declare function bind(handle: any, type: string | null, operators: Record<string, any>): any;
|
package/types/handle/index.d.ts
CHANGED
|
@@ -74,10 +74,6 @@ export type HandleOpts = {
|
|
|
74
74
|
* Writer keypair.
|
|
75
75
|
*/
|
|
76
76
|
keyPair?: KeyPair;
|
|
77
|
-
/**
|
|
78
|
-
* Join discovery server-only; flip later with `setActive`.
|
|
79
|
-
*/
|
|
80
|
-
passive?: boolean;
|
|
81
77
|
/**
|
|
82
78
|
* When `false`, skips creating a `Pairing` session.
|
|
83
79
|
*/
|
|
@@ -148,7 +144,6 @@ export type CeroHandle = Handle & Record<string, import('../lib/refs.js').Ref>;
|
|
|
148
144
|
* @property {Array<{ epoch: number, entropy: Uint8Array }>} [epochs] Rotation epochs delivered at join.
|
|
149
145
|
* @property {string} [namespace] Corestore namespace.
|
|
150
146
|
* @property {KeyPair} [keyPair] Writer keypair.
|
|
151
|
-
* @property {boolean} [passive] Join discovery server-only; flip later with `setActive`.
|
|
152
147
|
* @property {boolean} [pair] When `false`, skips creating a `Pairing` session.
|
|
153
148
|
*
|
|
154
149
|
* @typedef {object} CreateChildOpts
|
|
@@ -197,8 +192,11 @@ export declare class Handle extends ReadyResource {
|
|
|
197
192
|
_discovery: any;
|
|
198
193
|
_dir: string;
|
|
199
194
|
_opts: any;
|
|
195
|
+
extensions: any;
|
|
196
|
+
operators: any;
|
|
200
197
|
_onerror: any;
|
|
201
198
|
children: Set<any>;
|
|
199
|
+
_typeHooks: Set<any>;
|
|
202
200
|
_loading: Map<any, any>;
|
|
203
201
|
_joining: Map<any, any>;
|
|
204
202
|
_coreKeys: Map<any, any>;
|
|
@@ -211,7 +209,7 @@ export declare class Handle extends ReadyResource {
|
|
|
211
209
|
pair: Pairing;
|
|
212
210
|
_wantsPair: boolean;
|
|
213
211
|
_ac: AbortController;
|
|
214
|
-
_invitesSync: () =>
|
|
212
|
+
_invitesSync: (touched: any) => void;
|
|
215
213
|
/** @param {HandleOpts} [opts] */
|
|
216
214
|
constructor(opts?: HandleOpts);
|
|
217
215
|
/**
|
|
@@ -235,6 +233,8 @@ export declare class Handle extends ReadyResource {
|
|
|
235
233
|
* @returns {Blobs}
|
|
236
234
|
*/
|
|
237
235
|
get blobs(): Blobs;
|
|
236
|
+
/** The handle type of a child, null on the root. */
|
|
237
|
+
get type(): any;
|
|
238
238
|
/** Canonical id — identity id for the root handle, store key for children. */
|
|
239
239
|
get id(): any;
|
|
240
240
|
/** This device's id + name. `null` on child handles. */
|
|
@@ -294,14 +294,12 @@ export declare class Handle extends ReadyResource {
|
|
|
294
294
|
*/
|
|
295
295
|
claim(): Promise<void>;
|
|
296
296
|
/**
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
* back on focus.
|
|
297
|
+
* `true` ranks this handle as just touched, `false` takes it out of the swarm until the
|
|
298
|
+
* next update lands in it.
|
|
300
299
|
*
|
|
301
300
|
* @param {boolean} active
|
|
302
|
-
* @returns {Promise<void>}
|
|
303
301
|
*/
|
|
304
|
-
setActive(active: boolean):
|
|
302
|
+
setActive(active: boolean): void;
|
|
305
303
|
/**
|
|
306
304
|
* Mint a pairing invite for this handle.
|
|
307
305
|
*
|
|
@@ -415,6 +413,8 @@ export declare class Handle extends ReadyResource {
|
|
|
415
413
|
_reopen(type: string, id: string, opts: any): Promise<Handle>;
|
|
416
414
|
_suspend(): Promise<void>;
|
|
417
415
|
_resume(): Promise<void>;
|
|
416
|
+
_adopt(child: any, info: any): void;
|
|
417
|
+
_hookType(op: any, ref: any, fn: any, opts: any): () => void;
|
|
418
418
|
/**
|
|
419
419
|
* @param {Handle} child
|
|
420
420
|
* @param {{ role?: string }} [opts]
|