@derec-alliance/nodejs 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 CHANGED
@@ -126,7 +126,7 @@ const request = primitives.pairing.request.produce(
126
126
 
127
127
  // Step 3: Initiator extracts the request and produces the response.
128
128
  const { request: pairRequest } =
129
- primitives.pairing.request.extract(request.envelope, contact.secret_key);
129
+ primitives.pairing.request.extract(request.envelope, contact.secret_key, null);
130
130
  const produced = primitives.pairing.response.produce(
131
131
  channelId,
132
132
  pairRequest,
@@ -141,6 +141,7 @@ const processed = primitives.pairing.response.process(
141
141
  request.initiator_contact_message,
142
142
  pairResponse,
143
143
  request.secret_key,
144
+ null,
144
145
  );
145
146
 
146
147
  // Both sides hold the same shared key and rekeyed channel id.
@@ -227,7 +228,7 @@ The orchestrator handles the whole chain automatically:
227
228
  `ActionRequired` event with `action_kind: "PrePair"`. Call
228
229
  `protocol.accept(action)` to publish the keys (the library builds the
229
230
  response and routes it), or `protocol.reject(action, status, memo)` to
230
- refuse.
231
+ refuse — `status` is a `StatusEnum` value such as `StatusEnum.Rejected`.
231
232
  - **Scanner** — `protocol.start(FlowKind.Pairing, { kind, contact })` kicks
232
233
  off the plaintext PrePair leg. `start()` returns a `DeRecEvent[]`
233
234
  containing one `PairingStarted { channel_id, kind }` event that
@@ -316,12 +317,22 @@ const recovered = primitives.recovery.response.recover(
316
317
  // `recovered` is a Uint8Array carrying the reconstructed secret payload.
317
318
  ```
318
319
 
319
- When driving the protocol layer instead of the primitives, the recovering
320
- device receives a `SecretRecovered` event carrying the typed `secret`. Pass it
320
+ When driving the protocol layer instead of the primitives, a helper that
321
+ answers with a share that cannot be part of the secret is reported as a
322
+ `RecoveryShareCorrupted` event (`reason`: `"Malformed"`, `"InvalidProof"` or
323
+ `"Inconsistent"`); the share is set aside and never blocks the recovery from
324
+ the others. An honest helper never sends one, so treat it as a sign of a
325
+ damaged or compromised helper — for example, offer to unpair it.
326
+
327
+ The recovering device receives a `SecretRecovered` event carrying the typed
328
+ `secret`. Pass it
321
329
  to `protocol.restore(secret, version)` on a fresh `DeRecProtocol` instance to
322
330
  commit canonical helper / replica state and wipe the throwaway recovery-mode
323
331
  channels — at that point the device resumes normal operation as if the secret
324
332
  had been protected here originally.
333
+ A helper or member with no endpoint in the recovered roster gets no channel;
334
+ `restore` returns a `PeerNotRestored` event for it (`reason: "NoTransports"`)
335
+ and restores the rest.
325
336
 
326
337
  ```ts
327
338
  const events = await protocol.process(responseBytes);
@@ -332,8 +343,10 @@ for (const ev of events) {
332
343
  }
333
344
  ```
334
345
 
335
- Errors surface as objects with a `code` field — `ALREADY_RESTORED`,
336
- `CONFLICT` (with `channel_ids`), `INVARIANT`, or `STORAGE`.
346
+ Errors surface as a `DeRecError` with a `category` and `code` —
347
+ `already_restored`, `restore_conflict` (with `channel_ids`), `invariant`,
348
+ `invalid_recovered_secret` (a malformed `secret`), or `store_error` (a store call failed; `category`
349
+ names the store).
337
350
 
338
351
  > **Secret format:** the recoverable secret (the bytes helpers store and
339
352
  > recovery reconstructs) is `[version byte] · payload` — v1's payload is
@@ -380,6 +393,12 @@ console.log("Valid:", isValid);
380
393
  - No protobuf types are exposed
381
394
  - No cryptographic operations occur in JavaScript
382
395
  - Rust is the single source of truth
396
+ - Every `DeRecProtocol` method that touches protocol state returns a
397
+ `Promise`, including the `set*` setters. Overlapping calls on one
398
+ instance — a `tick()` timer firing while `process()` handles a message —
399
+ queue and run in the order they were made; they never collide. A store
400
+ or transport callback must not await a call on the instance that
401
+ invoked it, since that call waits behind the callback's own caller.
383
402
 
384
403
  ---
385
404
 
@@ -392,14 +411,18 @@ side runs as `SenderKind.ReplicaSource` (owns the secret), the other as
392
411
  with a stable `replicaId`:
393
412
 
394
413
  ```ts
395
- const owner = new DeRecProtocol(
396
- channelStore, shareStore, secretStore, transport,
397
- "https://owner.example.com", "https",
398
- /* threshold */ 2, /* keepVersionsCount */ 3,
399
- { name: "Owner" },
400
- null, null, null, null,
401
- /* replicaId */ 0xAAAA_AAAA_AAAA_AAAAn,
402
- );
414
+ const owner = new DeRecProtocolBuilder(secretId)
415
+ .withChannelStore(channelStore)
416
+ .withShareStore(shareStore)
417
+ .withSecretStore(secretStore)
418
+ .withUserSecretStore(userSecretStore)
419
+ .withStateStore(stateStore)
420
+ .withTransport(transport)
421
+ .withOwnTransports([{ uri: "https://owner.example.com", protocol: "https" }])
422
+ .withThreshold(2)
423
+ .withCommunicationInfo({ name: "Owner" })
424
+ .withReplicaId(0xAAAA_AAAA_AAAA_AAAAn)
425
+ .build();
403
426
  ```
404
427
 
405
428
  A typical Source↔Destination handshake:
@@ -452,6 +475,27 @@ End-to-end coverage lives in the repository's tests — see
452
475
 
453
476
  ---
454
477
 
478
+ ## When `process()` fails
479
+
480
+ `process()` settles expired deadlines (sharing-round and unpair timeouts)
481
+ before it handles the message, and those are never reported again. So when
482
+ the message then fails, the thrown `DeRecError` carries them: `events` holds
483
+ every event produced before the failure, and `channel_id` names the channel
484
+ the message came from (absent when the bytes were not a decodable envelope).
485
+ Handle the events as you would a successful call's, then the error:
486
+
487
+ ```ts
488
+ try {
489
+ handle(await protocol.process(bytes));
490
+ } catch (error) {
491
+ const failure = error as DeRecError;
492
+ handle(failure.events ?? []);
493
+ report(failure.channel_id, failure);
494
+ }
495
+ ```
496
+
497
+ ---
498
+
455
499
  ## Correlation and routing
456
500
 
457
501
  Two cross-cutting metadata fields appear on every channel-mode exchange:
@@ -461,13 +505,13 @@ Two cross-cutting metadata fields appear on every channel-mode exchange:
461
505
  end-to-end (random token on every outbound request, echo on every
462
506
  response). Primitive-only callers can manipulate it directly via
463
507
  `envelope.apply_trace_id(bytes, traceId)` and `envelope.read_trace_id(bytes)`.
464
- - **`replyTo`** — optional `TransportProtocol` on request bodies, telling
465
- the responder to route this exchange's response to an alternate endpoint.
508
+ - **`replyTo`** — optional `TransportProtocol` list on request bodies, telling
509
+ the responder to route this exchange's response to alternate endpoints.
466
510
  Set it per call (every `primitives.*.request.produce` takes a trailing
467
511
  `reply_to` arg) or protocol-wide with the `autoReplyTo` constructor flag
468
- on `DeRecProtocol` (stamps `replyTo = ownTransport` on every outbound
469
- request). Excludes pairing and `UpdateChannelInfo`, which already carry
470
- their own `transportProtocol` field.
512
+ on `DeRecProtocol` (stamps this node's own transports into `replyTo` on
513
+ every outbound request). Excludes pairing and `UpdateChannelInfo`, which
514
+ already carry their own `supportedTransports` field.
471
515
 
472
516
  The motivating case for `replyTo` is replicas: when Replica A sends a
473
517
  request on a channel the helper paired with sibling Replica B, the
@@ -554,13 +598,16 @@ that you can retire as soon as the PrePair leg completes.
554
598
 
555
599
  The recommended pattern is: pair on the ephemeral URI, then — as soon
556
600
  as the pairing completes on the contact creator side — call
557
- `setOwnTransports` with the permanent endpoint (`setOwnTransport` is
558
- deprecated and removed at 0.0.5) and start an
601
+ `setOwnTransports` with the permanent endpoint and start an
559
602
  `UpdateChannelInfo` flow against the peer to announce the swap. Once
560
603
  the peer acknowledges, retire the ephemeral URI. This keeps the
561
604
  plaintext PrePair window tight while letting subsequent traffic ride
562
605
  on the long-lived endpoint.
563
606
 
607
+ `UpdateChannelInfo` reaches helper channels only. A replica member that
608
+ changes its endpoint or `communication_info` publishes a new version first,
609
+ then updates its helpers; see [On a replica member](https://github.com/derecalliance/lib-derec/tree/main/library#on-a-replica-member).
610
+
564
611
  ### Replica fingerprint verification is mandatory
565
612
 
566
613
  Replica channels are created with `status: "Pending"` and remain there
@@ -571,6 +618,15 @@ target is still `Pending`. Treat verification as a required step in
571
618
  the pairing UX — a scanner that auto-pairs without it accepts a
572
619
  MITM-vulnerable replica.
573
620
 
621
+ Until a device confirms, it ignores everything the peer sends on that
622
+ channel: `process` changes no store, sends nothing back, and returns
623
+ `{ type: "MessageIgnored", channel_id, reason: "PendingVerification",
624
+ trace_id }`. This matters most for a replica destination. The source's own
625
+ confirmation publishes the vault immediately, so that copy usually arrives
626
+ before the destination's user has confirmed. Confirming does not replay it:
627
+ once the destination's `verifyFingerprint` resolves `true`, call
628
+ `start(FlowKind.ReplicaDiscovery)` to pull the copy from the source.
629
+
574
630
  ### The `derec.*` namespace in `communicationInfo` is library-owned
575
631
 
576
632
  `communicationInfo` is otherwise an opaque app-defined map, but every
Binary file
@@ -9,11 +9,12 @@
9
9
  * docs.
10
10
  *
11
11
  * Required setters: `withChannelStore`, `withShareStore`,
12
- * `withSecretStore`, `withTransport`, and either `withOwnTransport` or
13
- * `withOwnTransports`. Calling `build()` without all five throws.
12
+ * `withSecretStore`, `withUserSecretStore`, `withStateStore`,
13
+ * `withTransport`, and `withOwnTransports`. Calling `build()` without all
14
+ * seven throws.
14
15
  *
15
- * All optional setters carry the defaults documented on the Rust
16
- * builder.
16
+ * An optional setter that is never called leaves the Rust builder's default
17
+ * in force: the value is forwarded only when the application supplied one.
17
18
  */
18
19
  export class DeRecProtocolBuilder {
19
20
  free(): void;
@@ -43,7 +44,7 @@ export class DeRecProtocolBuilder {
43
44
  */
44
45
  withAutoAccept(policy: any): DeRecProtocolBuilder;
45
46
  /**
46
- * Whether outbound requests stamp `replyTo = ownTransport`.
47
+ * Whether outbound requests carry this node's own transports as their reply-to list.
47
48
  * Default: false.
48
49
  */
49
50
  withAutoReplyTo(enabled: boolean): DeRecProtocolBuilder;
@@ -57,34 +58,17 @@ export class DeRecProtocolBuilder {
57
58
  * `info` shape: `Record<string, string>`. Default: empty.
58
59
  */
59
60
  withCommunicationInfo(info: any): DeRecProtocolBuilder;
60
- /**
61
- * Number of recent versions each helper must retain. Default: 3.
62
- */
63
- withKeepVersionsCount(count: number): DeRecProtocolBuilder;
64
- /**
65
- * `endpoint` shape: `{ uri: string, protocol: string }`.
66
- * `protocol` is `"https"` or `"grpc"` (case-insensitive).
67
- *
68
- * @deprecated Use `withOwnTransports`, which takes the whole preference
69
- * list — `withOwnTransports([endpoint])` is the direct replacement.
70
- * Removed at 0.0.5.
71
- */
72
- withOwnTransport(endpoint: any): DeRecProtocolBuilder;
73
61
  /**
74
62
  * Every transport endpoint this application serves, in preference
75
63
  * order. `transports` is an array of `{ uri: string, protocol: string
76
64
  * }` objects, `protocol` being `"https"` or `"grpc"`
77
- * (case-insensitive), same shape as [`Self::with_own_transport`].
65
+ * (case-insensitive).
78
66
  *
79
67
  * The order is the application's own preference and decides which of
80
68
  * a peer's offered endpoints is used. Every listed transport must
81
69
  * actually be served, because delivery is push-only — listing an
82
70
  * endpoint this application does not serve makes pairing succeed and
83
71
  * replies vanish.
84
- *
85
- * Supersedes [`Self::with_own_transport`] for applications serving
86
- * more than one transport; the single-endpoint setter remains fully
87
- * supported.
88
72
  */
89
73
  withOwnTransports(transports: any[]): DeRecProtocolBuilder;
90
74
  /**
@@ -108,7 +92,7 @@ export class DeRecProtocolBuilder {
108
92
  withStateStore(store: any): DeRecProtocolBuilder;
109
93
  /**
110
94
  * Minimum number of shares required to reconstruct the secret.
111
- * Default: 3.
95
+ * Default: [`crate::protocol::DEFAULT_THRESHOLD`].
112
96
  */
113
97
  withThreshold(threshold: number): DeRecProtocolBuilder;
114
98
  /**
@@ -133,18 +117,13 @@ export class DeRecProtocolBuilder {
133
117
  withTimeouts(timeouts: any): DeRecProtocolBuilder;
134
118
  withTransport(transport: any): DeRecProtocolBuilder;
135
119
  /**
136
- * `ack` is `"required"` (default) or `"not_required"`.
120
+ * `ack` is exactly `"required"` (default) or `"not_required"`, naming
121
+ * [`UnpairAck::Required`] and [`UnpairAck::NotRequired`].
137
122
  */
138
123
  withUnpairAck(ack: string): DeRecProtocolBuilder;
139
124
  /**
140
125
  * Accept plaintext transport endpoints — `http://` and `grpc://`.
141
- * **Development only.** Default `false`. See `withUnsafeHttp` for the
142
- * conflict rule when both are set.
143
- */
144
- withUnsafeConnection(allow: boolean): DeRecProtocolBuilder;
145
- /**
146
- * Accept plaintext `http://` transport endpoints. **Development only.**
147
- * Default `false`.
126
+ * **Development only.** Default `false`.
148
127
  *
149
128
  * With it `false`, plaintext is accepted only for an endpoint this
150
129
  * device configured for *itself* that names loopback (`localhost`,
@@ -152,11 +131,8 @@ export class DeRecProtocolBuilder {
152
131
  * With it `true`, plaintext is accepted for any host on any path,
153
132
  * including endpoints a peer supplies. That is what makes the LAN case
154
133
  * work (a phone against a laptop), and why the name is blunt.
155
- *
156
- * Superseded by `withUnsafeConnection`; still honored, and wins on
157
- * conflict. Removed at 0.0.5.
158
134
  */
159
- withUnsafeHttp(allow: boolean): DeRecProtocolBuilder;
135
+ withUnsafeConnection(allow: boolean): DeRecProtocolBuilder;
160
136
  withUserSecretStore(store: any): DeRecProtocolBuilder;
161
137
  }
162
138
 
@@ -164,31 +140,46 @@ export class DeRecProtocolBuilder {
164
140
  * Higher-level DeRec protocol orchestrator for TypeScript/JavaScript consumers.
165
141
  *
166
142
  * Wraps [`crate::protocol::DeRecProtocol`] with JS-side store
167
- * and transport adapters so that a TypeScript application can drive all five
168
- * protocol flows without routing raw bytes manually.
143
+ * and transport adapters so that a TypeScript application can drive every
144
+ * protocol flow without routing raw bytes manually. Built with
145
+ * [`DeRecProtocolBuilderWasm`] (`DeRecProtocolBuilder` in JS).
169
146
  *
170
147
  * # Stores
171
148
  *
172
- * Pass four JS objects that implement the interfaces documented on each
173
- * parameter. All store methods must return `Promise`s — synchronous
174
- * implementations can wrap their result with `Promise.resolve(...)`.
149
+ * The five stores and the transport are JS objects implementing the
150
+ * `ChannelStore`, `ShareStore`, `SecretStore`, `UserSecretStore`,
151
+ * `StateStore` and `Transport` interfaces in `index.d.ts`. All their methods
152
+ * must return `Promise`s — synchronous implementations can wrap their result
153
+ * with `Promise.resolve(...)`.
175
154
  *
176
- * # Events
155
+ * # Concurrency
177
156
  *
178
- * [`process`](DeRecProtocolWasm::process) returns an `Array` of plain JS
179
- * objects, each with a `type` discriminant field:
157
+ * Every method that touches protocol state is `async` and runs under one
158
+ * lock per instance, so overlapping calls on the same instance — a
159
+ * `tick` timer firing while `process` handles an inbound message — queue
160
+ * and run one at a time, in the order they were made. Distinct instances
161
+ * do not share the lock: two instances bound to the same `secret_id` and
162
+ * the same stores must still be serialized by the caller.
180
163
  *
181
- * | `type` | Additional fields |
182
- * |--------------------|--------------------------------------------------------|
183
- * | `PairingCompleted` | `channel_id: string`, `pairing_channel_id: string`, `kind: number` |
184
- * | `ShareStored` | `channel_id: string`, `version: number` |
185
- * | `ShareConfirmed` | `channel_id: string`, `version: number` |
186
- * | `ShareVerified` | `channel_id: string`, `version: number` |
187
- * | `SecretsDiscovered`| `channel_id: string`, `secrets: SecretVersionEntry[]` |
188
- * | `SecretRecovered` | `secret: { helpers, secrets, replicas }` (same nested shape as `ReplicaSecretReceived.secret`) |
189
- * | `NoOp` | _(none)_ |
164
+ * A store or transport callback must not await a call on the instance
165
+ * that invoked it: that call queues behind the one waiting on the
166
+ * callback, and neither settles. Calling `free()` while a call is in
167
+ * flight throws.
190
168
  *
191
- * `SecretVersionEntry = { secret_id: bigint, versions: { version: number, description: string }[] }`
169
+ * Methods take `&self` for this reason: wasm-bindgen holds the borrow of
170
+ * the instance for an async call's whole lifetime, so under `&mut self` an
171
+ * overlapping call fails that borrow outside its promise and never
172
+ * settles.
173
+ *
174
+ * # Events
175
+ *
176
+ * [`process`](DeRecProtocolWasm::process), [`start`](DeRecProtocolWasm::start),
177
+ * [`accept`](DeRecProtocolWasm::accept), [`tick`](DeRecProtocolWasm::tick)
178
+ * and [`restore`](DeRecProtocolWasm::restore) return an `Array` of plain JS
179
+ * objects, one per [`crate::protocol::DeRecEvent`], each tagged by a `type`
180
+ * field naming the variant. Every `u64` identifier (`channel_id`,
181
+ * `secret_id`, `replica_id`, `trace_id`) is a decimal string. The full set of
182
+ * shapes is the `DeRecEvent` union in `index.d.ts`.
192
183
  */
193
184
  export class DeRecProtocolWasm {
194
185
  private constructor();
@@ -261,46 +252,36 @@ export class DeRecProtocolWasm {
261
252
  * # Returns
262
253
  *
263
254
  * An `Array` of removed channel ids as decimal strings.
255
+ *
256
+ * `older_than_secs` is a `u64`: a `bigint`, a non-negative safe-integer
257
+ * `number`, or a decimal string.
264
258
  */
265
- removeExpiredChannels(older_than_secs: number): Promise<any>;
259
+ removeExpiredChannels(older_than_secs: any): Promise<any>;
266
260
  /**
267
261
  * Rebuild this protocol's `secret_id` namespace from a recovered
268
262
  * `Secret`. Mirrors [`crate::protocol::DeRecProtocol::restore`] —
269
263
  * see that method for the full contract.
270
264
  *
271
265
  * `recoveredSecret` is the typed `Secret` object carried by the
272
- * `SecretRecovered` event; pass it verbatim.
266
+ * `SecretRecovered` event; pass it verbatim. A helper or member whose
267
+ * `transports` is empty, `null` or absent gets no channel; it is
268
+ * reported as a `PeerNotRestored` event in the returned array and the
269
+ * rest of the roster is restored.
273
270
  *
274
- * Errors surface as structured JS errors with a `code` field:
271
+ * Errors surface as a `DeRecError` (`category`, `code`, `message`):
275
272
  *
276
273
  * | code | meaning |
277
274
  * |--------------------|------------------------------------------------------------------|
278
- * | `ALREADY_RESTORED` | A user-secret snapshot already exists for this `secret_id`. |
279
- * | `CONFLICT` | Channels live at canonical helper / replica ids. The error |
275
+ * | `already_restored` | A user-secret snapshot already exists for this `secret_id`. |
276
+ * | `restore_conflict` | Channels live at ids restore is about to write. The error |
280
277
  * | | carries `channel_ids: string[]` listing the collisions. |
281
- * | `INVARIANT` | The recovered `Secret` is internally inconsistent. |
282
- * | `STORAGE` | A store I/O call failed mid-restore. |
278
+ * | `invariant` | The recovered `Secret` is internally inconsistent. |
279
+ * | `invalid_recovered_secret` | `recoveredSecret` is malformed — e.g. a missing or |
280
+ * | | non-decimal `channel_id` / `replica_id`. |
281
+ * | `store_error` | A store call failed mid-restore; `category` names the store. |
283
282
  */
284
283
  restore(recovered_secret: any, version: number): Promise<any>;
285
284
  /**
286
- * Generate an out-of-band contact message (QR code payload, deep link, …).
287
- *
288
- * Returns a plain JS `ContactMessage` object. The `channel_id` field identifies
289
- * the pairing session and will match the `channel_id` in the eventual
290
- * `PairingCompleted` event — read it directly from the returned object.
291
- *
292
- * The caller is responsible for serializing the contact for out-of-band
293
- * delivery (QR code, deep link, etc.). The peer passes the deserialized object
294
- * to [`start`](Self::start) with `FlowKind::Pairing`.
295
- *
296
- * # Arguments
297
- *
298
- * * `channel_id` — Optional `BigInt` channel identifier. Pass `null` or
299
- * `undefined` to have the library generate a random one.
300
- * * `contact_mode` — `0` for `InlineKeys` (keys embedded directly), `1`
301
- * for `HashedKeys` (contact carries only a SHA-384 binding hash; the
302
- * scanner fetches keys via a `PrePair` round-trip). `HashedKeys`
303
- * requires the protocol's `own_transport` to be ephemeral.
304
285
  * The secret identifier this protocol instance is bound to.
305
286
  */
306
287
  secretId(): bigint;
@@ -308,32 +289,13 @@ export class DeRecProtocolWasm {
308
289
  * Replace this node's local communication info. Does not contact peers —
309
290
  * follow up with a `start(UpdateChannelInfo, ...)` to propagate.
310
291
  */
311
- setCommunicationInfo(info: any): void;
312
- /**
313
- * Replace this node's endpoint for one protocol, leaving the others
314
- * alone. A node serves at most one endpoint per protocol, so the
315
- * `(uri, protocol)` pair identifies the entry it replaces; an entry for
316
- * a protocol not yet served is appended, and a replaced one keeps its
317
- * position in the preference order.
318
- *
319
- * @deprecated Use `setOwnTransports`, which takes the whole preference
320
- * list and is the only way to change which protocols this node serves,
321
- * or their order. Removed at 0.0.5.
322
- *
323
- * See `setCommunicationInfo` for the matching update-propagation
324
- * flow, and `setOwnTransports` to keep more than one endpoint.
325
- * IMPORTANT: keep the old endpoint operational during the changeover —
326
- * see the Rust docs on `set_own_transport` for the discipline.
327
- */
328
- setOwnTransport(uri: string, protocol: string): void;
292
+ setCommunicationInfo(info: any): Promise<void>;
329
293
  /**
330
294
  * Replace every endpoint this node advertises, in preference order.
331
295
  *
332
296
  * `transports` is an array of `{ uri: string, protocol: string }`
333
- * objects, same shape as `withOwnTransports`. The runtime counterpart
334
- * to that builder setter, and the way to change the whole set:
335
- * `setOwnTransport` replaces only the entry for the protocol its URI
336
- * names. A node serves at most one endpoint per protocol, so this list
297
+ * objects, same shape as `withOwnTransports`, and is its runtime
298
+ * counterpart. A node serves at most one endpoint per protocol, so this list
337
299
  * is a preference order over distinct protocols and two entries of the
338
300
  * same protocol are rejected.
339
301
  *
@@ -342,18 +304,17 @@ export class DeRecProtocolWasm {
342
304
  * operational during the changeover — see the Rust docs on
343
305
  * `set_own_transports` for the discipline.
344
306
  */
345
- setOwnTransports(transports: any[]): void;
307
+ setOwnTransports(transports: any[]): Promise<void>;
346
308
  /**
347
309
  * Unified entry point for initiating any protocol flow.
348
310
  *
349
311
  * # Arguments
350
312
  *
351
- * * `flow_kind` — Flow discriminant:
352
- * - `0` = Pairing (params: `{ kind: number, contact: ContactMessage, name?: string }`)
353
- * - `1` = Discovery (params: `{ target: BigInt | BigInt[] | null }`)
354
- * - `2` = ProtectSecret (params: `{ secrets: UserSecret[], description?: string }`)
355
- * - `3` = VerifyShares (params: `{ version: number, target: BigInt | BigInt[] | null }`)
356
- * - `4` = RecoverSecret (params: `{ secretId: Uint8Array, version: number }`)
313
+ * * `flow_kind` — `FlowKind` discriminant: `0` Pairing, `1` Discovery,
314
+ * `2` ProtectSecret, `3` VerifyShares, `4` RecoverSecret, `5` Unpair,
315
+ * `6` UpdateChannelInfo, `7` ReplicaDiscovery, `8` UnpairReplica.
316
+ * * `params` — the flow's parameters, declared per kind in `index.d.ts`
317
+ * as `PairingParams`, `DiscoveryParams`, … `UnpairReplicaParams`.
357
318
  *
358
319
  * # Returns
359
320
  *
@@ -411,30 +372,33 @@ export function envelope_apply_trace_id(envelope_bytes: Uint8Array, trace_id: bi
411
372
  export function envelope_read_trace_id(envelope_bytes: Uint8Array): bigint;
412
373
 
413
374
  /**
414
- * Structurally validate a JS-side [`ContactMessage`]. Throws on any
415
- * mode/field inconsistency (unknown `contact_mode`, mode/field mismatch,
416
- * wrong binding-hash length).
375
+ * A fresh replica identity. See [`crate::generate_replica_id`]: the caller
376
+ * persists it once per device and passes the same value on every protocol
377
+ * init. Never `0`.
417
378
  */
418
- export function pairing_contact_message_validate(contact_message: any): void;
379
+ export function generate_replica_id(): bigint;
380
+
381
+ /**
382
+ * The human-readable fingerprint of a pairing's shared key. Both ends derive
383
+ * the same value; comparing it out of band confirms the pairing.
384
+ */
385
+ export function pairing_fingerprint(shared_key: Uint8Array): string;
419
386
 
420
387
  export function pairing_request_create_contact(channel_id: bigint, contact_mode: number, transport_protocols: any, nonce: any): any;
421
388
 
422
389
  /**
423
- * Decodes a proto-encoded [`ContactMessage`]. Structurally validates the
424
- * decoded value before returning it to application code so consumers can
425
- * trust the mode/field invariants documented on the wire format.
390
+ * Decodes proto `ContactMessage` wire bytes. See
391
+ * [`crate::primitives::pairing::request::decode_contact`].
426
392
  */
427
393
  export function pairing_request_decode_contact(bytes: Uint8Array): any;
428
394
 
429
395
  /**
430
- * Encodes a [`ContactMessage`] to proto wire bytes. Structurally validates
431
- * the input first so a locally-constructed contact that violates the
432
- * mode/field invariant is rejected at the boundary rather than silently
433
- * serialized.
396
+ * Encodes a [`ContactMessage`] to proto wire bytes. See
397
+ * [`crate::primitives::pairing::request::encode_contact`].
434
398
  */
435
399
  export function pairing_request_encode_contact(contact_message: any): Uint8Array;
436
400
 
437
- export function pairing_request_extract(envelope_bytes: Uint8Array, secret_key: Uint8Array): any;
401
+ export function pairing_request_extract(envelope_bytes: Uint8Array, secret_key: Uint8Array, parameter_range: any): any;
438
402
 
439
403
  /**
440
404
  * Initiator-side: decode an inbound plaintext `PrePairRequest` envelope.
@@ -456,7 +420,7 @@ export function pairing_response_extract(envelope_bytes: Uint8Array, secret_key:
456
420
  */
457
421
  export function pairing_response_extract_pre_pair(envelope_bytes: Uint8Array): any;
458
422
 
459
- export function pairing_response_process(contact_message: any, response: any, secret_key: Uint8Array): any;
423
+ export function pairing_response_process(contact_message: any, response: any, secret_key: Uint8Array, parameter_range: any): any;
460
424
 
461
425
  /**
462
426
  * Scanner-side: validate the `PrePairResponse` against the contact's
@@ -464,6 +428,14 @@ export function pairing_response_process(contact_message: any, response: any, se
464
428
  */
465
429
  export function pairing_response_process_pre_pair(contact_message: any, response: any): any;
466
430
 
431
+ /**
432
+ * Scanner side of a `NO_KEYS` pairing: accept the contact creator's public
433
+ * keys. There is no binding hash to check them against, so the channel this
434
+ * leads to MUST stay unusable until both sides confirm `pairing_fingerprint`
435
+ * out of band.
436
+ */
437
+ export function pairing_response_process_pre_pair_no_keys(contact_message: any, response: any): any;
438
+
467
439
  export function pairing_response_produce(channel_id: bigint, request: any, secret_key: Uint8Array, communication_info: any, parameter_range: any, unsafe_connection: boolean): any;
468
440
 
469
441
  /**
@@ -471,6 +443,23 @@ export function pairing_response_produce(channel_id: bigint, request: any, secre
471
443
  */
472
444
  export function pairing_response_produce_pre_pair(channel_id: bigint, request: any, secret_key: Uint8Array): any;
473
445
 
446
+ /**
447
+ * Contact-creator side of a `NO_KEYS` pairing: generate key material and
448
+ * answer the `PrePairRequest` with its public half.
449
+ *
450
+ * The caller MUST first match the request's `nonce` against the contact it
451
+ * issued, and MUST keep the resulting channel unusable until both sides
452
+ * confirm `pairing_fingerprint` out of band.
453
+ */
454
+ export function pairing_response_produce_pre_pair_no_keys(channel_id: bigint, request: any): any;
455
+
456
+ /**
457
+ * The DeRec protocol version this build speaks — the `protocolVersionMajor`
458
+ * / `protocolVersionMinor` it writes into every envelope it produces —
459
+ * as `{ major, minor }`.
460
+ */
461
+ export function protocol_version(): any;
462
+
474
463
  export function recovery_request_extract(envelope_bytes: Uint8Array, shared_key: Uint8Array): any;
475
464
 
476
465
  export function recovery_request_produce(channel_id: bigint, secret_id: bigint, version: number, shared_key: Uint8Array, reply_to: any): any;