@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/README.md +33 -15
- package/android/CMakeLists.txt +1 -1
- package/android/src/main/jniLibs/arm64-v8a/libderec_library.a +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libderec_library.a +0 -0
- package/android/src/main/jniLibs/x86_64/libderec_library.a +0 -0
- package/cpp/Convert.cpp +125 -0
- package/cpp/Convert.h +35 -0
- package/cpp/DeRecInstaller.cpp +0 -12
- package/cpp/Primitives.cpp +175 -26
- package/cpp/Primitives.h +33 -0
- package/cpp/ProtocolHost.cpp +38 -50
- package/cpp/StoreCallbacks.cpp +179 -301
- package/cpp/UserSecretsJson.cpp +109 -0
- package/cpp/UserSecretsJson.h +28 -0
- package/cpp/derec_ffi.h +298 -132
- package/ios/DeRecFFI.xcframework/Info.plist +5 -5
- package/ios/DeRecFFI.xcframework/ios-arm64/Headers/derec_ffi.h +298 -132
- package/ios/DeRecFFI.xcframework/ios-arm64/libderec_library.a +0 -0
- package/ios/DeRecFFI.xcframework/ios-arm64_x86_64-simulator/Headers/derec_ffi.h +298 -132
- package/ios/DeRecFFI.xcframework/ios-arm64_x86_64-simulator/libderec_library.a +2 -2
- package/lib/errors.d.ts +16 -0
- package/lib/native.d.ts +5 -1
- package/lib/primitives.d.ts +18 -21
- package/lib/primitives.js +48 -25
- package/lib/protocol.d.ts +65 -102
- package/lib/protocol.js +98 -171
- package/lib/types.d.ts +299 -110
- package/lib/types.js +43 -13
- package/package.json +1 -1
- package/src/errors.ts +17 -0
- package/src/native.ts +2 -1
- package/src/primitives.ts +82 -25
- package/src/protocol.ts +105 -189
- package/src/types.ts +304 -99
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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 `
|
|
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
package/src/errors.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
// Copyright (c) 2026 DeRec Alliance. All rights reserved.
|
|
3
3
|
|
|
4
|
+
import type { DeRecEvent } from './types';
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
7
|
* Every category name `derec_error_category_name` can return, and no others.
|
|
6
8
|
*
|
|
@@ -42,4 +44,19 @@ export interface DeRecError {
|
|
|
42
44
|
memo?: string;
|
|
43
45
|
expected?: number;
|
|
44
46
|
got?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Present only when `code` is `"restore_conflict"`: the channels already
|
|
49
|
+
* living at the recovered canonical ids, as decimal strings — the same
|
|
50
|
+
* field `@derec-alliance/nodejs` carries on its restore conflict error.
|
|
51
|
+
* Clear exactly these and retry `restore`.
|
|
52
|
+
*/
|
|
53
|
+
channel_ids?: string[];
|
|
54
|
+
/** The channel the failing inbound message arrived on, when `process()` could tell. */
|
|
55
|
+
channel_id?: string;
|
|
56
|
+
/**
|
|
57
|
+
* On a failed `process()`: the events it produced before failing, such as
|
|
58
|
+
* sharing-round and unpair timeouts. They are not reported again, so
|
|
59
|
+
* handle them as you would a successful call's events.
|
|
60
|
+
*/
|
|
61
|
+
events?: DeRecEvent[];
|
|
45
62
|
}
|
package/src/native.ts
CHANGED
package/src/primitives.ts
CHANGED
|
@@ -55,6 +55,7 @@ import type {
|
|
|
55
55
|
PrePairResponseExtractResult,
|
|
56
56
|
PrePairResponseMessage,
|
|
57
57
|
ProcessPrePairResult,
|
|
58
|
+
ProducePrePairNoKeysResult,
|
|
58
59
|
ProducePrePairResult,
|
|
59
60
|
ProduceResult,
|
|
60
61
|
RecoverResult,
|
|
@@ -94,22 +95,17 @@ function replyTo(value: TransportProtocol[] | undefined): Uint8Array {
|
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
* `
|
|
101
|
-
* the commitment — so a malformed contact is rejected here rather than
|
|
102
|
-
* travelling.
|
|
98
|
+
* Every contact crossing the native seam goes through the core's contact
|
|
99
|
+
* codec, which also refuses a contact that violates the invariants of its
|
|
100
|
+
* contact mode. Delegates to `pairing.request.encode_contact` /
|
|
101
|
+
* `decode_contact`, defined below.
|
|
103
102
|
*/
|
|
104
103
|
function encodeContact(contact_message: ContactMessage): Uint8Array {
|
|
105
|
-
return
|
|
106
|
-
call('encode_contact_message', jsonToBytes(plainMessage(contact_message))),
|
|
107
|
-
);
|
|
104
|
+
return pairing.request.encode_contact(contact_message);
|
|
108
105
|
}
|
|
109
106
|
|
|
110
107
|
function decodeContact(wire: Uint8Array | ArrayBuffer): ContactMessage {
|
|
111
|
-
|
|
112
|
-
return reviveMessage(jsonFromBytes(json)) as ContactMessage;
|
|
108
|
+
return pairing.request.decode_contact(wire);
|
|
113
109
|
}
|
|
114
110
|
|
|
115
111
|
const discovery = {
|
|
@@ -247,22 +243,24 @@ function decodeTransportList(framed: Uint8Array | ArrayBuffer): TransportProtoco
|
|
|
247
243
|
|
|
248
244
|
const pairing = {
|
|
249
245
|
request: {
|
|
246
|
+
/** Creates an out-of-band `ContactMessage`. `nonce` omitted or `null`
|
|
247
|
+
* lets the library draw a random one; `ContactMode.NoKeys` requires the
|
|
248
|
+
* caller to supply it. */
|
|
250
249
|
create_contact(
|
|
251
250
|
channel_id: bigint,
|
|
252
251
|
contact_mode: ContactMode | number,
|
|
253
252
|
transport_protocols: TransportProtocol[],
|
|
253
|
+
nonce?: bigint | number | null,
|
|
254
254
|
): CreateContactResult {
|
|
255
|
-
// The C entry point
|
|
256
|
-
//
|
|
257
|
-
// flag is 0 and the library generates one — the same behaviour, not a
|
|
258
|
-
// default invented here.
|
|
255
|
+
// The C entry point carries `Option<u64>` as a presence flag plus a
|
|
256
|
+
// value; an absent nonce clears the flag and the library draws one.
|
|
259
257
|
const result = call(
|
|
260
258
|
'create_contact_message',
|
|
261
259
|
channel_id,
|
|
262
260
|
contact_mode,
|
|
263
261
|
encodeTransportList(transport_protocols),
|
|
264
|
-
0,
|
|
265
|
-
0n,
|
|
262
|
+
nonce == null ? 0 : 1,
|
|
263
|
+
nonce ?? 0n,
|
|
266
264
|
) as { contact_wire_bytes: ArrayBuffer; secret_key_material: ArrayBuffer };
|
|
267
265
|
return {
|
|
268
266
|
contact_message: decodeContact(result.contact_wire_bytes),
|
|
@@ -270,13 +268,22 @@ const pairing = {
|
|
|
270
268
|
};
|
|
271
269
|
},
|
|
272
270
|
|
|
273
|
-
/**
|
|
274
|
-
*
|
|
275
|
-
|
|
271
|
+
/** Serializes a `ContactMessage` to the bytes delivered out of band.
|
|
272
|
+
* Refuses a contact that violates the invariants of its contact mode or
|
|
273
|
+
* advertises no endpoint. */
|
|
274
|
+
encode_contact(contact_message: ContactMessage): Uint8Array {
|
|
275
|
+
return bytes(
|
|
276
|
+
call('encode_contact_message', jsonToBytes(plainMessage(contact_message))),
|
|
277
|
+
);
|
|
278
|
+
},
|
|
276
279
|
|
|
277
|
-
/**
|
|
278
|
-
*
|
|
279
|
-
|
|
280
|
+
/** Parses out-of-band contact bytes back into a `ContactMessage`.
|
|
281
|
+
* Refuses bytes that are not a contact, or a contact that violates the
|
|
282
|
+
* invariants of its contact mode. */
|
|
283
|
+
decode_contact(bytes: Uint8Array | ArrayBuffer): ContactMessage {
|
|
284
|
+
const json = call('decode_contact_message', bytes) as ArrayBuffer;
|
|
285
|
+
return reviveMessage(jsonFromBytes(json)) as ContactMessage;
|
|
286
|
+
},
|
|
280
287
|
|
|
281
288
|
produce(
|
|
282
289
|
kind: SenderKind,
|
|
@@ -306,8 +313,17 @@ const pairing = {
|
|
|
306
313
|
};
|
|
307
314
|
},
|
|
308
315
|
|
|
309
|
-
extract(
|
|
310
|
-
|
|
316
|
+
extract(
|
|
317
|
+
envelope_bytes: Uint8Array,
|
|
318
|
+
secret_key: Uint8Array,
|
|
319
|
+
parameter_range: ParameterRange | null,
|
|
320
|
+
): { request: PairRequestMessage } {
|
|
321
|
+
const result = call(
|
|
322
|
+
'extract_pair_request',
|
|
323
|
+
envelope_bytes,
|
|
324
|
+
secret_key,
|
|
325
|
+
encodeOptionalMessage(MessageKind.ParameterRange, parameter_range),
|
|
326
|
+
) as {
|
|
311
327
|
request_proto_bytes: ArrayBuffer;
|
|
312
328
|
};
|
|
313
329
|
return {
|
|
@@ -393,12 +409,14 @@ const pairing = {
|
|
|
393
409
|
contact_message: ContactMessage,
|
|
394
410
|
response: PairResponseMessage,
|
|
395
411
|
secret_key: Uint8Array,
|
|
412
|
+
parameter_range: ParameterRange | null,
|
|
396
413
|
): PairingProcessResult {
|
|
397
414
|
const result = call(
|
|
398
415
|
'process_pair_response_message',
|
|
399
416
|
encodeContact(contact_message),
|
|
400
417
|
encodeMessage(MessageKind.PairResponse, response),
|
|
401
418
|
secret_key,
|
|
419
|
+
encodeOptionalMessage(MessageKind.ParameterRange, parameter_range),
|
|
402
420
|
) as { shared_key: ArrayBuffer; channel_id: bigint };
|
|
403
421
|
return { shared_key: bytes(result.shared_key), channel_id: result.channel_id };
|
|
404
422
|
},
|
|
@@ -448,6 +466,45 @@ const pairing = {
|
|
|
448
466
|
nonce: result.nonce,
|
|
449
467
|
};
|
|
450
468
|
},
|
|
469
|
+
|
|
470
|
+
produce_pre_pair_no_keys(
|
|
471
|
+
channel_id: bigint,
|
|
472
|
+
request: PrePairRequestMessage,
|
|
473
|
+
): ProducePrePairNoKeysResult {
|
|
474
|
+
const result = call(
|
|
475
|
+
'produce_pre_pair_no_keys_response_message',
|
|
476
|
+
channel_id,
|
|
477
|
+
encodeMessage(MessageKind.PrePairRequest, request),
|
|
478
|
+
) as { envelope_wire_bytes: ArrayBuffer; secret_key_material: ArrayBuffer };
|
|
479
|
+
return {
|
|
480
|
+
envelope: bytes(result.envelope_wire_bytes),
|
|
481
|
+
secret_key_material: bytes(result.secret_key_material),
|
|
482
|
+
};
|
|
483
|
+
},
|
|
484
|
+
|
|
485
|
+
process_pre_pair_no_keys(
|
|
486
|
+
contact_message: ContactMessage,
|
|
487
|
+
response: PrePairResponseMessage,
|
|
488
|
+
): ProcessPrePairResult {
|
|
489
|
+
const result = call(
|
|
490
|
+
'process_pre_pair_no_keys_response_message',
|
|
491
|
+
encodeContact(contact_message),
|
|
492
|
+
encodeMessage(MessageKind.PrePairResponse, response),
|
|
493
|
+
) as {
|
|
494
|
+
mlkem_encapsulation_key: ArrayBuffer;
|
|
495
|
+
ecies_public_key: ArrayBuffer;
|
|
496
|
+
nonce: bigint;
|
|
497
|
+
};
|
|
498
|
+
return {
|
|
499
|
+
mlkem_encapsulation_key: bytes(result.mlkem_encapsulation_key),
|
|
500
|
+
ecies_public_key: bytes(result.ecies_public_key),
|
|
501
|
+
nonce: result.nonce,
|
|
502
|
+
};
|
|
503
|
+
},
|
|
504
|
+
},
|
|
505
|
+
|
|
506
|
+
fingerprint(shared_key: Uint8Array): string {
|
|
507
|
+
return call('pairing_fingerprint', shared_key) as string;
|
|
451
508
|
},
|
|
452
509
|
};
|
|
453
510
|
|