bunite-core 0.17.0 → 0.17.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/rpc/peer.ts CHANGED
@@ -1,50 +1,50 @@
1
1
  import {
2
- type CapDef,
3
- type Schema,
4
- type SchemaRoots,
2
+ type AlreadyExistsReason,
3
+ type FailedPreconditionReason,
4
+ type IpcCode,
5
+ IpcError,
6
+ type IpcStatus,
7
+ type ResourceExhaustedReason,
8
+ } from "./error";
9
+ import { frameworkTypeIdOf, RuntimeCap } from "./framework";
10
+ import {
11
+ type AnyCapDef,
12
+ type AnyCapToken,
13
+ type Attestation,
14
+ type CallCtx,
5
15
  type ClientOf,
16
+ type DisposalSpec,
17
+ type ExportedCap,
6
18
  type ImplOf,
7
19
  type ImplsOf,
8
- type CallCtx,
9
- type Attestation,
10
- type ExportedCap,
11
- type MethodDef,
12
- type AnyCapToken,
13
- type Stream as StreamType,
14
- type DisposalSpec,
15
20
  isCallDef,
16
- isStreamDef,
17
- isCapRef,
18
21
  isCapArray,
19
- isCapRecord,
20
22
  isCapDef,
23
+ isCapRecord,
24
+ isCapRef,
21
25
  isSchema,
26
+ isStreamDef,
27
+ type MethodDef,
28
+ type Schema,
29
+ type SchemaRoots,
30
+ type Stream as StreamType,
22
31
  } from "./schema";
23
- import { RuntimeCap, frameworkTypeIdOf } from "./framework";
24
32
  import {
25
- type Frame,
33
+ BOOTSTRAP_METHOD,
26
34
  type CallFrame,
27
- type ResultFrame,
28
- type StreamFrame,
29
- type CancelFrame,
30
- type DropFrame,
31
- type HelloFrame,
32
- type CapRevokedFrame,
33
35
  type CallMeta,
36
+ type CancelFrame,
34
37
  CapRef,
38
+ type CapRevokedFrame,
35
39
  DEFAULT_MAX_BYTES,
36
- PROTOCOL_VERSION,
40
+ type DropFrame,
37
41
  FRAMEWORK_NAME_PREFIX,
38
- BOOTSTRAP_METHOD,
42
+ type Frame,
43
+ type HelloFrame,
44
+ PROTOCOL_VERSION,
45
+ type ResultFrame,
46
+ type StreamFrame,
39
47
  } from "./wire";
40
- import {
41
- IpcError,
42
- type IpcStatus,
43
- type IpcCode,
44
- type FailedPreconditionReason,
45
- type ResourceExhaustedReason,
46
- type AlreadyExistsReason,
47
- } from "./error";
48
48
 
49
49
  export const USER_ROOTS_CAP_ID = 0;
50
50
  export const RUNTIME_CAP_ID = 1;
