@derec-alliance/react-native 0.0.5 → 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/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 {
@@ -208,6 +201,10 @@ export interface UserSecrets {
208
201
  version: number;
209
202
  secrets: UserSecretEntry[];
210
203
  description?: string;
204
+ /** Decimal `replica_id` of the member that published `version`. Absent
205
+ * when none is recorded. Store and return it unchanged: replica members
206
+ * compare it to detect a conflicting copy of the same version. */
207
+ author_replica_id?: string;
211
208
  }
212
209
  /**
213
210
  * Persistence for the user-facing secret contents, keyed by `secretId`.
@@ -245,6 +242,16 @@ export interface StateStore {
245
242
  remove(secretId: string, keyJson: Uint8Array): Promise<boolean>;
246
243
  loadAll(secretId: string, kind: 0 | 1 | 2 | 3 | 4): Promise<Uint8Array[]>;
247
244
  }
245
+ /** A transport protocol, by name. */
246
+ export type TransportProtocolName = "https" | "grpc";
247
+ /**
248
+ * One endpoint a node serves or a peer advertised, as every app-facing call
249
+ * and event carries it.
250
+ */
251
+ export interface Endpoint {
252
+ uri: string;
253
+ protocol: TransportProtocolName;
254
+ }
248
255
  /**
249
256
  * Outbound message delivery.
250
257
  *
@@ -289,10 +296,7 @@ export interface Transport {
289
296
  * provide — if that is genuinely wanted, say so with
290
297
  * {@link singleEndpointTransport} rather than by indexing.
291
298
  */
292
- send(endpoints: ReadonlyArray<{
293
- protocol: string;
294
- uri: string;
295
- }>, message: Uint8Array): Promise<void>;
299
+ send(endpoints: ReadonlyArray<Endpoint>, message: Uint8Array): Promise<void>;
296
300
  }
297
301
  /**
298
302
  * Delivers one message to one endpoint.
@@ -308,10 +312,22 @@ export interface Transport {
308
312
  * which is the safe reading. Trying an endpoint that would have refused costs
309
313
  * a round trip; skipping one that would have worked costs the delivery.
310
314
  */
311
- export type SendOne = (endpoint: {
312
- protocol: string;
313
- uri: string;
314
- }, message: Uint8Array) => Promise<void>;
315
+ export type SendOne = (endpoint: Endpoint, message: Uint8Array) => Promise<void>;
316
+ /**
317
+ * The DeRec protocol version this build speaks — the `protocolVersionMajor` /
318
+ * `protocolVersionMinor` it writes into every envelope it produces. Not the
319
+ * package version.
320
+ */
321
+ export declare function protocol_version(): {
322
+ major: number;
323
+ minor: number;
324
+ };
325
+ /**
326
+ * A fresh, random replica id — never `0`. Generate it once per device,
327
+ * persist it, and pass the same value to
328
+ * `DeRecProtocolBuilder.withReplicaId` on every init.
329
+ */
330
+ export declare function generate_replica_id(): bigint;
315
331
  /**
316
332
  * Builds a {@link Transport} that tries each endpoint in the order the peer
317
333
  * offered it and stops at the first success.
@@ -353,7 +369,7 @@ export declare enum SenderKind {
353
369
  * the scanner must fetch the actual keys over the wire via the `PrePair`
354
370
  * round-trip and verify them against the commitment before pairing.
355
371
  * - `NoKeys`: no key material and no commitment. The contact carries only
356
- * `channel_id`, `nonce`, and `transport_protocol` — small enough to be
372
+ * `channel_id`, `nonce`, and `supported_transports` — small enough to be
357
373
  * hand-typed or dictated. Keys are generated on the fly by the contact
358
374
  * creator when the `PrePairRequest` arrives; the scanner accepts them
359
375
  * without cryptographic verification. Trust rests entirely on the OOB
@@ -393,19 +409,31 @@ export declare enum FlowKind {
393
409
  * string so ids above 2^53 survive JS number handling. */
394
410
  UnpairReplica = 8
395
411
  }
