@derec-alliance/react-native 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/lib/types.d.ts CHANGED
@@ -2,11 +2,12 @@ export interface SecretStore {
2
2
  load(secretId: string, channelId: string, kind: 0 | 1 | 2): Promise<Uint8Array | null | undefined>;
3
3
  /**
4
4
  * Load secrets of the same `kind` for several channels in one call,
5
- * scoped to `secretId`. Must return an array with one entry per input
6
- * id, in the same order, using `null` (or `undefined`) for channels
7
- * with no stored secret of `kind`.
5
+ * scoped to `secretId`. Must return an array with exactly one entry per
6
+ * input id, in the same order, using `null` (or `undefined`) for channels
7
+ * with no stored secret of `kind`. Whether a missing entry is an error is
8
+ * decided by the library.
8
9
  */
9
- loadMany(secretId: string, channelIds: string[], kind: 0 | 1 | 2, missingPolicy: "skip" | "fail"): Promise<Array<Uint8Array | null | undefined>>;
10
+ loadMany(secretId: string, channelIds: string[], kind: 0 | 1 | 2): Promise<Array<Uint8Array | null | undefined>>;
10
11
  save(secretId: string, channelId: string, kind: 0 | 1 | 2, value: Uint8Array): Promise<void>;
11
12
  remove(secretId: string, channelId: string, kind: 0 | 1 | 2): Promise<void>;
12
13
  }
@@ -78,19 +79,11 @@ export declare function channelFilterMatches(filter: HelperFilter | ReplicaFilte
78
79
  /**
79
80
  * The endpoints a peer-supplied message advertises, in the peer's own order.
80
81
  *
81
- * Yields `supported_transports` when it is non-empty, and otherwise the
82
- * singular `transport_protocol` — which is how every implementation predating
83
- * the offer list advertises, and the reason this is a function rather than a
84
- * field read. Reading `transport_protocol` directly is a bug: its meaning
85
- * narrowed to "one entry of a list, and possibly absent", so a peer that has
86
- * moved past it looks unreachable to a reader that was correct before 0.0.3.
87
- *
88
82
  * Reports what was advertised, not what is acceptable — nothing here is
89
83
  * validated, and the protocol still applies its own transport policy to
90
84
  * whatever it records.
91
85
  */
92
86
  export declare function advertisedEndpoints(message: {
93
- transport_protocol?: TransportProtocol;
94
87
  supported_transports?: TransportProtocol[];
95
88
  } | null | undefined): TransportProtocol[];
96
89
  /**
@@ -172,7 +165,7 @@ export interface ChannelStore {
172
165
  * Order explicitly to make succession predictable.
173
166
  */
174
167
  listReplicas(secretId: string, filter: ReplicaFilter): Promise<Uint8Array | null | undefined>;
175
- linkChannel(secretId: string, channelId: string, linkedChannelId: string): Promise<void>;
168
+ linkChannel(secretId: string, a: string, b: string): Promise<void>;
176
169
  linkedChannels(secretId: string, channelId: string): Promise<string[]>;
177
170
  }
