@derec-alliance/react-native 0.0.2 → 0.0.4

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/cpp/derec_ffi.h CHANGED
@@ -26,23 +26,48 @@
26
26
  */
27
27
  #define SHARE_ALGORITHM_REPLICA_SECRET 1
28
28
 
29
+ /**
30
+ * Schema version stamped onto every channel record this build writes.
31
+ *
32
+ * Applications persist [`HelperChannel`] and [`ReplicaMember`] as opaque
33
+ * blobs whose shape the *library* owns, so a field change here is a
34
+ * migration the application cannot write without knowing a schema it does
35
+ * not define. The marker is what lets the library do that migration itself:
36
+ * a reader can tell a record apart by the shape it was written in rather
37
+ * than by guessing from which fields happen to be present.
38
+ *
39
+ * A record written before the marker existed deserializes as version 0 and
40
+ * is upgraded on read. A record claiming a version *newer* than this build
41
+ * understands is refused, because the alternative is silently dropping
42
+ * fields this build cannot see and writing the truncated result back.
43
+ *
44
+ * The value tracks the release that last changed the shape, not the release
45
+ * that is current: it moved to 3 when `transport` became `transports`, and
46
+ * stays there until the next shape change.
47
+ *
48
+ * Declared unconditionally, unlike the serde impls that stamp it: the SDK
49
+ * bridges mirror this number in their own encoders, and a constant they must
50
+ * agree with should not appear and disappear with a feature flag.
51
+ */
52
+ #define CHANNEL_RECORD_SCHEMA_VERSION 3
53
+
29
54
  /**
30
55
  * Latest encoding major version, used for all new encodes. Bump only on a
31
56
  * breaking format change, adding the matching `vN` module and match arm.
32
57
  */
33
- #define LATEST 2
58
+ #define LATEST 3
34
59
 
35
60
  /**
36
61
  * Minimum number of shares required to reconstruct the secret, absent an
37
- * explicit [`DeRecProtocolBuilder::with_threshold`] call. This is the sole
38
- * definition of the value — [`DeRecProtocolBuilder::new`] and the FFI
62
+ * explicit [`DeRecProtocolBuilder::with_threshold`](crate::protocol::DeRecProtocolBuilder::with_threshold) call. This is the sole
63
+ * definition of the value — [`DeRecProtocolBuilder::new`](crate::protocol::DeRecProtocolBuilder::new) and the FFI
39
64
  * config's serde default both read it rather than each hardcoding `3`.
40
65
  */
41
66
  #define DEFAULT_THRESHOLD 3
42
67
 
43
68
  /**
44
69
  * Number of recent share versions each helper retains, absent an explicit
45
- * [`DeRecProtocolBuilder::with_keep_versions_count`] call. Sole definition
70
+ * [`DeRecProtocolBuilder::with_keep_versions_count`](crate::protocol::DeRecProtocolBuilder::with_keep_versions_count) call. Sole definition
46
71
  * of the value; see [`DEFAULT_THRESHOLD`].
47
72
  */
48
73
  #define DEFAULT_KEEP_VERSIONS_COUNT 3
@@ -263,6 +288,26 @@
263
288
  */
264
289
  #define DEREC_CODE_TRANSPORT_INVALID 120
265
290
 
291
+ /**
292
+ * No transport is shared with the peer — its offered endpoints and this
293
+ * application's served endpoints intersect to nothing. Always a local,
294
+ * terminal error: push-only delivery means an unreachable peer also
295
+ * cannot be told. `DEREC_CATEGORY_INVALID_INPUT`.
296
+ */
297
+ #define DEREC_CODE_NO_USABLE_ENDPOINT 121
298
+
299
+ /**
300
+ * Both plaintext opt-in flags were set explicitly and disagree: the
301
+ * deprecated `unsafe_http` says one thing and `unsafe_connection` the
302
+ * other. Raised at protocol construction rather than resolved by
303
+ * precedence, because the flag precedence would favour is the one being
304
+ * removed, and a configuration layer that emits every field
305
+ * unconditionally would otherwise let a defaulted value silently beat a
306
+ * deliberate one. Set only `unsafe_connection`.
307
+ * `DEREC_CATEGORY_INVALID_INPUT`.
308
+ */
309
+ #define DEREC_CODE_CONFLICTING_PLAINTEXT_OPT_IN 122
310
+
266
311
  /**
267
312
  * Discriminants selecting which message [`derec_decode_message_json`] and
268
313
  * [`derec_encode_message_json`] operate on.
@@ -301,7 +346,7 @@
301
346
  /**
302
347
  * Not a standalone message on the wire, but it crosses this FFI on its own
303
348
  * as the `transport_protocol` argument of `create_contact_message` and the
304
- * `peer_transport_protocol` result of `produce_pair_response_message`.
349
+ * `peer_transports` result of `produce_pair_response_message`.
305
350
  */
