@phreshos/client 0.1.0 → 0.1.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/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2026 Zohayr SLILEH
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
package/README.md CHANGED
@@ -17,9 +17,31 @@ It uses the domain objects and shared contracts from `@phreshos/core` through
17
17
  a peer dependency. It does not redefine those objects, own server-side
18
18
  capabilities, or contain host and transport implementations.
19
19
 
20
- Its `Host` contract exposes only desktop-session capabilities: surface and
21
- pointer state, publicly served values, and unrestricted server-side Fetch. It
22
- does not expose system-wide Program or Process discovery.
20
+ Its `Host` contract exposes only desktop-session capabilities: the public
21
+ system Theme, surface and pointer state, publicly served values, and
22
+ unrestricted server-side Fetch. `host.theme.snapshot()` explicitly and
23
+ asynchronously reads the current snapshot retained by the desktop host.
24
+ `host.theme.subscribe("change", listener)` is an ordinary live subscription:
25
+ it receives only complete replacements published after registration, with no
26
+ initial value or replay. The Client cannot write the authoritative value. The
27
+ Host does not expose system-wide Program or Process discovery.
28
+
29
+ Surface and pointer access are independent objects rather than events merged
30
+ into Host:
31
+
32
+ ```ts
33
+ const surface = await host.surface.size()
34
+ const stopSurface = host.surface.subscribe("resize", next => undefined)
35
+
36
+ const position = await host.pointer.position()
37
+ const stopPointer = host.pointer.subscribe("move", next => undefined)
38
+ ```
39
+
40
+ A Surface contains only the width and height of the current Client Window's
41
+ own layer. Client code cannot select another layer, and the desktop's gutter
42
+ never enters an endpoint. Pointer position and movement both require the
43
+ `pointer` permission. Reads are asynchronous requests; subscriptions receive
44
+ only future publications and never replay a retained value.
23
45
 
24
46
  A Client may traverse `Process.parent()` through any number of ancestors in
25
47
  its own Program. The first parent outside that Program is structurally hidden
@@ -31,28 +53,53 @@ Its JavaScript entry point adapts the iframe boundary to these contracts. The
31
53
  SDK owns callbacks, waits, queues, and their cleanup; the boundary owns only
32
54
  the forwarding registrations requested by the SDK.
33
55
 
56
+ Importing the SDK and establishing the iframe's host lease inject no message
57
+ into the endpoint. Identity, Theme, Process, Window, readiness, lifecycle, and
58
+ application values enter only in response to an explicit request or a live
59
+ registration made by Program code.
60
+
34
61
  `Current` combines navigation into the executing Client's Process with its
35
- inbound subscription Channel. The paired Server is explicitly named as
62
+ Channel. The paired Server is explicitly named as
36
63
  `current.server`; its publishing, asking, existence, readiness, start, and stop
37
64
  operations never masquerade as properties of `current`. `current.stop()` stops
38
65
  the executing Client, while complete Process exit remains available only
39
- through `current.process()`.
66
+ through `current.process()`. It is the canonical Process-owned handle, so
67
+ `current.server === (await current.process()).server`.
68
+ Endpoint `process()` navigation is asynchronous; contextual ownership is
69
+ requested only when navigation needs it and then retained by the SDK.
70
+
71
+ All domain handles are canonical within this iframe's JavaScript realm. Lookup,
72
+ navigation, event payloads, and message metadata reuse the same weakly retained
73
+ handle. A Client and its synchronous `window` capability remain stable for the
74
+ Process lifetime; Window operations always address that Client's current live
75
+ presentation state.
40
76
 
41
77
  `server.ask()` does not route a question before the current Server incarnation
42
78
  is ready. The Client SDK owns one deadline across readiness and the answer;
43
79
  absence or incarnation loss rejects without turning the boundary into a waiter.
44
80
 
45
- The package provides two contextual values rather than constructors:
81
+ The package provides two contextual runtime entry points:
46
82
 
47
83
  ```ts
48
84
  import { host, current } from "@phreshos/client"
49
85
  ```
50
86
 
