@phreshos/client 0.1.37 → 0.1.39

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/README.md CHANGED
@@ -49,10 +49,16 @@ bun run verify
49
49
  `verify` checks the types and completions, builds the package, and validates its
50
50
  published shape.
51
51
 
52
+ `check` performs static checks, `build` creates distributable output, and `test`
53
+ runs Vitest assertions from `tests/`. Run `build` before testing built artifacts.
54
+ `verify` runs `check`, `build`, and `test` in order. Operational tooling belongs
55
+ in `scripts/`; tests and their fixtures belong in `tests/`. Verification uses
56
+ the committed dependency graph without local package substitutions.
57
+
52
58
  ## Related repositories
53
59
 
54
- - [`@phreshos/core`](https://github.com/PhreshOS/core) owns every shared
55
- contract and domain class exposed here.
60
+ - [`@phreshos/core`](https://github.com/PhreshOS/core) is the one public import
61
+ path for every shared contract and domain class implemented by these handles.
56
62
  - [`@phreshos/server`](https://github.com/PhreshOS/server) adapts the paired
57
63
  Server Endpoint boundary.
58
64
  - [`@phreshos/react`](https://github.com/PhreshOS/react) adapts the Client
@@ -4,19 +4,14 @@ import Events from "./events.js";
4
4
  export default class ClientAppearance extends Events<AppearanceEvents, never> implements WritableAppearance {
5
5
  constructor();
6
6
  snapshot(): Promise<Readonly<{
7
- background: import("@phreshos/core").ThemedValue<string, string>;
8
- foreground: import("@phreshos/core").ThemedValue<string, string>;
9
- primary: import("@phreshos/core").ThemedValue<string, string>;
10
- secondary: import("@phreshos/core").ThemedValue<string, string>;
11
- success: import("@phreshos/core").ThemedValue<string, string>;
12
- warning: import("@phreshos/core").ThemedValue<string, string>;
13
- danger: import("@phreshos/core").ThemedValue<string, string>;
14
- info: import("@phreshos/core").ThemedValue<string, string>;
15
- spacing: import("@phreshos/core").ThemedValue<number>;
16
- radius: import("@phreshos/core").ThemedValue<number>;
17
- surface: import("@phreshos/core").ThemedValue<import("@phreshos/core").AppearanceSurface, import("@phreshos/core").AppearanceSurface>;
18
- signInWallpaper: import("@phreshos/core").ThemedValue<string | null, string | null>;
19
- desktopWallpaper: import("@phreshos/core").ThemedValue<string | null, string | null>;
7
+ colors: import("@phreshos/core").ThemedValue<import("@phreshos/core").AppearanceColors>;
8
+ spacing: number;
9
+ radius: number;
10
+ shadow: import("@phreshos/core").ThemedValue<import("@phreshos/core").AppearanceShadow>;
11
+ material: import("@phreshos/core").ThemedValue<import("@phreshos/core").AppearanceMaterial>;
12
+ transaction: import("@phreshos/core").AppearanceTransaction;
13
+ signInWallpaper: import("@phreshos/core").ThemedValue<string | null>;
14
+ desktopWallpaper: import("@phreshos/core").ThemedValue<string | null>;
20
15
  }>>;
21
16
  update(appearance: Appearance): Promise<void>;
22
17
  }
@@ -1,19 +1,19 @@
1
- import { createAppearanceSnapshot } from "@phreshos/core";
1
+ import { parseAppearance } from "@phreshos/core";
2
2
  import Events from "./events.js";
3
3
  import wire from "./wire.js";
4
4
  /** Read-only System Appearance reached through the Desktop boundary. */
5
5
  export default class ClientAppearance extends Events {
6
6
  constructor() {
7
7
  super((event, listener, impossible) => wire.on("host-appearance", event, value => {
8
- listener(createAppearanceSnapshot(value));
8
+ listener(parseAppearance(value));
9
9
  }, null, impossible), observer => wire.onAll("host-appearance", (event, value) => {
10
10
  if (typeof event === "string")
11
- observer(event, createAppearanceSnapshot(value));
11
+ observer(event, parseAppearance(value));
12
12
  }));
13
13
  }
14
14
  async snapshot() {
15
15
  const [appearance] = await wire.request(["appearance"]);
16
- return createAppearanceSnapshot(appearance);
16
+ return parseAppearance(appearance);
17
17
  }
18
18
  async update(appearance) {
19
19
  await wire.request(["updateAppearance", appearance]);
package/dist/content.d.ts CHANGED
@@ -1,6 +1,7 @@
1
+ import type { WritableContent } from "@phreshos/core";
1
2
  export type ContentBody = Blob | ReadableStream<Uint8Array>;
2
3
  /** Converts one authored value into the browser body and metadata used by storage and serving. */
3
- export declare function content(value: unknown): {
4
+ export declare function content(value: WritableContent): {
4
5
  body: ContentBody;
5
6
  extension: string;
6
7
  type: string;
package/dist/context.d.ts CHANGED
@@ -1,13 +1,3 @@
1
- import type { ClientContext as CoreClientContext, ContextCapture as CoreContextCapture, ContextEvents as CoreContextEvents, ContextMessage as CoreContextMessage } from "@phreshos/core";
2
- import { ServerEndpoint, type Endpoint } from "./domain.js";
3
- /** The executing Process's canonical Server Endpoint handle. */
4
- export type ContextServer<Events extends object = {}, Fallback = unknown> = ServerEndpoint<Events, Fallback>;
5
- /** One value addressed to the current Client Endpoint, with a client-visible sender. */
6
- export type ContextMessage<Payload = unknown> = CoreContextMessage<Payload, Endpoint | null>;
7
- /** Applies the client-visible sender envelope to known Context events. */
8
- export type ContextEvents<Events extends object> = CoreContextEvents<Events, Endpoint | null>;
9
- /** Every event observable through the current Client Endpoint Context. */
10
- export type ContextCapture<Events extends object = {}> = CoreContextCapture<Events, Endpoint | null>;
11
- export type Context<Events extends object = {}> = CoreClientContext<Events>;
1
+ import type { ClientContext as CoreClientContext } from "@phreshos/core";
12
2
  /** Inbound events, owner hierarchy, and paired Server Endpoint for this Client runtime. */
13
- export declare const context: Context;
3
+ export declare const context: CoreClientContext;
package/dist/context.js CHANGED
@@ -1,21 +1,27 @@
1
1
  import Deadline from "./deadline.js";
2
- import { ClientEndpoint, ServerEndpoint, ServerTrafficHandle, TrafficHandle, bindEvents, endpointLifecycle, endpointEvents, process, program, visibleEndpoint, localWindow, window as windowHandle, } from "./domain.js";
2
+ import { ClientEndpoint, ServerEndpoint, ServerTrafficHandle, TrafficHandle, endpointLifecycle, endpointEvents, process, program, visibleEndpoint, localWindow, window as windowHandle, } from "./domain.js";
3
3
  import Events from "./events.js";
4
4
  import wire from "./wire.js";
5
5
  import { contextPermissions } from "./permissions.js";
6
- const ServerEndpointBase = ServerEndpoint;
7
- const ClientEndpointBase = ClientEndpoint;
8
- class ContextServerHandle extends ServerEndpointBase {
6
+ class ContextServerHandle extends ServerEndpoint {
9
7
  owner;
8
+ subscribe;
9
+ wait;
10
+ events;
10
11
  traffic = new ServerTrafficHandle(null, "server");
11
12
  lifecycle = endpointLifecycle(currentAddress, "server");
12
13
  constructor(owner) {
13
14
  super();
14
15
  this.owner = owner;
15
- bindEvents(this, endpointEvents(null, "server"));
16
+ const events = endpointEvents(null, "server");
17
+ this.subscribe = events.subscribe;
18
+ this.wait = events.wait;
19
+ this.events = events.events;
16
20
  }
17
21
  process() { return this.owner(); }
18
- publish(event, payload = undefined) { wire.send("end-end", event, payload); }
22
+ publish = (event, payload = undefined) => {
23
+ wire.send("end-end", event, payload);
24
+ };
19
25
  async exists() {
20
26
  const answer = await wire.request(["exists", "server"]);
21
27
  return answer[0];
@@ -54,22 +60,28 @@ function owner() {
54
60
  return ownerPromise;
55
61
  }
56
62
  contextServer = new ContextServerHandle(owner);
57
- class ContextClientHandle extends ClientEndpointBase {
63
+ class ContextClientHandle extends ClientEndpoint {
58
64
  owner;
65
+ subscribe;
66
+ wait;
67
+ events;
59
68
  traffic = new TrafficHandle(null, "client");
60
69
  lifecycle = endpointLifecycle(currentAddress, "client");
61
70
  window = windowHandle(currentAddress);
62
71
  constructor(owner) {
63
72
  super();
64
73
  this.owner = owner;
65
- bindEvents(this, endpointEvents(null, "client"));
74
+ const events = endpointEvents(null, "client");
75
+ this.subscribe = events.subscribe;
76
+ this.wait = events.wait;
77
+ this.events = events.events;
66
78
  }
67
79
  process() { return this.owner(); }
68
- publish(event, payload = undefined) {
80
+ publish = (event, payload = undefined) => {
69
81
  void wire.identity().then(identity => {
70
82
  wire.send("end-host", "send", { identity: identity.process, reference: identity.reference }, "client", event, payload);
71
83
  });
72
- }
84
+ };
73
85
  async exists() {
74
86
  const answer = await wire.request(["exists", "client"]);
75
87
  return answer[0];
@@ -101,9 +113,9 @@ class ClientContext extends Events {
101
113
  const answer = await wire.request(["current-program"]);
102
114
  return program(answer[0]);
103
115
  }
104
- async option(name) {
105
- const answer = await wire.request(["option", undefined, name]);
106
- return answer[0];
116
+ async options(name) {
117
+ const process = await owner();
118
+ return name === undefined ? process.options() : process.options(name);
107
119
  }
108
120
  async stop() { await wire.request(["stop-current"]); }
109
121
  async isService() { return contextClient.isService(); }
@@ -1,8 +1,8 @@
1
1
  import ClientPreferences from "./preferences.js";
2
- import ClientSurface from "./surface.js";
2
+ import ClientViewport from "./viewport.js";
3
3
  /** Desktop access bound to the current Client Endpoint's Process boundary. */
4
4
  class ClientDesktop {
5
- surface = new ClientSurface();
5
+ viewport = new ClientViewport();
6
6
  preferences = new ClientPreferences();
7
7
  }
8
8
  /** The Desktop environment containing this Client Endpoint. */
@@ -0,0 +1,9 @@
1
+ import type { DesktopViewportEvents, DesktopViewportSource } from "@phreshos/core";
2
+ import Events from "../events.js";
3
+ /** Read-only access to the Desktop viewport containing this Client Endpoint. */
4
+ export default class ClientViewport extends Events<DesktopViewportEvents, never> implements DesktopViewportSource {
5
+ constructor();
6
+ snapshot(): Promise<Readonly<{
7
+ size: import("@phreshos/core").DesktopSize;
8
+ }>>;
9
+ }
@@ -1,23 +1,23 @@
1
1
  import Events from "../events.js";
2
2
  import wire from "../wire.js";
3
- /** Read-only access to the Desktop surface containing this Client Endpoint. */
4
- export default class ClientSurface extends Events {
3
+ /** Read-only access to the Desktop viewport containing this Client Endpoint. */
4
+ export default class ClientViewport extends Events {
5
5
  constructor() {
6
- super((event, listener, impossible) => wire.on("host-desktop-surface", event, value => {
6
+ super((event, listener, impossible) => wire.on("host-desktop-viewport", event, value => {
7
7
  const snapshot = createSnapshot(value);
8
8
  if (snapshot)
9
9
  listener(snapshot);
10
- }, null, impossible), observer => wire.onAll("host-desktop-surface", (event, value) => {
10
+ }, null, impossible), observer => wire.onAll("host-desktop-viewport", (event, value) => {
11
11
  const snapshot = createSnapshot(value);
12
12
  if (typeof event === "string" && snapshot)
13
13
  observer(event, snapshot);
14
14
  }));
15
15
  }
16
16
  async snapshot() {
17
- const answer = await wire.request(["desktopSurface"]);
17
+ const answer = await wire.request(["desktopViewport"]);
18
18
  const snapshot = createSnapshot(answer[0]);
19
19
  if (!snapshot)
20
- throw new Error("The System returned an invalid Desktop surface");
20
+ throw new Error("The System returned an invalid Desktop viewport");
21
21
  return snapshot;
22
22
  }
23
23
  }
package/dist/domain.d.ts CHANGED
@@ -1,50 +1,12 @@
1
- import { ClientEndpoint as CoreClientEndpoint, Endpoint as CoreEndpoint, Process as CoreProcess, Program as CoreProgram, ServerEndpoint as CoreServerEndpoint, type AnswerCapture as CoreAnswerCapture, type AnswerMessage as CoreAnswerMessage, type AnswerOutcome, type AnswerSubscriber as CoreAnswerSubscriber, type AskCapture as CoreAskCapture, type AskMessage as CoreAskMessage, type AskSubscriber as CoreAskSubscriber, type Cleanup, type ClientTraffic as CoreClientTraffic, type ClientDeclaration, type EndpointTraffic as CoreEndpointTraffic, type Exit, type EventOptions, type LocalWindow, type Position, type ProgramProcess as CoreProgramProcess, type ProgramProcessRunEvent as CoreProgramProcessRunEvent, type ProgramProcessRunOptions as CoreProgramProcessRunOptions, 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";
1
+ import { ClientEndpoint as CoreClientEndpoint, Endpoint as CoreEndpoint, Process as CoreProcess, Program as CoreProgram, ServerEndpoint as CoreServerEndpoint, type AnswerCapture as CoreAnswerCapture, type AnswerMessage as CoreAnswerMessage, type AnswerOutcome, type AnswerSubscriber as CoreAnswerSubscriber, type AskCapture as CoreAskCapture, type AskMessage as CoreAskMessage, type AskSubscriber as CoreAskSubscriber, type Cleanup, type ClientTraffic as CoreClientTraffic, type ClientDeclaration, type EndpointReference as CoreEndpointReference, type EndpointSnapshot, type HandleAddress, type ProcessSnapshot, type ProgramSnapshot, type EndpointTraffic as CoreEndpointTraffic, type EndpointLifecycleEvents, type EndpointDeclaration, type Exit, type EventOptions, type LocalWindow, type ProgramProcess as CoreProgramProcess, type ProgramProcessRunEvent as CoreProgramProcessRunEvent, type ProgramProcessRunOptions as CoreProgramProcessRunOptions, type ServerTraffic as CoreServerTraffic, 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
- }
7
- export interface EndpointDeclarationRecord {
8
- start: boolean;
9
- service: boolean;
10
- }
11
- export interface ClientDeclarationRecord extends EndpointDeclarationRecord {
12
- title: string | null;
13
- size: Size | null;
14
- position: Position | null;
15
- layer: ClientDeclaration["layer"];
16
- minimize: boolean | null;
17
- permissions: ClientDeclaration["permissions"];
18
- }
19
- export interface ProgramRecord {
20
- reference: string;
21
- identity: string;
22
- assetId: string;
23
- installed?: boolean;
24
- name: string;
25
- version: string | null;
26
- description: string | null;
27
- hasAgent: boolean;
28
- server: EndpointDeclarationRecord | null;
29
- client: ClientDeclarationRecord | null;
30
- }
31
- export interface ProcessRecord {
32
- reference: string;
33
- identity: string;
34
- name: string | null;
35
- program: ProgramRecord;
36
- options: Record<string, string>;
37
- startedAt: string | Date;
38
- server: EndpointRecord | null;
39
- client: EndpointRecord | null;
40
- }
41
- export interface EndpointRecord {
42
- service: boolean;
43
- }
44
- export interface EndpointReference {
45
- kind: "server" | "client";
46
- process: ProcessRecord;
47
- }
3
+ export type { HandleAddress };
4
+ export type EndpointDeclarationRecord = EndpointDeclaration;
5
+ export type ClientDeclarationRecord = ClientDeclaration;
6
+ export type ProgramRecord = ProgramSnapshot;
7
+ export type ProcessRecord = ProcessSnapshot;
8
+ export type EndpointRecord = EndpointSnapshot;
9
+ export type EndpointReference = CoreEndpointReference;
48
10
  export type WindowRecord = WindowState;
49
11
  export type Program = CoreProgram;
50
12
  export type ProgramProcess = CoreProgramProcess;
@@ -79,48 +41,47 @@ export type Endpoint<Events extends object = {}, Fallback = unknown> = CoreEndpo
79
41
  export type ServerEndpoint<Events extends object = {}, Fallback = unknown> = CoreServerEndpoint<Events, Fallback>;
80
42
  export type ClientEndpoint<Events extends object = {}, Fallback = unknown> = CoreClientEndpoint<Events, Fallback>;
81
43
  export type Window = CoreWindow;
82
- export declare class TrafficHandle extends Events {
44
+ export declare class TrafficHandle<EventsMap extends object = {}, Fallback = unknown> extends Events<TrafficEvents<EventsMap>, TrafficMessage<Fallback>> {
83
45
  protected readonly target: HandleAddress | null;
84
46
  protected readonly kind: "server" | "client";
85
47
  constructor(target: HandleAddress | null, kind: "server" | "client");
86
- subscribeAsks(subscriber: (capture: AskCapture) => unknown): Cleanup;
87
- asks(options?: EventOptions): AsyncIterableIterator<Readonly<{
48
+ subscribeAsks<Payload = unknown>(subscriber: (capture: AskCapture<Payload>) => unknown): Cleanup;
49
+ asks<Payload = unknown>(options?: EventOptions): AsyncIterableIterator<Readonly<{
88
50
  event: string;
89
51
  questionId: string;
90
52
  message: Readonly<{
91
53
  to: ServerEndpoint<{}, unknown> | null;
92
- payload: unknown;
54
+ payload: Payload;
93
55
  }>;
94
56
  }>>;
95
57
  private followAsks;
96
58
  }
97
- export declare class ServerTrafficHandle extends TrafficHandle {
98
- subscribeAnswers(subscriber: (capture: AnswerCapture) => unknown): Cleanup;
99
- answers(options?: EventOptions): AsyncIterableIterator<Readonly<{
59
+ export declare class ServerTrafficHandle<EventsMap extends object = {}, Fallback = unknown> extends TrafficHandle<EventsMap, Fallback> {
60
+ subscribeAnswers<Result = unknown>(subscriber: (capture: AnswerCapture<Result>) => unknown): Cleanup;
61
+ answers<Result = unknown>(options?: EventOptions): AsyncIterableIterator<Readonly<{
100
62
  event: string;
101
63
  questionId: string;
102
64
  message: Readonly<{
103
65
  to: Endpoint<{}, unknown> | null;
104
- outcome: AnswerOutcome<unknown>;
66
+ outcome: AnswerOutcome<Result>;
105
67
  }>;
106
68
  }>>;
107
69
  private followAnswers;
108
70
  }
109
71
  type WindowTarget = () => Promise<HandleAddress>;
110
- export declare function scoped(route: string, subject: string | null, convert: (event: string, values: unknown[]) => unknown): Events<{}, unknown>;
72
+ export declare function scoped<Definitions extends object = {}, Fallback = unknown>(route: string, subject: string | null, convert: (event: string, values: unknown[]) => unknown): Events<Definitions, Fallback>;
111
73
  /** Destinationless events originating from one Endpoint handle. */
112
74
  export declare function endpointEvents(target: HandleAddress | null, half: "server" | "client"): Events<{}, unknown>;
113
75
  /** Start and stop transitions belonging directly to one permanent Endpoint. */
114
- export declare function endpointLifecycle(target: WindowTarget, half: "server" | "client"): Events<{}, unknown>;
76
+ export declare function endpointLifecycle(target: WindowTarget, half: "server" | "client"): Events<EndpointLifecycleEvents, never>;
115
77
  export declare function exit(code: unknown, signal: unknown): Exit;
116
78
  export declare function trafficMessage(value: unknown): TrafficMessage;
117
- export declare function bindEvents(target: object, events: Events): void;
118
- export declare function program(record: ProgramRecord): Program;
119
- export declare function process(record: ProcessRecord, endpoints?: {
79
+ export declare function program(value: unknown): Program;
80
+ export declare function process(value: unknown, endpoints?: {
120
81
  server?: ServerEndpoint;
121
82
  client?: ClientEndpoint;
122
83
  }): Process;
123
- export declare function endpoint(reference: EndpointReference | undefined): Endpoint;
84
+ export declare function endpoint(value: unknown): Endpoint;
124
85
  export declare function claimEndpoint(reference: string, kind: "server" | "client", endpoint: Endpoint): Endpoint<{}, unknown>;
125
86
  export declare function window(target: WindowTarget): Window;
126
87
  export declare function localWindow(target: WindowTarget): LocalWindow;
@@ -136,4 +97,3 @@ export declare const Endpoint: typeof CoreEndpoint;
136
97
  export declare const ServerEndpoint: typeof CoreServerEndpoint;
137
98
  /** Runtime constructor shared by all client-visible Client Endpoint handles. */
138
99
  export declare const ClientEndpoint: typeof CoreClientEndpoint;
139
- export {};
package/dist/domain.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ClientEndpoint as CoreClientEndpoint, Endpoint as CoreEndpoint, Process as CoreProcess, Program as CoreProgram, ServerEndpoint as CoreServerEndpoint, parseClientPermissions } from "@phreshos/core";
1
+ import { ClientEndpoint as CoreClientEndpoint, Endpoint as CoreEndpoint, Process as CoreProcess, Program as CoreProgram, ServerEndpoint as CoreServerEndpoint, parseEndpointReference, parseProcessSnapshot, parseProgramSnapshot } from "@phreshos/core";
2
2
  import Events, { stream } from "./events.js";
3
3
  import Deadline from "./deadline.js";
4
4
  import HandleRegistry from "./handle-registry.js";
@@ -7,11 +7,10 @@ import startup from "./startup.js";
7
7
  import { programPermissions } from "./permissions.js";
8
8
  import wire from "./wire.js";
9
9
  const handles = new HandleRegistry();
10
- const ProgramBase = CoreProgram;
11
- const ProcessBase = CoreProcess;
12
- const ServerEndpointBase = CoreServerEndpoint;
13
- const ClientEndpointBase = CoreClientEndpoint;
14
- class ProgramHandle extends ProgramBase {
10
+ class ProgramHandle extends CoreProgram {
11
+ subscribe;
12
+ wait;
13
+ events;
15
14
  identity;
16
15
  reference;
17
16
  data;
@@ -36,19 +35,18 @@ class ProgramHandle extends ProgramBase {
36
35
  this.startup = startup(this.address);
37
36
  this.permissions = programPermissions(this.address);
38
37
  this.process = new ProgramProcessHandle(this.address, record.reference);
39
- bindEvents(this, scoped("program-host", record.reference, programEvent));
38
+ const events = scoped("program-host", record.reference, programEvent);
39
+ this.subscribe = events.subscribe;
40
+ this.wait = events.wait;
41
+ this.events = events.events;
40
42
  }
41
43
  get name() { return this.record.name; }
42
44
  get assetId() { return this.record.assetId; }
43
45
  get version() { return this.record.version; }
44
46
  get description() { return this.record.description; }
45
47
  get hasAgent() { return this.record.hasAgent; }
46
- get server() {
47
- return this.record.server ? declaration(this.record.server) : null;
48
- }
49
- get client() {
50
- return this.record.client ? clientDeclaration(this.record.client) : null;
51
- }
48
+ get server() { return this.record.server; }
49
+ get client() { return this.record.client; }
52
50
  get address() { return { identity: this.identity, reference: this.reference }; }
53
51
  update(record) {
54
52
  if (record.reference !== this.reference)
@@ -92,28 +90,17 @@ function programCommandChunk(value) {
92
90
  }
93
91
  return Object.freeze({ stream: chunk.stream, text: chunk.text });
94
92
  }
95
- function declaration(record) {
96
- return Object.freeze({
97
- start: record.start,
98
- service: record.service
99
- });
100
- }
101
- function clientDeclaration(record) {
102
- return Object.freeze({
103
- ...declaration(record),
104
- title: record.title,
105
- size: record.size,
106
- position: record.position,
107
- layer: record.layer,
108
- minimize: record.minimize,
109
- permissions: parseClientPermissions(record.permissions)
110
- });
111
- }
112
93
  class ProgramProcessHandle {
113
94
  address;
95
+ subscribe;
96
+ wait;
97
+ events;
114
98
  constructor(address, reference) {
115
99
  this.address = address;
116
- bindEvents(this, scoped("program-process", reference, programProcessEvent));
100
+ const events = scoped("program-process", reference, programProcessEvent);
101
+ this.subscribe = events.subscribe;
102
+ this.wait = events.wait;
103
+ this.events = events.events;
117
104
  }
118
105
  async list() {
119
106
  const answer = await wire.request(["program-process-list", this.address]);
@@ -165,7 +152,10 @@ function processRunEvent(value) {
165
152
  function chronological(processes) {
166
153
  return processes.sort((left, right) => left.startedAt.getTime() - right.startedAt.getTime());
167
154
  }
168
- class ProcessHandle extends ProcessBase {
155
+ class ProcessHandle extends CoreProcess {
156
+ subscribe;
157
+ wait;
158
+ events;
169
159
  identity;
170
160
  reference;
171
161
  name;
@@ -173,7 +163,7 @@ class ProcessHandle extends ProcessBase {
173
163
  server;
174
164
  client;
175
165
  ownerProgram;
176
- options;
166
+ launchOptions;
177
167
  constructor(record, endpoints = {}) {
178
168
  super();
179
169
  this.identity = record.identity;
@@ -181,10 +171,13 @@ class ProcessHandle extends ProcessBase {
181
171
  this.name = record.name;
182
172
  this.startedAt = new Date(record.startedAt);
183
173
  this.ownerProgram = program(record.program);
184
- this.options = record.options;
174
+ this.launchOptions = Object.freeze({ ...record.options });
185
175
  this.server = endpointHandle(this, "server", endpoints.server);
186
176
  this.client = endpointHandle(this, "client", endpoints.client);
187
- bindEvents(this, scoped("process-host", record.reference, processEvent));
177
+ const events = scoped("process-host", record.reference, processEvent);
178
+ this.subscribe = events.subscribe;
179
+ this.wait = events.wait;
180
+ this.events = events.events;
188
181
  }
189
182
  program() { return this.ownerProgram; }
190
183
  get address() { return { identity: this.identity, reference: this.reference }; }
@@ -192,11 +185,8 @@ class ProcessHandle extends ProcessBase {
192
185
  const answer = await wire.request(["parent", this.address]);
193
186
  return answer[0] ? process(answer[0]) : null;
194
187
  }
195
- async option(name) {
196
- if (name in this.options)
197
- return this.options[name];
198
- const answer = await wire.request(["option", this.address, name]);
199
- return answer[0];
188
+ async options(name) {
189
+ return name === undefined ? this.launchOptions : this.launchOptions[name];
200
190
  }
201
191
  async exit() { await wire.request(["exit", this.address]); }
202
192
  async exited() {
@@ -245,8 +235,11 @@ export class ServerTrafficHandle extends TrafficHandle {
245
235
  }, impossible);
246
236
  }
247
237
  }
248
- class ServerEndpointHandle extends ServerEndpointBase {
238
+ class ServerEndpointHandle extends CoreServerEndpoint {
249
239
  owner;
240
+ subscribe;
241
+ wait;
242
+ events;
250
243
  traffic;
251
244
  lifecycle;
252
245
  constructor(owner) {
@@ -254,10 +247,15 @@ class ServerEndpointHandle extends ServerEndpointBase {
254
247
  this.owner = owner;
255
248
  this.traffic = new ServerTrafficHandle(owner.address, "server");
256
249
  this.lifecycle = endpointLifecycle(() => Promise.resolve(owner.address), "server");
257
- bindEvents(this, endpointEvents(owner.address, "server"));
250
+ const events = endpointEvents(owner.address, "server");
251
+ this.subscribe = events.subscribe;
252
+ this.wait = events.wait;
253
+ this.events = events.events;
258
254
  }
259
255
  async process() { return this.owner; }
260
- publish(event, payload = undefined) { wire.send("end-host", "send", this.owner.address, "server", event, payload); }
256
+ publish = (event, payload = undefined) => {
257
+ wire.send("end-host", "send", this.owner.address, "server", event, payload);
258
+ };
261
259
  async exists() {
262
260
  const answer = await wire.request(["exists", "server", this.owner.address]);
263
261
  return answer[0];
@@ -288,8 +286,11 @@ class ServerEndpointHandle extends ServerEndpointBase {
288
286
  }
289
287
  }
290
288
  }
291
- class ClientEndpointHandle extends ClientEndpointBase {
289
+ class ClientEndpointHandle extends CoreClientEndpoint {
292
290
  owner;
291
+ subscribe;
292
+ wait;
293
+ events;
293
294
  traffic;
294
295
  lifecycle;
295
296
  window;
@@ -299,10 +300,15 @@ class ClientEndpointHandle extends ClientEndpointBase {
299
300
  this.traffic = new TrafficHandle(owner.address, "client");
300
301
  this.lifecycle = endpointLifecycle(() => Promise.resolve(owner.address), "client");
301
302
  this.window = window(async () => owner.address);
302
- bindEvents(this, endpointEvents(owner.address, "client"));
303
+ const events = endpointEvents(owner.address, "client");
304
+ this.subscribe = events.subscribe;
305
+ this.wait = events.wait;
306
+ this.events = events.events;
303
307
  }
304
308
  async process() { return this.owner; }
305
- publish(event, payload = undefined) { wire.send("end-host", "send", this.owner.address, "client", event, payload); }
309
+ publish = (event, payload = undefined) => {
310
+ wire.send("end-host", "send", this.owner.address, "client", event, payload);
311
+ };
306
312
  async exists() {
307
313
  const answer = await wire.request(["exists", "client", this.owner.address]);
308
314
  return answer[0];
@@ -326,16 +332,18 @@ class WindowHandle extends Events {
326
332
  async position() { return (await this.state()).position; }
327
333
  async size() { return (await this.state()).size; }
328
334
  async minimized() { return (await this.state()).minimized; }
335
+ async maximized() { return (await this.state()).maximized; }
329
336
  async front() { return (await this.state()).front; }
330
337
  async layer() { return (await this.state()).layer; }
331
- async location() { return (await this.state()).location; }
332
338
  async move(position) { await wire.request(["move", await this.target(), position]); }
333
339
  async resize(size) { await wire.request(["resize", await this.target(), size]); }
334
340
  async setGeometry(geometry) { await wire.request(["setGeometry", await this.target(), geometry]); }
335
341
  async minimize(minimized = true) { await wire.request(["minimize", await this.target(), minimized]); }
342
+ async maximize(maximized = true) { await wire.request(["maximize", await this.target(), maximized]); }
336
343
  async changeTitle(title) { await wire.request(["changeTitle", await this.target(), title]); }
337
344
  async raise() { await wire.request(["raise", await this.target()]); }
338
345
  }
346
+ const windowTargets = new WeakMap();
339
347
  class LocalWindowHandle {
340
348
  target;
341
349
  selected;
@@ -351,6 +359,17 @@ class LocalWindowHandle {
351
359
  async move(position) { await this.change("windowLocalMove", position); }
352
360
  async resize(size) { await this.change("windowLocalResize", size); }
353
361
  async setGeometry(geometry) { await this.change("windowLocalGeometry", geometry); }
362
+ async minimize(minimized = true) { await this.change("windowLocalMinimize", minimized); }
363
+ async maximize(maximized = true) { await this.change("windowLocalMaximize", maximized); }
364
+ async changeTitle(title) { await wire.request(["windowLocalTitle", await this.target(), title]); }
365
+ async follow(window) {
366
+ const target = windowTargets.get(window);
367
+ if (!target)
368
+ throw new Error("Local Window follow requires a Window from this Client SDK");
369
+ await wire.request(["windowLocalFollow", await this.target(), await target(), this.selected]);
370
+ }
371
+ async unfollow() { await wire.request(["windowLocalUnfollow", await this.target(), this.selected]); }
372
+ async raise() { await wire.request(["windowLocalRaise", await this.target()]); }
354
373
  async change(operation, value) {
355
374
  await wire.request([operation, await this.target(), value, this.selected]);
356
375
  }
@@ -378,7 +397,7 @@ function deferredScoped(route, target, convert) {
378
397
  ];
379
398
  }
380
399
  function windowEvent(event) {
381
- return event === "move" || event === "resize" || event === "geometry" || event === "minimize" || event === "changeTitle" || event === "front";
400
+ return event === "move" || event === "resize" || event === "geometry" || event === "minimize" || event === "maximize" || event === "changeTitle" || event === "front";
382
401
  }
383
402
  function deferred(target, register, impossible) {
384
403
  let active = true;
@@ -471,24 +490,18 @@ export function trafficMessage(value) {
471
490
  const raw = value;
472
491
  return { to: visibleEndpoint(raw.to), payload: raw.payload };
473
492
  }
474
- export function bindEvents(target, events) {
475
- Object.assign(target, {
476
- subscribe: events.subscribe.bind(events),
477
- waitFor: events.waitFor.bind(events),
478
- events: events.events.bind(events)
479
- });
480
- }
481
- export function program(record) {
493
+ export function program(value) {
494
+ const record = parseProgramSnapshot(value);
482
495
  const handle = handles.obtain(`program:${record.reference}`, () => new ProgramHandle(record));
483
496
  handle.update(record);
484
497
  return handle;
485
498
  }
486
- export function process(record, endpoints = {}) {
499
+ export function process(value, endpoints = {}) {
500
+ const record = parseProcessSnapshot(value);
487
501
  return handles.obtain(`process:${record.reference}`, () => new ProcessHandle(record, endpoints));
488
502
  }
489
- export function endpoint(reference) {
490
- if (!reference)
491
- throw new Error("The boundary returned an invalid Endpoint reference");
503
+ export function endpoint(value) {
504
+ const reference = parseEndpointReference(value);
492
505
  const owner = process(reference.process);
493
506
  return reference.kind === "server" ? owner.server : owner.client;
494
507
  }
@@ -499,7 +512,9 @@ function endpointHandle(owner, kind, preferred) {
499
512
  return handles.obtain(`endpoint:${owner.reference}:${kind}`, () => preferred ?? (kind === "server" ? new ServerEndpointHandle(owner) : new ClientEndpointHandle(owner)));
500
513
  }
501
514
  export function window(target) {
502
- return new WindowHandle(target);
515
+ const handle = new WindowHandle(target);
516
+ windowTargets.set(handle, target);
517
+ return handle;
503
518
  }
504
519
  export function localWindow(target) {
505
520
  return new LocalWindowHandle(target);