178
171
  export interface Share {
@@ -198,6 +191,35 @@ export interface ShareStore {
198
191
  save(secretId: string, channelId: string, share: Share): Promise<void>;
199
192
  latestVersion(secretId: string): Promise<number | null>;
200
193
  removeChannel(secretId: string, channelId: string): Promise<void>;
194
+ /**
195
+ * Drop the shares stored under `(secretId, channelId)` at each of
196
+ * `versions`. Idempotent: a version that is not stored is skipped, and
197
+ * an empty array is a no-op.
198
+ *
199
+ * A helper calls this to apply `StoreShareRequestMessage.keepList`, the
200
+ * complete set of versions the owner wants retained: every stored
201
+ * version outside it is removed once the incoming share is persisted.
202
+ * Shares under other channels or partitions must be left untouched.
203
+ */
204
+ removeVersions(secretId: string, channelId: string, versions: number[]): Promise<void>;
205
+ /**
206
+ * Owner only: the versions every helper keeps after the owner distributes
207
+ * `version`. Asked once per sharing round, before anything is sent,
208
+ * including the rounds the library starts itself; the answer becomes
209
+ * `keepList` for every helper.
210
+ *
211
+ * Return `null` or `undefined` to send no `keepList` (it goes out empty):
212
+ * helpers then keep every version they hold. An app that wants to cap how
213
+ * many versions helpers retain returns that cap here. A returned list is
214
+ * used as is, plus `version`, which the library always adds. Helpers
215
+ * delete every version that is not listed, so list every version that
216
+ * could still become the latest: those that committed (for example, whose
217
+ * `SharingComplete` reported `threshold_met`) and those whose round is
218
+ * still open. Leave out only versions whose round failed or that the user
219
+ * rolled back; a list that leaves out too much can make the secret
220
+ * unrecoverable.
221
+ */
222
+ keepList(secretId: string, version: number): Promise<number[] | null | undefined>;
201
223
  }
202
224
  export interface UserSecretEntry {
203
225
  id: Uint8Array;
@@ -208,6 +230,10 @@ export interface UserSecrets {
208
230
  version: number;
209
231
  secrets: UserSecretEntry[];
210
232
  description?: string;
233
+ /** Decimal `replica_id` of the member that published `version`. Absent
234
+ * when none is recorded. Store and return it unchanged: replica members
235
+ * compare it to detect a conflicting copy of the same version. */
236
+ author_replica_id?: string;
211
237
  }
212
238
  /**
213
239
  * Persistence for the user-facing secret contents, keyed by `secretId`.
@@ -245,6 +271,16 @@ export interface StateStore {
245
271
  remove(secretId: string, keyJson: Uint8Array): Promise<boolean>;
246
272
  loadAll(secretId: string, kind: 0 | 1 | 2 | 3 | 4): Promise<Uint8Array[]>;
247
273
  }
274
+ /** A transport protocol, by name. */
275
+ export type TransportProtocolName = "https" | "grpc";
276
+ /**
277
+ * One endpoint a node serves or a peer advertised, as every app-facing call
278
+ * and event carries it.
279
+ */
280
+ export interface Endpoint {
281
+ uri: string;
282
+ protocol: TransportProtocolName;
283
+ }
248
284
  /**
249
285
  * Outbound message delivery.
250
286
  *
@@ -289,10 +325,7 @@ export interface Transport {
289
325
  * provide — if that is genuinely wanted, say so with
290
326
  * {@link singleEndpointTransport} rather than by indexing.
291
327
  */
292
- send(endpoints: ReadonlyArray<{
293
- protocol: string;
294
- uri: string;
295
- }>, message: Uint8Array): Promise<void>;
328
+ send(endpoints: ReadonlyArray<Endpoint>, message: Uint8Array): Promise<void>;
296
329
  }
297
330
  /**
298
331
  * Delivers one message to one endpoint.
@@ -308,10 +341,22 @@ export interface Transport {
308
341
  * which is the safe reading. Trying an endpoint that would have refused costs
309
342
  * a round trip; skipping one that would have worked costs the delivery.
310
343
  */
311
- export type SendOne = (endpoint: {
312
- protocol: string;
313
- uri: string;
314
- }, message: Uint8Array) => Promise<void>;
344
+ export type SendOne = (endpoint: Endpoint, message: Uint8Array) => Promise<void>;
345
+ /**
346
+ * The DeRec protocol version this build speaks — the `protocolVersionMajor` /
347
+ * `protocolVersionMinor` it writes into every envelope it produces. Not the
348
+ * package version.
349
+ */
350
+ export declare function protocol_version(): {
351
+ major: number;
352
+ minor: number;
353
+ };
354
+ /**
355
+ * A fresh, random replica id — never `0`. Generate it once per device,
356
+ * persist it, and pass the same value to
357
+ * `DeRecProtocolBuilder.withReplicaId` on every init.
358
+ */
359
+ export declare function generate_replica_id(): bigint;
315
360
  /**
316
361
  * Builds a {@link Transport} that tries each endpoint in the order the peer
317
362
  * offered it and stops at the first success.
@@ -353,7 +398,7 @@ export declare enum SenderKind {
353
398
  * the scanner must fetch the actual keys over the wire via the `PrePair`
354
399
  * round-trip and verify them against the commitment before pairing.
355
400
  * - `NoKeys`: no key material and no commitment. The contact carries only
356
- * `channel_id`, `nonce`, and `transport_protocol` — small enough to be
401
+ * `channel_id`, `nonce`, and `supported_transports` — small enough to be
357
402
  * hand-typed or dictated. Keys are generated on the fly by the contact
358
403
  * creator when the `PrePairRequest` arrives; the scanner accepts them
359
404
  * without cryptographic verification. Trust rests entirely on the OOB
@@ -393,19 +438,31 @@ export declare enum FlowKind {
393
438
  * string so ids above 2^53 survive JS number handling. */
394
439
  UnpairReplica = 8
395
440
  }
