@cero-base/cero 2.0.0 → 2.1.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.
@@ -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
- * Intercept writes to `ref` before they commit `fn(ctx)` runs in-path (awaited).
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: { op: string, name: string, row: any }) => any} fn
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
- * Subscribe to writes on `ref` — fires after each committed write, non-blocking (observe
127
- * only).
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: { op: string, name: string, row: any }) => void} fn
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 handler = (ctx) => ctx.name === ref.name && fn(ctx)
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
- ops.forEach((op) => db.off(`after:${op}`, handler))
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, count, watch, changes, call, open, rotate, bind, define, t, schema }
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, count, watch, changes, call } from '../lib/operators.js'
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
@@ -112,7 +112,7 @@ export class Server extends RPCServer {
112
112
  })
113
113
  }
114
114
 
115
- /** Register the row-level RPC handlers (put/set/get/del/count/watch/call). */
115
+ /** Register the row-level RPC handlers (put/set/get/del/watch/call). */
116
116
  _wireData() {
117
117
  this.rpc.onAddFile(async ({ handle, data, name, type }) => {
118
118
  const h = this._resolve(handle)
@@ -161,12 +161,6 @@ export class Server extends RPCServer {
161
161
  return {}
162
162
  })
163
163
 
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
164
  this.rpc.onWatch((stream) => {
171
165
  const { handle, ref, query, local } = stream.data
172
166
  let r, codec, live
@@ -280,6 +274,21 @@ export class Server extends RPCServer {
280
274
  return { epoch }
281
275
  })
282
276
 
277
+ this.rpc.onSetActive(({ handle, active }) => {
278
+ this._resolve(handle).setActive(active)
279
+ return {}
280
+ })
281
+
282
+ this.rpc.onSuspend(async () => {
283
+ await this.me.suspend()
284
+ return {}
285
+ })
286
+
287
+ this.rpc.onResume(async () => {
288
+ await this.me.resume()
289
+ return {}
290
+ })
291
+
283
292
  this.rpc.onJoin(async ({ parent, ref, invite }) => {
284
293
  if (this._resolve(parent) !== this.me) throw CeroError.UNSUPPORTED('nested handles')
285
294
  const child = await this.me._join(invite, ref)
@@ -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>;
@@ -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
  };
@@ -8,7 +8,6 @@ export declare function handleSync({ fields }?: {
8
8
  fields?: Record<string, any>;
9
9
  }): {
10
10
  name: string;
11
- bundled: boolean;
12
11
  schema: {
13
12
  handles: {
14
13
  kind: 'extend';
@@ -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 declare const registry: ({
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;
@@ -7,7 +7,6 @@ export declare function profileSync({ fields }?: {
7
7
  fields?: Record<string, any>;
8
8
  }): {
9
9
  name: string;
10
- bundled: boolean;
11
10
  schema: {
12
11
  profile: import("@cero-base/core").TypeDef;
13
12
  members: {
@@ -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: () => Promise<void>;
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
- * Flip this handle's swarm announce mode `setActive(false)` demotes an idle/background
298
- * room to server-only (still reachable, stops searching); `setActive(true)` promotes it
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): Promise<void>;
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]