@net-mesh/browser 0.44.1 → 0.45.1

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/CHANGELOG.md CHANGED
@@ -14,6 +14,26 @@ missing method at the call site rather than at install time. Unlike
14
14
  `@net-mesh/sdk`, this package never depends on `@net-mesh/core` — see
15
15
  the README on why it is a sibling package rather than a sub-path.
16
16
 
17
+ ## 0.45.1 — a closed stream keeps hearing its peer
18
+
19
+ - **Closing a stream no longer silences its peer.** After `close()`, frames
20
+ the peer still sends on that label reach `node.onEvent` as `stream_data`,
21
+ exactly as for a stream the page never opened. Before, the node dropped
22
+ them (counted `drops.stream_closed`) until the page reopened the stream,
23
+ so closing a stream was worse than never opening it. `stream_closed` is
24
+ no longer counted and reads 0.
25
+ - **A timed-out netcode player can rejoin.** `hostNetcode` closes a
26
+ player's stream when it times the player out, and only learns about a
27
+ player from its frames, so the change above was what locked a timed-out
28
+ player out for good. It is now re-admitted when heard again and carries
29
+ on from where it was applied.
30
+ - **A player cut off from its host stays quiet.** `joinNetcode` keeps at
31
+ most the newest 64 unacknowledged inputs (older ones were never sent
32
+ again anyway), keeps every input frame under one event (8,000 bytes) so
33
+ it never rides as fragments, and while the host has said nothing for a
34
+ second repeats its inputs only at the ping rate instead of with every
35
+ input. A cut-off player used to upload about 700 kB/s.
36
+
17
37
  ## 0.44.0 — sharded matches, compact snapshots
18
38
 