51
- The current Client's inbound Channel is composed directly into `current`. It
52
- exposes `subscribe()`, `waitFor()`, `events()`, and `observe()` for events
53
- addressed to this Client. It has no outbound, existence, readiness, or
54
- lifecycle operations; those belong to `current.server`, `current.stop()`, or an
55
- explicit Endpoint handle.
87
+ It also re-exports the shared Core runtime classes—`Program`, `Process`,
88
+ `Endpoint`, `Server`, and `Client`—and refines the handles returned through
89
+ them. These are the same domain classes used by the Server SDK, so
90
+ `instanceof Server` and `instanceof Client` retain one meaning. `Window`, like
91
+ `ClientTraffic`, is a type-only capability owned by Client and has no
92
+ independent `instanceof` identity.
93
+
94
+ The current Client's Channel is composed directly into `current`. Its
95
+ subscription tools receive events addressed to this Client, while `publish()`
96
+ emits outward from this Client without choosing a destination. Existence,
97
+ readiness, and lifecycle operations belong to `current.server`,
98
+ `current.stop()`, or an explicit Endpoint handle.
99
+
100
+ An Endpoint handle is also a selective source: `endpoint.subscribe()` follows
101
+ destinationless events emitted by that Endpoint. Its `traffic` property remains
102
+ reserved for directed publications, questions, and answers.
56
103
 
57
104
  Messages sent by an Endpoint in the same Program contain that real Endpoint in
58
105
  `from`. If the sender belongs to another Program, `from` is `null`; the foreign
@@ -61,5 +108,40 @@ The same rule applies to Client-visible traffic destinations.
61
108
 
62
109
  Client-visible Program handles can operate only within their own Program.
63
110
  They deliberately omit `install()` and `fork()`, and their storage areas never
64
- expose host filesystem paths. Client Window handles add synchronous
65
- `localMove()` and `localResize()` for representation-local gestures.
111
+ expose host filesystem paths. Client Window capabilities add awaitable
112
+ `localMove()` and `localResize()` for representation-local gestures. Their
113
+ Promises confirm that the current Client host accepted and applied the local
114
+ draft; they do not enter server authority or emit Window events.
115
+
116
+ An `under` or `over` Client may own one authoritative host-rendered Surface.
117
+ The capability is command-only: Program code may change or remove it, but
118
+ cannot read or subscribe to its server-owned state:
119
+
120
+ ```ts
121
+ await window.surface.set({
122
+ opacity: 0.65,
123
+ radius: "large",
124
+ transaction: { duration: 240, easing: "ease-out" }
125
+ })
126
+
127
+ await window.surface.remove()
128
+ ```
129
+
130
+ The server stores the target beside its Window and delivers it internally to
131
+ the desktop. `set()` with no settings creates a sharp, fully opaque Surface.
132
+ Opacity is a finite number from `0` through `1`; zero retains the Surface node.
133
+ Radius accepts a nonnegative pixel number, a Theme-derived `ScaleLevel`, or
134
+ `"full"`. Only `remove()` restores exact `null` and immediately removes the
135
+ node. The optional transaction uses milliseconds and a stable named or cubic
136
+ Bézier easing; the desktop performs the motion, honors reduced motion, and does
137
+ does not replay a stored transaction when restoring desktop state. The sharp
138
+ container follows the iframe geometry while the independently rounded Surface
139
+ neither clips nor masks Client content. `window` and `wallpaper` layers reject
140
+ the capability.
141
+
142
+ `program.icon()` requests the current Program's guaranteed PNG `Blob` on
143
+ demand. The desktop derives the Program from the calling frame; no identity,
144
+ private asset address, or filesystem path crosses from Client code.
145
+
146
+ Persistent startup is deliberately absent. Only a Server endpoint may change
147
+ whether an installed Program creates a Process when the system starts.
package/dist/channel.d.ts CHANGED
@@ -1,8 +1,12 @@
1
1
  import type { Channel as CoreChannel, ChannelCapture as CoreChannelCapture, ChannelEvents as CoreChannelEvents, ChannelMessage as CoreChannelMessage } from "@phreshos/core";
2
2
  import { type Endpoint } from "./domain.js";