@@ -90,7 +90,7 @@ export function _setCallContextStorage(als: CallContextStorage | null): void {
90
90
  export interface CapTableEntry {
91
91
  capId: number;
92
92
  typeId: number;
93
- cap: CapDef<any, any> | null;
93
+ cap: AnyCapDef | null;
94
94
  impl: unknown;
95
95
  refCount: number;
96
96
  }
@@ -173,23 +173,57 @@ export interface ServeHandle extends Disposable {
173
173
  }
174
174
 
175
175
  export interface ConnectionEvents {
176
- bootstrap: { name: string; version?: string; attestation: Attestation; result: "ok" | "denied" | "not_found" | "version_mismatch" | "invalid_argument" | "resource_exhausted" | "internal"; capId?: number };
177
- call: { capId: number; capName?: string; method: string; callId: number; durationMs?: number; result: "ok" | "cancelled" | IpcCode };
178
- stream: { capId: number; capName?: string; method: string; callId: number; event: "start" | "end" | "cancel" | "error"; count?: number };
176
+ bootstrap: {
177
+ name: string;
178
+ version?: string;
179
+ attestation: Attestation;
180
+ result:
181
+ | "ok"
182
+ | "denied"
183
+ | "not_found"
184
+ | "version_mismatch"
185
+ | "invalid_argument"
186
+ | "resource_exhausted"
187
+ | "internal";
188
+ capId?: number;
189
+ };
190
+ call: {
191
+ capId: number;
192
+ capName?: string;
193
+ method: string;
194
+ callId: number;
195
+ durationMs?: number;
196
+ result: "ok" | "cancelled" | IpcCode;
197
+ };
198
+ stream: {
199
+ capId: number;
200
+ capName?: string;
201
+ method: string;
202
+ callId: number;
203
+ event: "start" | "end" | "cancel" | "error";
204
+ count?: number;
205
+ };
179
206
  revoke: { capIds: number[]; reason: "unserve" | "replace" };
180
207
  error: { phase: string; error: Error };
181
208
  }
182
209
 
183
210
  export interface Connection {
184
- bootstrap<C extends CapDef<any, any>>(cap: C): Promise<ClientOf<C>>;
211
+ bootstrap<C extends AnyCapDef>(cap: C): Promise<ClientOf<C>>;
185
212
  bootstrap<R extends SchemaRoots>(schema: Schema<R>): Promise<{ [K in keyof R]: ClientOf<R[K]> }>;
186
- serve<C extends CapDef<any, any>>(cap: C, impl: ImplOf<C>, opts?: { ifExists?: IfExists }): ServeHandle;
187
- serveAll<R extends SchemaRoots>(schema: Schema<R>, impls: ImplsOf<R>, opts?: { ifExists?: IfExists }): ServeHandle;
188
- unserve(target: CapDef<any, any> | ServeHandle): void;
189
- replace<C extends CapDef<any, any>>(cap: C, impl: ImplOf<C>): void;
213
+ serve<C extends AnyCapDef>(cap: C, impl: ImplOf<C>, opts?: { ifExists?: IfExists }): ServeHandle;
214
+ serveAll<R extends SchemaRoots>(
215
+ schema: Schema<R>,
216
+ impls: ImplsOf<R>,
217
+ opts?: { ifExists?: IfExists },
218
+ ): ServeHandle;
219
+ unserve(target: AnyCapDef | ServeHandle): void;
220
+ replace<C extends AnyCapDef>(cap: C, impl: ImplOf<C>): void;
190
221
  runtime(): ClientOf<typeof RuntimeCap>;
191
222
  releaseRef(proxy: unknown): void;
192
- on<K extends keyof ConnectionEvents>(event: K, handler: (e: ConnectionEvents[K]) => void): () => void;
223
+ on<K extends keyof ConnectionEvents>(
224
+ event: K,
225
+ handler: (e: ConnectionEvents[K]) => void,
226
+ ): () => void;
193
227
  onClose(handler: () => void): () => void;
194
228
  /** Tear down the connection — rejects pending, fires onClose, closes transport. Reliable signal for application lifecycle. */
195
229
  shutdown(reason?: string): void;
@@ -244,14 +278,19 @@ function isExportedCap(v: unknown): v is ExportedCap<any> {
244
278
  return typeof v === "object" && v !== null && (v as any)[EXPORTED_CAP_BRAND] === true;
245
279
  }
246
280
 
247
- const proxyFinalizers = typeof FinalizationRegistry !== "undefined"
248
- ? new FinalizationRegistry<{ connRef: WeakRef<ConnectionImpl>; capId: number; dropped: () => boolean }>((held) => {
249
- if (held.dropped()) return;
250
- const conn = held.connRef.deref();
251
- if (!conn || conn.closed) return;
252
- conn._dropFromFinalizer(held.capId);
253
- })
254
- : ({ register: () => {} } as { register: (target: object, held: unknown) => void });
281
+ const proxyFinalizers =
282
+ typeof FinalizationRegistry !== "undefined"
283
+ ? new FinalizationRegistry<{
284
+ connRef: WeakRef<ConnectionImpl>;
285
+ capId: number;
286
+ dropped: () => boolean;
287
+ }>((held) => {
288
+ if (held.dropped()) return;
289
+ const conn = held.connRef.deref();
290
+ if (!conn || conn.closed) return;
291
+ conn._dropFromFinalizer(held.capId);
292
+ })
293
+ : ({ register: () => {} } as { register: (target: object, held: unknown) => void });
255
294
 
256
295
  interface ServerStreamCtx {
257
296
  iter: AsyncIterator<unknown> | null;
@@ -274,7 +313,7 @@ interface ClientStreamCtx {
274
313
  }
275
314
 
276
315
  interface RegistryEntry {
277
- cap: CapDef<any, any>;
316
+ cap: AnyCapDef;
278
317
  impl: unknown;
279
318
  version?: string;
280
319
  }
@@ -286,7 +325,10 @@ class ConnectionImpl implements Connection {
286
325
  private readonly clientStreams = new Map<number, ClientStreamCtx>();
287
326
  private readonly serverStreams = new Map<number, ServerStreamCtx>();
288
327
  private readonly serverCallChildren = new Map<number, { parentId: number }>();
289
- private readonly serverActiveCalls = new Map<number, { ctrl: AbortController; capId: number; capName: string; method: string; startedAt: number }>();
328
+ private readonly serverActiveCalls = new Map<
329
+ number,
330
+ { ctrl: AbortController; capId: number; capName: string; method: string; startedAt: number }
331
+ >();
290
332
  /** Server-side: name → registry entry. */
291
333
  private readonly registry = new Map<string, RegistryEntry>();
292
334
  /** Server-side: name → instance cap-id (cached bootstrap result). */
@@ -294,7 +336,9 @@ class ConnectionImpl implements Connection {
294
336
  /** Client-side: cap-ids that the server revoked via cap_revoked. */
295
337
  private readonly revokedCapIds = new Set<number>();
296
338
  private readonly closeHandlers = new Set<() => void>();
297
- private readonly observers: { [K in keyof ConnectionEvents]?: Set<(e: ConnectionEvents[K]) => void> } = {};
339
+ private readonly observers: {
340
+ [K in keyof ConnectionEvents]?: Set<(e: ConnectionEvents[K]) => void>;
341
+ } = {};
298
342
  private nextCallId = 1;
299
343
  private remoteHello: HelloFrame | null = null;
300
344
  private readonly remoteReady: Promise<HelloFrame>;
@@ -363,21 +407,30 @@ class ConnectionImpl implements Connection {
363
407
  return () => this.closeHandlers.delete(handler);
364
408
  }
365
409
 
366
- on<K extends keyof ConnectionEvents>(event: K, handler: (e: ConnectionEvents[K]) => void): () => void {
410
+ on<K extends keyof ConnectionEvents>(
411
+ event: K,
412
+ handler: (e: ConnectionEvents[K]) => void,
413
+ ): () => void {
367
414
  let set = this.observers[event] as Set<(e: ConnectionEvents[K]) => void> | undefined;
368
415
  if (!set) {
369
416
  set = new Set();
370
417
  (this.observers as Record<string, Set<unknown>>)[event] = set as unknown as Set<unknown>;
371
418
  }
372
419
  set.add(handler);
373
- return () => { set!.delete(handler); };
420
+ return () => {
421
+ set!.delete(handler);
422
+ };
374
423
  }
375
424
 
376
425
  private emitObs<K extends keyof ConnectionEvents>(event: K, data: ConnectionEvents[K]): void {
377
426
  const set = this.observers[event] as Set<(e: ConnectionEvents[K]) => void> | undefined;
378
427
  if (!set || set.size === 0) return;
379
428
  for (const h of set) {
380
- try { h(data); } catch { /* swallow */ }
429
+ try {
430
+ h(data);
431
+ } catch {
432
+ /* swallow */
433
+ }
381
434
  }
382
435
  }
383
436
 
@@ -393,7 +446,7 @@ class ConnectionImpl implements Connection {
393
446
 
394
447
  // ---- serve / unserve / replace ----
395
448
 
396
- serve<C extends CapDef<any, any>>(cap: C, impl: ImplOf<C>, opts?: { ifExists?: IfExists }): ServeHandle {
449
+ serve<C extends AnyCapDef>(cap: C, impl: ImplOf<C>, opts?: { ifExists?: IfExists }): ServeHandle {
397
450
  this.assertNotFrameworkName(cap.name);
398
451
  const ifExists = opts?.ifExists ?? "throw";
399
452
  const existing = this.registry.get(cap.name);
@@ -425,7 +478,11 @@ class ConnectionImpl implements Connection {
425
478
  return handle;
426
479
  }
427
480
 
428
- serveAll<R extends SchemaRoots>(schema: Schema<R>, impls: ImplsOf<R>, opts?: { ifExists?: IfExists }): ServeHandle {
481
+ serveAll<R extends SchemaRoots>(
482
+ schema: Schema<R>,
483
+ impls: ImplsOf<R>,
484
+ opts?: { ifExists?: IfExists },
485
+ ): ServeHandle {
429
486
  const ifExists = opts?.ifExists ?? "throw";
430
487
  // Pre-validate everything that can fail across all modes before mutating any state (atomicity).
431
488
  for (const k of Object.keys(schema.roots)) {
@@ -461,7 +518,7 @@ class ConnectionImpl implements Connection {
461
518
  return this.makeHandle(names);
462
519
  }
463
520
 
464
- unserve(target: CapDef<any, any> | ServeHandle): void {
521
+ unserve(target: AnyCapDef | ServeHandle): void {
465
522
  const names = isCapDef(target) ? [target.name] : Array.from((target as ServeHandle).names);
466
523
  const revoked: number[] = [];
467
524
  for (const name of names) {
@@ -481,7 +538,7 @@ class ConnectionImpl implements Connection {
481
538
  }
482
539
  }
483
540
 
484
- replace<C extends CapDef<any, any>>(cap: C, impl: ImplOf<C>): void {
541
+ replace<C extends AnyCapDef>(cap: C, impl: ImplOf<C>): void {
485
542
  const entry = this.registry.get(cap.name);
486
543
  if (!entry) throw new IpcError({ code: "not_found", message: `cap "${cap.name}" not served` });
487
544
  if (entry.version !== cap.version) {
@@ -496,7 +553,10 @@ class ConnectionImpl implements Connection {
496
553
  const instId = this.rootInstances.get(cap.name);
497
554
  if (instId !== undefined) {
498
555
  const e = this.capTable.get(instId);
499
- if (e) { e.impl = impl; e.cap = cap; }
556
+ if (e) {
557
+ e.impl = impl;
558
+ e.cap = cap;
559
+ }
500
560
  }
501
561
  this.emitObs("revoke", { capIds: instId !== undefined ? [instId] : [], reason: "replace" });
502
562
  }
@@ -522,27 +582,33 @@ class ConnectionImpl implements Connection {
522
582
  return this.runtimeProxy;
523
583
  }
524
584
 
525
- bootstrap<C extends CapDef<any, any>>(cap: C): Promise<ClientOf<C>>;
585
+ bootstrap<C extends AnyCapDef>(cap: C): Promise<ClientOf<C>>;
526
586
  bootstrap<R extends SchemaRoots>(schema: Schema<R>): Promise<{ [K in keyof R]: ClientOf<R[K]> }>;
527
- async bootstrap(target: CapDef<any, any> | Schema<any>): Promise<unknown> {
587
+ async bootstrap(target: AnyCapDef | Schema<any>): Promise<unknown> {
528
588
  if (isCapDef(target)) return this._bootstrapCap(target);
529
589
  if (isSchema(target)) return this._bootstrapSchema(target);
530
- throw new IpcError({ code: "invalid_argument", message: "bootstrap target must be CapDef or Schema" });
590
+ throw new IpcError({
591
+ code: "invalid_argument",
592
+ message: "bootstrap target must be CapDef or Schema",
593
+ });
531
594
  }
532
595
 
533
- private async _bootstrapCap<C extends CapDef<any, any>>(cap: C): Promise<ClientOf<C>> {
596
+ private async _bootstrapCap<C extends AnyCapDef>(cap: C): Promise<ClientOf<C>> {
534
597
  await this.remoteReady;
535
598
  const args: { name: string; version?: string } = { name: cap.name };
536
599
  if (cap.version != null) args.version = cap.version;
537
600
  const raw = await this.sendCallTyped(USER_ROOTS_CAP_ID, BOOTSTRAP_METHOD, args, undefined);
538
601
  if (!(raw instanceof CapRef)) {
539
- throw new IpcError({ code: "invalid_argument", message: "bootstrap did not return a CapRef" });
602
+ throw new IpcError({
603
+ code: "invalid_argument",
604
+ message: "bootstrap did not return a CapRef",
605
+ });
540
606
  }
541
607
  return this.makeCapProxy(cap, raw.capId) as ClientOf<C>;
542
608
  }
543
609
 
544
610
  private async _bootstrapSchema<R extends SchemaRoots>(
545
- schema: Schema<R>
611
+ schema: Schema<R>,
546
612
  ): Promise<{ [K in keyof R]: ClientOf<R[K]> }> {
547
613
  const keys = Object.keys(schema.roots) as (keyof R & string)[];
548
614
  const settled = await Promise.allSettled(keys.map((k) => this._bootstrapCap(schema.roots[k])));
@@ -551,14 +617,20 @@ class ConnectionImpl implements Connection {
551
617
  // Release server refCount on the roots that succeeded — otherwise their cap-table entries linger until connection close.
552
618
  for (const r of settled) {
553
619
  if (r.status === "fulfilled") {
554
- try { this.releaseRef(r.value); } catch { /* swallow */ }
620
+ try {
621
+ this.releaseRef(r.value);
622
+ } catch {
623
+ /* swallow */
624
+ }
555
625
  }
556
626
  }
557
627
  throw rejected.reason;
558
628
  }
559
629
  const out = {} as { [K in keyof R]: ClientOf<R[K]> };
560
630
  for (let i = 0; i < keys.length; i++) {
561
- (out as Record<string, unknown>)[keys[i]] = (settled[i] as PromiseFulfilledResult<unknown>).value;
631
+ (out as Record<string, unknown>)[keys[i]] = (
632
+ settled[i] as PromiseFulfilledResult<unknown>
633
+ ).value;
562
634
  }
563
635
  return out;
564
636
  }
@@ -601,10 +673,19 @@ class ConnectionImpl implements Connection {
601
673
  private handleUnknownFrame(frame: unknown): void {
602
674
  const id = (frame as { id?: unknown })?.id;
603
675
  if (typeof id === "number") {
604
- this.transport.send({ op: "result", id, ok: false, error: { code: "invalid_argument", message: "unknown opcode" } });
676
+ this.transport.send({
677
+ op: "result",
678
+ id,
679
+ ok: false,
680
+ error: { code: "invalid_argument", message: "unknown opcode" },
681
+ });
605
682
  return;
606
683
  }
607
- this.transport.send({ op: "goaway", reason: "invalid_argument", error: { code: "invalid_argument", message: "unknown opcode" } });
684
+ this.transport.send({
685
+ op: "goaway",
686
+ reason: "invalid_argument",
687
+ error: { code: "invalid_argument", message: "unknown opcode" },
688
+ });
608
689
  this.shutdown("invalid_argument");
609
690
  }
610
691
 
@@ -615,7 +696,7 @@ class ConnectionImpl implements Connection {
615
696
 
616
697
  private handleGoaway(frame: Extract<Frame, { op: "goaway" }>): void {
617
698
  this.rejectRemoteReady(
618
- new IpcError(frame.error ?? { code: "unavailable", message: frame.reason ?? "peer goaway" })
699
+ new IpcError(frame.error ?? { code: "unavailable", message: frame.reason ?? "peer goaway" }),
619
700
  );
620
701
  this.shutdown(frame.reason ?? "remote goaway");
621
702
  }
@@ -654,30 +735,58 @@ class ConnectionImpl implements Connection {
654
735
 
655
736
  const entry = this.capTable.get(frame.target.id);
656
737
  if (!entry) {
657
- this.emitObs("call", { capId: frame.target.id, method: frame.method, callId: frame.id, result: "not_found" });
738
+ this.emitObs("call", {
739
+ capId: frame.target.id,
740
+ method: frame.method,
741
+ callId: frame.id,
742
+ result: "not_found",
743
+ });
658
744
  return this.sendError(frame.id, "not_found", `cap-id ${frame.target.id} not found`);
659
745
  }
660
746
 
661
747
  const cap = entry.cap;
662
748
  if (!cap || !entry.impl) {
663
- this.emitObs("call", { capId: frame.target.id, method: frame.method, callId: frame.id, result: "not_found" });
749
+ this.emitObs("call", {
750
+ capId: frame.target.id,
751
+ method: frame.method,
752
+ callId: frame.id,
753
+ result: "not_found",
754
+ });
664
755
  return this.sendError(frame.id, "not_found", "cap has no impl");
665
756
  }
666
757
 
667
758
  const methodDef = cap.methods[frame.method] as MethodDef | undefined;
668
759
  if (!methodDef) {
669
- this.emitObs("call", { capId: frame.target.id, capName: cap.name, method: frame.method, callId: frame.id, result: "not_found" });
760
+ this.emitObs("call", {
761
+ capId: frame.target.id,
762
+ capName: cap.name,
763
+ method: frame.method,
764
+ callId: frame.id,
765
+ result: "not_found",
766
+ });
670
767
  return this.sendError(frame.id, "not_found", `method "${frame.method}" on cap "${cap.name}"`);
671
768
  }
672
769
  const impl = (entry.impl as Record<string, unknown>)[frame.method];
673
770
  if (typeof impl !== "function") {
674
- this.emitObs("call", { capId: frame.target.id, capName: cap.name, method: frame.method, callId: frame.id, result: "not_found" });
771
+ this.emitObs("call", {
772
+ capId: frame.target.id,
773
+ capName: cap.name,
774
+ method: frame.method,
775
+ callId: frame.id,
776
+ result: "not_found",
777
+ });
675
778
  return this.sendError(frame.id, "not_found", `method "${frame.method}" has no handler`);
676
779
  }
677
780
 
678
781
  // Bound inbound work — symmetric with sendCallTyped's outbound check.
679
782
  if (this.serverActiveCalls.size + this.serverStreams.size >= this.maxInFlightCalls) {
680
- this.emitObs("call", { capId: frame.target.id, capName: cap.name, method: frame.method, callId: frame.id, result: "resource_exhausted" });
783
+ this.emitObs("call", {
784
+ capId: frame.target.id,
785
+ capName: cap.name,
786
+ method: frame.method,
787
+ callId: frame.id,
788
+ result: "resource_exhausted",
789
+ });
681
790
  return this.sendError(
682
791
  frame.id,
683
792
  "resource_exhausted",
@@ -686,14 +795,23 @@ class ConnectionImpl implements Connection {
686
795
  );
687
796
  }
688
797
 
689
- await this.invokeServerMethod(frame, cap, methodDef, impl as (params: unknown, ctx: CallCtx) => unknown);
798
+ await this.invokeServerMethod(
799
+ frame,
800
+ cap,
801
+ methodDef,
802
+ impl as (params: unknown, ctx: CallCtx) => unknown,
803
+ );
690
804
  }
691
805
 
692
806
  private async handleBootstrap(frame: CallFrame): Promise<void> {
693
807
  const args = (frame.args ?? {}) as { name?: unknown; version?: unknown };
694
808
  const name = args.name;
695
809
  if (typeof name !== "string") {
696
- this.emitObs("bootstrap", { name: String(name), attestation: this.attestation, result: "invalid_argument" });
810
+ this.emitObs("bootstrap", {
811
+ name: String(name),
812
+ attestation: this.attestation,
813
+ result: "invalid_argument",
814
+ });
697
815
  return this.sendError(frame.id, "invalid_argument", "bootstrap requires {name: string}");
698
816
  }
699
817
  const clientVersion = args.version != null ? String(args.version) : undefined;
@@ -702,18 +820,28 @@ class ConnectionImpl implements Connection {
702
820
  // not via bootstrap). For user-facing bootstrap, only the registry is consulted.
703
821
  const entry = this.registry.get(name);
704
822
  if (!entry) {
705
- this.emitObs("bootstrap", { name, version: clientVersion, attestation: this.attestation, result: "not_found" });
823
+ this.emitObs("bootstrap", {
824
+ name,
825
+ version: clientVersion,
826
+ attestation: this.attestation,
827
+ result: "not_found",
828
+ });
706
829
  return this.sendError(frame.id, "not_found", `cap "${name}" not served`);
707
830
  }
708
831
 
709
832
  const serverVersion = entry.version;
710
833
  if (serverVersion != null && clientVersion != null && serverVersion !== clientVersion) {
711
- this.emitObs("bootstrap", { name, version: clientVersion, attestation: this.attestation, result: "version_mismatch" });
834
+ this.emitObs("bootstrap", {
835
+ name,
836
+ version: clientVersion,
837
+ attestation: this.attestation,
838
+ result: "version_mismatch",
839
+ });
712
840
  return this.sendError(
713
841
  frame.id,
714
842
  "failed_precondition",
715
843
  `version mismatch (server "${serverVersion}", client "${clientVersion}")`,
716
- { reason: "version_mismatch" as FailedPreconditionReason }
844
+ { reason: "version_mismatch" as FailedPreconditionReason },
717
845
  );
718
846
  }
719
847
 
@@ -722,24 +850,42 @@ class ConnectionImpl implements Connection {
722
850
  try {
723
851
  allowed = await this.policy(name, this.attestation);
724
852
  } catch (err) {
725
- this.emitObs("error", { phase: "policy", error: err instanceof Error ? err : new Error(String(err)) });
726
- this.emitObs("bootstrap", { name, version: clientVersion, attestation: this.attestation, result: "internal" });
853
+ this.emitObs("error", {
854
+ phase: "policy",
855
+ error: err instanceof Error ? err : new Error(String(err)),
856
+ });
857
+ this.emitObs("bootstrap", {
858
+ name,
859
+ version: clientVersion,
860
+ attestation: this.attestation,
861
+ result: "internal",
862
+ });
727
863
  return this.sendError(frame.id, "internal", "policy threw");
728
864
  }
729
865
  if (typeof allowed !== "boolean") {
730
866
  // Non-boolean return = programming bug; surface explicitly (not silent deny).
731
- this.emitObs("error", { phase: "policy", error: new Error(`policy must return boolean (got ${typeof allowed})`) });
732
- this.emitObs("bootstrap", { name, version: clientVersion, attestation: this.attestation, result: "internal" });
867
+ this.emitObs("error", {
868
+ phase: "policy",
869
+ error: new Error(`policy must return boolean (got ${typeof allowed})`),
870
+ });
871
+ this.emitObs("bootstrap", {
872
+ name,
873
+ version: clientVersion,
874
+ attestation: this.attestation,
875
+ result: "internal",
876
+ });
733
877
  return this.sendError(frame.id, "internal", "policy returned non-boolean");
734
878
  }
735
879
  if (!allowed) {
736
- this.emitObs("bootstrap", { name, version: clientVersion, attestation: this.attestation, result: "denied" });
737
- return this.sendError(
738
- frame.id,
739
- "failed_precondition",
740
- "policy denied",
741
- { reason: "unauthorized" as FailedPreconditionReason }
742
- );
880
+ this.emitObs("bootstrap", {
881
+ name,
882
+ version: clientVersion,
883
+ attestation: this.attestation,
884
+ result: "denied",
885
+ });
886
+ return this.sendError(frame.id, "failed_precondition", "policy denied", {
887
+ reason: "unauthorized" as FailedPreconditionReason,
888
+ });
743
889
  }
744
890
  }
745
891
 
@@ -766,21 +912,37 @@ class ConnectionImpl implements Connection {
766
912
  } catch (err) {
767
913
  if (err instanceof IpcError) {
768
914
  const result = err.code === "resource_exhausted" ? "resource_exhausted" : "internal";
769
- this.emitObs("bootstrap", { name, version: clientVersion, attestation: this.attestation, result });
770
- return this.sendError(frame.id, err.code, err.message, err.details as Record<string, unknown> | undefined);
915
+ this.emitObs("bootstrap", {
916
+ name,
917
+ version: clientVersion,
918
+ attestation: this.attestation,
919
+ result,
920
+ });
921
+ return this.sendError(
922
+ frame.id,
923
+ err.code,
924
+ err.message,
925
+ err.details as Record<string, unknown> | undefined,
926
+ );
771
927
  }
772
928
  throw err;
773
929
  }
774
930
  }
775
- this.emitObs("bootstrap", { name, version: clientVersion, attestation: this.attestation, result: "ok", capId });
931
+ this.emitObs("bootstrap", {
932
+ name,
933
+ version: clientVersion,
934
+ attestation: this.attestation,
935
+ result: "ok",
936
+ capId,
937
+ });
776
938
  this.transport.send({ op: "result", id: frame.id, ok: true, value: new CapRef(capId) });
777
939
  }
778
940
 
779
941
  private async invokeServerMethod(
780
942
  frame: CallFrame,
781
- cap: CapDef<any, any>,
943
+ cap: AnyCapDef,
782
944
  methodDef: MethodDef,
783
- impl: (params: unknown, ctx: CallCtx) => unknown
945
+ impl: (params: unknown, ctx: CallCtx) => unknown,
784
946
  ): Promise<void> {
785
947
  const ctx = this.makeCallCtx(frame);
786
948
 
@@ -789,13 +951,17 @@ class ConnectionImpl implements Connection {
789
951
  try {
790
952
  const runStream = () => impl(frame.args, ctx) as StreamType<unknown>;
791
953
  const als = callContextStorage;
792
- const scoped = als
793
- ? () => als.run({ callId: frame.id }, runStream)
794
- : runStream;
954
+ const scoped = als ? () => als.run({ callId: frame.id }, runStream) : runStream;
795
955
  const stream = scoped();
796
956
  this.runServerStream(frame.id, stream, ctx, hintBudget, cap, frame.method, frame.target.id);
797
957
  } catch (err) {
798
- this.emitObs("stream", { capId: frame.target.id, capName: cap.name, method: frame.method, callId: frame.id, event: "error" });
958
+ this.emitObs("stream", {
959
+ capId: frame.target.id,
960
+ capName: cap.name,
961
+ method: frame.method,
962
+ callId: frame.id,
963
+ event: "error",
964
+ });
799
965
  this.transport.send({ op: "stream", id: frame.id, ev: "error", error: toStatus(err) });
800
966
  }
801
967
  return;
@@ -814,22 +980,34 @@ class ConnectionImpl implements Connection {
814
980
  const encoder = makeReturnEncoder(methodDef.returns);
815
981
  const runImpl = () => Promise.resolve(impl(frame.args, ctx));
816
982
  const als = callContextStorage;
817
- const scoped = als
818
- ? () => als.run({ callId: frame.id }, runImpl)
819
- : runImpl;
983
+ const scoped = als ? () => als.run({ callId: frame.id }, runImpl) : runImpl;
820
984
  try {
821
985
  const result = await scoped();
822
986
  if (deadlineTimer) clearTimeout(deadlineTimer);
823
987
  if (!this.serverActiveCalls.delete(frame.id)) return;
824
988
  const encoded = encoder(result);
825
989
  this.transport.send({ op: "result", id: frame.id, ok: true, value: encoded });
826
- this.emitObs("call", { capId: frame.target.id, capName: cap.name, method: frame.method, callId: frame.id, durationMs: performance.now() - startedAt, result: "ok" });
990
+ this.emitObs("call", {
991
+ capId: frame.target.id,
992
+ capName: cap.name,
993
+ method: frame.method,
994
+ callId: frame.id,
995
+ durationMs: performance.now() - startedAt,
996
+ result: "ok",
997
+ });
827
998
  } catch (err) {
828
999
  if (deadlineTimer) clearTimeout(deadlineTimer);
829
1000
  if (!this.serverActiveCalls.delete(frame.id)) return;
830
1001
  const status = toStatus(err);
831
1002
  this.sendErrorFromStatus(frame.id, status);
832
- this.emitObs("call", { capId: frame.target.id, capName: cap.name, method: frame.method, callId: frame.id, durationMs: performance.now() - startedAt, result: status.code });
1003
+ this.emitObs("call", {
1004
+ capId: frame.target.id,
1005
+ capName: cap.name,
1006
+ method: frame.method,
1007
+ callId: frame.id,
1008
+ durationMs: performance.now() - startedAt,
1009
+ result: status.code,
1010
+ });
833
1011
  }
834
1012
  return;
835
1013
  }
@@ -837,7 +1015,10 @@ class ConnectionImpl implements Connection {
837
1015
  this.sendError(frame.id, "not_found", "unknown method kind");
838
1016
  }
839
1017
 
840
- private armServerDeadline(frame: CallFrame, ctx: CallCtx): ReturnType<typeof setTimeout> | undefined {
1018
+ private armServerDeadline(
1019
+ frame: CallFrame,
1020
+ ctx: CallCtx,
1021
+ ): ReturnType<typeof setTimeout> | undefined {
841
1022
  const ms = frame.meta?.deadlineMs;
842
1023
  if (!ms) return;
843
1024
  return setTimeout(() => {
@@ -859,7 +1040,7 @@ class ConnectionImpl implements Connection {
859
1040
  return ctx;
860
1041
  }
861
1042
 
862
- private exportCap<C extends CapDef<any, any>>(capDef: C, impl: unknown): ExportedCap<C> {
1043
+ private exportCap<C extends AnyCapDef>(capDef: C, impl: unknown): ExportedCap<C> {
863
1044
  const typeId = frameworkTypeIdOf(capDef) ?? FIRST_USER_TYPE_ID;
864
1045
  const entry = this.capTable.allocate({
865
1046
  typeId,
@@ -880,7 +1061,7 @@ class ConnectionImpl implements Connection {
880
1061
  stream: StreamType<unknown>,
881
1062
  ctx: CallCtx,
882
1063
  initialCredit: number,
883
- cap: CapDef<any, any>,
1064
+ cap: AnyCapDef,
884
1065
  method: string,
885
1066
  capId: number,
886
1067
  ): void {
@@ -903,7 +1084,9 @@ class ConnectionImpl implements Connection {
903
1084
 
904
1085
  const waitForCredit = (): Promise<void> => {
905
1086
  if (slot.credit > 0 || slot.cancelled) return Promise.resolve();
906
- return new Promise<void>((resolve) => { slot.creditWaker = resolve; });
1087
+ return new Promise<void>((resolve) => {
1088
+ slot.creditWaker = resolve;
1089
+ });
907
1090
  };
908
1091
 
909
1092
  const drain = async () => {
@@ -922,11 +1105,25 @@ class ConnectionImpl implements Connection {
922
1105
  } catch (err) {
923
1106
  errored = true;
924
1107
  this.transport.send({ op: "stream", id: callId, ev: "error", error: toStatus(err) });
925
- this.emitObs("stream", { capId, capName: cap.name, method, callId, event: "error", count: slot.count });
1108
+ this.emitObs("stream", {
1109
+ capId,
1110
+ capName: cap.name,
1111
+ method,
1112
+ callId,
1113
+ event: "error",
1114
+ count: slot.count,
1115
+ });
926
1116
  } finally {
927
1117
  if (!errored) {
928
1118
  this.transport.send({ op: "stream", id: callId, ev: "end" });
929
- this.emitObs("stream", { capId, capName: cap.name, method, callId, event: slot.cancelled ? "cancel" : "end", count: slot.count });
1119
+ this.emitObs("stream", {
1120
+ capId,
1121
+ capName: cap.name,
1122
+ method,
1123
+ callId,
1124
+ event: slot.cancelled ? "cancel" : "end",
1125
+ count: slot.count,
1126
+ });
930
1127
  }
931
1128
  this.serverStreams.delete(callId);
932
1129
  }
@@ -996,7 +1193,9 @@ class ConnectionImpl implements Connection {
996
1193
 
997
1194
  releaseRef(proxy: unknown): void {
998
1195
  if (typeof proxy !== "object" || proxy === null) return;
999
- const meta = (proxy as Record<symbol, unknown>)[CAP_PROXY_META] as { capId: number; dropped: boolean } | undefined;
1196
+ const meta = (proxy as Record<symbol, unknown>)[CAP_PROXY_META] as
1197
+ | { capId: number; dropped: boolean }
1198
+ | undefined;
1000
1199
  if (!meta || meta.dropped) return;
1001
1200
  meta.dropped = true;
1002
1201
  this.sendDrop(meta.capId);
@@ -1040,7 +1239,10 @@ class ConnectionImpl implements Connection {
1040
1239
  const released = this.capTable.release(id, delta);
1041
1240
  if (released) {
1042
1241
  for (const [rootName, capId] of this.rootInstances) {
1043
- if (capId === id) { this.rootInstances.delete(rootName); break; }
1242
+ if (capId === id) {
1243
+ this.rootInstances.delete(rootName);
1244
+ break;
1245
+ }
1044
1246
  }
1045
1247
  }
1046
1248
  }
@@ -1068,28 +1270,38 @@ class ConnectionImpl implements Connection {
1068
1270
  meta?: CallMeta,
1069
1271
  capName?: string,
1070
1272
  ): Promise<unknown> {
1071
- if (this.closed_) return Promise.reject(new IpcError({ code: "unavailable", message: "connection closed" }));
1273
+ if (this.closed_)
1274
+ return Promise.reject(new IpcError({ code: "unavailable", message: "connection closed" }));
1072
1275
  if (this.revokedCapIds.has(capId)) {
1073
- return Promise.reject(new IpcError({
1074
- code: "failed_precondition",
1075
- message: "cap revoked",
1076
- details: { reason: "revoked" as FailedPreconditionReason },
1077
- }));
1276
+ return Promise.reject(
1277
+ new IpcError({
1278
+ code: "failed_precondition",
1279
+ message: "cap revoked",
1280
+ details: { reason: "revoked" as FailedPreconditionReason },
1281
+ }),
1282
+ );
1078
1283
  }
1079
1284
  if (this.pending.size >= this.maxInFlightCalls) {
1080
- return Promise.reject(new IpcError({
1081
- code: "resource_exhausted",
1082
- message: `in-flight calls limit ${this.maxInFlightCalls}`,
1083
- details: { reason: "max_concurrent_calls" as ResourceExhaustedReason },
1084
- }));
1285
+ return Promise.reject(
1286
+ new IpcError({
1287
+ code: "resource_exhausted",
1288
+ message: `in-flight calls limit ${this.maxInFlightCalls}`,
1289
+ details: { reason: "max_concurrent_calls" as ResourceExhaustedReason },
1290
+ }),
1291
+ );
1085
1292
  }
1086
1293
  const id = this.nextId();
1087
1294
  return new Promise((resolve, reject) => {
1088
1295
  const abort = new AbortController();
1089
1296
  const pending: PendingCall = {
1090
- resolve, reject, abort, decodeReturn,
1297
+ resolve,
1298
+ reject,
1299
+ abort,
1300
+ decodeReturn,
1091
1301
  startedAt: performance.now(),
1092
- capId, method, capName,
1302
+ capId,
1303
+ method,
1304
+ capName,
1093
1305
  kind: "call",
1094
1306
  };
1095
1307
  if (meta?.deadlineMs) {
@@ -1102,14 +1314,21 @@ class ConnectionImpl implements Connection {
1102
1314
  }
1103
1315
  this.pending.set(id, pending);
1104
1316
  let finalMeta = meta;
1105
- if ((finalMeta?.parentCallId === undefined) && callContextStorage) {
1317
+ if (finalMeta?.parentCallId === undefined && callContextStorage) {
1106
1318
  const scope = callContextStorage.getStore();
1107
1319
  if (scope) finalMeta = { ...(finalMeta ?? {}), parentCallId: scope.callId };
1108
1320
  }
1109
1321
  if (finalMeta?.parentCallId !== undefined) {
1110
1322
  this.serverCallChildren.set(id, { parentId: finalMeta.parentCallId });
1111
1323
  }
1112
- this.transport.send({ op: "call", id, target: { kind: "cap", id: capId }, method, args, meta: finalMeta });
1324
+ this.transport.send({
1325
+ op: "call",
1326
+ id,
1327
+ target: { kind: "cap", id: capId },
1328
+ method,
1329
+ args,
1330
+ meta: finalMeta,
1331
+ });
1113
1332
  });
1114
1333
  }
1115
1334
 
@@ -1121,17 +1340,29 @@ class ConnectionImpl implements Connection {
1121
1340
  capName?: string,
1122
1341
  ): StreamType<T> {
1123
1342
  if (this.closed_) {
1124
- const empty = makeClientStream<T>(capId, 0, () => {}, () => {});
1343
+ const empty = makeClientStream<T>(
1344
+ capId,
1345
+ 0,
1346
+ () => {},
1347
+ () => {},
1348
+ );
1125
1349
  empty.fail(new IpcError({ code: "unavailable", message: "connection closed" }));
1126
1350
  return empty.stream;
1127
1351
  }
1128
1352
  if (this.revokedCapIds.has(capId)) {
1129
- const empty = makeClientStream<T>(capId, 0, () => {}, () => {});
1130
- empty.fail(new IpcError({
1131
- code: "failed_precondition",
1132
- message: "cap revoked",
1133
- details: { reason: "revoked" as FailedPreconditionReason },
1134
- }));
1353
+ const empty = makeClientStream<T>(
1354
+ capId,
1355
+ 0,
1356
+ () => {},
1357
+ () => {},
1358
+ );
1359
+ empty.fail(
1360
+ new IpcError({
1361
+ code: "failed_precondition",
1362
+ message: "cap revoked",
1363
+ details: { reason: "revoked" as FailedPreconditionReason },
1364
+ }),
1365
+ );
1135
1366
  return empty.stream;
1136
1367
  }
1137
1368
  const id = this.nextId();
@@ -1151,7 +1382,7 @@ class ConnectionImpl implements Connection {
1151
1382
  return ctx.stream;
1152
1383
  }
1153
1384
 
1154
- makeCapProxy<C extends CapDef<any, any>>(capDef: C, capId: number): ClientOf<C> {
1385
+ makeCapProxy<C extends AnyCapDef>(capDef: C, capId: number): ClientOf<C> {
1155
1386
  const proxy: Record<string | symbol, unknown> = {};
1156
1387
  const meta = { capId, dropped: false };
1157
1388
  proxy[CAP_PROXY_META] = meta;
@@ -1164,26 +1395,33 @@ class ConnectionImpl implements Connection {
1164
1395
  for (const name of Object.keys(capDef.methods)) {
1165
1396
  const def = capDef.methods[name] as MethodDef;
1166
1397
  if (isStreamDef(def)) {
1167
- proxy[name] = (params?: unknown) => this.openClientStream(capId, name, params, undefined, capDef.name);
1398
+ proxy[name] = (params?: unknown) =>
1399
+ this.openClientStream(capId, name, params, undefined, capDef.name);
1168
1400
  } else if (isCallDef(def)) {
1169
1401
  const decoder = makeReturnDecoder(def.returns, (cd, cid) => this.makeCapProxy(cd, cid));
1170
- proxy[name] = (params?: unknown) => this.sendCallTyped(capId, name, params, decoder, undefined, capDef.name);
1402
+ proxy[name] = (params?: unknown) =>
1403
+ this.sendCallTyped(capId, name, params, decoder, undefined, capDef.name);
1171
1404
  }
1172
1405
  }
1173
1406
 
1174
1407
  const disposal = capDef.disposal as DisposalSpec | undefined;
1175
1408
  if (disposal) {
1176
- const conn = this;
1177
1409
  proxy[Symbol.dispose] = () => {
1178
1410
  try {
1179
1411
  const r = (proxy[disposal.method] as (() => unknown) | undefined)?.();
1180
1412
  if (r && typeof (r as Promise<unknown>).then === "function") {
1181
1413
  (r as Promise<unknown>).catch((err) =>
1182
- conn.emitObs("error", { phase: "dispose", error: err instanceof Error ? err : new Error(String(err)) })
1414
+ this.emitObs("error", {
1415
+ phase: "dispose",
1416
+ error: err instanceof Error ? err : new Error(String(err)),
1417
+ }),
1183
1418
  );
1184
1419
  }
1185
1420
  } catch (err) {
1186
- conn.emitObs("error", { phase: "dispose", error: err instanceof Error ? err : new Error(String(err)) });
1421
+ this.emitObs("error", {
1422
+ phase: "dispose",
1423
+ error: err instanceof Error ? err : new Error(String(err)),
1424
+ });
1187
1425
  }
1188
1426
  drop();
1189
1427
  };
@@ -1201,7 +1439,11 @@ class ConnectionImpl implements Connection {
1201
1439
  }
1202
1440
 
1203
1441
  _dropFromFinalizer(capId: number): void {
1204
- try { this.sendDrop(capId); } catch { /* swallow */ }
1442
+ try {
1443
+ this.sendDrop(capId);
1444
+ } catch {
1445
+ /* swallow */
1446
+ }
1205
1447
  }
1206
1448
 
1207
1449
  shutdown(reason: string = "shutdown"): void {
@@ -1234,10 +1476,18 @@ class ConnectionImpl implements Connection {
1234
1476
  this.rejectRemoteReady(new IpcError({ code: "unavailable", message: reason }));
1235
1477
  }
1236
1478
  for (const fn of this.closeHandlers) {
1237
- try { fn(); } catch { /* swallow */ }
1479
+ try {
1480
+ fn();
1481
+ } catch {
1482
+ /* swallow */
1483
+ }
1238
1484
  }
1239
1485
  this.closeHandlers.clear();
1240
- try { this.transport.close(); } catch { /* swallow */ }
1486
+ try {
1487
+ this.transport.close();
1488
+ } catch {
1489
+ /* swallow */
1490
+ }
1241
1491
  }
1242
1492
 
1243
1493
  private invokeServerDisposal(entry: CapTableEntry): void {
@@ -1248,13 +1498,17 @@ class ConnectionImpl implements Connection {
1248
1498
  const impl = entry.impl as Record<string, unknown> | null;
1249
1499
  const fn = impl?.[disposal.method] as ((p: unknown, c?: unknown) => unknown) | undefined;
1250
1500
  if (!fn) return;
1251
- try { void fn.call(impl, undefined, undefined); } catch { /* swallow */ }
1501
+ try {
1502
+ void fn.call(impl, undefined, undefined);
1503
+ } catch {
1504
+ /* swallow */
1505
+ }
1252
1506
  }
1253
1507
  }
1254
1508
 
1255
1509
  function makeReturnEncoder(returns: AnyCapToken | undefined): (v: unknown) => unknown {
1256
1510
  if (!returns) return (v) => v;
1257
- const expectExportedCap = (v: unknown, expectedCap: CapDef<any, any>): CapRef => {
1511
+ const expectExportedCap = (v: unknown, expectedCap: AnyCapDef): CapRef => {
1258
1512
  if (!isExportedCap(v)) {
1259
1513
  throw new IpcError({
1260
1514
  code: "failed_precondition",
@@ -1275,7 +1529,10 @@ function makeReturnEncoder(returns: AnyCapToken | undefined): (v: unknown) => un
1275
1529
  if (isCapArray(returns)) {
1276
1530
  return (v) => {
1277
1531
  if (!Array.isArray(v)) {
1278
- throw new IpcError({ code: "invalid_argument", message: "expected ExportedCap[] for cap.array method" });
1532
+ throw new IpcError({
1533
+ code: "invalid_argument",
1534
+ message: "expected ExportedCap[] for cap.array method",
1535
+ });
1279
1536
  }
1280
1537
  return v.map((item) => expectExportedCap(item, returns.cap));
1281
1538
  };
@@ -1283,7 +1540,10 @@ function makeReturnEncoder(returns: AnyCapToken | undefined): (v: unknown) => un
1283
1540
  if (isCapRecord(returns)) {
1284
1541
  return (v) => {
1285
1542
  if (!v || typeof v !== "object") {
1286
- throw new IpcError({ code: "invalid_argument", message: "expected Record<string, ExportedCap> for cap.record method" });
1543
+ throw new IpcError({
1544
+ code: "invalid_argument",
1545
+ message: "expected Record<string, ExportedCap> for cap.record method",
1546
+ });
1287
1547
  }
1288
1548
  const out: Record<string, CapRef> = {};
1289
1549
  for (const k of Object.keys(v as object)) {
@@ -1296,14 +1556,15 @@ function makeReturnEncoder(returns: AnyCapToken | undefined): (v: unknown) => un
1296
1556
  }
1297
1557
 
1298
1558
  function makeReturnDecoder(
1299
- returns: { cap?: CapDef<any, any> } | undefined,
1300
- spawn: (cap: CapDef<any, any>, capId: number) => unknown
1559
+ returns: { cap?: AnyCapDef } | undefined,
1560
+ spawn: (cap: AnyCapDef, capId: number) => unknown,
1301
1561
  ): ReturnDecoder | undefined {
1302
1562
  if (!returns) return undefined;
1303
1563
  if (isCapRef(returns)) {
1304
1564
  const inner = returns.cap;
1305
1565
  return (raw) => {
1306
- if (!(raw instanceof CapRef)) throw new IpcError({ code: "invalid_argument", message: "expected CapRef" });
1566
+ if (!(raw instanceof CapRef))
1567
+ throw new IpcError({ code: "invalid_argument", message: "expected CapRef" });
1307
1568
  return spawn(inner, raw.capId);
1308
1569
  };
1309
1570
  }
@@ -1311,9 +1572,11 @@ function makeReturnDecoder(
1311
1572
  const inner = returns.cap;
1312
1573
  const disposal = inner.disposal as DisposalSpec | undefined;
1313
1574
  return (raw) => {
1314
- if (!Array.isArray(raw)) throw new IpcError({ code: "invalid_argument", message: "expected array" });
1575
+ if (!Array.isArray(raw))
1576
+ throw new IpcError({ code: "invalid_argument", message: "expected array" });
1315
1577
  const proxies = raw.map((item) => {
1316
- if (!(item instanceof CapRef)) throw new IpcError({ code: "invalid_argument", message: "expected CapRef in array" });
1578
+ if (!(item instanceof CapRef))
1579
+ throw new IpcError({ code: "invalid_argument", message: "expected CapRef in array" });
1317
1580
  return spawn(inner, item.capId);
1318
1581
  });
1319
1582
  attachArrayDisposal(proxies, disposal);
@@ -1323,11 +1586,13 @@ function makeReturnDecoder(
1323
1586
  if (isCapRecord(returns)) {
1324
1587
  const inner = returns.cap;
1325
1588
  return (raw) => {
1326
- if (!raw || typeof raw !== "object") throw new IpcError({ code: "invalid_argument", message: "expected record" });
1589
+ if (!raw || typeof raw !== "object")
1590
+ throw new IpcError({ code: "invalid_argument", message: "expected record" });
1327
1591
  const out: Record<string, unknown> = {};
1328
1592
  for (const k of Object.keys(raw as object)) {
1329
1593
  const item = (raw as Record<string, unknown>)[k];
1330
- if (!(item instanceof CapRef)) throw new IpcError({ code: "invalid_argument", message: "expected CapRef in record" });
1594
+ if (!(item instanceof CapRef))
1595
+ throw new IpcError({ code: "invalid_argument", message: "expected CapRef in record" });
1331
1596
  out[k] = spawn(inner, item.capId);
1332
1597
  }
1333
1598
  return out;
@@ -1364,7 +1629,7 @@ function makeClientStream<T>(
1364
1629
  capId: number,
1365
1630
  streamId: number,
1366
1631
  cancel: () => void,
1367
- sendCredit: (messages: number) => void
1632
+ sendCredit: (messages: number) => void,
1368
1633
  ): ClientStreamHandle<T> {
1369
1634
  const buffer: T[] = [];
1370
1635
  const waiters: Array<{ resolve(r: IteratorResult<T>): void; reject(e: Error): void }> = [];
@@ -1403,8 +1668,14 @@ function makeClientStream<T>(
1403
1668
  while (waiters.length > 0) {
1404
1669
  const w = waiters.shift()!;
1405
1670
  const r = pump();
1406
- if (r) { w.resolve(r); continue; }
1407
- if (failure) { w.reject(failure); continue; }
1671
+ if (r) {
1672
+ w.resolve(r);
1673
+ continue;
1674
+ }
1675
+ if (failure) {
1676
+ w.reject(failure);
1677
+ continue;
1678
+ }
1408
1679
  waiters.unshift(w);
1409
1680
  break;
1410
1681
  }