306
351
  #define DEREC_MESSAGE_KIND_TRANSPORT_PROTOCOL 14
307
352
 
@@ -345,13 +390,13 @@
345
390
  * Replica catch-up. Takes no parameters: the group and this device's own
346
391
  * version are both read from the stores.
347
392
  */
348
- #define FLOW_KIND_SYNC_CHECK 7
393
+ #define FLOW_KIND_REPLICA_DISCOVERY 7
349
394
 
350
395
  /**
351
396
  * Remove a member from the replica group. Params:
352
397
  * `{ "replica_id": "<decimal>", "memo": "<optional>" }`.
353
398
  */
354
- #define FLOW_KIND_REMOVE_REPLICA 8
399
+ #define FLOW_KIND_UNPAIR_REPLICA 8
355
400
 
356
401
  /**
357
402
  * Opaque handle returned by [`derec_protocol_new`] and consumed by
@@ -552,7 +597,7 @@ typedef struct ExtractPairRequestResult {
552
597
  typedef struct ProducePairResponseMessageResult {
553
598
  struct DeRecError error;
554
599
  struct DeRecBuffer response_wire_bytes;
555
- struct DeRecBuffer peer_transport_protocol;
600
+ struct DeRecBuffer peer_transports;
556
601
  struct DeRecBuffer shared_key;
557
602
  /**
558
603
  * Post-handshake rekey channel id the responder is committing to.
@@ -694,6 +739,17 @@ typedef struct DeRecProtocolNewResult {
694
739
  * [`crate::protocol::types::HelperChannel`] and
695
740
  * [`crate::protocol::types::ReplicaMember`] respectively.
696
741
  *
742
+ * Both listing callbacks receive a `filter` buffer holding a JSON-encoded
743
+ * [`crate::protocol::types::HelperFilter`] or
744
+ * [`crate::protocol::types::ReplicaFilter`] — an object with `ids`, `status`,
745
+ * `role` and `exclude`, where an empty array or a null `role` restricts
746
+ * nothing. A backend should apply it in its query rather than by listing
747
+ * everything and discarding rows; see
748
+ * [`crate::protocol::types::ChannelFilter`]. The library re-applies it to
749
+ * whatever comes back, so ignoring it is slow rather than wrong — but
750
+ * returning fewer rows than it selects is wrong, and undetectable. The buffer is owned
751
+ * by the caller and valid only for the duration of the call.
752
+ *
697
753
  * The order `list_replicas` returns is significant in exactly one situation —
698
754
  * it selects the successor when the group's source is removed. See
699
755
  * [`crate::protocol::DeRecChannelStore::replicas`] for the full contract.
@@ -717,8 +773,18 @@ typedef struct ChannelStoreCallbacks {
717
773
  uint64_t channel_id,
718
774
  uint64_t replica_id,
719
775
  uint32_t *out_existed);
720
- int32_t (*list_helpers)(void *user_data, uint64_t secret_id, uint8_t **out_ptr, size_t *out_len);
721
- int32_t (*list_replicas)(void *user_data, uint64_t secret_id, uint8_t **out_ptr, size_t *out_len);
776
+ int32_t (*list_helpers)(void *user_data,
777
+ uint64_t secret_id,
778
+ const uint8_t *filter,
779
+ size_t filter_len,
780
+ uint8_t **out_ptr,
781
+ size_t *out_len);
782
+ int32_t (*list_replicas)(void *user_data,
783
+ uint64_t secret_id,
784
+ const uint8_t *filter,
785
+ size_t filter_len,
786
+ uint8_t **out_ptr,
787
+ size_t *out_len);
722
788
  int32_t (*link_channel)(void *user_data, uint64_t secret_id, uint64_t a, uint64_t b);
723
789
  int32_t (*linked_channels)(void *user_data,
724
790
  uint64_t secret_id,
@@ -861,10 +927,24 @@ typedef struct StateStoreCallbacks {
861
927
  */
