@minip2p/react-native 0.7.1 → 0.7.2

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/src/adapter.ts CHANGED
@@ -1,11 +1,6 @@
1
1
  /* oxlint-disable class-methods-use-this, complexity, func-style, max-classes-per-file, no-use-before-define -- The adapter keeps its contract-complete native endpoint and public SDK subclass together, and uses hoisted conversion helpers. */
2
2
 
3
- import {
4
- BackpressureError,
5
- MessageTooLargeError,
6
- Minip2pBase,
7
- NotPermittedError,
8
- } from "@minip2p/core";
3
+ import { Minip2pBase, StreamClosedError } from "@minip2p/core";
9
4
  import type {
10
5
  Bytes,
11
6
  ConnectionInfo,
@@ -15,7 +10,11 @@ import type {
15
10
  Reachability,
16
11
  RelayReservationInfo,
17
12
  } from "@minip2p/core";
18
- import { P2pEvent_Tags, resolveEndpointConfig } from "@minip2p/core/backend";
13
+ import {
14
+ P2pEvent_Tags,
15
+ resolveEndpointConfig,
16
+ typedFfiError,
17
+ } from "@minip2p/core/backend";
19
18
  import type {
20
19
  BackendConnectTarget,
21
20
  Minip2pBackend,
@@ -28,7 +27,6 @@ import type {
28
27
  import { EventDrain } from "./event-drain";
29
28
  import {
30
29
  ConnectTarget,
31
- FfiError_Tags,
32
30
  P2pEndpoint,
33
31
  circuitAddress as nativeCircuitAddress,
34
32
  generateSecretKey as nativeGenerateSecretKey,
@@ -153,10 +151,13 @@ class ReactNativeBackend implements Minip2pBackend {
153
151
  if (info === undefined) {
154
152
  return undefined;
155
153
  }
156
- const connId = this.#connectionIds.toPublic(info.connId);
157
- return info.remoteAddr === undefined
158
- ? { connId }
159
- : { connId, remoteAddr: info.remoteAddr };
154
+ return {
155
+ connId: this.#connectionIds.toPublic(info.connId),
156
+ ...(info.remoteAddr !== undefined && { remoteAddr: info.remoteAddr }),
157
+ ...(info.readyProtocols !== undefined && {
158
+ readyProtocols: info.readyProtocols,
159
+ }),
160
+ };
160
161
  }
161
162
 
162
163
  circuitAddress(relayAddress: string, peerId: string): string {
@@ -211,34 +212,49 @@ class ReactNativeBackend implements Minip2pBackend {
211
212
  };
212
213
  }
213
214
 
214
- sendStream(peerId: string, streamId: number, data: Uint8Array): void {
215
+ sendStream(
216
+ peerId: string,
217
+ connId: number,
218
+ streamId: number,
219
+ data: Uint8Array
220
+ ): void {
215
221
  translateErrors(() => {
216
222
  this.#endpoint.sendStream(
217
223
  peerId,
224
+ this.#connectionIds.toNative(connId),
218
225
  numberToU64(streamId, "streamId"),
219
226
  toArrayBuffer(data)
220
227
  );
221
228
  });
222
229
  }
223
230
 
224
- closeStreamWrite(peerId: string, streamId: number): void {
231
+ closeStreamWrite(peerId: string, connId: number, streamId: number): void {
225
232
  translateErrors(() => {
226
233
  this.#endpoint.closeStreamWrite(
227
234
  peerId,
235
+ this.#connectionIds.toNative(connId),
228
236
  numberToU64(streamId, "streamId")
229
237
  );
230
238
  });
231
239
  }
232
240
 
233
- resetStream(peerId: string, streamId: number): void {
241
+ resetStream(peerId: string, connId: number, streamId: number): void {
234
242
  translateErrors(() => {
235
- this.#endpoint.resetStream(peerId, numberToU64(streamId, "streamId"));
243
+ this.#endpoint.resetStream(
244
+ peerId,
245
+ this.#connectionIds.toNative(connId),
246
+ numberToU64(streamId, "streamId")
247
+ );
236
248
  });
237
249
  }
238
250
 
239
- abandonStream(peerId: string, streamId: number): void {
251
+ abandonStream(peerId: string, connId: number, streamId: number): void {
240
252
  translateErrors(() => {
241
- this.#endpoint.abandonStream(peerId, numberToU64(streamId, "streamId"));
253
+ this.#endpoint.abandonStream(
254
+ peerId,
255
+ this.#connectionIds.toNative(connId),
256
+ numberToU64(streamId, "streamId")
257
+ );
242
258
  });
243
259
  }
244
260
 
@@ -308,12 +324,13 @@ export function circuitAddress(relayAddress: string, peerId: string): string {
308
324
  * Native connection IDs span the full `u64` range, so they cannot round-trip
309
325
  * through a JavaScript `number`. Each endpoint owns one map so a native ID
310
326
  * resolves to the same public ID in events and synchronous results. An entry
311
- * is released once its `ConnectionClosed` event is normalized, which bounds
312
- * the map by live connections. Public numbers come from a counter that never
313
- * repeats, so an event arriving after the release gets a fresh number instead
314
- * of aliasing a live connection. Stream and connect-attempt IDs are not
315
- * mapped because they round-trip into native calls, and native allocates
316
- * them well inside the safe integer range.
327
+ * is released once its `ConnectionClosed`, or the `ConnectionReplaced` that
328
+ * retires it, is normalized, which bounds the map by live connections. Public
329
+ * numbers come from a counter that never repeats, so an event arriving after
330
+ * the release gets a fresh number instead of aliasing a live connection.
331
+ * Stream operations map the public ID back to native. Stream and
332
+ * connect-attempt IDs are not mapped because native allocates them well
333
+ * inside the safe integer range.
317
334
  */
318
335
  class ConnectionIdMap {
319
336
  readonly #publicByNative = new Map<bigint, number>();
@@ -332,6 +349,20 @@ class ConnectionIdMap {
332
349
  return publicId;
333
350
  }
334
351
 
352
+ /**
353
+ * The native ID behind a public one. Stream operations pass it back so
354
+ * native rejects a stream whose connection it already replaced. A released
355
+ * connection throws `StreamClosedError`: its stream operation can run after
356
+ * the release but before the SDK dispatches the ending event.
357
+ */
358
+ toNative(publicId: number): bigint {
359
+ const native = this.#nativeByPublic.get(publicId);
360
+ if (native === undefined) {
361
+ throw new StreamClosedError("The stream's connection ended");
362
+ }
363
+ return native;
364
+ }
365
+
335
366
  release(publicId: number): void {
336
367
  const native = this.#nativeByPublic.get(publicId);
337
368
  if (native !== undefined) {
@@ -354,6 +385,8 @@ function normalizeEvent(
354
385
  ) as P2pEvent;
355
386
  if (normalized.tag === P2pEvent_Tags.ConnectionClosed) {
356
387
  connectionIds.release(normalized.inner.connId);
388
+ } else if (normalized.tag === P2pEvent_Tags.ConnectionReplaced) {
389
+ connectionIds.release(normalized.inner.oldConnId);
357
390
  }
358
391
  return normalized;
359
392
  }
@@ -372,10 +405,17 @@ function normalizeReservation(
372
405
  return normalizeBigInts(reservation) as RelayReservationInfo;
373
406
  }
374
407
 
408
+ /** Event fields carrying a native connection ID. */
409
+ const CONNECTION_ID_KEYS: ReadonlySet<string> = new Set([
410
+ "connId",
411
+ "oldConnId",
412
+ "newConnId",
413
+ ]);
414
+
375
415
  /**
376
- * Converts native `bigint` fields to numbers. `connId` fields go through the
377
- * endpoint's connection map when one is supplied; every other `u64` keeps the
378
- * checked conversion.
416
+ * Converts native `bigint` fields to numbers. Connection ID fields go through
417
+ * the endpoint's connection map when one is supplied; every other `u64` keeps
418
+ * the checked conversion.
379
419
  */
380
420
  function normalizeBigInts(
381
421
  value: unknown,
@@ -383,7 +423,9 @@ function normalizeBigInts(
383
423
  key?: string
384
424
  ): unknown {
385
425
  if (typeof value === "bigint") {
386
- return key === "connId" && connectionIds !== undefined
426
+ return key !== undefined &&
427
+ CONNECTION_ID_KEYS.has(key) &&
428
+ connectionIds !== undefined
387
429
  ? connectionIds.toPublic(value)
388
430
  : u64ToNumber(value, "native u64");
389
431
  }
@@ -434,27 +476,16 @@ function translateErrors<T>(operation: () => T): T {
434
476
  try {
435
477
  return operation();
436
478
  } catch (error) {
437
- const tag = getErrorTag(error);
438
- switch (tag) {
439
- case FfiError_Tags.Backpressure: {
440
- throw new BackpressureError();
441
- }
442
- case FfiError_Tags.MessageTooLarge: {
443
- throw new MessageTooLargeError();
444
- }
445
- case FfiError_Tags.NotPermitted: {
446
- throw new NotPermittedError(getErrorDetail(error));
447
- }
448
- default: {
449
- throw error;
450
- }
451
- }
479
+ throw typedFfiError(getErrorTag(error), getErrorDetail(error)) ?? error;
452
480
  }
453
481
  }
454
482
 
455
- function getErrorTag(error: unknown): FfiError_Tags | undefined {
456
- return typeof error === "object" && error !== null && "tag" in error
457
- ? (error.tag as FfiError_Tags)
483
+ function getErrorTag(error: unknown): string | undefined {
484
+ return typeof error === "object" &&
485
+ error !== null &&
486
+ "tag" in error &&
487
+ typeof error.tag === "string"
488
+ ? error.tag
458
489
  : undefined;
459
490
  }
460
491
 
@@ -76,11 +76,11 @@ interface NativeModuleInterface {
76
76
  ubrn_uniffi_minip2p_ffi_fn_func_generate_secret_key(uniffi_out_err: UniffiRustCallStatus): Uint8Array;
77
77
  ubrn_uniffi_minip2p_ffi_fn_func_peer_id_from_secret_key(secretKey: Uint8Array, uniffi_out_err: UniffiRustCallStatus): Uint8Array;
78
78
  ubrn_uniffi_minip2p_ffi_fn_constructor_p2pendpoint_new(secretKey: Uint8Array, config: Uint8Array, uniffi_out_err: UniffiRustCallStatus): bigint;
79
- ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_abandon_stream(uniffiSelf: bigint, peerId: Uint8Array, streamId: bigint, uniffi_out_err: UniffiRustCallStatus): void;
79
+ ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_abandon_stream(uniffiSelf: bigint, peerId: Uint8Array, connId: bigint, streamId: bigint, uniffi_out_err: UniffiRustCallStatus): void;
80
80
  ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_active_reservation(uniffiSelf: bigint, uniffi_out_err: UniffiRustCallStatus): Uint8Array;
81
81
  ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_add_protocol(uniffiSelf: bigint, protocolId: Uint8Array, uniffi_out_err: UniffiRustCallStatus): void;
82
82
  ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_cancel_connect(uniffiSelf: bigint, id: bigint, uniffi_out_err: UniffiRustCallStatus): void;
83
- ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_close_stream_write(uniffiSelf: bigint, peerId: Uint8Array, streamId: bigint, uniffi_out_err: UniffiRustCallStatus): void;
83
+ ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_close_stream_write(uniffiSelf: bigint, peerId: Uint8Array, connId: bigint, streamId: bigint, uniffi_out_err: UniffiRustCallStatus): void;
84
84
  ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_connect(uniffiSelf: bigint, target: Uint8Array, uniffi_out_err: UniffiRustCallStatus): bigint;
85
85
  ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_connected_peers(uniffiSelf: bigint, uniffi_out_err: UniffiRustCallStatus): Uint8Array;
86
86
  ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_connection_info(uniffiSelf: bigint, peerId: Uint8Array, uniffi_out_err: UniffiRustCallStatus): Uint8Array;
@@ -98,8 +98,8 @@ interface NativeModuleInterface {
98
98
  ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_ping(uniffiSelf: bigint, peerId: Uint8Array, uniffi_out_err: UniffiRustCallStatus): void;
99
99
  ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_publish(uniffiSelf: bigint, topic: Uint8Array, data: Uint8Array, uniffi_out_err: UniffiRustCallStatus): void;
100
100
  ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_reachability(uniffiSelf: bigint, uniffi_out_err: UniffiRustCallStatus): Uint8Array;
101
- ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_reset_stream(uniffiSelf: bigint, peerId: Uint8Array, streamId: bigint, uniffi_out_err: UniffiRustCallStatus): void;
102
- ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_send_stream(uniffiSelf: bigint, peerId: Uint8Array, streamId: bigint, data: Uint8Array, uniffi_out_err: UniffiRustCallStatus): void;
101
+ ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_reset_stream(uniffiSelf: bigint, peerId: Uint8Array, connId: bigint, streamId: bigint, uniffi_out_err: UniffiRustCallStatus): void;
102
+ ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_send_stream(uniffiSelf: bigint, peerId: Uint8Array, connId: bigint, streamId: bigint, data: Uint8Array, uniffi_out_err: UniffiRustCallStatus): void;
103
103
  ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_set_active(uniffiSelf: bigint, active: number, uniffi_out_err: UniffiRustCallStatus): void;
104
104
  ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_start(uniffiSelf: bigint, doorbell: bigint, uniffi_out_err: UniffiRustCallStatus): void;
105
105
  ubrn_uniffi_minip2p_ffi_fn_method_p2pendpoint_stop(uniffiSelf: bigint, uniffi_out_err: UniffiRustCallStatus): void;