@derec-alliance/react-native 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -15
- package/android/CMakeLists.txt +1 -1
- package/android/src/main/jniLibs/arm64-v8a/libderec_library.a +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libderec_library.a +0 -0
- package/android/src/main/jniLibs/x86_64/libderec_library.a +0 -0
- package/cpp/Convert.cpp +125 -0
- package/cpp/Convert.h +35 -0
- package/cpp/DeRecInstaller.cpp +0 -12
- package/cpp/Primitives.cpp +159 -26
- package/cpp/Primitives.h +16 -0
- package/cpp/ProtocolHost.cpp +22 -47
- package/cpp/StoreCallbacks.cpp +97 -304
- package/cpp/UserSecretsJson.cpp +109 -0
- package/cpp/UserSecretsJson.h +28 -0
- package/cpp/derec_ffi.h +256 -120
- package/ios/DeRecFFI.xcframework/ios-arm64/Headers/derec_ffi.h +256 -120
- package/ios/DeRecFFI.xcframework/ios-arm64/libderec_library.a +0 -0
- package/ios/DeRecFFI.xcframework/ios-arm64_x86_64-simulator/Headers/derec_ffi.h +256 -120
- package/ios/DeRecFFI.xcframework/ios-arm64_x86_64-simulator/libderec_library.a +2 -2
- package/lib/errors.d.ts +7 -0
- package/lib/native.d.ts +5 -1
- package/lib/primitives.d.ts +18 -21
- package/lib/primitives.js +48 -25
- package/lib/protocol.d.ts +49 -97
- package/lib/protocol.js +71 -162
- package/lib/types.d.ts +218 -107
- package/lib/types.js +43 -13
- package/package.json +1 -1
- package/src/errors.ts +7 -0
- package/src/native.ts +2 -1
- package/src/primitives.ts +82 -25
- package/src/protocol.ts +79 -179
- package/src/types.ts +232 -96
package/src/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
|
}
|
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
|
|
package/src/protocol.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
ContactMessage,
|
|
12
12
|
ContactMode,
|
|
13
13
|
DeRecEvent,
|
|
14
|
+
Endpoint,
|
|
14
15
|
DiscoveryParams,
|
|
15
16
|
PairingParams,
|
|
16
17
|
ParameterRange,
|
|
@@ -20,6 +21,7 @@ import type {
|
|
|
20
21
|
SecretStore,
|
|
21
22
|
ShareStore,
|
|
22
23
|
StateStore,
|
|
24
|
+
StatusEnum,
|
|
23
25
|
ReplicaDiscoveryParams,
|
|
24
26
|
Target,
|
|
25
27
|
Timeouts,
|
|
@@ -81,25 +83,6 @@ function decodeEvents(buffer: ArrayBuffer): DeRecEvent[] {
|
|
|
81
83
|
return reviveEventBytes(jsonFromBytes(buffer)) as DeRecEvent[];
|
|
82
84
|
}
|
|
83
85
|
|
|
84
|
-
/**
|
|
85
|
-
* Maps a transport protocol name to the `derec_proto::Protocol` discriminant.
|
|
86
|
-
* The shared enum fixture every other numeric mapping in this SDK is checked
|
|
87
|
-
* against does not carry this enum (it
|
|
88
|
-
* only covers the Rust-internal serde enums listed under its `"enums"` key);
|
|
89
|
-
* the transport `Protocol` enum lives in `protobufs/transportprotocol.proto`
|
|
90
|
-
* instead, where `HTTPS = 0` and `GRPC = 1` are defined.
|
|
91
|
-
*/
|
|
92
|
-
export function protocolDiscriminant(protocol: string): number {
|
|
93
|
-
switch (protocol.toLowerCase()) {
|
|
94
|
-
case 'https':
|
|
95
|
-
return 0;
|
|
96
|
-
case 'grpc':
|
|
97
|
-
return 1;
|
|
98
|
-
default:
|
|
99
|
-
throw new Error(`DeRec: unknown transport protocol "${protocol}"`);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
86
|
function encodeTarget(target: Target): unknown {
|
|
104
87
|
if (target === null) {
|
|
105
88
|
return null;
|
|
@@ -261,13 +244,8 @@ function buildStartParams(flowKind: FlowKind, params: unknown): Uint8Array {
|
|
|
261
244
|
if (p.communication_info !== undefined) {
|
|
262
245
|
out.communication_info = p.communication_info;
|
|
263
246
|
}
|
|
264
|
-
if (p.own_transports !== undefined
|
|
247
|
+
if (p.own_transports !== undefined) {
|
|
265
248
|
out.own_transports = p.own_transports;
|
|
266
|
-
// The first entry also fills the deprecated singular field so a peer
|
|
267
|
-
// predating `supported_transports` still learns the new address.
|
|
268
|
-
out.transport_protocol = p.own_transports[0];
|
|
269
|
-
} else if (p.transport_protocol !== undefined) {
|
|
270
|
-
out.transport_protocol = p.transport_protocol;
|
|
271
249
|
}
|
|
272
250
|
return jsonToBytes(out);
|
|
273
251
|
}
|
|
@@ -313,7 +291,6 @@ export class DeRecProtocolBuilder {
|
|
|
313
291
|
private readonly secretIdValue: bigint;
|
|
314
292
|
private config: Record<string, unknown> = {};
|
|
315
293
|
private stores: Record<string, unknown> = {};
|
|
316
|
-
private communicationInfo: Record<string, string> | undefined;
|
|
317
294
|
|
|
318
295
|
constructor(secretId: bigint | number) {
|
|
319
296
|
this.secretIdValue = BigInt(secretId);
|
|
@@ -349,23 +326,10 @@ export class DeRecProtocolBuilder {
|
|
|
349
326
|
return this;
|
|
350
327
|
}
|
|
351
328
|
|
|
352
|
-
/**
|
|
353
|
-
* @deprecated Use {@link withOwnTransports}, which takes the whole
|
|
354
|
-
* preference list — `withOwnTransports([endpoint])` is the direct
|
|
355
|
-
* replacement. Removed at 0.0.5.
|
|
356
|
-
*/
|
|
357
|
-
withOwnTransport(endpoint: { uri: string; protocol: string }): this {
|
|
358
|
-
this.config.own_transport_uri = endpoint.uri;
|
|
359
|
-
this.config.own_transport_protocol = protocolDiscriminant(endpoint.protocol);
|
|
360
|
-
return this;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
329
|
/**
|
|
364
330
|
* Set every transport endpoint this application serves, in preference
|
|
365
|
-
* order. Written to the config's `own_transports` array
|
|
366
|
-
*
|
|
367
|
-
* Rust side when non-empty — see `ProtocolConfig` in
|
|
368
|
-
* `library/src/interop/ffi/protocol/handle/mod.rs`.
|
|
331
|
+
* order. Written to the config's `own_transports` array — see
|
|
332
|
+
* `ProtocolConfig` in `library/src/interop/ffi/protocol/handle/mod.rs`.
|
|
369
333
|
*
|
|
370
334
|
* The order given is forwarded verbatim: it is not sorted, deduplicated,
|
|
371
335
|
* or reordered here. It is this application's own preference and
|
|
@@ -374,15 +338,11 @@ export class DeRecProtocolBuilder {
|
|
|
374
338
|
* listing an endpoint this application does not serve makes pairing
|
|
375
339
|
* succeed and replies vanish.
|
|
376
340
|
*
|
|
377
|
-
*
|
|
378
|
-
*
|
|
379
|
-
* supported.
|
|
341
|
+
* Required: `build()` with no own transport is refused by the library,
|
|
342
|
+
* since a node with no endpoint cannot be reached by any peer.
|
|
380
343
|
*/
|
|
381
|
-
withOwnTransports(transports:
|
|
382
|
-
this.config.own_transports = transports.map((
|
|
383
|
-
uri: t.uri,
|
|
384
|
-
protocol: protocolDiscriminant(t.protocol),
|
|
385
|
-
}));
|
|
344
|
+
withOwnTransports(transports: Endpoint[]): this {
|
|
345
|
+
this.config.own_transports = transports.map(({ uri, protocol }) => ({ uri, protocol }));
|
|
386
346
|
return this;
|
|
387
347
|
}
|
|
388
348
|
|
|
@@ -410,24 +370,9 @@ export class DeRecProtocolBuilder {
|
|
|
410
370
|
return this;
|
|
411
371
|
}
|
|
412
372
|
|
|
413
|
-
/**
|
|
414
|
-
* @deprecated Use {@link withUnsafeConnection}, which names both gated
|
|
415
|
-
* schemes. Removed at 0.0.5. Default: false.
|
|
416
|
-
*/
|
|
417
|
-
withUnsafeHttp(allow: boolean): this {
|
|
418
|
-
this.config.unsafe_http = allow;
|
|
419
|
-
return this;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
373
|
/**
|
|
423
374
|
* Accept plaintext `http://` and `grpc://` transport endpoints.
|
|
424
|
-
* **Development only.** Default: false.
|
|
425
|
-
* {@link withUnsafeHttp}, which names only the HTTP scheme.
|
|
426
|
-
*
|
|
427
|
-
* Either flag alone is honored. Setting both to disagreeing values fails
|
|
428
|
-
* construction with the error code `CONFLICTING_PLAINTEXT_OPT_IN` rather
|
|
429
|
-
* than resolving silently, because precedence would hand the decision to
|
|
430
|
-
* the flag being removed.
|
|
375
|
+
* **Development only.** Default: false.
|
|
431
376
|
*/
|
|
432
377
|
withUnsafeConnection(allow: boolean): this {
|
|
433
378
|
this.config.unsafe_connection = allow;
|
|
@@ -435,24 +380,11 @@ export class DeRecProtocolBuilder {
|
|
|
435
380
|
}
|
|
436
381
|
|
|
437
382
|
/**
|
|
438
|
-
* Default: empty.
|
|
439
|
-
* is
|
|
440
|
-
* no encoder for that message — the C ABI exposes one only for
|
|
441
|
-
* `ContactMessage`. Hand-rolling one here would be SDK-side protocol logic
|
|
442
|
-
* with no test coverage — exactly what this codebase's "Rust decides, the
|
|
443
|
-
* SDK only marshals" rule forbids. Instead,
|
|
444
|
-
* `build()` constructs the protocol with an empty `communication_info`
|
|
445
|
-
* (a legitimate, always-accepted value — see `decode_communication_info`
|
|
446
|
-
* in `library/src/interop/ffi/protocol/handle/mod.rs`, which treats a zero-length
|
|
447
|
-
* buffer as "no entries") and then calls the already-bound
|
|
448
|
-
* {@link DeRecProtocol.setCommunicationInfo}, which takes the same map as
|
|
449
|
-
* plain JSON (`derec_protocol_set_communication_info` in
|
|
450
|
-
* `library/src/interop/ffi/protocol/handle/config.rs`). That setter is queued on
|
|
451
|
-
* the protocol's serial worker before `build()` returns, so it is ordered
|
|
452
|
-
* ahead of every call the caller can subsequently make.
|
|
383
|
+
* Default: empty. Written to the config's `communication_info` key, so the
|
|
384
|
+
* map is part of the protocol from construction.
|
|
453
385
|
*/
|
|
454
386
|
withCommunicationInfo(info: Record<string, string>): this {
|
|
455
|
-
this.
|
|
387
|
+
this.config.communication_info = info;
|
|
456
388
|
return this;
|
|
457
389
|
}
|
|
458
390
|
|
|
@@ -464,13 +396,7 @@ export class DeRecProtocolBuilder {
|
|
|
464
396
|
|
|
465
397
|
/** Default: "required". */
|
|
466
398
|
withUnpairAck(ack: UnpairAck): this {
|
|
467
|
-
|
|
468
|
-
this.config.unpair_ack = 0;
|
|
469
|
-
} else if (ack === 'not_required') {
|
|
470
|
-
this.config.unpair_ack = 1;
|
|
471
|
-
} else {
|
|
472
|
-
throw new Error(`DeRec: unknown unpair ack "${ack as string}"`);
|
|
473
|
-
}
|
|
399
|
+
this.config.unpair_ack = ack;
|
|
474
400
|
return this;
|
|
475
401
|
}
|
|
476
402
|
|
|
@@ -480,17 +406,20 @@ export class DeRecProtocolBuilder {
|
|
|
480
406
|
return this;
|
|
481
407
|
}
|
|
482
408
|
|
|
483
|
-
/**
|
|
409
|
+
/**
|
|
410
|
+
* Default: empty policy (every flow off). A flow left out of `policy` is
|
|
411
|
+
* left out of the config, and the library applies its own default to it.
|
|
412
|
+
*/
|
|
484
413
|
withAutoAccept(policy: AutoAcceptPolicy): this {
|
|
485
414
|
this.config.auto_accept = {
|
|
486
|
-
pairing: policy.pairing
|
|
487
|
-
pre_pair: policy.prePair
|
|
488
|
-
store_share: policy.storeShare
|
|
489
|
-
verify_share: policy.verifyShare
|
|
490
|
-
discovery: policy.discovery
|
|
491
|
-
get_share: policy.getShare
|
|
492
|
-
unpair: policy.unpair
|
|
493
|
-
update_channel_info: policy.updateChannelInfo
|
|
415
|
+
pairing: policy.pairing,
|
|
416
|
+
pre_pair: policy.prePair,
|
|
417
|
+
store_share: policy.storeShare,
|
|
418
|
+
verify_share: policy.verifyShare,
|
|
419
|
+
discovery: policy.discovery,
|
|
420
|
+
get_share: policy.getShare,
|
|
421
|
+
unpair: policy.unpair,
|
|
422
|
+
update_channel_info: policy.updateChannelInfo,
|
|
494
423
|
};
|
|
495
424
|
return this;
|
|
496
425
|
}
|
|
@@ -508,30 +437,26 @@ export class DeRecProtocolBuilder {
|
|
|
508
437
|
* against the peer's range on inbound ones: a range that fails to
|
|
509
438
|
* intersect rejects the pairing. Every bound is optional and defaults to
|
|
510
439
|
* `0`, which the protocol reads as "no constraint on this dimension".
|
|
440
|
+
* Bounds cross to the library as decimal strings, so the full `i64` range
|
|
441
|
+
* survives; a bound left out is left out of the config, and the library
|
|
442
|
+
* applies its default.
|
|
511
443
|
*
|
|
512
444
|
* Default: unset — no constraints advertised, every peer range accepted.
|
|
513
445
|
*/
|
|
514
446
|
withParameterRange(range: Partial<ParameterRange>): this {
|
|
515
|
-
const n = (v: bigint | undefined) => Number(v ?? 0n);
|
|
516
447
|
this.config.parameter_range = {
|
|
517
|
-
min_share_size:
|
|
518
|
-
max_share_size:
|
|
519
|
-
min_time_between_verifications:
|
|
520
|
-
max_time_between_verifications:
|
|
521
|
-
min_time_between_share_updates:
|
|
522
|
-
max_time_between_share_updates:
|
|
523
|
-
min_unresponsive_deletion_timeout:
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
min_unresponsive_deactivation_timeout: n(
|
|
530
|
-
range.min_unresponsive_deactivation_timeout,
|
|
531
|
-
),
|
|
532
|
-
max_unresponsive_deactivation_timeout: n(
|
|
533
|
-
range.max_unresponsive_deactivation_timeout,
|
|
534
|
-
),
|
|
448
|
+
min_share_size: range.min_share_size?.toString(),
|
|
449
|
+
max_share_size: range.max_share_size?.toString(),
|
|
450
|
+
min_time_between_verifications: range.min_time_between_verifications?.toString(),
|
|
451
|
+
max_time_between_verifications: range.max_time_between_verifications?.toString(),
|
|
452
|
+
min_time_between_share_updates: range.min_time_between_share_updates?.toString(),
|
|
453
|
+
max_time_between_share_updates: range.max_time_between_share_updates?.toString(),
|
|
454
|
+
min_unresponsive_deletion_timeout: range.min_unresponsive_deletion_timeout?.toString(),
|
|
455
|
+
max_unresponsive_deletion_timeout: range.max_unresponsive_deletion_timeout?.toString(),
|
|
456
|
+
min_unresponsive_deactivation_timeout:
|
|
457
|
+
range.min_unresponsive_deactivation_timeout?.toString(),
|
|
458
|
+
max_unresponsive_deactivation_timeout:
|
|
459
|
+
range.max_unresponsive_deactivation_timeout?.toString(),
|
|
535
460
|
};
|
|
536
461
|
return this;
|
|
537
462
|
}
|
|
@@ -540,8 +465,6 @@ export class DeRecProtocolBuilder {
|
|
|
540
465
|
const config = {
|
|
541
466
|
secret_id: this.secretIdValue.toString(),
|
|
542
467
|
replica_id: null,
|
|
543
|
-
own_transport_uri: '',
|
|
544
|
-
own_transport_protocol: 0,
|
|
545
468
|
...this.config,
|
|
546
469
|
};
|
|
547
470
|
const host = (getNative() as unknown as NativeHost).protocol_new(
|
|
@@ -549,29 +472,15 @@ export class DeRecProtocolBuilder {
|
|
|
549
472
|
new Uint8Array(0),
|
|
550
473
|
this.stores,
|
|
551
474
|
) as NativeHost;
|
|
552
|
-
|
|
553
|
-
if (this.communicationInfo !== undefined) {
|
|
554
|
-
// `setCommunicationInfo` is asynchronous, but `build()` stays
|
|
555
|
-
// synchronous: the guarantee callers need is not that the map has been
|
|
556
|
-
// applied by the time `build()` returns, it is that no flow can run
|
|
557
|
-
// before it. Posting it here puts it on the protocol's serial worker
|
|
558
|
-
// queue ahead of anything the caller has had the chance to start, so
|
|
559
|
-
// every subsequent call observes it. Left unhandled deliberately — a
|
|
560
|
-
// failure reaches the runtime's unhandled-rejection reporting rather
|
|
561
|
-
// than being silently discarded, and `build()` has no synchronous
|
|
562
|
-
// channel to raise it on.
|
|
563
|
-
void protocol.setCommunicationInfo(this.communicationInfo);
|
|
564
|
-
}
|
|
565
|
-
return protocol;
|
|
475
|
+
return DeRecProtocol.fromHost(host);
|
|
566
476
|
}
|
|
567
477
|
}
|
|
568
478
|
|
|
569
479
|
/**
|
|
570
480
|
* Thin wrapper around the `ProtocolHost` JSI host object, mirroring
|
|
571
481
|
* `@derec-alliance/nodejs`'s `DeRecProtocol` — same methods, and the same
|
|
572
|
-
* sync/async split
|
|
573
|
-
*
|
|
574
|
-
* `secretId` is synchronous and everything else returns a `Promise`. Every method encodes its
|
|
482
|
+
* sync/async split: `secretId` is synchronous and everything else returns a
|
|
483
|
+
* `Promise`. Every method encodes its
|
|
575
484
|
* arguments into the wire shape the host function expects and decodes its
|
|
576
485
|
* result back into the typed value declared here; no protocol decision is
|
|
577
486
|
* made in this class.
|
|
@@ -601,68 +510,39 @@ export class DeRecProtocol {
|
|
|
601
510
|
}
|
|
602
511
|
|
|
603
512
|
/**
|
|
604
|
-
*
|
|
605
|
-
* `void`. The native setter takes the same handle mutex a running flow
|
|
606
|
-
* holds across its store callbacks, so calling it on the JavaScript thread
|
|
607
|
-
* would block that thread until the flow released the mutex — which it
|
|
608
|
-
* cannot do while it is waiting on the JavaScript thread. The binding
|
|
609
|
-
* therefore queues the setter onto the same serial worker every flow runs
|
|
610
|
-
* on, which orders it after any call already in flight. The nodejs SDK is
|
|
611
|
-
* WASM and single-threaded, so it has no such hazard.
|
|
513
|
+
* Replaces this node's local communication info.
|
|
612
514
|
*
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
*
|
|
515
|
+
* The native setter takes the same handle mutex a running flow holds
|
|
516
|
+
* across its store callbacks, so calling it on the JavaScript thread would
|
|
517
|
+
* block that thread until the flow released the mutex — which it cannot do
|
|
518
|
+
* while it is waiting on the JavaScript thread. The binding therefore
|
|
519
|
+
* queues the setter onto the same serial worker every flow runs on, which
|
|
520
|
+
* orders it after any call already in flight. Awaiting the returned
|
|
521
|
+
* `Promise` surfaces a failure that would otherwise be swallowed.
|
|
616
522
|
*/
|
|
617
523
|
setCommunicationInfo(info: Record<string, string>): Promise<void> {
|
|
618
524
|
return this.host.setCommunicationInfo(jsonToBytes(info)) as Promise<void>;
|
|
619
525
|
}
|
|
620
526
|
|
|
621
|
-
/**
|
|
622
|
-
* Replace this node's endpoint for one protocol, leaving the others
|
|
623
|
-
* alone. A node serves at most one endpoint per protocol, so the
|
|
624
|
-
* `(uri, protocol)` pair identifies the entry it replaces; an entry for a
|
|
625
|
-
* protocol not yet served is appended, and a replaced one keeps its
|
|
626
|
-
* position in the preference order.
|
|
627
|
-
*
|
|
628
|
-
* Returns a `Promise` for the same reason {@link setCommunicationInfo} does.
|
|
629
|
-
*
|
|
630
|
-
* @deprecated Use {@link setOwnTransports}, which takes the whole
|
|
631
|
-
* preference list and is the only way to change which protocols this node
|
|
632
|
-
* serves, or their order. Removed at 0.0.5.
|
|
633
|
-
*/
|
|
634
|
-
setOwnTransport(uri: string, protocol: string): Promise<void> {
|
|
635
|
-
return this.host.setOwnTransport(
|
|
636
|
-
uri,
|
|
637
|
-
protocolDiscriminant(protocol),
|
|
638
|
-
) as Promise<void>;
|
|
639
|
-
}
|
|
640
|
-
|
|
641
527
|
/**
|
|
642
528
|
* Replaces every endpoint this node advertises, in preference order —
|
|
643
|
-
* the runtime counterpart to `withOwnTransports
|
|
644
|
-
* change a multi-endpoint node's set ({@link setOwnTransport} collapses
|
|
645
|
-
* it to the one endpoint it is given).
|
|
529
|
+
* the runtime counterpart to `withOwnTransports`.
|
|
646
530
|
*
|
|
647
531
|
* Every entry is validated before any is stored, so a malformed URI
|
|
648
532
|
* leaves the previous set intact. An empty array is rejected.
|
|
649
533
|
*
|
|
650
|
-
*
|
|
534
|
+
* Queued onto the serial worker for the same reason as
|
|
535
|
+
* {@link setCommunicationInfo}.
|
|
651
536
|
*/
|
|
652
|
-
setOwnTransports(
|
|
653
|
-
transports
|
|
654
|
-
): Promise<void> {
|
|
655
|
-
const wire = transports.map(({ uri, protocol }) => ({
|
|
656
|
-
uri,
|
|
657
|
-
protocol: protocolDiscriminant(protocol),
|
|
658
|
-
}));
|
|
537
|
+
setOwnTransports(transports: Endpoint[]): Promise<void> {
|
|
538
|
+
const wire = transports.map(({ uri, protocol }) => ({ uri, protocol }));
|
|
659
539
|
return this.host.setOwnTransports(jsonToBytes(wire)) as Promise<void>;
|
|
660
540
|
}
|
|
661
541
|
|
|
662
542
|
/**
|
|
663
543
|
* Decodes the `contact_wire_bytes` `derec_protocol_create_contact`
|
|
664
544
|
* produces into a typed `ContactMessage`, so an application can read the
|
|
665
|
-
* contact's `nonce`, `
|
|
545
|
+
* contact's `nonce`, `supported_transports` and mode without a protobuf
|
|
666
546
|
* codec of its own. Feed the returned object straight back into
|
|
667
547
|
* `start(FlowKind.Pairing, { contact })`, which re-encodes it.
|
|
668
548
|
*/
|
|
@@ -713,7 +593,7 @@ export class DeRecProtocol {
|
|
|
713
593
|
return decodeEvents(buffer);
|
|
714
594
|
}
|
|
715
595
|
|
|
716
|
-
async reject(actionBytes: Uint8Array, status:
|
|
596
|
+
async reject(actionBytes: Uint8Array, status: StatusEnum, memo: string): Promise<void> {
|
|
717
597
|
await this.host.reject(actionBytes, status, memo);
|
|
718
598
|
}
|
|
719
599
|
|
|
@@ -730,6 +610,21 @@ export class DeRecProtocol {
|
|
|
730
610
|
return jsonFromBytes(buffer) as string[];
|
|
731
611
|
}
|
|
732
612
|
|
|
613
|
+
/**
|
|
614
|
+
* Rebuild this protocol's `secret_id` namespace from a recovered `Secret`.
|
|
615
|
+
* Pass the `secret` carried by the `SecretRecovered` event verbatim.
|
|
616
|
+
* A helper or member whose `transports` is empty gets no channel: it is
|
|
617
|
+
* reported as a `PeerNotRestored` event in the returned array and the rest
|
|
618
|
+
* of the roster is restored.
|
|
619
|
+
*
|
|
620
|
+
* Rejects with a `DeRecError`; among its codes:
|
|
621
|
+
*
|
|
622
|
+
* | code | meaning |
|
|
623
|
+
* |--------------------|-------------------------------------------------------------|
|
|
624
|
+
* | `already_restored` | A user-secret snapshot already exists for this `secret_id`. |
|
|
625
|
+
* | `restore_conflict` | Channels live at ids restore is about to write. The error |
|
|
626
|
+
* | | carries `channel_ids: string[]` listing the collisions. |
|
|
627
|
+
*/
|
|
733
628
|
async restore(
|
|
734
629
|
recoveredSecret: Extract<DeRecEvent, { type: 'SecretRecovered' }>['secret'],
|
|
735
630
|
version: number,
|
|
@@ -743,4 +638,9 @@ export class DeRecProtocol {
|
|
|
743
638
|
free(): void {
|
|
744
639
|
this.host.free();
|
|
745
640
|
}
|
|
641
|
+
|
|
642
|
+
/** Same as {@link DeRecProtocol.free}, for `using`. */
|
|
643
|
+
[Symbol.dispose](): void {
|
|
644
|
+
this.free();
|
|
645
|
+
}
|
|
746
646
|
}
|