441
+ /** Result status carried in every protocol response (`result.proto`). Passed
442
+ * to `reject()` to say why an inbound request was refused. */
443
+ export declare enum StatusEnum {
444
+ Ok = 0,
445
+ Partial = 1,
446
+ Fail = 2,
447
+ SizeLimitExceeded = 3,
448
+ TooFrequent = 4,
449
+ UnknownSecretId = 5,
450
+ UnknownShareVersion = 6,
451
+ DecryptionFailed = 7,
452
+ VerificationFailed = 8,
453
+ FormatError = 9,
454
+ Rejected = 10,
455
+ IncompatibleParameterRange = 11,
456
+ UnsupportedTransportProtocol = 12,
457
+ VersionConflict = 13,
458
+ ReplicaIdConflict = 14,
459
+ RequestToClose = 99
460
+ }
396
461
  export type UnpairAck = "required" | "not_required";
397
462
  export interface ContactMessage {
398
463
  channel_id: bigint;
399
464
  /** `ContactMode` numeric value (0 = INLINE_KEYS, 1 = HASHED_KEYS, 2 = NO_KEYS). */
400
465
  contact_mode: number;
401
- /**
402
- * @deprecated Reading this field directly is incorrect: its meaning narrowed
403
- * to "one entry of a list, and possibly absent", so a peer advertising only
404
- * `supported_transports` looks unreachable to a reader that was correct
405
- * before 0.0.3. Call {@link advertisedEndpoints}, which resolves both
406
- * spellings. Removed at 0.0.5.
407
- */
408
- transport_protocol?: TransportProtocol;
409
466
  nonce: bigint;
410
467
  /** Present only when `contact_mode === ContactMode.InlineKeys`. */
411
468
  mlkem_encapsulation_key?: Uint8Array;
@@ -415,8 +472,7 @@ export interface ContactMessage {
415
472
  contact_binding_hash?: Uint8Array;
416
473
  timestamp?: Timestamp;
417
474
  /** Every transport endpoint the creator of this contact can be reached
418
- * on, in its own preference order. Empty means "only
419
- * `transport_protocol` is offered". */
475
+ * on, in its own preference order. */
420
476
  supported_transports: TransportProtocol[];
421
477
  }
422
478
  export interface UserSecret {
@@ -455,23 +511,11 @@ export interface UpdateChannelInfoParams {
455
511
  /** New communication-info map. `null`/absent leaves the peer's stored
456
512
  * map untouched; pass an empty object to clear it. */
457
513
  communication_info?: Record<string, string>;
458
- /**
459
- * New transport endpoint. Absent leaves it untouched.
460
- *
461
- * @deprecated Use `own_transports`, which carries every endpoint this node
462
- * now serves; its first entry also fills this field for peers predating the
463
- * list. Removed at 0.0.5.
464
- */
465
- transport_protocol?: {
466
- uri: string;
467
- protocol: number;
468
- };
469
514
  /**
470
515
  * Every endpoint this node now serves, in its own preference order.
471
- * Omitted leaves the target(s)' stored set untouched. Takes precedence
472
- * over `transport_protocol`, whose first entry it also fills.
516
+ * Omitted leaves the target(s)' stored set untouched.
473
517
  */
474
- own_transports?: TransportProtocol[];
518
+ own_transports?: Endpoint[];
475
519
  }
476
520
  /**
477
521
  * How long the protocol waits on each thing that can keep it waiting. Every
@@ -504,6 +548,15 @@ export interface Timeouts {
504
548
  /** `ReplicaDiscovery` takes no parameters: the group and this device's own version
505
549
  * are both read from the stores. The argument may be omitted entirely. */
506
550
  export type ReplicaDiscoveryParams = Record<string, never>;
551
+ /** Any member may remove any member, the source included: a lost or stolen
552
+ * source must be removable by the devices that remain, and the library
553
+ * checks no role. Ask the user before starting this flow, above all when it
554
+ * names the source. Removing the source promotes the first remaining member
555
+ * in the order the channel store's `listReplicas` returns. The removed
556
+ * member is not asked and gets no event when told to leave: when a roster
557
+ * excluding it arrives it drops its whole `secret_id` partition and emits
558
+ * `SelfRemovedFromGroup`. The secret survives on the remaining members and
559
+ * the helpers. */
507
560
  export interface UnpairReplicaParams {
508
561
  /** The member to remove, as a **decimal** `u64` string — the same form
509
562
  * `ReplicaPaired.peer_replica_id` hands back. A value naming no current
@@ -524,11 +577,30 @@ export type DeRecEvent = {
524
577
  channel_id: string;
525
578
  action: Uint8Array;
526
579
  action_kind: PendingActionKind;
580
+ /** Correlation token of the inbound request, decimal-encoded. */
581
+ trace_id: string;
582
+ /** Pairing only. */
527
583
  peer_communication_info?: Record<string, string>;
584
+ /** `sender_kind` of the inbound pair request (Pairing only). */
528
585
  sender_kind?: SenderKind;
586
+ /** Share version (StoreShare / VerifyShare / GetShare). */
529
587
  version?: number;
588
+ /** Description of the secret version (StoreShare only). */
530
589
  share_description?: string;
590
+ /** Secret identifier, decimal-encoded (StoreShare / VerifyShare /
591
+ * GetShare). On GetShare, with `version`, names the requested share. */
531
592
  share_secret_id?: string;
593
+ /** Length in bytes of the share the helper would store (StoreShare
594
+ * only) — what a size or quota decision is made on. */
595
+ share_size?: number;
596
+ /** The peer's memo (Unpair only). */
597
+ unpair_memo?: string;
598
+ /** Communication info the peer replaces its stored map with
599
+ * (UpdateChannelInfo only). Absent: unchanged. Empty: cleared. */
600
+ updated_communication_info?: Record<string, string>;
601
+ /** Endpoints the peer is moving to (UpdateChannelInfo only). Absent:
602
+ * unchanged. */
603
+ updated_transports?: Endpoint[];
532
604
  } | {
533
605
  type: "ShareStored";
534
606
  channel_id: string;
@@ -541,7 +613,7 @@ export type DeRecEvent = {
541
613
  type: "ShareRejected";
542
614
  channel_id: string;
543
615
  version: number;
544
- status: number;
616
+ status: StatusEnum;
545
617
  memo: string;
546
618
  }
547
619
  /** A publishing round finished — every targeted helper confirmed,
@@ -567,14 +639,17 @@ export type DeRecEvent = {
567
639
  }
568
640
  /** A group member refused a secret sync. Keyed by `replica_id`, not
569
641
  * `channel_id`: every member answers on the one group channel. A
570
- * `VERSION_CONFLICT` status means the round must be resolved and
571
- * republished at a new version. */
642
+ * `VERSION_CONFLICT` status means another member holds a different copy
643
+ * of this version: do not publish from this device again until the
644
+ * conflict is resolved. Run `start(FlowKind.ReplicaDiscovery)` to receive
645
+ * the group's copy as `ReplicaVersionConflict`, merge, and publish the
646
+ * result once with `start(FlowKind.ProtectSecret)`. */
572
647
  | {
573
648
  type: "ReplicaSyncRejected";
574
649
  replica_id: string;
575
650
  secret_id: string;
576
651
  version: number;
577
- status: number;
652
+ status: StatusEnum;
578
653
  memo: string;
579
654
  }
580
655
  /** A secret sync could not be delivered to a member at all — distinct from
@@ -602,7 +677,8 @@ export type DeRecEvent = {
602
677
  /** This device left the group and dropped its whole `secret_id` partition —
603
678
  * group channel, helper channels, shares, secrets and the snapshot. Fires
604
679
  * only once it was told to leave *and* has since seen a roster excluding
605
- * it; absence alone never destroys a copy of the secret. */
680
+ * it; absence alone never destroys a copy of the secret. The teardown is
681
+ * automatic: this device is not asked first and gets no earlier event. */
606
682
  | {
607
683
  type: "SelfRemovedFromGroup";
608
684
  version: number;
@@ -628,6 +704,16 @@ export type DeRecEvent = {
628
704
  type: "ShareVerified";
629
705
  channel_id: string;
630
706
  version: number;
707
+ }
708
+ /** A helper refused a verification challenge: its response carried a
709
+ * non-OK `status` instead of a proof. The challenge is spent; a new
710
+ * `VerifyShares` round challenges the helper again. */
711
+ | {
712
+ type: "ShareVerifyRejected";
713
+ channel_id: string;
714
+ version: number;
715
+ status: StatusEnum;
716
+ memo: string;
631
717
  } | {
632
718
  type: "SecretsDiscovered";
633
719
  channel_id: string;
@@ -648,6 +734,33 @@ export type DeRecEvent = {
648
734
  shares_received: number;
649
735
  error: string;
650
736
  }
737
+ /** A helper refused a recovery share request: its response carried a
738
+ * non-OK `status` (e.g. `UNKNOWN_SHARE_VERSION`) instead of a share. The
739
+ * refusal is not collected — it does not count towards `shares_received`
740
+ * and the recovery stays open for the other helpers' shares — but it does
741
+ * answer that helper's `RecoverSecretStarted`. */
742
+ | {
743
+ type: "RecoveryShareRefused";
744
+ channel_id: string;
745
+ version: number;
746
+ status: StatusEnum;
747
+ memo: string;
748
+ }
749
+ /** A helper answered with a share that cannot be part of the secret;
750
+ * `reason` says how it failed. `Malformed` and `InvalidProof` are judged
751
+ * on arrival; `Inconsistent` (valid on its own but disagreeing with the
752
+ * shares the secret was rebuilt from) is reported alongside
753
+ * `SecretRecovered`, once per helper. The share is set aside — it does
754
+ * not count towards `shares_received` and never blocks the recovery. An
755
+ * honest helper never sends one, so the app may treat it as a sign of a
756
+ * damaged or compromised helper, e.g. offer to unpair it. It also
757
+ * answers that helper's `RecoverSecretStarted`. */
758
+ | {
759
+ type: "RecoveryShareCorrupted";
760
+ channel_id: string;
761
+ version: number;
762
+ reason: CorruptionReason;
763
+ }
651
764
  /** Recovery completed — the typed `Secret` snapshot the owner
652
765
  * originally protected. Mirrors `ReplicaSecretReceived.secret`:
653
766
  * `secrets` is the user-facing `Vec<UserSecret>` the application
@@ -660,12 +773,9 @@ export type DeRecEvent = {
660
773
  helpers: Array<{
661
774
  channel_id: string;
662
775
  /** Every endpoint this peer advertised, in the order it offered them. */
663
- transports: Array<{
664
- uri: string;
665
- protocol: number;
666
- }>;
776
+ transports: Endpoint[];
667
777
  shared_key: Uint8Array;
668
- communication_info: Record<string, string>;
778
+ communication_info?: Record<string, string>;
669
779
  }>;
670
780
  secrets: Array<{
671
781
  id: Uint8Array;
@@ -685,12 +795,9 @@ export type DeRecEvent = {
685
795
  members: Array<{
686
796
  replica_id: string;
687
797
  /** Every endpoint this peer advertised, in the order it offered them. */
688
- transports: Array<{
689
- uri: string;
690
- protocol: number;
691
- }>;
798
+ transports: Endpoint[];
692
799
  role: "Source" | "Destination";
693
- communication_info: Record<string, string>;
800
+ communication_info?: Record<string, string>;
694
801
  }>;
695
802
  shared_key: Uint8Array;
696
803
  };
@@ -701,7 +808,7 @@ export type DeRecEvent = {
701
808
  } | {
702
809
  type: "UnpairRejected";
703
810
  channel_id: string;
704
- status: number;
811
+ status: StatusEnum;
705
812
  memo: string;
706
813
  }
707
814
  /** Contact creator answered the scanner's `PrePairRequest` with a
@@ -710,7 +817,7 @@ export type DeRecEvent = {
710
817
  | {
711
818
  type: "PrePairRejected";
712
819
  channel_id: string;
713
- status: number;
820
+ status: StatusEnum;
714
821
  memo: string;
715
822
  }
716
823
  /** Fires alongside `PairingCompleted` on replica-mode pair handshakes.
@@ -729,25 +836,28 @@ export type DeRecEvent = {
729
836
  /** A `ReplicaSource` peer pushed a secret sync on a
730
837
  * `ReplicaDestination` channel. The library decoded the
731
838
  * `ReplicaSecretPayload`; the app installs `secret.secrets` and
732
- * optionally uses `shares` for recovery. `from_replica_id` and the
733
- * `replica_id` fields inside `secret` are `u64` as **decimal**
734
- * strings. */
839
+ * optionally uses `shares` for recovery. `from_replica_id`,
840
+ * `author_replica_id` and the `replica_id` fields inside `secret` are
841
+ * `u64` as **decimal** strings.
842
+ *
843
+ * `from_replica_id` is the member this copy came from: the publisher on
844
+ * a push, the serving member on a catch-up. `author_replica_id` is the
845
+ * member that published `version`, or `null` when the serving member's
846
+ * snapshot records none. */
735
847
  | {
736
848
  type: "ReplicaSecretReceived";
737
849
  channel_id: string;
738
850
  from_replica_id: string;
851
+ author_replica_id: string | null;
739
852
  secret_id: string;
740
853
  version: number;
741
854
  secret: {
742
855
  helpers: Array<{
743
856
  channel_id: string;
744
857
  /** Every endpoint this peer advertised, in the order it offered them. */
745
- transports: Array<{
746
- uri: string;
747
- protocol: number;
748
- }>;
858
+ transports: Endpoint[];
749
859
  shared_key: Uint8Array;
750
- communication_info: Record<string, string>;
860
+ communication_info?: Record<string, string>;
751
861
  }>;
752
862
  secrets: Array<{
753
863
  id: Uint8Array;
@@ -765,12 +875,9 @@ export type DeRecEvent = {
765
875
  members: Array<{
766
876
  replica_id: string;
767
877
  /** Every endpoint this peer advertised, in the order it offered them. */
768
- transports: Array<{
769
- uri: string;
770
- protocol: number;
771
- }>;
878
+ transports: Endpoint[];
772
879
  role: "Source" | "Destination";
773
- communication_info: Record<string, string>;
880
+ communication_info?: Record<string, string>;
774
881
  }>;
775
882
  shared_key: Uint8Array;
776
883
  };
@@ -793,18 +900,16 @@ export type DeRecEvent = {
793
900
  type: "ReplicaSecretInstalled";
794
901
  channel_id: string;
795
902
  from_replica_id: string;
903
+ author_replica_id: string | null;
796
904
  secret_id: string;
797
905
  version: number;
798
906
  secret: {
799
907
  helpers: Array<{
800
908
  channel_id: string;
801
909
  /** Every endpoint this peer advertised, in the order it offered them. */
802
- transports: Array<{
803
- uri: string;
804
- protocol: number;
805
- }>;
910
+ transports: Endpoint[];
806
911
  shared_key: Uint8Array;
807
- communication_info: Record<string, string>;
912
+ communication_info?: Record<string, string>;
808
913
  }>;
809
914
  secrets: Array<{
810
915
  id: Uint8Array;
@@ -822,12 +927,9 @@ export type DeRecEvent = {
822
927
  members: Array<{
823
928
  replica_id: string;
824
929
  /** Every endpoint this peer advertised, in the order it offered them. */
825
- transports: Array<{
826
- uri: string;
827
- protocol: number;
828
- }>;
930
+ transports: Endpoint[];
829
931
  role: "Source" | "Destination";
830
- communication_info: Record<string, string>;
932
+ communication_info?: Record<string, string>;
831
933
  }>;
832
934
  shared_key: Uint8Array;
833
935
  };
@@ -837,6 +939,59 @@ export type DeRecEvent = {
837
939
  committed_share: Uint8Array;
838
940
  }>;
839
941
  }
942
+ /** A member offered a different copy of the version this device holds.
943
+ * Nothing was written: this device keeps its own copy and refuses the
944
+ * incoming one with `VERSION_CONFLICT`, so the publisher sees
945
+ * `ReplicaSyncRejected`. Both copies are complete states — the held one
946
+ * is in the local stores, the incoming one is `secret`. Resolve by
947
+ * publishing the chosen state with `start(FlowKind.ProtectSecret)`; the
948
+ * next version supersedes both on every member and helper. Until then,
949
+ * do not publish from this device: any further `ProtectSecret` is a
950
+ * higher version that every other member applies over its own copy,
951
+ * losing the change it never merged.
952
+ *
953
+ * `held_author_replica_id` / `incoming_author_replica_id` are the
954
+ * decimal `replica_id` of each copy's publisher, or `null` when that
955
+ * copy records none. */
956
+ | {
957
+ type: "ReplicaVersionConflict";
958
+ channel_id: string;
959
+ from_replica_id: string;
960
+ secret_id: string;
961
+ version: number;
962
+ held_author_replica_id: string | null;
963
+ incoming_author_replica_id: string | null;
964
+ secret: {
965
+ helpers: Array<{
966
+ channel_id: string;
967
+ /** Every endpoint this peer advertised, in the order it offered them. */
968
+ transports: Endpoint[];
969
+ shared_key: Uint8Array;
970
+ communication_info?: Record<string, string>;
971
+ }>;
972
+ secrets: Array<{
973
+ id: Uint8Array;
974
+ name: string;
975
+ data: Uint8Array;
976
+ }>;
977
+ /** The same shape as `SecretRecovered.secret.replicas`. */
978
+ replicas?: {
979
+ /** The one channel every member is addressed on. */
980
+ channel_id: string;
981
+ /** Every member of the group, including the writer. Exactly one
982
+ * carries `role: "Source"` — that member is where the secret
983
+ * originated, which is why no separate owner field is needed. */
984
+ members: Array<{
985
+ replica_id: string;
986
+ /** Every endpoint this peer advertised, in the order it offered them. */
987
+ transports: Endpoint[];
988
+ role: "Source" | "Destination";
989
+ communication_info?: Record<string, string>;
990
+ }>;
991
+ shared_key: Uint8Array;
992
+ };
993
+ };
994
+ }
840
995
  /** Peer's ack of a secret sync we sent. `status` is the `StatusEnum`
841
996
  * integer (0 = Ok), `memo` is the peer's explanation. */
842
997
  | {
@@ -845,7 +1000,7 @@ export type DeRecEvent = {
845
1000
  from_replica_id: string;
846
1001
  secret_id: string;
847
1002
  version: number;
848
- status: number;
1003
+ status: StatusEnum;
849
1004
  memo: string;
850
1005
  }
851
1006
  /** A peer announced an updated `communication_info` map and/or
@@ -862,7 +1017,7 @@ export type DeRecEvent = {
862
1017
  | {
863
1018
  type: "ChannelInfoUpdateRejected";
864
1019
  channel_id: string;
865
- status: number;
1020
+ status: StatusEnum;
866
1021
  memo: string;
867
1022
  }
868
1023
  /** Emitted by `process()` in place of `ActionRequired` when the
@@ -879,6 +1034,38 @@ export type DeRecEvent = {
879
1034
  } | {
880
1035
  type: "NoOp";
881
1036
  }
1037
+ /** An inbound message was dropped untouched: no store was written and
1038
+ * nothing was sent back. `reason` says why.
1039
+ *
1040
+ * `"PendingVerification"` means the peer sent something before this
1041
+ * device confirmed the channel's fingerprint — typically a replica source
1042
+ * pushing its first copy while this destination still shows the code.
1043
+ * Confirming does not replay it: after `verifyFingerprint` succeeds, a
1044
+ * replica destination calls `start(FlowKind.ReplicaDiscovery)` to pull
1045
+ * the copy itself. `"Expired"` means the message was older than the
1046
+ * inbound timeout. `trace_id` matches the peer's `*Started` event for
1047
+ * the same round (`"0"` when the sender set none). */
1048
+ | {
1049
+ type: "MessageIgnored";
1050
+ channel_id: string;
1051
+ reason: IgnoreReason;
1052
+ trace_id: string;
1053
+ }
1054
+ /** Returned by `restore`: a roster entry got no channel, so this device
1055
+ * cannot reach that peer. Every other entry and the user-secret snapshot
1056
+ * were restored; `reason` says why this one was not. `"NoTransports"`
1057
+ * means the recovered roster names no endpoint for it.
1058
+ *
1059
+ * For a helper, `channel_id` is its channel and `replica_id` is absent.
1060
+ * For a replica group member, `channel_id` is the group's channel and
1061
+ * `replica_id` names the member. The peer itself is untouched — a helper
1062
+ * still holds its share — and pairing with it again makes it reachable. */
1063
+ | {
1064
+ type: "PeerNotRestored";
1065
+ channel_id: string;
1066
+ replica_id?: string;
1067
+ reason: NotRestoredReason;
1068
+ }
882
1069
  /** A pairing handshake was dispatched successfully. `kind` is the
883
1070
  * local party's role — same value the subsequent `PairingCompleted`
884
1071
  * will carry. Emitted by `start(Pairing)`. */
@@ -989,8 +1176,8 @@ export type DeRecEvent = {
989
1176
  * inbound shares. The protocol enforces no size, quota or rate limit
990
1177
  * of its own, and `maxShareSize` is checked for range overlap at
991
1178
  * pairing time only, never against an actual share. While this is
992
- * `false`, `ActionRequired` carries the decoded request, so the
993
- * application can inspect the share and call `reject()` with
1179
+ * `false`, `ActionRequired` carries `share_size`, so the application
1180
+ * can compare it to its quota and call `reject()` with
994
1181
  * `StatusEnum.SizeLimitExceeded`. Setting it `true` removes that
995
1182
  * opportunity entirely: every share from every paired Owner is stored
996
1183
  * unconditionally, at whatever size it arrives. Keep off in any
@@ -1066,6 +1253,19 @@ export interface CommunicationInfoKeyValue {
1066
1253
  export interface CommunicationInfo {
1067
1254
  communication_info_entries: CommunicationInfoKeyValue[];
1068
1255
  }
1256
+ /** Why a `MessageIgnored` event dropped a message. Matches the Rust
1257
+ * `IgnoreReason` discriminants one-for-one. */
1258
+ export type IgnoreReason = "PendingVerification" | "Expired";
1259
+ /** Why a `PeerNotRestored` event left a roster entry without a channel.
1260
+ * Matches the Rust `NotRestoredReason` discriminants one-for-one. */
1261
+ export type NotRestoredReason = "NoTransports";
1262
+ /** Why a `RecoveryShareCorrupted` event set a helper's share aside.
1263
+ * Matches the Rust `CorruptionReason` discriminants one-for-one:
1264
+ * `Malformed` — no decodable share for the requested secret and version;
1265
+ * `InvalidProof` — the share fails its own Merkle proof;
1266
+ * `Inconsistent` — valid on its own, but its commitment root or ciphertext
1267
+ * disagrees with the shares the secret was rebuilt from. */
1268
+ export type CorruptionReason = "Malformed" | "InvalidProof" | "Inconsistent";
1069
1269
  /**
1070
1270
  * The label vocabulary for `ActionRequired.action_kind` and
1071
1271
  * `AutoAccepted.action_kind` — one value per pending-action kind the
@@ -1092,17 +1292,9 @@ export interface PairRequestMessage {
1092
1292
  nonce: bigint;
1093
1293
  communication_info?: CommunicationInfo;
1094
1294
  parameter_range?: ParameterRange;
1095
- /**
1096
- * @deprecated Reading this field directly is incorrect: its meaning narrowed
1097
- * to "one entry of a list, and possibly absent", so a peer advertising only
1098
- * `supported_transports` looks unreachable to a reader that was correct
1099
- * before 0.0.3. Call {@link advertisedEndpoints}, which resolves both
1100
- * spellings. Removed at 0.0.5.
1101
- */
1102
- transport_protocol?: TransportProtocol;
1103
1295
  timestamp?: Timestamp;
1104
1296
  /** Every transport endpoint the initiator can be reached on, in its own
1105
- * preference order. Empty means "only `transport_protocol` is offered". */
1297
+ * preference order. */
1106
1298
  supported_transports: TransportProtocol[];
1107
1299
  }
1108
1300
  export interface PairResponseMessage {
@@ -1122,21 +1314,12 @@ export interface PairResponseMessage {
1122
1314
  }
1123
1315
  export interface PrePairRequestMessage {
1124
1316
  nonce: bigint;
1125
- /**
1126
- * @deprecated Reading this field directly is incorrect: its meaning narrowed
1127
- * to "one entry of a list, and possibly absent", so a peer advertising only
1128
- * `supported_transports` looks unreachable to a reader that was correct
1129
- * before 0.0.3. Call {@link advertisedEndpoints}, which resolves both
1130
- * spellings. Removed at 0.0.5.
1131
- */
1132
- transport_protocol?: TransportProtocol;
1133
1317
  timestamp?: Timestamp;
1134
1318
  /**
1135
1319
  * Every endpoint the sender can be reached on for the PrePair reply, in
1136
- * its own preference order. At least one of this and `transport_protocol`
1137
- * must be present.
1320
+ * its own preference order.
1138
1321
  */
1139
- supported_transports?: TransportProtocol[];
1322
+ supported_transports: TransportProtocol[];
1140
1323
  }
1141
1324
  export interface PrePairResponseMessage {
1142
1325
  result?: DeRecResult;
@@ -1292,6 +1475,12 @@ export interface PairingProcessResult {
1292
1475
  export interface ProducePrePairResult {
1293
1476
  envelope: Uint8Array;
1294
1477
  }
1478
+ export interface ProducePrePairNoKeysResult {
1479
+ envelope: Uint8Array;
1480
+ /** Secret key material generated for this pairing. The caller MUST persist
1481
+ * it: the `PairRequest` that follows is encrypted to it. */
1482
+ secret_key_material: Uint8Array;
1483
+ }
1295
1484
  export interface PrePairRequestExtractResult {
1296
1485
  request: PrePairRequestMessage;
1297
1486
  }