3
+ /** One value addressed to the current Client, with a client-visible sender. */
3
4
  export type ChannelMessage<Payload = unknown> = CoreChannelMessage<Payload, Endpoint | null>;
5
+ /** Applies the client-visible sender envelope to known Channel events. */
4
6
  export type ChannelEvents<Events extends object> = CoreChannelEvents<Events, Endpoint | null>;
7
+ /** Every event observable through the current Client's Channel. */
5
8
  export type ChannelCapture<Events extends object = {}> = CoreChannelCapture<Events, Endpoint | null>;
9
+ /** Events explicitly accepted by the current Client. */
6
10
  export interface Channel<Events extends object = {}> extends CoreChannel<Events, Endpoint | null> {
7
11
  }
8
12
  export declare const channel: Channel;
package/dist/channel.js CHANGED
@@ -8,6 +8,9 @@ class ClientChannel extends Events {
8
8
  observer(event, message(value));
9
9
  }));
10
10
  }
11
+ publish(event, payload = undefined) {
12
+ wire.send("end-host", "emit", event, payload);
13
+ }
11
14
  }
12
15
  function message(value) {
13
16
  const raw = value;
package/dist/current.d.ts CHANGED
@@ -1,20 +1,23 @@
1
- import type { Askable, Channel as CoreChannel, Publishable } from "@phreshos/core";
2
- import { type Process, type Program, type Endpoint, type Window } from "./domain.js";
3
- /** The paired Server as addressed from the currently executing Client. */
4
- export interface CurrentServer extends Publishable, Askable {
5
- exists(): Promise<boolean>;
6
- start(): Promise<void>;
7
- stop(): Promise<void>;
8
- waitReady(timeout?: number): Promise<void>;
9
- }
1
+ import type { Channel as CoreChannel } from "@phreshos/core";
2
+ import { Server, type Endpoint, type Process, type Program, type Window } from "./domain.js";
3
+ /** The current Process's canonical Server handle. */
4
+ export type CurrentServer<Events extends object = {}> = Server<Events>;
10
5
  /** Current Client context: its inbound Channel, owner hierarchy, and paired Server. */
11
6
  export interface Current<Events extends object = {}> extends CoreChannel<Events, Endpoint | null> {
7
+ /** The same Server handle exposed by the current Process. */
12
8
  readonly server: CurrentServer;
9
+ /** Presentation capability of this current Client. */
10
+ readonly window: Window;
11
+ /** Returns the Process represented by this Client. */
13
12
  process(): Promise<Process>;
13
+ /** Returns the accessible parent Process, or `null` when none exists. */
14
14
  parent(): Promise<Process | null>;
15
+ /** Returns the Program that owns this Client. */
15
16
  program(): Promise<Program>;
16
- window(): Promise<Window>;
17
+ /** Returns one immutable option supplied when this Process was created. */
17
18
  option(name: string): Promise<string | undefined>;
19
+ /** Stops the current Client; rejects when it is the final live Endpoint. */
18
20
  stop(): Promise<void>;
19
21
  }
22
+ /** Inbound events, owner hierarchy, and paired Server for the current Client. */
20
23
  export declare const current: Current;
package/dist/current.js CHANGED
@@ -1,15 +1,19 @@
1
1
  import { channel } from "./channel.js";
2
2
  import Deadline from "./deadline.js";
3
- import { process, program } from "./domain.js";
3
+ import { Client, Server, ServerTrafficHandle, TrafficHandle, bindEvents, endpointEvents, process, program, window as windowHandle } from "./domain.js";
4
4
  import wire from "./wire.js";
5
- class PairedServer {
6
- publish(event, payload) { wire.send("end-end", event, payload); }
7
- async ask(event, payload) {
8
- return this.askWithin(undefined, event, payload);
9
- }
10
- timeout(milliseconds) {
11
- return { ask: (event, payload) => this.askWithin(milliseconds, event, payload) };
5
+ const ServerBase = Server;
6
+ const ClientBase = Client;
7
+ class CurrentServerHandle extends ServerBase {
8
+ owner;
9
+ traffic = new ServerTrafficHandle(null, "server");
10
+ constructor(owner) {
11
+ super();
12
+ this.owner = owner;
13
+ bindEvents(this, endpointEvents(null, "server"));
12
14
  }
15
+ process() { return this.owner(); }
16
+ publish(event, payload = undefined) { wire.send("end-end", event, payload); }
13
17
  async exists() {
14
18
  const answer = await wire.request(["exists", "server"]);
15
19
  return answer[0];
@@ -17,21 +21,69 @@ class PairedServer {
17
21
  async start() { await wire.request(["start-endpoint", undefined, "server"]); }
18
22
  async stop() { await wire.request(["stop-endpoint", undefined, "server"]); }
19
23
  async waitReady(timeout) { await wire.request(["wait-ready"], timeout); }
24
+ async ask(event, payload = undefined) {
25
+ return this.askWithin(undefined, event, payload);
26
+ }
27
+ timeout(milliseconds) {
28
+ return { ask: (event, payload = undefined) => this.askWithin(milliseconds, event, payload) };
29
+ }
20
30
  async askWithin(timeout, event, payload) {
21
31
  const deadline = new Deadline(timeout);
22
32
  await wire.requestWithin(["wait-ready", null, true], deadline);
23
33
  return await wire.askServerWithin(event, payload, deadline);
24
34
  }
25
35
  }
36
+ let ownerPromise = null;
37
+ let currentServer;
38
+ let currentClient;
39
+ function owner() {
40
+ if (!ownerPromise) {
41
+ const resolving = wire.request(["process"]).then(answer => {
42
+ return process(answer[0], { server: currentServer, client: currentClient });
43
+ });
44
+ const retained = resolving.catch(error => {
45
+ if (ownerPromise === retained)
46
+ ownerPromise = null;
47
+ throw error;
48
+ });
49
+ ownerPromise = retained;
50
+ }
51
+ return ownerPromise;
52
+ }
53
+ currentServer = new CurrentServerHandle(owner);
54
+ class CurrentClientHandle extends ClientBase {
55
+ owner;
56
+ traffic = new TrafficHandle(null, "client");
57
+ window = windowHandle(async () => {
58
+ const identity = await wire.identity();
59
+ return { identity: identity.process, reference: identity.reference };
60
+ });
61
+ constructor(owner) {
62
+ super();
63
+ this.owner = owner;
64
+ bindEvents(this, endpointEvents(null, "client"));
65
+ }
66
+ process() { return this.owner(); }
67
+ publish(event, payload = undefined) {
68
+ void wire.identity().then(identity => {
69
+ wire.send("end-host", "send", { identity: identity.process, reference: identity.reference }, "client", event, payload);
70
+ });
71
+ }
72
+ async exists() {
73
+ const answer = await wire.request(["exists", "client"]);
74
+ return answer[0];
75
+ }
76
+ async start(overrides = {}) { await wire.request(["start-endpoint", undefined, "client", overrides]); }
77
+ async stop() { await wire.request(["stop-endpoint", undefined, "client"]); }
78
+ }
79
+ currentClient = new CurrentClientHandle(owner);
26
80
  class ClientCurrent {
27
- server = new PairedServer();
81
+ server = currentServer;
82
+ window = currentClient.window;
28
83
  constructor() {
29
84
  bindChannel(this, channel);
30
85
  }
31
- async process() {
32
- const answer = await wire.request(["process"]);
33
- return process(answer[0]);
34
- }
86
+ process() { return owner(); }
35
87
  async parent() {
36
88
  const answer = await wire.request(["parent"]);
37
89
  return answer[0] ? process(answer[0]) : null;
@@ -40,7 +92,6 @@ class ClientCurrent {
40
92
  const answer = await wire.request(["program"]);
41
93
  return program(answer[0]);
42
94
  }
43
- async window() { return (await this.process()).client.window(); }
44
95
  async option(name) {
45
96
  const answer = await wire.request(["option", undefined, name]);
46
97
  return answer[0];
@@ -49,10 +100,12 @@ class ClientCurrent {
49
100
  }
50
101
  function bindChannel(target, source) {
51
102
  Object.assign(target, {
103
+ publish: source.publish.bind(source),
52
104
  subscribe: source.subscribe.bind(source),
53
105
  waitFor: source.waitFor.bind(source),
54
106
  events: source.events.bind(source),
55
107
  observe: source.observe.bind(source)
56
108
  });
57
109
  }
110
+ /** Inbound events, owner hierarchy, and paired Server for the current Client. */
58
111
  export const current = new ClientCurrent();
package/dist/domain.d.ts CHANGED
@@ -1,16 +1,21 @@
1
- import { Client as CoreClient, Endpoint as CoreEndpoint, Process as CoreProcess, Program as CoreProgram, Server as CoreServer, Window as CoreWindow, type AnswerCapture as CoreAnswerCapture, type AnswerMessage as CoreAnswerMessage, type AnswerObserver as CoreAnswerObserver, type AskCapture as CoreAskCapture, type AskMessage as CoreAskMessage, type AskObserver as CoreAskObserver, type ClientTraffic as CoreClientTraffic, type ClientDeclaration, type EndpointTraffic as CoreEndpointTraffic, type EndpointDeclaration, type Exit, type Launch, type Position, type ServerTraffic as CoreServerTraffic, type Size, type TrafficMessage as CoreTrafficMessage, type TrafficCapture as CoreTrafficCapture, type TrafficEvents as CoreTrafficEvents } from "@phreshos/core";
1
+ import { Client as CoreClient, Endpoint as CoreEndpoint, Process as CoreProcess, Program as CoreProgram, Server as CoreServer, type AnswerCapture as CoreAnswerCapture, type AnswerMessage as CoreAnswerMessage, type AnswerObserver as CoreAnswerObserver, type AskCapture as CoreAskCapture, type AskMessage as CoreAskMessage, type AskObserver as CoreAskObserver, type Cleanup, type ClientTraffic as CoreClientTraffic, type ClientDeclaration, type EndpointTraffic as CoreEndpointTraffic, type EndpointDeclaration, type Exit, type Launch, type Position, type ServerTraffic as CoreServerTraffic, type Size, type TrafficMessage as CoreTrafficMessage, type TrafficCapture as CoreTrafficCapture, type TrafficEvents as CoreTrafficEvents, type Window as CoreWindow, type WindowState } from "@phreshos/core";
2
2
  import Events from "./events.js";
3
+ export interface HandleAddress {
4
+ identity: string;
5
+ reference: string;
6
+ }
3
7
  export interface ProgramRecord {
8
+ reference: string;
4
9
  identity: string;
5
10
  installed?: boolean;
6
11
  name: string;
7
12
  version: string | null;
8
13
  description: string | null;
9
- icons?: boolean;
10
14
  server: EndpointDeclaration | null;
11
15
  client: ClientDeclaration | null;
12
16
  }
13
17
  export interface ProcessRecord {
18
+ reference: string;
14
19
  identity: string;
15
20
  name: string | null;
16
21
  program: ProgramRecord;
@@ -23,71 +28,119 @@ export interface EndpointReference {
23
28
  kind: "server" | "client";
24
29
  process: ProcessRecord;
25
30
  }
26
- export type Program<Events extends object = {}> = Omit<CoreProgram<Events>, "processes" | "getProcess" | "createProcess"> & {
31
+ export type WindowRecord = WindowState;
32
+ /** Program handle visible inside a structurally isolated Client. */
33
+ export type Program<Events extends object = {}> = Omit<CoreProgram<Events>, "processes" | "firstProcess" | "lastProcess" | "getProcess" | "createProcess"> & {
34
+ /** Returns every live Process of this Program visible to the current Client. */
27
35
  processes(): Promise<Process[]>;
36
+ /** Returns the earliest-started visible live Process, or `null` when none exist. */
37
+ firstProcess(): Promise<Process | null>;
38
+ /** Returns the latest-started visible live Process, or `null` when none exist. */
39
+ lastProcess(): Promise<Process | null>;
40
+ /** Finds a visible live Process by runtime identity or Program-local name. */
28
41
  getProcess(identityOrName: string): Promise<Process | null>;
42
+ /** Creates one Process of this same Program. */
29
43
  createProcess(launch?: Launch): Promise<Process>;
30
44
  };
45
+ /** Process handle visible inside a structurally isolated Client. */
31
46
  export type Process<Events extends object = {}> = Omit<CoreProcess<Events>, "server" | "client" | "program" | "parent"> & {
47
+ /** Permanent handle to this Process's Server. */
32
48
  readonly server: Server;
49
+ /** Permanent handle to this Process's Client. */
33
50
  readonly client: Client;
51
+ /** Returns the Program that owns this Process. */
34
52
  program(): Program;
53
+ /** Returns the visible parent Process, or `null` when no parent is accessible. */
35
54
  parent(): Promise<Process | null>;
36
55
  };
56
+ /** Traffic value with identities hidden when they cross the Client boundary. */
37
57
  export type TrafficMessage<Payload = unknown> = CoreTrafficMessage<Payload, Endpoint | null>;
58
+ /** Applies client-visible destination metadata to known traffic events. */
38
59
  export type TrafficEvents<Events extends object> = CoreTrafficEvents<Events, Endpoint | null>;
60
+ /** Every ordinary event observable in client-visible Endpoint traffic. */
39
61
  export type TrafficCapture<Events extends object = {}> = CoreTrafficCapture<Events, Endpoint | null>;
62
+ /** Question with a Server destination hidden when it crosses the Client boundary. */
40
63
  export type AskMessage<Payload = unknown> = CoreAskMessage<Payload, Server | null>;
64
+ /** One question observable in client-visible Endpoint traffic. */
41
65
  export type AskCapture<Payload = unknown> = CoreAskCapture<Payload, Server | null>;
66
+ /** Callback that observes questions sent by a client-visible Endpoint. */
42
67
  export type AskObserver<Payload = unknown> = CoreAskObserver<Payload, Server | null>;
68
+ /** Answer with an Endpoint destination hidden when it crosses the Client boundary. */
43
69
  export type AnswerMessage<Result = unknown> = CoreAnswerMessage<Result, Endpoint | null>;
70
+ /** One answer observable in client-visible Server traffic. */
44
71
  export type AnswerCapture<Result = unknown> = CoreAnswerCapture<Result, Endpoint | null>;
72
+ /** Callback that observes answers sent by a client-visible Server. */
45
73
  export type AnswerObserver<Result = unknown> = CoreAnswerObserver<Result, Endpoint | null>;
74
+ /** Directed communication originating from one client-visible Endpoint. */
46
75
  export type EndpointTraffic<Events extends object = {}> = CoreEndpointTraffic<Events, Endpoint | null, Server | null>;
76
+ /** Directed communication originating from one client-visible Server. */
47
77
  export type ServerTraffic<Events extends object = {}> = CoreServerTraffic<Events, Endpoint | null, Server | null>;
78
+ /** Directed communication originating from one client-visible Client. */
48
79
  export type ClientTraffic<Events extends object = {}> = CoreClientTraffic<Events, Endpoint | null, Server | null>;
80
+ /** Common Endpoint handle visible inside a structurally isolated Client. */
49
81
  export type Endpoint<Events extends object = {}> = Omit<CoreEndpoint<Events>, "process" | "traffic"> & {
82
+ /** Directed communication originating from this Endpoint. */
50
83
  readonly traffic: EndpointTraffic<Events>;
51
- process(): Process;
84
+ /** Returns the Process that owns this Endpoint. */
85
+ process(): Promise<Process>;
52
86
  };
87
+ /** Server handle visible inside a structurally isolated Client. */
53
88
  export type Server<Events extends object = {}> = Omit<CoreServer<Events>, "process" | "traffic"> & Endpoint<Events> & {
89
+ /** Directed communication originating from this Server. */
54
90
  readonly traffic: ServerTraffic<Events>;
55
- process(): Process;
91
+ /** Returns the Process that owns this Server. */
92
+ process(): Promise<Process>;
56
93
  };
94
+ /** Client handle visible inside a structurally isolated Client. */
57
95
  export type Client<Events extends object = {}> = Omit<CoreClient<Events>, "process" | "traffic" | "window"> & Endpoint<Events> & {
96
+ /** Directed communication originating from this Client. */
58
97
  readonly traffic: ClientTraffic<Events>;
59
- process(): Process;
60
- window(): Promise<Window>;
98
+ /** Presentation capability permanently owned by this Client handle. */
99
+ readonly window: Window;
100
+ /** Returns the Process that owns this Client. */
101
+ process(): Promise<Process>;
61
102
  };
62
- export type Window<Events extends object = {}> = Omit<CoreWindow<Events>, "client"> & {
63
- client(): Client;
64
- localMove(position: Position): void;
65
- localResize(size: Size): void;
103
+ /** Client-owned Window capability visible inside a Client boundary. */
104
+ export type Window = CoreWindow & {
105
+ /** Moves this Window representation without changing authoritative state. */
106
+ localMove(position: Position): Promise<void>;
107
+ /** Resizes this Window representation without changing authoritative state. */
108
+ localResize(size: Size): Promise<void>;
66
109
  };
110
+ export declare class TrafficHandle extends Events {
111
+ protected readonly target: HandleAddress | null;
112
+ protected readonly kind: "server" | "client";
113
+ constructor(target: HandleAddress | null, kind: "server" | "client");
114
+ observeAsks(observer: (capture: AskCapture) => unknown): Cleanup;
115
+ }
116
+ export declare class ServerTrafficHandle extends TrafficHandle {
117
+ observeAnswers(observer: (capture: AnswerCapture) => unknown): Cleanup;
118
+ }
119
+ type WindowTarget = () => Promise<HandleAddress>;
67
120
  export declare function scoped(route: string, subject: string | null, convert: (event: string, values: unknown[]) => unknown): Events;
121
+ /** Destinationless events originating from one Endpoint handle. */
122
+ export declare function endpointEvents(target: HandleAddress | null, half: "server" | "client"): Events;
68
123
  export declare function exit(code: unknown, signal: unknown): Exit;
69
124
  export declare function trafficMessage(value: unknown): TrafficMessage;
70
125
  export declare function bindEvents(target: object, events: Events): void;
71
126
  export declare function program(record: ProgramRecord): Program;
72
- export declare function process(record: ProcessRecord): Process;
127
+ export declare function process(record: ProcessRecord, endpoints?: {
128
+ server?: Server;
129
+ client?: Client;
130
+ }): Process;
73
131
  export declare function endpoint(reference: EndpointReference | undefined): Endpoint;
132
+ export declare function claimEndpoint(reference: string, kind: "server" | "client", endpoint: Endpoint): Endpoint<{}>;
133
+ export declare function window(target: WindowTarget): Window;
74
134
  /** Resolves only endpoint identities intentionally visible to this Client. */
75
135
  export declare function visibleEndpoint(reference: EndpointReference | null | undefined): Endpoint | null;
76
- export declare const Program: {
77
- new <Events extends object = {}>(): Program<Events>;
78
- };
79
- export declare const Process: {
80
- new <Events extends object = {}>(): Process<Events>;
81
- };
82
- export declare const Endpoint: {
83
- new <Events extends object = {}>(): Endpoint<Events>;
84
- };
85
- export declare const Server: {
86
- new <Events extends object = {}>(): Server<Events>;
87
- };
88
- export declare const Client: {
89
- new <Events extends object = {}>(): Client<Events>;
90
- };
91
- export declare const Window: {
92
- new <Events extends object = {}>(): Window<Events>;
93
- };
136
+ /** Runtime constructor shared by all client-visible Program handles. */
137
+ export declare const Program: typeof CoreProgram;
138
+ /** Runtime constructor shared by all client-visible Process handles. */
139
+ export declare const Process: typeof CoreProcess;
140
+ /** Runtime constructor shared by all client-visible Endpoint handles. */
141
+ export declare const Endpoint: typeof CoreEndpoint;
142
+ /** Runtime constructor shared by all client-visible Server handles. */
143
+ export declare const Server: typeof CoreServer;
144
+ /** Runtime constructor shared by all client-visible Client handles. */
145
+ export declare const Client: typeof CoreClient;
146
+ export {};