@cero-base/cero 1.19.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.
- package/README.md +38 -643
- package/package.json +9 -6
- package/src/build/index.js +63 -61
- package/src/build/internal.js +123 -0
- package/src/build/schemas.js +6 -11
- package/src/extensions/handle-sync.js +3 -11
- package/src/extensions/index.js +86 -0
- package/src/extensions/profile-sync.js +15 -16
- package/src/handle/index.js +290 -284
- package/src/index.js +24 -81
- package/src/lib/bluetooth.js +25 -56
- package/src/lib/constants.js +0 -15
- package/src/lib/operators.js +35 -134
- package/src/lib/peek.js +4 -8
- package/src/lib/refs.js +10 -8
- package/src/lib/spec.js +2 -3
- package/src/local/index.js +2 -3
- package/src/rpc/client.js +54 -77
- package/src/rpc/index.js +3 -3
- package/src/rpc/server.js +40 -43
- package/types/build/index.d.ts +11 -9
- package/types/build/{builtins.d.ts → internal.d.ts} +20 -38
- package/types/build/schemas.d.ts +4 -3
- package/types/extensions/handle-sync.d.ts +2 -8
- package/types/extensions/index.d.ts +102 -0
- package/types/extensions/profile-sync.d.ts +0 -5
- package/types/handle/index.d.ts +90 -108
- package/types/index.d.ts +21 -17
- package/types/lib/bluetooth.d.ts +8 -32
- package/types/lib/constants.d.ts +0 -11
- package/types/lib/operators.d.ts +30 -83
- package/types/lib/peek.d.ts +2 -3
- package/types/lib/refs.d.ts +5 -5
- package/types/lib/spec.d.ts +2 -3
- package/types/local/index.d.ts +2 -3
- package/types/rpc/client.d.ts +29 -26
- package/types/rpc/index.d.ts +3 -3
- package/types/rpc/server.d.ts +7 -10
- package/src/build/builtins.js +0 -174
- package/src/lib/internal.js +0 -9
- package/types/lib/internal.d.ts +0 -24
package/types/lib/operators.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export type Ref = import('./refs.js').Ref;
|
|
2
|
+
export type HookContext = import('@cero-base/core/database').HookContext;
|
|
2
3
|
export type CeroHandle = import('../handle/index.js').CeroHandle;
|
|
3
4
|
export type SingleResult = {
|
|
4
5
|
data: any;
|
|
@@ -13,6 +14,7 @@ export type GetByIdResult = {
|
|
|
13
14
|
};
|
|
14
15
|
/**
|
|
15
16
|
* @typedef {import('./refs.js').Ref} Ref
|
|
17
|
+
* @typedef {import('@cero-base/core/database').HookContext} HookContext
|
|
16
18
|
* @typedef {import('../handle/index.js').CeroHandle} CeroHandle
|
|
17
19
|
* @typedef {{ data: any }} SingleResult
|
|
18
20
|
* @typedef {{ data: any[], total: number, size: number }} ListResult
|
|
@@ -35,9 +37,7 @@ export declare function resolveFile(handle: object, id: string, name?: string):
|
|
|
35
37
|
name?: string;
|
|
36
38
|
};
|
|
37
39
|
/**
|
|
38
|
-
* Insert (or overwrite by id) a row on `ref`.
|
|
39
|
-
* `put(handle.files, { data, type, name? })` uploads the bytes to this handle's
|
|
40
|
-
* blob store, records `{ id, name }`, and resolves the file.
|
|
40
|
+
* Insert (or overwrite by id) a row on `ref`.
|
|
41
41
|
*
|
|
42
42
|
* @param {Ref} ref
|
|
43
43
|
* @param {Record<string, any>} row
|
|
@@ -45,9 +45,7 @@ export declare function resolveFile(handle: object, id: string, name?: string):
|
|
|
45
45
|
*/
|
|
46
46
|
export declare function put(ref: Ref, row: Record<string, any>): Promise<SingleResult>;
|
|
47
47
|
/**
|
|
48
|
-
* Upsert a row on `ref` — merges with the existing row and preserves
|
|
49
|
-
* `createdAt`. Pass `{ upsert: false }` to update-only: a missing row is left
|
|
50
|
-
* untouched instead of created (atomic — never resurrects a deleted row).
|
|
48
|
+
* Upsert a row on `ref` — merges with the existing row and preserves `createdAt`.
|
|
51
49
|
*
|
|
52
50
|
* @param {Ref} ref
|
|
53
51
|
* @param {Record<string, any>} row
|
|
@@ -65,16 +63,6 @@ export declare function set(ref: Ref, row: Record<string, any>, opts?: {
|
|
|
65
63
|
* @returns {Promise<void>}
|
|
66
64
|
*/
|
|
67
65
|
export declare function del(ref: Ref, id?: string): Promise<void>;
|
|
68
|
-
/**
|
|
69
|
-
* Count rows on `ref`, optionally filtered.
|
|
70
|
-
*
|
|
71
|
-
* @param {Ref} ref
|
|
72
|
-
* @param {Record<string, any>} [q]
|
|
73
|
-
* @returns {Promise<{ data: number }>}
|
|
74
|
-
*/
|
|
75
|
-
export declare function count(ref: Ref, q?: Record<string, any>): Promise<{
|
|
76
|
-
data: number;
|
|
77
|
-
}>;
|
|
78
66
|
/**
|
|
79
67
|
* Invoke an `action`-kind ref (a custom mutation declared in the schema).
|
|
80
68
|
*
|
|
@@ -84,43 +72,39 @@ export declare function count(ref: Ref, q?: Record<string, any>): Promise<{
|
|
|
84
72
|
*/
|
|
85
73
|
export declare function call(ref: Ref, d?: Record<string, any>): Promise<any>;
|
|
86
74
|
/**
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
75
|
+
* Rule that runs before a write to `ref` lands — at apply, on every peer, inside the op's
|
|
76
|
+
* transaction. Return `false` to refuse it: the writer's own call rejects with `REFUSED`.
|
|
77
|
+
* `ctx` is `{ op, name, row, existing, id, memberId, role, get, put, set, del }`; mutate
|
|
78
|
+
* `ctx.row` to rewrite what is stored. `op` is the op as it applies, so an upsert on a
|
|
79
|
+
* collection is a `put`. The four operators on `ctx` read and write the room as it stands at
|
|
80
|
+
* this op, inside the transaction. Must be deterministic — read only `ctx`, never a clock or
|
|
81
|
+
* local state — and registered before any op applies, in the process that owns the data. The
|
|
82
|
+
* imported operators throw inside a hook; use the ones on `ctx`. Not available over RPC.
|
|
90
83
|
*
|
|
91
84
|
* @param {Ref} ref
|
|
92
|
-
* @param {(ctx:
|
|
85
|
+
* @param {(ctx: HookContext) => unknown} fn
|
|
93
86
|
* @param {{ signal?: AbortSignal }} [opts]
|
|
94
87
|
* @returns {() => void}
|
|
95
88
|
*/
|
|
96
|
-
export declare function before(ref: Ref, fn: (ctx: {
|
|
97
|
-
op: string;
|
|
98
|
-
name: string;
|
|
99
|
-
row: any;
|
|
100
|
-
}) => any, opts?: {
|
|
89
|
+
export declare function before(ref: Ref, fn: (ctx: HookContext) => unknown, opts?: {
|
|
101
90
|
signal?: AbortSignal;
|
|
102
91
|
}): () => void;
|
|
103
92
|
/**
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
93
|
+
* Rule that runs after a write to `ref` lands — at apply, on every peer, inside the op's
|
|
94
|
+
* transaction. Write derived rows through `ctx.put` / `ctx.set` / `ctx.del`; a throw refuses
|
|
95
|
+
* the whole op. Same `ctx` and the same determinism and registration rules as `before`. Use
|
|
96
|
+
* `changes(ref)` instead to observe writes locally.
|
|
107
97
|
*
|
|
108
98
|
* @param {Ref} ref
|
|
109
|
-
* @param {(ctx:
|
|
99
|
+
* @param {(ctx: HookContext) => unknown} fn
|
|
110
100
|
* @param {{ signal?: AbortSignal }} [opts]
|
|
111
101
|
* @returns {() => void}
|
|
112
102
|
*/
|
|
113
|
-
export declare function after(ref: Ref, fn: (ctx: {
|
|
114
|
-
op: string;
|
|
115
|
-
name: string;
|
|
116
|
-
row: any;
|
|
117
|
-
}) => void, opts?: {
|
|
103
|
+
export declare function after(ref: Ref, fn: (ctx: HookContext) => unknown, opts?: {
|
|
118
104
|
signal?: AbortSignal;
|
|
119
105
|
}): () => void;
|
|
120
106
|
/**
|
|
121
|
-
* Read from `ref`. For data refs, dispatches to the underlying store.
|
|
122
|
-
* `handle`-kind refs, lists existing child handles of that type from the
|
|
123
|
-
* parent's `handles` collection.
|
|
107
|
+
* Read from `ref`. For data refs, dispatches to the underlying store.
|
|
124
108
|
*
|
|
125
109
|
* @param {Ref} ref
|
|
126
110
|
* @param {string | Record<string, any>} [q]
|
|
@@ -128,10 +112,8 @@ export declare function after(ref: Ref, fn: (ctx: {
|
|
|
128
112
|
*/
|
|
129
113
|
export declare function get(ref: Ref, q?: string | Record<string, any>): Promise<SingleResult | ListResult | GetByIdResult>;
|
|
130
114
|
/**
|
|
131
|
-
* Live snapshot stream on `ref` — re-emits the latest `get()` result on
|
|
132
|
-
*
|
|
133
|
-
* handle destroys it. Pass `{ signal }` to bind it to a finer scope, or
|
|
134
|
-
* destroy the stream directly to stop watching sooner.
|
|
115
|
+
* Live snapshot stream on `ref` — re-emits the latest `get()` result on every underlying
|
|
116
|
+
* mutation.
|
|
135
117
|
*
|
|
136
118
|
* @param {Ref} ref
|
|
137
119
|
* @param {Record<string, any>} [q]
|
|
@@ -142,20 +124,13 @@ export declare function watch(ref: Ref, q?: Record<string, any>, opts?: {
|
|
|
142
124
|
signal?: AbortSignal;
|
|
143
125
|
}): import('streamx').Readable;
|
|
144
126
|
/**
|
|
145
|
-
* Delta subscription: batches of `{ prev, next }` row pairs instead of
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* with `reset: true`). File-typed fields resolve on both sides.
|
|
127
|
+
* Delta subscription: batches of `{ prev, next }` row pairs instead of full snapshots —
|
|
128
|
+
* lossless under backpressure, self-contained (the first batch, and any batch after a view
|
|
129
|
+
* swap, replays current.
|
|
149
130
|
*/
|
|
150
131
|
export declare function changes(ref: any, q: any, opts: any): any;
|
|
151
132
|
/**
|
|
152
|
-
* Open (or create / join / load) a child handle through a `handle`-kind
|
|
153
|
-
* ref. Dispatches on the normalize of `arg`:
|
|
154
|
-
*
|
|
155
|
-
* - `string` → join via an invite string
|
|
156
|
-
* - `{ invite: string }` → join via invite (object form)
|
|
157
|
-
* - `{ id: string }` → load an existing handle by id
|
|
158
|
-
* - `object | undefined` → create a new handle with the given opts
|
|
133
|
+
* Open (or create / join / load) a child handle through a `handle`-kind ref.
|
|
159
134
|
*
|
|
160
135
|
* @param {Ref} ref
|
|
161
136
|
* @param {string | { invite?: string, id?: string, name?: string, routes?: any, role?: string, accept?: boolean } | undefined} [arg]
|
|
@@ -170,13 +145,9 @@ export declare function open(ref: Ref, arg?: string | {
|
|
|
170
145
|
accept?: boolean;
|
|
171
146
|
} | undefined): Promise<CeroHandle>;
|
|
172
147
|
/**
|
|
173
|
-
* Rotate a handle's encryption epoch. A fresh secret is sealed to every
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
* permission (admin or owner). Compose with removal:
|
|
177
|
-
*
|
|
178
|
-
* await cero.del(room.members, memberId)
|
|
179
|
-
* await cero.rotate(room)
|
|
148
|
+
* Rotate a handle's encryption epoch. A fresh secret is sealed to every current member and
|
|
149
|
+
* announced through the log — members removed before the rotation cannot decrypt anything
|
|
150
|
+
* written after it.
|
|
180
151
|
*
|
|
181
152
|
* @param {any} handle
|
|
182
153
|
* @returns {Promise<{ epoch: number }>}
|
|
@@ -184,27 +155,3 @@ export declare function open(ref: Ref, arg?: string | {
|
|
|
184
155
|
export declare function rotate(handle: any): Promise<{
|
|
185
156
|
epoch: number;
|
|
186
157
|
}>;
|
|
187
|
-
/**
|
|
188
|
-
* Put custom operators on `handle`, currying it as their first argument so
|
|
189
|
-
* `handle.ns.fn(args)` calls `fn(handle, args)`. `arg` is either:
|
|
190
|
-
* - a `{ ns: module }` map → bind exactly those, or
|
|
191
|
-
* - `null` → the registered root operators, or
|
|
192
|
-
* - a child-handle type → the registered operators for that type.
|
|
193
|
-
* The scope forms are how cero binds handles automatically; pass a map yourself
|
|
194
|
-
* for manual binding.
|
|
195
|
-
*
|
|
196
|
-
* @param {any} handle
|
|
197
|
-
* @param {Record<string, any> | string | null} arg
|
|
198
|
-
* @returns {any} handle
|
|
199
|
-
*/
|
|
200
|
-
export declare function bind(handle: any, arg: Record<string, any> | string | null): any;
|
|
201
|
-
/**
|
|
202
|
-
* Register custom operators by scope. A bare key binds on the root handle; a key
|
|
203
|
-
* that names a child-handle type binds on every handle of that type. Call once
|
|
204
|
-
* at startup, before `cero()` / `connect()`, in both processes.
|
|
205
|
-
*
|
|
206
|
-
* @param {Record<string, any>} map
|
|
207
|
-
*/
|
|
208
|
-
export declare function define(map: Record<string, any>): void;
|
|
209
|
-
/** Test seam: clear all registered operators. */
|
|
210
|
-
export declare function _clearDefined(): void;
|
package/types/lib/peek.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Quickly check whether the on-disk directory at `dir` already holds an
|
|
3
|
-
*
|
|
4
|
-
* read-only and closes everything before returning.
|
|
2
|
+
* Quickly check whether the on-disk directory at `dir` already holds an initialised cero
|
|
3
|
+
* identity (i.e. a stored master seed).
|
|
5
4
|
*
|
|
6
5
|
* @param {string} dir Cero data directory.
|
|
7
6
|
* @param {any} spec Built spec — same value passed to `cero(dir, spec)`.
|
package/types/lib/refs.d.ts
CHANGED
|
@@ -11,28 +11,28 @@ export type RefInfo = {
|
|
|
11
11
|
* from a generated spec.
|
|
12
12
|
*/
|
|
13
13
|
/**
|
|
14
|
-
* Typed pointer to a single ref (table or handle slot) on a `Handle` or
|
|
15
|
-
* `Local`. Operators (`put`/`get`/`open`/...) take a `Ref` as their first
|
|
16
|
-
* argument and dispatch through the owning handle's store.
|
|
14
|
+
* Typed pointer to a single ref (table or handle slot) on a `Handle` or `Local`.
|
|
17
15
|
*/
|
|
18
16
|
export declare class Ref {
|
|
19
17
|
handle: any;
|
|
20
18
|
name: string;
|
|
21
19
|
kind: string;
|
|
22
20
|
schema: string;
|
|
21
|
+
type: any;
|
|
23
22
|
/**
|
|
24
23
|
* @param {any} handle Owner — a `Handle` (or `Local`) the ref lives on.
|
|
25
24
|
* @param {string} name Ref name as declared in the schema.
|
|
26
25
|
* @param {string} kind Ref kind: `'collection'`, `'single'`, `'action'`, or `'handle'`.
|
|
27
26
|
* @param {string | null} [schema] Fully-qualified schema id, if any.
|
|
28
27
|
*/
|
|
29
|
-
constructor(handle: any, name: string, kind: string, schema?: string | null);
|
|
28
|
+
constructor(handle: any, name: string, kind: string, schema?: string | null, type?: any);
|
|
30
29
|
/**
|
|
31
30
|
* Attach a `Ref` property to `target` for every entry in `refs`, so callers
|
|
32
31
|
* write `handle.someRef` instead of looking refs up by name.
|
|
33
32
|
*
|
|
34
33
|
* @param {any} target
|
|
35
34
|
* @param {Record<string, RefInfo>} refs
|
|
35
|
+
* @param {Record<string, any>} [handles] The handle types, so `target.room.notes` names every room's notes.
|
|
36
36
|
*/
|
|
37
|
-
static attach(target: any, refs: Record<string, RefInfo>): void;
|
|
37
|
+
static attach(target: any, refs: Record<string, RefInfo>, handles?: Record<string, any>): void;
|
|
38
38
|
}
|
package/types/lib/spec.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Re-exports of the schema DSL (`t`) and `schema()` wrapper from
|
|
3
|
-
*
|
|
4
|
-
* pulling in the core package directly.
|
|
2
|
+
* Re-exports of the schema DSL (`t`) and `schema()` wrapper from `@cero-base/core/schema`,
|
|
3
|
+
* so cero apps can describe their tables without pulling in the core package directly.
|
|
5
4
|
*/
|
|
6
5
|
export { t, schema } from '@cero-base/core/schema';
|
package/types/local/index.d.ts
CHANGED
|
@@ -21,9 +21,8 @@ export type LocalOpts = {
|
|
|
21
21
|
* @property {Uint8Array} [storageKey] 32-byte key encrypting the local store at rest.
|
|
22
22
|
*/
|
|
23
23
|
/**
|
|
24
|
-
* Per-device, single-writer storage for cero — holds the master seed,
|
|
25
|
-
*
|
|
26
|
-
* `Storage` and exposes each local ref as a property of the instance.
|
|
24
|
+
* Per-device, single-writer storage for cero — holds the master seed, device keypair and
|
|
25
|
+
* any per-handle keypairs.
|
|
27
26
|
*/
|
|
28
27
|
export declare class Local extends ReadyResource {
|
|
29
28
|
dir: string;
|
package/types/rpc/client.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { RPCClient } from '@cero-base/core/rpc';
|
|
2
|
-
import { put, set, get, del,
|
|
2
|
+
import { put, set, get, del, watch, changes, call, open, rotate } from '../lib/operators.js';
|
|
3
3
|
import { t, schema } from '../lib/spec.js';
|
|
4
|
-
export { put, set, get, del,
|
|
4
|
+
export { put, set, get, del, watch, changes, call, open, rotate, t, schema };
|
|
5
5
|
export type BaseRPCClient = import('@cero-base/core/rpc').RPCClient;
|
|
6
6
|
export type RefInfo = {
|
|
7
7
|
kind?: 'single' | 'collection' | 'action' | 'handle';
|
|
8
8
|
schema?: string;
|
|
9
9
|
type?: string;
|
|
10
|
-
|
|
10
|
+
internal?: boolean;
|
|
11
11
|
};
|
|
12
12
|
export type Spec = import('@cero-base/core/rpc').Spec & {
|
|
13
13
|
meta: {
|
|
@@ -50,10 +50,7 @@ export type HandleStub = {
|
|
|
50
50
|
*/
|
|
51
51
|
export declare function restore(me: Client, phrase: string): Promise<Client>;
|
|
52
52
|
/**
|
|
53
|
-
* Per-device `local`-namespace surface on a Client.
|
|
54
|
-
* local ref (e.g. `client.local.settings`) and routes ops over RPC with
|
|
55
|
-
* `local: true`, so they hit the server's per-device store and never
|
|
56
|
-
* replicate. Built-in local refs (identity master/keypair) are not exposed.
|
|
53
|
+
* Per-device `local`-namespace surface on a Client.
|
|
57
54
|
*/
|
|
58
55
|
declare class LocalRefs {
|
|
59
56
|
parent: Client;
|
|
@@ -68,11 +65,12 @@ declare class LocalRefs {
|
|
|
68
65
|
get id(): any;
|
|
69
66
|
}
|
|
70
67
|
/**
|
|
71
|
-
* IPC-side RPC client for cero. Wraps an `hrpc` channel and exposes the
|
|
72
|
-
*
|
|
73
|
-
*
|
|
68
|
+
* IPC-side RPC client for cero. Wraps an `hrpc` channel and exposes the same
|
|
69
|
+
* handle/ref/row API as a local cero instance, transparently routing every operation
|
|
70
|
+
* across the wire.
|
|
74
71
|
*/
|
|
75
72
|
export declare class Client extends RPCClient {
|
|
73
|
+
operators: Record<string, any>;
|
|
76
74
|
id: any;
|
|
77
75
|
deviceId: any;
|
|
78
76
|
store: this;
|
|
@@ -86,9 +84,16 @@ export declare class Client extends RPCClient {
|
|
|
86
84
|
/**
|
|
87
85
|
* @param {any} ipc Framed IPC stream (must be writable).
|
|
88
86
|
* @param {Spec} spec Compiled cero spec (schema + rpc + handles).
|
|
87
|
+
* @param {{ operators?: Record<string, any> }} [opts] The operators to bind, instead of the ones the spec carries.
|
|
89
88
|
*/
|
|
90
|
-
constructor(ipc: any, spec: Spec
|
|
89
|
+
constructor(ipc: any, spec: Spec, opts?: {
|
|
90
|
+
operators?: Record<string, any>;
|
|
91
|
+
});
|
|
91
92
|
_open(): Promise<void>;
|
|
93
|
+
/** Pause networking and storage on the server. Idempotent. */
|
|
94
|
+
suspend(): Promise<void>;
|
|
95
|
+
/** Resume a suspended server. Idempotent. */
|
|
96
|
+
resume(): Promise<void>;
|
|
92
97
|
/**
|
|
93
98
|
* Create a new child handle of the given type.
|
|
94
99
|
*
|
|
@@ -115,9 +120,9 @@ export declare class Client extends RPCClient {
|
|
|
115
120
|
_join(invite: string, type: string): Promise<Handle>;
|
|
116
121
|
}
|
|
117
122
|
/**
|
|
118
|
-
* Client-side proxy for a remote handle. Exposes the same row-ops surface
|
|
119
|
-
*
|
|
120
|
-
*
|
|
123
|
+
* Client-side proxy for a remote handle. Exposes the same row-ops surface as `Client` but
|
|
124
|
+
* scoped to a single child handle id, and routes every call through the parent's RPC
|
|
125
|
+
* channel.
|
|
121
126
|
*/
|
|
122
127
|
declare class Handle {
|
|
123
128
|
parent: Client;
|
|
@@ -145,23 +150,24 @@ declare class Handle {
|
|
|
145
150
|
*
|
|
146
151
|
* @param {any} ipc
|
|
147
152
|
* @param {object} spec
|
|
153
|
+
* @param {{ operators?: Record<string, any> }} [opts]
|
|
148
154
|
* @returns {Promise<Client>}
|
|
149
155
|
*/
|
|
150
|
-
export declare function connect(ipc: any, spec: object
|
|
156
|
+
export declare function connect(ipc: any, spec: object, opts?: {
|
|
157
|
+
operators?: Record<string, any>;
|
|
158
|
+
}): Promise<Client>;
|
|
151
159
|
/**
|
|
152
|
-
* Symmetric client entry. Mirrors the main `cero`, but `cero(ipc, spec)` connects
|
|
153
|
-
*
|
|
154
|
-
* surface is attached, so `import { cero } from '@cero-base/cero/client'` works
|
|
155
|
-
* just like `import { cero } from '@cero-base/cero'`.
|
|
156
|
-
*
|
|
157
|
-
* Note: `before`/`after`/`peek` are intentionally not exposed here — they hook the
|
|
158
|
-
* local write path / probe a local store, which a client proxy has no notion of.
|
|
160
|
+
* Symmetric client entry. Mirrors the main `cero`, but `cero(ipc, spec)` connects to a
|
|
161
|
+
* server (via `connect`) instead of opening a local store.
|
|
159
162
|
*
|
|
160
163
|
* @param {any} ipc Framed IPC duplex stream.
|
|
161
164
|
* @param {any} spec Built cero spec.
|
|
165
|
+
* @param {{ operators?: Record<string, any> }} [opts]
|
|
162
166
|
* @returns {Promise<Client>}
|
|
163
167
|
*/
|
|
164
|
-
export declare function cero(ipc: any, spec: any
|
|
168
|
+
export declare function cero(ipc: any, spec: any, opts?: {
|
|
169
|
+
operators?: Record<string, any>;
|
|
170
|
+
}): Promise<Client>;
|
|
165
171
|
export declare namespace cero {
|
|
166
172
|
export { connect };
|
|
167
173
|
export { restore };
|
|
@@ -170,13 +176,10 @@ export declare namespace cero {
|
|
|
170
176
|
export { set };
|
|
171
177
|
export { get };
|
|
172
178
|
export { del };
|
|
173
|
-
export { count };
|
|
174
179
|
export { watch };
|
|
175
180
|
export { changes };
|
|
176
181
|
export { call };
|
|
177
182
|
export { open };
|
|
178
183
|
export { rotate };
|
|
179
|
-
export { bind };
|
|
180
|
-
export { define };
|
|
181
184
|
export { schema };
|
|
182
185
|
}
|
package/types/rpc/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* RPC barrel — re-exports the `Server`/`Client` classes and their
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* RPC barrel — re-exports the `Server`/`Client` classes and their `serve()`/`connect()`
|
|
3
|
+
* helpers so consumers can spin up either side of the cero IPC bridge from a single
|
|
4
|
+
* import.
|
|
5
5
|
*/
|
|
6
6
|
export { Server, serve } from './server.js';
|
|
7
7
|
export { Client, connect } from './client.js';
|
package/types/rpc/server.d.ts
CHANGED
|
@@ -57,10 +57,9 @@ export type GetResult = {
|
|
|
57
57
|
* @typedef {{ data: any, total?: number, size?: number }} GetResult Single-ref get omits `total`/`size`; list/handle refs include them.
|
|
58
58
|
*/
|
|
59
59
|
/**
|
|
60
|
-
* IPC-side RPC server for cero. Bridges an `hrpc` channel to a live
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* over the wire using the spec-bound codec.
|
|
60
|
+
* IPC-side RPC server for cero. Bridges an `hrpc` channel to a live `Handle` tree:
|
|
61
|
+
* lazy-initializes the root via `cero()` on the first `init` call, then exposes data ops,
|
|
62
|
+
* pairing, and handle lifecycle.
|
|
64
63
|
*/
|
|
65
64
|
export declare class Server extends RPCServer {
|
|
66
65
|
storage: string;
|
|
@@ -83,8 +82,6 @@ export declare class Server extends RPCServer {
|
|
|
83
82
|
* @param {Partial<ServerOpts>} [opts]
|
|
84
83
|
*/
|
|
85
84
|
constructor(ipc: any, spec: object, { storage, ...opts }?: Partial<ServerOpts>);
|
|
86
|
-
/** End every watch stream bound to a handle (e.g. when it closes or leaves). */
|
|
87
|
-
_endWatches(handle: any): void;
|
|
88
85
|
/**
|
|
89
86
|
* Root cero id (null until `init` has run).
|
|
90
87
|
*
|
|
@@ -98,11 +95,13 @@ export declare class Server extends RPCServer {
|
|
|
98
95
|
*/
|
|
99
96
|
get identity(): any;
|
|
100
97
|
_close(): Promise<void>;
|
|
98
|
+
/** End every watch stream bound to a handle (e.g. when it closes or leaves). */
|
|
99
|
+
_endWatches(handle: any): void;
|
|
101
100
|
/** Wire the `init` handler that lazily constructs the root cero handle. */
|
|
102
101
|
_wireInit(): void;
|
|
103
102
|
/** Wire the `restore` handler that rebuilds the local store from a phrase. */
|
|
104
103
|
_wireRestore(): void;
|
|
105
|
-
/** Register the row-level RPC handlers (put/set/get/del/
|
|
104
|
+
/** Register the row-level RPC handlers (put/set/get/del/watch/call). */
|
|
106
105
|
_wireData(): void;
|
|
107
106
|
/** Register invite/revoke/join RPC handlers. */
|
|
108
107
|
_wirePairing(): void;
|
|
@@ -117,9 +116,7 @@ export declare class Server extends RPCServer {
|
|
|
117
116
|
*/
|
|
118
117
|
_resolve(id: string): any;
|
|
119
118
|
/**
|
|
120
|
-
* Resolve a `{ handle, ref }` pair to its `Ref` and codec.
|
|
121
|
-
* set, the ref is resolved against the root's per-device `local` store and
|
|
122
|
-
* paired with the codec bound from the local schema.
|
|
119
|
+
* Resolve a `{ handle, ref }` pair to its `Ref` and codec.
|
|
123
120
|
*
|
|
124
121
|
* @param {string} id
|
|
125
122
|
* @param {string} name
|
package/src/build/builtins.js
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
// Build wiring for the builtin schemas (schemas.js): turns the grouped field
|
|
2
|
-
// maps into the type / collection / dispatch / command descriptors the builder
|
|
3
|
-
// registers. Every cero schema includes these; app refs are added on top.
|
|
4
|
-
import { CeroError } from '@cero-base/core/errors'
|
|
5
|
-
import { COUNTERS, EPOCHS, DB_TYPE } from '../lib/constants.js'
|
|
6
|
-
import * as schemas from './schemas.js'
|
|
7
|
-
|
|
8
|
-
// Builtin collections by scope — ref name → { type, kind? }. kind defaults to
|
|
9
|
-
// 'collection' (id-keyed); 'single' has no key. Dispatches are derived for
|
|
10
|
-
// main; counters is internal (a collection with no add/set/del).
|
|
11
|
-
export const refs = {
|
|
12
|
-
main: {
|
|
13
|
-
members: { type: 'member' },
|
|
14
|
-
devices: { type: 'device' },
|
|
15
|
-
invites: { type: 'invite' },
|
|
16
|
-
handles: { type: 'handle' },
|
|
17
|
-
files: { type: 'file' }
|
|
18
|
-
},
|
|
19
|
-
local: {
|
|
20
|
-
master: { type: 'master', kind: 'single' },
|
|
21
|
-
keypair: { type: 'keypair', kind: 'single' },
|
|
22
|
-
'handle-keypairs': { type: 'handle-keypair' },
|
|
23
|
-
environment: { type: 'environment', kind: 'single' }
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function getHyperdbType(prim) {
|
|
28
|
-
return DB_TYPE[prim] || 'string'
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const at = (ns, n) => `@${ns}/${n}`
|
|
32
|
-
const keyOf = (def) => (def.kind === 'single' ? [] : ['id'])
|
|
33
|
-
|
|
34
|
-
const fields = (map) =>
|
|
35
|
-
Object.entries(map).map(([name, m]) => ({
|
|
36
|
-
name,
|
|
37
|
-
type: getHyperdbType(m.prim),
|
|
38
|
-
required: m.required === true
|
|
39
|
-
}))
|
|
40
|
-
|
|
41
|
-
// Merge app `t.extend` fields into a builtin's base fields — base can't be redeclared.
|
|
42
|
-
const merge = (type, base, extra) => {
|
|
43
|
-
if (!extra) return base
|
|
44
|
-
for (const k in extra) {
|
|
45
|
-
if (k in base) {
|
|
46
|
-
throw CeroError.INVALID(`'${k}' is a base field of '${type}' and cannot be redeclared`)
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return { ...base, ...extra }
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const descriptors = (group, extend = {}) =>
|
|
53
|
-
Object.entries(group).map(([name, base]) => ({
|
|
54
|
-
name,
|
|
55
|
-
compact: false,
|
|
56
|
-
fields: fields(merge(name, base, extend[name]))
|
|
57
|
-
}))
|
|
58
|
-
|
|
59
|
-
// meta.refs entries for a scope's builtins.
|
|
60
|
-
export function builtinRefs(ns, scope) {
|
|
61
|
-
return Object.fromEntries(
|
|
62
|
-
Object.entries(refs[scope]).map(([name, def]) => [
|
|
63
|
-
name,
|
|
64
|
-
{
|
|
65
|
-
kind: def.kind || 'collection',
|
|
66
|
-
path: [name],
|
|
67
|
-
builtin: true,
|
|
68
|
-
...(scope === 'main' && { verb: def.type }),
|
|
69
|
-
schema: at(ns, def.type)
|
|
70
|
-
}
|
|
71
|
-
])
|
|
72
|
-
)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// hyperschema type descriptors. scope is 'main' | 'local' | 'rpc'; `extend`
|
|
76
|
-
// merges app `t.extend` fields into the matching type.
|
|
77
|
-
export function builtinTypes(scope, extend) {
|
|
78
|
-
return descriptors(schemas[scope], extend)
|
|
79
|
-
}
|
|
80
|
-
export function rpcTypes() {
|
|
81
|
-
return descriptors(schemas.rpc)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// hyperdb collection descriptors for a scope.
|
|
85
|
-
export function builtinCollections(ns, scope) {
|
|
86
|
-
const out = Object.entries(refs[scope]).map(([name, def]) => ({
|
|
87
|
-
name,
|
|
88
|
-
schema: at(ns, def.type),
|
|
89
|
-
key: keyOf(def)
|
|
90
|
-
}))
|
|
91
|
-
if (scope === 'main') {
|
|
92
|
-
out.push({ name: COUNTERS, schema: at(ns, 'counter'), key: ['name'] })
|
|
93
|
-
out.push({ name: EPOCHS, schema: at(ns, 'epoch'), key: ['epoch'] })
|
|
94
|
-
}
|
|
95
|
-
return out
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// hyperdispatch descriptors (main scope only).
|
|
99
|
-
export function builtinDispatches(ns) {
|
|
100
|
-
return [
|
|
101
|
-
{ name: 'add-writer', requestType: at(ns, 'writer') },
|
|
102
|
-
{ name: 'del-writer', requestType: at(ns, 'writer') },
|
|
103
|
-
{ name: 'claim-writer', requestType: at(ns, 'claim') },
|
|
104
|
-
...Object.values(refs.main).flatMap(({ type }) => [
|
|
105
|
-
{ name: `add-${type}`, requestType: at(ns, type) },
|
|
106
|
-
{ name: `set-${type}`, requestType: at(ns, type) },
|
|
107
|
-
{ name: `del-${type}`, requestType: at(ns, 'del-by-id') }
|
|
108
|
-
])
|
|
109
|
-
]
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Registered AFTER the app's own dispatches (see build/index.js): hyperdispatch
|
|
113
|
-
// numbers routes positionally and persists them, so a spec built before
|
|
114
|
-
// rotation must see rotate-key appended at the end — inserting it into the
|
|
115
|
-
// builtin group would collide with the app's persisted route ids on an
|
|
116
|
-
// incremental rebuild.
|
|
117
|
-
export function rotateDispatch(ns) {
|
|
118
|
-
return { name: 'rotate-key', requestType: at(ns, 'epoch') }
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export function rpcCommands(ns) {
|
|
122
|
-
const ref = (n) => at(ns, n)
|
|
123
|
-
return [
|
|
124
|
-
{ name: 'init', request: { name: ref('req-empty') }, response: { name: ref('res-identity') } },
|
|
125
|
-
{
|
|
126
|
-
name: 'restore',
|
|
127
|
-
request: { name: ref('req-restore') },
|
|
128
|
-
response: { name: ref('res-identity') }
|
|
129
|
-
},
|
|
130
|
-
{ name: 'seed', request: { name: ref('req-empty') }, response: { name: ref('res-seed') } },
|
|
131
|
-
{ name: 'add-row', request: { name: ref('req-row') }, response: { name: ref('res-data') } },
|
|
132
|
-
{
|
|
133
|
-
name: 'add-file',
|
|
134
|
-
request: { name: ref('req-add-file') },
|
|
135
|
-
response: { name: ref('res-data') }
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
name: 'add-handle',
|
|
139
|
-
request: { name: ref('req-row') },
|
|
140
|
-
response: { name: ref('res-handle') }
|
|
141
|
-
},
|
|
142
|
-
{ name: 'set', request: { name: ref('req-row') }, response: { name: ref('res-data') } },
|
|
143
|
-
{ name: 'get', request: { name: ref('req-query') }, response: { name: ref('res-rows') } },
|
|
144
|
-
{ name: 'get-one', request: { name: ref('req-id') }, response: { name: ref('res-data') } },
|
|
145
|
-
{ name: 'del', request: { name: ref('req-id') }, response: { name: ref('res-ok') } },
|
|
146
|
-
{ name: 'count', request: { name: ref('req-query') }, response: { name: ref('res-count') } },
|
|
147
|
-
{
|
|
148
|
-
name: 'watch',
|
|
149
|
-
request: { name: ref('req-query') },
|
|
150
|
-
response: { name: ref('res-rows'), stream: true }
|
|
151
|
-
},
|
|
152
|
-
{ name: 'call', request: { name: ref('req-call') }, response: { name: ref('res-data') } },
|
|
153
|
-
{ name: 'invite', request: { name: ref('req-invite') }, response: { name: ref('res-invite') } },
|
|
154
|
-
{ name: 'revoke', request: { name: ref('req-revoke') }, response: { name: ref('res-ok') } },
|
|
155
|
-
{ name: 'join', request: { name: ref('req-join') }, response: { name: ref('res-handle') } },
|
|
156
|
-
{
|
|
157
|
-
name: 'open-handle',
|
|
158
|
-
request: { name: ref('req-open') },
|
|
159
|
-
response: { name: ref('res-handle') }
|
|
160
|
-
},
|
|
161
|
-
{
|
|
162
|
-
name: 'close-handle',
|
|
163
|
-
request: { name: ref('req-handle') },
|
|
164
|
-
response: { name: ref('res-ok') }
|
|
165
|
-
},
|
|
166
|
-
{ name: 'leave', request: { name: ref('req-handle') }, response: { name: ref('res-ok') } },
|
|
167
|
-
{
|
|
168
|
-
name: 'changes',
|
|
169
|
-
request: { name: ref('req-query') },
|
|
170
|
-
response: { name: ref('res-changes'), stream: true }
|
|
171
|
-
},
|
|
172
|
-
{ name: 'rotate', request: { name: ref('req-handle') }, response: { name: ref('res-epoch') } }
|
|
173
|
-
]
|
|
174
|
-
}
|
package/src/lib/internal.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
// Process-wide registry for extensions registered via `cero.use()`.
|
|
2
|
-
// `build()` folds in each extension's schema; `cero()` runs each setup.
|
|
3
|
-
// The bundled extensions are on by default — `cero.use(profileSync({...}))`
|
|
4
|
-
// replaces a default by name, `{ extensions: false }` (on build and cero)
|
|
5
|
-
// leaves them out entirely.
|
|
6
|
-
import { profileSync } from '../extensions/profile-sync.js'
|
|
7
|
-
import { handleSync } from '../extensions/handle-sync.js'
|
|
8
|
-
|
|
9
|
-
export const internal = { extensions: [profileSync(), handleSync()] }
|
package/types/lib/internal.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export declare const internal: {
|
|
2
|
-
extensions: ({
|
|
3
|
-
name: string;
|
|
4
|
-
bundled: boolean;
|
|
5
|
-
schema: {
|
|
6
|
-
profile: import("@cero-base/core").TypeDef;
|
|
7
|
-
members: {
|
|
8
|
-
kind: 'extend';
|
|
9
|
-
fields: Record<string, import("@cero-base/core").Prim>;
|
|
10
|
-
};
|
|
11
|
-
};
|
|
12
|
-
setup(me: any): void;
|
|
13
|
-
} | {
|
|
14
|
-
name: string;
|
|
15
|
-
bundled: boolean;
|
|
16
|
-
schema: {
|
|
17
|
-
handles: {
|
|
18
|
-
kind: 'extend';
|
|
19
|
-
fields: Record<string, import("@cero-base/core").Prim>;
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
setup(me: any): void;
|
|
23
|
-
})[];
|
|
24
|
-
};
|