@derec-alliance/react-native 0.0.4 → 0.0.6
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 +9 -15
- package/android/CMakeLists.txt +1 -1
- package/android/src/main/jniLibs/arm64-v8a/libderec_library.a +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libderec_library.a +0 -0
- package/android/src/main/jniLibs/x86_64/libderec_library.a +0 -0
- package/cpp/Convert.cpp +125 -0
- package/cpp/Convert.h +35 -0
- package/cpp/DeRecInstaller.cpp +0 -12
- package/cpp/Primitives.cpp +159 -26
- package/cpp/Primitives.h +16 -0
- package/cpp/ProtocolHost.cpp +22 -47
- package/cpp/StoreCallbacks.cpp +97 -304
- package/cpp/UserSecretsJson.cpp +109 -0
- package/cpp/UserSecretsJson.h +28 -0
- package/cpp/derec_ffi.h +256 -120
- package/ios/DeRecFFI.xcframework/ios-arm64/Headers/derec_ffi.h +256 -120
- package/ios/DeRecFFI.xcframework/ios-arm64/libderec_library.a +0 -0
- package/ios/DeRecFFI.xcframework/ios-arm64_x86_64-simulator/Headers/derec_ffi.h +256 -120
- package/ios/DeRecFFI.xcframework/ios-arm64_x86_64-simulator/libderec_library.a +2 -2
- package/lib/errors.d.ts +7 -0
- package/lib/native.d.ts +5 -1
- package/lib/primitives.d.ts +18 -21
- package/lib/primitives.js +48 -25
- package/lib/protocol.d.ts +49 -97
- package/lib/protocol.js +71 -162
- package/lib/types.d.ts +218 -107
- package/lib/types.js +43 -13
- package/package.json +1 -1
- package/src/errors.ts +7 -0
- package/src/native.ts +2 -1
- package/src/primitives.ts +82 -25
- package/src/protocol.ts +79 -179
- package/src/types.ts +232 -96
package/src/types.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
// Copyright (c) 2026 DeRec Alliance. All rights reserved.
|
|
3
3
|
|
|
4
|
+
import { getNative } from './native';
|
|
5
|
+
|
|
4
6
|
export interface SecretStore {
|
|
5
7
|
load(
|
|
6
8
|
secretId: string,
|
|
@@ -9,15 +11,15 @@ export interface SecretStore {
|
|
|
9
11
|
): Promise<Uint8Array | null | undefined>;
|
|
10
12
|
/**
|
|
11
13
|
* 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`.
|
|
14
|
+
* scoped to `secretId`. Must return an array with exactly one entry per
|
|
15
|
+
* input id, in the same order, using `null` (or `undefined`) for channels
|
|
16
|
+
* with no stored secret of `kind`. Whether a missing entry is an error is
|
|
17
|
+
* decided by the library.
|
|
15
18
|
*/
|
|
16
19
|
loadMany(
|
|
17
20
|
secretId: string,
|
|
18
21
|
channelIds: string[],
|
|
19
22
|
kind: 0 | 1 | 2,
|
|
20
|
-
missingPolicy: "skip" | "fail",
|
|
21
23
|
): Promise<Array<Uint8Array | null | undefined>>;
|
|
22
24
|
save(
|
|
23
25
|
secretId: string,
|
|
@@ -120,30 +122,15 @@ export function channelFilterMatches(
|
|
|
120
122
|
/**
|
|
121
123
|
* The endpoints a peer-supplied message advertises, in the peer's own order.
|
|
122
124
|
*
|
|
123
|
-
* Yields `supported_transports` when it is non-empty, and otherwise the
|
|
124
|
-
* singular `transport_protocol` — which is how every implementation predating
|
|
125
|
-
* the offer list advertises, and the reason this is a function rather than a
|
|
126
|
-
* field read. Reading `transport_protocol` directly is a bug: its meaning
|
|
127
|
-
* narrowed to "one entry of a list, and possibly absent", so a peer that has
|
|
128
|
-
* moved past it looks unreachable to a reader that was correct before 0.0.3.
|
|
129
|
-
*
|
|
130
125
|
* Reports what was advertised, not what is acceptable — nothing here is
|
|
131
126
|
* validated, and the protocol still applies its own transport policy to
|
|
132
127
|
* whatever it records.
|
|
133
128
|
*/
|
|
134
129
|
export function advertisedEndpoints(
|
|
135
|
-
message:
|
|
136
|
-
| {
|
|
137
|
-
transport_protocol?: TransportProtocol;
|
|
138
|
-
supported_transports?: TransportProtocol[];
|
|
139
|
-
}
|
|
140
|
-
| null
|
|
141
|
-
| undefined,
|
|
130
|
+
message: { supported_transports?: TransportProtocol[] } | null | undefined,
|
|
142
131
|
): TransportProtocol[] {
|
|
143
132
|
if (!message) return [];
|
|
144
|
-
|
|
145
|
-
if (offers.length > 0) return offers;
|
|
146
|
-
return message.transport_protocol ? [message.transport_protocol] : [];
|
|
133
|
+
return message.supported_transports ?? [];
|
|
147
134
|
}
|
|
148
135
|
|
|
149
136
|
/**
|
|
@@ -242,11 +229,7 @@ export interface ChannelStore {
|
|
|
242
229
|
secretId: string,
|
|
243
230
|
filter: ReplicaFilter,
|
|
244
231
|
): Promise<Uint8Array | null | undefined>;
|
|
245
|
-
linkChannel(
|
|
246
|
-
secretId: string,
|
|
247
|
-
channelId: string,
|
|
248
|
-
linkedChannelId: string,
|
|
249
|
-
): Promise<void>;
|
|
232
|
+
linkChannel(secretId: string, a: string, b: string): Promise<void>;
|
|
250
233
|
linkedChannels(secretId: string, channelId: string): Promise<string[]>;
|
|
251
234
|
}
|
|
252
235
|
|
|
@@ -256,6 +239,17 @@ export interface Share {
|
|
|
256
239
|
bytes: Uint8Array;
|
|
257
240
|
}
|
|
258
241
|
|
|
242
|
+
/**
|
|
243
|
+
* Share-record persistence.
|
|
244
|
+
*
|
|
245
|
+
* Rows are keyed by `(secretId, channelId, version)` where `secretId` is
|
|
246
|
+
* the partition passed to every method. `Share.secretId` is a different
|
|
247
|
+
* value: it names the secret the bytes belong to, which on a helper is
|
|
248
|
+
* the owner's id and routinely differs from the partition this device
|
|
249
|
+
* stores under. Key on the argument and carry `share.secretId` alongside
|
|
250
|
+
* as data — keying on it instead puts rows where no `load` looks, since
|
|
251
|
+
* every read filters on the partition.
|
|
252
|
+
*/
|
|
259
253
|
export interface ShareStore {
|
|
260
254
|
load(secretId: string, channelId: string, versions: number[]): Promise<Share[]>;
|
|
261
255
|
loadMany(
|
|
@@ -279,6 +273,10 @@ export interface UserSecrets {
|
|
|
279
273
|
version: number;
|
|
280
274
|
secrets: UserSecretEntry[];
|
|
281
275
|
description?: string;
|
|
276
|
+
/** Decimal `replica_id` of the member that published `version`. Absent
|
|
277
|
+
* when none is recorded. Store and return it unchanged: replica members
|
|
278
|
+
* compare it to detect a conflicting copy of the same version. */
|
|
279
|
+
author_replica_id?: string;
|
|
282
280
|
}
|
|
283
281
|
|
|
284
282
|
/**
|
|
@@ -322,6 +320,18 @@ export interface StateStore {
|
|
|
322
320
|
loadAll(secretId: string, kind: 0 | 1 | 2 | 3 | 4): Promise<Uint8Array[]>;
|
|
323
321
|
}
|
|
324
322
|
|
|
323
|
+
/** A transport protocol, by name. */
|
|
324
|
+
export type TransportProtocolName = "https" | "grpc";
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* One endpoint a node serves or a peer advertised, as every app-facing call
|
|
328
|
+
* and event carries it.
|
|
329
|
+
*/
|
|
330
|
+
export interface Endpoint {
|
|
331
|
+
uri: string;
|
|
332
|
+
protocol: TransportProtocolName;
|
|
333
|
+
}
|
|
334
|
+
|
|
325
335
|
/**
|
|
326
336
|
* Outbound message delivery.
|
|
327
337
|
*
|
|
@@ -367,7 +377,7 @@ export interface Transport {
|
|
|
367
377
|
* {@link singleEndpointTransport} rather than by indexing.
|
|
368
378
|
*/
|
|
369
379
|
send(
|
|
370
|
-
endpoints: ReadonlyArray<
|
|
380
|
+
endpoints: ReadonlyArray<Endpoint>,
|
|
371
381
|
message: Uint8Array,
|
|
372
382
|
): Promise<void>;
|
|
373
383
|
}
|
|
@@ -387,10 +397,28 @@ export interface Transport {
|
|
|
387
397
|
* a round trip; skipping one that would have worked costs the delivery.
|
|
388
398
|
*/
|
|
389
399
|
export type SendOne = (
|
|
390
|
-
endpoint:
|
|
400
|
+
endpoint: Endpoint,
|
|
391
401
|
message: Uint8Array,
|
|
392
402
|
) => Promise<void>;
|
|
393
403
|
|
|
404
|
+
/**
|
|
405
|
+
* The DeRec protocol version this build speaks — the `protocolVersionMajor` /
|
|
406
|
+
* `protocolVersionMinor` it writes into every envelope it produces. Not the
|
|
407
|
+
* package version.
|
|
408
|
+
*/
|
|
409
|
+
export function protocol_version(): { major: number; minor: number } {
|
|
410
|
+
return getNative().version();
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* A fresh, random replica id — never `0`. Generate it once per device,
|
|
415
|
+
* persist it, and pass the same value to
|
|
416
|
+
* `DeRecProtocolBuilder.withReplicaId` on every init.
|
|
417
|
+
*/
|
|
418
|
+
export function generate_replica_id(): bigint {
|
|
419
|
+
return getNative().generate_replica_id();
|
|
420
|
+
}
|
|
421
|
+
|
|
394
422
|
/**
|
|
395
423
|
* Builds a {@link Transport} that tries each endpoint in the order the peer
|
|
396
424
|
* offered it and stops at the first success.
|
|
@@ -462,7 +490,7 @@ export enum SenderKind {
|
|
|
462
490
|
* the scanner must fetch the actual keys over the wire via the `PrePair`
|
|
463
491
|
* round-trip and verify them against the commitment before pairing.
|
|
464
492
|
* - `NoKeys`: no key material and no commitment. The contact carries only
|
|
465
|
-
* `channel_id`, `nonce`, and `
|
|
493
|
+
* `channel_id`, `nonce`, and `supported_transports` — small enough to be
|
|
466
494
|
* hand-typed or dictated. Keys are generated on the fly by the contact
|
|
467
495
|
* creator when the `PrePairRequest` arrives; the scanner accepts them
|
|
468
496
|
* without cryptographic verification. Trust rests entirely on the OOB
|
|
@@ -504,20 +532,33 @@ export enum FlowKind {
|
|
|
504
532
|
UnpairReplica = 8,
|
|
505
533
|
}
|
|
506
534
|
|
|
535
|
+
/** Result status carried in every protocol response (`result.proto`). Passed
|
|
536
|
+
* to `reject()` to say why an inbound request was refused. */
|
|
537
|
+
export enum StatusEnum {
|
|
538
|
+
Ok = 0,
|
|
539
|
+
Partial = 1,
|
|
540
|
+
Fail = 2,
|
|
541
|
+
SizeLimitExceeded = 3,
|
|
542
|
+
TooFrequent = 4,
|
|
543
|
+
UnknownSecretId = 5,
|
|
544
|
+
UnknownShareVersion = 6,
|
|
545
|
+
DecryptionFailed = 7,
|
|
546
|
+
VerificationFailed = 8,
|
|
547
|
+
FormatError = 9,
|
|
548
|
+
Rejected = 10,
|
|
549
|
+
IncompatibleParameterRange = 11,
|
|
550
|
+
UnsupportedTransportProtocol = 12,
|
|
551
|
+
VersionConflict = 13,
|
|
552
|
+
ReplicaIdConflict = 14,
|
|
553
|
+
RequestToClose = 99,
|
|
554
|
+
}
|
|
555
|
+
|
|
507
556
|
export type UnpairAck = "required" | "not_required";
|
|
508
557
|
|
|
509
558
|
export interface ContactMessage {
|
|
510
559
|
channel_id: bigint;
|
|
511
560
|
/** `ContactMode` numeric value (0 = INLINE_KEYS, 1 = HASHED_KEYS, 2 = NO_KEYS). */
|
|
512
561
|
contact_mode: number;
|
|
513
|
-
/**
|
|
514
|
-
* @deprecated Reading this field directly is incorrect: its meaning narrowed
|
|
515
|
-
* to "one entry of a list, and possibly absent", so a peer advertising only
|
|
516
|
-
* `supported_transports` looks unreachable to a reader that was correct
|
|
517
|
-
* before 0.0.3. Call {@link advertisedEndpoints}, which resolves both
|
|
518
|
-
* spellings. Removed at 0.0.5.
|
|
519
|
-
*/
|
|
520
|
-
transport_protocol?: TransportProtocol;
|
|
521
562
|
nonce: bigint;
|
|
522
563
|
/** Present only when `contact_mode === ContactMode.InlineKeys`. */
|
|
523
564
|
mlkem_encapsulation_key?: Uint8Array;
|
|
@@ -527,8 +568,7 @@ export interface ContactMessage {
|
|
|
527
568
|
contact_binding_hash?: Uint8Array;
|
|
528
569
|
timestamp?: Timestamp;
|
|
529
570
|
/** Every transport endpoint the creator of this contact can be reached
|
|
530
|
-
* on, in its own preference order.
|
|
531
|
-
* `transport_protocol` is offered". */
|
|
571
|
+
* on, in its own preference order. */
|
|
532
572
|
supported_transports: TransportProtocol[];
|
|
533
573
|
}
|
|
534
574
|
|
|
@@ -576,20 +616,11 @@ export interface UpdateChannelInfoParams {
|
|
|
576
616
|
* map untouched; pass an empty object to clear it. */
|
|
577
617
|
communication_info?: Record<string, string>;
|
|
578
618
|
|
|
579
|
-
/**
|
|
580
|
-
* New transport endpoint. Absent leaves it untouched.
|
|
581
|
-
*
|
|
582
|
-
* @deprecated Use `own_transports`, which carries every endpoint this node
|
|
583
|
-
* now serves; its first entry also fills this field for peers predating the
|
|
584
|
-
* list. Removed at 0.0.5.
|
|
585
|
-
*/
|
|
586
|
-
transport_protocol?: { uri: string; protocol: number };
|
|
587
619
|
/**
|
|
588
620
|
* Every endpoint this node now serves, in its own preference order.
|
|
589
|
-
* Omitted leaves the target(s)' stored set untouched.
|
|
590
|
-
* over `transport_protocol`, whose first entry it also fills.
|
|
621
|
+
* Omitted leaves the target(s)' stored set untouched.
|
|
591
622
|
*/
|
|
592
|
-
own_transports?:
|
|
623
|
+
own_transports?: Endpoint[];
|
|
593
624
|
}
|
|
594
625
|
|
|
595
626
|
/**
|
|
@@ -648,18 +679,34 @@ export type DeRecEvent =
|
|
|
648
679
|
action: Uint8Array;
|
|
649
680
|
|
|
650
681
|
action_kind: PendingActionKind;
|
|
682
|
+
/** Correlation token of the inbound request, decimal-encoded. */
|
|
683
|
+
trace_id: string;
|
|
684
|
+
/** Pairing only. */
|
|
651
685
|
peer_communication_info?: Record<string, string>;
|
|
652
|
-
|
|
686
|
+
/** `sender_kind` of the inbound pair request (Pairing only). */
|
|
653
687
|
sender_kind?: SenderKind;
|
|
654
|
-
|
|
688
|
+
/** Share version (StoreShare / VerifyShare / GetShare). */
|
|
655
689
|
version?: number;
|
|
690
|
+
/** Description of the secret version (StoreShare only). */
|
|
656
691
|
share_description?: string;
|
|
657
|
-
|
|
692
|
+
/** Secret identifier, decimal-encoded (StoreShare / VerifyShare /
|
|
693
|
+
* GetShare). On GetShare, with `version`, names the requested share. */
|
|
658
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[];
|
|
659
706
|
}
|
|
660
707
|
| { type: "ShareStored"; channel_id: string; version: number }
|
|
661
708
|
| { type: "ShareConfirmed"; channel_id: string; version: number }
|
|
662
|
-
| { type: "ShareRejected"; channel_id: string; version: number; status:
|
|
709
|
+
| { type: "ShareRejected"; channel_id: string; version: number; status: StatusEnum; memo: string }
|
|
663
710
|
/** A publishing round finished — every targeted helper confirmed,
|
|
664
711
|
* rejected, or timed out.
|
|
665
712
|
*
|
|
@@ -684,7 +731,7 @@ export type DeRecEvent =
|
|
|
684
731
|
replica_id: string;
|
|
685
732
|
secret_id: string;
|
|
686
733
|
version: number;
|
|
687
|
-
status:
|
|
734
|
+
status: StatusEnum;
|
|
688
735
|
memo: string;
|
|
689
736
|
}
|
|
690
737
|
/** A secret sync could not be delivered to a member at all — distinct from
|
|
@@ -737,9 +784,9 @@ export type DeRecEvent =
|
|
|
737
784
|
helpers: Array<{
|
|
738
785
|
channel_id: string;
|
|
739
786
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
740
|
-
transports:
|
|
787
|
+
transports: Endpoint[];
|
|
741
788
|
shared_key: Uint8Array;
|
|
742
|
-
communication_info
|
|
789
|
+
communication_info?: Record<string, string>;
|
|
743
790
|
}>;
|
|
744
791
|
secrets: Array<{
|
|
745
792
|
id: Uint8Array;
|
|
@@ -759,9 +806,9 @@ export type DeRecEvent =
|
|
|
759
806
|
members: Array<{
|
|
760
807
|
replica_id: string;
|
|
761
808
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
762
|
-
transports:
|
|
809
|
+
transports: Endpoint[];
|
|
763
810
|
role: "Source" | "Destination";
|
|
764
|
-
communication_info
|
|
811
|
+
communication_info?: Record<string, string>;
|
|
765
812
|
}>;
|
|
766
813
|
shared_key: Uint8Array;
|
|
767
814
|
};
|
|
@@ -770,12 +817,12 @@ export type DeRecEvent =
|
|
|
770
817
|
|
|
771
818
|
| { type: "Unpaired"; channel_id: string }
|
|
772
819
|
|
|
773
|
-
| { type: "UnpairRejected"; channel_id: string; status:
|
|
820
|
+
| { type: "UnpairRejected"; channel_id: string; status: StatusEnum; memo: string }
|
|
774
821
|
|
|
775
822
|
/** Contact creator answered the scanner's `PrePairRequest` with a
|
|
776
823
|
* non-Ok status (HashedKeys flow). Distinct from a cryptographic
|
|
777
824
|
* hash mismatch, which surfaces as a thrown error from `process()`. */
|
|
778
|
-
| { type: "PrePairRejected"; channel_id: string; status:
|
|
825
|
+
| { type: "PrePairRejected"; channel_id: string; status: StatusEnum; memo: string }
|
|
779
826
|
|
|
780
827
|
/** Fires alongside `PairingCompleted` on replica-mode pair handshakes.
|
|
781
828
|
* `peer_replica_id` is the peer's `u64` as a **decimal** string,
|
|
@@ -793,22 +840,28 @@ export type DeRecEvent =
|
|
|
793
840
|
/** A `ReplicaSource` peer pushed a secret sync on a
|
|
794
841
|
* `ReplicaDestination` channel. The library decoded the
|
|
795
842
|
* `ReplicaSecretPayload`; the app installs `secret.secrets` and
|
|
796
|
-
* optionally uses `shares` for recovery. `from_replica_id
|
|
797
|
-
* `replica_id` fields inside `secret` are
|
|
798
|
-
* strings.
|
|
843
|
+
* optionally uses `shares` for recovery. `from_replica_id`,
|
|
844
|
+
* `author_replica_id` and the `replica_id` fields inside `secret` are
|
|
845
|
+
* `u64` as **decimal** strings.
|
|
846
|
+
*
|
|
847
|
+
* `from_replica_id` is the member this copy came from: the publisher on
|
|
848
|
+
* a push, the serving member on a catch-up. `author_replica_id` is the
|
|
849
|
+
* member that published `version`, or `null` when the serving member's
|
|
850
|
+
* snapshot records none. */
|
|
799
851
|
| {
|
|
800
852
|
type: "ReplicaSecretReceived";
|
|
801
853
|
channel_id: string;
|
|
802
854
|
from_replica_id: string;
|
|
855
|
+
author_replica_id: string | null;
|
|
803
856
|
secret_id: string;
|
|
804
857
|
version: number;
|
|
805
858
|
secret: {
|
|
806
859
|
helpers: Array<{
|
|
807
860
|
channel_id: string;
|
|
808
861
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
809
|
-
transports:
|
|
862
|
+
transports: Endpoint[];
|
|
810
863
|
shared_key: Uint8Array;
|
|
811
|
-
communication_info
|
|
864
|
+
communication_info?: Record<string, string>;
|
|
812
865
|
}>;
|
|
813
866
|
secrets: Array<{
|
|
814
867
|
id: Uint8Array;
|
|
@@ -826,9 +879,9 @@ export type DeRecEvent =
|
|
|
826
879
|
members: Array<{
|
|
827
880
|
replica_id: string;
|
|
828
881
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
829
|
-
transports:
|
|
882
|
+
transports: Endpoint[];
|
|
830
883
|
role: "Source" | "Destination";
|
|
831
|
-
communication_info
|
|
884
|
+
communication_info?: Record<string, string>;
|
|
832
885
|
}>;
|
|
833
886
|
shared_key: Uint8Array;
|
|
834
887
|
};
|
|
@@ -851,15 +904,16 @@ export type DeRecEvent =
|
|
|
851
904
|
type: "ReplicaSecretInstalled";
|
|
852
905
|
channel_id: string;
|
|
853
906
|
from_replica_id: string;
|
|
907
|
+
author_replica_id: string | null;
|
|
854
908
|
secret_id: string;
|
|
855
909
|
version: number;
|
|
856
910
|
secret: {
|
|
857
911
|
helpers: Array<{
|
|
858
912
|
channel_id: string;
|
|
859
913
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
860
|
-
transports:
|
|
914
|
+
transports: Endpoint[];
|
|
861
915
|
shared_key: Uint8Array;
|
|
862
|
-
communication_info
|
|
916
|
+
communication_info?: Record<string, string>;
|
|
863
917
|
}>;
|
|
864
918
|
secrets: Array<{
|
|
865
919
|
id: Uint8Array;
|
|
@@ -877,9 +931,9 @@ export type DeRecEvent =
|
|
|
877
931
|
members: Array<{
|
|
878
932
|
replica_id: string;
|
|
879
933
|
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
880
|
-
transports:
|
|
934
|
+
transports: Endpoint[];
|
|
881
935
|
role: "Source" | "Destination";
|
|
882
|
-
communication_info
|
|
936
|
+
communication_info?: Record<string, string>;
|
|
883
937
|
}>;
|
|
884
938
|
shared_key: Uint8Array;
|
|
885
939
|
};
|
|
@@ -889,6 +943,56 @@ export type DeRecEvent =
|
|
|
889
943
|
committed_share: Uint8Array;
|
|
890
944
|
}>;
|
|
891
945
|
}
|
|
946
|
+
/** A member offered a different copy of the version this device holds.
|
|
947
|
+
* Nothing was written: this device keeps its own copy and refuses the
|
|
948
|
+
* incoming one with `VERSION_CONFLICT`, so the publisher sees
|
|
949
|
+
* `ReplicaSyncRejected`. Both copies are complete states — the held one
|
|
950
|
+
* is in the local stores, the incoming one is `secret`. Resolve by
|
|
951
|
+
* publishing the chosen state with `start(FlowKind.ProtectSecret)`; the
|
|
952
|
+
* next version supersedes both on every member and helper.
|
|
953
|
+
*
|
|
954
|
+
* `held_author_replica_id` / `incoming_author_replica_id` are the
|
|
955
|
+
* decimal `replica_id` of each copy's publisher, or `null` when that
|
|
956
|
+
* copy records none. */
|
|
957
|
+
| {
|
|
958
|
+
type: "ReplicaVersionConflict";
|
|
959
|
+
channel_id: string;
|
|
960
|
+
from_replica_id: string;
|
|
961
|
+
secret_id: string;
|
|
962
|
+
version: number;
|
|
963
|
+
held_author_replica_id: string | null;
|
|
964
|
+
incoming_author_replica_id: string | null;
|
|
965
|
+
secret: {
|
|
966
|
+
helpers: Array<{
|
|
967
|
+
channel_id: string;
|
|
968
|
+
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
969
|
+
transports: Endpoint[];
|
|
970
|
+
shared_key: Uint8Array;
|
|
971
|
+
communication_info?: Record<string, string>;
|
|
972
|
+
}>;
|
|
973
|
+
secrets: Array<{
|
|
974
|
+
id: Uint8Array;
|
|
975
|
+
name: string;
|
|
976
|
+
data: Uint8Array;
|
|
977
|
+
}>;
|
|
978
|
+
/** The same shape as `SecretRecovered.secret.replicas`. */
|
|
979
|
+
replicas?: {
|
|
980
|
+
/** The one channel every member is addressed on. */
|
|
981
|
+
channel_id: string;
|
|
982
|
+
/** Every member of the group, including the writer. Exactly one
|
|
983
|
+
* carries `role: "Source"` — that member is where the secret
|
|
984
|
+
* originated, which is why no separate owner field is needed. */
|
|
985
|
+
members: Array<{
|
|
986
|
+
replica_id: string;
|
|
987
|
+
/** Every endpoint this peer advertised, in the order it offered them. */
|
|
988
|
+
transports: Endpoint[];
|
|
989
|
+
role: "Source" | "Destination";
|
|
990
|
+
communication_info?: Record<string, string>;
|
|
991
|
+
}>;
|
|
992
|
+
shared_key: Uint8Array;
|
|
993
|
+
};
|
|
994
|
+
};
|
|
995
|
+
}
|
|
892
996
|
/** Peer's ack of a secret sync we sent. `status` is the `StatusEnum`
|
|
893
997
|
* integer (0 = Ok), `memo` is the peer's explanation. */
|
|
894
998
|
| {
|
|
@@ -897,7 +1001,7 @@ export type DeRecEvent =
|
|
|
897
1001
|
from_replica_id: string;
|
|
898
1002
|
secret_id: string;
|
|
899
1003
|
version: number;
|
|
900
|
-
status:
|
|
1004
|
+
status: StatusEnum;
|
|
901
1005
|
memo: string;
|
|
902
1006
|
}
|
|
903
1007
|
/** A peer announced an updated `communication_info` map and/or
|
|
@@ -914,7 +1018,7 @@ export type DeRecEvent =
|
|
|
914
1018
|
| {
|
|
915
1019
|
type: "ChannelInfoUpdateRejected";
|
|
916
1020
|
channel_id: string;
|
|
917
|
-
status:
|
|
1021
|
+
status: StatusEnum;
|
|
918
1022
|
memo: string;
|
|
919
1023
|
}
|
|
920
1024
|
/** Emitted by `process()` in place of `ActionRequired` when the
|
|
@@ -926,6 +1030,38 @@ export type DeRecEvent =
|
|
|
926
1030
|
* (`"Pairing"`, `"StoreShare"`, …). */
|
|
927
1031
|
| { type: "AutoAccepted"; channel_id: string; action_kind: PendingActionKind }
|
|
928
1032
|
| { type: "NoOp" }
|
|
1033
|
+
/** An inbound message was dropped untouched: no store was written and
|
|
1034
|
+
* nothing was sent back. `reason` says why.
|
|
1035
|
+
*
|
|
1036
|
+
* `"PendingVerification"` means the peer sent something before this
|
|
1037
|
+
* device confirmed the channel's fingerprint — typically a replica source
|
|
1038
|
+
* pushing its first copy while this destination still shows the code.
|
|
1039
|
+
* Confirming does not replay it: after `verifyFingerprint` succeeds, a
|
|
1040
|
+
* replica destination calls `start(FlowKind.ReplicaDiscovery)` to pull
|
|
1041
|
+
* the copy itself. `"Expired"` means the message was older than the
|
|
1042
|
+
* inbound timeout. `trace_id` matches the peer's `*Started` event for
|
|
1043
|
+
* the same round (`"0"` when the sender set none). */
|
|
1044
|
+
| {
|
|
1045
|
+
type: "MessageIgnored";
|
|
1046
|
+
channel_id: string;
|
|
1047
|
+
reason: IgnoreReason;
|
|
1048
|
+
trace_id: string;
|
|
1049
|
+
}
|
|
1050
|
+
/** Returned by `restore`: a roster entry got no channel, so this device
|
|
1051
|
+
* cannot reach that peer. Every other entry and the user-secret snapshot
|
|
1052
|
+
* were restored; `reason` says why this one was not. `"NoTransports"`
|
|
1053
|
+
* means the recovered roster names no endpoint for it.
|
|
1054
|
+
*
|
|
1055
|
+
* For a helper, `channel_id` is its channel and `replica_id` is absent.
|
|
1056
|
+
* For a replica group member, `channel_id` is the group's channel and
|
|
1057
|
+
* `replica_id` names the member. The peer itself is untouched — a helper
|
|
1058
|
+
* still holds its share — and pairing with it again makes it reachable. */
|
|
1059
|
+
| {
|
|
1060
|
+
type: "PeerNotRestored";
|
|
1061
|
+
channel_id: string;
|
|
1062
|
+
replica_id?: string;
|
|
1063
|
+
reason: NotRestoredReason;
|
|
1064
|
+
}
|
|
929
1065
|
/** A pairing handshake was dispatched successfully. `kind` is the
|
|
930
1066
|
* local party's role — same value the subsequent `PairingCompleted`
|
|
931
1067
|
* will carry. Emitted by `start(Pairing)`. */
|
|
@@ -994,8 +1130,8 @@ export type DeRecEvent =
|
|
|
994
1130
|
* inbound shares. The protocol enforces no size, quota or rate limit
|
|
995
1131
|
* of its own, and `maxShareSize` is checked for range overlap at
|
|
996
1132
|
* pairing time only, never against an actual share. While this is
|
|
997
|
-
* `false`, `ActionRequired` carries
|
|
998
|
-
*
|
|
1133
|
+
* `false`, `ActionRequired` carries `share_size`, so the application
|
|
1134
|
+
* can compare it to its quota and call `reject()` with
|
|
999
1135
|
* `StatusEnum.SizeLimitExceeded`. Setting it `true` removes that
|
|
1000
1136
|
* opportunity entirely: every share from every paired Owner is stored
|
|
1001
1137
|
* unconditionally, at whatever size it arrives. Keep off in any
|
|
@@ -1088,6 +1224,14 @@ export interface CommunicationInfo {
|
|
|
1088
1224
|
// `ContactMessage` is defined once above and covers both `INLINE_KEYS` and
|
|
1089
1225
|
// `HASHED_KEYS` modes.
|
|
1090
1226
|
|
|
1227
|
+
/** Why a `MessageIgnored` event dropped a message. Matches the Rust
|
|
1228
|
+
* `IgnoreReason` discriminants one-for-one. */
|
|
1229
|
+
export type IgnoreReason = "PendingVerification" | "Expired";
|
|
1230
|
+
|
|
1231
|
+
/** Why a `PeerNotRestored` event left a roster entry without a channel.
|
|
1232
|
+
* Matches the Rust `NotRestoredReason` discriminants one-for-one. */
|
|
1233
|
+
export type NotRestoredReason = "NoTransports";
|
|
1234
|
+
|
|
1091
1235
|
/**
|
|
1092
1236
|
* The label vocabulary for `ActionRequired.action_kind` and
|
|
1093
1237
|
* `AutoAccepted.action_kind` — one value per pending-action kind the
|
|
@@ -1124,17 +1268,9 @@ export interface PairRequestMessage {
|
|
|
1124
1268
|
nonce: bigint;
|
|
1125
1269
|
communication_info?: CommunicationInfo;
|
|
1126
1270
|
parameter_range?: ParameterRange;
|
|
1127
|
-
/**
|
|
1128
|
-
* @deprecated Reading this field directly is incorrect: its meaning narrowed
|
|
1129
|
-
* to "one entry of a list, and possibly absent", so a peer advertising only
|
|
1130
|
-
* `supported_transports` looks unreachable to a reader that was correct
|
|
1131
|
-
* before 0.0.3. Call {@link advertisedEndpoints}, which resolves both
|
|
1132
|
-
* spellings. Removed at 0.0.5.
|
|
1133
|
-
*/
|
|
1134
|
-
transport_protocol?: TransportProtocol;
|
|
1135
1271
|
timestamp?: Timestamp;
|
|
1136
1272
|
/** Every transport endpoint the initiator can be reached on, in its own
|
|
1137
|
-
* preference order.
|
|
1273
|
+
* preference order. */
|
|
1138
1274
|
supported_transports: TransportProtocol[];
|
|
1139
1275
|
}
|
|
1140
1276
|
|
|
@@ -1156,21 +1292,12 @@ export interface PairResponseMessage {
|
|
|
1156
1292
|
|
|
1157
1293
|
export interface PrePairRequestMessage {
|
|
1158
1294
|
nonce: bigint;
|
|
1159
|
-
/**
|
|
1160
|
-
* @deprecated Reading this field directly is incorrect: its meaning narrowed
|
|
1161
|
-
* to "one entry of a list, and possibly absent", so a peer advertising only
|
|
1162
|
-
* `supported_transports` looks unreachable to a reader that was correct
|
|
1163
|
-
* before 0.0.3. Call {@link advertisedEndpoints}, which resolves both
|
|
1164
|
-
* spellings. Removed at 0.0.5.
|
|
1165
|
-
*/
|
|
1166
|
-
transport_protocol?: TransportProtocol;
|
|
1167
1295
|
timestamp?: Timestamp;
|
|
1168
1296
|
/**
|
|
1169
1297
|
* Every endpoint the sender can be reached on for the PrePair reply, in
|
|
1170
|
-
* its own preference order.
|
|
1171
|
-
* must be present.
|
|
1298
|
+
* its own preference order.
|
|
1172
1299
|
*/
|
|
1173
|
-
supported_transports
|
|
1300
|
+
supported_transports: TransportProtocol[];
|
|
1174
1301
|
}
|
|
1175
1302
|
|
|
1176
1303
|
export interface PrePairResponseMessage {
|
|
@@ -1356,6 +1483,15 @@ export interface ProducePrePairResult {
|
|
|
1356
1483
|
envelope: Uint8Array;
|
|
1357
1484
|
}
|
|
1358
1485
|
|
|
1486
|
+
export interface ProducePrePairNoKeysResult {
|
|
1487
|
+
|
|
1488
|
+
envelope: Uint8Array;
|
|
1489
|
+
|
|
1490
|
+
/** Secret key material generated for this pairing. The caller MUST persist
|
|
1491
|
+
* it: the `PairRequest` that follows is encrypted to it. */
|
|
1492
|
+
secret_key_material: Uint8Array;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1359
1495
|
export interface PrePairRequestExtractResult {
|
|
1360
1496
|
|
|
1361
1497
|
request: PrePairRequestMessage;
|