@derec-alliance/nodejs 0.0.5 → 0.0.7
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 +77 -21
- package/derec_descriptor.bin +0 -0
- package/derec_library.d.ts +110 -121
- package/derec_library.js +171 -169
- package/derec_library_bg.wasm +0 -0
- package/derec_library_bg.wasm.d.ts +35 -35
- package/index.d.ts +462 -168
- package/index.js +33 -3
- package/package.json +1 -1
- package/proto/contact.proto +15 -48
- package/proto/getshare.proto +4 -14
- package/proto/pair.proto +5 -29
- package/proto/prepair.proto +14 -39
- package/proto/secretidsversions.proto +4 -14
- package/proto/storeshare.proto +8 -39
- package/proto/unpair.proto +4 -14
- package/proto/updatechannelinfo.proto +16 -45
- package/proto/verify.proto +4 -14
package/index.d.ts
CHANGED
|
@@ -9,15 +9,15 @@ export interface SecretStore {
|
|
|
9
9
|
): Promise<Uint8Array | null | undefined>;
|
|
10
10
|
/**
|
|
11
11
|
* Load secrets of the same `kind` for several channels in one call,
|
|
12
|
-
* scoped to `secretId`. Must return an array with one entry per
|
|
13
|
-
* id, in the same order, using `null` (or `undefined`) for channels
|
|
14
|
-
* with no stored secret of `kind`.
|
|
12
|
+
* scoped to `secretId`. Must return an array with exactly one entry per
|
|
13
|
+
* input id, in the same order, using `null` (or `undefined`) for channels
|
|
14
|
+
* with no stored secret of `kind`. Whether a missing entry is an error is
|
|
15
|
+
* decided by the library.
|
|
15
16
|
*/
|
|
16
17
|
loadMany(
|
|
17
18
|
secretId: string,
|
|
18
19
|
channelIds: string[],
|
|
19
20
|
kind: 0 | 1 | 2,
|
|
20
|
-
missingPolicy: "skip" | "fail",
|
|
21
21
|
): Promise<Array<Uint8Array | null | undefined>>;
|
|
22
22
|
save(
|
|
23
23
|
secretId: string,
|
|
@@ -123,22 +123,15 @@ export declare function channelFilterMatches(
|
|
|
123
123
|
/**
|
|
124
124
|
* The endpoints a peer-supplied message advertises, in the peer's own order.
|
|
125
125
|
*
|
|
126
|
-
* Yields `supported_transports` when it is non-empty, and otherwise the
|
|
127
|
-
* singular `transport_protocol` — which is how every implementation predating
|
|
128
|
-
* the offer list advertises, and the reason this is a function rather than a
|
|
129
|
-
* field read. Reading `transport_protocol` directly is a bug: its meaning
|
|
130
|
-
* narrowed to "one entry of a list, and possibly absent", so a peer that has
|
|
131
|
-
* moved past it looks unreachable to a reader that was correct before 0.0.3.
|
|
132
|
-
*
|
|
133
126
|
* Reports what was advertised, not what is acceptable — nothing here is
|
|
134
127
|
* validated, and the protocol still applies its own transport policy to
|
|
135
128
|
* whatever it records.
|
|
136
129
|
*/
|
|
137
130
|
export declare function advertisedEndpoints(
|
|
138
131
|
message:
|
|
139
|
-
| Pick<ContactMessage, "
|
|
140
|
-
| Pick<PairRequestMessage, "
|
|
141
|
-
| Pick<PrePairRequestMessage, "
|
|
132
|
+
| Pick<ContactMessage, "supported_transports">
|
|
133
|
+
| Pick<PairRequestMessage, "supported_transports">
|
|
134
|
+
| Pick<PrePairRequestMessage, "supported_transports">
|
|
142
135
|
| null
|
|
143
136
|
| undefined,
|
|
144
137
|
): TransportProtocol[];
|
|
@@ -228,11 +221,7 @@ export interface ChannelStore {
|
|
|
228
221
|
secretId: string,
|
|
229
222
|
filter: ReplicaFilter,
|
|
230
223
|
): Promise<Uint8Array | null | undefined>;
|
|
231
|
-
linkChannel(
|
|
232
|
-
secretId: string,
|
|
233
|
-
channelId: string,
|
|
234
|
-
linkedChannelId: string,
|
|
235
|
-
): Promise<void>;
|
|
224
|
+
linkChannel(secretId: string, a: string, b: string): Promise<void>;
|
|
236
225
|
linkedChannels(secretId: string, channelId: string): Promise<string[]>;
|
|
237
226
|
}
|
|
238
227
|
|
|
@@ -264,6 +253,35 @@ export interface ShareStore {
|
|
|
264
253
|
save(secretId: string, channelId: string, share: Share): Promise<void>;
|
|
265
254
|
latestVersion(secretId: string): Promise<number | null>;
|
|
266
255
|
removeChannel(secretId: string, channelId: string): Promise<void>;
|
|
256
|
+
/**
|
|
257
|
+
* Drop the shares stored under `(secretId, channelId)` at each of
|
|
258
|
+
* `versions`. Idempotent: a version that is not stored is skipped, and
|
|
259
|
+
* an empty array is a no-op.
|
|
260
|
+
*
|
|
261
|
+
* A helper calls this to apply `StoreShareRequestMessage.keepList`, the
|
|
262
|
+
* complete set of versions the owner wants retained: every stored
|
|
263
|
+
* version outside it is removed once the incoming share is persisted.
|
|
264
|
+
* Shares under other channels or partitions must be left untouched.
|
|
265
|
+
*/
|
|
266
|
+
removeVersions(secretId: string, channelId: string, versions: number[]): Promise<void>;
|
|
267
|
+
/**
|
|
268
|
+
* Owner only: the versions every helper keeps after the owner distributes
|
|
269
|
+
* `version`. Asked once per sharing round, before anything is sent,
|
|
270
|
+
* including the rounds the library starts itself; the answer becomes
|
|
271
|
+
* `keepList` for every helper.
|
|
272
|
+
*
|
|
273
|
+
* Return `null` or `undefined` to send no `keepList` (it goes out empty):
|
|
274
|
+
* helpers then keep every version they hold. An app that wants to cap how
|
|
275
|
+
* many versions helpers retain returns that cap here. A returned list is
|
|
276
|
+
* used as is, plus `version`, which the library always adds. Helpers
|
|
277
|
+
* delete every version that is not listed, so list every version that
|
|
278
|
+
* could still become the latest: those that committed (for example, whose
|
|
279
|
+
* `SharingComplete` reported `threshold_met`) and those whose round is
|
|
280
|
+
* still open. Leave out only versions whose round failed or that the user
|
|
281
|
+
* rolled back; a list that leaves out too much can make the secret
|
|
282
|
+
* unrecoverable.
|
|
283
|
+
*/
|
|
284
|
+
keepList(secretId: string, version: number): Promise<number[] | null | undefined>;
|
|
267
285
|
}
|
|
268
286
|
|
|
269
287
|
export interface UserSecretEntry {
|
|
@@ -276,6 +294,10 @@ export interface UserSecrets {
|
|
|
276
294
|
version: number;
|
|
277
295
|
secrets: UserSecretEntry[];
|
|
278
296
|
description?: string;
|
|
297
|
+
/** Decimal `replica_id` of the member that published `version`. Absent
|
|
298
|
+
* when none is recorded. Store and return it unchanged: replica members
|
|
299
|
+
* compare it to detect a conflicting copy of the same version. */
|
|
300
|
+
author_replica_id?: string;
|
|
279
301
|
}
|
|
280
302
|
|
|
281
303
|
/**
|
|
@@ -319,6 +341,18 @@ export interface StateStore {
|
|
|
319
341
|
loadAll(secretId: string, kind: 0 | 1 | 2 | 3 | 4): Promise<Uint8Array[]>;
|
|
320
342
|
}
|
|
321
343
|
|
|
344
|
+
/** A transport protocol, by name. */
|
|
345
|
+
export type TransportProtocolName = "https" | "grpc";
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* One endpoint a node serves or a peer advertised, as every app-facing call
|
|
349
|
+
* and event carries it.
|
|
350
|
+
*/
|
|
351
|
+
export interface Endpoint {
|
|
352
|
+
uri: string;
|
|
353
|
+
protocol: TransportProtocolName;
|
|
354
|
+
}
|
|
355
|
+
|
|
322
356
|
/**
|
|
323
357
|
* Outbound message delivery.
|
|
324
358
|
*
|
|
@@ -364,7 +398,7 @@ export interface Transport {
|
|
|
364
398
|
* with {@link singleEndpointTransport} rather than by indexing.
|
|
365
399
|
*/
|
|
366
400
|
send(
|
|
367
|
-
endpoints: ReadonlyArray<
|
|
401
|
+
endpoints: ReadonlyArray<Endpoint>,
|
|
368
402
|
message: Uint8Array,
|
|
369
403
|
): Promise<void>;
|
|
370
404
|
}
|
|
@@ -384,10 +418,25 @@ export interface Transport {
|
|
|
384
418
|
* a round trip; skipping one that would have worked costs the delivery.
|
|
385
419
|
*/
|
|
386
420
|
export type SendOne = (
|
|
387
|
-
endpoint:
|
|
421
|
+
endpoint: Endpoint,
|
|
388
422
|
message: Uint8Array,
|
|
389
423
|
) => Promise<void>;
|
|
390
424
|
|
|
425
|
+
/**
|
|
426
|
+
* The DeRec protocol version this build speaks — the `protocolVersionMajor` /
|
|
427
|
+
* `protocolVersionMinor` it writes into every envelope it produces. Not the
|
|
428
|
+
* package version.
|
|
429
|
+
*/
|
|
430
|
+
export declare function protocol_version(): { major: number; minor: number };
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* A fresh replica identity, generated by the core — never `0`. Persist it
|
|
434
|
+
* once per device and pass the same value to `withReplicaId` on every
|
|
435
|
+
* protocol init: a device whose id changes cannot be re-identified by its
|
|
436
|
+
* group.
|
|
437
|
+
*/
|
|
438
|
+
export declare function generate_replica_id(): bigint;
|
|
439
|
+
|
|
391
440
|
/**
|
|
392
441
|
* Builds a {@link Transport} that tries each endpoint in the order the peer
|
|
393
442
|
* offered it and stops at the first success.
|
|
@@ -432,7 +481,7 @@ export enum SenderKind {
|
|
|
432
481
|
* the scanner must fetch the actual keys over the wire via the `PrePair`
|
|
433
482
|
* round-trip and verify them against the commitment before pairing.
|
|
434
483
|
* - `NoKeys`: no key material and no commitment. The contact carries only
|
|
435
|
-
* `channel_id`, `nonce`, and `
|
|
484
|
+
* `channel_id`, `nonce`, and `supported_transports` — small enough to be
|
|
436
485
|
* hand-typed or dictated. Keys are generated on the fly by the contact
|
|
437
486
|
* creator when the `PrePairRequest` arrives; the scanner accepts them
|
|
438
487
|
* without cryptographic verification. Trust rests entirely on the OOB
|
|
@@ -474,20 +523,33 @@ export enum FlowKind {
|
|
|
474
523
|
UnpairReplica = 8,
|
|
475
524
|
}
|
|
476
525
|
|
|
526
|
+
/** Result status carried in every protocol response (`result.proto`). Passed
|
|
527
|
+
* to `reject()` to say why an inbound request was refused. */
|
|
528
|
+
export enum StatusEnum {
|
|
529
|
+
Ok = 0,
|
|
530
|
+
Partial = 1,
|
|
531
|
+
Fail = 2,
|
|
532
|
+
SizeLimitExceeded = 3,
|
|
533
|
+
TooFrequent = 4,
|
|
534
|
+
UnknownSecretId = 5,
|
|
535
|
+
UnknownShareVersion = 6,
|
|
536
|
+
DecryptionFailed = 7,
|
|
537
|
+
VerificationFailed = 8,
|
|
538
|
+
FormatError = 9,
|
|
539
|
+
Rejected = 10,
|
|
540
|
+
IncompatibleParameterRange = 11,
|
|
541
|
+
UnsupportedTransportProtocol = 12,
|
|
542
|
+
VersionConflict = 13,
|
|
543
|
+
ReplicaIdConflict = 14,
|
|
544
|
+
RequestToClose = 99,
|
|
545
|
+
}
|
|
546
|
+
|
|
477
547
|
export type UnpairAck = "required" | "not_required";
|
|
478
548
|
|
|
479
549
|
export interface ContactMessage {
|
|
480
550
|
channel_id: bigint;
|
|
481
551
|
/** `ContactMode` numeric value (0 = INLINE_KEYS, 1 = HASHED_KEYS, 2 = NO_KEYS). */
|
|
482
552
|
contact_mode: number;
|
|
483
|
-
/**
|
|
484
|
-
* @deprecated Reading this field directly is incorrect: its meaning narrowed
|
|
485
|
-
* to "one entry of a list, and possibly absent", so a peer advertising only
|
|
486
|
-
* `supported_transports` looks unreachable to a reader that was correct
|
|
487
|
-
* before 0.0.3. Call {@link advertisedEndpoints}, which resolves both
|
|
488
|
-
* spellings. Removed at 0.0.5.
|
|
489
|
-
*/
|
|
490
|
-
transport_protocol?: TransportProtocol;
|
|
491
553
|
nonce: bigint;
|
|
492
554
|
/** Present only when `contact_mode === ContactMode.InlineKeys`. */
|
|
493
555
|
mlkem_encapsulation_key?: Uint8Array;
|
|
@@ -497,8 +559,7 @@ export interface ContactMessage {
|
|
|
497
559
|
contact_binding_hash?: Uint8Array;
|
|
498
560
|
timestamp?: Timestamp;
|
|
499
561
|
/** Every transport endpoint the creator of this contact can be reached
|
|
500
|
-
* on, in its own preference order.
|
|
501
|
-
* `transport_protocol` is offered". */
|
|
562
|
+
* on, in its own preference order. */
|
|
502
563
|
supported_transports: TransportProtocol[];
|
|
503
564
|
}
|
|
504
565
|
|
|
@@ -546,20 +607,11 @@ export interface UpdateChannelInfoParams {
|
|
|
546
607
|
* map untouched; pass an empty object to clear it. */
|
|
547
608
|
communication_info?: Record<string, string>;
|
|
548
609
|
|
|
549
|
-
/**
|
|
550
|
-
* New transport endpoint. Absent leaves it untouched.
|
|
551
|
-
*
|
|
552
|
-
* @deprecated Use `own_transports`, which carries every endpoint this node
|
|
553
|
-
* now serves; its first entry also fills this field for peers predating the
|
|
554
|
-
* list. Removed at 0.0.5.
|
|
555
|
-
*/
|
|
556
|
-
transport_protocol?: { uri: string; protocol: number };
|
|
557
610
|
/**
|
|
558
611
|
* Every endpoint this node now serves, in its own preference order.
|
|
559
|
-
* Omitted leaves the target(s)' stored set untouched.
|
|
560
|
-
* over `transport_protocol`, whose first entry it also fills.
|
|
612
|
+
* Omitted leaves the target(s)' stored set untouched.
|
|
561
613
|
*/
|
|
562
|
-
own_transports?:
|
|
614
|
+
own_transports?: Endpoint[];
|
|
563
615
|
}
|
|
564
616
|
|
|
565
617
|
/**
|
|
@@ -592,6 +644,15 @@ export interface Timeouts {
|
|
|
592
644
|
* are both read from the stores. The argument may be omitted entirely. */
|
|
593
645
|
export type ReplicaDiscoveryParams = Record<string, never>;
|
|
594
646
|
|
|
647
|
+
/** Any member may remove any member, the source included: a lost or stolen
|
|
648
|
+
* source must be removable by the devices that remain, and the library
|
|
649
|
+
* checks no role. Ask the user before starting this flow, above all when it
|
|
650
|
+
* names the source. Removing the source promotes the first remaining member
|
|
651
|
+
* in the order the channel store's `listReplicas` returns. The removed
|
|
652
|
+
* member is not asked and gets no event when told to leave: when a roster
|
|
653
|
+
* excluding it arrives it drops its whole `secret_id` partition and emits
|
|
654
|
+
* `SelfRemovedFromGroup`. The secret survives on the remaining members and
|
|
655
|
+
* the helpers. */
|
|
595
656
|
export interface UnpairReplicaParams {
|
|
596
657
|
/** The member to remove, as a **decimal** `u64` string — the same form
|
|
597
658
|
* `ReplicaPaired.peer_replica_id` hands back. A value naming no current
|
|
@@ -618,18 +679,34 @@ export type DeRecEvent =
|
|
|
618
679
|
action: Uint8Array;
|
|
619
680
|
|
|
620
681
|
action_kind: PendingActionKind;
|
|
682
|
+
/** Correlation token of the inbound request, decimal-encoded. */
|
|
683
|
+
trace_id: string;
|
|
684
|
+
/** Pairing only. */
|
|
621
685
|
peer_communication_info?: Record<string, string>;
|
|
622
|
-
|
|
686
|
+
/** `sender_kind` of the inbound pair request (Pairing only). */
|
|
623
687
|
sender_kind?: SenderKind;
|
|
624
|
-
|
|
688
|
+
/** Share version (StoreShare / VerifyShare / GetShare). */
|
|
625
689
|
version?: number;
|
|
690
|
+
/** Description of the secret version (StoreShare only). */
|
|
626
691
|
share_description?: string;
|
|
627
|
-
|
|
692
|
+
/** Secret identifier, decimal-encoded (StoreShare / VerifyShare /
|
|
693
|
+
* GetShare). On GetShare, with `version`, names the requested share. */
|
|
628
694
|
share_secret_id?: string;
|
|
695
|
+
/** Length in bytes of the share the helper would store (StoreShare
|
|
696
|
+
* only) — what a size or quota decision is made on. */
|
|
697
|
+
share_size?: number;
|
|
698
|
+
/** The peer's memo (Unpair only). */
|
|
699
|
+
unpair_memo?: string;
|
|
700
|
+
/** Communication info the peer replaces its stored map with
|
|
701
|
+
* (UpdateChannelInfo only). Absent: unchanged. Empty: cleared. */
|
|
702
|
+
updated_communication_info?: Record<string, string>;
|
|
703
|
+
/** Endpoints the peer is moving to (UpdateChannelInfo only). Absent:
|
|
704
|
+
* unchanged. */
|
|
705
|
+
updated_transports?: Endpoint[];
|
|
629
706
|
}
|
|
630
707
|
| { type: "ShareStored"; channel_id: string; version: number }
|
|
631
708
|
| { type: "ShareConfirmed"; channel_id: string; version: number }
|
|
632
|
-
| { type: "ShareRejected"; channel_id: string; version: number; status:
|
|
709
|
+
| { type: "ShareRejected"; channel_id: string; version: number; status: StatusEnum; memo: string }
|
|
633
710
|
/** A publishing round finished — every targeted helper confirmed,
|
|
634
711
|
* rejected, or timed out.
|
|
635
712
|
*
|
|
@@ -647,14 +724,17 @@ export type DeRecEvent =
|
|
|
647
724
|
| { type: "SharingComplete"; version: number; confirmed_count: number; failed_count: number; threshold_met: boolean }
|
|
648
725
|
/** A group member refused a secret sync. Keyed by `replica_id`, not
|
|
649
726
|
* `channel_id`: every member answers on the one group channel. A
|
|
650
|
-
* `VERSION_CONFLICT` status means
|
|
651
|
-
*
|
|
727
|
+
* `VERSION_CONFLICT` status means another member holds a different copy
|
|
728
|
+
* of this version: do not publish from this device again until the
|
|
729
|
+
* conflict is resolved. Run `start(FlowKind.ReplicaDiscovery)` to receive
|
|
730
|
+
* the group's copy as `ReplicaVersionConflict`, merge, and publish the
|
|
731
|
+
* result once with `start(FlowKind.ProtectSecret)`. */
|
|
652
732
|
| {
|
|
653
733
|
type: "ReplicaSyncRejected";
|
|
654
734
|
replica_id: string;
|
|
655
735
|
secret_id: string;
|
|
656
736
|
version: number;
|
|
657
|
-
status:
|
|
737
|
+
status: StatusEnum;
|
|
658
738
|
memo: string;
|
|
659
739
|
}
|
|
660
740
|
/** A secret sync could not be delivered to a member at all — distinct from
|
|
@@ -671,7 +751,8 @@ export type DeRecEvent =
|
|
|
671
751
|
/** This device left the group and dropped its whole `secret_id` partition —
|
|
672
752
|
* group channel, helper channels, shares, secrets and the snapshot. Fires
|
|
673
753
|
* only once it was told to leave *and* has since seen a roster excluding
|
|
674
|
-
* it; absence alone never destroys a copy of the secret.
|
|
754
|
+
* it; absence alone never destroys a copy of the secret. The teardown is
|
|
755
|
+
* automatic: this device is not asked first and gets no earlier event. */
|
|
675
756
|
| { type: "SelfRemovedFromGroup"; version: number }
|
|
676
757
|
/** A replica catch-up finished. `fetched_from` is absent when this device
|
|
677
758
|
* was already current, in which case no hydration event follows. */
|
|
@@ -687,6 +768,10 @@ export type DeRecEvent =
|
|
|
687
768
|
* library keeps no durable per-member sync state. */
|
|
688
769
|
| { type: "ReplicaSyncComplete"; version: number; synced: string[]; behind: string[] }
|
|
689
770
|
| { type: "ShareVerified"; channel_id: string; version: number }
|
|
771
|
+
/** A helper refused a verification challenge: its response carried a
|
|
772
|
+
* non-OK `status` instead of a proof. The challenge is spent; a new
|
|
773
|
+
* `VerifyShares` round challenges the helper again. */
|
|
774
|
+
| { type: "ShareVerifyRejected"; channel_id: string; version: number; status: StatusEnum; memo: string }
|
|
690
775
|
| {
|
|
691
776
|
type: "SecretsDiscovered";
|
|
692
777
|
channel_id: string;
|
|
@@ -695,6 +780,22 @@ export type DeRecEvent =
|
|
|
695
780
|
}
|
|
696
781
|
| { type: "RecoveryShareReceived"; channel_id: string; shares_received: number }
|
|
697
782
|
| { type: "RecoveryShareError"; channel_id: string; shares_received: number; error: string }
|
|
783
|
+
/** A helper refused a recovery share request: its response carried a
|
|
784
|
+
* non-OK `status` (e.g. `UNKNOWN_SHARE_VERSION`) instead of a share. The
|
|
785
|
+
* refusal is not collected — it does not count towards `shares_received`
|
|
786
|
+
* and the recovery stays open for the other helpers' shares — but it does
|
|
787
|
+
* answer that helper's `RecoverSecretStarted`. */
|
|
788
|
+
| { type: "RecoveryShareRefused"; channel_id: string; version: number; status: StatusEnum; memo: string }
|
|
789
|
+
/** A helper answered with a share that cannot be part of the secret;
|
|
790
|
+
* `reason` says how it failed. `Malformed` and `InvalidProof` are judged
|
|
791
|
+
* on arrival; `Inconsistent` (valid on its own but disagreeing with the
|
|
792
|
+
* shares the secret was rebuilt from) is reported alongside
|
|
793
|
+
* `SecretRecovered`, once per helper. The share is set aside — it does
|
|
794
|
+
* not count towards `shares_received` and never blocks the recovery. An
|
|
795
|
+
* honest helper never sends one, so the app may treat it as a sign of a
|
|
796
|
+
* damaged or compromised helper, e.g. offer to unpair it. It also
|
|
797
|
+
* answers that helper's `RecoverSecretStarted`. */
|
|
798
|
+
| { type: "RecoveryShareCorrupted"; channel_id: string; version: number; reason: CorruptionReason }
|
|
698
799
|
/** Recovery completed — the typed `Secret` snapshot the owner
|
|
699
800
|
* originally protected. Mirrors `ReplicaSecretReceived.secret`:
|
|
700
801
|
* `secrets` is the user-facing `Vec<UserSecret>` the application
|
|
@@ -707,9 +808,9 @@ export type DeRecEvent =
|
|
|
707
808
|
helpers: Array<{
|
|
708
809
|
channel_id: string;
|
|
709
810
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
710
|
-
transports:
|
|
811
|
+
transports: Endpoint[];
|
|
711
812
|
shared_key: Uint8Array;
|
|
712
|
-
communication_info
|
|
813
|
+
communication_info?: Record<string, string>;
|
|
713
814
|
}>;
|
|
714
815
|
secrets: Array<{
|
|
715
816
|
id: Uint8Array;
|
|
@@ -729,9 +830,9 @@ export type DeRecEvent =
|
|
|
729
830
|
members: Array<{
|
|
730
831
|
replica_id: string;
|
|
731
832
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
732
|
-
transports:
|
|
833
|
+
transports: Endpoint[];
|
|
733
834
|
role: "Source" | "Destination";
|
|
734
|
-
communication_info
|
|
835
|
+
communication_info?: Record<string, string>;
|
|
735
836
|
}>;
|
|
736
837
|
shared_key: Uint8Array;
|
|
737
838
|
};
|
|
@@ -740,12 +841,12 @@ export type DeRecEvent =
|
|
|
740
841
|
|
|
741
842
|
| { type: "Unpaired"; channel_id: string }
|
|
742
843
|
|
|
743
|
-
| { type: "UnpairRejected"; channel_id: string; status:
|
|
844
|
+
| { type: "UnpairRejected"; channel_id: string; status: StatusEnum; memo: string }
|
|
744
845
|
|
|
745
846
|
/** Contact creator answered the scanner's `PrePairRequest` with a
|
|
746
847
|
* non-Ok status (HashedKeys flow). Distinct from a cryptographic
|
|
747
848
|
* hash mismatch, which surfaces as a thrown error from `process()`. */
|
|
748
|
-
| { type: "PrePairRejected"; channel_id: string; status:
|
|
849
|
+
| { type: "PrePairRejected"; channel_id: string; status: StatusEnum; memo: string }
|
|
749
850
|
|
|
750
851
|
/** Fires alongside `PairingCompleted` on replica-mode pair handshakes.
|
|
751
852
|
* `peer_replica_id` is the peer's `u64` as a **decimal** string,
|
|
@@ -763,22 +864,28 @@ export type DeRecEvent =
|
|
|
763
864
|
/** A `ReplicaSource` peer pushed a secret sync on a
|
|
764
865
|
* `ReplicaDestination` channel. The library decoded the
|
|
765
866
|
* `ReplicaSecretPayload`; the app installs `secret.secrets` and
|
|
766
|
-
* optionally uses `shares` for recovery. `from_replica_id
|
|
767
|
-
* `replica_id` fields inside `secret` are
|
|
768
|
-
* strings.
|
|
867
|
+
* optionally uses `shares` for recovery. `from_replica_id`,
|
|
868
|
+
* `author_replica_id` and the `replica_id` fields inside `secret` are
|
|
869
|
+
* `u64` as **decimal** strings.
|
|
870
|
+
*
|
|
871
|
+
* `from_replica_id` is the member this copy came from: the publisher on
|
|
872
|
+
* a push, the serving member on a catch-up. `author_replica_id` is the
|
|
873
|
+
* member that published `version`, or `null` when the serving member's
|
|
874
|
+
* snapshot records none. */
|
|
769
875
|
| {
|
|
770
876
|
type: "ReplicaSecretReceived";
|
|
771
877
|
channel_id: string;
|
|
772
878
|
from_replica_id: string;
|
|
879
|
+
author_replica_id: string | null;
|
|
773
880
|
secret_id: string;
|
|
774
881
|
version: number;
|
|
775
882
|
secret: {
|
|
776
883
|
helpers: Array<{
|
|
777
884
|
channel_id: string;
|
|
778
885
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
779
|
-
transports:
|
|
886
|
+
transports: Endpoint[];
|
|
780
887
|
shared_key: Uint8Array;
|
|
781
|
-
communication_info
|
|
888
|
+
communication_info?: Record<string, string>;
|
|
782
889
|
}>;
|
|
783
890
|
secrets: Array<{
|
|
784
891
|
id: Uint8Array;
|
|
@@ -796,9 +903,9 @@ export type DeRecEvent =
|
|
|
796
903
|
members: Array<{
|
|
797
904
|
replica_id: string;
|
|
798
905
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
799
|
-
transports:
|
|
906
|
+
transports: Endpoint[];
|
|
800
907
|
role: "Source" | "Destination";
|
|
801
|
-
communication_info
|
|
908
|
+
communication_info?: Record<string, string>;
|
|
802
909
|
}>;
|
|
803
910
|
shared_key: Uint8Array;
|
|
804
911
|
};
|
|
@@ -821,15 +928,16 @@ export type DeRecEvent =
|
|
|
821
928
|
type: "ReplicaSecretInstalled";
|
|
822
929
|
channel_id: string;
|
|
823
930
|
from_replica_id: string;
|
|
931
|
+
author_replica_id: string | null;
|
|
824
932
|
secret_id: string;
|
|
825
933
|
version: number;
|
|
826
934
|
secret: {
|
|
827
935
|
helpers: Array<{
|
|
828
936
|
channel_id: string;
|
|
829
937
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
830
|
-
transports:
|
|
938
|
+
transports: Endpoint[];
|
|
831
939
|
shared_key: Uint8Array;
|
|
832
|
-
communication_info
|
|
940
|
+
communication_info?: Record<string, string>;
|
|
833
941
|
}>;
|
|
834
942
|
secrets: Array<{
|
|
835
943
|
id: Uint8Array;
|
|
@@ -847,9 +955,9 @@ export type DeRecEvent =
|
|
|
847
955
|
members: Array<{
|
|
848
956
|
replica_id: string;
|
|
849
957
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
850
|
-
transports:
|
|
958
|
+
transports: Endpoint[];
|
|
851
959
|
role: "Source" | "Destination";
|
|
852
|
-
communication_info
|
|
960
|
+
communication_info?: Record<string, string>;
|
|
853
961
|
}>;
|
|
854
962
|
shared_key: Uint8Array;
|
|
855
963
|
};
|
|
@@ -859,6 +967,59 @@ export type DeRecEvent =
|
|
|
859
967
|
committed_share: Uint8Array;
|
|
860
968
|
}>;
|
|
861
969
|
}
|
|
970
|
+
/** A member offered a different copy of the version this device holds.
|
|
971
|
+
* Nothing was written: this device keeps its own copy and refuses the
|
|
972
|
+
* incoming one with `VERSION_CONFLICT`, so the publisher sees
|
|
973
|
+
* `ReplicaSyncRejected`. Both copies are complete states — the held one
|
|
974
|
+
* is in the local stores, the incoming one is `secret`. Resolve by
|
|
975
|
+
* publishing the chosen state with `start(FlowKind.ProtectSecret)`; the
|
|
976
|
+
* next version supersedes both on every member and helper. Until then,
|
|
977
|
+
* do not publish from this device: any further `ProtectSecret` is a
|
|
978
|
+
* higher version that every other member applies over its own copy,
|
|
979
|
+
* losing the change it never merged.
|
|
980
|
+
*
|
|
981
|
+
* `held_author_replica_id` / `incoming_author_replica_id` are the
|
|
982
|
+
* decimal `replica_id` of each copy's publisher, or `null` when that
|
|
983
|
+
* copy records none. */
|
|
984
|
+
| {
|
|
985
|
+
type: "ReplicaVersionConflict";
|
|
986
|
+
channel_id: string;
|
|
987
|
+
from_replica_id: string;
|
|
988
|
+
secret_id: string;
|
|
989
|
+
version: number;
|
|
990
|
+
held_author_replica_id: string | null;
|
|
991
|
+
incoming_author_replica_id: string | null;
|
|
992
|
+
secret: {
|
|
993
|
+
helpers: Array<{
|
|
994
|
+
channel_id: string;
|
|
995
|
+
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
996
|
+
transports: Endpoint[];
|
|
997
|
+
shared_key: Uint8Array;
|
|
998
|
+
communication_info?: Record<string, string>;
|
|
999
|
+
}>;
|
|
1000
|
+
secrets: Array<{
|
|
1001
|
+
id: Uint8Array;
|
|
1002
|
+
name: string;
|
|
1003
|
+
data: Uint8Array;
|
|
1004
|
+
}>;
|
|
1005
|
+
/** The same shape as `SecretRecovered.secret.replicas`. */
|
|
1006
|
+
replicas?: {
|
|
1007
|
+
/** The one channel every member is addressed on. */
|
|
1008
|
+
channel_id: string;
|
|
1009
|
+
/** Every member of the group, including the writer. Exactly one
|
|
1010
|
+
* carries `role: "Source"` — that member is where the secret
|
|
1011
|
+
* originated, which is why no separate owner field is needed. */
|
|
1012
|
+
members: Array<{
|
|
1013
|
+
replica_id: string;
|
|
1014
|
+
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
1015
|
+
transports: Endpoint[];
|
|
1016
|
+
role: "Source" | "Destination";
|
|
1017
|
+
communication_info?: Record<string, string>;
|
|
1018
|
+
}>;
|
|
1019
|
+
shared_key: Uint8Array;
|
|
1020
|
+
};
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
862
1023
|
/** Peer's ack of a secret sync we sent. `status` is the `StatusEnum`
|
|
863
1024
|
* integer (0 = Ok), `memo` is the peer's explanation. */
|
|
864
1025
|
| {
|
|
@@ -867,7 +1028,7 @@ export type DeRecEvent =
|
|
|
867
1028
|
from_replica_id: string;
|
|
868
1029
|
secret_id: string;
|
|
869
1030
|
version: number;
|
|
870
|
-
status:
|
|
1031
|
+
status: StatusEnum;
|
|
871
1032
|
memo: string;
|
|
872
1033
|
}
|
|
873
1034
|
/** A peer announced an updated `communication_info` map and/or
|
|
@@ -884,7 +1045,7 @@ export type DeRecEvent =
|
|
|
884
1045
|
| {
|
|
885
1046
|
type: "ChannelInfoUpdateRejected";
|
|
886
1047
|
channel_id: string;
|
|
887
|
-
status:
|
|
1048
|
+
status: StatusEnum;
|
|
888
1049
|
memo: string;
|
|
889
1050
|
}
|
|
890
1051
|
/** Emitted by `process()` in place of `ActionRequired` when the
|
|
@@ -896,6 +1057,38 @@ export type DeRecEvent =
|
|
|
896
1057
|
* (`"Pairing"`, `"StoreShare"`, …). */
|
|
897
1058
|
| { type: "AutoAccepted"; channel_id: string; action_kind: PendingActionKind }
|
|
898
1059
|
| { type: "NoOp" }
|
|
1060
|
+
/** An inbound message was dropped untouched: no store was written and
|
|
1061
|
+
* nothing was sent back. `reason` says why.
|
|
1062
|
+
*
|
|
1063
|
+
* `"PendingVerification"` means the peer sent something before this
|
|
1064
|
+
* device confirmed the channel's fingerprint — typically a replica source
|
|
1065
|
+
* pushing its first copy while this destination still shows the code.
|
|
1066
|
+
* Confirming does not replay it: after `verifyFingerprint` succeeds, a
|
|
1067
|
+
* replica destination calls `start(FlowKind.ReplicaDiscovery)` to pull
|
|
1068
|
+
* the copy itself. `"Expired"` means the message was older than the
|
|
1069
|
+
* inbound timeout. `trace_id` matches the peer's `*Started` event for
|
|
1070
|
+
* the same round (`"0"` when the sender set none). */
|
|
1071
|
+
| {
|
|
1072
|
+
type: "MessageIgnored";
|
|
1073
|
+
channel_id: string;
|
|
1074
|
+
reason: IgnoreReason;
|
|
1075
|
+
trace_id: string;
|
|
1076
|
+
}
|
|
1077
|
+
/** Returned by `restore`: a roster entry got no channel, so this device
|
|
1078
|
+
* cannot reach that peer. Every other entry and the user-secret snapshot
|
|
1079
|
+
* were restored; `reason` says why this one was not. `"NoTransports"`
|
|
1080
|
+
* means the recovered roster names no endpoint for it.
|
|
1081
|
+
*
|
|
1082
|
+
* For a helper, `channel_id` is its channel and `replica_id` is absent.
|
|
1083
|
+
* For a replica group member, `channel_id` is the group's channel and
|
|
1084
|
+
* `replica_id` names the member. The peer itself is untouched — a helper
|
|
1085
|
+
* still holds its share — and pairing with it again makes it reachable. */
|
|
1086
|
+
| {
|
|
1087
|
+
type: "PeerNotRestored";
|
|
1088
|
+
channel_id: string;
|
|
1089
|
+
replica_id?: string;
|
|
1090
|
+
reason: NotRestoredReason;
|
|
1091
|
+
}
|
|
899
1092
|
/** A pairing handshake was dispatched successfully. `kind` is the
|
|
900
1093
|
* local party's role — same value the subsequent `PairingCompleted`
|
|
901
1094
|
* will carry. Emitted by `start(Pairing)`. */
|
|
@@ -964,8 +1157,8 @@ export type DeRecEvent =
|
|
|
964
1157
|
* inbound shares. The protocol enforces no size, quota or rate limit
|
|
965
1158
|
* of its own, and `maxShareSize` is checked for range overlap at
|
|
966
1159
|
* pairing time only, never against an actual share. While this is
|
|
967
|
-
* `false`, `ActionRequired` carries
|
|
968
|
-
*
|
|
1160
|
+
* `false`, `ActionRequired` carries `share_size`, so the application
|
|
1161
|
+
* can compare it to its quota and call `reject()` with
|
|
969
1162
|
* `StatusEnum.SizeLimitExceeded`. Setting it `true` removes that
|
|
970
1163
|
* opportunity entirely: every share from every paired Owner is stored
|
|
971
1164
|
* unconditionally, at whatever size it arrives. Keep off in any
|
|
@@ -993,10 +1186,23 @@ export interface AutoAcceptPolicy {
|
|
|
993
1186
|
* between them without reaching for reference docs.
|
|
994
1187
|
*
|
|
995
1188
|
* Required setters: `withChannelStore`, `withShareStore`,
|
|
996
|
-
* `withSecretStore`, `
|
|
997
|
-
* `withOwnTransports`. Calling `build()` without all
|
|
1189
|
+
* `withSecretStore`, `withUserSecretStore`, `withStateStore`,
|
|
1190
|
+
* `withTransport`, and `withOwnTransports`. Calling `build()` without all
|
|
1191
|
+
* seven throws.
|
|
1192
|
+
*
|
|
1193
|
+
* An optional setter that is never called leaves the library's default in
|
|
1194
|
+
* force.
|
|
998
1195
|
*/
|
|
999
1196
|
export declare class DeRecProtocolBuilder {
|
|
1197
|
+
/**
|
|
1198
|
+
* Release the builder's memory in the library. `build()` already releases
|
|
1199
|
+
* it; call this only for a builder that is discarded unbuilt. Safe to call
|
|
1200
|
+
* more than once.
|
|
1201
|
+
*/
|
|
1202
|
+
free(): void;
|
|
1203
|
+
/** Same as {@link DeRecProtocolBuilder.free}, for `using`. */
|
|
1204
|
+
[Symbol.dispose](): void;
|
|
1205
|
+
|
|
1000
1206
|
/**
|
|
1001
1207
|
* Construct a builder bound to a specific secret. `secretId`
|
|
1002
1208
|
* identifies the single secret this protocol instance manages.
|
|
@@ -1011,33 +1217,21 @@ export declare class DeRecProtocolBuilder {
|
|
|
1011
1217
|
withUserSecretStore(store: UserSecretStore): DeRecProtocolBuilder;
|
|
1012
1218
|
withStateStore(store: StateStore): DeRecProtocolBuilder;
|
|
1013
1219
|
withTransport(transport: Transport): DeRecProtocolBuilder;
|
|
1014
|
-
/**
|
|
1015
|
-
* @deprecated Use {@link withOwnTransports}, which takes the whole
|
|
1016
|
-
* preference list — `withOwnTransports([endpoint])` is the direct
|
|
1017
|
-
* replacement. Removed at 0.0.5.
|
|
1018
|
-
*/
|
|
1019
|
-
withOwnTransport(endpoint: { uri: string; protocol: string }): DeRecProtocolBuilder;
|
|
1020
1220
|
/**
|
|
1021
1221
|
* Set every transport endpoint this application serves, in preference
|
|
1022
1222
|
* order. `protocol` is `"https"` or `"grpc"` (case-insensitive) per
|
|
1023
|
-
* entry
|
|
1223
|
+
* entry.
|
|
1024
1224
|
*
|
|
1025
1225
|
* The order is this application's own preference and decides which of
|
|
1026
1226
|
* a peer's offered endpoints is used; it is not sorted, deduplicated,
|
|
1027
1227
|
* or reordered. Every listed transport must actually be served,
|
|
1028
1228
|
* because delivery is push-only — listing an endpoint this application
|
|
1029
1229
|
* does not serve makes pairing succeed and replies vanish.
|
|
1030
|
-
*
|
|
1031
|
-
* Supersedes {@link withOwnTransport} for applications serving more
|
|
1032
|
-
* than one transport; the single-endpoint setter remains fully
|
|
1033
|
-
* supported.
|
|
1034
1230
|
*/
|
|
1035
|
-
withOwnTransports(transports:
|
|
1231
|
+
withOwnTransports(transports: Endpoint[]): DeRecProtocolBuilder;
|
|
1036
1232
|
|
|
1037
|
-
/** Default: 3. */
|
|
1233
|
+
/** Minimum number of shares required to reconstruct the secret. Default: 3. */
|
|
1038
1234
|
withThreshold(threshold: number): DeRecProtocolBuilder;
|
|
1039
|
-
/** Default: 3. */
|
|
1040
|
-
withKeepVersionsCount(count: number): DeRecProtocolBuilder;
|
|
1041
1235
|
/**
|
|
1042
1236
|
* Configure how long the protocol waits on each thing that can keep it
|
|
1043
1237
|
* waiting. Every field is optional and **absent means "keep the library
|
|
@@ -1055,8 +1249,8 @@ export declare class DeRecProtocolBuilder {
|
|
|
1055
1249
|
withTimeouts(timeouts: Timeouts): DeRecProtocolBuilder;
|
|
1056
1250
|
|
|
1057
1251
|
/**
|
|
1058
|
-
* Accept plaintext `http://` transport endpoints.
|
|
1059
|
-
* Default: `false`.
|
|
1252
|
+
* Accept plaintext `http://` and `grpc://` transport endpoints.
|
|
1253
|
+
* **Development only.** Default: `false`.
|
|
1060
1254
|
*
|
|
1061
1255
|
* With `false`, plaintext is accepted in exactly one situation: an endpoint
|
|
1062
1256
|
* this device configured for **itself** that names loopback (`localhost`,
|
|
@@ -1072,33 +1266,20 @@ export declare class DeRecProtocolBuilder {
|
|
|
1072
1266
|
* delivery is your `Transport`. Nothing here stops an application sending
|
|
1073
1267
|
* plaintext — it governs which endpoints the protocol will record,
|
|
1074
1268
|
* propagate to peers, and reply to.
|
|
1075
|
-
*
|
|
1076
|
-
* @deprecated Use {@link withUnsafeConnection}, which names both gated
|
|
1077
|
-
* schemes. Removed at 0.0.5.
|
|
1078
|
-
*/
|
|
1079
|
-
withUnsafeHttp(allow: boolean): DeRecProtocolBuilder;
|
|
1080
|
-
/**
|
|
1081
|
-
* Accept plaintext `http://` and `grpc://` transport endpoints.
|
|
1082
|
-
* **Development only.** Default: `false`. Supersedes
|
|
1083
|
-
* {@link withUnsafeHttp}, which names only the HTTP scheme.
|
|
1084
|
-
*
|
|
1085
|
-
* Either flag alone is honored. Setting both to disagreeing values fails
|
|
1086
|
-
* construction with the error code `CONFLICTING_PLAINTEXT_OPT_IN` rather
|
|
1087
|
-
* than resolving silently, because precedence would hand the decision to
|
|
1088
|
-
* the flag being removed.
|
|
1089
1269
|
*/
|
|
1090
1270
|
withUnsafeConnection(allow: boolean): DeRecProtocolBuilder;
|
|
1091
1271
|
/** Default: empty. */
|
|
1092
1272
|
withCommunicationInfo(info: Record<string, string>): DeRecProtocolBuilder;
|
|
1093
1273
|
/** Default: false. */
|
|
1094
1274
|
withAutoRespondOnFailure(enabled: boolean): DeRecProtocolBuilder;
|
|
1095
|
-
/**
|
|
1275
|
+
/** Exactly `"required"` or `"not_required"`; any other string throws
|
|
1276
|
+
* `invalid_unpair_ack`. Default: `"required"`. */
|
|
1096
1277
|
withUnpairAck(ack: UnpairAck): DeRecProtocolBuilder;
|
|
1097
1278
|
/**
|
|
1098
1279
|
* When `true`, every outbound channel-mode request stamps
|
|
1099
|
-
* `request.
|
|
1100
|
-
* back here even if the channel's stored peer endpoint
|
|
1101
|
-
* elsewhere. Default: false.
|
|
1280
|
+
* `request.reply_to` with this node's own transports so the responder
|
|
1281
|
+
* routes its reply back here even if the channel's stored peer endpoint
|
|
1282
|
+
* points elsewhere. Default: false.
|
|
1102
1283
|
*/
|
|
1103
1284
|
withAutoReplyTo(enabled: boolean): DeRecProtocolBuilder;
|
|
1104
1285
|
/**
|
|
@@ -1113,7 +1294,8 @@ export declare class DeRecProtocolBuilder {
|
|
|
1113
1294
|
/**
|
|
1114
1295
|
* Stable per-device replica id. Required to participate in any
|
|
1115
1296
|
* `ReplicaSource` / `ReplicaDestination` pairing. The id must be
|
|
1116
|
-
* stable across restarts
|
|
1297
|
+
* stable across restarts: mint it once with {@link generate_replica_id}
|
|
1298
|
+
* and persist it. Default: unset.
|
|
1117
1299
|
*/
|
|
1118
1300
|
withReplicaId(id: bigint | number): DeRecProtocolBuilder;
|
|
1119
1301
|
/**
|
|
@@ -1136,10 +1318,33 @@ export declare class DeRecProtocolBuilder {
|
|
|
1136
1318
|
build(): DeRecProtocol;
|
|
1137
1319
|
}
|
|
1138
1320
|
|
|
1321
|
+
/**
|
|
1322
|
+
* Every method that touches protocol state returns a `Promise` and runs under
|
|
1323
|
+
* one lock per instance, so overlapping calls on the same instance — a `tick`
|
|
1324
|
+
* timer firing while `process` handles an inbound message — queue and run one
|
|
1325
|
+
* at a time, in the order they were made. Distinct instances do not share the
|
|
1326
|
+
* lock: two instances bound to the same `secretId` and the same stores must
|
|
1327
|
+
* still be serialized by the caller.
|
|
1328
|
+
*
|
|
1329
|
+
* A store or transport callback must not await a call on the instance that
|
|
1330
|
+
* invoked it: that call queues behind the one waiting on the callback, and
|
|
1331
|
+
* neither settles. Calling `free()` while a call is in flight throws.
|
|
1332
|
+
*/
|
|
1139
1333
|
export declare class DeRecProtocol {
|
|
1140
1334
|
/** Use {@link DeRecProtocolBuilder} to construct instances. */
|
|
1141
1335
|
private constructor();
|
|
1142
1336
|
|
|
1337
|
+
/**
|
|
1338
|
+
* Release this protocol's memory in the library, and its references to the
|
|
1339
|
+
* stores and transport. The library's memory is not reclaimed by the
|
|
1340
|
+
* JavaScript garbage collector in time to rely on, so call this when done.
|
|
1341
|
+
* Safe to call more than once; any other method called afterwards throws,
|
|
1342
|
+
* as does calling this while a call is in flight.
|
|
1343
|
+
*/
|
|
1344
|
+
free(): void;
|
|
1345
|
+
/** Same as {@link DeRecProtocol.free}, for `using`. */
|
|
1346
|
+
[Symbol.dispose](): void;
|
|
1347
|
+
|
|
1143
1348
|
/** The secret identifier this protocol instance is bound to. */
|
|
1144
1349
|
secretId(): bigint;
|
|
1145
1350
|
|
|
@@ -1152,8 +1357,8 @@ export declare class DeRecProtocol {
|
|
|
1152
1357
|
* directly in the contact. `ContactMode.HashedKeys`
|
|
1153
1358
|
* embeds only a SHA-384 binding hash (keys are
|
|
1154
1359
|
* fetched later via the `PrePair` round-trip).
|
|
1155
|
-
* `HashedKeys` requires
|
|
1156
|
-
* ephemeral.
|
|
1360
|
+
* `HashedKeys` requires the advertised own
|
|
1361
|
+
* transports to be ephemeral.
|
|
1157
1362
|
*/
|
|
1158
1363
|
/**
|
|
1159
1364
|
* Single entry point for all three `ContactMode` variants.
|
|
@@ -1197,29 +1402,11 @@ export declare class DeRecProtocol {
|
|
|
1197
1402
|
* contact peers — follow up with
|
|
1198
1403
|
* <c>start(FlowKind.UpdateChannelInfo, ...)</c> to propagate.
|
|
1199
1404
|
*/
|
|
1200
|
-
setCommunicationInfo(info: Record<string, string>): void
|
|
1201
|
-
|
|
1202
|
-
/**
|
|
1203
|
-
* Replace this node's endpoint for one protocol, leaving the others
|
|
1204
|
-
* alone. A node serves at most one endpoint per protocol, so the
|
|
1205
|
-
* `(uri, protocol)` pair identifies the entry it replaces; an entry for
|
|
1206
|
-
* a protocol not yet served is appended, and a replaced one keeps its
|
|
1207
|
-
* position in the preference order.
|
|
1208
|
-
*
|
|
1209
|
-
* IMPORTANT: keep the old endpoint operational during the changeover
|
|
1210
|
-
* (see the Rust docs on the matching setter for the discipline).
|
|
1211
|
-
*
|
|
1212
|
-
* @deprecated Use {@link setOwnTransports}, which takes the whole
|
|
1213
|
-
* preference list and is the only way to change which protocols this
|
|
1214
|
-
* node serves, or their order. Removed at 0.0.5.
|
|
1215
|
-
*/
|
|
1216
|
-
setOwnTransport(uri: string, protocol: string): void;
|
|
1405
|
+
setCommunicationInfo(info: Record<string, string>): Promise<void>;
|
|
1217
1406
|
|
|
1218
1407
|
/**
|
|
1219
1408
|
* Replace every endpoint this node advertises, in preference order —
|
|
1220
|
-
* the runtime counterpart to
|
|
1221
|
-
* change the whole set (<c>setOwnTransport</c> replaces only the entry
|
|
1222
|
-
* for the protocol its URI names).
|
|
1409
|
+
* the runtime counterpart to `withOwnTransports`.
|
|
1223
1410
|
*
|
|
1224
1411
|
* A node serves at most one endpoint per protocol, so this list is a
|
|
1225
1412
|
* preference order over distinct protocols. Two entries of the same
|
|
@@ -1228,7 +1415,7 @@ export declare class DeRecProtocol {
|
|
|
1228
1415
|
* Every entry is validated before any is stored, so a malformed URI
|
|
1229
1416
|
* leaves the previous set intact. An empty array is rejected.
|
|
1230
1417
|
*/
|
|
1231
|
-
setOwnTransports(transports:
|
|
1418
|
+
setOwnTransports(transports: Endpoint[]): Promise<void>;
|
|
1232
1419
|
|
|
1233
1420
|
process(message: Uint8Array): Promise<DeRecEvent[]>;
|
|
1234
1421
|
|
|
@@ -1242,14 +1429,14 @@ export declare class DeRecProtocol {
|
|
|
1242
1429
|
* shorter than the configured timeout.
|
|
1243
1430
|
*
|
|
1244
1431
|
* Safe to call at any time; with nothing in flight it resolves to an empty
|
|
1245
|
-
* array.
|
|
1246
|
-
*
|
|
1432
|
+
* array. Overlapping calls with `process` on the same instance queue
|
|
1433
|
+
* rather than collide.
|
|
1247
1434
|
*/
|
|
1248
1435
|
tick(): Promise<DeRecEvent[]>;
|
|
1249
1436
|
|
|
1250
1437
|
accept(actionBytes: Uint8Array): Promise<DeRecEvent[]>;
|
|
1251
1438
|
|
|
1252
|
-
reject(actionBytes: Uint8Array, status:
|
|
1439
|
+
reject(actionBytes: Uint8Array, status: StatusEnum, memo: string): Promise<void>;
|
|
1253
1440
|
|
|
1254
1441
|
/**
|
|
1255
1442
|
* Derive the human-readable fingerprint for a paired channel. Both sides
|
|
@@ -1264,6 +1451,11 @@ export declare class DeRecProtocol {
|
|
|
1264
1451
|
* Verify `fingerprint` against the channel's locally-derived one. On
|
|
1265
1452
|
* match, the channel transitions from `Pending` to `Paired`. Returns
|
|
1266
1453
|
* `true` on confirmation, `false` on mismatch.
|
|
1454
|
+
*
|
|
1455
|
+
* On a replica destination, confirming is also the decision to adopt the
|
|
1456
|
+
* group's vault: the source's publish is then installed as it arrives,
|
|
1457
|
+
* with no further prompt. Ask the user before calling this; to decline,
|
|
1458
|
+
* never confirm.
|
|
1267
1459
|
*/
|
|
1268
1460
|
verifyFingerprint(channelId: bigint | number, fingerprint: string): Promise<boolean>;
|
|
1269
1461
|
/**
|
|
@@ -1274,23 +1466,36 @@ export declare class DeRecProtocol {
|
|
|
1274
1466
|
* threshold given even when that policy is disabled. The age comparison
|
|
1275
1467
|
* is strict, so a channel created within the current second survives
|
|
1276
1468
|
* even `0`.
|
|
1469
|
+
*
|
|
1470
|
+
* `olderThanSecs` is a `u64`: a `bigint`, a non-negative safe-integer
|
|
1471
|
+
* `number`, or a decimal string. Anything else throws `decode_error`.
|
|
1277
1472
|
*/
|
|
1278
|
-
removeExpiredChannels(olderThanSecs: number): Promise<string[]>;
|
|
1473
|
+
removeExpiredChannels(olderThanSecs: bigint | number | string): Promise<string[]>;
|
|
1279
1474
|
|
|
1280
1475
|
/**
|
|
1281
1476
|
* Rebuild this protocol's `secret_id` namespace from a recovered
|
|
1282
1477
|
* `Secret`. Mirrors the Rust `DeRecProtocol::restore` — pass the
|
|
1283
1478
|
* typed `secret` carried by the `SecretRecovered` event verbatim.
|
|
1284
1479
|
*
|
|
1285
|
-
*
|
|
1480
|
+
* Recovery and restore are separate steps on purpose: `SecretRecovered`
|
|
1481
|
+
* writes nothing. Show the user what was recovered, or ask them, before
|
|
1482
|
+
* calling `restore`, which commits it to this device.
|
|
1483
|
+
*
|
|
1484
|
+
* A helper or member whose `transports` is empty gets no channel: it is
|
|
1485
|
+
* reported as a `PeerNotRestored` event in the returned array and the rest
|
|
1486
|
+
* of the roster is restored.
|
|
1487
|
+
*
|
|
1488
|
+
* Errors surface as a `DeRecError` (`category`, `code`, `message`):
|
|
1286
1489
|
*
|
|
1287
1490
|
* | code | meaning |
|
|
1288
1491
|
* |--------------------|------------------------------------------------------------------|
|
|
1289
|
-
* | `
|
|
1290
|
-
* | `
|
|
1492
|
+
* | `already_restored` | A user-secret snapshot already exists for this `secret_id`. |
|
|
1493
|
+
* | `restore_conflict` | Channels live at ids restore is about to write. The error |
|
|
1291
1494
|
* | | carries `channel_ids: string[]` listing the collisions. |
|
|
1292
|
-
* | `
|
|
1293
|
-
* | `
|
|
1495
|
+
* | `invariant` | The recovered `Secret` is internally inconsistent. |
|
|
1496
|
+
* | `invalid_recovered_secret` | `recoveredSecret` is malformed — e.g. a missing or |
|
|
1497
|
+
* | | non-decimal `channel_id` / `replica_id`. |
|
|
1498
|
+
* | `store_error` | A store call failed mid-restore; `category` names the store. |
|
|
1294
1499
|
*/
|
|
1295
1500
|
restore(
|
|
1296
1501
|
recoveredSecret: Extract<DeRecEvent, { type: "SecretRecovered" }>["secret"],
|
|
@@ -1397,6 +1602,22 @@ export interface CommunicationInfo {
|
|
|
1397
1602
|
* protocol can raise. Matches the Rust `PendingActionKind` discriminants
|
|
1398
1603
|
* one-for-one.
|
|
1399
1604
|
*/
|
|
1605
|
+
/** Why a `MessageIgnored` event dropped a message. Matches the Rust
|
|
1606
|
+
* `IgnoreReason` discriminants one-for-one. */
|
|
1607
|
+
export type IgnoreReason = "PendingVerification" | "Expired";
|
|
1608
|
+
|
|
1609
|
+
/** Why a `PeerNotRestored` event left a roster entry without a channel.
|
|
1610
|
+
* Matches the Rust `NotRestoredReason` discriminants one-for-one. */
|
|
1611
|
+
export type NotRestoredReason = "NoTransports";
|
|
1612
|
+
|
|
1613
|
+
/** Why a `RecoveryShareCorrupted` event set a helper's share aside.
|
|
1614
|
+
* Matches the Rust `CorruptionReason` discriminants one-for-one:
|
|
1615
|
+
* `Malformed` — no decodable share for the requested secret and version;
|
|
1616
|
+
* `InvalidProof` — the share fails its own Merkle proof;
|
|
1617
|
+
* `Inconsistent` — valid on its own, but its commitment root or ciphertext
|
|
1618
|
+
* disagrees with the shares the secret was rebuilt from. */
|
|
1619
|
+
export type CorruptionReason = "Malformed" | "InvalidProof" | "Inconsistent";
|
|
1620
|
+
|
|
1400
1621
|
export type PendingActionKind =
|
|
1401
1622
|
| "Pairing"
|
|
1402
1623
|
| "PrePair"
|
|
@@ -1427,17 +1648,9 @@ export interface PairRequestMessage {
|
|
|
1427
1648
|
nonce: bigint;
|
|
1428
1649
|
communication_info?: CommunicationInfo;
|
|
1429
1650
|
parameter_range?: ParameterRange;
|
|
1430
|
-
/**
|
|
1431
|
-
* @deprecated Reading this field directly is incorrect: its meaning narrowed
|
|
1432
|
-
* to "one entry of a list, and possibly absent", so a peer advertising only
|
|
1433
|
-
* `supported_transports` looks unreachable to a reader that was correct
|
|
1434
|
-
* before 0.0.3. Call {@link advertisedEndpoints}, which resolves both
|
|
1435
|
-
* spellings. Removed at 0.0.5.
|
|
1436
|
-
*/
|
|
1437
|
-
transport_protocol?: TransportProtocol;
|
|
1438
1651
|
timestamp?: Timestamp;
|
|
1439
1652
|
/** Every transport endpoint the initiator can be reached on, in its own
|
|
1440
|
-
* preference order.
|
|
1653
|
+
* preference order. */
|
|
1441
1654
|
supported_transports: TransportProtocol[];
|
|
1442
1655
|
}
|
|
1443
1656
|
|
|
@@ -1459,21 +1672,12 @@ export interface PairResponseMessage {
|
|
|
1459
1672
|
|
|
1460
1673
|
export interface PrePairRequestMessage {
|
|
1461
1674
|
nonce: bigint;
|
|
1462
|
-
/**
|
|
1463
|
-
* @deprecated Reading this field directly is incorrect: its meaning narrowed
|
|
1464
|
-
* to "one entry of a list, and possibly absent", so a peer advertising only
|
|
1465
|
-
* `supported_transports` looks unreachable to a reader that was correct
|
|
1466
|
-
* before 0.0.3. Call {@link advertisedEndpoints}, which resolves both
|
|
1467
|
-
* spellings. Removed at 0.0.5.
|
|
1468
|
-
*/
|
|
1469
|
-
transport_protocol?: TransportProtocol;
|
|
1470
1675
|
timestamp?: Timestamp;
|
|
1471
1676
|
/**
|
|
1472
1677
|
* Every endpoint the sender can be reached on for the PrePair reply, in
|
|
1473
|
-
* its own preference order.
|
|
1474
|
-
* must be present.
|
|
1678
|
+
* its own preference order.
|
|
1475
1679
|
*/
|
|
1476
|
-
supported_transports
|
|
1680
|
+
supported_transports: TransportProtocol[];
|
|
1477
1681
|
}
|
|
1478
1682
|
|
|
1479
1683
|
export interface PrePairResponseMessage {
|
|
@@ -1659,6 +1863,15 @@ export interface ProducePrePairResult {
|
|
|
1659
1863
|
envelope: Uint8Array;
|
|
1660
1864
|
}
|
|
1661
1865
|
|
|
1866
|
+
export interface ProducePrePairNoKeysResult {
|
|
1867
|
+
|
|
1868
|
+
envelope: Uint8Array;
|
|
1869
|
+
|
|
1870
|
+
/** Secret key material generated for this pairing. The caller MUST persist
|
|
1871
|
+
* it: the `PairRequest` that follows is encrypted to it. */
|
|
1872
|
+
secret_key_material: Uint8Array;
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1662
1875
|
export interface PrePairRequestExtractResult {
|
|
1663
1876
|
|
|
1664
1877
|
request: PrePairRequestMessage;
|
|
@@ -1711,6 +1924,7 @@ export type DeRecErrorCategory =
|
|
|
1711
1924
|
| "secret_store"
|
|
1712
1925
|
| "channel_store"
|
|
1713
1926
|
| "share_store"
|
|
1927
|
+
| "state_store"
|
|
1714
1928
|
| "input"
|
|
1715
1929
|
| "protobuf"
|
|
1716
1930
|
| "invariant"
|
|
@@ -1724,6 +1938,16 @@ export interface DeRecError {
|
|
|
1724
1938
|
memo?: string;
|
|
1725
1939
|
expected?: number;
|
|
1726
1940
|
got?: number;
|
|
1941
|
+
/** The channel the failing inbound message arrived on, when `process()` could tell. */
|
|
1942
|
+
channel_id?: string;
|
|
1943
|
+
/**
|
|
1944
|
+
* On a failed `process()`: the events it produced before failing, such as
|
|
1945
|
+
* sharing-round and unpair timeouts. They are not reported again, so
|
|
1946
|
+
* handle them as you would a successful call's events.
|
|
1947
|
+
*/
|
|
1948
|
+
events?: DeRecEvent[];
|
|
1949
|
+
/** On a `restore` `CONFLICT`: the pre-existing channels at canonical ids. */
|
|
1950
|
+
channel_ids?: string[];
|
|
1727
1951
|
}
|
|
1728
1952
|
|
|
1729
1953
|
export declare const primitives: {
|
|
@@ -1758,16 +1982,32 @@ export declare const primitives: {
|
|
|
1758
1982
|
* commitment and the scanner must complete a
|
|
1759
1983
|
* `PrePair` round-trip first.
|
|
1760
1984
|
* @param transport_protocols Every endpoint this initiator serves, in
|
|
1761
|
-
* preference order.
|
|
1762
|
-
*
|
|
1763
|
-
*
|
|
1985
|
+
* preference order. For `HashedKeys` mode
|
|
1986
|
+
* they MUST be ephemeral.
|
|
1987
|
+
* @param nonce Correlation nonce embedded in the contact. Omitted or
|
|
1988
|
+
* `null`, the library draws a random `u64` — the right
|
|
1989
|
+
* choice for `InlineKeys` / `HashedKeys`, where the nonce
|
|
1990
|
+
* is a security parameter. Required for `ContactMode.NoKeys`,
|
|
1991
|
+
* where the caller typically picks a short human-typable
|
|
1992
|
+
* value for manual entry. Must fit in a `u64`.
|
|
1764
1993
|
*/
|
|
1765
1994
|
create_contact(
|
|
1766
1995
|
channel_id: bigint,
|
|
1767
1996
|
contact_mode: ContactMode | number,
|
|
1768
1997
|
transport_protocols: TransportProtocol[],
|
|
1998
|
+
nonce?: bigint | number | null,
|
|
1769
1999
|
): CreateContactResult;
|
|
2000
|
+
/**
|
|
2001
|
+
* Serializes a `ContactMessage` to the bytes delivered out of band.
|
|
2002
|
+
* Throws on a contact that violates the invariants of its contact mode
|
|
2003
|
+
* or advertises no endpoint.
|
|
2004
|
+
*/
|
|
1770
2005
|
encode_contact(contact_message: ContactMessage): Uint8Array;
|
|
2006
|
+
/**
|
|
2007
|
+
* Parses out-of-band contact bytes back into a `ContactMessage`. Throws
|
|
2008
|
+
* on bytes that are not a contact, or a contact that violates the
|
|
2009
|
+
* invariants of its contact mode.
|
|
2010
|
+
*/
|
|
1771
2011
|
decode_contact(bytes: Uint8Array): ContactMessage;
|
|
1772
2012
|
produce(
|
|
1773
2013
|
kind: SenderKind,
|
|
@@ -1777,7 +2017,17 @@ export declare const primitives: {
|
|
|
1777
2017
|
parameter_range: ParameterRange | null,
|
|
1778
2018
|
): PairingRequestProduceResult;
|
|
1779
2019
|
|
|
1780
|
-
|
|
2020
|
+
/**
|
|
2021
|
+
* @param parameter_range The range this side accepts, or `null` for
|
|
2022
|
+
* none. A request advertising a range that does
|
|
2023
|
+
* not overlap it is refused with
|
|
2024
|
+
* `incompatible_parameter_range`.
|
|
2025
|
+
*/
|
|
2026
|
+
extract(
|
|
2027
|
+
envelope_bytes: Uint8Array,
|
|
2028
|
+
secret_key: Uint8Array,
|
|
2029
|
+
parameter_range: ParameterRange | null,
|
|
2030
|
+
): { request: PairRequestMessage };
|
|
1781
2031
|
|
|
1782
2032
|
/**
|
|
1783
2033
|
* Scanner-side: build a plaintext `PrePairRequest` envelope when the
|
|
@@ -1789,8 +2039,6 @@ export declare const primitives: {
|
|
|
1789
2039
|
/**
|
|
1790
2040
|
* @param own_transports Every endpoint this scanner serves for the
|
|
1791
2041
|
* PrePair reply, in its own preference order.
|
|
1792
|
-
* The first entry also fills the deprecated
|
|
1793
|
-
* singular field for peers predating the list.
|
|
1794
2042
|
*/
|
|
1795
2043
|
produce_pre_pair(
|
|
1796
2044
|
own_transports: TransportProtocol[],
|
|
@@ -1805,6 +2053,10 @@ export declare const primitives: {
|
|
|
1805
2053
|
};
|
|
1806
2054
|
response: {
|
|
1807
2055
|
/**
|
|
2056
|
+
* @param parameter_range The range this side accepts and advertises,
|
|
2057
|
+
* or `null` for none. A request advertising a
|
|
2058
|
+
* range that does not overlap it is refused
|
|
2059
|
+
* with `incompatible_parameter_range`.
|
|
1808
2060
|
* @param unsafe_connection Accept plaintext peer endpoints
|
|
1809
2061
|
* (`http://`, `grpc://`). Development only.
|
|
1810
2062
|
*/
|
|
@@ -1818,10 +2070,18 @@ export declare const primitives: {
|
|
|
1818
2070
|
): PairingResponseProduceResult;
|
|
1819
2071
|
|
|
1820
2072
|
extract(envelope_bytes: Uint8Array, secret_key: Uint8Array): { response: PairResponseMessage };
|
|
2073
|
+
/**
|
|
2074
|
+
* @param parameter_range The range this side accepts, or `null` for
|
|
2075
|
+
* none. A response advertising a range that
|
|
2076
|
+
* does not overlap it is refused with
|
|
2077
|
+
* `incompatible_parameter_range` before any key
|
|
2078
|
+
* is derived.
|
|
2079
|
+
*/
|
|
1821
2080
|
process(
|
|
1822
2081
|
contact_message: ContactMessage,
|
|
1823
2082
|
response: PairResponseMessage,
|
|
1824
2083
|
secret_key: Uint8Array,
|
|
2084
|
+
parameter_range: ParameterRange | null,
|
|
1825
2085
|
): PairingProcessResult;
|
|
1826
2086
|
|
|
1827
2087
|
/**
|
|
@@ -1849,7 +2109,41 @@ export declare const primitives: {
|
|
|
1849
2109
|
contact_message: ContactMessage,
|
|
1850
2110
|
response: PrePairResponseMessage,
|
|
1851
2111
|
): ProcessPrePairResult;
|
|
2112
|
+
|
|
2113
|
+
/**
|
|
2114
|
+
* Contact-creator side of a `NoKeys` pairing: generate key material and
|
|
2115
|
+
* answer the `PrePairRequest` with its public half.
|
|
2116
|
+
*
|
|
2117
|
+
* The caller MUST first match the request's `nonce` against the contact
|
|
2118
|
+
* it issued — the only thing that authenticates a `NoKeys` request — and
|
|
2119
|
+
* MUST persist `secret_key_material`. The resulting channel MUST stay
|
|
2120
|
+
* unusable until both sides confirm `pairing.fingerprint` out of band.
|
|
2121
|
+
*/
|
|
2122
|
+
produce_pre_pair_no_keys(
|
|
2123
|
+
channel_id: bigint,
|
|
2124
|
+
request: PrePairRequestMessage,
|
|
2125
|
+
): ProducePrePairNoKeysResult;
|
|
2126
|
+
|
|
2127
|
+
/**
|
|
2128
|
+
* Scanner side of a `NoKeys` pairing: accept the contact creator's
|
|
2129
|
+
* public keys. There is no binding hash to check them against, so the
|
|
2130
|
+
* resulting channel MUST stay unusable until both sides confirm
|
|
2131
|
+
* `pairing.fingerprint` out of band. Throws on a non-`Ok` status, a
|
|
2132
|
+
* missing key or a `nonce` mismatch.
|
|
2133
|
+
*/
|
|
2134
|
+
process_pre_pair_no_keys(
|
|
2135
|
+
contact_message: ContactMessage,
|
|
2136
|
+
response: PrePairResponseMessage,
|
|
2137
|
+
): ProcessPrePairResult;
|
|
1852
2138
|
};
|
|
2139
|
+
|
|
2140
|
+
/**
|
|
2141
|
+
* The human-readable fingerprint of a pairing's 32-byte shared key. Both
|
|
2142
|
+
* ends derive the same value; comparing it out of band confirms the
|
|
2143
|
+
* pairing. A `NoKeys` pairing MUST be confirmed this way before use.
|
|
2144
|
+
* Throws on a key that is not 32 bytes.
|
|
2145
|
+
*/
|
|
2146
|
+
fingerprint(shared_key: Uint8Array): string;
|
|
1853
2147
|
};
|
|
1854
2148
|
recovery: {
|
|
1855
2149
|
request: {
|