862
928
  typedef struct TransportCallbacks {
863
929
  void *user_data;
930
+ /**
931
+ * Deliver `bytes` to a peer reachable at any of `endpoints`.
932
+ *
933
+ * `endpoints` is a length-delimited sequence of encoded
934
+ * `TransportProtocol` messages — each entry preceded by its protobuf
935
+ * varint byte length, the same framing protobuf uses for a repeated
936
+ * embedded message field. They are the endpoints that peer advertised,
937
+ * in the order it offered them, already filtered to those the library
938
+ * will record.
939
+ *
940
+ * The library does not rank them. Which endpoint to dial, and whether
941
+ * to fall back to another when one is unreachable, is the
942
+ * implementation's choice. Return `0` once the message has reached any
943
+ * one of them; non-zero only when it reached none.
944
+ */
864
945
  int32_t (*send)(void *user_data,
865
- const uint8_t *uri_ptr,
866
- size_t uri_len,
867
- int32_t protocol,
946
+ const uint8_t *endpoints_ptr,
947
+ size_t endpoints_len,
868
948
  const uint8_t *bytes,
869
949
  size_t len);
870
950
  } TransportCallbacks;
@@ -1287,8 +1367,8 @@ struct DeRecMessageJsonResult derec_encode_message_json(int32_t kind,
1287
1367
  */
1288
1368
  struct CreateContactMessageResult create_contact_message(uint64_t channel_id,
1289
1369
  int32_t contact_mode,
1290
- const uint8_t *transport_protocol_ptr,
1291
- size_t transport_protocol_len,
1370
+ const uint8_t *transport_protocols_ptr,
1371
+ size_t transport_protocols_len,
1292
1372
  uint32_t has_nonce,
1293
1373
  uint64_t nonce);
1294
1374
 
@@ -1362,8 +1442,8 @@ struct DecodeContactMessageResult decode_contact_message(const uint8_t *contact_
1362
1442
  * Non-null input pointers must point to the corresponding readable byte ranges.
1363
1443
  */
1364
1444
  struct ProducePairRequestMessageResult produce_pair_request_message(int32_t sender_kind,
1365
- const uint8_t *transport_protocol_ptr,
1366
- size_t transport_protocol_len,
1445
+ const uint8_t *transport_protocols_ptr,
1446
+ size_t transport_protocols_len,
1367
1447
  const uint8_t *contact_message_ptr,
1368
1448
  size_t contact_message_len,
1369
1449
  const uint8_t *communication_info_ptr,
@@ -1402,7 +1482,8 @@ struct ProducePairResponseMessageResult produce_pair_response_message(uint64_t c
1402
1482
  const uint8_t *communication_info_ptr,
1403
1483
  size_t communication_info_len,
1404
1484
  const uint8_t *parameter_range_ptr,
1405
- size_t parameter_range_len);
1485
+ size_t parameter_range_len,
1486
+ uint32_t unsafe_connection);
1406
1487
 
1407
1488
  /**
1408
1489
  * # Safety
@@ -1439,8 +1520,8 @@ struct ProcessPairResponseMessageResult process_pair_response_message(const uint
1439
1520
  *
1440
1521
  * Non-null input pointers must point to the corresponding readable byte ranges.
1441
1522
  */
1442
- struct ProducePrePairRequestMessageResult produce_pre_pair_request_message(const uint8_t *transport_protocol_ptr,
1443
- size_t transport_protocol_len,
1523
+ struct ProducePrePairRequestMessageResult produce_pre_pair_request_message(const uint8_t *transport_protocols_ptr,
1524
+ size_t transport_protocols_len,
1444
1525
  const uint8_t *contact_message_ptr,
1445
1526
  size_t contact_message_len);
1446
1527
 
@@ -1527,6 +1608,7 @@ struct ProcessPrePairResponseMessageResult process_pre_pair_response_message(con
1527
1608
  * "secret_id": "12345678901234567890",
1528
1609
  * "own_transport_uri": "https://example.com/derec",
1529
1610
  * "own_transport_protocol": 1,
1611
+ * "own_transports": [{ "uri": "https://example.com/derec", "protocol": 0 }],
1530
1612
  * "threshold": 3,
1531
1613
  * "keep_versions_count": 2,
1532
1614
  * "timeout_in_secs": 30,
@@ -1553,6 +1635,11 @@ struct ProcessPrePairResponseMessageResult process_pre_pair_response_message(con
1553
1635
  * `derec_protocol_set_own_transport` must be called before pairing
1554
1636
  * in that case.
1555
1637
  * - `own_transport_protocol`: [`derec_proto::Protocol`] discriminant.
1638
+ * - `own_transports`: every endpoint this application serves, in
1639
+ * preference order — the order decides which of a peer's offered
1640
+ * endpoints is used. Optional; when non-empty it takes precedence over
1641
+ * `own_transport_uri` / `own_transport_protocol`, which stay fully
1642
+ * supported for callers that serve a single transport.
1556
1643
  * - `threshold` / `keep_versions_count`: optional; omitted means
1557
1644
  * [`crate::protocol::DEFAULT_THRESHOLD`] /
1558
1645
  * [`crate::protocol::DEFAULT_KEEP_VERSIONS_COUNT`].
@@ -1634,10 +1721,17 @@ struct DeRecError derec_protocol_set_communication_info(struct DeRecProtocolHand
1634
1721
  size_t info_json_len);
1635
1722
 
1636
1723
  /**
1637
- * Replace this node's local transport endpoint. See
1638
- * [`crate::protocol::DeRecProtocol::set_own_transport`] for the
1639
- * changeover discipline (keep the old endpoint up during the
1640
- * transition).
1724
+ * Replace this node's endpoint **for one protocol**, leaving the others
1725
+ * alone. A node serves at most one endpoint per protocol, so the `(uri,
1726
+ * protocol)` pair identifies the entry it replaces; an entry for a protocol
1727
+ * not yet served is appended, and a replaced one keeps its position in the
1728
+ * preference order. See
1729
+ * [`crate::protocol::DeRecProtocol::set_own_transport`] for the changeover
1730
+ * discipline (keep the old endpoint up during the transition).
1731
+ *
1732
+ * Superseded by [`derec_protocol_set_own_transports`], which takes the
1733
+ * whole preference list and is the only way to change *which* protocols
1734
+ * this node serves, or their order.
1641
1735
  *
1642
1736
  * # Safety
1643
1737
  *
@@ -1650,11 +1744,38 @@ struct DeRecError derec_protocol_set_communication_info(struct DeRecProtocolHand
1650
1744
  * from different threads are safe: the handle's internal mutex
1651
1745
  * serializes them.
1652
1746
  */
1747
+ __attribute__((deprecated("use derec_protocol_set_own_transports, which takes the whole preference list; removed at 0.0.5")))
1653
1748
  struct DeRecError derec_protocol_set_own_transport(struct DeRecProtocolHandle *handle,
1654
1749
  const uint8_t *uri_ptr,
1655
1750
  size_t uri_len,
1656
1751
  int32_t protocol);
1657
1752
 
1753
+ /**
1754
+ * Replace every endpoint this node advertises, in preference order.
1755
+ *
1756
+ * The runtime counterpart to the `own_transports` array accepted by
1757
+ * [`super::derec_protocol_new`], and the way to change the whole set:
1758
+ * `derec_protocol_set_own_transport` replaces only the entry for the
1759
+ * protocol its URI names. A device serves at most one endpoint per
1760
+ * protocol, so this list is a preference order over distinct protocols and
1761
+ * two entries of the same protocol are rejected. Body is the same JSON
1762
+ * shape that config array uses — `[{"uri": "...", "protocol": 0}, ...]`.
1763
+ *
1764
+ * Every entry is validated before any is stored, so a malformed URI
1765
+ * leaves the previous set intact rather than half-applied.
1766
+ *
1767
+ * # Safety
1768
+ *
1769
+ * `handle` must be a valid pointer returned by
1770
+ * [`super::derec_protocol_new`]. `json_ptr`/`json_len` must describe a
1771
+ * readable byte range. Concurrent calls on the same handle from
1772
+ * different threads are safe: the handle's internal mutex serializes
1773
+ * them.
1774
+ */
1775
+ struct DeRecError derec_protocol_set_own_transports(struct DeRecProtocolHandle *handle,
1776
+ const uint8_t *json_ptr,
1777
+ size_t json_len);
1778
+
1658
1779
  /**
1659
1780
  * Remove `Pending` channels older than `older_than_secs`. See
1660
1781
  * [`crate::protocol::DeRecProtocol::remove_expired_channels`] for the
@@ -26,23 +26,48 @@
26
26
  */
27
27
  #define SHARE_ALGORITHM_REPLICA_SECRET 1
28
28
 
29
+ /**
30
+ * Schema version stamped onto every channel record this build writes.
31
+ *
32
+ * Applications persist [`HelperChannel`] and [`ReplicaMember`] as opaque
33
+ * blobs whose shape the *library* owns, so a field change here is a
34
+ * migration the application cannot write without knowing a schema it does
35
+ * not define. The marker is what lets the library do that migration itself:
36
+ * a reader can tell a record apart by the shape it was written in rather
37
+ * than by guessing from which fields happen to be present.
38
+ *
39
+ * A record written before the marker existed deserializes as version 0 and
40
+ * is upgraded on read. A record claiming a version *newer* than this build
41
+ * understands is refused, because the alternative is silently dropping
42
+ * fields this build cannot see and writing the truncated result back.
43
+ *
44
+ * The value tracks the release that last changed the shape, not the release
45
+ * that is current: it moved to 3 when `transport` became `transports`, and
46
+ * stays there until the next shape change.
47
+ *
48
+ * Declared unconditionally, unlike the serde impls that stamp it: the SDK
49
+ * bridges mirror this number in their own encoders, and a constant they must
50
+ * agree with should not appear and disappear with a feature flag.
51
+ */
52
+ #define CHANNEL_RECORD_SCHEMA_VERSION 3
53
+
29
54
  /**
30
55
  * Latest encoding major version, used for all new encodes. Bump only on a
31
56
  * breaking format change, adding the matching `vN` module and match arm.
32
57
  */
33
- #define LATEST 2
58
+ #define LATEST 3
34
59
 
35
60
  /**
36
61
  * Minimum number of shares required to reconstruct the secret, absent an
37
- * explicit [`DeRecProtocolBuilder::with_threshold`] call. This is the sole
38
- * definition of the value — [`DeRecProtocolBuilder::new`] and the FFI
62
+ * explicit [`DeRecProtocolBuilder::with_threshold`](crate::protocol::DeRecProtocolBuilder::with_threshold) call. This is the sole
63
+ * definition of the value — [`DeRecProtocolBuilder::new`](crate::protocol::DeRecProtocolBuilder::new) and the FFI
39
64
  * config's serde default both read it rather than each hardcoding `3`.
40
65
  */
41
66
  #define DEFAULT_THRESHOLD 3
42
67
 
43
68
  /**
44
69
  * Number of recent share versions each helper retains, absent an explicit
45
- * [`DeRecProtocolBuilder::with_keep_versions_count`] call. Sole definition
70
+ * [`DeRecProtocolBuilder::with_keep_versions_count`](crate::protocol::DeRecProtocolBuilder::with_keep_versions_count) call. Sole definition
46
71
  * of the value; see [`DEFAULT_THRESHOLD`].
47
72
  */
48
73
  #define DEFAULT_KEEP_VERSIONS_COUNT 3
@@ -263,6 +288,26 @@
263
288
  */
264
289
  #define DEREC_CODE_TRANSPORT_INVALID 120
265
290
 
291
+ /**
292
+ * No transport is shared with the peer — its offered endpoints and this
293
+ * application's served endpoints intersect to nothing. Always a local,
294
+ * terminal error: push-only delivery means an unreachable peer also
295
+ * cannot be told. `DEREC_CATEGORY_INVALID_INPUT`.
296
+ */
297
+ #define DEREC_CODE_NO_USABLE_ENDPOINT 121
298
+
299
+ /**
300
+ * Both plaintext opt-in flags were set explicitly and disagree: the
301
+ * deprecated `unsafe_http` says one thing and `unsafe_connection` the
302
+ * other. Raised at protocol construction rather than resolved by
303
+ * precedence, because the flag precedence would favour is the one being
304
+ * removed, and a configuration layer that emits every field
305
+ * unconditionally would otherwise let a defaulted value silently beat a
306
+ * deliberate one. Set only `unsafe_connection`.
307
+ * `DEREC_CATEGORY_INVALID_INPUT`.
308
+ */
309
+ #define DEREC_CODE_CONFLICTING_PLAINTEXT_OPT_IN 122
310
+
266
311
  /**
267
312
  * Discriminants selecting which message [`derec_decode_message_json`] and
268
313
  * [`derec_encode_message_json`] operate on.
@@ -301,7 +346,7 @@
301
346
  /**
302
347
  * Not a standalone message on the wire, but it crosses this FFI on its own
303
348
  * as the `transport_protocol` argument of `create_contact_message` and the
304
- * `peer_transport_protocol` result of `produce_pair_response_message`.
349
+ * `peer_transports` result of `produce_pair_response_message`.
305
350
  */
306
351
  #define DEREC_MESSAGE_KIND_TRANSPORT_PROTOCOL 14
307
352
 
@@ -345,13 +390,13 @@
345
390
  * Replica catch-up. Takes no parameters: the group and this device's own
346
391
  * version are both read from the stores.
347
392
  */
348
- #define FLOW_KIND_SYNC_CHECK 7
393
+ #define FLOW_KIND_REPLICA_DISCOVERY 7
349
394
 
350
395
  /**
351
396
  * Remove a member from the replica group. Params:
352
397
  * `{ "replica_id": "<decimal>", "memo": "<optional>" }`.
353
398
  */
354
- #define FLOW_KIND_REMOVE_REPLICA 8
399
+ #define FLOW_KIND_UNPAIR_REPLICA 8
355
400
 
356
401
  /**
357
402
  * Opaque handle returned by [`derec_protocol_new`] and consumed by
@@ -552,7 +597,7 @@ typedef struct ExtractPairRequestResult {
552
597
  typedef struct ProducePairResponseMessageResult {
553
598
  struct DeRecError error;
554
599
  struct DeRecBuffer response_wire_bytes;
555
- struct DeRecBuffer peer_transport_protocol;
600
+ struct DeRecBuffer peer_transports;
556
601
  struct DeRecBuffer shared_key;
557
602
  /**
558
603
  * Post-handshake rekey channel id the responder is committing to.
@@ -694,6 +739,17 @@ typedef struct DeRecProtocolNewResult {
694
739
  * [`crate::protocol::types::HelperChannel`] and
695
740
  * [`crate::protocol::types::ReplicaMember`] respectively.
696
741
  *
742
+ * Both listing callbacks receive a `filter` buffer holding a JSON-encoded
743
+ * [`crate::protocol::types::HelperFilter`] or
744
+ * [`crate::protocol::types::ReplicaFilter`] — an object with `ids`, `status`,
745
+ * `role` and `exclude`, where an empty array or a null `role` restricts
746
+ * nothing. A backend should apply it in its query rather than by listing
747
+ * everything and discarding rows; see
748
+ * [`crate::protocol::types::ChannelFilter`]. The library re-applies it to
749
+ * whatever comes back, so ignoring it is slow rather than wrong — but
750
+ * returning fewer rows than it selects is wrong, and undetectable. The buffer is owned
751
+ * by the caller and valid only for the duration of the call.
752
+ *
697
753
  * The order `list_replicas` returns is significant in exactly one situation —
698
754
  * it selects the successor when the group's source is removed. See
699
755
  * [`crate::protocol::DeRecChannelStore::replicas`] for the full contract.
@@ -717,8 +773,18 @@ typedef struct ChannelStoreCallbacks {
717
773
  uint64_t channel_id,
718
774
  uint64_t replica_id,
719
775
  uint32_t *out_existed);
720
- int32_t (*list_helpers)(void *user_data, uint64_t secret_id, uint8_t **out_ptr, size_t *out_len);
721
- int32_t (*list_replicas)(void *user_data, uint64_t secret_id, uint8_t **out_ptr, size_t *out_len);
776
+ int32_t (*list_helpers)(void *user_data,
777
+ uint64_t secret_id,
778
+ const uint8_t *filter,
779
+ size_t filter_len,
780
+ uint8_t **out_ptr,
781
+ size_t *out_len);
782
+ int32_t (*list_replicas)(void *user_data,
783
+ uint64_t secret_id,
784
+ const uint8_t *filter,
785
+ size_t filter_len,
786
+ uint8_t **out_ptr,
787
+ size_t *out_len);
722
788
  int32_t (*link_channel)(void *user_data, uint64_t secret_id, uint64_t a, uint64_t b);
723
789
  int32_t (*linked_channels)(void *user_data,
724
790
  uint64_t secret_id,
@@ -861,10 +927,24 @@ typedef struct StateStoreCallbacks {
861
927
  */
862
928
  typedef struct TransportCallbacks {
863
929
  void *user_data;
930
+ /**
931
+ * Deliver `bytes` to a peer reachable at any of `endpoints`.
932
+ *
933
+ * `endpoints` is a length-delimited sequence of encoded
934
+ * `TransportProtocol` messages — each entry preceded by its protobuf
935
+ * varint byte length, the same framing protobuf uses for a repeated
936
+ * embedded message field. They are the endpoints that peer advertised,
937
+ * in the order it offered them, already filtered to those the library
938
+ * will record.
939
+ *
940
+ * The library does not rank them. Which endpoint to dial, and whether
941
+ * to fall back to another when one is unreachable, is the
942
+ * implementation's choice. Return `0` once the message has reached any
943
+ * one of them; non-zero only when it reached none.
944
+ */
864
945
  int32_t (*send)(void *user_data,
865
- const uint8_t *uri_ptr,
866
- size_t uri_len,
867
- int32_t protocol,
946
+ const uint8_t *endpoints_ptr,
947
+ size_t endpoints_len,
868
948
  const uint8_t *bytes,
869
949
  size_t len);
870
950
  } TransportCallbacks;
@@ -1287,8 +1367,8 @@ struct DeRecMessageJsonResult derec_encode_message_json(int32_t kind,
1287
1367
  */
1288
1368
  struct CreateContactMessageResult create_contact_message(uint64_t channel_id,
1289
1369
  int32_t contact_mode,
1290
- const uint8_t *transport_protocol_ptr,
1291
- size_t transport_protocol_len,
1370
+ const uint8_t *transport_protocols_ptr,
1371
+ size_t transport_protocols_len,
1292
1372
  uint32_t has_nonce,
1293
1373
  uint64_t nonce);
1294
1374
 
@@ -1362,8 +1442,8 @@ struct DecodeContactMessageResult decode_contact_message(const uint8_t *contact_
1362
1442
  * Non-null input pointers must point to the corresponding readable byte ranges.
1363
1443
  */
1364
1444
  struct ProducePairRequestMessageResult produce_pair_request_message(int32_t sender_kind,
1365
- const uint8_t *transport_protocol_ptr,
1366
- size_t transport_protocol_len,
1445
+ const uint8_t *transport_protocols_ptr,
1446
+ size_t transport_protocols_len,
1367
1447
  const uint8_t *contact_message_ptr,
1368
1448
  size_t contact_message_len,
1369
1449
  const uint8_t *communication_info_ptr,
@@ -1402,7 +1482,8 @@ struct ProducePairResponseMessageResult produce_pair_response_message(uint64_t c
1402
1482
  const uint8_t *communication_info_ptr,
1403
1483
  size_t communication_info_len,
1404
1484
  const uint8_t *parameter_range_ptr,
1405
- size_t parameter_range_len);
1485
+ size_t parameter_range_len,
1486
+ uint32_t unsafe_connection);
1406
1487
 
1407
1488
  /**
1408
1489
  * # Safety
@@ -1439,8 +1520,8 @@ struct ProcessPairResponseMessageResult process_pair_response_message(const uint
1439
1520
  *
1440
1521
  * Non-null input pointers must point to the corresponding readable byte ranges.
1441
1522
  */
1442
- struct ProducePrePairRequestMessageResult produce_pre_pair_request_message(const uint8_t *transport_protocol_ptr,
1443
- size_t transport_protocol_len,
1523
+ struct ProducePrePairRequestMessageResult produce_pre_pair_request_message(const uint8_t *transport_protocols_ptr,
1524
+ size_t transport_protocols_len,
1444
1525
  const uint8_t *contact_message_ptr,
1445
1526
  size_t contact_message_len);
1446
1527
 
@@ -1527,6 +1608,7 @@ struct ProcessPrePairResponseMessageResult process_pre_pair_response_message(con
1527
1608
  * "secret_id": "12345678901234567890",
1528
1609
  * "own_transport_uri": "https://example.com/derec",
1529
1610
  * "own_transport_protocol": 1,
1611
+ * "own_transports": [{ "uri": "https://example.com/derec", "protocol": 0 }],
1530
1612
  * "threshold": 3,
1531
1613
  * "keep_versions_count": 2,
1532
1614
  * "timeout_in_secs": 30,
@@ -1553,6 +1635,11 @@ struct ProcessPrePairResponseMessageResult process_pre_pair_response_message(con
1553
1635
  * `derec_protocol_set_own_transport` must be called before pairing
1554
1636
  * in that case.
1555
1637
  * - `own_transport_protocol`: [`derec_proto::Protocol`] discriminant.
1638
+ * - `own_transports`: every endpoint this application serves, in
1639
+ * preference order — the order decides which of a peer's offered
1640
+ * endpoints is used. Optional; when non-empty it takes precedence over
1641
+ * `own_transport_uri` / `own_transport_protocol`, which stay fully
1642
+ * supported for callers that serve a single transport.
1556
1643
  * - `threshold` / `keep_versions_count`: optional; omitted means
1557
1644
  * [`crate::protocol::DEFAULT_THRESHOLD`] /
1558
1645
  * [`crate::protocol::DEFAULT_KEEP_VERSIONS_COUNT`].
@@ -1634,10 +1721,17 @@ struct DeRecError derec_protocol_set_communication_info(struct DeRecProtocolHand
1634
1721
  size_t info_json_len);
1635
1722
 
1636
1723
  /**
1637
- * Replace this node's local transport endpoint. See
1638
- * [`crate::protocol::DeRecProtocol::set_own_transport`] for the
1639
- * changeover discipline (keep the old endpoint up during the
1640
- * transition).
1724
+ * Replace this node's endpoint **for one protocol**, leaving the others
1725
+ * alone. A node serves at most one endpoint per protocol, so the `(uri,
1726
+ * protocol)` pair identifies the entry it replaces; an entry for a protocol
1727
+ * not yet served is appended, and a replaced one keeps its position in the
1728
+ * preference order. See
1729
+ * [`crate::protocol::DeRecProtocol::set_own_transport`] for the changeover
1730
+ * discipline (keep the old endpoint up during the transition).
1731
+ *
1732
+ * Superseded by [`derec_protocol_set_own_transports`], which takes the
1733
+ * whole preference list and is the only way to change *which* protocols
1734
+ * this node serves, or their order.
1641
1735
  *
1642
1736
  * # Safety
1643
1737
  *
@@ -1650,11 +1744,38 @@ struct DeRecError derec_protocol_set_communication_info(struct DeRecProtocolHand
1650
1744
  * from different threads are safe: the handle's internal mutex
1651
1745
  * serializes them.
1652
1746
  */
1747
+ __attribute__((deprecated("use derec_protocol_set_own_transports, which takes the whole preference list; removed at 0.0.5")))
1653
1748
  struct DeRecError derec_protocol_set_own_transport(struct DeRecProtocolHandle *handle,
1654
1749
  const uint8_t *uri_ptr,
1655
1750
  size_t uri_len,
1656
1751
  int32_t protocol);
1657
1752
 
1753
+ /**
1754
+ * Replace every endpoint this node advertises, in preference order.
1755
+ *
1756
+ * The runtime counterpart to the `own_transports` array accepted by
1757
+ * [`super::derec_protocol_new`], and the way to change the whole set:
1758
+ * `derec_protocol_set_own_transport` replaces only the entry for the
1759
+ * protocol its URI names. A device serves at most one endpoint per
1760
+ * protocol, so this list is a preference order over distinct protocols and
1761
+ * two entries of the same protocol are rejected. Body is the same JSON
1762
+ * shape that config array uses — `[{"uri": "...", "protocol": 0}, ...]`.
1763
+ *
1764
+ * Every entry is validated before any is stored, so a malformed URI
1765
+ * leaves the previous set intact rather than half-applied.
1766
+ *
1767
+ * # Safety
1768
+ *
1769
+ * `handle` must be a valid pointer returned by
1770
+ * [`super::derec_protocol_new`]. `json_ptr`/`json_len` must describe a
1771
+ * readable byte range. Concurrent calls on the same handle from
1772
+ * different threads are safe: the handle's internal mutex serializes
1773
+ * them.
1774
+ */
1775
+ struct DeRecError derec_protocol_set_own_transports(struct DeRecProtocolHandle *handle,
1776
+ const uint8_t *json_ptr,
1777
+ size_t json_len);
1778
+
1658
1779
  /**
1659
1780
  * Remove `Pending` channels older than `older_than_secs`. See
1660
1781
  * [`crate::protocol::DeRecProtocol::remove_expired_channels`] for the