@phreshos/client 0.1.46 → 0.1.48
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/appearance.d.ts +2 -2
- package/dist/context.js +10 -10
- package/dist/domain.d.ts +2 -2
- package/dist/domain.js +78 -44
- package/dist/permissions.d.ts +2 -4
- package/dist/permissions.js +6 -17
- package/dist/service.d.ts +4 -8
- package/dist/service.js +62 -34
- package/dist/system.js +20 -1
- package/dist/wire.d.ts +2 -2
- package/dist/wire.js +2 -2
- package/package.json +3 -3
- package/dist/launch.d.ts +0 -4
- package/dist/launch.js +0 -14
package/dist/appearance.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type AppearanceEvents, type AppearanceUpdate, type WritableAppearance } from "@phreshos/core";
|
|
2
2
|
import Events from "./events.js";
|
|
3
3
|
/** Read-only System Appearance reached through the Desktop boundary. */
|
|
4
4
|
export default class ClientAppearance extends Events<AppearanceEvents, never> implements WritableAppearance {
|
|
@@ -13,5 +13,5 @@ export default class ClientAppearance extends Events<AppearanceEvents, never> im
|
|
|
13
13
|
signInWallpaper: import("@phreshos/core").ThemedValue<string | null>;
|
|
14
14
|
desktopWallpaper: import("@phreshos/core").ThemedValue<string | null>;
|
|
15
15
|
}>>;
|
|
16
|
-
update(appearance:
|
|
16
|
+
update(appearance: AppearanceUpdate): Promise<void>;
|
|
17
17
|
}
|
package/dist/context.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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
|
-
import {
|
|
5
|
+
import { programPermissions } from "./permissions.js";
|
|
6
6
|
class ContextServerHandle extends ServerEndpoint {
|
|
7
7
|
owner;
|
|
8
8
|
subscribe;
|
|
@@ -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,8 +95,8 @@ contextClient = new ContextClientHandle(owner);
|
|
|
95
95
|
class ClientContext extends Events {
|
|
96
96
|
server = contextServer;
|
|
97
97
|
window = contextClient.window;
|
|
98
|
-
|
|
99
|
-
permissions =
|
|
98
|
+
presentation = presentation(currentAddress);
|
|
99
|
+
permissions = programPermissions();
|
|
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) => {
|
|
102
102
|
if (typeof event === "string")
|
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,10 +1,9 @@
|
|
|
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, parseProgramDefinition, 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";
|
|
5
5
|
import { area, sql, store } from "./storage.js";
|
|
6
6
|
import startup from "./startup.js";
|
|
7
|
-
import launch from "./launch.js";
|
|
8
7
|
import { programPermissions } from "./permissions.js";
|
|
9
8
|
import wire from "./wire.js";
|
|
10
9
|
const handles = new HandleRegistry();
|
|
@@ -20,7 +19,6 @@ class ProgramHandle extends CoreProgram {
|
|
|
20
19
|
logs;
|
|
21
20
|
database;
|
|
22
21
|
startup;
|
|
23
|
-
launch;
|
|
24
22
|
permissions;
|
|
25
23
|
record;
|
|
26
24
|
constructor(record) {
|
|
@@ -34,7 +32,6 @@ class ProgramHandle extends CoreProgram {
|
|
|
34
32
|
this.logs = sql("logs", this.address);
|
|
35
33
|
this.database = sql("database", this.address);
|
|
36
34
|
this.startup = startup(this.address);
|
|
37
|
-
this.launch = launch(this.address);
|
|
38
35
|
this.permissions = programPermissions(this.address);
|
|
39
36
|
const events = scoped("program-host", record.reference, programEvent);
|
|
40
37
|
this.subscribe = events.subscribe;
|
|
@@ -58,6 +55,16 @@ class ProgramHandle extends CoreProgram {
|
|
|
58
55
|
const answer = await wire.request(["icon", this.address, size]);
|
|
59
56
|
return new Blob([Uint8Array.from(answer[0])], { type: "image/png" });
|
|
60
57
|
}
|
|
58
|
+
async definition() {
|
|
59
|
+
const answer = await wire.request(["program-definition", this.address]);
|
|
60
|
+
return parseProgramDefinition(answer[0]);
|
|
61
|
+
}
|
|
62
|
+
async pinned() {
|
|
63
|
+
const answer = await wire.request(["pinned", this.address, "get"]);
|
|
64
|
+
return answer[0];
|
|
65
|
+
}
|
|
66
|
+
async pin() { await wire.request(["pinned", this.address, "pin"]); }
|
|
67
|
+
async unpin() { await wire.request(["pinned", this.address, "unpin"]); }
|
|
61
68
|
async agent() {
|
|
62
69
|
if (!this.hasAgent)
|
|
63
70
|
return null;
|
|
@@ -236,12 +243,12 @@ class ServerEndpointHandle extends CoreServerEndpoint {
|
|
|
236
243
|
this.wait = events.wait;
|
|
237
244
|
this.events = events.events;
|
|
238
245
|
}
|
|
239
|
-
async process() { return this.owner; }
|
|
246
|
+
async process() { await this.running(); return this.owner; }
|
|
240
247
|
publish = (event, payload = undefined) => {
|
|
241
248
|
wire.send("end-host", "send", this.owner.address, "server", event, payload);
|
|
242
249
|
};
|
|
243
|
-
async
|
|
244
|
-
const answer = await wire.request(["
|
|
250
|
+
async running() {
|
|
251
|
+
const answer = await wire.request(["running", "server", this.owner.address]);
|
|
245
252
|
return answer[0];
|
|
246
253
|
}
|
|
247
254
|
async start(launch = {}) { await wire.request(["start-endpoint", this.owner.address, "server", launch]); }
|
|
@@ -289,12 +296,12 @@ class ClientEndpointHandle extends CoreClientEndpoint {
|
|
|
289
296
|
this.wait = events.wait;
|
|
290
297
|
this.events = events.events;
|
|
291
298
|
}
|
|
292
|
-
async process() { return this.owner; }
|
|
299
|
+
async process() { await this.running(); return this.owner; }
|
|
293
300
|
publish = (event, payload = undefined) => {
|
|
294
301
|
wire.send("end-host", "send", this.owner.address, "client", event, payload);
|
|
295
302
|
};
|
|
296
|
-
async
|
|
297
|
-
const answer = await wire.request(["
|
|
303
|
+
async running() {
|
|
304
|
+
const answer = await wire.request(["running", "client", this.owner.address]);
|
|
298
305
|
return answer[0];
|
|
299
306
|
}
|
|
300
307
|
async start(launch = {}) { await wire.request(["start-endpoint", this.owner.address, "client", launch]); }
|
|
@@ -314,6 +321,8 @@ class WindowHandle extends Events {
|
|
|
314
321
|
}
|
|
315
322
|
async title() { return (await this.state()).title; }
|
|
316
323
|
async header() { return (await this.state()).header; }
|
|
324
|
+
async frame() { return (await this.state()).frame; }
|
|
325
|
+
async transaction() { return (await this.state()).transaction; }
|
|
317
326
|
async position() { return (await this.state()).position; }
|
|
318
327
|
async size() { return (await this.state()).size; }
|
|
319
328
|
async minimized() { return (await this.state()).minimized; }
|
|
@@ -325,40 +334,61 @@ class WindowHandle extends Events {
|
|
|
325
334
|
async setGeometry(geometry) { await wire.request(["setGeometry", await this.target(), geometry]); }
|
|
326
335
|
async minimize(minimized = true) { await wire.request(["minimize", await this.target(), minimized]); }
|
|
327
336
|
async maximize(maximized = true) { await wire.request(["maximize", await this.target(), maximized]); }
|
|
328
|
-
async
|
|
329
|
-
async
|
|
337
|
+
async setTitle(title) { await wire.request(["setTitle", await this.target(), title]); }
|
|
338
|
+
async setHeader(header) { await wire.request(["setHeader", await this.target(), header]); }
|
|
339
|
+
async setFrame(frame) { await wire.request(["setFrame", await this.target(), frame]); }
|
|
340
|
+
async setTransaction(transaction) { await wire.request(["setTransaction", await this.target(), transaction]); }
|
|
330
341
|
async raise() { await wire.request(["raise", await this.target()]); }
|
|
331
342
|
}
|
|
332
|
-
|
|
333
|
-
class LocalWindowHandle {
|
|
343
|
+
class WindowPresentationHandle extends Events {
|
|
334
344
|
target;
|
|
335
345
|
selected;
|
|
336
346
|
constructor(target, selected) {
|
|
347
|
+
super((event, listener, impossible) => {
|
|
348
|
+
if (!windowEvent(event)) {
|
|
349
|
+
impossible?.(new Error(`A Window presentation has no "${event}" event`));
|
|
350
|
+
return () => undefined;
|
|
351
|
+
}
|
|
352
|
+
return wire.on("presentation", event, listener, null, impossible);
|
|
353
|
+
}, (listener, impossible) => wire.onAll("presentation", (event, ...values) => {
|
|
354
|
+
if (typeof event === "string")
|
|
355
|
+
listener(event, values[0]);
|
|
356
|
+
}, null, impossible));
|
|
337
357
|
this.target = target;
|
|
338
358
|
this.selected = selected;
|
|
339
359
|
}
|
|
340
360
|
transaction(transaction) {
|
|
341
|
-
return new
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
async
|
|
347
|
-
async
|
|
348
|
-
async
|
|
349
|
-
async
|
|
350
|
-
async
|
|
351
|
-
async
|
|
352
|
-
async
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
}
|
|
358
|
-
async
|
|
359
|
-
async
|
|
361
|
+
return new WindowPresentationHandle(this.target, { transaction, wait: false });
|
|
362
|
+
}
|
|
363
|
+
transactionAndWait(transaction) {
|
|
364
|
+
return new WindowPresentationHandle(this.target, { transaction, wait: true });
|
|
365
|
+
}
|
|
366
|
+
async title() { return await this.read("title"); }
|
|
367
|
+
async header() { return await this.read("header"); }
|
|
368
|
+
async frame() { return await this.read("frame"); }
|
|
369
|
+
async position() { return await this.read("position"); }
|
|
370
|
+
async size() { return await this.read("size"); }
|
|
371
|
+
async minimized() { return await this.read("minimized"); }
|
|
372
|
+
async maximized() { return await this.read("maximized"); }
|
|
373
|
+
async front() { return await this.read("front"); }
|
|
374
|
+
async layer() { return await this.read("layer"); }
|
|
375
|
+
async move(position) { await this.change("windowPresentationMove", position); }
|
|
376
|
+
async resize(size) { await this.change("windowPresentationResize", size); }
|
|
377
|
+
async setGeometry(geometry) { await this.change("windowPresentationGeometry", geometry); }
|
|
378
|
+
async minimize(minimized = true) { await this.change("windowPresentationMinimize", minimized); }
|
|
379
|
+
async maximize(maximized = true) { await this.change("windowPresentationMaximize", maximized); }
|
|
380
|
+
async setTitle(title) { await this.change("windowPresentationTitle", title); }
|
|
381
|
+
async setHeader(header) { await this.change("windowPresentationHeader", header); }
|
|
382
|
+
async setFrame(frame) { await this.change("windowPresentationFrame", frame); }
|
|
383
|
+
async follow() { await this.change("windowPresentationFollow"); }
|
|
384
|
+
async unfollow() { await this.change("windowPresentationUnfollow"); }
|
|
385
|
+
async raise() { await this.change("windowPresentationRaise"); }
|
|
360
386
|
async change(operation, value) {
|
|
361
|
-
await wire.request([operation, await this.target(), value, this.selected]);
|
|
387
|
+
await wire.request([operation, await this.target(), value, this.selected?.transaction, this.selected?.wait === true]);
|
|
388
|
+
}
|
|
389
|
+
async read(property) {
|
|
390
|
+
const answer = await wire.request(["windowPresentationRead", await this.target(), property]);
|
|
391
|
+
return answer[0];
|
|
362
392
|
}
|
|
363
393
|
}
|
|
364
394
|
function deferredScoped(route, target, convert) {
|
|
@@ -384,7 +414,7 @@ function deferredScoped(route, target, convert) {
|
|
|
384
414
|
];
|
|
385
415
|
}
|
|
386
416
|
function windowEvent(event) {
|
|
387
|
-
return event === "move" || event === "resize" || event === "
|
|
417
|
+
return event === "move" || event === "resize" || event === "minimize" || event === "maximize" || event === "changeTitle" || event === "changeHeader" || event === "changeFrame" || event === "changeTransaction" || event === "front";
|
|
388
418
|
}
|
|
389
419
|
function deferred(target, register, impossible) {
|
|
390
420
|
let active = true;
|
|
@@ -396,8 +426,6 @@ function deferred(target, register, impossible) {
|
|
|
396
426
|
const failure = error instanceof Error ? error : new Error(String(error));
|
|
397
427
|
if (active && impossible)
|
|
398
428
|
impossible(failure);
|
|
399
|
-
else if (active)
|
|
400
|
-
queueMicrotask(() => { throw failure; });
|
|
401
429
|
});
|
|
402
430
|
return () => {
|
|
403
431
|
active = false;
|
|
@@ -426,11 +454,17 @@ export function endpointEvents(target, half) {
|
|
|
426
454
|
}
|
|
427
455
|
/** Start and stop transitions belonging directly to one permanent Endpoint. */
|
|
428
456
|
export function endpointLifecycle(target, half) {
|
|
429
|
-
|
|
457
|
+
const resolved = () => target();
|
|
458
|
+
const viable = async () => {
|
|
459
|
+
const address = await resolved();
|
|
460
|
+
await wire.request(["running", half, address]);
|
|
461
|
+
return address;
|
|
462
|
+
};
|
|
463
|
+
return new Events((event, listener, impossible) => deferred(impossible ? viable : resolved, subject => wire.on("process-host", endpointLifecycleEvent(event), (...values) => {
|
|
430
464
|
const message = unscoped(subject, values);
|
|
431
465
|
if (message?.[1] === half)
|
|
432
466
|
listener(undefined);
|
|
433
|
-
}, subject, impossible), impossible), (listener, impossible) => deferred(
|
|
467
|
+
}, subject, impossible), impossible), (listener, impossible) => deferred(impossible ? viable : resolved, subject => wire.onAll("process-host", (event, ...values) => {
|
|
434
468
|
if (event !== "endpointStart" && event !== "endpointStop")
|
|
435
469
|
return;
|
|
436
470
|
const message = unscoped(subject, values);
|
|
@@ -457,6 +491,8 @@ function programEvent(event, values) {
|
|
|
457
491
|
return { process: process(values[0]), ...exit(values[1], values[2]) };
|
|
458
492
|
if (event === "uninstall")
|
|
459
493
|
return { purge: values[0] === true };
|
|
494
|
+
if (event === "pinned")
|
|
495
|
+
return values[0] === true;
|
|
460
496
|
return undefined;
|
|
461
497
|
}
|
|
462
498
|
function processEvent(event, values) {
|
|
@@ -496,12 +532,10 @@ function endpointHandle(owner, kind, preferred) {
|
|
|
496
532
|
return handles.obtain(`endpoint:${owner.reference}:${kind}`, () => preferred ?? (kind === "server" ? new ServerEndpointHandle(owner) : new ClientEndpointHandle(owner)));
|
|
497
533
|
}
|
|
498
534
|
export function window(target) {
|
|
499
|
-
|
|
500
|
-
windowTargets.set(handle, target);
|
|
501
|
-
return handle;
|
|
535
|
+
return new WindowHandle(target);
|
|
502
536
|
}
|
|
503
|
-
export function
|
|
504
|
-
return new
|
|
537
|
+
export function presentation(target) {
|
|
538
|
+
return new WindowPresentationHandle(target);
|
|
505
539
|
}
|
|
506
540
|
/** Resolves an Endpoint reference through the Client Endpoint's global handle registry. */
|
|
507
541
|
export function visibleEndpoint(reference) {
|
package/dist/permissions.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ProgramPermissions } from "@phreshos/core";
|
|
2
2
|
import type { HandleAddress } from "./domain.js";
|
|
3
3
|
export declare const defaultPermissionTimeout = 120000;
|
|
4
4
|
/** Bind authoritative permission state to one exact Program handle. */
|
|
5
|
-
export declare function programPermissions(program
|
|
6
|
-
/** Permission state and owner requests belonging to the current Client Endpoint. */
|
|
7
|
-
export declare function contextPermissions(): ContextPermissions;
|
|
5
|
+
export declare function programPermissions(program?: HandleAddress): ProgramPermissions;
|
package/dist/permissions.js
CHANGED
|
@@ -4,30 +4,19 @@ export const defaultPermissionTimeout = 120_000;
|
|
|
4
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
|
-
return {
|
|
8
|
-
async get(name) { return parsePermission(name, (await operate("get", name))[0]); },
|
|
9
|
-
async all() { return parsePermissions((await operate("all"))[0]); },
|
|
10
|
-
async allows(name, permission = true) { return (await operate("allows", name, permission))[0] === true; },
|
|
11
|
-
async set(name, permission) { await operate("set", name, permission); },
|
|
12
|
-
async delete(name) { await operate("delete", name); }
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
/** Permission state and owner requests belonging to the current Client Endpoint. */
|
|
16
|
-
export function contextPermissions() {
|
|
17
7
|
const timed = (timeout) => ({
|
|
18
8
|
async request(name, permission = true) {
|
|
19
9
|
const identity = crypto.randomUUID();
|
|
20
|
-
const result = await wire.requestOrNull(["
|
|
10
|
+
const result = await wire.requestOrNull(["program-permissions", program, "request", identity, name, permission], timeout);
|
|
21
11
|
return result === null ? null : parsePermission(name, result[0]);
|
|
22
12
|
}
|
|
23
13
|
});
|
|
24
14
|
return {
|
|
25
|
-
async get(name) {
|
|
26
|
-
|
|
27
|
-
},
|
|
28
|
-
async
|
|
29
|
-
|
|
30
|
-
},
|
|
15
|
+
async get(name) { return parsePermission(name, (await operate("get", name))[0]); },
|
|
16
|
+
async all() { return parsePermissions((await operate("all"))[0]); },
|
|
17
|
+
async allows(name, permission = true) { return (await operate("allows", name, permission))[0] === true; },
|
|
18
|
+
async allow(name, permission = true) { await operate("allow", name, permission); },
|
|
19
|
+
async deny(name) { await operate("deny", name); },
|
|
31
20
|
request: timed(defaultPermissionTimeout).request,
|
|
32
21
|
timeout(milliseconds) {
|
|
33
22
|
if (!Number.isFinite(milliseconds) || milliseconds < 0)
|
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,58 @@
|
|
|
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() {
|
|
26
|
+
const [value] = await wire.request(["service-program-metadata", this.serviceAddress]);
|
|
27
|
+
return parseServiceProgramMetadata(value);
|
|
28
|
+
}
|
|
29
|
+
async programIcon(size = "medium") {
|
|
30
|
+
const [value] = await wire.request(["service-program-icon", this.serviceAddress, size]);
|
|
31
|
+
return parseServiceProgramIcon(value);
|
|
23
32
|
}
|
|
24
33
|
}
|
|
25
34
|
class ServerHandler extends CoreServerService {
|
|
26
|
-
|
|
35
|
+
serviceAddress;
|
|
27
36
|
subscribe;
|
|
28
37
|
wait;
|
|
29
38
|
events;
|
|
30
39
|
lifecycle;
|
|
31
40
|
service;
|
|
32
|
-
constructor(
|
|
41
|
+
constructor(serviceAddress) {
|
|
33
42
|
super();
|
|
34
|
-
this.
|
|
35
|
-
this.service = new ServiceHandle(
|
|
43
|
+
this.serviceAddress = serviceAddress;
|
|
44
|
+
this.service = new ServiceHandle(serviceAddress);
|
|
36
45
|
this.lifecycle = this.service.lifecycle;
|
|
37
|
-
const events = new Events(...serviceEvents(
|
|
46
|
+
const events = new Events(...serviceEvents(serviceAddress, "events"));
|
|
38
47
|
this.subscribe = events.subscribe;
|
|
39
48
|
this.wait = events.wait;
|
|
40
49
|
this.events = events.events;
|
|
41
50
|
}
|
|
42
51
|
publish = (event, payload = undefined) => { this.service.publish(event, payload); };
|
|
43
|
-
|
|
52
|
+
address() { return this.serviceAddress; }
|
|
53
|
+
available() { return this.service.available(); }
|
|
54
|
+
programMetadata() { return this.service.programMetadata(); }
|
|
55
|
+
programIcon(size) { return this.service.programIcon(size); }
|
|
44
56
|
waitReady(timeout) { return this.service.waitReady(timeout); }
|
|
45
57
|
async ask(event, payload = undefined) {
|
|
46
58
|
return await this.askWithin(new Deadline(), event, payload);
|
|
@@ -53,7 +65,7 @@ class ServerHandler extends CoreServerService {
|
|
|
53
65
|
const address = `client:${identity.process}:${crypto.randomUUID()}`;
|
|
54
66
|
const question = crypto.randomUUID();
|
|
55
67
|
const waiting = wire.expectWithin(address, deadline);
|
|
56
|
-
wire.send("end-host", "service-ask", this.
|
|
68
|
+
wire.send("end-host", "service-ask", this.serviceAddress, address, question, event, payload);
|
|
57
69
|
try {
|
|
58
70
|
return await waiting;
|
|
59
71
|
}
|
|
@@ -63,45 +75,61 @@ class ServerHandler extends CoreServerService {
|
|
|
63
75
|
}
|
|
64
76
|
}
|
|
65
77
|
class ClientHandler extends CoreClientService {
|
|
78
|
+
serviceAddress;
|
|
66
79
|
subscribe;
|
|
67
80
|
wait;
|
|
68
81
|
events;
|
|
69
82
|
lifecycle;
|
|
70
83
|
service;
|
|
71
|
-
constructor(
|
|
84
|
+
constructor(serviceAddress) {
|
|
72
85
|
super();
|
|
73
|
-
this.
|
|
86
|
+
this.serviceAddress = serviceAddress;
|
|
87
|
+
this.service = new ServiceHandle(serviceAddress);
|
|
74
88
|
this.lifecycle = this.service.lifecycle;
|
|
75
|
-
const events = new Events(...serviceEvents(
|
|
89
|
+
const events = new Events(...serviceEvents(serviceAddress, "events"));
|
|
76
90
|
this.subscribe = events.subscribe;
|
|
77
91
|
this.wait = events.wait;
|
|
78
92
|
this.events = events.events;
|
|
79
93
|
}
|
|
80
94
|
publish = (event, payload = undefined) => { this.service.publish(event, payload); };
|
|
81
|
-
|
|
95
|
+
address() { return this.serviceAddress; }
|
|
96
|
+
available() { return this.service.available(); }
|
|
97
|
+
programMetadata() { return this.service.programMetadata(); }
|
|
98
|
+
programIcon(size) { return this.service.programIcon(size); }
|
|
82
99
|
waitReady(timeout) { return this.service.waitReady(timeout); }
|
|
83
100
|
}
|
|
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" });
|
|
101
|
+
export function prepareService(address) {
|
|
102
|
+
if (!isServiceAddress(address))
|
|
103
|
+
throw new Error("A complete Service address is required");
|
|
104
|
+
const identity = JSON.stringify([address.program, address.process, address.endpoint]);
|
|
105
|
+
if (address.endpoint === "server") {
|
|
106
|
+
const normalized = Object.freeze({ program: address.program, process: address.process, endpoint: "server" });
|
|
94
107
|
return handles.obtain(`service:${identity}`, () => new ServerHandler(normalized));
|
|
95
108
|
}
|
|
96
|
-
const normalized = Object.freeze({
|
|
109
|
+
const normalized = Object.freeze({ program: address.program, process: address.process, endpoint: "client" });
|
|
97
110
|
return handles.obtain(`service:${identity}`, () => new ClientHandler(normalized));
|
|
98
111
|
}
|
|
99
|
-
function serviceEvents(
|
|
112
|
+
function serviceEvents(address, scope) {
|
|
100
113
|
return [
|
|
101
|
-
(event, listener, impossible) => wire.followService(
|
|
102
|
-
(listener, impossible) => wire.followService(
|
|
114
|
+
(event, listener, impossible) => wire.followService(address, scope, event, listener, impossible),
|
|
115
|
+
(listener, impossible) => wire.followService(address, scope, null, (event, payload) => {
|
|
103
116
|
if (typeof event === "string")
|
|
104
117
|
listener(event, payload);
|
|
105
118
|
}, impossible)
|
|
106
119
|
];
|
|
107
120
|
}
|
|
121
|
+
function parseServiceProgramMetadata(value) {
|
|
122
|
+
if (!value || typeof value !== "object")
|
|
123
|
+
throw new Error("The System returned invalid Service Program metadata");
|
|
124
|
+
const metadata = value;
|
|
125
|
+
if (typeof metadata.name !== "string" || typeof metadata.version !== "string") {
|
|
126
|
+
throw new Error("The System returned invalid Service Program metadata");
|
|
127
|
+
}
|
|
128
|
+
return Object.freeze({ name: metadata.name, version: metadata.version });
|
|
129
|
+
}
|
|
130
|
+
function parseServiceProgramIcon(value) {
|
|
131
|
+
if (!Array.isArray(value) || value.some(byte => typeof byte !== "number")) {
|
|
132
|
+
throw new Error("The System returned an invalid Service Program icon");
|
|
133
|
+
}
|
|
134
|
+
return new Blob([Uint8Array.from(value)], { type: "image/png" });
|
|
135
|
+
}
|
package/dist/system.js
CHANGED
|
@@ -15,18 +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) {
|
|
21
22
|
return executeRequest(this, request);
|
|
22
23
|
}
|
|
23
|
-
service(key) { return prepareService(key); }
|
|
24
24
|
async *shell(command, options = {}) {
|
|
25
25
|
const { signal, ...settings } = options;
|
|
26
26
|
for await (const event of wire.stream(["shell", command, settings], undefined, signal))
|
|
27
27
|
yield parseShellEvent(event);
|
|
28
28
|
}
|
|
29
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
|
+
}
|
|
30
47
|
class SystemProgramHandle extends Events {
|
|
31
48
|
constructor() {
|
|
32
49
|
super((event, listener, impossible) => wire.on("host-program", event, (...values) => listener(systemProgramEvent(event, values)), null, impossible), observer => wire.onAll("host-program", (event, ...values) => {
|
|
@@ -111,6 +128,8 @@ function systemProgramEvent(event, values) {
|
|
|
111
128
|
return program(values[1]);
|
|
112
129
|
if (event === "uninstall")
|
|
113
130
|
return { program: program(values[1]), purge: values[2] === true };
|
|
131
|
+
if (event === "pinned")
|
|
132
|
+
return { program: program(values[1]), pinned: values[2] === true };
|
|
114
133
|
return values[0];
|
|
115
134
|
}
|
|
116
135
|
function systemConnectionEvent(_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.48",
|
|
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.56"
|
|
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.56",
|
|
56
56
|
"typescript": "^6.0.3",
|
|
57
57
|
"vitest": "^4.1.10"
|
|
58
58
|
}
|
package/dist/launch.d.ts
DELETED
package/dist/launch.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { parseLaunch } from "@phreshos/core";
|
|
2
|
-
import wire from "./wire.js";
|
|
3
|
-
/** Bind saved launch operations to one Program handle. */
|
|
4
|
-
export default function launch(program) {
|
|
5
|
-
return {
|
|
6
|
-
async get() {
|
|
7
|
-
const [value] = await wire.request(["launch", program, "get"]);
|
|
8
|
-
return value === null ? null : parseLaunch(value);
|
|
9
|
-
},
|
|
10
|
-
async set(value) {
|
|
11
|
-
await wire.request(["launch", program, "set", parseLaunch(value)]);
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
}
|