wenay-common2 1.0.74 → 1.0.76

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.
@@ -9,6 +9,7 @@ const rpc_limits_1 = require("./rpc-limits");
9
9
  const myThrow_1 = require("../../toError/myThrow");
10
10
  const rpc_off_1 = require("./rpc-off");
11
11
  const rpc_caps_1 = require("./rpc-caps");
12
+ const transport_lifecycle_1 = require("../events/transport-lifecycle");
12
13
  const SHARED_POOLS = new WeakMap();
13
14
  function sharedPool(socket, key) {
14
15
  let byKey = SHARED_POOLS.get(socket);
@@ -53,6 +54,28 @@ function listenKeyArg(a) {
53
54
  }
54
55
  return a;
55
56
  }
57
+ function createPathProxyCache() {
58
+ const values = new Map();
59
+ const registry = new FinalizationRegistry(function releaseProxy(entry) {
60
+ if (values.get(entry.key)?.token == entry.token)
61
+ values.delete(entry.key);
62
+ });
63
+ function get(path) {
64
+ const key = (0, rpc_path_1.rpcPathKey)(path);
65
+ const proxy = values.get(key)?.ref.deref();
66
+ if (!proxy)
67
+ values.delete(key);
68
+ return proxy;
69
+ }
70
+ function set(path, proxy) {
71
+ const key = (0, rpc_path_1.rpcPathKey)(path);
72
+ const token = {};
73
+ values.set(key, { ref: new WeakRef(proxy), token });
74
+ registry.register(proxy, { key, token });
75
+ return proxy;
76
+ }
77
+ return { get, set };
78
+ }
56
79
  const IS_RPC_PIPE = Symbol.for("isRpcPipe");
