@phreshos/client 0.1.45 → 0.1.47
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/dist/context.js +8 -8
- package/dist/desktop/preferences.d.ts +1 -0
- package/dist/domain.d.ts +2 -2
- package/dist/domain.js +67 -39
- package/dist/service.d.ts +4 -8
- package/dist/service.js +56 -34
- package/dist/system.js +22 -2
- package/dist/wire.d.ts +2 -2
- package/dist/wire.js +2 -2
- package/package.json +3 -3
package/dist/context.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Deadline from "./deadline.js";
|
|
2
|
-
import { ClientEndpoint, ServerEndpoint, ServerTrafficHandle, TrafficHandle, endpointLifecycle, endpointEvents, process, program, visibleEndpoint,
|
|
2
|
+
import { ClientEndpoint, ServerEndpoint, ServerTrafficHandle, TrafficHandle, endpointLifecycle, endpointEvents, process, program, visibleEndpoint, presentation, 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";
|
|
@@ -18,12 +18,12 @@ class ContextServerHandle extends ServerEndpoint {
|
|
|
18
18
|
this.wait = events.wait;
|
|
19
19
|
this.events = events.events;
|
|
20
20
|
}
|
|
21
|
-
process() { return this.owner(); }
|
|
21
|
+
async process() { await this.running(); return this.owner(); }
|
|
22
22
|
publish = (event, payload = undefined) => {
|
|
23
23
|
wire.send("end-end", event, payload);
|
|
24
24
|
};
|
|
25
|
-
async
|
|
26
|
-
const answer = await wire.request(["
|
|
25
|
+
async running() {
|
|
26
|
+
const answer = await wire.request(["running", "server"]);
|
|
27
27
|
return answer[0];
|
|
28
28
|
}
|
|
29
29
|
async start(launch = {}) { await wire.request(["start-endpoint", undefined, "server", launch]); }
|
|
@@ -76,14 +76,14 @@ class ContextClientHandle extends ClientEndpoint {
|
|
|
76
76
|
this.wait = events.wait;
|
|
77
77
|
this.events = events.events;
|
|
78
78
|
}
|
|
79
|
-
process() { return this.owner(); }
|
|
79
|
+
async process() { await this.running(); return this.owner(); }
|
|
80
80
|
publish = (event, payload = undefined) => {
|
|
81
81
|
void wire.identity().then(identity => {
|
|
82
82
|
wire.send("end-host", "send", { identity: identity.process, reference: identity.reference }, "client", event, payload);
|
|
83
83
|
});
|
|
84
84
|
};
|
|
85
|
-
async
|
|
86
|
-
const answer = await wire.request(["
|
|
85
|
+
async running() {
|
|
86
|
+
const answer = await wire.request(["running", "client"]);
|
|
87
87
|
return answer[0];
|
|
88
88
|
}
|
|
89
89
|
async start(launch = {}) { await wire.request(["start-endpoint", undefined, "client", launch]); }
|
|
@@ -95,7 +95,7 @@ contextClient = new ContextClientHandle(owner);
|
|
|
95
95
|
class ClientContext extends Events {
|
|
96
96
|
server = contextServer;
|
|
97
97
|
window = contextClient.window;
|
|
98
|
-
|
|
98
|
+
presentation = presentation(currentAddress);
|
|
99
99
|
permissions = contextPermissions();
|
|
100
100
|
constructor() {
|
|
101
101
|
super((event, listener, impossible) => wire.on("end-end", event, value => listener(contextMessage(value)), null, impossible), (listener, impossible) => wire.onAll("end-end", (event, value) => {
|
|
@@ -6,6 +6,7 @@ export default class ClientPreferences extends Events<DesktopPreferencesEvents,
|
|
|
6
6
|
snapshot(): Promise<Readonly<{
|
|
7
7
|
theme: import("@phreshos/core").Theme;
|
|
8
8
|
animations: boolean;
|
|
9
|
+
scale: number;
|
|
9
10
|
}>>;
|
|
10
11
|
update(preferences: DesktopPreferencesUpdate): Promise<void>;
|
|
11
12
|
}
|
package/dist/domain.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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
|
|
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 WindowPresentation, 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
3
|
export type { HandleAddress };
|
|
4
4
|
export type EndpointDeclarationRecord = EndpointDeclaration;
|
|
@@ -83,7 +83,7 @@ export declare function process(value: unknown, endpoints?: {
|
|
|
83
83
|
export declare function endpoint(value: unknown): Endpoint;
|
|
84
84
|
export declare function claimEndpoint(reference: string, kind: "server" | "client", endpoint: Endpoint): Endpoint<{}, unknown>;
|
|
85
85
|
export declare function window(target: WindowTarget): Window;
|
|
86
|
-
export declare function
|
|
86
|
+
export declare function presentation(target: WindowTarget): WindowPresentation;
|
|
87
87
|
/** Resolves an Endpoint reference through the Client Endpoint's global handle registry. */
|
|
88
88
|
export declare function visibleEndpoint(reference: EndpointReference | null | undefined): Endpoint | null;
|
|
89
89
|
/** Runtime constructor shared by all client-visible Program handles. */
|
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, parseEndpointReference, parseProcessSnapshot, parseProgramSnapshot } 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";
|
|
@@ -236,12 +236,12 @@ class ServerEndpointHandle extends CoreServerEndpoint {
|
|
|
236
236
|
this.wait = events.wait;
|
|
237
237
|
this.events = events.events;
|
|
238
238
|
}
|
|
239
|
-
async process() { return this.owner; }
|
|
239
|
+
async process() { await this.running(); return this.owner; }
|
|
240
240
|
publish = (event, payload = undefined) => {
|
|
241
241
|
wire.send("end-host", "send", this.owner.address, "server", event, payload);
|
|
242
242
|
};
|
|
243
|
-
async
|
|
244
|
-
const answer = await wire.request(["
|
|
243
|
+
async running() {
|
|
244
|
+
const answer = await wire.request(["running", "server", this.owner.address]);
|
|
245
245
|
return answer[0];
|
|
246
246
|
}
|
|
247
247
|
async start(launch = {}) { await wire.request(["start-endpoint", this.owner.address, "server", launch]); }
|
|
@@ -289,12 +289,12 @@ class ClientEndpointHandle extends CoreClientEndpoint {
|
|
|
289
289
|
this.wait = events.wait;
|
|
290
290
|
this.events = events.events;
|
|
291
291
|
}
|
|
292
|
-
async process() { return this.owner; }
|
|
292
|
+
async process() { await this.running(); return this.owner; }
|
|
293
293
|
publish = (event, payload = undefined) => {
|
|
294
294
|
wire.send("end-host", "send", this.owner.address, "client", event, payload);
|
|
295
295
|
};
|
|
296
|
-
async
|
|
297
|
-
const answer = await wire.request(["
|
|
296
|
+
async running() {
|
|
297
|
+
const answer = await wire.request(["running", "client", this.owner.address]);
|
|
298
298
|
return answer[0];
|
|
299
299
|
}
|
|
300
300
|
async start(launch = {}) { await wire.request(["start-endpoint", this.owner.address, "client", launch]); }
|
|
@@ -313,6 +313,9 @@ class WindowHandle extends Events {
|
|
|
313
313
|
return answer[0];
|
|
314
314
|
}
|
|
315
315
|
async title() { return (await this.state()).title; }
|
|
316
|
+
async header() { return (await this.state()).header; }
|
|
317
|
+
async frame() { return (await this.state()).frame; }
|
|
318
|
+
async transaction() { return (await this.state()).transaction; }
|
|
316
319
|
async position() { return (await this.state()).position; }
|
|
317
320
|
async size() { return (await this.state()).size; }
|
|
318
321
|
async minimized() { return (await this.state()).minimized; }
|
|
@@ -324,38 +327,61 @@ class WindowHandle extends Events {
|
|
|
324
327
|
async setGeometry(geometry) { await wire.request(["setGeometry", await this.target(), geometry]); }
|
|
325
328
|
async minimize(minimized = true) { await wire.request(["minimize", await this.target(), minimized]); }
|
|
326
329
|
async maximize(maximized = true) { await wire.request(["maximize", await this.target(), maximized]); }
|
|
327
|
-
async
|
|
330
|
+
async setTitle(title) { await wire.request(["setTitle", await this.target(), title]); }
|
|
331
|
+
async setHeader(header) { await wire.request(["setHeader", await this.target(), header]); }
|
|
332
|
+
async setFrame(frame) { await wire.request(["setFrame", await this.target(), frame]); }
|
|
333
|
+
async setTransaction(transaction) { await wire.request(["setTransaction", await this.target(), transaction]); }
|
|
328
334
|
async raise() { await wire.request(["raise", await this.target()]); }
|
|
329
335
|
}
|
|
330
|
-
|
|
331
|
-
class LocalWindowHandle {
|
|
336
|
+
class WindowPresentationHandle extends Events {
|
|
332
337
|
target;
|
|
333
338
|
selected;
|
|
334
339
|
constructor(target, selected) {
|
|
340
|
+
super((event, listener, impossible) => {
|
|
341
|
+
if (!windowEvent(event)) {
|
|
342
|
+
impossible?.(new Error(`A Window presentation has no "${event}" event`));
|
|
343
|
+
return () => undefined;
|
|
344
|
+
}
|
|
345
|
+
return wire.on("presentation", event, listener, null, impossible);
|
|
346
|
+
}, (listener, impossible) => wire.onAll("presentation", (event, ...values) => {
|
|
347
|
+
if (typeof event === "string")
|
|
348
|
+
listener(event, values[0]);
|
|
349
|
+
}, null, impossible));
|
|
335
350
|
this.target = target;
|
|
336
351
|
this.selected = selected;
|
|
337
352
|
}
|
|
338
353
|
transaction(transaction) {
|
|
339
|
-
return new
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
async
|
|
345
|
-
async
|
|
346
|
-
async
|
|
347
|
-
async
|
|
348
|
-
async
|
|
349
|
-
async
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
355
|
-
async
|
|
356
|
-
async
|
|
354
|
+
return new WindowPresentationHandle(this.target, { transaction, wait: false });
|
|
355
|
+
}
|
|
356
|
+
transactionAndWait(transaction) {
|
|
357
|
+
return new WindowPresentationHandle(this.target, { transaction, wait: true });
|
|
358
|
+
}
|
|
359
|
+
async title() { return await this.read("title"); }
|
|
360
|
+
async header() { return await this.read("header"); }
|
|
361
|
+
async frame() { return await this.read("frame"); }
|
|
362
|
+
async position() { return await this.read("position"); }
|
|
363
|
+
async size() { return await this.read("size"); }
|
|
364
|
+
async minimized() { return await this.read("minimized"); }
|
|
365
|
+
async maximized() { return await this.read("maximized"); }
|
|
366
|
+
async front() { return await this.read("front"); }
|
|
367
|
+
async layer() { return await this.read("layer"); }
|
|
368
|
+
async move(position) { await this.change("windowPresentationMove", position); }
|
|
369
|
+
async resize(size) { await this.change("windowPresentationResize", size); }
|
|
370
|
+
async setGeometry(geometry) { await this.change("windowPresentationGeometry", geometry); }
|
|
371
|
+
async minimize(minimized = true) { await this.change("windowPresentationMinimize", minimized); }
|
|
372
|
+
async maximize(maximized = true) { await this.change("windowPresentationMaximize", maximized); }
|
|
373
|
+
async setTitle(title) { await this.change("windowPresentationTitle", title); }
|
|
374
|
+
async setHeader(header) { await this.change("windowPresentationHeader", header); }
|
|
375
|
+
async setFrame(frame) { await this.change("windowPresentationFrame", frame); }
|
|
376
|
+
async follow() { await this.change("windowPresentationFollow"); }
|
|
377
|
+
async unfollow() { await this.change("windowPresentationUnfollow"); }
|
|
378
|
+
async raise() { await this.change("windowPresentationRaise"); }
|
|
357
379
|
async change(operation, value) {
|
|
358
|
-
await wire.request([operation, await this.target(), value, this.selected]);
|
|
380
|
+
await wire.request([operation, await this.target(), value, this.selected?.transaction, this.selected?.wait === true]);
|
|
381
|
+
}
|
|
382
|
+
async read(property) {
|
|
383
|
+
const answer = await wire.request(["windowPresentationRead", await this.target(), property]);
|
|
384
|
+
return answer[0];
|
|
359
385
|
}
|
|
360
386
|
}
|
|
361
387
|
function deferredScoped(route, target, convert) {
|
|
@@ -381,7 +407,7 @@ function deferredScoped(route, target, convert) {
|
|
|
381
407
|
];
|
|
382
408
|
}
|
|
383
409
|
function windowEvent(event) {
|
|
384
|
-
return event === "move" || event === "resize" || event === "
|
|
410
|
+
return event === "move" || event === "resize" || event === "minimize" || event === "maximize" || event === "changeTitle" || event === "changeHeader" || event === "changeFrame" || event === "changeTransaction" || event === "front";
|
|
385
411
|
}
|
|
386
412
|
function deferred(target, register, impossible) {
|
|
387
413
|
let active = true;
|
|
@@ -393,8 +419,6 @@ function deferred(target, register, impossible) {
|
|
|
393
419
|
const failure = error instanceof Error ? error : new Error(String(error));
|
|
394
420
|
if (active && impossible)
|
|
395
421
|
impossible(failure);
|
|
396
|
-
else if (active)
|
|
397
|
-
queueMicrotask(() => { throw failure; });
|
|
398
422
|
});
|
|
399
423
|
return () => {
|
|
400
424
|
active = false;
|
|
@@ -423,11 +447,17 @@ export function endpointEvents(target, half) {
|
|
|
423
447
|
}
|
|
424
448
|
/** Start and stop transitions belonging directly to one permanent Endpoint. */
|
|
425
449
|
export function endpointLifecycle(target, half) {
|
|
426
|
-
|
|
450
|
+
const resolved = () => target();
|
|
451
|
+
const viable = async () => {
|
|
452
|
+
const address = await resolved();
|
|
453
|
+
await wire.request(["running", half, address]);
|
|
454
|
+
return address;
|
|
455
|
+
};
|
|
456
|
+
return new Events((event, listener, impossible) => deferred(impossible ? viable : resolved, subject => wire.on("process-host", endpointLifecycleEvent(event), (...values) => {
|
|
427
457
|
const message = unscoped(subject, values);
|
|
428
458
|
if (message?.[1] === half)
|
|
429
459
|
listener(undefined);
|
|
430
|
-
}, subject, impossible), impossible), (listener, impossible) => deferred(
|
|
460
|
+
}, subject, impossible), impossible), (listener, impossible) => deferred(impossible ? viable : resolved, subject => wire.onAll("process-host", (event, ...values) => {
|
|
431
461
|
if (event !== "endpointStart" && event !== "endpointStop")
|
|
432
462
|
return;
|
|
433
463
|
const message = unscoped(subject, values);
|
|
@@ -493,12 +523,10 @@ function endpointHandle(owner, kind, preferred) {
|
|
|
493
523
|
return handles.obtain(`endpoint:${owner.reference}:${kind}`, () => preferred ?? (kind === "server" ? new ServerEndpointHandle(owner) : new ClientEndpointHandle(owner)));
|
|
494
524
|
}
|
|
495
525
|
export function window(target) {
|
|
496
|
-
|
|
497
|
-
windowTargets.set(handle, target);
|
|
498
|
-
return handle;
|
|
526
|
+
return new WindowHandle(target);
|
|
499
527
|
}
|
|
500
|
-
export function
|
|
501
|
-
return new
|
|
528
|
+
export function presentation(target) {
|
|
529
|
+
return new WindowPresentationHandle(target);
|
|
502
530
|
}
|
|
503
531
|
/** Resolves an Endpoint reference through the Client Endpoint's global handle registry. */
|
|
504
532
|
export function visibleEndpoint(reference) {
|
package/dist/service.d.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import { type ClientService, type ServerService, type
|
|
2
|
-
export declare function prepareService<EventsMap extends object = {}, Fallback = unknown>(
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export declare function prepareService<EventsMap extends object = {}, Fallback = unknown>(key: ServiceKey & {
|
|
6
|
-
endpoint: "client";
|
|
7
|
-
}): ClientService<EventsMap, Fallback>;
|
|
8
|
-
export declare function prepareService(key: ServiceKey): Service;
|
|
1
|
+
import { type ClientService, type ServerService, type ServiceAddress } from "@phreshos/core";
|
|
2
|
+
export declare function prepareService<EventsMap extends object = {}, Fallback = unknown>(address: ServiceAddress<"server">): ServerService<EventsMap, Fallback>;
|
|
3
|
+
export declare function prepareService<EventsMap extends object = {}, Fallback = unknown>(address: ServiceAddress<"client">): ClientService<EventsMap, Fallback>;
|
|
4
|
+
export declare function prepareService(address: ServiceAddress): ServerService | ClientService;
|
package/dist/service.js
CHANGED
|
@@ -1,46 +1,54 @@
|
|
|
1
|
-
import { ClientService as CoreClientService, ServerService as CoreServerService,
|
|
1
|
+
import { ClientService as CoreClientService, ServerService as CoreServerService, isServiceAddress } from "@phreshos/core";
|
|
2
2
|
import Deadline from "./deadline.js";
|
|
3
3
|
import Events from "./events.js";
|
|
4
4
|
import HandleRegistry from "./handle-registry.js";
|
|
5
5
|
import wire from "./wire.js";
|
|
6
6
|
const handles = new HandleRegistry();
|
|
7
7
|
class ServiceHandle {
|
|
8
|
-
|
|
8
|
+
serviceAddress;
|
|
9
9
|
lifecycle;
|
|
10
|
-
constructor(
|
|
11
|
-
this.
|
|
12
|
-
this.lifecycle = new Events(...serviceEvents(
|
|
10
|
+
constructor(serviceAddress) {
|
|
11
|
+
this.serviceAddress = serviceAddress;
|
|
12
|
+
this.lifecycle = new Events(...serviceEvents(serviceAddress, "lifecycle"));
|
|
13
13
|
}
|
|
14
14
|
publish(event, payload = undefined) {
|
|
15
|
-
wire.send("end-host", "service-send", this.
|
|
15
|
+
wire.send("end-host", "service-send", this.serviceAddress, event, payload);
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
address() { return this.serviceAddress; }
|
|
18
|
+
async available() {
|
|
19
|
+
const answer = await wire.request(["service-available", this.serviceAddress]);
|
|
19
20
|
return answer[0];
|
|
20
21
|
}
|
|
21
22
|
async waitReady(timeout) {
|
|
22
|
-
await wire.request(["service-wait-ready", this.
|
|
23
|
+
await wire.request(["service-wait-ready", this.serviceAddress, timeout], timeout);
|
|
24
|
+
}
|
|
25
|
+
async programMetadata(options = {}) {
|
|
26
|
+
const iconSize = options.icon ?? "medium";
|
|
27
|
+
const [value] = await wire.request(["service-program-metadata", this.serviceAddress, iconSize]);
|
|
28
|
+
return parseServiceProgramMetadata(value);
|
|
23
29
|
}
|
|
24
30
|
}
|
|
25
31
|
class ServerHandler extends CoreServerService {
|
|
26
|
-
|
|
32
|
+
serviceAddress;
|
|
27
33
|
subscribe;
|
|
28
34
|
wait;
|
|
29
35
|
events;
|
|
30
36
|
lifecycle;
|
|
31
37
|
service;
|
|
32
|
-
constructor(
|
|
38
|
+
constructor(serviceAddress) {
|
|
33
39
|
super();
|
|
34
|
-
this.
|
|
35
|
-
this.service = new ServiceHandle(
|
|
40
|
+
this.serviceAddress = serviceAddress;
|
|
41
|
+
this.service = new ServiceHandle(serviceAddress);
|
|
36
42
|
this.lifecycle = this.service.lifecycle;
|
|
37
|
-
const events = new Events(...serviceEvents(
|
|
43
|
+
const events = new Events(...serviceEvents(serviceAddress, "events"));
|
|
38
44
|
this.subscribe = events.subscribe;
|
|
39
45
|
this.wait = events.wait;
|
|
40
46
|
this.events = events.events;
|
|
41
47
|
}
|
|
42
48
|
publish = (event, payload = undefined) => { this.service.publish(event, payload); };
|
|
43
|
-
|
|
49
|
+
address() { return this.serviceAddress; }
|
|
50
|
+
available() { return this.service.available(); }
|
|
51
|
+
programMetadata(options) { return this.service.programMetadata(options); }
|
|
44
52
|
waitReady(timeout) { return this.service.waitReady(timeout); }
|
|
45
53
|
async ask(event, payload = undefined) {
|
|
46
54
|
return await this.askWithin(new Deadline(), event, payload);
|
|
@@ -53,7 +61,7 @@ class ServerHandler extends CoreServerService {
|
|
|
53
61
|
const address = `client:${identity.process}:${crypto.randomUUID()}`;
|
|
54
62
|
const question = crypto.randomUUID();
|
|
55
63
|
const waiting = wire.expectWithin(address, deadline);
|
|
56
|
-
wire.send("end-host", "service-ask", this.
|
|
64
|
+
wire.send("end-host", "service-ask", this.serviceAddress, address, question, event, payload);
|
|
57
65
|
try {
|
|
58
66
|
return await waiting;
|
|
59
67
|
}
|
|
@@ -63,45 +71,59 @@ class ServerHandler extends CoreServerService {
|
|
|
63
71
|
}
|
|
64
72
|
}
|
|
65
73
|
class ClientHandler extends CoreClientService {
|
|
74
|
+
serviceAddress;
|
|
66
75
|
subscribe;
|
|
67
76
|
wait;
|
|
68
77
|
events;
|
|
69
78
|
lifecycle;
|
|
70
79
|
service;
|
|
71
|
-
constructor(
|
|
80
|
+
constructor(serviceAddress) {
|
|
72
81
|
super();
|
|
73
|
-
this.
|
|
82
|
+
this.serviceAddress = serviceAddress;
|
|
83
|
+
this.service = new ServiceHandle(serviceAddress);
|
|
74
84
|
this.lifecycle = this.service.lifecycle;
|
|
75
|
-
const events = new Events(...serviceEvents(
|
|
85
|
+
const events = new Events(...serviceEvents(serviceAddress, "events"));
|
|
76
86
|
this.subscribe = events.subscribe;
|
|
77
87
|
this.wait = events.wait;
|
|
78
88
|
this.events = events.events;
|
|
79
89
|
}
|
|
80
90
|
publish = (event, payload = undefined) => { this.service.publish(event, payload); };
|
|
81
|
-
|
|
91
|
+
address() { return this.serviceAddress; }
|
|
92
|
+
available() { return this.service.available(); }
|
|
93
|
+
programMetadata(options) { return this.service.programMetadata(options); }
|
|
82
94
|
waitReady(timeout) { return this.service.waitReady(timeout); }
|
|
83
95
|
}
|
|
84
|
-
export function prepareService(
|
|
85
|
-
if (!
|
|
86
|
-
throw new Error("A complete
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
process:
|
|
90
|
-
});
|
|
91
|
-
const identity = JSON.stringify([key.program ?? null, key.process, key.endpoint]);
|
|
92
|
-
if (key.endpoint === "server") {
|
|
93
|
-
const normalized = Object.freeze({ ...address, endpoint: "server" });
|
|
96
|
+
export function prepareService(address) {
|
|
97
|
+
if (!isServiceAddress(address))
|
|
98
|
+
throw new Error("A complete Service address is required");
|
|
99
|
+
const identity = JSON.stringify([address.program, address.process, address.endpoint]);
|
|
100
|
+
if (address.endpoint === "server") {
|
|
101
|
+
const normalized = Object.freeze({ program: address.program, process: address.process, endpoint: "server" });
|
|
94
102
|
return handles.obtain(`service:${identity}`, () => new ServerHandler(normalized));
|
|
95
103
|
}
|
|
96
|
-
const normalized = Object.freeze({
|
|
104
|
+
const normalized = Object.freeze({ program: address.program, process: address.process, endpoint: "client" });
|
|
97
105
|
return handles.obtain(`service:${identity}`, () => new ClientHandler(normalized));
|
|
98
106
|
}
|
|
99
|
-
function serviceEvents(
|
|
107
|
+
function serviceEvents(address, scope) {
|
|
100
108
|
return [
|
|
101
|
-
(event, listener, impossible) => wire.followService(
|
|
102
|
-
(listener, impossible) => wire.followService(
|
|
109
|
+
(event, listener, impossible) => wire.followService(address, scope, event, listener, impossible),
|
|
110
|
+
(listener, impossible) => wire.followService(address, scope, null, (event, payload) => {
|
|
103
111
|
if (typeof event === "string")
|
|
104
112
|
listener(event, payload);
|
|
105
113
|
}, impossible)
|
|
106
114
|
];
|
|
107
115
|
}
|
|
116
|
+
function parseServiceProgramMetadata(value) {
|
|
117
|
+
if (!value || typeof value !== "object")
|
|
118
|
+
throw new Error("The System returned invalid Service Program metadata");
|
|
119
|
+
const metadata = value;
|
|
120
|
+
if (typeof metadata.name !== "string" || typeof metadata.version !== "string"
|
|
121
|
+
|| !Array.isArray(metadata.icon) || metadata.icon.some(byte => typeof byte !== "number")) {
|
|
122
|
+
throw new Error("The System returned invalid Service Program metadata");
|
|
123
|
+
}
|
|
124
|
+
return Object.freeze({
|
|
125
|
+
name: metadata.name,
|
|
126
|
+
version: metadata.version,
|
|
127
|
+
icon: new Blob([Uint8Array.from(metadata.icon)], { type: "image/png" })
|
|
128
|
+
});
|
|
129
|
+
}
|
package/dist/system.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseShellEvent, parseSessionEndSnapshot } from "@phreshos/core";
|
|
1
|
+
import { parseShellEvent, parseSessionEndSnapshot, execute as executeRequest } from "@phreshos/core";
|
|
2
2
|
import ClientAppearance from "./appearance.js";
|
|
3
3
|
import wire from "./wire.js";
|
|
4
4
|
import { prepareService } from "./service.js";
|
|
@@ -15,15 +15,35 @@ class ClientSystem {
|
|
|
15
15
|
process = new SystemProcessHandle();
|
|
16
16
|
connection = new SystemConnectionHandle();
|
|
17
17
|
session = new SystemSessionHandle();
|
|
18
|
+
service = new SystemServiceHandle();
|
|
18
19
|
uploads = uploads;
|
|
19
20
|
network = network;
|
|
20
|
-
|
|
21
|
+
execute(request) {
|
|
22
|
+
return executeRequest(this, request);
|
|
23
|
+
}
|
|
21
24
|
async *shell(command, options = {}) {
|
|
22
25
|
const { signal, ...settings } = options;
|
|
23
26
|
for await (const event of wire.stream(["shell", command, settings], undefined, signal))
|
|
24
27
|
yield parseShellEvent(event);
|
|
25
28
|
}
|
|
26
29
|
}
|
|
30
|
+
class SystemServiceHandle extends Events {
|
|
31
|
+
constructor() {
|
|
32
|
+
super((event, listener, impossible) => wire.on("host-service", event, (...values) => listener(prepareService(values[1])), null, impossible), observer => wire.onAll("host-service", (event, ...values) => {
|
|
33
|
+
if (typeof event === "string")
|
|
34
|
+
observer(event, prepareService(values[1]));
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
async list() {
|
|
38
|
+
const [addresses] = await wire.request(["host-service-list"]);
|
|
39
|
+
return addresses.map(address => prepareService(address));
|
|
40
|
+
}
|
|
41
|
+
async search(name) {
|
|
42
|
+
const [addresses] = await wire.request(["host-service-search", name]);
|
|
43
|
+
return addresses.map(address => prepareService(address));
|
|
44
|
+
}
|
|
45
|
+
prepare(address) { return prepareService(address); }
|
|
46
|
+
}
|
|
27
47
|
class SystemProgramHandle extends Events {
|
|
28
48
|
constructor() {
|
|
29
49
|
super((event, listener, impossible) => wire.on("host-program", event, (...values) => listener(systemProgramEvent(event, values)), null, impossible), observer => wire.onAll("host-program", (event, ...values) => {
|
package/dist/wire.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Cleanup,
|
|
1
|
+
import type { Cleanup, ServiceAddress } from "@phreshos/core";
|
|
2
2
|
import Deadline from "./deadline.js";
|
|
3
3
|
import type { HandleAddress } from "./domain.js";
|
|
4
4
|
type Handler = (...values: unknown[]) => unknown;
|
|
@@ -37,7 +37,7 @@ declare class Wire {
|
|
|
37
37
|
/** Follow destinationless events emitted by one Endpoint. */
|
|
38
38
|
follow(target: HandleAddress | null, half: "server" | "client", event: string | null, handler: Handler, impossible?: Failure): Cleanup;
|
|
39
39
|
/** Follow one exact service lifecycle or application event route. */
|
|
40
|
-
followService(
|
|
40
|
+
followService(address: ServiceAddress, scope: "lifecycle" | "events", event: string | null, handler: Handler, impossible?: Failure): Cleanup;
|
|
41
41
|
private register;
|
|
42
42
|
private unregister;
|
|
43
43
|
private deliver;
|
package/dist/wire.js
CHANGED
|
@@ -269,12 +269,12 @@ class Wire {
|
|
|
269
269
|
});
|
|
270
270
|
}
|
|
271
271
|
/** Follow one exact service lifecycle or application event route. */
|
|
272
|
-
followService(
|
|
272
|
+
followService(address, scope, event, handler, impossible) {
|
|
273
273
|
const subscription = crypto.randomUUID();
|
|
274
274
|
const stop = this.on("service-event", subscription, handler);
|
|
275
275
|
if (impossible)
|
|
276
276
|
this.impossible.set(subscription, impossible);
|
|
277
|
-
this.send("end-host", "service-follow", subscription,
|
|
277
|
+
this.send("end-host", "service-follow", subscription, address, scope, event, impossible !== undefined);
|
|
278
278
|
return once(() => {
|
|
279
279
|
stop();
|
|
280
280
|
this.impossible.delete(subscription);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phreshos/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.47",
|
|
4
4
|
"description": "The SDK used by a Program's client endpoint.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -46,13 +46,13 @@
|
|
|
46
46
|
"test": "vitest run --project default"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"@phreshos/core": "^0.1.
|
|
49
|
+
"@phreshos/core": "^0.1.55"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@the-link/messagepack": "^0.1.0"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@phreshos/core": "^0.1.
|
|
55
|
+
"@phreshos/core": "^0.1.55",
|
|
56
56
|
"typescript": "^6.0.3",
|
|
57
57
|
"vitest": "^4.1.10"
|
|
58
58
|
}
|