412
+ /** Result status carried in every protocol response (`result.proto`). Passed
413
+ * to `reject()` to say why an inbound request was refused. */
414
+ export declare enum StatusEnum {
415
+ Ok = 0,
416
+ Partial = 1,
417
+ Fail = 2,
418
+ SizeLimitExceeded = 3,
419
+ TooFrequent = 4,
420
+ UnknownSecretId = 5,
421
+ UnknownShareVersion = 6,
422
+ DecryptionFailed = 7,
423
+ VerificationFailed = 8,
424
+ FormatError = 9,
425
+ Rejected = 10,
426
+ IncompatibleParameterRange = 11,
427
+ UnsupportedTransportProtocol = 12,
428
+ VersionConflict = 13,
429
+ ReplicaIdConflict = 14,
430
+ RequestToClose = 99
431
+ }
396
432
  export type UnpairAck = "required" | "not_required";
397
433
  export interface ContactMessage {
398
434
  channel_id: bigint;
399
435
  /** `ContactMode` numeric value (0 = INLINE_KEYS, 1 = HASHED_KEYS, 2 = NO_KEYS). */
400
436
  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
437
  nonce: bigint;
410
438
  /** Present only when `contact_mode === ContactMode.InlineKeys`. */
411
439
  mlkem_encapsulation_key?: Uint8Array;
@@ -415,8 +443,7 @@ export interface ContactMessage {
415
443
  contact_binding_hash?: Uint8Array;
416
444
  timestamp?: Timestamp;
417
445
  /** 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". */
446
+ * on, in its own preference order. */
420
447
  supported_transports: TransportProtocol[];
421
448
  }
422
449
  export interface UserSecret {
@@ -455,23 +482,11 @@ export interface UpdateChannelInfoParams {
455
482
  /** New communication-info map. `null`/absent leaves the peer's stored
456
483
  * map untouched; pass an empty object to clear it. */
457
484
  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
485
  /**
470
486
  * 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.
487
+ * Omitted leaves the target(s)' stored set untouched.
473
488
  */
474
- own_transports?: TransportProtocol[];
489
+ own_transports?: Endpoint[];
475
490
  }
476
491
  /**
477
492
  * How long the protocol waits on each thing that can keep it waiting. Every
@@ -524,11 +539,30 @@ export type DeRecEvent = {
524
539
  channel_id: string;
525
540
  action: Uint8Array;
526
541
  action_kind: PendingActionKind;
542
+ /** Correlation token of the inbound request, decimal-encoded. */
543
+ trace_id: string;
544
+ /** Pairing only. */
527
545
  peer_communication_info?: Record<string, string>;
546
+ /** `sender_kind` of the inbound pair request (Pairing only). */
528
547
  sender_kind?: SenderKind;
548
+ /** Share version (StoreShare / VerifyShare / GetShare). */
529
549
  version?: number;
550
+ /** Description of the secret version (StoreShare only). */
530
551
  share_description?: string;
552
+ /** Secret identifier, decimal-encoded (StoreShare / VerifyShare /
553
+ * GetShare). On GetShare, with `version`, names the requested share. */
531
554
  share_secret_id?: string;
555
+ /** Length in bytes of the share the helper would store (StoreShare
556
+ * only) — what a size or quota decision is made on. */
557
+ share_size?: number;
558
+ /** The peer's memo (Unpair only). */
559
+ unpair_memo?: string;
560
+ /** Communication info the peer replaces its stored map with
561
+ * (UpdateChannelInfo only). Absent: unchanged. Empty: cleared. */
562
+ updated_communication_info?: Record<string, string>;
563
+ /** Endpoints the peer is moving to (UpdateChannelInfo only). Absent:
564
+ * unchanged. */
565
+ updated_transports?: Endpoint[];
532
566
  } | {
533
567
  type: "ShareStored";
534
568
  channel_id: string;
@@ -541,7 +575,7 @@ export type DeRecEvent = {
541
575
  type: "ShareRejected";
542
576
  channel_id: string;
543
577
  version: number;
544
- status: number;
578
+ status: StatusEnum;
545
579
  memo: string;
546
580
  }
547
581
  /** A publishing round finished — every targeted helper confirmed,
@@ -574,7 +608,7 @@ export type DeRecEvent = {
574
608
  replica_id: string;
575
609
  secret_id: string;
576
610
  version: number;
577
- status: number;
611
+ status: StatusEnum;
578
612
  memo: string;
579
613
  }
580
614
  /** A secret sync could not be delivered to a member at all — distinct from
@@ -660,12 +694,9 @@ export type DeRecEvent = {
660
694
  helpers: Array<{
661
695
  channel_id: string;
662
696
  /** Every endpoint this peer advertised, in the order it offered them. */
663
- transports: Array<{
664
- uri: string;
665
- protocol: number;
666
- }>;
697
+ transports: Endpoint[];
667
698
  shared_key: Uint8Array;
668
- communication_info: Record<string, string>;
699
+ communication_info?: Record<string, string>;
669
700
  }>;
670
701
  secrets: Array<{
671
702
  id: Uint8Array;
@@ -685,12 +716,9 @@ export type DeRecEvent = {
685
716
  members: Array<{
686
717
  replica_id: string;
687
718
  /** Every endpoint this peer advertised, in the order it offered them. */
688
- transports: Array<{
689
- uri: string;
690
- protocol: number;
691
- }>;
719
+ transports: Endpoint[];
692
720
  role: "Source" | "Destination";
693
- communication_info: Record<string, string>;
721
+ communication_info?: Record<string, string>;
694
722
  }>;
695
723
  shared_key: Uint8Array;
696
724
  };
@@ -701,7 +729,7 @@ export type DeRecEvent = {
701
729
  } | {
702
730
  type: "UnpairRejected";
703
731
  channel_id: string;
704
- status: number;
732
+ status: StatusEnum;
705
733
  memo: string;
706
734
  }
707
735
  /** Contact creator answered the scanner's `PrePairRequest` with a
@@ -710,7 +738,7 @@ export type DeRecEvent = {
710
738
  | {
711
739
  type: "PrePairRejected";
712
740
  channel_id: string;
713
- status: number;
741
+ status: StatusEnum;
714
742
  memo: string;
715
743
  }
716
744
  /** Fires alongside `PairingCompleted` on replica-mode pair handshakes.
@@ -729,25 +757,28 @@ export type DeRecEvent = {
729
757
  /** A `ReplicaSource` peer pushed a secret sync on a
730
758
  * `ReplicaDestination` channel. The library decoded the
731
759
  * `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. */
760
+ * optionally uses `shares` for recovery. `from_replica_id`,
761
+ * `author_replica_id` and the `replica_id` fields inside `secret` are
762
+ * `u64` as **decimal** strings.
763
+ *
764
+ * `from_replica_id` is the member this copy came from: the publisher on
765
+ * a push, the serving member on a catch-up. `author_replica_id` is the
766
+ * member that published `version`, or `null` when the serving member's
767
+ * snapshot records none. */
735
768
  | {
736
769
  type: "ReplicaSecretReceived";
737
770
  channel_id: string;
738
771
  from_replica_id: string;
772
+ author_replica_id: string | null;
739
773
  secret_id: string;
740
774
  version: number;
741
775
  secret: {
742
776
  helpers: Array<{
743
777
  channel_id: string;
744
778
  /** Every endpoint this peer advertised, in the order it offered them. */
745
- transports: Array<{
746
- uri: string;
747
- protocol: number;
748
- }>;
779
+ transports: Endpoint[];
749
780
  shared_key: Uint8Array;
750
- communication_info: Record<string, string>;
781
+ communication_info?: Record<string, string>;
751
782
  }>;
752
783
  secrets: Array<{
753
784
  id: Uint8Array;
@@ -765,12 +796,9 @@ export type DeRecEvent = {
765
796
  members: Array<{
766
797
  replica_id: string;
767
798
  /** Every endpoint this peer advertised, in the order it offered them. */
768
- transports: Array<{
769
- uri: string;
770
- protocol: number;
771
- }>;
799
+ transports: Endpoint[];
772
800
  role: "Source" | "Destination";
773
- communication_info: Record<string, string>;
801
+ communication_info?: Record<string, string>;
774
802
  }>;
775
803
  shared_key: Uint8Array;
776
804
  };
@@ -793,18 +821,16 @@ export type DeRecEvent = {
793
821
  type: "ReplicaSecretInstalled";
794
822
  channel_id: string;
795
823
  from_replica_id: string;
824
+ author_replica_id: string | null;
796
825
  secret_id: string;
797
826
  version: number;
798
827
  secret: {
799
828
  helpers: Array<{
800
829
  channel_id: string;
801
830
  /** Every endpoint this peer advertised, in the order it offered them. */
802
- transports: Array<{
803
- uri: string;
804
- protocol: number;
805
- }>;
831
+ transports: Endpoint[];
806
832
  shared_key: Uint8Array;
807
- communication_info: Record<string, string>;
833
+ communication_info?: Record<string, string>;
808
834
  }>;
809
835
  secrets: Array<{
810
836
  id: Uint8Array;
@@ -822,12 +848,9 @@ export type DeRecEvent = {
822
848
  members: Array<{
823
849
  replica_id: string;
824
850
  /** Every endpoint this peer advertised, in the order it offered them. */
825
- transports: Array<{
826
- uri: string;
827
- protocol: number;
828
- }>;
851
+ transports: Endpoint[];
829
852
  role: "Source" | "Destination";
830
- communication_info: Record<string, string>;
853
+ communication_info?: Record<string, string>;
831
854
  }>;
832
855
  shared_key: Uint8Array;
833
856
  };
@@ -837,6 +860,56 @@ export type DeRecEvent = {
837
860
  committed_share: Uint8Array;
838
861
  }>;
839
862
  }
863
+ /** A member offered a different copy of the version this device holds.
864
+ * Nothing was written: this device keeps its own copy and refuses the
865
+ * incoming one with `VERSION_CONFLICT`, so the publisher sees
866
+ * `ReplicaSyncRejected`. Both copies are complete states — the held one
867
+ * is in the local stores, the incoming one is `secret`. Resolve by
868
+ * publishing the chosen state with `start(FlowKind.ProtectSecret)`; the
869
+ * next version supersedes both on every member and helper.
870
+ *
871
+ * `held_author_replica_id` / `incoming_author_replica_id` are the
872
+ * decimal `replica_id` of each copy's publisher, or `null` when that
873
+ * copy records none. */
874
+ | {
875
+ type: "ReplicaVersionConflict";
876
+ channel_id: string;
877
+ from_replica_id: string;
878
+ secret_id: string;
879
+ version: number;
880
+ held_author_replica_id: string | null;
881
+ incoming_author_replica_id: string | null;
882
+ secret: {
883
+ helpers: Array<{
884
+ channel_id: string;
885
+ /** Every endpoint this peer advertised, in the order it offered them. */
886
+ transports: Endpoint[];
887
+ shared_key: Uint8Array;
888
+ communication_info?: Record<string, string>;
889
+ }>;
890
+ secrets: Array<{
891
+ id: Uint8Array;
892
+ name: string;
893
+ data: Uint8Array;
894
+ }>;
895
+ /** The same shape as `SecretRecovered.secret.replicas`. */
896
+ replicas?: {
897
+ /** The one channel every member is addressed on. */
898
+ channel_id: string;
899
+ /** Every member of the group, including the writer. Exactly one
900
+ * carries `role: "Source"` — that member is where the secret
901
+ * originated, which is why no separate owner field is needed. */
902
+ members: Array<{
903
+ replica_id: string;
904
+ /** Every endpoint this peer advertised, in the order it offered them. */
905
+ transports: Endpoint[];
906
+ role: "Source" | "Destination";
907
+ communication_info?: Record<string, string>;
908
+ }>;
909
+ shared_key: Uint8Array;
910
+ };
911
+ };
912
+ }
840
913
  /** Peer's ack of a secret sync we sent. `status` is the `StatusEnum`
841
914
  * integer (0 = Ok), `memo` is the peer's explanation. */
842
915
  | {
@@ -845,7 +918,7 @@ export type DeRecEvent = {
845
918
  from_replica_id: string;
846
919
  secret_id: string;
847
920
  version: number;
848
- status: number;
921
+ status: StatusEnum;
849
922
  memo: string;
850
923
  }
851
924
  /** A peer announced an updated `communication_info` map and/or
@@ -862,7 +935,7 @@ export type DeRecEvent = {
862
935
  | {
863
936
  type: "ChannelInfoUpdateRejected";
864
937
  channel_id: string;
865
- status: number;
938
+ status: StatusEnum;
866
939
  memo: string;
867
940
  }
868
941
  /** Emitted by `process()` in place of `ActionRequired` when the
@@ -879,6 +952,38 @@ export type DeRecEvent = {
879
952
  } | {
880
953
  type: "NoOp";
881
954
  }
955
+ /** An inbound message was dropped untouched: no store was written and
956
+ * nothing was sent back. `reason` says why.
957
+ *
958
+ * `"PendingVerification"` means the peer sent something before this
959
+ * device confirmed the channel's fingerprint — typically a replica source
960
+ * pushing its first copy while this destination still shows the code.
961
+ * Confirming does not replay it: after `verifyFingerprint` succeeds, a
962
+ * replica destination calls `start(FlowKind.ReplicaDiscovery)` to pull
963
+ * the copy itself. `"Expired"` means the message was older than the
964
+ * inbound timeout. `trace_id` matches the peer's `*Started` event for
965
+ * the same round (`"0"` when the sender set none). */
966
+ | {
967
+ type: "MessageIgnored";
968
+ channel_id: string;
969
+ reason: IgnoreReason;
970
+ trace_id: string;
971
+ }
972
+ /** Returned by `restore`: a roster entry got no channel, so this device
973
+ * cannot reach that peer. Every other entry and the user-secret snapshot
974
+ * were restored; `reason` says why this one was not. `"NoTransports"`
975
+ * means the recovered roster names no endpoint for it.
976
+ *
977
+ * For a helper, `channel_id` is its channel and `replica_id` is absent.
978
+ * For a replica group member, `channel_id` is the group's channel and
979
+ * `replica_id` names the member. The peer itself is untouched — a helper
980
+ * still holds its share — and pairing with it again makes it reachable. */
981
+ | {
982
+ type: "PeerNotRestored";
983
+ channel_id: string;
984
+ replica_id?: string;
985
+ reason: NotRestoredReason;
986
+ }
882
987
  /** A pairing handshake was dispatched successfully. `kind` is the
883
988
  * local party's role — same value the subsequent `PairingCompleted`
884
989
  * will carry. Emitted by `start(Pairing)`. */
@@ -989,8 +1094,8 @@ export type DeRecEvent = {
989
1094
  * inbound shares. The protocol enforces no size, quota or rate limit
990
1095
  * of its own, and `maxShareSize` is checked for range overlap at
991
1096
  * 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
1097
+ * `false`, `ActionRequired` carries `share_size`, so the application
1098
+ * can compare it to its quota and call `reject()` with
994
1099
  * `StatusEnum.SizeLimitExceeded`. Setting it `true` removes that
995
1100
  * opportunity entirely: every share from every paired Owner is stored
996
1101
  * unconditionally, at whatever size it arrives. Keep off in any
@@ -1066,6 +1171,12 @@ export interface CommunicationInfoKeyValue {
1066
1171
  export interface CommunicationInfo {
1067
1172
  communication_info_entries: CommunicationInfoKeyValue[];
1068
1173
  }
1174
+ /** Why a `MessageIgnored` event dropped a message. Matches the Rust
1175
+ * `IgnoreReason` discriminants one-for-one. */
1176
+ export type IgnoreReason = "PendingVerification" | "Expired";
1177
+ /** Why a `PeerNotRestored` event left a roster entry without a channel.
1178
+ * Matches the Rust `NotRestoredReason` discriminants one-for-one. */
1179
+ export type NotRestoredReason = "NoTransports";
1069
1180
  /**
1070
1181
  * The label vocabulary for `ActionRequired.action_kind` and
1071
1182
  * `AutoAccepted.action_kind` — one value per pending-action kind the
@@ -1092,17 +1203,9 @@ export interface PairRequestMessage {
1092
1203
  nonce: bigint;
1093
1204
  communication_info?: CommunicationInfo;
1094
1205
  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
1206
  timestamp?: Timestamp;
1104
1207
  /** Every transport endpoint the initiator can be reached on, in its own
1105
- * preference order. Empty means "only `transport_protocol` is offered". */
1208
+ * preference order. */
1106
1209
  supported_transports: TransportProtocol[];
1107
1210
  }
1108
1211
  export interface PairResponseMessage {
@@ -1122,21 +1225,12 @@ export interface PairResponseMessage {
1122
1225
  }
1123
1226
  export interface PrePairRequestMessage {
1124
1227
  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
1228
  timestamp?: Timestamp;
1134
1229
  /**
1135
1230
  * 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.
1231
+ * its own preference order.
1138
1232
  */
1139
- supported_transports?: TransportProtocol[];
1233
+ supported_transports: TransportProtocol[];
1140
1234
  }
1141
1235
  export interface PrePairResponseMessage {
1142
1236
  result?: DeRecResult;
@@ -1292,6 +1386,12 @@ export interface PairingProcessResult {
1292
1386
  export interface ProducePrePairResult {
1293
1387
  envelope: Uint8Array;
1294
1388
  }
1389
+ export interface ProducePrePairNoKeysResult {
1390
+ envelope: Uint8Array;
1391
+ /** Secret key material generated for this pairing. The caller MUST persist
1392
+ * it: the `PairRequest` that follows is encrypted to it. */
1393
+ secret_key_material: Uint8Array;
1394
+ }
1295
1395
  export interface PrePairRequestExtractResult {
1296
1396
  request: PrePairRequestMessage;
1297
1397
  }
package/lib/types.js CHANGED
@@ -2,11 +2,14 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  // Copyright (c) 2026 DeRec Alliance. All rights reserved.
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.FlowKind = exports.ContactMode = exports.SenderKind = void 0;
5
+ exports.StatusEnum = exports.FlowKind = exports.ContactMode = exports.SenderKind = void 0;
6
6
  exports.channelFilterMatches = channelFilterMatches;
7
7
  exports.advertisedEndpoints = advertisedEndpoints;
8
+ exports.protocol_version = protocol_version;
9
+ exports.generate_replica_id = generate_replica_id;
8
10
  exports.sequentialFailover = sequentialFailover;
9
11
  exports.singleEndpointTransport = singleEndpointTransport;
12
+ const native_1 = require("./native");
10
13
  /**
11
14
  * Whether a channel or member with these attributes survives `filter`.
12
15
  *
@@ -37,13 +40,6 @@ function channelFilterMatches(filter, id, status, role) {
37
40
  /**
38
41
  * The endpoints a peer-supplied message advertises, in the peer's own order.
39
42
  *
40
- * Yields `supported_transports` when it is non-empty, and otherwise the
41
- * singular `transport_protocol` — which is how every implementation predating
42
- * the offer list advertises, and the reason this is a function rather than a
43
- * field read. Reading `transport_protocol` directly is a bug: its meaning
44
- * narrowed to "one entry of a list, and possibly absent", so a peer that has
45
- * moved past it looks unreachable to a reader that was correct before 0.0.3.
46
- *
47
43
  * Reports what was advertised, not what is acceptable — nothing here is
48
44
  * validated, and the protocol still applies its own transport policy to
49
45
  * whatever it records.
@@ -51,10 +47,23 @@ function channelFilterMatches(filter, id, status, role) {
51
47
  function advertisedEndpoints(message) {
52
48
  if (!message)
53
49
  return [];
54
- const offers = message.supported_transports ?? [];
55
- if (offers.length > 0)
56
- return offers;
57
- return message.transport_protocol ? [message.transport_protocol] : [];
50
+ return message.supported_transports ?? [];
51
+ }
52
+ /**
53
+ * The DeRec protocol version this build speaks — the `protocolVersionMajor` /
54
+ * `protocolVersionMinor` it writes into every envelope it produces. Not the
55
+ * package version.
56
+ */
57
+ function protocol_version() {
58
+ return (0, native_1.getNative)().version();
59
+ }
60
+ /**
61
+ * A fresh, random replica id — never `0`. Generate it once per device,
62
+ * persist it, and pass the same value to
63
+ * `DeRecProtocolBuilder.withReplicaId` on every init.
64
+ */
65
+ function generate_replica_id() {
66
+ return (0, native_1.getNative)().generate_replica_id();
58
67
  }
59
68
  /**
60
69
  * Builds a {@link Transport} that tries each endpoint in the order the peer
@@ -126,7 +135,7 @@ var SenderKind;
126
135
  * the scanner must fetch the actual keys over the wire via the `PrePair`
127
136
  * round-trip and verify them against the commitment before pairing.
128
137
  * - `NoKeys`: no key material and no commitment. The contact carries only
129
- * `channel_id`, `nonce`, and `transport_protocol` — small enough to be
138
+ * `channel_id`, `nonce`, and `supported_transports` — small enough to be
130
139
  * hand-typed or dictated. Keys are generated on the fly by the contact
131
140
  * creator when the `PrePairRequest` arrives; the scanner accepts them
132
141
  * without cryptographic verification. Trust rests entirely on the OOB
@@ -168,3 +177,24 @@ var FlowKind;
168
177
  * string so ids above 2^53 survive JS number handling. */
169
178
  FlowKind[FlowKind["UnpairReplica"] = 8] = "UnpairReplica";
170
179
  })(FlowKind || (exports.FlowKind = FlowKind = {}));
180
+ /** Result status carried in every protocol response (`result.proto`). Passed
181
+ * to `reject()` to say why an inbound request was refused. */
182
+ var StatusEnum;
183
+ (function (StatusEnum) {
184
+ StatusEnum[StatusEnum["Ok"] = 0] = "Ok";
185
+ StatusEnum[StatusEnum["Partial"] = 1] = "Partial";
186
+ StatusEnum[StatusEnum["Fail"] = 2] = "Fail";
187
+ StatusEnum[StatusEnum["SizeLimitExceeded"] = 3] = "SizeLimitExceeded";
188
+ StatusEnum[StatusEnum["TooFrequent"] = 4] = "TooFrequent";
189
+ StatusEnum[StatusEnum["UnknownSecretId"] = 5] = "UnknownSecretId";
190
+ StatusEnum[StatusEnum["UnknownShareVersion"] = 6] = "UnknownShareVersion";
191
+ StatusEnum[StatusEnum["DecryptionFailed"] = 7] = "DecryptionFailed";
192
+ StatusEnum[StatusEnum["VerificationFailed"] = 8] = "VerificationFailed";
193
+ StatusEnum[StatusEnum["FormatError"] = 9] = "FormatError";
194
+ StatusEnum[StatusEnum["Rejected"] = 10] = "Rejected";
195
+ StatusEnum[StatusEnum["IncompatibleParameterRange"] = 11] = "IncompatibleParameterRange";
196
+ StatusEnum[StatusEnum["UnsupportedTransportProtocol"] = 12] = "UnsupportedTransportProtocol";
197
+ StatusEnum[StatusEnum["VersionConflict"] = 13] = "VersionConflict";
198
+ StatusEnum[StatusEnum["ReplicaIdConflict"] = 14] = "ReplicaIdConflict";
199
+ StatusEnum[StatusEnum["RequestToClose"] = 99] = "RequestToClose";
200
+ })(StatusEnum || (exports.StatusEnum = StatusEnum = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@derec-alliance/react-native",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "React Native bindings for derec-library, the Rust SDK for the DeRec protocol.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
package/src/errors.ts CHANGED
@@ -42,4 +42,11 @@ export interface DeRecError {
42
42
  memo?: string;
43
43
  expected?: number;
44
44
  got?: number;
45
+ /**
46
+ * Present only when `code` is `"restore_conflict"`: the channels already
47
+ * living at the recovered canonical ids, as decimal strings — the same
48
+ * field `@derec-alliance/nodejs` carries on its restore conflict error.
49
+ * Clear exactly these and retry `restore`.
50
+ */
51
+ channel_ids?: string[];
45
52
  }