57
80
  function createClient(socket, key, opts) {
58
81
  const limit = opts?.limit ?? 10000;
@@ -67,6 +90,7 @@ function createClient(socket, key, opts) {
67
90
  const zombies = new Set();
68
91
  const retire = (id) => { zombies.add(id); };
69
92
  let disposed = false;
93
+ const transport = (0, transport_lifecycle_1.createTransportLifecycle)(true);
70
94
  let disconnectCbs = [];
71
95
  let disconnectResolve = () => { };
72
96
  const disconnectPromise = new Promise(res => { disconnectResolve = res; });
@@ -77,6 +101,7 @@ function createClient(socket, key, opts) {
77
101
  return (0, rpc_off_1.makeOff)(disconnectPromise, offDisconnect);
78
102
  }
79
103
  const routeCache = {};
104
+ let schemaKnown = false;
80
105
  let strictData = {};
81
106
  let strictWaiters = [];
82
107
  let debug = false;
@@ -138,6 +163,8 @@ function createClient(socket, key, opts) {
138
163
  break;
139
164
  }
140
165
  case rpc_protocol_1.Pkt.SHAPE: {
166
+ if (!callbacks.has(msg[1]))
167
+ break;
141
168
  let m = compactShapes.get(msg[1]);
142
169
  if (!m) {
143
170
  m = [];
@@ -181,15 +208,17 @@ function createClient(socket, key, opts) {
181
208
  break;
182
209
  }
183
210
  case rpc_protocol_1.Pkt.MAP: {
211
+ schemaKnown = true;
184
212
  if (msg[1]) {
185
213
  for (const k of Object.keys(routeCache))
186
214
  delete routeCache[k];
187
215
  Object.assign(routeCache, msg[1]);
188
216
  }
189
217
  if (Array.isArray(msg[3])) {
190
- declaredListens ??= new Set();
191
- for (const p of msg[3])
192
- declaredListens.add(p);
218
+ declaredListens = new Set(msg[3]);
219
+ for (const sub of wireSubs.values()) {
220
+ sub.recoverable = declaredListens.has((0, rpc_path_1.rpcPathKey)(sub.path.slice(0, -1)));
221
+ }
193
222
  }
194
223
  if (msg[2]) {
195
224
  for (const k of Object.keys(strictData))
@@ -212,7 +241,9 @@ function createClient(socket, key, opts) {
212
241
  });
213
242
  const sendPipe = (path, steps, wait) => {
214
243
  if (disposed)
215
- return wait ? Promise.reject(new Error("RPC client disposed")) : Promise.resolve();
244
+ return wait ? Promise.reject(new Error('RPC client disposed')) : Promise.resolve();
245
+ if (!transport.api.connected())
246
+ return wait ? Promise.reject(new Error('RPC transport disconnected')) : Promise.resolve();
216
247
  const cbIds = [];
217
248
  const cleanSteps = steps.map(step => {
218
249
  if (step.type === 'call') {
@@ -225,15 +256,22 @@ function createClient(socket, key, opts) {
225
256
  socket.emit(key, [rpc_protocol_1.Pkt.PIPE, 0, ref, cleanSteps, false]);
226
257
  return Promise.resolve();
227
258
  }
228
- return new Promise((resolve, reject) => {
229
- if (pending.size >= limit)
230
- return reject(new Error("RPC limit"));
259
+ let record;
260
+ const promise = new Promise(function trackPipe(resolve, reject) {
261
+ if (pending.size >= limit) {
262
+ reject(new Error('RPC limit'));
263
+ return;
264
+ }
231
265
  const reqId = pool.next();
232
- pending.set(reqId, { ok: resolve, fail: reject, cbs: cbIds });
266
+ record = { ok: resolve, fail: reject, cbs: cbIds };
267
+ pending.set(reqId, record);
233
268
  if (debug)
234
- console.log("[RPC PIPE]", path.join("."), "steps=", steps.length, "id=", reqId);
269
+ console.log('[RPC PIPE]', path.join('.'), 'steps=', steps.length, 'id=', reqId);
235
270
  socket.emit(key, [rpc_protocol_1.Pkt.PIPE, reqId, ref, cleanSteps]);
236
271
  });
272
+ if (record)
273
+ record.promise = promise;
274
+ return promise;
237
275
  };
238
276
  const buildPipeProxy = (path, steps, wait) => {
239
277
  const proxy = new Proxy(function () { }, {
@@ -276,134 +314,324 @@ function createClient(socket, key, opts) {
276
314
  });
277
315
  return proxy;
278
316
  };
279
- const sendCallWire = (path, args, wait) => {
280
- if (disposed)
281
- return wait ? Promise.reject(new Error("RPC client disposed")) : Promise.resolve();
317
+ function createCallAttempt(path, args) {
318
+ if (disposed) {
319
+ return { promise: Promise.reject(new Error('RPC client disposed')), abandon: function abandonDisposed() { } };
320
+ }
321
+ if (!transport.api.connected()) {
322
+ return { promise: Promise.reject(new Error('RPC transport disconnected')), abandon: function abandonOffline() { } };
323
+ }
324
+ if (pending.size >= limit) {
325
+ return { promise: Promise.reject(new Error('RPC limit')), abandon: function abandonLimited() { } };
326
+ }
282
327
  const cbIds = [];
283
328
  const clean = (0, rpc_walk_1.pack)(args, pool, callbacks, cbIds);
284
329
  const ref = routeCache[(0, rpc_path_1.rpcPathKey)(path)] ?? path;
285
- if (!wait) {
286
- socket.emit(key, [rpc_protocol_1.Pkt.CALL, 0, ref, clean, false]);
287
- return Promise.resolve();
288
- }
289
- return new Promise((resolve, reject) => {
290
- if (pending.size >= limit)
291
- return reject(new Error("RPC limit"));
292
- const reqId = pool.next();
293
- pending.set(reqId, { ok: resolve, fail: reject, cbs: cbIds });
294
- if (debug)
295
- console.log("[RPC]", path.join("."), "id=", reqId);
296
- socket.emit(key, [rpc_protocol_1.Pkt.CALL, reqId, ref, clean]);
330
+ const reqId = pool.next();
331
+ let record;
332
+ const promise = new Promise(function trackCall(resolve, reject) {
333
+ record = { ok: resolve, fail: reject, cbs: cbIds };
334
+ pending.set(reqId, record);
297
335
  });
298
- };
336
+ record.promise = promise;
337
+ if (debug)
338
+ console.log('[RPC]', path.join('.'), 'id=', reqId);
339
+ socket.emit(key, [rpc_protocol_1.Pkt.CALL, reqId, ref, clean]);
340
+ function abandon(reason) {
341
+ if (pending.get(reqId) != record)
342
+ return;
343
+ pending.delete(reqId);
344
+ for (const cbId of cbIds) {
345
+ callbacks.delete(cbId);
346
+ compactShapes.delete(cbId);
347
+ }
348
+ record.fail(new Error(reason));
349
+ }
350
+ return { promise, abandon };
351
+ }
352
+ function sendCallWire(path, args, wait) {
353
+ if (disposed)
354
+ return wait ? Promise.reject(new Error('RPC client disposed')) : Promise.resolve();
355
+ if (!transport.api.connected())
356
+ return wait ? Promise.reject(new Error('RPC transport disconnected')) : Promise.resolve();
357
+ if (wait)
358
+ return createCallAttempt(path, args).promise;
359
+ const cbIds = [];
360
+ const clean = (0, rpc_walk_1.pack)(args, pool, callbacks, cbIds);
361
+ const ref = routeCache[(0, rpc_path_1.rpcPathKey)(path)] ?? path;
362
+ socket.emit(key, [rpc_protocol_1.Pkt.CALL, 0, ref, clean, false]);
363
+ return Promise.resolve();
364
+ }
299
365
  const dedupe = opts?.dedupeListen ?? true;
300
366
  const wireSubs = new Map();
301
367
  let declaredListens = null;
368
+ function finishLogical(sub) {
369
+ if (sub.ended)
370
+ return;
371
+ sub.ended = true;
372
+ sub.attempt = null;
373
+ if (wireSubs.get(sub.key) == sub)
374
+ wireSubs.delete(sub.key);
375
+ for (const consumer of sub.consumers)
376
+ consumer.resolve();
377
+ sub.consumers.clear();
378
+ }
379
+ function finishAttempt(sub, attempt) {
380
+ if (sub.attempt != attempt)
381
+ return;
382
+ sub.attempt = null;
383
+ finishLogical(sub);
384
+ }
385
+ function startAttempt(sub) {
386
+ if (disposed || sub.ended || sub.attempt || sub.consumers.size == 0 || !transport.api.connected())
387
+ return;
388
+ const attempt = { call: createCallAttempt(sub.path, sub.realArgs) };
389
+ sub.attempt = attempt;
390
+ attempt.call.promise.then(function physicalListenEnded() { finishAttempt(sub, attempt); }, function physicalListenFailed() { finishAttempt(sub, attempt); });
391
+ }
392
+ function stopLogical(sub, socketAlive = transport.api.connected()) {
393
+ if (sub.ended)
394
+ return;
395
+ const attempt = sub.attempt;
396
+ sub.attempt = null;
397
+ if (wireSubs.get(sub.key) == sub)
398
+ wireSubs.delete(sub.key);
399
+ sub.ended = true;
400
+ if (socketAlive && transport.api.connected()) {
401
+ sendCallWire([...sub.path.slice(0, -1), 'removeCallback'], [], false);
402
+ }
403
+ else {
404
+ attempt?.call.abandon('RPC Listen stopped while transport is disconnected');
405
+ }
406
+ for (const consumer of sub.consumers)
407
+ consumer.resolve();
408
+ sub.consumers.clear();
409
+ }
302
410
  function subscribeShared(path, args) {
303
411
  if (disposed)
304
- return Promise.reject(new Error("RPC client disposed"));
412
+ return Promise.reject(new Error('RPC client disposed'));
305
413
  const listenPathKey = (0, rpc_path_1.rpcPathKey)(path.slice(0, -1));
306
- const skey = listenPathKey + "::" + JSON.stringify(args.map(listenKeyArg));
414
+ const skey = listenPathKey + '::' + JSON.stringify(args.map(listenKeyArg));
307
415
  let sub = wireSubs.get(skey);
308
416
  if (!sub) {
309
- const created = { consumers: new Set(), stop: () => { } };
310
- wireSubs.set(skey, created);
311
417
  let fnPos = 0;
312
- const realArgs = args.map(a => {
313
- if (typeof a != "function")
314
- return a;
315
- const i = fnPos++;
316
- return (...ev) => {
317
- let err;
318
- created.consumers.forEach(c => {
418
+ const created = {
419
+ key: skey,
420
+ path: [...path],
421
+ realArgs: [],
422
+ consumers: new Set(),
423
+ attempt: null,
424
+ recoverable: declaredListens?.has(listenPathKey) == true,
425
+ ended: false,
426
+ stop: function stopCreated(socketAlive) { stopLogical(created, socketAlive); },
427
+ };
428
+ created.realArgs = args.map(function buildMultiplexer(arg) {
429
+ if (typeof arg != 'function')
430
+ return arg;
431
+ const index = fnPos++;
432
+ return function multicastListenEvent(...event) {
433
+ let error;
434
+ for (const consumer of created.consumers) {
319
435
  try {
320
- c.fns[i]?.(...ev);
436
+ consumer.fns[index]?.(...event);
321
437
  }
322
- catch (e) {
323
- err ??= e;
438
+ catch (caught) {
439
+ error ??= caught;
324
440
  }
325
- });
326
- if (err !== undefined)
327
- setTimeout(() => { throw err; }, 0);
441
+ }
442
+ if (error != undefined)
443
+ setTimeout(function rethrowConsumerError() { throw error; }, 0);
328
444
  };
329
445
  });
330
- const finish = () => {
331
- if (wireSubs.get(skey) == created)
332
- wireSubs.delete(skey);
333
- created.consumers.forEach(c => c.resolve());
334
- created.consumers.clear();
335
- };
336
- created.stop = () => {
337
- sendCallWire([...path.slice(0, -1), "removeCallback"], [], false);
338
- finish();
339
- };
340
- sendCallWire(path, realArgs, true).then(finish, finish);
446
+ wireSubs.set(skey, created);
341
447
  sub = created;
342
448
  }
343
- const consumer = { fns: args.filter(a => typeof a == "function"), resolve: () => { } };
449
+ const consumer = {
450
+ fns: args.filter(a => typeof a == 'function'),
451
+ resolve: function resolveLater() { },
452
+ };
344
453
  sub.consumers.add(consumer);
345
- const p = new Promise(res => { consumer.resolve = res; });
346
- const unsub = function unsubscribe() {
454
+ const promise = new Promise(function waitForListenEnd(resolve) { consumer.resolve = resolve; });
455
+ startAttempt(sub);
456
+ function unsubscribe() {
347
457
  if (!sub.consumers.delete(consumer))
348
458
  return;
349
459
  consumer.resolve();
350
460
  if (sub.consumers.size == 0)
351
461
  sub.stop();
352
- };
353
- return (0, rpc_off_1.makeOff)(p, unsub, { off: unsub, unsubscribe: unsub, removeCallback: unsub });
462
+ }
463
+ return (0, rpc_off_1.makeOff)(promise, unsubscribe, { off: unsubscribe, unsubscribe, removeCallback: unsubscribe });
464
+ }
465
+ function abandonTransportGeneration(reason) {
466
+ for (const sub of [...wireSubs.values()]) {
467
+ const attempt = sub.attempt;
468
+ sub.attempt = null;
469
+ attempt?.call.abandon(reason);
470
+ if (!sub.recoverable)
471
+ finishLogical(sub);
472
+ }
473
+ const error = new Error(reason);
474
+ for (const [id, request] of [...pending]) {
475
+ pending.delete(id);
476
+ for (const cbId of request.cbs) {
477
+ callbacks.delete(cbId);
478
+ compactShapes.delete(cbId);
479
+ }
480
+ request.promise?.catch(function consumeAbandonedTransportReject() { });
481
+ request.fail(error);
482
+ }
483
+ callbacks.clear();
484
+ compactShapes.clear();
485
+ }
486
+ function transportDisconnected(reason) {
487
+ abandonTransportGeneration('RPC transport disconnected: ' + reason);
488
+ schemaKnown = false;
489
+ capsSent = false;
490
+ peerServerCaps = 0;
491
+ declaredListens = declaredListens ? new Set() : null;
492
+ for (const route of Object.keys(routeCache))
493
+ delete routeCache[route];
494
+ authStatus = undefined;
495
+ authPending = false;
496
+ const strict = strictWaiters;
497
+ strictWaiters = [];
498
+ for (const resolve of strict)
499
+ resolve(undefined);
500
+ const auths = authWaiters;
501
+ authWaiters = [];
502
+ for (const resolve of auths)
503
+ resolve({ ok: false, reason });
354
504
  }
505
+ function transportConnected() {
506
+ for (const sub of [...wireSubs.values()]) {
507
+ if (sub.recoverable)
508
+ startAttempt(sub);
509
+ else
510
+ finishLogical(sub);
511
+ }
512
+ }
513
+ transport.api.onDisconnect(transportDisconnected);
514
+ transport.api.onConnect(transportConnected);
355
515
  const sendCall = (path, args, wait) => {
356
516
  const last = path[path.length - 1];
357
517
  if (dedupe && wait && path.length > 1 && (last == "callback" || last == "on") && args.some(a => typeof a == "function")) {
518
+ if (!transport.api.connected())
519
+ return sendCallWire(path, args, wait);
358
520
  const isListen = declaredListens ? declaredListens.has((0, rpc_path_1.rpcPathKey)(path.slice(0, -1))) : true;
359
521
  if (isListen)
360
522
  return subscribeShared(path, args);
361
523
  }
362
524
  return sendCallWire(path, args, wait);
363
525
  };
364
- const buildProxy = (path, wait) => new Proxy(function () { }, {
365
- get(_, p) {
366
- if (p == "then" || p == "catch" || p == Symbol.toPrimitive)
367
- return undefined;
368
- return buildProxy([...path, String(p)], wait);
369
- },
370
- apply(_, __, args) {
371
- const [fp, fa] = (0, rpc_walk_1.resolveCA)(path, args);
372
- return sendCall(fp, fa, wait);
373
- },
374
- });
375
- const buildStrict = (path, wait) => {
376
- let tgt = strictData;
377
- for (const seg of path) {
378
- tgt = tgt?.[seg];
379
- if (tgt == null || tgt == "null")
526
+ function lookupRpcMemberState(path, member) {
527
+ if (!schemaKnown)
528
+ return undefined;
529
+ const memberPath = [...path, member];
530
+ const memberKey = (0, rpc_path_1.rpcPathKey)(memberPath);
531
+ if (Object.prototype.hasOwnProperty.call(routeCache, memberKey))
532
+ return true;
533
+ if (declaredListens?.has(memberKey))
534
+ return true;
535
+ const target = resolveStrictTarget(memberPath);
536
+ if (target == 'dynamic')
537
+ return undefined;
538
+ return target != undefined && target != null && target != 'null';
539
+ }
540
+ function createRpcMemberLookup(path) {
541
+ const lookup = function lookupRpcMember(member) { return lookupRpcMemberState(path, member); };
542
+ Object.defineProperty(lookup, transport_lifecycle_1.RPC_MEMBER_LOOKUP, { value: true });
543
+ return lookup;
544
+ }
545
+ const proxyCaches = {
546
+ func: createPathProxyCache(),
547
+ space: createPathProxyCache(),
548
+ strict: createPathProxyCache(),
549
+ };
550
+ function buildProxy(path, wait, cache) {
551
+ const cached = cache.get(path);
552
+ if (cached)
553
+ return cached;
554
+ const proxy = new Proxy(function () { }, {
555
+ get(_, p) {
556
+ if (p == transport_lifecycle_1.RPC_MEMBER_LOOKUP)
557
+ return createRpcMemberLookup(path);
558
+ if (p == transport_lifecycle_1.RPC_TRANSPORT_LIFECYCLE)
559
+ return transport.api;
560
+ if (p == 'then' || p == 'catch' || p == Symbol.toPrimitive)
561
+ return undefined;
562
+ return buildProxy([...path, String(p)], wait, cache);
563
+ },
564
+ apply(_, __, args) {
565
+ const [fp, fa] = (0, rpc_walk_1.resolveCA)(path, args);
566
+ return sendCall(fp, fa, wait);
567
+ },
568
+ });
569
+ return cache.set(path, proxy);
570
+ }
571
+ function resolveStrictTarget(path) {
572
+ let target = strictData;
573
+ for (const segment of path) {
574
+ if (target == 'dynamic')
575
+ return target;
576
+ target = target?.[segment];
577
+ if (target == null || target == 'null')
380
578
  return undefined;
381
- if (tgt == "dynamic")
382
- return buildProxy([...path], wait);
383
579
  }
384
- if (tgt == "dynamic")
385
- return buildProxy(path, wait);
386
- return new Proxy(tgt == "func" ? function () { } : {}, {
387
- has: (_, p) => tgt?.[String(p)] !== "null",
388
- ownKeys: () => tgt && typeof tgt == "object" ? Object.keys(tgt) : [],
580
+ return target;
581
+ }
582
+ function buildStrict(path, wait) {
583
+ const initialTarget = resolveStrictTarget(path);
584
+ if (initialTarget == null || initialTarget == 'null')
585
+ return undefined;
586
+ const cached = proxyCaches.strict.get(path);
587
+ if (cached)
588
+ return cached;
589
+ const target = () => { };
590
+ const proxy = new Proxy(target, {
591
+ has: (_, p) => {
592
+ const target = resolveStrictTarget(path);
593
+ return target == 'dynamic' || (target?.[String(p)] != 'null' && target?.[String(p)] != undefined);
594
+ },
595
+ ownKeys: () => {
596
+ const target = resolveStrictTarget(path);
597
+ return target && typeof target == 'object' ? Object.keys(target) : [];
598
+ },
389
599
  getOwnPropertyDescriptor: () => ({ enumerable: true, configurable: true }),
390
- getPrototypeOf: () => !tgt || tgt == "null" ? Object.prototype : tgt == "func" ? Function.prototype : null,
600
+ getPrototypeOf: () => {
601
+ const target = resolveStrictTarget(path);
602
+ return target == 'func' || target == 'dynamic' ? Function.prototype : target ? null : Object.prototype;
603
+ },
391
604
  get(_, p) {
392
- if (p == "then" || p == "catch" || p == Symbol.toPrimitive)
605
+ if (p == transport_lifecycle_1.RPC_MEMBER_LOOKUP)
606
+ return createRpcMemberLookup(path);
607
+ if (p == transport_lifecycle_1.RPC_TRANSPORT_LIFECYCLE)
608
+ return transport.api;
609
+ if (p == 'then' || p == 'catch' || p == Symbol.toPrimitive)
393
610
  return undefined;
394
- if (p == "call" && tgt == "func")
395
- return (_, ...args) => sendCall(path, args, wait);
396
- if (tgt === "func")
611
+ const target = resolveStrictTarget(path);
612
+ if (p == 'call' && target == 'func') {
613
+ return function strictCall(_, ...args) { return sendCall(path, args, wait); };
614
+ }
615
+ if (target == 'func')
397
616
  return undefined;
398
- const child = tgt?.[String(p)];
399
- return child == "null" || child == undefined ? undefined : buildStrict([...path, String(p)], wait);
617
+ if (target != 'dynamic') {
618
+ const child = target?.[String(p)];
619
+ if (child == 'null' || child == undefined)
620
+ return undefined;
621
+ }
622
+ return buildStrict([...path, String(p)], wait);
400
623
  },
401
624
  apply(_, __, args) {
625
+ const target = resolveStrictTarget(path);
626
+ if (target != 'func' && target != 'dynamic') {
627
+ throw new TypeError('RPC strict path is not callable');
628
+ }
402
629
  const [fp, fa] = (0, rpc_walk_1.resolveCA)(path, args);
403
630
  return sendCall(fp, fa, wait);
404
631
  },
405
632
  });
406
- };
633
+ return proxyCaches.strict.set(path, proxy);
634
+ }
407
635
  const releaseCbs = (fn) => {
408
636
  callbacks.forEach((cb, id) => { if (cb == fn) {
409
637
  callbacks.delete(id);
@@ -411,40 +639,41 @@ function createClient(socket, key, opts) {
411
639
  } });
412
640
  };
413
641
  function abortAll(reason) {
414
- const err = { error: { name: "RPC_ABORT", message: reason } };
415
- pending.forEach((p, id) => { retire(id); p.fail(err); });
642
+ const err = { error: { name: 'RPC_ABORT', message: reason } };
643
+ pending.forEach(function abortPending(p, id) {
644
+ retire(id);
645
+ for (const cbId of p.cbs)
646
+ compactShapes.delete(cbId);
647
+ p.fail(err);
648
+ });
416
649
  pending.clear();
417
- callbacks.forEach((_, id) => retire(id));
650
+ callbacks.forEach(function abortCallback(_, id) { retire(id); });
418
651
  callbacks.clear();
652
+ compactShapes.clear();
419
653
  }
420
654
  function drainWireSubs(socketAlive) {
421
- const subs = Array.from(wireSubs.values());
655
+ const subs = [...wireSubs.values()];
422
656
  wireSubs.clear();
423
- for (const s of subs) {
424
- if (socketAlive)
425
- s.stop();
426
- else {
427
- s.consumers.forEach(c => c.resolve());
428
- s.consumers.clear();
429
- }
430
- }
657
+ for (const sub of subs)
658
+ sub.stop(socketAlive);
431
659
  }
432
- function dispose(reason = "RPC client disposed", opts) {
660
+ function dispose(reason = 'RPC client disposed', opts) {
433
661
  if (disposed)
434
662
  return;
435
663
  const socketAlive = opts?.socketAlive ?? true;
436
- abortAll(reason);
437
664
  drainWireSubs(socketAlive);
665
+ abortAll(reason);
438
666
  disposed = true;
667
+ transport.control.close(reason);
439
668
  authPending = false;
440
669
  const sw = strictWaiters;
441
670
  strictWaiters = [];
442
- for (const r of sw)
443
- r(undefined);
671
+ for (const resolve of sw)
672
+ resolve(undefined);
444
673
  const aw = authWaiters;
445
674
  authWaiters = [];
446
- for (const r of aw)
447
- r({ ok: false, reason });
675
+ for (const resolve of aw)
676
+ resolve({ ok: false, reason });
448
677
  const dc = disconnectCbs;
449
678
  disconnectCbs = [];
450
679
  for (const cb of dc)
@@ -467,7 +696,9 @@ function createClient(socket, key, opts) {
467
696
  end: releaseCbs,
468
697
  subscriptions: () => Array.from(wireSubs, ([k, s]) => ({ key: k, consumers: s.consumers.size })),
469
698
  };
470
- const func = buildProxy([], true);
699
+ const func = buildProxy([], true, proxyCaches.func);
700
+ const space = buildProxy([], false, proxyCaches.space);
701
+ const strict = buildStrict([], true);
471
702
  const pipe = buildPipeProxy([], [], true);
472
703
  const pipeStrict = buildPipeProxy([], [], true);
473
704
  let _ready = null;
@@ -475,6 +706,7 @@ function createClient(socket, key, opts) {
475
706
  const init = async (obj) => {
476
707
  if (obj) {
477
708
  strictData = obj;
709
+ schemaKnown = true;
478
710
  return;
479
711
  }
480
712
  if (authToken != null) {
@@ -486,7 +718,9 @@ function createClient(socket, key, opts) {
486
718
  };
487
719
  function reauth(token) {
488
720
  if (disposed)
489
- return Promise.resolve({ ok: false, reason: "RPC client disposed" });
721
+ return Promise.resolve({ ok: false, reason: 'RPC client disposed' });
722
+ if (!transport.api.connected())
723
+ return Promise.resolve({ ok: false, reason: 'RPC transport disconnected' });
490
724
  authToken = token;
491
725
  authPending = true;
492
726
  socket.emit(key, [rpc_protocol_1.Pkt.HELLO, token]);
@@ -499,10 +733,11 @@ function createClient(socket, key, opts) {
499
733
  func,
500
734
  pipe,
501
735
  pipeStrict,
502
- space: buildProxy([], false),
736
+ space,
503
737
  all: func,
504
- strict: buildStrict([], true),
738
+ strict,
505
739
  api,
740
+ [transport_lifecycle_1.RPC_TRANSPORT_CONTROL]: transport.control,
506
741
  abortAll,
507
742
  dispose,
508
743
  close: dispose,
@@ -20,5 +20,7 @@ export declare function createRpcClientHub<T extends Record<string, RpcDescripto
20
20
  readonly socket: T2;
21
21
  onConnect: (func?: ((count: number) => void) | null) => void;
22
22
  onDisconnect: (func?: ((reason: string) => void) | null) => void;
23
+ connectListen: (cb: (count: number) => void) => () => void;
24
+ disconnectListen: (cb: (reason: string) => void) => () => void;
23
25
  connectCount: () => number;
24
26
  };