@cero-base/core 0.0.5 → 0.4.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/LICENSE +201 -0
- package/README.md +200 -61
- package/package.json +85 -26
- package/src/blobs/index.js +297 -0
- package/src/database/CLAUDE.md +3 -0
- package/src/database/bootstrap.js +76 -0
- package/src/database/dispatch.js +156 -0
- package/src/database/index.js +572 -0
- package/src/identity/CLAUDE.md +3 -0
- package/src/identity/index.js +232 -0
- package/src/index.js +20 -1
- package/src/lib/CLAUDE.md +3 -0
- package/src/lib/constants.js +24 -4
- package/src/lib/errors.js +150 -0
- package/src/lib/schema.js +59 -194
- package/src/lib/spec/index.js +353 -0
- package/src/lib/spec/schema.json +284 -0
- package/src/lib/utils.js +54 -49
- package/src/network/discovery.js +80 -0
- package/src/network/index.js +231 -0
- package/src/pairing/index.js +482 -0
- package/src/pairing/invite.js +199 -0
- package/src/rpc/client.js +45 -0
- package/src/rpc/index.js +141 -0
- package/src/rpc/server.js +45 -0
- package/src/storage/index.js +261 -0
- package/types/blobs/index.d.ts +169 -0
- package/types/database/bootstrap.d.ts +17 -0
- package/types/database/dispatch.d.ts +8 -0
- package/types/database/index.d.ts +329 -0
- package/types/identity/index.d.ts +160 -0
- package/types/index.d.ts +11 -0
- package/types/lib/constants.d.ts +13 -0
- package/types/lib/errors.d.ts +110 -0
- package/types/lib/schema.d.ts +53 -0
- package/types/lib/spec/index.d.ts +95 -0
- package/types/lib/utils.d.ts +39 -0
- package/types/network/discovery.d.ts +44 -0
- package/types/network/index.d.ts +115 -0
- package/types/pairing/index.d.ts +194 -0
- package/types/pairing/invite.d.ts +157 -0
- package/types/rpc/client.d.ts +18 -0
- package/types/rpc/index.d.ts +67 -0
- package/types/rpc/server.d.ts +18 -0
- package/types/storage/index.d.ts +163 -0
- package/src/lib/base.js +0 -98
- package/src/lib/batch.js +0 -95
- package/src/lib/builder.js +0 -24
- package/src/lib/collection.js +0 -208
- package/src/lib/crypto.js +0 -6
- package/src/lib/index.js +0 -6
- package/src/lib/room.js +0 -156
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
export function resolveStruct(name: any, v?: number): {
|
|
2
|
+
preencode(state: any, m: any): void;
|
|
3
|
+
encode(state: any, m: any): void;
|
|
4
|
+
decode(state: any): {
|
|
5
|
+
hash: any;
|
|
6
|
+
coreKey: any;
|
|
7
|
+
blockOffset: any;
|
|
8
|
+
blockLength: any;
|
|
9
|
+
byteOffset: any;
|
|
10
|
+
byteLength: any;
|
|
11
|
+
size: any;
|
|
12
|
+
createdAt: any;
|
|
13
|
+
meta: any;
|
|
14
|
+
} | {
|
|
15
|
+
status: any;
|
|
16
|
+
reason: any;
|
|
17
|
+
key: any;
|
|
18
|
+
encryptionKey: any;
|
|
19
|
+
extra: any;
|
|
20
|
+
} | {
|
|
21
|
+
data: any;
|
|
22
|
+
} | {
|
|
23
|
+
id: any;
|
|
24
|
+
name: any;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
export function getStruct(name: any, v?: number): {
|
|
28
|
+
preencode(state: any, m: any): void;
|
|
29
|
+
encode(state: any, m: any): void;
|
|
30
|
+
decode(state: any): {
|
|
31
|
+
hash: any;
|
|
32
|
+
coreKey: any;
|
|
33
|
+
blockOffset: any;
|
|
34
|
+
blockLength: any;
|
|
35
|
+
byteOffset: any;
|
|
36
|
+
byteLength: any;
|
|
37
|
+
size: any;
|
|
38
|
+
createdAt: any;
|
|
39
|
+
meta: any;
|
|
40
|
+
} | {
|
|
41
|
+
status: any;
|
|
42
|
+
reason: any;
|
|
43
|
+
key: any;
|
|
44
|
+
encryptionKey: any;
|
|
45
|
+
extra: any;
|
|
46
|
+
} | {
|
|
47
|
+
data: any;
|
|
48
|
+
} | {
|
|
49
|
+
id: any;
|
|
50
|
+
name: any;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
export function getEnum(name: any): void;
|
|
54
|
+
export function getEncoding(name: any): {
|
|
55
|
+
preencode(state: any, m: any): void;
|
|
56
|
+
encode(state: any, m: any): void;
|
|
57
|
+
decode(state: any): {
|
|
58
|
+
status: any;
|
|
59
|
+
reason: any;
|
|
60
|
+
key: any;
|
|
61
|
+
encryptionKey: any;
|
|
62
|
+
extra: any;
|
|
63
|
+
};
|
|
64
|
+
} | {
|
|
65
|
+
preencode(state: any, m: any): void;
|
|
66
|
+
encode(state: any, m: any): void;
|
|
67
|
+
decode(state: any): {
|
|
68
|
+
data: any;
|
|
69
|
+
};
|
|
70
|
+
} | {
|
|
71
|
+
preencode(state: any, m: any): void;
|
|
72
|
+
encode(state: any, m: any): void;
|
|
73
|
+
decode(state: any): {
|
|
74
|
+
id: any;
|
|
75
|
+
name: any;
|
|
76
|
+
};
|
|
77
|
+
} | {
|
|
78
|
+
preencode(state: any, m: any): void;
|
|
79
|
+
encode(state: any, m: any): void;
|
|
80
|
+
decode(state: any): {
|
|
81
|
+
hash: any;
|
|
82
|
+
coreKey: any;
|
|
83
|
+
blockOffset: any;
|
|
84
|
+
blockLength: any;
|
|
85
|
+
byteOffset: any;
|
|
86
|
+
byteLength: any;
|
|
87
|
+
size: any;
|
|
88
|
+
createdAt: any;
|
|
89
|
+
meta: any;
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
export function encode(name: any, value: any, v?: number): any;
|
|
93
|
+
export function decode(name: any, buffer: any, v?: number): any;
|
|
94
|
+
export function setVersion(v: any): void;
|
|
95
|
+
export let version: number;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a short opaque id (z32-encoded 16 random bytes).
|
|
3
|
+
*
|
|
4
|
+
* @returns {string}
|
|
5
|
+
*/
|
|
6
|
+
export function genId(): string;
|
|
7
|
+
/**
|
|
8
|
+
* Stream-of-snapshots primitive. Couples a `get` (returns the latest value)
|
|
9
|
+
* with a `watch` (re-fires on change) and emits the newest snapshot every
|
|
10
|
+
* time `watch` ticks.
|
|
11
|
+
*
|
|
12
|
+
* @template T
|
|
13
|
+
* @param {object} args
|
|
14
|
+
* @param {() => Promise<T> | T} args.get
|
|
15
|
+
* @param {(fn: () => void) => (() => void) | void} args.watch Returns an unsubscribe.
|
|
16
|
+
* @returns {import('streamx').Readable<T>}
|
|
17
|
+
*/
|
|
18
|
+
export function subscribe<T>({ get, watch }: {
|
|
19
|
+
get: () => Promise<T> | T;
|
|
20
|
+
watch: (fn: () => void) => (() => void) | void;
|
|
21
|
+
}): any;
|
|
22
|
+
/**
|
|
23
|
+
* z32-encode a 32-byte key into a canonical string id.
|
|
24
|
+
*
|
|
25
|
+
* @type {(key: Uint8Array) => string}
|
|
26
|
+
*/
|
|
27
|
+
export const toId: (key: Uint8Array) => string;
|
|
28
|
+
/**
|
|
29
|
+
* Decode a canonical string id back into a 32-byte key.
|
|
30
|
+
*
|
|
31
|
+
* @type {(id: string) => Uint8Array}
|
|
32
|
+
*/
|
|
33
|
+
export const toKey: (id: string) => Uint8Array;
|
|
34
|
+
/**
|
|
35
|
+
* Test whether a string is a well-formed canonical id.
|
|
36
|
+
*
|
|
37
|
+
* @type {(id: string) => boolean}
|
|
38
|
+
*/
|
|
39
|
+
export const isKeyId: (id: string) => boolean;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handle for a single topic membership on a {@link Network}. Wraps a hyperswarm
|
|
3
|
+
* PeerDiscovery session and lets it switch between active/passive announce/lookup.
|
|
4
|
+
*/
|
|
5
|
+
export class Discovery {
|
|
6
|
+
/**
|
|
7
|
+
* @param {import('./index.js').Network} network Owning network.
|
|
8
|
+
* @param {any} session Hyperswarm PeerDiscovery session from `swarm.join()`.
|
|
9
|
+
* @param {'active' | 'passive'} mode
|
|
10
|
+
*/
|
|
11
|
+
constructor(network: import("./index.js").Network, session: any, mode: "active" | "passive");
|
|
12
|
+
network: import("./index.js").Network;
|
|
13
|
+
session: any;
|
|
14
|
+
_mode: "active" | "passive";
|
|
15
|
+
_destroyed: boolean;
|
|
16
|
+
/** @returns {'active' | 'passive'} */
|
|
17
|
+
get mode(): "active" | "passive";
|
|
18
|
+
/** @returns {boolean} */
|
|
19
|
+
get destroyed(): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Switch to active (client+server) announce/lookup.
|
|
22
|
+
*
|
|
23
|
+
* @returns {Promise<void>}
|
|
24
|
+
*/
|
|
25
|
+
activate(): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Switch to passive announce.
|
|
28
|
+
*
|
|
29
|
+
* @returns {Promise<void>}
|
|
30
|
+
*/
|
|
31
|
+
deactivate(): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Wait for the current announce/lookup to settle.
|
|
34
|
+
*
|
|
35
|
+
* @returns {Promise<void>}
|
|
36
|
+
*/
|
|
37
|
+
flush(): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Leave the topic and tear down the session. Idempotent.
|
|
40
|
+
*
|
|
41
|
+
* @returns {Promise<void>}
|
|
42
|
+
*/
|
|
43
|
+
destroy(): Promise<void>;
|
|
44
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {object} NetworkOpts
|
|
3
|
+
* @property {import('../identity/index.js').Identity} [identity] Long-lived keypair used as the swarm identity.
|
|
4
|
+
* @property {Array<{ host: string, port: number }>} [bootstrap] Custom DHT bootstrap nodes.
|
|
5
|
+
* @property {(remotePublicKey: Uint8Array, payload: any) => boolean} [firewall] Incoming-connection filter.
|
|
6
|
+
* @property {Uint8Array[]} [relayThrough] Relay public keys to tunnel through.
|
|
7
|
+
*
|
|
8
|
+
* @typedef {{ replicate: (stream: any) => any }} Replicable
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Hyperswarm peer-discovery + replication multiplexer. Wraps a swarm and a
|
|
12
|
+
* shared wakeup channel, replicating any attached resource onto every peer.
|
|
13
|
+
*/
|
|
14
|
+
export class Network extends ReadyResource {
|
|
15
|
+
/** @param {NetworkOpts} [opts] */
|
|
16
|
+
constructor({ identity, bootstrap, firewall, relayThrough }?: NetworkOpts);
|
|
17
|
+
identity: import("../index.js").Identity;
|
|
18
|
+
bootstrap: {
|
|
19
|
+
host: string;
|
|
20
|
+
port: number;
|
|
21
|
+
}[];
|
|
22
|
+
firewall: (remotePublicKey: Uint8Array, payload: any) => boolean;
|
|
23
|
+
relayThrough: Uint8Array<ArrayBufferLike>[];
|
|
24
|
+
swarm: any;
|
|
25
|
+
wakeup: any;
|
|
26
|
+
_replicateables: Set<any>;
|
|
27
|
+
_discoveries: Set<any>;
|
|
28
|
+
/** @returns {Map<string, any>} Known peers keyed by public-key string. */
|
|
29
|
+
get peers(): Map<string, any>;
|
|
30
|
+
/** @returns {Set<any>} Live connection streams. */
|
|
31
|
+
get connections(): Set<any>;
|
|
32
|
+
/** @returns {boolean} */
|
|
33
|
+
get suspended(): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Wait for pending DHT announces and lookups to settle, bounded by timeout.
|
|
36
|
+
*
|
|
37
|
+
* @param {{ timeout?: number }} [opts]
|
|
38
|
+
* @returns {Promise<void>}
|
|
39
|
+
*/
|
|
40
|
+
flush({ timeout }?: {
|
|
41
|
+
timeout?: number;
|
|
42
|
+
}): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Pause the swarm — keeps state, drops sockets. Idempotent.
|
|
45
|
+
*
|
|
46
|
+
* @returns {Promise<void>}
|
|
47
|
+
*/
|
|
48
|
+
suspend(): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Resume a suspended swarm. Idempotent.
|
|
51
|
+
*
|
|
52
|
+
* @returns {Promise<void>}
|
|
53
|
+
*/
|
|
54
|
+
resume(): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Announce/lookup on a 32-byte topic and return a Discovery handle.
|
|
57
|
+
*
|
|
58
|
+
* @param {Uint8Array} topic
|
|
59
|
+
* @param {{ mode?: 'active' | 'passive' }} [opts] `active` = client+server, `passive` = server-only
|
|
60
|
+
* @returns {Discovery}
|
|
61
|
+
*/
|
|
62
|
+
join(topic: Uint8Array, { mode }?: {
|
|
63
|
+
mode?: "active" | "passive";
|
|
64
|
+
}): Discovery;
|
|
65
|
+
/**
|
|
66
|
+
* Register a replicable resource (hypercore, autobee, hyperdb).
|
|
67
|
+
* It is replicated on every current and future swarm connection.
|
|
68
|
+
*
|
|
69
|
+
* @param {Replicable} core
|
|
70
|
+
* @returns {void}
|
|
71
|
+
*/
|
|
72
|
+
attach(core: Replicable): void;
|
|
73
|
+
/**
|
|
74
|
+
* Unregister a previously attached resource. New connections will no
|
|
75
|
+
* longer replicate it (existing replication streams continue).
|
|
76
|
+
*
|
|
77
|
+
* @param {Replicable} core
|
|
78
|
+
* @returns {void}
|
|
79
|
+
*/
|
|
80
|
+
detach(core: Replicable): void;
|
|
81
|
+
/**
|
|
82
|
+
* Replicate a one-off resource onto every current swarm connection
|
|
83
|
+
* without registering it as a long-lived attachment.
|
|
84
|
+
*
|
|
85
|
+
* @param {Replicable} target
|
|
86
|
+
* @returns {void}
|
|
87
|
+
*/
|
|
88
|
+
replicate(target: Replicable): void;
|
|
89
|
+
}
|
|
90
|
+
export type NetworkOpts = {
|
|
91
|
+
/**
|
|
92
|
+
* Long-lived keypair used as the swarm identity.
|
|
93
|
+
*/
|
|
94
|
+
identity?: import("../identity/index.js").Identity;
|
|
95
|
+
/**
|
|
96
|
+
* Custom DHT bootstrap nodes.
|
|
97
|
+
*/
|
|
98
|
+
bootstrap?: Array<{
|
|
99
|
+
host: string;
|
|
100
|
+
port: number;
|
|
101
|
+
}>;
|
|
102
|
+
/**
|
|
103
|
+
* Incoming-connection filter.
|
|
104
|
+
*/
|
|
105
|
+
firewall?: (remotePublicKey: Uint8Array, payload: any) => boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Relay public keys to tunnel through.
|
|
108
|
+
*/
|
|
109
|
+
relayThrough?: Uint8Array[];
|
|
110
|
+
};
|
|
111
|
+
export type Replicable = {
|
|
112
|
+
replicate: (stream: any) => any;
|
|
113
|
+
};
|
|
114
|
+
import ReadyResource from 'ready-resource';
|
|
115
|
+
import { Discovery } from './discovery.js';
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {object} PairingOpts
|
|
3
|
+
* @property {import('../network/index.js').Network} network Network to host the BlindPairing member.
|
|
4
|
+
* @property {import('../identity/index.js').Identity} identity Identity used to sign invites and derive the topic.
|
|
5
|
+
* @property {Uint8Array} [topic] Optional override topic; defaults to `identity.publicKey`.
|
|
6
|
+
* @property {any} [inviteEncoding] compact-encoding type for the invite payload `data`.
|
|
7
|
+
* @property {any} [joinerEncoding] compact-encoding type for the joiner-supplied `userData`.
|
|
8
|
+
*
|
|
9
|
+
* @typedef {object} CreateInviteOpts
|
|
10
|
+
* @property {string} [role] Role tag bound into the invite.
|
|
11
|
+
* @property {number} [expiresIn] TTL in ms; `0`/omitted = no expiry.
|
|
12
|
+
* @property {any} [data] Arbitrary payload (encoded via `inviteEncoding` when set).
|
|
13
|
+
*
|
|
14
|
+
* @typedef {object} JoinOpts
|
|
15
|
+
* @property {any} [userData] Payload sent with the candidate request.
|
|
16
|
+
* @property {number} [timeout] Deadline for the handshake, in ms. Defaults to 30000.
|
|
17
|
+
*
|
|
18
|
+
* @typedef {object} ConfirmOpts
|
|
19
|
+
* @property {Uint8Array} [key] 32-byte resource key delivered to the joiner; required at runtime.
|
|
20
|
+
* @property {Uint8Array | null} [encryptionKey] Optional 32-byte symmetric key.
|
|
21
|
+
* @property {Uint8Array | null} [additional] Extra opaque bytes piggybacked on the response.
|
|
22
|
+
*
|
|
23
|
+
* @typedef {{ key: Uint8Array, encryptionKey: Uint8Array | null, additional: Uint8Array | null }} JoinResult
|
|
24
|
+
*
|
|
25
|
+
* @typedef {object} CandidateOpts
|
|
26
|
+
* @property {Pairing} pairing Owning Pairing instance.
|
|
27
|
+
* @property {any} req blind-pairing candidate request being answered.
|
|
28
|
+
* @property {Invite} invite Invite the candidate paired against.
|
|
29
|
+
* @property {Uint8Array} seed Per-invite seed used to sign the response.
|
|
30
|
+
* @property {any} userData Decoded joiner payload (raw bytes when no encoding).
|
|
31
|
+
* @property {() => void} onsettle Called once when the candidate is confirmed or denied.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Blind-pairing membership wrapper. Hosts invites, dispatches incoming
|
|
35
|
+
* candidates to the application for accept/deny, and provides the joiner
|
|
36
|
+
* side of the handshake. All wire payloads are signed and routed through
|
|
37
|
+
* the supplied network.
|
|
38
|
+
*/
|
|
39
|
+
export class Pairing extends ReadyResource {
|
|
40
|
+
/**
|
|
41
|
+
* Cheap structural test for a candidate invite string.
|
|
42
|
+
*
|
|
43
|
+
* @param {unknown} str
|
|
44
|
+
* @returns {boolean}
|
|
45
|
+
*/
|
|
46
|
+
static isInvite(str: unknown): boolean;
|
|
47
|
+
/** @param {PairingOpts} [opts] */
|
|
48
|
+
constructor({ network, identity, topic, inviteEncoding, joinerEncoding }?: PairingOpts);
|
|
49
|
+
network: import("../index.js").Network;
|
|
50
|
+
identity: import("../index.js").Identity;
|
|
51
|
+
topic: Uint8Array<ArrayBufferLike>;
|
|
52
|
+
inviteEncoding: any;
|
|
53
|
+
joinerEncoding: any;
|
|
54
|
+
_blind: any;
|
|
55
|
+
_member: any;
|
|
56
|
+
_invites: Map<any, any>;
|
|
57
|
+
_candidates: Set<any>;
|
|
58
|
+
/**
|
|
59
|
+
* Mint a new pairing invite. Returns its canonical wire form (z32 string).
|
|
60
|
+
*
|
|
61
|
+
* @param {CreateInviteOpts} [opts]
|
|
62
|
+
* @returns {Promise<string>}
|
|
63
|
+
*/
|
|
64
|
+
createInvite({ role, expiresIn, data }?: CreateInviteOpts): Promise<string>;
|
|
65
|
+
/**
|
|
66
|
+
* Forget a previously-minted invite. New candidates carrying it will be
|
|
67
|
+
* dropped silently.
|
|
68
|
+
*
|
|
69
|
+
* @param {string} inviteStr
|
|
70
|
+
* @returns {boolean}
|
|
71
|
+
*/
|
|
72
|
+
revoke(inviteStr: string): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Joiner side — start a pairing handshake against `inviteStr` and resolve
|
|
75
|
+
* with the host's response when the host confirms.
|
|
76
|
+
*
|
|
77
|
+
* @param {string} inviteStr
|
|
78
|
+
* @param {JoinOpts} [opts]
|
|
79
|
+
* @returns {Promise<JoinResult>}
|
|
80
|
+
*/
|
|
81
|
+
join(inviteStr: string, { userData, timeout }?: JoinOpts): Promise<JoinResult>;
|
|
82
|
+
/**
|
|
83
|
+
* Whether the underlying blind-pairing layer is suspended.
|
|
84
|
+
*
|
|
85
|
+
* @returns {boolean}
|
|
86
|
+
*/
|
|
87
|
+
get suspended(): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Pause blind-pairing — keeps state, drops sockets. Idempotent.
|
|
90
|
+
*
|
|
91
|
+
* @returns {Promise<void>}
|
|
92
|
+
*/
|
|
93
|
+
suspend(): Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* Resume a suspended blind-pairing layer. Idempotent.
|
|
96
|
+
*
|
|
97
|
+
* @returns {Promise<void>}
|
|
98
|
+
*/
|
|
99
|
+
resume(): Promise<void>;
|
|
100
|
+
_onCandidate(req: any): Promise<void>;
|
|
101
|
+
}
|
|
102
|
+
export type PairingOpts = {
|
|
103
|
+
/**
|
|
104
|
+
* Network to host the BlindPairing member.
|
|
105
|
+
*/
|
|
106
|
+
network: import("../network/index.js").Network;
|
|
107
|
+
/**
|
|
108
|
+
* Identity used to sign invites and derive the topic.
|
|
109
|
+
*/
|
|
110
|
+
identity: import("../identity/index.js").Identity;
|
|
111
|
+
/**
|
|
112
|
+
* Optional override topic; defaults to `identity.publicKey`.
|
|
113
|
+
*/
|
|
114
|
+
topic?: Uint8Array;
|
|
115
|
+
/**
|
|
116
|
+
* compact-encoding type for the invite payload `data`.
|
|
117
|
+
*/
|
|
118
|
+
inviteEncoding?: any;
|
|
119
|
+
/**
|
|
120
|
+
* compact-encoding type for the joiner-supplied `userData`.
|
|
121
|
+
*/
|
|
122
|
+
joinerEncoding?: any;
|
|
123
|
+
};
|
|
124
|
+
export type CreateInviteOpts = {
|
|
125
|
+
/**
|
|
126
|
+
* Role tag bound into the invite.
|
|
127
|
+
*/
|
|
128
|
+
role?: string;
|
|
129
|
+
/**
|
|
130
|
+
* TTL in ms; `0`/omitted = no expiry.
|
|
131
|
+
*/
|
|
132
|
+
expiresIn?: number;
|
|
133
|
+
/**
|
|
134
|
+
* Arbitrary payload (encoded via `inviteEncoding` when set).
|
|
135
|
+
*/
|
|
136
|
+
data?: any;
|
|
137
|
+
};
|
|
138
|
+
export type JoinOpts = {
|
|
139
|
+
/**
|
|
140
|
+
* Payload sent with the candidate request.
|
|
141
|
+
*/
|
|
142
|
+
userData?: any;
|
|
143
|
+
/**
|
|
144
|
+
* Deadline for the handshake, in ms. Defaults to 30000.
|
|
145
|
+
*/
|
|
146
|
+
timeout?: number;
|
|
147
|
+
};
|
|
148
|
+
export type ConfirmOpts = {
|
|
149
|
+
/**
|
|
150
|
+
* 32-byte resource key delivered to the joiner; required at runtime.
|
|
151
|
+
*/
|
|
152
|
+
key?: Uint8Array;
|
|
153
|
+
/**
|
|
154
|
+
* Optional 32-byte symmetric key.
|
|
155
|
+
*/
|
|
156
|
+
encryptionKey?: Uint8Array | null;
|
|
157
|
+
/**
|
|
158
|
+
* Extra opaque bytes piggybacked on the response.
|
|
159
|
+
*/
|
|
160
|
+
additional?: Uint8Array | null;
|
|
161
|
+
};
|
|
162
|
+
export type JoinResult = {
|
|
163
|
+
key: Uint8Array;
|
|
164
|
+
encryptionKey: Uint8Array | null;
|
|
165
|
+
additional: Uint8Array | null;
|
|
166
|
+
};
|
|
167
|
+
export type CandidateOpts = {
|
|
168
|
+
/**
|
|
169
|
+
* Owning Pairing instance.
|
|
170
|
+
*/
|
|
171
|
+
pairing: Pairing;
|
|
172
|
+
/**
|
|
173
|
+
* blind-pairing candidate request being answered.
|
|
174
|
+
*/
|
|
175
|
+
req: any;
|
|
176
|
+
/**
|
|
177
|
+
* Invite the candidate paired against.
|
|
178
|
+
*/
|
|
179
|
+
invite: Invite;
|
|
180
|
+
/**
|
|
181
|
+
* Per-invite seed used to sign the response.
|
|
182
|
+
*/
|
|
183
|
+
seed: Uint8Array;
|
|
184
|
+
/**
|
|
185
|
+
* Decoded joiner payload (raw bytes when no encoding).
|
|
186
|
+
*/
|
|
187
|
+
userData: any;
|
|
188
|
+
/**
|
|
189
|
+
* Called once when the candidate is confirmed or denied.
|
|
190
|
+
*/
|
|
191
|
+
onsettle: () => void;
|
|
192
|
+
};
|
|
193
|
+
import ReadyResource from 'ready-resource';
|
|
194
|
+
import { Invite } from './invite.js';
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {object} InviteFields
|
|
3
|
+
* @property {Uint8Array} publicKey Signer's long-lived public key.
|
|
4
|
+
* @property {string} role Optional role tag baked into the signed body.
|
|
5
|
+
* @property {number} expires Absolute expiry timestamp; `0` means never.
|
|
6
|
+
* @property {Uint8Array | null} data Encoded payload (raw or via `encoding`).
|
|
7
|
+
* @property {Uint8Array} blindInvite Raw blind-pairing invite handed to candidates.
|
|
8
|
+
* @property {Uint8Array} [sig] Ed25519 signature over the canonical body.
|
|
9
|
+
* @property {string | null} [_str] Cached z32 string form.
|
|
10
|
+
*
|
|
11
|
+
* @typedef {object} CreateInviteOpts
|
|
12
|
+
* @property {Uint8Array} secretKey 64-byte Ed25519 secret key used to sign.
|
|
13
|
+
* @property {Uint8Array} publicKey 32-byte Ed25519 public key matching `secretKey`.
|
|
14
|
+
* @property {string} role Optional role tag for the joiner.
|
|
15
|
+
* @property {number} expiresIn TTL in ms from now; `0` means never expires.
|
|
16
|
+
* @property {any} data Caller payload; encoded via `encoding` when provided.
|
|
17
|
+
* @property {Uint8Array} blindInvite Raw blind-pairing invite to wrap.
|
|
18
|
+
* @property {any} [encoding] compact-encoding type used to encode `data`.
|
|
19
|
+
*
|
|
20
|
+
* @typedef {object} ParseInviteOpts
|
|
21
|
+
* @property {any} [encoding] compact-encoding type used to decode the embedded payload.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Signed, expirable pairing invite. Wraps a blind-pairing invite with a
|
|
25
|
+
* role, optional payload and an Ed25519 signature so the host can be
|
|
26
|
+
* authenticated by the joiner before any handshake happens.
|
|
27
|
+
*
|
|
28
|
+
* @property {any} [_rawData] Decoded payload kept alongside the encoded `data` for convenience.
|
|
29
|
+
* @property {any} _blind Lazily-decoded blind-pairing invite view (cache).
|
|
30
|
+
*/
|
|
31
|
+
export class Invite {
|
|
32
|
+
/**
|
|
33
|
+
* Build and sign a new invite envelope wrapping a blind-pairing invite.
|
|
34
|
+
*
|
|
35
|
+
* @param {CreateInviteOpts} opts
|
|
36
|
+
* @returns {Invite}
|
|
37
|
+
*/
|
|
38
|
+
static create({ secretKey, publicKey, role, expiresIn, data, blindInvite, encoding }: CreateInviteOpts): Invite;
|
|
39
|
+
/**
|
|
40
|
+
* Parse a z32 invite string, verify its signature and (optionally) decode
|
|
41
|
+
* its payload.
|
|
42
|
+
*
|
|
43
|
+
* @param {string} str
|
|
44
|
+
* @param {ParseInviteOpts} [opts]
|
|
45
|
+
* @returns {Invite}
|
|
46
|
+
*/
|
|
47
|
+
static parse(str: string, { encoding }?: ParseInviteOpts): Invite;
|
|
48
|
+
/**
|
|
49
|
+
* Cheap structural test — does `str` decode as an invite envelope? Does not
|
|
50
|
+
* verify the signature.
|
|
51
|
+
*
|
|
52
|
+
* @param {unknown} str
|
|
53
|
+
* @returns {boolean}
|
|
54
|
+
*/
|
|
55
|
+
static isInvite(str: unknown): boolean;
|
|
56
|
+
/** @param {InviteFields} fields */
|
|
57
|
+
constructor(fields: InviteFields);
|
|
58
|
+
version: number;
|
|
59
|
+
publicKey: Uint8Array<ArrayBufferLike>;
|
|
60
|
+
role: string;
|
|
61
|
+
expires: number;
|
|
62
|
+
data: Uint8Array<ArrayBufferLike>;
|
|
63
|
+
blindInvite: Uint8Array<ArrayBufferLike>;
|
|
64
|
+
sig: Uint8Array<ArrayBufferLike>;
|
|
65
|
+
_str: string;
|
|
66
|
+
_blind: any;
|
|
67
|
+
/**
|
|
68
|
+
* Whether the invite is past its TTL (always `false` when `expires === 0`).
|
|
69
|
+
*
|
|
70
|
+
* @returns {boolean}
|
|
71
|
+
*/
|
|
72
|
+
get expired(): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Lazily-decoded view of the underlying blind-pairing invite.
|
|
75
|
+
*
|
|
76
|
+
* @returns {any}
|
|
77
|
+
*/
|
|
78
|
+
get blind(): any;
|
|
79
|
+
/**
|
|
80
|
+
* Verify the embedded signature against the encoded body.
|
|
81
|
+
*
|
|
82
|
+
* @returns {boolean}
|
|
83
|
+
*/
|
|
84
|
+
verify(): boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Serialise to the canonical z32 wire form (cached).
|
|
87
|
+
*
|
|
88
|
+
* @returns {string}
|
|
89
|
+
*/
|
|
90
|
+
toString(): string;
|
|
91
|
+
}
|
|
92
|
+
export type InviteFields = {
|
|
93
|
+
/**
|
|
94
|
+
* Signer's long-lived public key.
|
|
95
|
+
*/
|
|
96
|
+
publicKey: Uint8Array;
|
|
97
|
+
/**
|
|
98
|
+
* Optional role tag baked into the signed body.
|
|
99
|
+
*/
|
|
100
|
+
role: string;
|
|
101
|
+
/**
|
|
102
|
+
* Absolute expiry timestamp; `0` means never.
|
|
103
|
+
*/
|
|
104
|
+
expires: number;
|
|
105
|
+
/**
|
|
106
|
+
* Encoded payload (raw or via `encoding`).
|
|
107
|
+
*/
|
|
108
|
+
data: Uint8Array | null;
|
|
109
|
+
/**
|
|
110
|
+
* Raw blind-pairing invite handed to candidates.
|
|
111
|
+
*/
|
|
112
|
+
blindInvite: Uint8Array;
|
|
113
|
+
/**
|
|
114
|
+
* Ed25519 signature over the canonical body.
|
|
115
|
+
*/
|
|
116
|
+
sig?: Uint8Array;
|
|
117
|
+
/**
|
|
118
|
+
* Cached z32 string form.
|
|
119
|
+
*/
|
|
120
|
+
_str?: string | null;
|
|
121
|
+
};
|
|
122
|
+
export type CreateInviteOpts = {
|
|
123
|
+
/**
|
|
124
|
+
* 64-byte Ed25519 secret key used to sign.
|
|
125
|
+
*/
|
|
126
|
+
secretKey: Uint8Array;
|
|
127
|
+
/**
|
|
128
|
+
* 32-byte Ed25519 public key matching `secretKey`.
|
|
129
|
+
*/
|
|
130
|
+
publicKey: Uint8Array;
|
|
131
|
+
/**
|
|
132
|
+
* Optional role tag for the joiner.
|
|
133
|
+
*/
|
|
134
|
+
role: string;
|
|
135
|
+
/**
|
|
136
|
+
* TTL in ms from now; `0` means never expires.
|
|
137
|
+
*/
|
|
138
|
+
expiresIn: number;
|
|
139
|
+
/**
|
|
140
|
+
* Caller payload; encoded via `encoding` when provided.
|
|
141
|
+
*/
|
|
142
|
+
data: any;
|
|
143
|
+
/**
|
|
144
|
+
* Raw blind-pairing invite to wrap.
|
|
145
|
+
*/
|
|
146
|
+
blindInvite: Uint8Array;
|
|
147
|
+
/**
|
|
148
|
+
* compact-encoding type used to encode `data`.
|
|
149
|
+
*/
|
|
150
|
+
encoding?: any;
|
|
151
|
+
};
|
|
152
|
+
export type ParseInviteOpts = {
|
|
153
|
+
/**
|
|
154
|
+
* compact-encoding type used to decode the embedded payload.
|
|
155
|
+
*/
|
|
156
|
+
encoding?: any;
|
|
157
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side RPC adapter. Mirror of `RPCServer` — wraps an IPC duplex
|
|
3
|
+
* in a length-framed stream and constructs the spec's hrpc binding ready
|
|
4
|
+
* to issue requests. Frames are paused until `_open` runs so handlers
|
|
5
|
+
* registered before `ready()` see a clean slate.
|
|
6
|
+
*/
|
|
7
|
+
export class RPCClient extends ReadyResource {
|
|
8
|
+
/**
|
|
9
|
+
* @param {any} ipc Duplex IPC stream (e.g. a socket or pipe).
|
|
10
|
+
* @param {import('./index.js').Spec} spec Spec object exposing `rpc` and `schema`.
|
|
11
|
+
*/
|
|
12
|
+
constructor(ipc: any, spec: import("./index.js").Spec);
|
|
13
|
+
ipc: any;
|
|
14
|
+
spec: import("./index.js").Spec;
|
|
15
|
+
framed: any;
|
|
16
|
+
rpc: any;
|
|
17
|
+
}
|
|
18
|
+
import ReadyResource from 'ready-resource';
|