File size: 1,986 Bytes
4e23b01
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/**
 * `createKlient` over an in-process engine scope — the host bootstraps the
 * engine (`bootstrap()` from agent-core-v2) and passes the app scope (or its
 * handle) in. Calls and events never leave the process, but everything the
 * facade returns has crossed the same JSON round-trip as the networked
 * transports, so behavior is indistinguishable.
 */

import type {
  EventSourceRef,
  IDisposable,
  KlientChannel,
  ScopeRef,
} from '../../core/channel.js';
import { createKlientFromChannel, type Klient, type KlientOptions } from '../../core/klient.js';
import { createMemoryDispatcher, type ScopeLike } from './dispatcher.js';

export type { ScopeLike } from './dispatcher.js';

export interface MemoryKlientOptions extends KlientOptions {
  /**
   * A bootstrapped engine app scope (`bootstrap(...).app` or an
   * `IAppScopeHandle`). The klient does NOT own its lifecycle — `close()`
   * leaves the scope alone.
   */
  readonly scope: ScopeLike;
}

class MemoryChannel implements KlientChannel {
  private readonly dispatcher;

  constructor(scope: ScopeLike) {
    this.dispatcher = createMemoryDispatcher(scope);
  }

  call(scope: ScopeRef, service: string, method: string, args: unknown[]): Promise<unknown> {
    return this.dispatcher.call(scope, service, method, args);
  }

  stream(scope: ScopeRef, service: string, method: string, args: unknown[]): AsyncIterable<unknown> {
    return this.dispatcher.stream(scope, service, method, args);
  }

  listen(
    scope: ScopeRef,
    source: EventSourceRef,
    handler: (data: unknown) => void,
    onError?: (error: Error) => void,
  ): IDisposable {
    return this.dispatcher.listen(scope, source, handler, onError);
  }

  close(): Promise<void> {
    // The scope belongs to the host; nothing transport-side to release.
    return Promise.resolve();
  }
}

export function createKlient(options: MemoryKlientOptions): Klient {
  return createKlientFromChannel(new MemoryChannel(options.scope), options);
}