@phreshos/node 0.1.17 → 0.1.18
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/events.d.ts +4 -3
- package/dist/events.js +2 -1
- package/dist/network.d.ts +3 -0
- package/dist/network.js +13 -0
- package/dist/project.js +33 -21
- package/dist/representation.d.ts +6 -21
- package/dist/representation.js +13 -21
- package/dist/system.d.ts +1 -2
- package/dist/system.js +63 -57
- package/dist/traffic.d.ts +1 -1
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -56,6 +56,12 @@ bun run verify
|
|
|
56
56
|
`verify` checks the types, builds the package, runs the connection and Project
|
|
57
57
|
tests, and validates the published package shape independently.
|
|
58
58
|
|
|
59
|
+
`check` performs static checks, `build` creates distributable output, and `test`
|
|
60
|
+
runs Vitest assertions from `tests/`. Run `build` before testing built artifacts.
|
|
61
|
+
`verify` runs `check`, `build`, and `test` in order. Operational tooling belongs
|
|
62
|
+
in `scripts/`; tests and their fixtures belong in `tests/`. Verification uses
|
|
63
|
+
the committed dependency graph without local package substitutions.
|
|
64
|
+
|
|
59
65
|
## Related repositories
|
|
60
66
|
|
|
61
67
|
- [`@phreshos/core`](https://github.com/PhreshOS/core) owns the shared System
|
package/dist/events.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { subscribableDefinition, type Cleanup, type EventOptions, type Subscribable, type SubscribableDefinition } from "@phreshos/core";
|
|
2
2
|
type Failure = (error: Error) => void;
|
|
3
3
|
type Register<Message> = (subscriber: (message: Message) => unknown, impossible?: Failure) => Cleanup;
|
|
4
4
|
type Subscribe = (event: string | null, subscriber: (message: unknown) => unknown, impossible?: Failure) => Cleanup;
|
|
5
5
|
/** Adapts one live representation source into the shared Subscribable contract. */
|
|
6
|
-
export default class Events<Definitions extends object, Fallback = never> {
|
|
6
|
+
export default class Events<Definitions extends object, Fallback = never> implements Subscribable<Definitions, Fallback> {
|
|
7
7
|
private readonly names;
|
|
8
8
|
private readonly register;
|
|
9
|
+
readonly [subscribableDefinition]?: SubscribableDefinition<Definitions, Fallback>;
|
|
9
10
|
constructor(names: readonly string[], register: Subscribe);
|
|
10
11
|
readonly subscribe: Subscribable<Definitions, Fallback>["subscribe"];
|
|
11
|
-
readonly
|
|
12
|
+
readonly wait: Subscribable<Definitions, Fallback>["wait"];
|
|
12
13
|
readonly events: Subscribable<Definitions, Fallback>["events"];
|
|
13
14
|
private listen;
|
|
14
15
|
}
|
package/dist/events.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { subscribableDefinition } from "@phreshos/core";
|
|
1
2
|
/** Adapts one live representation source into the shared Subscribable contract. */
|
|
2
3
|
export default class Events {
|
|
3
4
|
names;
|
|
@@ -19,7 +20,7 @@ export default class Events {
|
|
|
19
20
|
eventOrSubscriber({ event: capture.event, message: capture.payload });
|
|
20
21
|
});
|
|
21
22
|
});
|
|
22
|
-
|
|
23
|
+
wait = ((event, timeout = 10_000) => new Promise((resolve, reject) => {
|
|
23
24
|
let stop = () => undefined;
|
|
24
25
|
const timer = setTimeout(() => {
|
|
25
26
|
stop();
|
package/dist/network.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import websocket from "./websocket.js";
|
|
2
|
+
/** Networking shares the lifetime of its owning System connection. */
|
|
3
|
+
export default function network(signal) {
|
|
4
|
+
return {
|
|
5
|
+
async fetch(input, init) {
|
|
6
|
+
const request = new Request(input, init);
|
|
7
|
+
return fetch(request, { signal: AbortSignal.any([request.signal, signal()]) });
|
|
8
|
+
},
|
|
9
|
+
websocket(url, protocols) {
|
|
10
|
+
return websocket(url, protocols, signal());
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
package/dist/project.js
CHANGED
|
@@ -61,34 +61,45 @@ export class Project {
|
|
|
61
61
|
if (mode === "development" && !config.server?.development && !config.client?.development) {
|
|
62
62
|
throw new Error("Nothing here says how this Program is developed");
|
|
63
63
|
}
|
|
64
|
-
|
|
64
|
+
const definition = {
|
|
65
65
|
identity: config.identity,
|
|
66
66
|
name: config.name,
|
|
67
67
|
version: config.version,
|
|
68
68
|
description: config.description,
|
|
69
|
+
categories: config.categories,
|
|
70
|
+
keywords: config.keywords,
|
|
71
|
+
website: config.website,
|
|
69
72
|
icon: config.icon && resolve(this.directory, config.icon),
|
|
70
73
|
agent: config.agent && resolve(this.directory, config.agent),
|
|
71
|
-
storage: resolve(this.directory, "storage")
|
|
72
|
-
...server && { server: {
|
|
73
|
-
location: resolve(this.directory, server.location),
|
|
74
|
-
start: server.start,
|
|
75
|
-
service: server.service,
|
|
76
|
-
installCommand: config.server?.installCommand,
|
|
77
|
-
uninstallCommand: config.server?.uninstallCommand,
|
|
78
|
-
...serverExecution(server)
|
|
79
|
-
} },
|
|
80
|
-
...client && { client: {
|
|
81
|
-
location: /^https?:\/\//i.test(client.location) ? client.location : resolve(this.directory, client.location),
|
|
82
|
-
start: client.start,
|
|
83
|
-
service: client.service,
|
|
84
|
-
title: config.client?.title,
|
|
85
|
-
size: config.client?.size,
|
|
86
|
-
position: config.client?.position,
|
|
87
|
-
layer: config.client?.layer,
|
|
88
|
-
minimize: config.client?.minimize,
|
|
89
|
-
permissions: config.client?.permissions
|
|
90
|
-
} }
|
|
74
|
+
storage: resolve(this.directory, "storage")
|
|
91
75
|
};
|
|
76
|
+
const serverDefinition = server ? {
|
|
77
|
+
location: resolve(this.directory, server.location),
|
|
78
|
+
start: server.start,
|
|
79
|
+
service: server.service,
|
|
80
|
+
installCommand: config.server?.installCommand,
|
|
81
|
+
uninstallCommand: config.server?.uninstallCommand,
|
|
82
|
+
...serverExecution(server)
|
|
83
|
+
} : null;
|
|
84
|
+
const clientDefinition = client ? {
|
|
85
|
+
location: /^https?:\/\//i.test(client.location) ? client.location : resolve(this.directory, client.location),
|
|
86
|
+
start: client.start,
|
|
87
|
+
service: client.service,
|
|
88
|
+
title: config.client?.title,
|
|
89
|
+
size: config.client?.size,
|
|
90
|
+
position: config.client?.position,
|
|
91
|
+
layer: config.client?.layer,
|
|
92
|
+
minimize: config.client?.minimize,
|
|
93
|
+
maximize: config.client?.maximize,
|
|
94
|
+
permissions: config.client?.permissions
|
|
95
|
+
} : null;
|
|
96
|
+
if (serverDefinition && clientDefinition)
|
|
97
|
+
return { ...definition, server: serverDefinition, client: clientDefinition };
|
|
98
|
+
if (serverDefinition)
|
|
99
|
+
return { ...definition, server: serverDefinition };
|
|
100
|
+
if (clientDefinition)
|
|
101
|
+
return { ...definition, client: clientDefinition };
|
|
102
|
+
throw new Error("A Program must define a Server, a Client, or both");
|
|
92
103
|
}
|
|
93
104
|
/** Run the optional author-owned production build command. */
|
|
94
105
|
async build() {
|
|
@@ -326,6 +337,7 @@ function packageDefinition(config, version) {
|
|
|
326
337
|
position: config.client.position,
|
|
327
338
|
layer: config.client.layer,
|
|
328
339
|
minimize: config.client.minimize,
|
|
340
|
+
maximize: config.client.maximize,
|
|
329
341
|
permissions: config.client.permissions
|
|
330
342
|
} }
|
|
331
343
|
};
|
package/dist/representation.d.ts
CHANGED
|
@@ -1,32 +1,17 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Appearance, type ProcessSnapshot, type ProgramSnapshot, type ServiceKey, type WindowState as CoreWindowState } from "@phreshos/core";
|
|
2
2
|
import type { GatewayConnection } from "./transport.js";
|
|
3
|
-
export
|
|
4
|
-
reference: string;
|
|
5
|
-
identity: string;
|
|
6
|
-
assetId: string;
|
|
3
|
+
export type ProgramState = ProgramSnapshot & Readonly<{
|
|
7
4
|
installed: boolean;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
description: string | null;
|
|
11
|
-
hasAgent: boolean;
|
|
12
|
-
server: EndpointDeclaration | null;
|
|
13
|
-
client: ClientDeclaration | null;
|
|
14
|
-
}
|
|
15
|
-
export interface WindowState {
|
|
16
|
-
title: string;
|
|
17
|
-
position: WindowGeometry["position"];
|
|
18
|
-
size: WindowGeometry["size"];
|
|
5
|
+
}>;
|
|
6
|
+
export type WindowState = Omit<CoreWindowState, "front"> & Readonly<{
|
|
19
7
|
depth: number;
|
|
20
|
-
|
|
21
|
-
layer: WindowLayer;
|
|
22
|
-
location: string;
|
|
23
|
-
}
|
|
8
|
+
}>;
|
|
24
9
|
export interface ProcessIdentityState {
|
|
25
10
|
reference: string;
|
|
26
11
|
identity: string;
|
|
27
12
|
name: string | null;
|
|
28
13
|
program: string;
|
|
29
|
-
options:
|
|
14
|
+
options: ProcessSnapshot["options"];
|
|
30
15
|
startedAt: Date;
|
|
31
16
|
}
|
|
32
17
|
export interface ProcessState extends ProcessIdentityState {
|
package/dist/representation.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { parseProgramSnapshot, parseAppearance } from "@phreshos/core";
|
|
2
3
|
const maximumStreamQueue = 256;
|
|
3
4
|
/** A connection-owned, live representation of the authoritative System model. */
|
|
4
5
|
export default class SystemRepresentation {
|
|
@@ -13,7 +14,7 @@ export default class SystemRepresentation {
|
|
|
13
14
|
this.connection = connection;
|
|
14
15
|
const session = ownerSession(connection.session);
|
|
15
16
|
this.authorization = session.authorization;
|
|
16
|
-
this.appearance = session.linkManager.appearance.value;
|
|
17
|
+
this.appearance = parseAppearance(session.linkManager.appearance.value);
|
|
17
18
|
for (const [, value] of session.authManager.programManager.programs) {
|
|
18
19
|
const program = programState(value);
|
|
19
20
|
this.programs.set(program.identity, program);
|
|
@@ -133,7 +134,7 @@ export default class SystemRepresentation {
|
|
|
133
134
|
followModel(appearance) {
|
|
134
135
|
const subscribe = (event, listener) => this.release.push(this.connection.subscribe(event, listener));
|
|
135
136
|
subscribe(`property-update:${appearance}`, value => {
|
|
136
|
-
this.appearance = value;
|
|
137
|
+
this.appearance = parseAppearance(value);
|
|
137
138
|
this.emit("appearance", this.appearance);
|
|
138
139
|
});
|
|
139
140
|
subscribe("/auth/program/create", value => this.arriveProgram("create", value));
|
|
@@ -148,7 +149,7 @@ export default class SystemRepresentation {
|
|
|
148
149
|
subscribe("/auth/process/client-stop", (identity, value) => this.changeEndpoint(identity, "client", value, false));
|
|
149
150
|
subscribe("/auth/process/client-access", (identity, value) => this.changeEndpoint(identity, "client", value));
|
|
150
151
|
subscribe("/auth/process/exited", (value, code, signal) => this.exitProcess(value, code, signal));
|
|
151
|
-
for (const event of ["move", "resize", "geometry", "change-title", "raise", "minimize"]) {
|
|
152
|
+
for (const event of ["move", "resize", "geometry", "change-title", "raise", "minimize", "maximize"]) {
|
|
152
153
|
subscribe(`/auth/process/${event}`, value => this.changeWindow(event, value));
|
|
153
154
|
}
|
|
154
155
|
}
|
|
@@ -253,21 +254,10 @@ function ownerSession(value) {
|
|
|
253
254
|
};
|
|
254
255
|
}
|
|
255
256
|
function programState(value) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
return {
|
|
260
|
-
reference: value.reference,
|
|
261
|
-
identity: value.identity,
|
|
262
|
-
assetId: value.assetId,
|
|
263
|
-
installed: value.installed === true,
|
|
264
|
-
name: value.name,
|
|
265
|
-
version: typeof value.version === "string" ? value.version : null,
|
|
266
|
-
description: typeof value.description === "string" ? value.description : null,
|
|
267
|
-
hasAgent: value.hasAgent === true,
|
|
268
|
-
server: value.server,
|
|
269
|
-
client: value.client
|
|
270
|
-
};
|
|
257
|
+
const parsed = parseProgramSnapshot(value);
|
|
258
|
+
if (parsed.installed === undefined)
|
|
259
|
+
throw new Error("The System returned a Program without installation state");
|
|
260
|
+
return { ...parsed, installed: parsed.installed };
|
|
271
261
|
}
|
|
272
262
|
function processState(value) {
|
|
273
263
|
const identity = processIdentityState(value);
|
|
@@ -307,7 +297,7 @@ export function processIdentityState(value) {
|
|
|
307
297
|
};
|
|
308
298
|
}
|
|
309
299
|
function windowState(value) {
|
|
310
|
-
if (!record(value) || typeof value.title !== "string" || typeof value.
|
|
300
|
+
if (!record(value) || typeof value.title !== "string" || typeof value.depth !== "number" || typeof value.minimized !== "boolean" || typeof value.maximized !== "boolean") {
|
|
311
301
|
throw new Error("The System returned an invalid Window");
|
|
312
302
|
}
|
|
313
303
|
return {
|
|
@@ -316,8 +306,8 @@ function windowState(value) {
|
|
|
316
306
|
size: value.size,
|
|
317
307
|
depth: value.depth,
|
|
318
308
|
minimized: value.minimized,
|
|
319
|
-
|
|
320
|
-
|
|
309
|
+
maximized: value.maximized,
|
|
310
|
+
layer: value.layer
|
|
321
311
|
};
|
|
322
312
|
}
|
|
323
313
|
function windowMessage(event, process) {
|
|
@@ -332,6 +322,8 @@ function windowMessage(event, process) {
|
|
|
332
322
|
return window.title;
|
|
333
323
|
if (event === "minimize")
|
|
334
324
|
return window.minimized;
|
|
325
|
+
if (event === "maximize")
|
|
326
|
+
return window.maximized;
|
|
335
327
|
return true;
|
|
336
328
|
}
|
|
337
329
|
function camel(value) { return value === "change-title" ? "changeTitle" : value; }
|
package/dist/system.d.ts
CHANGED
|
@@ -11,8 +11,7 @@ export declare class System implements CoreSystem {
|
|
|
11
11
|
readonly program: SystemProgram;
|
|
12
12
|
readonly process: SystemProcess;
|
|
13
13
|
readonly uploads: SystemUploads;
|
|
14
|
-
|
|
15
|
-
websocket(url: string | URL, protocols?: string | string[]): Promise<WebSocket>;
|
|
14
|
+
readonly network: import("@phreshos/core").Network;
|
|
16
15
|
shell(command: string, options?: ShellOptions): AsyncGenerator<import("@phreshos/core").ShellEvent, void, void>;
|
|
17
16
|
private constructor();
|
|
18
17
|
/** Connect to the System selected by argument, environment, or owner default. */
|
package/dist/system.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ClientEndpoint as CoreClientEndpoint, ClientService as CoreClientService, Process as CoreProcess, Program as CoreProgram, ServerEndpoint as CoreServerEndpoint, ServerService as CoreServerService, isServiceKey,
|
|
1
|
+
import { ClientEndpoint as CoreClientEndpoint, ClientService as CoreClientService, Process as CoreProcess, Program as CoreProgram, ServerEndpoint as CoreServerEndpoint, ServerService as CoreServerService, isServiceKey, parseEndpointReference } from "@phreshos/core";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { gatewayAddress } from "./address.js";
|
|
4
4
|
import Events from "./events.js";
|
|
@@ -11,13 +11,9 @@ import SystemRepresentation, { processIdentityState } from "./representation.js"
|
|
|
11
11
|
import { GatewayConnection, openConnection } from "./transport.js";
|
|
12
12
|
import Uploads from "./uploads.js";
|
|
13
13
|
import shell from "./shell.js";
|
|
14
|
-
import
|
|
14
|
+
import network from "./network.js";
|
|
15
15
|
const systems = new WeakMap();
|
|
16
16
|
const processSnapshots = new WeakMap();
|
|
17
|
-
const ProgramBase = CoreProgram;
|
|
18
|
-
const ProcessBase = CoreProcess;
|
|
19
|
-
const ServerEndpointBase = CoreServerEndpoint;
|
|
20
|
-
const ClientEndpointBase = CoreClientEndpoint;
|
|
21
17
|
/** One connected owner-local implementation of the shared System contract. */
|
|
22
18
|
export class System {
|
|
23
19
|
storage;
|
|
@@ -25,13 +21,7 @@ export class System {
|
|
|
25
21
|
program;
|
|
26
22
|
process;
|
|
27
23
|
uploads;
|
|
28
|
-
|
|
29
|
-
const request = new Request(input, init);
|
|
30
|
-
return await fetch(request, { signal: connectedSignal(this, request.signal) });
|
|
31
|
-
}
|
|
32
|
-
websocket(url, protocols) {
|
|
33
|
-
return websocket(url, protocols, connectedSignal(this));
|
|
34
|
-
}
|
|
24
|
+
network = network(() => connectedSignal(this));
|
|
35
25
|
async *shell(command, options = {}) {
|
|
36
26
|
yield* shell(command, { ...options, signal: connectedSignal(this, options.signal) });
|
|
37
27
|
}
|
|
@@ -157,8 +147,11 @@ class ProgramRegistry extends Events {
|
|
|
157
147
|
return event === "uninstall" ? { program, everything: values[1] === true } : program;
|
|
158
148
|
}
|
|
159
149
|
}
|
|
160
|
-
class ProgramHandle extends
|
|
150
|
+
class ProgramHandle extends CoreProgram {
|
|
161
151
|
system;
|
|
152
|
+
subscribe;
|
|
153
|
+
wait;
|
|
154
|
+
events;
|
|
162
155
|
reference;
|
|
163
156
|
identity;
|
|
164
157
|
data;
|
|
@@ -177,11 +170,14 @@ class ProgramHandle extends ProgramBase {
|
|
|
177
170
|
this.reference = snapshot.reference;
|
|
178
171
|
this.identity = snapshot.identity;
|
|
179
172
|
const address = this.address();
|
|
180
|
-
|
|
173
|
+
const events = new Events(["forget", "uninstall"], (event, subscriber) => {
|
|
181
174
|
if (event === null)
|
|
182
175
|
throw new Error("Program events are named");
|
|
183
176
|
return representation(system).on(`program:${this.reference}:${event}`, (...values) => subscriber(values[0]));
|
|
184
|
-
})
|
|
177
|
+
});
|
|
178
|
+
this.subscribe = events.subscribe;
|
|
179
|
+
this.wait = events.wait;
|
|
180
|
+
this.events = events.events;
|
|
185
181
|
representation(system).on(`program:${this.reference}:change`, value => this.update(value));
|
|
186
182
|
const call = (event, ...values) => representation(system).call(event, ...values);
|
|
187
183
|
this.data = filesystemStorage(() => programStoragePath(system, address, "data"), `Program "${this.identity}" data`, () => connectedSignal(system));
|
|
@@ -204,18 +200,7 @@ class ProgramHandle extends ProgramBase {
|
|
|
204
200
|
service: this.snapshot.server.service
|
|
205
201
|
}) : null;
|
|
206
202
|
}
|
|
207
|
-
get client() {
|
|
208
|
-
return this.snapshot.client ? Object.freeze({
|
|
209
|
-
start: this.snapshot.client.start,
|
|
210
|
-
service: this.snapshot.client.service,
|
|
211
|
-
title: this.snapshot.client.title,
|
|
212
|
-
size: this.snapshot.client.size,
|
|
213
|
-
position: this.snapshot.client.position,
|
|
214
|
-
layer: this.snapshot.client.layer,
|
|
215
|
-
minimize: this.snapshot.client.minimize,
|
|
216
|
-
permissions: parseClientPermissions(this.snapshot.client.permissions)
|
|
217
|
-
}) : null;
|
|
218
|
-
}
|
|
203
|
+
get client() { return this.snapshot.client; }
|
|
219
204
|
update(snapshot) {
|
|
220
205
|
if (snapshot.reference !== this.reference)
|
|
221
206
|
throw new Error("A Program handle cannot become another Program");
|
|
@@ -358,8 +343,11 @@ class ProcessRegistry extends Events {
|
|
|
358
343
|
return process ? processHandle(this.system, process) : null;
|
|
359
344
|
}
|
|
360
345
|
}
|
|
361
|
-
class ProcessHandle extends
|
|
346
|
+
class ProcessHandle extends CoreProcess {
|
|
362
347
|
system;
|
|
348
|
+
subscribe;
|
|
349
|
+
wait;
|
|
350
|
+
events;
|
|
363
351
|
identity;
|
|
364
352
|
name;
|
|
365
353
|
startedAt;
|
|
@@ -369,7 +357,10 @@ class ProcessHandle extends ProcessBase {
|
|
|
369
357
|
super();
|
|
370
358
|
this.system = system;
|
|
371
359
|
processSnapshots.set(this, snapshot);
|
|
372
|
-
|
|
360
|
+
const events = new Events(["exit"], (_event, subscriber) => (representation(system).on(`process:${snapshot.reference}:exit`, value => subscriber(value))));
|
|
361
|
+
this.subscribe = events.subscribe;
|
|
362
|
+
this.wait = events.wait;
|
|
363
|
+
this.events = events.events;
|
|
373
364
|
this.identity = snapshot.identity;
|
|
374
365
|
this.name = snapshot.name;
|
|
375
366
|
this.startedAt = new Date(snapshot.startedAt);
|
|
@@ -389,7 +380,10 @@ class ProcessHandle extends ProcessBase {
|
|
|
389
380
|
});
|
|
390
381
|
return value === null ? null : processHandle(this.system, processIdentityState(value));
|
|
391
382
|
}
|
|
392
|
-
async
|
|
383
|
+
async options(name) {
|
|
384
|
+
const options = processState(this.system, this).options;
|
|
385
|
+
return name === undefined ? Object.freeze({ ...options }) : options[name];
|
|
386
|
+
}
|
|
393
387
|
async exit() {
|
|
394
388
|
await representation(this.system).call("/process/exit", this.identity);
|
|
395
389
|
}
|
|
@@ -432,9 +426,12 @@ class EndpointOperations extends Events {
|
|
|
432
426
|
await representation(this.system).call(`/process/endpoint/${operation}`, this.owner.identity, this.endpoint, launch);
|
|
433
427
|
}
|
|
434
428
|
}
|
|
435
|
-
class ServerEndpointHandle extends
|
|
429
|
+
class ServerEndpointHandle extends CoreServerEndpoint {
|
|
436
430
|
system;
|
|
437
431
|
owner;
|
|
432
|
+
subscribe;
|
|
433
|
+
wait;
|
|
434
|
+
events;
|
|
438
435
|
endpoint = "server";
|
|
439
436
|
traffic;
|
|
440
437
|
lifecycle;
|
|
@@ -446,7 +443,9 @@ class ServerEndpointHandle extends ServerEndpointBase {
|
|
|
446
443
|
this.base = new EndpointOperations(system, owner, "server");
|
|
447
444
|
this.traffic = new ServerTrafficHandle(representation(system), owner.identity, "server", value => endpointFromReference(system, value));
|
|
448
445
|
this.lifecycle = this.base.lifecycle;
|
|
449
|
-
|
|
446
|
+
this.subscribe = this.base.subscribe;
|
|
447
|
+
this.wait = this.base.wait;
|
|
448
|
+
this.events = this.base.events;
|
|
450
449
|
}
|
|
451
450
|
process() { return this.base.process(); }
|
|
452
451
|
exists() { return this.base.exists(); }
|
|
@@ -454,7 +453,7 @@ class ServerEndpointHandle extends ServerEndpointBase {
|
|
|
454
453
|
isService() { return this.base.isService(); }
|
|
455
454
|
start(launch) { return this.base.start(launch); }
|
|
456
455
|
stop() { return this.base.stop(); }
|
|
457
|
-
publish(event, payload)
|
|
456
|
+
publish = (event, payload) => this.base.publish(event, payload);
|
|
458
457
|
async ask(event, payload) {
|
|
459
458
|
return await this.askWithin(event, payload, 10_000);
|
|
460
459
|
}
|
|
@@ -465,7 +464,10 @@ class ServerEndpointHandle extends ServerEndpointBase {
|
|
|
465
464
|
return representation(this.system).call("/process/endpoint/ask", this.owner.identity, event, payload, timeout);
|
|
466
465
|
}
|
|
467
466
|
}
|
|
468
|
-
class ClientEndpointHandle extends
|
|
467
|
+
class ClientEndpointHandle extends CoreClientEndpoint {
|
|
468
|
+
subscribe;
|
|
469
|
+
wait;
|
|
470
|
+
events;
|
|
469
471
|
endpoint = "client";
|
|
470
472
|
traffic;
|
|
471
473
|
lifecycle;
|
|
@@ -476,7 +478,9 @@ class ClientEndpointHandle extends ClientEndpointBase {
|
|
|
476
478
|
this.base = new EndpointOperations(system, owner, "client");
|
|
477
479
|
this.traffic = new EndpointTrafficHandle(representation(system), owner.identity, "client", value => endpointFromReference(system, value));
|
|
478
480
|
this.lifecycle = this.base.lifecycle;
|
|
479
|
-
|
|
481
|
+
this.subscribe = this.base.subscribe;
|
|
482
|
+
this.wait = this.base.wait;
|
|
483
|
+
this.events = this.base.events;
|
|
480
484
|
this.window = new SystemWindow(system, owner);
|
|
481
485
|
}
|
|
482
486
|
process() { return this.base.process(); }
|
|
@@ -485,13 +489,13 @@ class ClientEndpointHandle extends ClientEndpointBase {
|
|
|
485
489
|
isService() { return this.base.isService(); }
|
|
486
490
|
start(launch) { return this.base.start(launch); }
|
|
487
491
|
stop() { return this.base.stop(); }
|
|
488
|
-
publish(event, payload)
|
|
492
|
+
publish = (event, payload) => this.base.publish(event, payload);
|
|
489
493
|
}
|
|
490
494
|
class SystemWindow extends Events {
|
|
491
495
|
system;
|
|
492
496
|
process;
|
|
493
497
|
constructor(system, process) {
|
|
494
|
-
super(["move", "resize", "geometry", "minimize", "changeTitle", "front"], (event, subscriber) => {
|
|
498
|
+
super(["move", "resize", "geometry", "minimize", "maximize", "changeTitle", "front"], (event, subscriber) => {
|
|
495
499
|
if (event === null)
|
|
496
500
|
throw new Error("Window events are named");
|
|
497
501
|
return representation(system).on(`window:${process.identity}:${event}`, subscriber);
|
|
@@ -503,13 +507,14 @@ class SystemWindow extends Events {
|
|
|
503
507
|
async position() { return (await this.snapshot()).position; }
|
|
504
508
|
async size() { return (await this.snapshot()).size; }
|
|
505
509
|
async minimized() { return (await this.snapshot()).minimized; }
|
|
510
|
+
async maximized() { return (await this.snapshot()).maximized; }
|
|
506
511
|
async front() { return frontWindow(this.system, this.process); }
|
|
507
512
|
async layer() { return (await this.snapshot()).layer; }
|
|
508
|
-
async location() { return (await this.snapshot()).location; }
|
|
509
513
|
async move(position) { await this.change("move", position); }
|
|
510
514
|
async resize(size) { await this.change("resize", size); }
|
|
511
515
|
async setGeometry(geometry) { await this.change("geometry", geometry); }
|
|
512
516
|
async minimize(minimized = true) { await this.change("minimize", minimized); }
|
|
517
|
+
async maximize(maximized = true) { await this.change("maximize", maximized); }
|
|
513
518
|
async changeTitle(title) { await this.change("change-title", title); }
|
|
514
519
|
async raise() { await this.change("raise"); }
|
|
515
520
|
snapshot() {
|
|
@@ -545,6 +550,9 @@ class ServerServiceHandle extends CoreServerService {
|
|
|
545
550
|
system;
|
|
546
551
|
key;
|
|
547
552
|
lifecycle;
|
|
553
|
+
subscribe;
|
|
554
|
+
wait;
|
|
555
|
+
events;
|
|
548
556
|
base;
|
|
549
557
|
constructor(system, key) {
|
|
550
558
|
super();
|
|
@@ -552,9 +560,12 @@ class ServerServiceHandle extends CoreServerService {
|
|
|
552
560
|
this.key = key;
|
|
553
561
|
this.base = new ServiceBase(system, key);
|
|
554
562
|
this.lifecycle = this.base.lifecycle;
|
|
555
|
-
|
|
563
|
+
const events = new Events([], (event, subscriber, impossible) => representation(system).follow({
|
|
556
564
|
scope: "service", key, kind: "events", event
|
|
557
|
-
}, (_received, payload) => subscriber(payload), impossible))
|
|
565
|
+
}, (_received, payload) => subscriber(payload), impossible));
|
|
566
|
+
this.subscribe = events.subscribe;
|
|
567
|
+
this.wait = events.wait;
|
|
568
|
+
this.events = events.events;
|
|
558
569
|
}
|
|
559
570
|
exists() { return this.base.exists(); }
|
|
560
571
|
waitReady(timeout) { return this.base.waitReady(timeout); }
|
|
@@ -568,14 +579,20 @@ class ServerServiceHandle extends CoreServerService {
|
|
|
568
579
|
}
|
|
569
580
|
class ClientServiceHandle extends CoreClientService {
|
|
570
581
|
lifecycle;
|
|
582
|
+
subscribe;
|
|
583
|
+
wait;
|
|
584
|
+
events;
|
|
571
585
|
base;
|
|
572
586
|
constructor(system, key) {
|
|
573
587
|
super();
|
|
574
588
|
this.base = new ServiceBase(system, key);
|
|
575
589
|
this.lifecycle = this.base.lifecycle;
|
|
576
|
-
|
|
590
|
+
const events = new Events([], (event, subscriber, impossible) => representation(system).follow({
|
|
577
591
|
scope: "service", key, kind: "events", event
|
|
578
|
-
}, (_received, payload) => subscriber(payload), impossible))
|
|
592
|
+
}, (_received, payload) => subscriber(payload), impossible));
|
|
593
|
+
this.subscribe = events.subscribe;
|
|
594
|
+
this.wait = events.wait;
|
|
595
|
+
this.events = events.events;
|
|
579
596
|
}
|
|
580
597
|
exists() { return this.base.exists(); }
|
|
581
598
|
waitReady(timeout) { return this.base.waitReady(timeout); }
|
|
@@ -611,16 +628,6 @@ function programProcessEvent(system, event, values) {
|
|
|
611
628
|
const process = processHandle(system, required(values[0]));
|
|
612
629
|
return event === "exit" ? { process, ...values[1] } : process;
|
|
613
630
|
}
|
|
614
|
-
function bindEvents(target, events) {
|
|
615
|
-
Object.assign(target, eventsOf(events));
|
|
616
|
-
}
|
|
617
|
-
function eventsOf(events) {
|
|
618
|
-
return {
|
|
619
|
-
subscribe: events.subscribe,
|
|
620
|
-
waitFor: events.waitFor,
|
|
621
|
-
events: events.events
|
|
622
|
-
};
|
|
623
|
-
}
|
|
624
631
|
function chronological(left, right) { return left.startedAt.getTime() - right.startedAt.getTime(); }
|
|
625
632
|
async function programStoragePath(system, handle, area) {
|
|
626
633
|
const value = await representation(system).call("/program/area", handle, area, "path", []);
|
|
@@ -629,10 +636,9 @@ async function programStoragePath(system, handle, area) {
|
|
|
629
636
|
return value;
|
|
630
637
|
}
|
|
631
638
|
function endpointFromReference(system, value) {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
}
|
|
639
|
+
if (value === null)
|
|
640
|
+
return null;
|
|
641
|
+
const reference = parseEndpointReference(value);
|
|
636
642
|
const owner = processHandle(system, required(representation(system).processes.get(reference.process.identity), reference.process.identity));
|
|
637
643
|
return reference.kind === "server" ? owner.server : owner.client;
|
|
638
644
|
}
|
package/dist/traffic.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { AnswerSubscriber, AskSubscriber, Cleanup, Endpoint, EventOptions,
|
|
|
2
2
|
import Events from "./events.js";
|
|
3
3
|
import type SystemRepresentation from "./representation.js";
|
|
4
4
|
type Kind = "publish" | "ask" | "answer";
|
|
5
|
-
type ResolveEndpoint = (value: unknown) => Endpoint;
|
|
5
|
+
type ResolveEndpoint = (value: unknown) => Endpoint | null;
|
|
6
6
|
/** Directed traffic originating from one canonical Endpoint. */
|
|
7
7
|
export declare class EndpointTrafficHandle<Definitions extends object = {}> extends Events<TrafficEvents<Definitions>, never> {
|
|
8
8
|
private readonly representation;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phreshos/node",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
4
4
|
"description": "Node.js access to PhreshOS and Program projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -31,9 +31,8 @@
|
|
|
31
31
|
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
32
32
|
"check": "tsc --noEmit && tsc -p tsconfig.test.json",
|
|
33
33
|
"build": "node --run clean && tsc --noEmit false --outDir dist --rootDir source",
|
|
34
|
-
"test": "
|
|
35
|
-
"verify
|
|
36
|
-
"verify": "node --run check && node --run test && node --run verify:package",
|
|
34
|
+
"test": "vitest run --project default",
|
|
35
|
+
"verify": "node --run check && node --run build && node --run test",
|
|
37
36
|
"prepack": "node --run build"
|
|
38
37
|
},
|
|
39
38
|
"dependencies": {
|
|
@@ -43,12 +42,13 @@
|
|
|
43
42
|
"jiti": "^2.7.0"
|
|
44
43
|
},
|
|
45
44
|
"peerDependencies": {
|
|
46
|
-
"@phreshos/core": "^0.1.
|
|
45
|
+
"@phreshos/core": "^0.1.43"
|
|
47
46
|
},
|
|
48
47
|
"devDependencies": {
|
|
49
|
-
"@phreshos/core": "^0.1.
|
|
48
|
+
"@phreshos/core": "^0.1.43",
|
|
50
49
|
"@types/adm-zip": "^0.5.8",
|
|
51
50
|
"@types/node": "^26.2.0",
|
|
52
|
-
"typescript": "^6.0.3"
|
|
51
|
+
"typescript": "^6.0.3",
|
|
52
|
+
"vitest": "^4.1.10"
|
|
53
53
|
}
|
|
54
54
|
}
|