@phreshos/client 0.1.38 → 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 +6 -0
- package/dist/appearance.d.ts +8 -7
- package/dist/appearance.js +4 -4
- package/dist/context.js +25 -13
- package/dist/desktop/desktop.js +2 -2
- package/dist/desktop/viewport.d.ts +9 -0
- package/dist/desktop/{surface.js → viewport.js} +6 -6
- package/dist/domain.d.ts +21 -61
- package/dist/domain.js +63 -60
- package/dist/events.d.ts +3 -2
- package/dist/events.js +2 -1
- package/dist/network.d.ts +7 -0
- package/dist/network.js +79 -0
- package/dist/permissions.d.ts +2 -2
- package/dist/permissions.js +2 -2
- package/dist/service.js +26 -21
- package/dist/system.js +2 -75
- package/package.json +8 -8
- package/dist/desktop/surface.d.ts +0 -9
package/README.md
CHANGED
|
@@ -49,6 +49,12 @@ 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
60
|
- [`@phreshos/core`](https://github.com/PhreshOS/core) is the one public import
|
package/dist/appearance.d.ts
CHANGED
|
@@ -4,13 +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
|
-
colors: import("@phreshos/core").AppearanceColors
|
|
8
|
-
spacing:
|
|
9
|
-
radius:
|
|
10
|
-
shadow: import("@phreshos/core").ThemedValue<import("@phreshos/core").AppearanceShadow
|
|
11
|
-
material: import("@phreshos/core").ThemedValue<import("@phreshos/core").AppearanceMaterial
|
|
12
|
-
|
|
13
|
-
|
|
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>;
|
|
14
15
|
}>>;
|
|
15
16
|
update(appearance: Appearance): Promise<void>;
|
|
16
17
|
}
|
package/dist/appearance.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import {
|
|
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(
|
|
8
|
+
listener(parseAppearance(value));
|
|
9
9
|
}, null, impossible), observer => wire.onAll("host-appearance", (event, value) => {
|
|
10
10
|
if (typeof event === "string")
|
|
11
|
-
observer(event,
|
|
11
|
+
observer(event, parseAppearance(value));
|
|
12
12
|
}));
|
|
13
13
|
}
|
|
14
14
|
async snapshot() {
|
|
15
15
|
const [appearance] = await wire.request(["appearance"]);
|
|
16
|
-
return
|
|
16
|
+
return parseAppearance(appearance);
|
|
17
17
|
}
|
|
18
18
|
async update(appearance) {
|
|
19
19
|
await wire.request(["updateAppearance", appearance]);
|
package/dist/context.js
CHANGED
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
import Deadline from "./deadline.js";
|
|
2
|
-
import { ClientEndpoint, ServerEndpoint, ServerTrafficHandle, TrafficHandle,
|
|
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
|
-
|
|
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
|
-
|
|
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) {
|
|
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
|
|
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
|
-
|
|
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
|
|
105
|
-
const
|
|
106
|
-
return
|
|
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(); }
|
package/dist/desktop/desktop.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import ClientPreferences from "./preferences.js";
|
|
2
|
-
import
|
|
2
|
+
import ClientViewport from "./viewport.js";
|
|
3
3
|
/** Desktop access bound to the current Client Endpoint's Process boundary. */
|
|
4
4
|
class ClientDesktop {
|
|
5
|
-
|
|
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
|
|
4
|
-
export default class
|
|
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-
|
|
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-
|
|
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(["
|
|
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
|
|
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
|
|
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
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
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:
|
|
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<
|
|
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<
|
|
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<
|
|
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
|
|
118
|
-
export declare function
|
|
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(
|
|
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,
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
196
|
-
|
|
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
|
|
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
|
-
|
|
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) {
|
|
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
|
|
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
|
-
|
|
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) {
|
|
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,13 +332,14 @@ 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
|
}
|
|
@@ -353,6 +360,8 @@ class LocalWindowHandle {
|
|
|
353
360
|
async resize(size) { await this.change("windowLocalResize", size); }
|
|
354
361
|
async setGeometry(geometry) { await this.change("windowLocalGeometry", geometry); }
|
|
355
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]); }
|
|
356
365
|
async follow(window) {
|
|
357
366
|
const target = windowTargets.get(window);
|
|
358
367
|
if (!target)
|
|
@@ -388,7 +397,7 @@ function deferredScoped(route, target, convert) {
|
|
|
388
397
|
];
|
|
389
398
|
}
|
|
390
399
|
function windowEvent(event) {
|
|
391
|
-
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";
|
|
392
401
|
}
|
|
393
402
|
function deferred(target, register, impossible) {
|
|
394
403
|
let active = true;
|
|
@@ -481,24 +490,18 @@ export function trafficMessage(value) {
|
|
|
481
490
|
const raw = value;
|
|
482
491
|
return { to: visibleEndpoint(raw.to), payload: raw.payload };
|
|
483
492
|
}
|
|
484
|
-
export function
|
|
485
|
-
|
|
486
|
-
subscribe: events.subscribe.bind(events),
|
|
487
|
-
waitFor: events.waitFor.bind(events),
|
|
488
|
-
events: events.events.bind(events)
|
|
489
|
-
});
|
|
490
|
-
}
|
|
491
|
-
export function program(record) {
|
|
493
|
+
export function program(value) {
|
|
494
|
+
const record = parseProgramSnapshot(value);
|
|
492
495
|
const handle = handles.obtain(`program:${record.reference}`, () => new ProgramHandle(record));
|
|
493
496
|
handle.update(record);
|
|
494
497
|
return handle;
|
|
495
498
|
}
|
|
496
|
-
export function process(
|
|
499
|
+
export function process(value, endpoints = {}) {
|
|
500
|
+
const record = parseProcessSnapshot(value);
|
|
497
501
|
return handles.obtain(`process:${record.reference}`, () => new ProcessHandle(record, endpoints));
|
|
498
502
|
}
|
|
499
|
-
export function endpoint(
|
|
500
|
-
|
|
501
|
-
throw new Error("The boundary returned an invalid Endpoint reference");
|
|
503
|
+
export function endpoint(value) {
|
|
504
|
+
const reference = parseEndpointReference(value);
|
|
502
505
|
const owner = process(reference.process);
|
|
503
506
|
return reference.kind === "server" ? owner.server : owner.client;
|
|
504
507
|
}
|
package/dist/events.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { subscribableDefinition, type Cleanup, type EventOptions, type Subscribable, type SubscribableDefinition } from "@phreshos/core";
|
|
2
2
|
export declare const defaultTimeout = 10000;
|
|
3
3
|
type Failure = (error: Error) => void;
|
|
4
4
|
type Listener = (message: unknown) => unknown;
|
|
@@ -8,9 +8,10 @@ type Register<Message> = (listener: (message: Message) => unknown, impossible?:
|
|
|
8
8
|
export default class Events<Vocabulary extends object = {}, Fallback = unknown> implements Subscribable<Vocabulary, Fallback> {
|
|
9
9
|
private readonly listen;
|
|
10
10
|
private readonly listenAll;
|
|
11
|
+
readonly [subscribableDefinition]?: SubscribableDefinition<Vocabulary, Fallback>;
|
|
11
12
|
constructor(listen: (event: string, listener: Listener, impossible?: Failure) => Cleanup, listenAll: (listener: EveryListener, impossible?: Failure) => Cleanup);
|
|
12
13
|
readonly subscribe: Subscribable<Vocabulary, Fallback>["subscribe"];
|
|
13
|
-
readonly
|
|
14
|
+
readonly wait: Subscribable<Vocabulary, Fallback>["wait"];
|
|
14
15
|
readonly events: Subscribable<Vocabulary, Fallback>["events"];
|
|
15
16
|
}
|
|
16
17
|
/** Converts one persistent registration into a bounded asynchronous iterator. */
|
package/dist/events.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { subscribableDefinition } from "@phreshos/core";
|
|
1
2
|
export const defaultTimeout = 10_000;
|
|
2
3
|
/** SDK-owned waits, queues and callbacks over boundary forwarding state. */
|
|
3
4
|
export default class Events {
|
|
@@ -12,7 +13,7 @@ export default class Events {
|
|
|
12
13
|
return this.listen(eventOrSubscriber, subscriber);
|
|
13
14
|
return this.listenAll((event, message) => eventOrSubscriber({ event, message }));
|
|
14
15
|
});
|
|
15
|
-
|
|
16
|
+
wait = ((event, timeout = defaultTimeout) => {
|
|
16
17
|
return new Promise((resolve, reject) => {
|
|
17
18
|
let settled = false;
|
|
18
19
|
let stop = () => undefined;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Network } from "@phreshos/core";
|
|
2
|
+
declare class ClientNetwork implements Network {
|
|
3
|
+
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
4
|
+
websocket(url: string | URL, protocols?: string | string[]): Promise<WebSocket>;
|
|
5
|
+
}
|
|
6
|
+
declare const _default: ClientNetwork;
|
|
7
|
+
export default _default;
|
package/dist/network.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import wire from "./wire.js";
|
|
2
|
+
import controlledStream from "./controlled-stream.js";
|
|
3
|
+
import websocket from "./websocket.js";
|
|
4
|
+
class ClientNetwork {
|
|
5
|
+
async fetch(input, init) {
|
|
6
|
+
const request = new Request(input, {
|
|
7
|
+
...init,
|
|
8
|
+
...init?.body instanceof ReadableStream ? { duplex: "half" } : {}
|
|
9
|
+
});
|
|
10
|
+
const body = request.body;
|
|
11
|
+
const control = new MessageChannel();
|
|
12
|
+
const abort = () => control.port1.postMessage("abort");
|
|
13
|
+
if (request.signal.aborted) {
|
|
14
|
+
control.port1.close();
|
|
15
|
+
control.port2.close();
|
|
16
|
+
throw request.signal.reason;
|
|
17
|
+
}
|
|
18
|
+
request.signal.addEventListener("abort", abort, { once: true });
|
|
19
|
+
const description = {
|
|
20
|
+
body: body !== null,
|
|
21
|
+
cache: request.cache,
|
|
22
|
+
credentials: request.credentials,
|
|
23
|
+
headers: requestHeaders(request.headers, init?.headers),
|
|
24
|
+
integrity: request.integrity,
|
|
25
|
+
keepalive: request.keepalive,
|
|
26
|
+
method: request.method,
|
|
27
|
+
mode: request.mode,
|
|
28
|
+
redirect: request.redirect,
|
|
29
|
+
referrer: request.referrer,
|
|
30
|
+
referrerPolicy: request.referrerPolicy,
|
|
31
|
+
url: request.url
|
|
32
|
+
};
|
|
33
|
+
let result;
|
|
34
|
+
try {
|
|
35
|
+
const answer = await wire.request(["fetch", description, body, control.port2], undefined, body ? [body, control.port2] : [control.port2]);
|
|
36
|
+
result = answer[0];
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
abort();
|
|
40
|
+
closeControl(request.signal, control.port1, abort);
|
|
41
|
+
throw request.signal.aborted ? request.signal.reason : error;
|
|
42
|
+
}
|
|
43
|
+
const responseBody = result.body
|
|
44
|
+
? controlledStream(result.body, abort, () => closeControl(request.signal, control.port1, abort))
|
|
45
|
+
: null;
|
|
46
|
+
if (!responseBody)
|
|
47
|
+
closeControl(request.signal, control.port1, abort);
|
|
48
|
+
const response = new Response(responseBody, {
|
|
49
|
+
headers: result.headers,
|
|
50
|
+
status: result.status,
|
|
51
|
+
statusText: result.statusText
|
|
52
|
+
});
|
|
53
|
+
Object.defineProperties(response, {
|
|
54
|
+
redirected: { configurable: true, enumerable: true, value: result.redirected },
|
|
55
|
+
type: { configurable: true, enumerable: true, value: result.type },
|
|
56
|
+
url: { configurable: true, enumerable: true, value: result.url }
|
|
57
|
+
});
|
|
58
|
+
return response;
|
|
59
|
+
}
|
|
60
|
+
websocket(url, protocols) {
|
|
61
|
+
return websocket(url, protocols);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function requestHeaders(normalized, supplied) {
|
|
65
|
+
if (!supplied)
|
|
66
|
+
return [...normalized.entries()];
|
|
67
|
+
const explicit = supplied instanceof Headers
|
|
68
|
+
? [...supplied.entries()]
|
|
69
|
+
: Array.isArray(supplied)
|
|
70
|
+
? supplied.map(([name, value]) => [name, value])
|
|
71
|
+
: Object.entries(supplied);
|
|
72
|
+
const names = new Set(explicit.map(([name]) => name.toLowerCase()));
|
|
73
|
+
return [...normalized.entries()].filter(([name]) => !names.has(name.toLowerCase())).concat(explicit);
|
|
74
|
+
}
|
|
75
|
+
function closeControl(signal, port, abort) {
|
|
76
|
+
signal.removeEventListener("abort", abort);
|
|
77
|
+
port.close();
|
|
78
|
+
}
|
|
79
|
+
export default new ClientNetwork();
|
package/dist/permissions.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ContextPermissions, ProgramPermissions } from "@phreshos/core";
|
|
2
2
|
import type { HandleAddress } from "./domain.js";
|
|
3
3
|
export declare const defaultPermissionTimeout = 120000;
|
|
4
|
-
/** Bind authoritative
|
|
4
|
+
/** Bind authoritative permission state to one exact Program handle. */
|
|
5
5
|
export declare function programPermissions(program: HandleAddress): ProgramPermissions;
|
|
6
|
-
/**
|
|
6
|
+
/** Permission state and owner requests belonging to the current Client Endpoint. */
|
|
7
7
|
export declare function contextPermissions(): ContextPermissions;
|
package/dist/permissions.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { parsePermission, parsePermissions } from "@phreshos/core";
|
|
2
2
|
import wire from "./wire.js";
|
|
3
3
|
export const defaultPermissionTimeout = 120_000;
|
|
4
|
-
/** Bind authoritative
|
|
4
|
+
/** Bind authoritative permission state to one exact Program handle. */
|
|
5
5
|
export function programPermissions(program) {
|
|
6
6
|
const operate = (operation, name, permission) => (wire.request(["program-permissions", program, operation, name, permission]));
|
|
7
7
|
return {
|
|
@@ -12,7 +12,7 @@ export function programPermissions(program) {
|
|
|
12
12
|
async delete(name) { await operate("delete", name); }
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
|
-
/**
|
|
15
|
+
/** Permission state and owner requests belonging to the current Client Endpoint. */
|
|
16
16
|
export function contextPermissions() {
|
|
17
17
|
const timed = (timeout) => ({
|
|
18
18
|
async request(name, permission = true) {
|
package/dist/service.js
CHANGED
|
@@ -4,8 +4,6 @@ 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
|
-
const ServerServiceBase = CoreServerService;
|
|
8
|
-
const ClientServiceBase = CoreClientService;
|
|
9
7
|
class ServiceHandle {
|
|
10
8
|
key;
|
|
11
9
|
lifecycle;
|
|
@@ -24,8 +22,11 @@ class ServiceHandle {
|
|
|
24
22
|
await wire.request(["service-wait-ready", this.key, timeout], timeout);
|
|
25
23
|
}
|
|
26
24
|
}
|
|
27
|
-
class ServerHandler extends
|
|
25
|
+
class ServerHandler extends CoreServerService {
|
|
28
26
|
key;
|
|
27
|
+
subscribe;
|
|
28
|
+
wait;
|
|
29
|
+
events;
|
|
29
30
|
lifecycle;
|
|
30
31
|
service;
|
|
31
32
|
constructor(key) {
|
|
@@ -33,9 +34,12 @@ class ServerHandler extends ServerServiceBase {
|
|
|
33
34
|
this.key = key;
|
|
34
35
|
this.service = new ServiceHandle(key);
|
|
35
36
|
this.lifecycle = this.service.lifecycle;
|
|
36
|
-
|
|
37
|
+
const events = new Events(...serviceEvents(key, "events"));
|
|
38
|
+
this.subscribe = events.subscribe;
|
|
39
|
+
this.wait = events.wait;
|
|
40
|
+
this.events = events.events;
|
|
37
41
|
}
|
|
38
|
-
publish(event, payload = undefined) { this.service.publish(event, payload); }
|
|
42
|
+
publish = (event, payload = undefined) => { this.service.publish(event, payload); };
|
|
39
43
|
exists() { return this.service.exists(); }
|
|
40
44
|
waitReady(timeout) { return this.service.waitReady(timeout); }
|
|
41
45
|
async ask(event, payload = undefined) {
|
|
@@ -58,31 +62,39 @@ class ServerHandler extends ServerServiceBase {
|
|
|
58
62
|
}
|
|
59
63
|
}
|
|
60
64
|
}
|
|
61
|
-
class ClientHandler extends
|
|
65
|
+
class ClientHandler extends CoreClientService {
|
|
66
|
+
subscribe;
|
|
67
|
+
wait;
|
|
68
|
+
events;
|
|
62
69
|
lifecycle;
|
|
63
70
|
service;
|
|
64
71
|
constructor(key) {
|
|
65
72
|
super();
|
|
66
73
|
this.service = new ServiceHandle(key);
|
|
67
74
|
this.lifecycle = this.service.lifecycle;
|
|
68
|
-
|
|
75
|
+
const events = new Events(...serviceEvents(key, "events"));
|
|
76
|
+
this.subscribe = events.subscribe;
|
|
77
|
+
this.wait = events.wait;
|
|
78
|
+
this.events = events.events;
|
|
69
79
|
}
|
|
70
|
-
publish(event, payload = undefined) { this.service.publish(event, payload); }
|
|
80
|
+
publish = (event, payload = undefined) => { this.service.publish(event, payload); };
|
|
71
81
|
exists() { return this.service.exists(); }
|
|
72
82
|
waitReady(timeout) { return this.service.waitReady(timeout); }
|
|
73
83
|
}
|
|
74
84
|
export function prepareService(key) {
|
|
75
85
|
if (!isServiceKey(key))
|
|
76
86
|
throw new Error("A complete service key is required");
|
|
77
|
-
const
|
|
87
|
+
const address = Object.freeze({
|
|
78
88
|
...(key.program === undefined ? {} : { program: key.program }),
|
|
79
|
-
process: key.process
|
|
80
|
-
endpoint: key.endpoint
|
|
89
|
+
process: key.process
|
|
81
90
|
});
|
|
82
91
|
const identity = JSON.stringify([key.program ?? null, key.process, key.endpoint]);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
92
|
+
if (key.endpoint === "server") {
|
|
93
|
+
const normalized = Object.freeze({ ...address, endpoint: "server" });
|
|
94
|
+
return handles.obtain(`service:${identity}`, () => new ServerHandler(normalized));
|
|
95
|
+
}
|
|
96
|
+
const normalized = Object.freeze({ ...address, endpoint: "client" });
|
|
97
|
+
return handles.obtain(`service:${identity}`, () => new ClientHandler(normalized));
|
|
86
98
|
}
|
|
87
99
|
function serviceEvents(key, scope) {
|
|
88
100
|
return [
|
|
@@ -93,10 +105,3 @@ function serviceEvents(key, scope) {
|
|
|
93
105
|
}, impossible)
|
|
94
106
|
];
|
|
95
107
|
}
|
|
96
|
-
function bindEvents(target, events) {
|
|
97
|
-
Object.assign(target, {
|
|
98
|
-
subscribe: events.subscribe.bind(events),
|
|
99
|
-
waitFor: events.waitFor.bind(events),
|
|
100
|
-
events: events.events.bind(events)
|
|
101
|
-
});
|
|
102
|
-
}
|
package/dist/system.js
CHANGED
|
@@ -3,76 +3,18 @@ import ClientAppearance from "./appearance.js";
|
|
|
3
3
|
import wire from "./wire.js";
|
|
4
4
|
import { prepareService } from "./service.js";
|
|
5
5
|
import { uploads } from "./uploads.js";
|
|
6
|
-
import controlledStream from "./controlled-stream.js";
|
|
7
6
|
import Events from "./events.js";
|
|
8
7
|
import { exit, process, program } from "./domain.js";
|
|
9
8
|
import { systemStorage } from "./storage.js";
|
|
10
|
-
import
|
|
9
|
+
import network from "./network.js";
|
|
11
10
|
class ClientSystem {
|
|
12
11
|
storage = systemStorage();
|
|
13
12
|
appearance = new ClientAppearance();
|
|
14
13
|
program = new SystemProgramHandle();
|
|
15
14
|
process = new SystemProcessHandle();
|
|
16
15
|
uploads = uploads;
|
|
16
|
+
network = network;
|
|
17
17
|
service(key) { return prepareService(key); }
|
|
18
|
-
async fetch(input, init) {
|
|
19
|
-
const request = new Request(input, {
|
|
20
|
-
...init,
|
|
21
|
-
...init?.body instanceof ReadableStream ? { duplex: "half" } : {}
|
|
22
|
-
});
|
|
23
|
-
const body = request.body;
|
|
24
|
-
const control = new MessageChannel();
|
|
25
|
-
const abort = () => control.port1.postMessage("abort");
|
|
26
|
-
if (request.signal.aborted) {
|
|
27
|
-
control.port1.close();
|
|
28
|
-
control.port2.close();
|
|
29
|
-
throw request.signal.reason;
|
|
30
|
-
}
|
|
31
|
-
request.signal.addEventListener("abort", abort, { once: true });
|
|
32
|
-
const description = {
|
|
33
|
-
body: body !== null,
|
|
34
|
-
cache: request.cache,
|
|
35
|
-
credentials: request.credentials,
|
|
36
|
-
headers: requestHeaders(request.headers, init?.headers),
|
|
37
|
-
integrity: request.integrity,
|
|
38
|
-
keepalive: request.keepalive,
|
|
39
|
-
method: request.method,
|
|
40
|
-
mode: request.mode,
|
|
41
|
-
redirect: request.redirect,
|
|
42
|
-
referrer: request.referrer,
|
|
43
|
-
referrerPolicy: request.referrerPolicy,
|
|
44
|
-
url: request.url
|
|
45
|
-
};
|
|
46
|
-
let result;
|
|
47
|
-
try {
|
|
48
|
-
const answer = await wire.request(["fetch", description, body, control.port2], undefined, body ? [body, control.port2] : [control.port2]);
|
|
49
|
-
result = answer[0];
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
abort();
|
|
53
|
-
closeControl(request.signal, control.port1, abort);
|
|
54
|
-
throw request.signal.aborted ? request.signal.reason : error;
|
|
55
|
-
}
|
|
56
|
-
const responseBody = result.body
|
|
57
|
-
? controlledStream(result.body, abort, () => closeControl(request.signal, control.port1, abort))
|
|
58
|
-
: null;
|
|
59
|
-
if (!responseBody)
|
|
60
|
-
closeControl(request.signal, control.port1, abort);
|
|
61
|
-
const response = new Response(responseBody, {
|
|
62
|
-
headers: result.headers,
|
|
63
|
-
status: result.status,
|
|
64
|
-
statusText: result.statusText
|
|
65
|
-
});
|
|
66
|
-
Object.defineProperties(response, {
|
|
67
|
-
redirected: { configurable: true, enumerable: true, value: result.redirected },
|
|
68
|
-
type: { configurable: true, enumerable: true, value: result.type },
|
|
69
|
-
url: { configurable: true, enumerable: true, value: result.url }
|
|
70
|
-
});
|
|
71
|
-
return response;
|
|
72
|
-
}
|
|
73
|
-
websocket(url, protocols) {
|
|
74
|
-
return websocket(url, protocols);
|
|
75
|
-
}
|
|
76
18
|
async *shell(command, options = {}) {
|
|
77
19
|
const { signal, ...settings } = options;
|
|
78
20
|
for await (const event of wire.stream(["shell", command, settings], undefined, signal))
|
|
@@ -133,20 +75,5 @@ function systemProgramEvent(event, values) {
|
|
|
133
75
|
return { program: program(values[1]), everything: values[2] === true };
|
|
134
76
|
return values[0];
|
|
135
77
|
}
|
|
136
|
-
function requestHeaders(normalized, supplied) {
|
|
137
|
-
if (!supplied)
|
|
138
|
-
return [...normalized.entries()];
|
|
139
|
-
const explicit = supplied instanceof Headers
|
|
140
|
-
? [...supplied.entries()]
|
|
141
|
-
: Array.isArray(supplied)
|
|
142
|
-
? supplied.map(([name, value]) => [name, value])
|
|
143
|
-
: Object.entries(supplied);
|
|
144
|
-
const names = new Set(explicit.map(([name]) => name.toLowerCase()));
|
|
145
|
-
return [...normalized.entries()].filter(([name]) => !names.has(name.toLowerCase())).concat(explicit);
|
|
146
|
-
}
|
|
147
|
-
function closeControl(signal, port, abort) {
|
|
148
|
-
signal.removeEventListener("abort", abort);
|
|
149
|
-
port.close();
|
|
150
|
-
}
|
|
151
78
|
/** The global System represented through this Client runtime. */
|
|
152
79
|
export const system = new ClientSystem();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phreshos/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.39",
|
|
4
4
|
"description": "The SDK used by a Program's client endpoint.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -41,19 +41,19 @@
|
|
|
41
41
|
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
42
42
|
"check": "tsc --noEmit && tsc -p tsconfig.test.json",
|
|
43
43
|
"build": "node --run clean && tsc --noEmit false --outDir dist --rootDir source",
|
|
44
|
-
"verify
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"prepack": "node --run build"
|
|
44
|
+
"verify": "node --run check && node --run build && node --run test",
|
|
45
|
+
"prepack": "node --run build",
|
|
46
|
+
"test": "vitest run --project default"
|
|
48
47
|
},
|
|
49
48
|
"peerDependencies": {
|
|
50
|
-
"@phreshos/core": "^0.1.
|
|
49
|
+
"@phreshos/core": "^0.1.43"
|
|
51
50
|
},
|
|
52
51
|
"dependencies": {
|
|
53
52
|
"@the-link/messagepack": "^0.1.0"
|
|
54
53
|
},
|
|
55
54
|
"devDependencies": {
|
|
56
|
-
"@phreshos/core": "^0.1.
|
|
57
|
-
"typescript": "^6.0.3"
|
|
55
|
+
"@phreshos/core": "^0.1.43",
|
|
56
|
+
"typescript": "^6.0.3",
|
|
57
|
+
"vitest": "^4.1.10"
|
|
58
58
|
}
|
|
59
59
|
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { DesktopSurfaceEvents, DesktopSurfaceSource } from "@phreshos/core";
|
|
2
|
-
import Events from "../events.js";
|
|
3
|
-
/** Read-only access to the Desktop surface containing this Client Endpoint. */
|
|
4
|
-
export default class ClientSurface extends Events<DesktopSurfaceEvents, never> implements DesktopSurfaceSource {
|
|
5
|
-
constructor();
|
|
6
|
-
snapshot(): Promise<Readonly<{
|
|
7
|
-
size: import("@phreshos/core").DesktopSize;
|
|
8
|
-
}>>;
|
|
9
|
-
}
|