19
39
  - **`joinShards` merges a match split across several hosts** (topology A:
@@ -19,6 +19,16 @@ export class LeafNode {
19
19
  * `transport:rtc`; `reflex_addr` and `rtc_addr` stay absent.
20
20
  */
21
21
  announce(capabilities: string[]): Promise<void>;
22
+ /**
23
+ * Apply one signed grant-revocation bundle, and say how many grants
24
+ * it newly revoked.
25
+ *
26
+ * The grant twin of [`Self::apply_org_revocation_bundle`]: the
27
+ * bundle is verified in-leaf before anything moves, an org can
28
+ * revoke only grants it issued, and every live served call that
29
+ * rode on a revoked grant retires with the `Revoked` terminal.
30
+ */
31
+ apply_org_grant_revocation_bundle(bundle_hex: string): number;
22
32
  /**
23
33
  * Apply one signed revocation bundle from the control-plane
24
34
  * feed, and say how many floors it raised.
@@ -1345,6 +1355,7 @@ export interface InitOutput {
1345
1355
  readonly __wbg_proxystream_free: (a: number, b: number) => void;
1346
1356
  readonly leafnode_anchor_id_hex: (a: number, b: number) => void;
1347
1357
  readonly leafnode_announce: (a: number, b: number, c: number) => number;
1358
+ readonly leafnode_apply_org_grant_revocation_bundle: (a: number, b: number, c: number, d: number) => void;
1348
1359
  readonly leafnode_apply_org_revocation_bundle: (a: number, b: number, c: number, d: number) => void;
1349
1360
  readonly leafnode_arm_network_retry: (a: number, b: number) => void;
1350
1361
  readonly leafnode_call: (a: number, b: number, c: number, d: number, e: number, f: number) => number;
@@ -1451,16 +1462,16 @@ export interface InitOutput {
1451
1462
  readonly proxystream_send: (a: number, b: number) => number;
1452
1463
  readonly proxystream_stream_id_hex: (a: number, b: number) => void;
1453
1464
  readonly start: () => void;
1454
- readonly __wasm_bindgen_func_elem_6535: (a: number, b: number, c: number, d: number) => void;
1455
- readonly __wasm_bindgen_func_elem_6537: (a: number, b: number, c: number, d: number) => void;
1456
- readonly __wasm_bindgen_func_elem_2375: (a: number, b: number, c: number) => number;
1457
- readonly __wasm_bindgen_func_elem_2376: (a: number, b: number, c: number) => void;
1458
- readonly __wasm_bindgen_func_elem_2376_112: (a: number, b: number, c: number) => void;
1459
- readonly __wasm_bindgen_func_elem_2376_113: (a: number, b: number, c: number) => void;
1460
- readonly __wasm_bindgen_func_elem_2376_114: (a: number, b: number, c: number) => void;
1461
- readonly __wasm_bindgen_func_elem_2376_115: (a: number, b: number, c: number) => void;
1462
- readonly __wasm_bindgen_func_elem_2376_116: (a: number, b: number, c: number) => void;
1463
- readonly __wasm_bindgen_func_elem_2376_117: (a: number, b: number, c: number) => void;
1465
+ readonly __wasm_bindgen_func_elem_6615: (a: number, b: number, c: number, d: number) => void;
1466
+ readonly __wasm_bindgen_func_elem_6617: (a: number, b: number, c: number, d: number) => void;
1467
+ readonly __wasm_bindgen_func_elem_2432: (a: number, b: number, c: number) => number;
1468
+ readonly __wasm_bindgen_func_elem_2433: (a: number, b: number, c: number) => void;
1469
+ readonly __wasm_bindgen_func_elem_2433_113: (a: number, b: number, c: number) => void;
1470
+ readonly __wasm_bindgen_func_elem_2433_114: (a: number, b: number, c: number) => void;
1471
+ readonly __wasm_bindgen_func_elem_2433_115: (a: number, b: number, c: number) => void;
1472
+ readonly __wasm_bindgen_func_elem_2433_116: (a: number, b: number, c: number) => void;
1473
+ readonly __wasm_bindgen_func_elem_2433_117: (a: number, b: number, c: number) => void;
1474
+ readonly __wasm_bindgen_func_elem_2433_118: (a: number, b: number, c: number) => void;
1464
1475
  readonly __wbindgen_export: (a: number, b: number) => number;
1465
1476
  readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
1466
1477
  readonly __wbindgen_export3: (a: number) => void;
package/dist/net_leaf.js CHANGED
@@ -54,6 +54,34 @@ export class LeafNode {
54
54
  const ret = wasm.leafnode_announce(this.__wbg_ptr, ptr0, len0);
55
55
  return takeObject(ret);
56
56
  }
57
+ /**
58
+ * Apply one signed grant-revocation bundle, and say how many grants
59
+ * it newly revoked.
60
+ *
61
+ * The grant twin of [`Self::apply_org_revocation_bundle`]: the
62
+ * bundle is verified in-leaf before anything moves, an org can
63
+ * revoke only grants it issued, and every live served call that
64
+ * rode on a revoked grant retires with the `Revoked` terminal.
65
+ * @param {string} bundle_hex
66
+ * @returns {number}
67
+ */
68
+ apply_org_grant_revocation_bundle(bundle_hex) {
69
+ try {
70
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
71
+ const ptr0 = passStringToWasm0(bundle_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
72
+ const len0 = WASM_VECTOR_LEN;
73
+ wasm.leafnode_apply_org_grant_revocation_bundle(retptr, this.__wbg_ptr, ptr0, len0);
74
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
75
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
76
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
77
+ if (r2) {
78
+ throw takeObject(r1);
79
+ }
80
+ return r0 >>> 0;
81
+ } finally {
82
+ wasm.__wbindgen_add_to_stack_pointer(16);
83
+ }
84
+ }
57
85
  /**
58
86
  * Apply one signed revocation bundle from the control-plane
59
87
  * feed, and say how many floors it raised.
@@ -2712,13 +2740,13 @@ function __wbg_get_imports() {
2712
2740
  const ret = getObject(arg0).errorCode;
2713
2741
  return ret;
2714
2742
  },
2743
+ __wbg_error_0b48a92af341cfbc: function(arg0, arg1) {
2744
+ console.error(getStringFromWasm0(arg0, arg1));
2745
+ },
2715
2746
  __wbg_error_3da0c81bd4184d52: function(arg0) {
2716
2747
  const ret = getObject(arg0).error;
2717
2748
  return isLikeNone(ret) ? 0 : addHeapObject(ret);
2718
2749
  },
2719
- __wbg_error_5f3dc2db8f851959: function(arg0, arg1) {
2720
- console.error(getStringFromWasm0(arg0, arg1));
2721
- },
2722
2750
  __wbg_error_6a23b57453026a47: function() { return handleError(function (arg0) {
2723
2751
  const ret = getObject(arg0).error;
2724
2752
  return isLikeNone(ret) ? 0 : addHeapObject(ret);
@@ -2912,7 +2940,7 @@ function __wbg_get_imports() {
2912
2940
  const a = state0.a;
2913
2941
  state0.a = 0;
2914
2942
  try {
2915
- return __wasm_bindgen_func_elem_6537(a, state0.b, arg0, arg1);
2943
+ return __wasm_bindgen_func_elem_6617(a, state0.b, arg0, arg1);
2916
2944
  } finally {
2917
2945
  state0.a = a;
2918
2946
  }
@@ -2954,7 +2982,7 @@ function __wbg_get_imports() {
2954
2982
  const a = state0.a;
2955
2983
  state0.a = 0;
2956
2984
  try {
2957
- return __wasm_bindgen_func_elem_6537(a, state0.b, arg0, arg1);
2985
+ return __wasm_bindgen_func_elem_6617(a, state0.b, arg0, arg1);
2958
2986
  } finally {
2959
2987
  state0.a = a;
2960
2988
  }
@@ -3264,47 +3292,47 @@ function __wbg_get_imports() {
3264
3292
  },
3265
3293
  __wbindgen_generic_0000000000000001: function(arg0, arg1) {
3266
3294
  // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 34, ret: Externref, inner_ret: Some(Externref) }, mutable: true }) -> Externref`.
3267
- const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2375);
3295
+ const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2432);
3268
3296
  return addHeapObject(ret);
3269
3297
  },
3270
3298
  __wbindgen_generic_0000000000000002: function(arg0, arg1) {
3271
3299
  // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 35, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3272
- const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2376);
3300
+ const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2433);
3273
3301
  return addHeapObject(ret);
3274
3302
  },
3275
3303
  __wbindgen_generic_0000000000000003: function(arg0, arg1) {
3276
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 865, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
3277
- const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_6535);
3304
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 864, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
3305
+ const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_6615);
3278
3306
  return addHeapObject(ret);
3279
3307
  },
3280
3308
  __wbindgen_generic_0000000000000004: function(arg0, arg1) {
3281
3309
  // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("CloseEvent")], shim_idx: 35, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3282
- const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2376_112);
3310
+ const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2433_113);
3283
3311
  return addHeapObject(ret);
3284
3312
  },
3285
3313
  __wbindgen_generic_0000000000000005: function(arg0, arg1) {
3286
3314
  // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 35, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3287
- const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2376_113);
3315
+ const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2433_114);
3288
3316
  return addHeapObject(ret);
3289
3317
  },
3290
3318
  __wbindgen_generic_0000000000000006: function(arg0, arg1) {
3291
3319
  // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("MessageEvent")], shim_idx: 35, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3292
- const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2376_114);
3320
+ const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2433_115);
3293
3321
  return addHeapObject(ret);
3294
3322
  },
3295
3323
  __wbindgen_generic_0000000000000007: function(arg0, arg1) {
3296
3324
  // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("RTCDataChannelEvent")], shim_idx: 35, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3297
- const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2376_115);
3325
+ const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2433_116);
3298
3326
  return addHeapObject(ret);
3299
3327
  },
3300
3328
  __wbindgen_generic_0000000000000008: function(arg0, arg1) {
3301
3329
  // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("RTCPeerConnectionIceErrorEvent")], shim_idx: 35, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3302
- const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2376_116);
3330
+ const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2433_117);
3303
3331
  return addHeapObject(ret);
3304
3332
  },
3305
3333
  __wbindgen_generic_0000000000000009: function(arg0, arg1) {
3306
3334
  // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("RTCPeerConnectionIceEvent")], shim_idx: 35, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
3307
- const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2376_117);
3335
+ const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2433_118);
3308
3336
  return addHeapObject(ret);
3309
3337
  },
3310
3338
  __wbindgen_generic_000000000000000a: function(arg0) {
@@ -3331,47 +3359,47 @@ function __wbg_get_imports() {
3331
3359
  };
3332
3360
  }
3333
3361
 
3334
- function __wasm_bindgen_func_elem_2376(arg0, arg1, arg2) {
3335
- wasm.__wasm_bindgen_func_elem_2376(arg0, arg1, addHeapObject(arg2));
3362
+ function __wasm_bindgen_func_elem_2433(arg0, arg1, arg2) {
3363
+ wasm.__wasm_bindgen_func_elem_2433(arg0, arg1, addHeapObject(arg2));
3336
3364
  }
3337
3365
 
3338
- function __wasm_bindgen_func_elem_2376_112(arg0, arg1, arg2) {
3339
- wasm.__wasm_bindgen_func_elem_2376_112(arg0, arg1, addHeapObject(arg2));
3366
+ function __wasm_bindgen_func_elem_2433_113(arg0, arg1, arg2) {
3367
+ wasm.__wasm_bindgen_func_elem_2433_113(arg0, arg1, addHeapObject(arg2));
3340
3368
  }
3341
3369
 
3342
- function __wasm_bindgen_func_elem_2376_113(arg0, arg1, arg2) {
3343
- wasm.__wasm_bindgen_func_elem_2376_113(arg0, arg1, addHeapObject(arg2));
3370
+ function __wasm_bindgen_func_elem_2433_114(arg0, arg1, arg2) {
3371
+ wasm.__wasm_bindgen_func_elem_2433_114(arg0, arg1, addHeapObject(arg2));
3344
3372
  }
3345
3373
 
3346
- function __wasm_bindgen_func_elem_2376_114(arg0, arg1, arg2) {
3347
- wasm.__wasm_bindgen_func_elem_2376_114(arg0, arg1, addHeapObject(arg2));
3374
+ function __wasm_bindgen_func_elem_2433_115(arg0, arg1, arg2) {
3375
+ wasm.__wasm_bindgen_func_elem_2433_115(arg0, arg1, addHeapObject(arg2));
3348
3376
  }
3349
3377
 
3350
- function __wasm_bindgen_func_elem_2376_115(arg0, arg1, arg2) {
3351
- wasm.__wasm_bindgen_func_elem_2376_115(arg0, arg1, addHeapObject(arg2));
3378
+ function __wasm_bindgen_func_elem_2433_116(arg0, arg1, arg2) {
3379
+ wasm.__wasm_bindgen_func_elem_2433_116(arg0, arg1, addHeapObject(arg2));
3352
3380
  }
3353
3381
 
3354
- function __wasm_bindgen_func_elem_2376_116(arg0, arg1, arg2) {
3355
- wasm.__wasm_bindgen_func_elem_2376_116(arg0, arg1, addHeapObject(arg2));
3382
+ function __wasm_bindgen_func_elem_2433_117(arg0, arg1, arg2) {
3383
+ wasm.__wasm_bindgen_func_elem_2433_117(arg0, arg1, addHeapObject(arg2));
3356
3384
  }
3357
3385
 
3358
- function __wasm_bindgen_func_elem_2376_117(arg0, arg1, arg2) {
3359
- wasm.__wasm_bindgen_func_elem_2376_117(arg0, arg1, addHeapObject(arg2));
3386
+ function __wasm_bindgen_func_elem_2433_118(arg0, arg1, arg2) {
3387
+ wasm.__wasm_bindgen_func_elem_2433_118(arg0, arg1, addHeapObject(arg2));
3360
3388
  }
3361
3389
 
3362
- function __wasm_bindgen_func_elem_2375(arg0, arg1, arg2) {
3363
- const ret = wasm.__wasm_bindgen_func_elem_2375(arg0, arg1, addHeapObject(arg2));
3390
+ function __wasm_bindgen_func_elem_2432(arg0, arg1, arg2) {
3391
+ const ret = wasm.__wasm_bindgen_func_elem_2432(arg0, arg1, addHeapObject(arg2));
3364
3392
  return takeObject(ret);
3365
3393
  }
3366
3394
 
3367
- function __wasm_bindgen_func_elem_6537(arg0, arg1, arg2, arg3) {
3368
- wasm.__wasm_bindgen_func_elem_6537(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
3395
+ function __wasm_bindgen_func_elem_6617(arg0, arg1, arg2, arg3) {
3396
+ wasm.__wasm_bindgen_func_elem_6617(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
3369
3397
  }
3370
3398
 
3371
- function __wasm_bindgen_func_elem_6535(arg0, arg1, arg2) {
3399
+ function __wasm_bindgen_func_elem_6615(arg0, arg1, arg2) {
3372
3400
  try {
3373
3401
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
3374
- wasm.__wasm_bindgen_func_elem_6535(retptr, arg0, arg1, addHeapObject(arg2));
3402
+ wasm.__wasm_bindgen_func_elem_6615(retptr, arg0, arg1, addHeapObject(arg2));
3375
3403
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
3376
3404
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
3377
3405
  if (r1) {
Binary file
@@ -13,6 +13,7 @@ export const __wbg_orguploadcallhandle_free: (a: number, b: number) => void;
13
13
  export const __wbg_proxystream_free: (a: number, b: number) => void;
14
14
  export const leafnode_anchor_id_hex: (a: number, b: number) => void;
15
15
  export const leafnode_announce: (a: number, b: number, c: number) => number;
16
+ export const leafnode_apply_org_grant_revocation_bundle: (a: number, b: number, c: number, d: number) => void;
16
17
  export const leafnode_apply_org_revocation_bundle: (a: number, b: number, c: number, d: number) => void;
17
18
  export const leafnode_arm_network_retry: (a: number, b: number) => void;
18
19
  export const leafnode_call: (a: number, b: number, c: number, d: number, e: number, f: number) => number;
@@ -119,16 +120,16 @@ export const proxystream_peer_node_hex: (a: number, b: number) => void;
119
120
  export const proxystream_send: (a: number, b: number) => number;
120
121
  export const proxystream_stream_id_hex: (a: number, b: number) => void;
121
122
  export const start: () => void;
122
- export const __wasm_bindgen_func_elem_6535: (a: number, b: number, c: number, d: number) => void;
123
- export const __wasm_bindgen_func_elem_6537: (a: number, b: number, c: number, d: number) => void;
124
- export const __wasm_bindgen_func_elem_2375: (a: number, b: number, c: number) => number;
125
- export const __wasm_bindgen_func_elem_2376: (a: number, b: number, c: number) => void;
126
- export const __wasm_bindgen_func_elem_2376_112: (a: number, b: number, c: number) => void;
127
- export const __wasm_bindgen_func_elem_2376_113: (a: number, b: number, c: number) => void;
128
- export const __wasm_bindgen_func_elem_2376_114: (a: number, b: number, c: number) => void;
129
- export const __wasm_bindgen_func_elem_2376_115: (a: number, b: number, c: number) => void;
130
- export const __wasm_bindgen_func_elem_2376_116: (a: number, b: number, c: number) => void;
131
- export const __wasm_bindgen_func_elem_2376_117: (a: number, b: number, c: number) => void;
123
+ export const __wasm_bindgen_func_elem_6615: (a: number, b: number, c: number, d: number) => void;
124
+ export const __wasm_bindgen_func_elem_6617: (a: number, b: number, c: number, d: number) => void;
125
+ export const __wasm_bindgen_func_elem_2432: (a: number, b: number, c: number) => number;
126
+ export const __wasm_bindgen_func_elem_2433: (a: number, b: number, c: number) => void;
127
+ export const __wasm_bindgen_func_elem_2433_113: (a: number, b: number, c: number) => void;
128
+ export const __wasm_bindgen_func_elem_2433_114: (a: number, b: number, c: number) => void;
129
+ export const __wasm_bindgen_func_elem_2433_115: (a: number, b: number, c: number) => void;
130
+ export const __wasm_bindgen_func_elem_2433_116: (a: number, b: number, c: number) => void;
131
+ export const __wasm_bindgen_func_elem_2433_117: (a: number, b: number, c: number) => void;
132
+ export const __wasm_bindgen_func_elem_2433_118: (a: number, b: number, c: number) => void;
132
133
  export const __wbindgen_export: (a: number, b: number) => number;
133
134
  export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
134
135
  export const __wbindgen_export3: (a: number) => void;
@@ -34,6 +34,20 @@ export class NetcodeError extends Error {
34
34
  * ticks, and a host skips the gap the earlier frame would have filled.
35
35
  */
36
36
  const MAX_INPUT_BACKLOG = 64;
37
+ /**
38
+ * Largest input frame, bytes. Under one event, as the host's snapshot
39
+ * default is, so an input frame never rides as fragments: on the lossy
40
+ * carrier one lost fragment loses the whole frame. A backlog that does not
41
+ * fit sends its newest inputs.
42
+ */
43
+ const MAX_INPUT_FRAME_BYTES = 8000;
44
+ /**
45
+ * How long the host may say nothing before input frames stop going out at
46
+ * the input rate, ms. While it is silent, unacknowledged inputs are repeated
47
+ * only on the ping timer: a player cut off from its host used to send its
48
+ * whole backlog, as fragments, with every input (~700 kB/s, net-fps report).
49
+ */
50
+ const HOST_SILENT_MS = 1000;
37
51
  /** A fresh {@link InputSequencer}: `seq` 0, nothing pending. */
38
52
  export function createInputSequencer() {
39
53
  return { seq: 0, pending: [] };
@@ -121,11 +135,23 @@ export function joinNetcode(options) {
121
135
  let lastSnapshotAt = null;
122
136
  const inputEpoch = () => (options.epoch === undefined ? {} : { ep: options.epoch() });
123
137
  // The newest `redundancy` inputs — or, past that, the whole backlog up to
124
- // MAX_INPUT_BACKLOG, in one frame.
138
+ // MAX_INPUT_BACKLOG, in one frame of at most MAX_INPUT_FRAME_BYTES. A
139
+ // backlog too big for one frame sends its newest inputs: a host skips
140
+ // whatever an earlier frame would have filled anyway.
125
141
  const sendInputs = () => {
126
- const count = inputs.pending.length > redundancy ? MAX_INPUT_BACKLOG : redundancy;
127
- send({ n: label, k: 'i', i: inputs.pending.slice(-count), ...inputEpoch() });
142
+ let count = Math.min(inputs.pending.length, inputs.pending.length > redundancy ? MAX_INPUT_BACKLOG : redundancy);
143
+ for (;;) {
144
+ const bytes = encodeFrame({ n: label, k: 'i', i: inputs.pending.slice(-count), ...inputEpoch() });
145
+ if (bytes.byteLength <= MAX_INPUT_FRAME_BYTES || count <= 1) {
146
+ sendBytes(bytes);
147
+ return;
148
+ }
149
+ count = Math.max(1, Math.min(count - 1, Math.floor((count * MAX_INPUT_FRAME_BYTES) / bytes.byteLength)));
150
+ }
128
151
  };
152
+ // When the host was last heard from: any frame of this label, or binary.
153
+ let hostHeardAt = now();
154
+ const hostSilent = () => now() - hostHeardAt > HOST_SILENT_MS;
129
155
  const offset = () => clock.estimate()?.offsetMs ?? null;
130
156
  const hostNow = () => {
131
157
  const o = offset();
@@ -191,7 +217,8 @@ export function joinNetcode(options) {
191
217
  // replaced (a reconnect, a relayed → direct upgrade) and a stream handle
192
218
  // is fenced to the session it was opened on. The protocol repeats what
193
219
  // was lost, so reopening is all recovery needs.
194
- const send = (frame) => {
220
+ const send = (frame) => sendBytes(encodeFrame(frame));
221
+ const sendBytes = (payload) => {
195
222
  const current = stream;
196
223
  if (current === null) {
197
224
  void open();
@@ -211,7 +238,7 @@ export function joinNetcode(options) {
211
238
  }
212
239
  };
213
240
  try {
214
- void Promise.resolve(current.send(encodeFrame(frame))).catch(retire);
241
+ void Promise.resolve(current.send(payload)).catch(retire);
215
242
  }
216
243
  catch (error) {
217
244
  retire(error);
@@ -223,12 +250,14 @@ export function joinNetcode(options) {
223
250
  if (eventPeer(event.peerNode) !== host)
224
251
  return;
225
252
  if (isBinaryFrame(event.payload)) {
253
+ hostHeardAt = now();
226
254
  onBinary(event.payload);
227
255
  return;
228
256
  }
229
257
  const frame = decodeFrame(event.payload, label);
230
258
  if (frame === null)
231
259
  return;
260
+ hostHeardAt = now();
232
261
  if (frame.k === 'q') {
233
262
  clock.add(frame.t0, frame.t1, frame.t2, now());
234
263
  return;
@@ -492,12 +521,18 @@ export function joinNetcode(options) {
492
521
  const seq = inputs.seq;
493
522
  const seen = (hostNow() ?? now()) - delay;
494
523
  inputs.pending.push({ seq, seen, data });
524
+ // Only the newest MAX_INPUT_BACKLOG are ever sent again, so older
525
+ // ones are dropped rather than held (and replayed) until an ack.
526
+ if (inputs.pending.length > MAX_INPUT_BACKLOG)
527
+ inputs.pending.splice(0, inputs.pending.length - MAX_INPUT_BACKLOG);
495
528
  if (options.local && predicted !== null) {
496
529
  predicted = options.local.predict(predicted, data);
497
530
  if (correcting !== null)
498
531
  correcting = { ...correcting, from: options.local.predict(correcting.from, data) };
499
532
  }
500
- sendInputs();
533
+ // A silent host gets the backlog from the ping timer, not per input.
534
+ if (!hostSilent())
535
+ sendInputs();
501
536
  },
502
537
  view() {
503
538
  const at = hostNow();
package/dist/stream.d.ts CHANGED
@@ -179,7 +179,14 @@ export declare class LeafStream implements AsyncIterable<Uint8Array> {
179
179
  /** Listen for payloads. Returns a cancel handle. */
180
180
  onMessage(listener: (payload: Uint8Array) => void): () => void;
181
181
  [Symbol.asyncIterator](): AsyncIterableIterator<Uint8Array>;
182
- /** Close the stream and end every consumer. */
182
+ /**
183
+ * Close the stream and end every consumer.
184
+ *
185
+ * Close is local: the peer's half is its own. Frames the peer still
186
+ * sends on this label reach `node.onEvent` as `stream_data`, exactly as
187
+ * for a stream this page never opened. Before 0.45.1 the node dropped
188
+ * them (`drops.stream_closed`) until the stream was reopened.
189
+ */
183
190
  close(): void;
184
191
  /**
185
192
  * One callback from the wasm boundary.
package/dist/stream.js CHANGED
@@ -176,7 +176,14 @@ export class LeafStream {
176
176
  this.retiredBy = reason;
177
177
  this.close();
178
178
  }
179
- /** Close the stream and end every consumer. */
179
+ /**
180
+ * Close the stream and end every consumer.
181
+ *
182
+ * Close is local: the peer's half is its own. Frames the peer still
183
+ * sends on this label reach `node.onEvent` as `stream_data`, exactly as
184
+ * for a stream this page never opened. Before 0.45.1 the node dropped
185
+ * them (`drops.stream_closed`) until the stream was reopened.
186
+ */
180
187
  close() {
181
188
  if (this.closed)
182
189
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@net-mesh/browser",
3
- "version": "0.44.1",
3
+ "version": "0.45.1",
4
4
  "description": "Browser-native Net mesh leaf \u2014 idiomatic TypeScript over the net-mesh-leaf wasm node",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",