@phreshos/client 0.1.12 → 0.1.14
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 +33 -4
- package/dist/channel.d.ts +2 -2
- package/dist/channel.js +1 -1
- package/dist/current.d.ts +1 -1
- package/dist/current.js +4 -4
- package/dist/domain.d.ts +30 -10
- package/dist/domain.js +68 -27
- package/dist/host.d.ts +13 -13
- package/dist/host.js +2 -4
- package/dist/main.d.ts +2 -2
- package/dist/permissions.d.ts +4 -4
- package/dist/permissions.js +2 -2
- package/dist/service.d.ts +5 -5
- package/dist/service.js +13 -17
- package/dist/theme.js +4 -18
- package/dist/wire.js +1 -1
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -51,11 +51,11 @@ same canonical capability:
|
|
|
51
51
|
```ts
|
|
52
52
|
const program = await current.program()
|
|
53
53
|
|
|
54
|
-
await program.
|
|
55
|
-
await current.
|
|
56
|
-
await current.
|
|
54
|
+
await program.permission.granted("pointer")
|
|
55
|
+
await current.permission.request("pointer")
|
|
56
|
+
await current.permission.timeout(5_000).request("pointer")
|
|
57
57
|
|
|
58
|
-
current.
|
|
58
|
+
current.permission === program.permission
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
`granted()` reads the effective decision without prompting. `request()` asks
|
|
@@ -63,6 +63,20 @@ only when no known decision can answer immediately and returns `null` if its
|
|
|
63
63
|
deadline expires. The desktop remains the internal enforcement boundary, but
|
|
64
64
|
permission ownership does not alter the public shape of `host`.
|
|
65
65
|
|
|
66
|
+
The Client Host exposes only direct, exact Service handles. Creating a handle
|
|
67
|
+
does not read or start the Service and exposes no Service registry:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
const service = host.service({
|
|
71
|
+
program: "counter",
|
|
72
|
+
endpoint: "server",
|
|
73
|
+
name: "state"
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
await service.waitReady()
|
|
77
|
+
if (await service.enabled()) await service.channel.ask("value")
|
|
78
|
+
```
|
|
79
|
+
|
|
66
80
|
A Client may traverse `Process.parent()` through any number of ancestors in
|
|
67
81
|
its own Program. The first parent outside that Program is structurally hidden
|
|
68
82
|
and returned as `null`; no cross-Program Process handle enters the client. If
|
|
@@ -133,6 +147,21 @@ authoritative, subscribable Window capability and its `window.local` physical
|
|
|
133
147
|
representation on this desktop. Local reads and updates have no events and do
|
|
134
148
|
not change Server state. `current.window` is only convenient access to the
|
|
135
149
|
executing Client's canonical Window; it has no additional authority.
|
|
150
|
+
|
|
151
|
+
A Program may converge its Clients on one named Process without a manual
|
|
152
|
+
`find()`/`create()` race:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
const shared = await program.process.findOrCreate({
|
|
156
|
+
name: "shared-server",
|
|
157
|
+
server: true,
|
|
158
|
+
client: false
|
|
159
|
+
})
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
The authoritative Core returns the existing Process only when its normalized
|
|
163
|
+
launch is equivalent; a conflicting launch rejects without changing it.
|
|
164
|
+
|
|
136
165
|
When both dimensions must change, `setGeometry({ position, size })` commits
|
|
137
166
|
them through one authoritative request and produces one `geometry` event.
|
|
138
167
|
Calling `move()` and `resize()` sequentially or through `Promise.all()` remains
|
package/dist/channel.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Channel as CoreChannel, ChannelCapture as CoreChannelCapture, ChannelEvents as CoreChannelEvents, ChannelMessage as CoreChannelMessage
|
|
1
|
+
import type { Channel as CoreChannel, ChannelCapture as CoreChannelCapture, ChannelEvents as CoreChannelEvents, ChannelMessage as CoreChannelMessage } from "@phreshos/core";
|
|
2
2
|
import { type Endpoint } from "./domain.js";
|
|
3
3
|
/** One value addressed to the current Client, with a client-visible sender. */
|
|
4
4
|
export type ChannelMessage<Payload = unknown> = CoreChannelMessage<Payload, Endpoint | null>;
|
|
@@ -7,6 +7,6 @@ export type ChannelEvents<Events extends object> = CoreChannelEvents<Events, End
|
|
|
7
7
|
/** Every event observable through the current Client's Channel. */
|
|
8
8
|
export type ChannelCapture<Events extends object = {}> = CoreChannelCapture<Events, Endpoint | null>;
|
|
9
9
|
/** Events explicitly accepted by the current Client. */
|
|
10
|
-
export interface Channel<Events extends object = {}> extends CoreChannel<Events, Endpoint | null
|
|
10
|
+
export interface Channel<Events extends object = {}> extends CoreChannel<Events, Endpoint | null> {
|
|
11
11
|
}
|
|
12
12
|
export declare const channel: Channel;
|
package/dist/channel.js
CHANGED
|
@@ -12,7 +12,7 @@ class ClientChannel extends Events {
|
|
|
12
12
|
publish(event, payload = undefined) {
|
|
13
13
|
wire.send("end-host", "emit", event, payload);
|
|
14
14
|
}
|
|
15
|
-
async enableService(
|
|
15
|
+
async enableService(name) { await enableCurrentService(name); }
|
|
16
16
|
async disableService() { await disableCurrentService(); }
|
|
17
17
|
}
|
|
18
18
|
function message(value) {
|
package/dist/current.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface Current<Events extends object = {}> extends Channel<Events>, Pi
|
|
|
9
9
|
/** Presentation capability of this current Client. */
|
|
10
10
|
readonly window: Window;
|
|
11
11
|
/** The same permission capability exposed by the current Program. */
|
|
12
|
-
readonly
|
|
12
|
+
readonly permission: Program["permission"];
|
|
13
13
|
/** Returns the Process represented by this Client. */
|
|
14
14
|
process(): Promise<Process>;
|
|
15
15
|
/** Returns the accessible parent Process, or `null` when none exists. */
|
package/dist/current.js
CHANGED
|
@@ -3,7 +3,7 @@ import Deadline from "./deadline.js";
|
|
|
3
3
|
import { Client, Server, ServerTrafficHandle, TrafficHandle, bindEvents, endpointEvents, process, program, window as windowHandle } from "./domain.js";
|
|
4
4
|
import wire from "./wire.js";
|
|
5
5
|
import { endpointService } from "./service.js";
|
|
6
|
-
import {
|
|
6
|
+
import { currentProgramPermission } from "./permissions.js";
|
|
7
7
|
const ServerBase = Server;
|
|
8
8
|
const ClientBase = Client;
|
|
9
9
|
class CurrentServerHandle extends ServerBase {
|
|
@@ -41,7 +41,7 @@ let currentServer;
|
|
|
41
41
|
let currentClient;
|
|
42
42
|
function owner() {
|
|
43
43
|
if (!ownerPromise) {
|
|
44
|
-
const resolving = wire.request(["process"]).then(answer => {
|
|
44
|
+
const resolving = wire.request(["current-process"]).then(answer => {
|
|
45
45
|
return process(answer[0], { server: currentServer, client: currentClient });
|
|
46
46
|
});
|
|
47
47
|
const retained = resolving.catch(error => {
|
|
@@ -84,7 +84,7 @@ currentClient = new CurrentClientHandle(owner);
|
|
|
84
84
|
class ClientCurrent {
|
|
85
85
|
server = currentServer;
|
|
86
86
|
window = currentClient.window;
|
|
87
|
-
|
|
87
|
+
permission = currentProgramPermission;
|
|
88
88
|
constructor() {
|
|
89
89
|
bindChannel(this, channel);
|
|
90
90
|
}
|
|
@@ -94,7 +94,7 @@ class ClientCurrent {
|
|
|
94
94
|
return answer[0] ? process(answer[0]) : null;
|
|
95
95
|
}
|
|
96
96
|
async program() {
|
|
97
|
-
const answer = await wire.request(["program"]);
|
|
97
|
+
const answer = await wire.request(["current-program"]);
|
|
98
98
|
return program(answer[0]);
|
|
99
99
|
}
|
|
100
100
|
async option(name) {
|
package/dist/domain.d.ts
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
|
-
import { Client as CoreClient, Endpoint as CoreEndpoint, Process as CoreProcess, Program as CoreProgram, Server as CoreServer, type AnswerCapture as CoreAnswerCapture, type AnswerMessage as CoreAnswerMessage, type AnswerObserver as CoreAnswerObserver, type AskCapture as CoreAskCapture, type AskMessage as CoreAskMessage, type AskObserver as CoreAskObserver, type Cleanup, type ClientTraffic as CoreClientTraffic, type ClientDeclaration, type EndpointTraffic as CoreEndpointTraffic, type
|
|
1
|
+
import { Client as CoreClient, Endpoint as CoreEndpoint, Process as CoreProcess, Program as CoreProgram, Server as CoreServer, type AnswerCapture as CoreAnswerCapture, type AnswerMessage as CoreAnswerMessage, type AnswerObserver as CoreAnswerObserver, type AskCapture as CoreAskCapture, type AskMessage as CoreAskMessage, type AskObserver as CoreAskObserver, type Cleanup, type ClientTraffic as CoreClientTraffic, type ClientDeclaration, type EndpointTraffic as CoreEndpointTraffic, type Exit, type Launch, type LocalWindow, type Permission, type Position, type ProgramProcess as CoreProgramProcess, type ServerTraffic as CoreServerTraffic, type Size, type TrafficMessage as CoreTrafficMessage, type TrafficCapture as CoreTrafficCapture, type TrafficEvents as CoreTrafficEvents, type Window as CoreWindow, type WindowState } from "@phreshos/core";
|
|
2
2
|
import Events from "./events.js";
|
|
3
3
|
export interface HandleAddress {
|
|
4
4
|
identity: string;
|
|
5
5
|
reference: string;
|
|
6
6
|
}
|
|
7
|
+
export interface EndpointDeclarationRecord {
|
|
8
|
+
start: boolean;
|
|
9
|
+
hasService: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface ClientDeclarationRecord extends EndpointDeclarationRecord {
|
|
12
|
+
title: string | null;
|
|
13
|
+
size: Size | null;
|
|
14
|
+
position: Position | null;
|
|
15
|
+
layer: ClientDeclaration["layer"];
|
|
16
|
+
minimize: boolean | null;
|
|
17
|
+
}
|
|
7
18
|
export interface ProgramRecord {
|
|
8
19
|
reference: string;
|
|
9
20
|
identity: string;
|
|
@@ -11,8 +22,8 @@ export interface ProgramRecord {
|
|
|
11
22
|
name: string;
|
|
12
23
|
version: string | null;
|
|
13
24
|
description: string | null;
|
|
14
|
-
server:
|
|
15
|
-
client:
|
|
25
|
+
server: EndpointDeclarationRecord | null;
|
|
26
|
+
client: ClientDeclarationRecord | null;
|
|
16
27
|
}
|
|
17
28
|
export interface ProcessRecord {
|
|
18
29
|
reference: string;
|
|
@@ -30,19 +41,28 @@ export interface EndpointReference {
|
|
|
30
41
|
}
|
|
31
42
|
export type WindowRecord = WindowState;
|
|
32
43
|
/** Program handle visible inside a structurally isolated Client. */
|
|
33
|
-
export type Program<Events extends object = {}> = Omit<CoreProgram<Events>, "
|
|
44
|
+
export type Program<Events extends object = {}> = Omit<CoreProgram<Events>, "process"> & {
|
|
34
45
|
/** Effective permission decisions owned by this Program. */
|
|
35
|
-
readonly
|
|
46
|
+
readonly permission: Permission;
|
|
47
|
+
/** Operations and lifecycle observation for this Program's Processes. */
|
|
48
|
+
readonly process: ProgramProcess;
|
|
49
|
+
};
|
|
50
|
+
/** Client-visible Process operations scoped to one Program. */
|
|
51
|
+
export type ProgramProcess = Omit<CoreProgramProcess, "list" | "first" | "last" | "find" | "create" | "findOrCreate"> & {
|
|
36
52
|
/** Returns every live Process of this Program visible to the current Client. */
|
|
37
|
-
|
|
53
|
+
list(): Promise<Process[]>;
|
|
38
54
|
/** Returns the earliest-started visible live Process, or `null` when none exist. */
|
|
39
|
-
|
|
55
|
+
first(): Promise<Process | null>;
|
|
40
56
|
/** Returns the latest-started visible live Process, or `null` when none exist. */
|
|
41
|
-
|
|
57
|
+
last(): Promise<Process | null>;
|
|
42
58
|
/** Finds a visible live Process by runtime identity or Program-local name. */
|
|
43
|
-
|
|
59
|
+
find(identityOrName: string): Promise<Process | null>;
|
|
44
60
|
/** Creates one Process of this same Program. */
|
|
45
|
-
|
|
61
|
+
create(launch?: Launch): Promise<Process>;
|
|
62
|
+
/** Finds the named Process or atomically creates it with the same resolved launch. */
|
|
63
|
+
findOrCreate(launch: Launch & Readonly<{
|
|
64
|
+
name: string;
|
|
65
|
+
}>): Promise<Process>;
|
|
46
66
|
};
|
|
47
67
|
/** Process handle visible inside a structurally isolated Client. */
|
|
48
68
|
export type Process<Events extends object = {}> = Omit<CoreProcess<Events>, "server" | "client" | "program" | "parent"> & {
|
package/dist/domain.js
CHANGED
|
@@ -5,7 +5,7 @@ import HandleRegistry from "./handle-registry.js";
|
|
|
5
5
|
import { area, sql, store } from "./storage.js";
|
|
6
6
|
import wire from "./wire.js";
|
|
7
7
|
import { endpointService } from "./service.js";
|
|
8
|
-
import {
|
|
8
|
+
import { currentProgramPermission } from "./permissions.js";
|
|
9
9
|
const handles = new HandleRegistry();
|
|
10
10
|
const ProgramBase = CoreProgram;
|
|
11
11
|
const ProcessBase = CoreProcess;
|
|
@@ -19,43 +19,31 @@ class ProgramHandle extends ProgramBase {
|
|
|
19
19
|
store = store();
|
|
20
20
|
logs = sql("logs");
|
|
21
21
|
database = sql("database");
|
|
22
|
-
|
|
22
|
+
permission = currentProgramPermission;
|
|
23
|
+
process;
|
|
23
24
|
record;
|
|
24
25
|
constructor(record) {
|
|
25
26
|
super();
|
|
26
27
|
this.identity = record.identity;
|
|
27
28
|
this.reference = record.reference;
|
|
28
29
|
this.record = record;
|
|
29
|
-
|
|
30
|
+
this.process = new ProgramProcessHandle(record.reference);
|
|
31
|
+
bindEvents(this, scoped("program-host", record.reference, programEvent));
|
|
30
32
|
}
|
|
31
33
|
get name() { return this.record.name; }
|
|
32
34
|
get version() { return this.record.version; }
|
|
33
35
|
get description() { return this.record.description; }
|
|
34
|
-
get server() {
|
|
35
|
-
|
|
36
|
+
get server() {
|
|
37
|
+
return this.record.server ? declaration("server", this.record.server) : null;
|
|
38
|
+
}
|
|
39
|
+
get client() {
|
|
40
|
+
return this.record.client ? clientDeclaration(this.record.client) : null;
|
|
41
|
+
}
|
|
36
42
|
update(record) {
|
|
37
43
|
if (record.reference !== this.reference)
|
|
38
44
|
throw new Error("A Program handle cannot become another Program");
|
|
39
45
|
this.record = record;
|
|
40
46
|
}
|
|
41
|
-
async processes() {
|
|
42
|
-
const answer = await wire.request(["processes"]);
|
|
43
|
-
return answer[0].map(record => process(record));
|
|
44
|
-
}
|
|
45
|
-
async firstProcess() {
|
|
46
|
-
return chronological(await this.processes())[0] ?? null;
|
|
47
|
-
}
|
|
48
|
-
async lastProcess() {
|
|
49
|
-
return chronological(await this.processes()).at(-1) ?? null;
|
|
50
|
-
}
|
|
51
|
-
async getProcess(identityOrName) {
|
|
52
|
-
const answer = await wire.request(["program-process", undefined, identityOrName]);
|
|
53
|
-
return answer[0] ? process(answer[0]) : null;
|
|
54
|
-
}
|
|
55
|
-
async createProcess(launch = {}) {
|
|
56
|
-
const answer = await wire.request(["create-process", undefined, launch]);
|
|
57
|
-
return process(answer[0]);
|
|
58
|
-
}
|
|
59
47
|
async icon(size = "medium") {
|
|
60
48
|
const answer = await wire.request(["icon", size]);
|
|
61
49
|
return new Blob([Uint8Array.from(answer[0])], { type: "image/png" });
|
|
@@ -66,8 +54,58 @@ class ProgramHandle extends ProgramBase {
|
|
|
66
54
|
}
|
|
67
55
|
async uninstall(everything = false) { await wire.request(["uninstall", undefined, everything]); }
|
|
68
56
|
async forget() { await wire.request(["forget"]); }
|
|
57
|
+
}
|
|
58
|
+
function declaration(endpoint, record) {
|
|
59
|
+
return Object.freeze({
|
|
60
|
+
start: record.start,
|
|
61
|
+
hasService: () => record.hasService,
|
|
62
|
+
docs: () => endpointDocs(endpoint, record.hasService)
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function clientDeclaration(record) {
|
|
66
|
+
return Object.freeze({
|
|
67
|
+
...declaration("client", record),
|
|
68
|
+
title: record.title,
|
|
69
|
+
size: record.size,
|
|
70
|
+
position: record.position,
|
|
71
|
+
layer: record.layer,
|
|
72
|
+
minimize: record.minimize
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
async function endpointDocs(endpoint, declared) {
|
|
76
|
+
if (!declared)
|
|
77
|
+
return null;
|
|
78
|
+
const answer = await wire.request(["endpoint-docs", endpoint]);
|
|
79
|
+
return answer[0];
|
|
80
|
+
}
|
|
81
|
+
class ProgramProcessHandle {
|
|
82
|
+
constructor(program) {
|
|
83
|
+
bindEvents(this, scoped("program-process", program, programProcessEvent));
|
|
84
|
+
}
|
|
85
|
+
async list() {
|
|
86
|
+
const answer = await wire.request(["program-process-list"]);
|
|
87
|
+
return answer[0].map(record => process(record));
|
|
88
|
+
}
|
|
89
|
+
async first() {
|
|
90
|
+
return chronological(await this.list())[0] ?? null;
|
|
91
|
+
}
|
|
92
|
+
async last() {
|
|
93
|
+
return chronological(await this.list()).at(-1) ?? null;
|
|
94
|
+
}
|
|
95
|
+
async find(identityOrName) {
|
|
96
|
+
const answer = await wire.request(["program-process-find", identityOrName]);
|
|
97
|
+
return answer[0] ? process(answer[0]) : null;
|
|
98
|
+
}
|
|
99
|
+
async create(launch = {}) {
|
|
100
|
+
const answer = await wire.request(["program-process-create", launch]);
|
|
101
|
+
return process(answer[0]);
|
|
102
|
+
}
|
|
103
|
+
async findOrCreate(launch) {
|
|
104
|
+
const answer = await wire.request(["program-process-find-or-create", launch]);
|
|
105
|
+
return process(answer[0]);
|
|
106
|
+
}
|
|
69
107
|
async exitAll() {
|
|
70
|
-
const answer = await wire.request(["exit-all"]);
|
|
108
|
+
const answer = await wire.request(["program-process-exit-all"]);
|
|
71
109
|
return answer[0];
|
|
72
110
|
}
|
|
73
111
|
}
|
|
@@ -333,13 +371,16 @@ function unscoped(subject, values) {
|
|
|
333
371
|
return values;
|
|
334
372
|
return values[0] === subject ? values.slice(1) : null;
|
|
335
373
|
}
|
|
336
|
-
function
|
|
374
|
+
function programProcessEvent(event, values) {
|
|
337
375
|
if (event === "endpointStart" || event === "endpointStop")
|
|
338
376
|
return lifecycleEndpoint(values[0], values[1]);
|
|
339
|
-
if (event === "
|
|
377
|
+
if (event === "create")
|
|
340
378
|
return process(values[0]);
|
|
341
|
-
if (event === "
|
|
379
|
+
if (event === "exit")
|
|
342
380
|
return { process: process(values[0]), ...exit(values[1], values[2]) };
|
|
381
|
+
return undefined;
|
|
382
|
+
}
|
|
383
|
+
function programEvent(event, values) {
|
|
343
384
|
if (event === "uninstall")
|
|
344
385
|
return { everythingRemoved: values[0] === true };
|
|
345
386
|
return undefined;
|
package/dist/host.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import type { ClientServiceHandler, ServedFile, ServerServiceHandler, Theme, ThemeProperties } from "@phreshos/core";
|
|
1
|
+
import type { ClientServiceHandler, ServedFile, ServerServiceHandler, ServiceKey, Theme, ThemeProperties } from "@phreshos/core";
|
|
2
2
|
import { type HostPointer } from "./pointer.js";
|
|
3
3
|
import { type HostDesktop } from "./desktop.js";
|
|
4
|
+
type ServiceEndpoint = ServiceKey["endpoint"];
|
|
5
|
+
type ServiceAddress<Endpoint extends ServiceEndpoint> = Omit<ServiceKey, "endpoint"> & Readonly<{
|
|
6
|
+
endpoint: Endpoint;
|
|
7
|
+
}>;
|
|
8
|
+
type ServiceHandle<Endpoint extends ServiceEndpoint, Events extends object> = Endpoint extends "server" ? ServerServiceHandler<Events> : ClientServiceHandler<Events>;
|
|
4
9
|
/** Desktop capabilities structurally available to a Client endpoint. */
|
|
5
10
|
export interface Host {
|
|
6
11
|
/** Read-only system Theme explicitly read from and observed through the desktop host. */
|
|
@@ -13,18 +18,13 @@ export interface Host {
|
|
|
13
18
|
serve(value: unknown): Promise<ServedFile>;
|
|
14
19
|
/** Performs an unrestricted server-side fetch on behalf of this Client. */
|
|
15
20
|
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
16
|
-
/** Returns a stable handle for
|
|
17
|
-
service<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
/** Returns a stable handle for one exact Client service identity. */
|
|
23
|
-
service<ServiceEvents extends object = {}>(key: {
|
|
24
|
-
program: string;
|
|
25
|
-
endpoint: "client";
|
|
26
|
-
name: string;
|
|
27
|
-
}): ClientServiceHandler<ServiceEvents>;
|
|
21
|
+
/** Returns a precisely typed stable handle for either service endpoint. */
|
|
22
|
+
service<Endpoint extends ServiceEndpoint>(key: ServiceAddress<Endpoint>): ServiceHandle<Endpoint, {}>;
|
|
23
|
+
/** Returns a typed stable handle for one exact Server service identity. */
|
|
24
|
+
service<ServiceEvents extends object>(key: ServiceAddress<"server">): ServerServiceHandler<ServiceEvents>;
|
|
25
|
+
/** Returns a typed stable handle for one exact Client service identity. */
|
|
26
|
+
service<ServiceEvents extends object>(key: ServiceAddress<"client">): ClientServiceHandler<ServiceEvents>;
|
|
28
27
|
}
|
|
29
28
|
/** Desktop capabilities available to this Client. */
|
|
30
29
|
export declare const host: Host;
|
|
30
|
+
export {};
|
package/dist/host.js
CHANGED
|
@@ -3,11 +3,12 @@ import ClientTheme from "./theme.js";
|
|
|
3
3
|
import wire from "./wire.js";
|
|
4
4
|
import ClientPointer, {} from "./pointer.js";
|
|
5
5
|
import ClientDesktop, {} from "./desktop.js";
|
|
6
|
-
import {
|
|
6
|
+
import { prepareService } from "./service.js";
|
|
7
7
|
class ClientHost {
|
|
8
8
|
theme = new ClientTheme();
|
|
9
9
|
desktop = new ClientDesktop();
|
|
10
10
|
pointer = new ClientPointer();
|
|
11
|
+
service(key) { return prepareService(key); }
|
|
11
12
|
async serve(value) {
|
|
12
13
|
const source = content(value);
|
|
13
14
|
const channel = new MessageChannel();
|
|
@@ -78,9 +79,6 @@ class ClientHost {
|
|
|
78
79
|
});
|
|
79
80
|
return response;
|
|
80
81
|
}
|
|
81
|
-
service(key) {
|
|
82
|
-
return serviceHandle(key);
|
|
83
|
-
}
|
|
84
82
|
}
|
|
85
83
|
function requestHeaders(normalized, supplied) {
|
|
86
84
|
if (!supplied)
|
package/dist/main.d.ts
CHANGED
|
@@ -4,5 +4,5 @@ export { type DesktopEvents, type DesktopSize, type HostDesktop } from "./deskto
|
|
|
4
4
|
export { current, type Current, type CurrentServer } from "./current.js";
|
|
5
5
|
export { type Channel, type ChannelCapture, type ChannelEvents, type ChannelMessage } from "./channel.js";
|
|
6
6
|
export { ClientServiceHandler, ServerServiceHandler, ServiceHandler, type ClientServiceChannel, type ServerServiceChannel, type ServiceChannel, type ServiceKey, type ServiceLifecycleEvents } from "@phreshos/core";
|
|
7
|
-
export { Client, Endpoint, Process, Program, Server, type Window, type AnswerCapture, type AnswerMessage, type AnswerObserver, type AskCapture, type AskMessage, type AskObserver, type ClientTraffic, type EndpointTraffic, type ServerTraffic, type TrafficCapture, type TrafficEvents, type TrafficMessage } from "./domain.js";
|
|
8
|
-
export type { Askable, Capture, Captures, ClientDeclaration, Cleanup, DirectoryStat, EndpointDeclaration, EntryStat, EventMessage, EventName, EventObserver, EventOptions, EventSubscriber, Exit, FileStat, Launch, LaunchClient, Layer, LogKind, LogRecord, LogSource, Message, OtherStat, Outcome, PermissionDecision,
|
|
7
|
+
export { Client, Endpoint, Process, Program, Server, type Window, type ProgramProcess, type AnswerCapture, type AnswerMessage, type AnswerObserver, type AskCapture, type AskMessage, type AskObserver, type ClientTraffic, type EndpointTraffic, type ServerTraffic, type TrafficCapture, type TrafficEvents, type TrafficMessage } from "./domain.js";
|
|
8
|
+
export type { Askable, Capture, Captures, ClientDeclaration, Cleanup, DirectoryStat, EndpointDeclaration, EntryStat, EventMessage, EventName, EventObserver, EventOptions, EventSubscriber, Exit, FileStat, Launch, LaunchClient, Layer, LogKind, LogRecord, LogSource, Message, OtherStat, Outcome, PermissionDecision, Permission, Position, ProgramArea, ProgramEvents, ProgramProcessEvents, ProgramProcessExit, ProgramSql, ProgramStore, ProcessEvents, Publishable, ServedFile, Size, Subscribable, SubscribableEvents, SubscribableFallback, TimedAskable, TimedPermission, Timeoutable, Theme, ThemeEvents, ThemeProperties, Value, WritableTheme, WindowEvents, WindowGeometry, WindowLayer, WindowState, Easing, LocalWindow, LocalWindowSurface, SurfaceSettings, Transaction } from "@phreshos/core";
|
package/dist/permissions.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { PermissionDecision, PermissionName,
|
|
1
|
+
import type { Permission, PermissionDecision, PermissionName, TimedPermission } from "@phreshos/core";
|
|
2
2
|
/** Client access to the current Program's effective permission decisions. */
|
|
3
|
-
export default class
|
|
3
|
+
export default class ClientPermission implements Permission {
|
|
4
4
|
granted(name: PermissionName): Promise<PermissionDecision>;
|
|
5
5
|
request(name: PermissionName): Promise<PermissionDecision>;
|
|
6
|
-
timeout(milliseconds: number):
|
|
6
|
+
timeout(milliseconds: number): TimedPermission;
|
|
7
7
|
private requestWithin;
|
|
8
8
|
}
|
|
9
9
|
/** The one Program-owned permission capability visible in this isolated Client. */
|
|
10
|
-
export declare const
|
|
10
|
+
export declare const currentProgramPermission: ClientPermission;
|
package/dist/permissions.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import wire from "./wire.js";
|
|
2
2
|
const defaultPermissionTimeout = 30_000;
|
|
3
3
|
/** Client access to the current Program's effective permission decisions. */
|
|
4
|
-
export default class
|
|
4
|
+
export default class ClientPermission {
|
|
5
5
|
async granted(name) {
|
|
6
6
|
const answer = await wire.request(["permission-granted", name]);
|
|
7
7
|
return answer[0];
|
|
@@ -20,4 +20,4 @@ export default class ClientPermissions {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
/** The one Program-owned permission capability visible in this isolated Client. */
|
|
23
|
-
export const
|
|
23
|
+
export const currentProgramPermission = new ClientPermission();
|
package/dist/service.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { type ClientServiceHandler, type ServerServiceHandler, type
|
|
1
|
+
import { type ClientServiceHandler, type ServerServiceHandler, type ServiceHandler, type ServiceKey } from "@phreshos/core";
|
|
2
2
|
import type { HandleAddress } from "./domain.js";
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function prepareService<EventsMap extends object = {}>(key: ServiceKey & {
|
|
4
4
|
endpoint: "server";
|
|
5
5
|
}): ServerServiceHandler<EventsMap>;
|
|
6
|
-
export declare function
|
|
6
|
+
export declare function prepareService<EventsMap extends object = {}>(key: ServiceKey & {
|
|
7
7
|
endpoint: "client";
|
|
8
8
|
}): ClientServiceHandler<EventsMap>;
|
|
9
|
-
export declare function
|
|
10
|
-
export declare function enableCurrentService(
|
|
9
|
+
export declare function prepareService(key: ServiceKey): ServiceHandler;
|
|
10
|
+
export declare function enableCurrentService(name: string): Promise<void>;
|
|
11
11
|
export declare function disableCurrentService(): Promise<void>;
|
|
12
12
|
export declare function endpointService<EventsMap extends object = {}>(target: HandleAddress | null, endpoint: "server"): Promise<ServerServiceHandler<EventsMap> | null>;
|
|
13
13
|
export declare function endpointService<EventsMap extends object = {}>(target: HandleAddress | null, endpoint: "client"): Promise<ClientServiceHandler<EventsMap> | null>;
|
package/dist/service.js
CHANGED
|
@@ -46,47 +46,43 @@ class ClientChannelHandle extends Events {
|
|
|
46
46
|
}
|
|
47
47
|
class ServerHandler extends ServerServiceBase {
|
|
48
48
|
key;
|
|
49
|
-
program;
|
|
50
|
-
endpoint = "server";
|
|
51
49
|
name;
|
|
52
50
|
channel;
|
|
53
51
|
constructor(key) {
|
|
54
52
|
super();
|
|
55
53
|
this.key = key;
|
|
56
|
-
this.program = key.program;
|
|
57
54
|
this.name = key.name;
|
|
58
55
|
this.channel = new ServerChannelHandle(key);
|
|
59
56
|
bindEvents(this, new Events(...serviceEvents(key, "lifecycle")));
|
|
60
57
|
}
|
|
61
|
-
async
|
|
62
|
-
const answer = await wire.request(["service-
|
|
58
|
+
async enabled() {
|
|
59
|
+
const answer = await wire.request(["service-enabled", this.key]);
|
|
63
60
|
return answer[0];
|
|
64
61
|
}
|
|
65
|
-
async
|
|
66
|
-
|
|
67
|
-
return answer[0];
|
|
62
|
+
async waitReady(timeout) {
|
|
63
|
+
await wire.request(["service-wait-ready", this.key, timeout], timeout);
|
|
68
64
|
}
|
|
69
65
|
}
|
|
70
66
|
class ClientHandler extends ClientServiceBase {
|
|
71
67
|
key;
|
|
72
|
-
program;
|
|
73
|
-
endpoint = "client";
|
|
74
68
|
name;
|
|
75
69
|
channel;
|
|
76
70
|
constructor(key) {
|
|
77
71
|
super();
|
|
78
72
|
this.key = key;
|
|
79
|
-
this.program = key.program;
|
|
80
73
|
this.name = key.name;
|
|
81
74
|
this.channel = new ClientChannelHandle(key);
|
|
82
75
|
bindEvents(this, new Events(...serviceEvents(key, "lifecycle")));
|
|
83
76
|
}
|
|
84
|
-
async
|
|
85
|
-
const answer = await wire.request(["service-
|
|
77
|
+
async enabled() {
|
|
78
|
+
const answer = await wire.request(["service-enabled", this.key]);
|
|
86
79
|
return answer[0];
|
|
87
80
|
}
|
|
81
|
+
async waitReady(timeout) {
|
|
82
|
+
await wire.request(["service-wait-ready", this.key, timeout], timeout);
|
|
83
|
+
}
|
|
88
84
|
}
|
|
89
|
-
export function
|
|
85
|
+
export function prepareService(key) {
|
|
90
86
|
if (!isServiceKey(key))
|
|
91
87
|
throw new Error("A complete service key is required");
|
|
92
88
|
const normalized = Object.freeze({ program: key.program, endpoint: key.endpoint, name: key.name });
|
|
@@ -97,15 +93,15 @@ export function service(key) {
|
|
|
97
93
|
: new ClientHandler(normalized);
|
|
98
94
|
});
|
|
99
95
|
}
|
|
100
|
-
export async function enableCurrentService(
|
|
101
|
-
await wire.request(["enable-service",
|
|
96
|
+
export async function enableCurrentService(name) {
|
|
97
|
+
await wire.request(["enable-service", name]);
|
|
102
98
|
}
|
|
103
99
|
export async function disableCurrentService() {
|
|
104
100
|
await wire.request(["disable-service"]);
|
|
105
101
|
}
|
|
106
102
|
export async function endpointService(target, endpoint) {
|
|
107
103
|
const answer = await wire.request(["endpoint-service", target, endpoint]);
|
|
108
|
-
return answer[0] ?
|
|
104
|
+
return answer[0] ? prepareService(answer[0]) : null;
|
|
109
105
|
}
|
|
110
106
|
function serviceEvents(key, scope) {
|
|
111
107
|
return [
|
package/dist/theme.js
CHANGED
|
@@ -5,28 +5,14 @@ import wire from "./wire.js";
|
|
|
5
5
|
export default class ClientTheme extends Events {
|
|
6
6
|
constructor() {
|
|
7
7
|
super((event, listener, impossible) => wire.on("host-theme", event, value => {
|
|
8
|
-
|
|
9
|
-
listener(createThemeSnapshot(value));
|
|
8
|
+
listener(createThemeSnapshot(value));
|
|
10
9
|
}, null, impossible), observer => wire.onAll("host-theme", (event, value) => {
|
|
11
|
-
if (typeof event === "string"
|
|
10
|
+
if (typeof event === "string")
|
|
12
11
|
observer(event, createThemeSnapshot(value));
|
|
13
12
|
}));
|
|
14
13
|
}
|
|
15
14
|
async snapshot() {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
throw new Error("The desktop returned an invalid Theme snapshot");
|
|
19
|
-
return createThemeSnapshot(answer[0]);
|
|
15
|
+
const [theme] = await wire.request(["theme"]);
|
|
16
|
+
return createThemeSnapshot(theme);
|
|
20
17
|
}
|
|
21
18
|
}
|
|
22
|
-
function isObject(value) {
|
|
23
|
-
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
24
|
-
return false;
|
|
25
|
-
const theme = value;
|
|
26
|
-
const surface = theme.surface;
|
|
27
|
-
return typeof theme.background === "string" && typeof theme.foreground === "string" && typeof theme.accent === "string"
|
|
28
|
-
&& typeof theme.spacing === "number" && typeof theme.radius === "number"
|
|
29
|
-
&& typeof surface === "object" && surface !== null
|
|
30
|
-
&& typeof surface.grain === "number" && typeof surface.animation === "number"
|
|
31
|
-
&& typeof surface.backdrop === "number" && typeof surface.opacity === "number";
|
|
32
|
-
}
|
package/dist/wire.js
CHANGED
|
@@ -62,7 +62,7 @@ class Wire {
|
|
|
62
62
|
/** Resolves this endpoint's Process address only for operations that need it. */
|
|
63
63
|
identity() {
|
|
64
64
|
if (!this.identityPromise) {
|
|
65
|
-
const resolving = this.request(["process"]).then(value => {
|
|
65
|
+
const resolving = this.request(["current-process"]).then(value => {
|
|
66
66
|
const [record] = value;
|
|
67
67
|
if (typeof record?.identity !== "string" || typeof record.reference !== "string") {
|
|
68
68
|
throw new Error("The desktop returned an invalid Process identity");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phreshos/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "The SDK used by a Program's client endpoint.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -41,18 +41,19 @@
|
|
|
41
41
|
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
42
42
|
"check": "tsc --noEmit",
|
|
43
43
|
"build": "node --run clean && tsc --noEmit false --outDir dist --rootDir source",
|
|
44
|
+
"verify:completions": "node scripts/verify-completions.mjs",
|
|
44
45
|
"verify:package": "node scripts/verify-package.mjs",
|
|
45
|
-
"verify": "node --run check && node --run build && node --run verify:package",
|
|
46
|
+
"verify": "node --run check && node --run verify:completions && node --run build && node --run verify:package",
|
|
46
47
|
"prepack": "node --run build"
|
|
47
48
|
},
|
|
48
49
|
"peerDependencies": {
|
|
49
|
-
"@phreshos/core": "^0.1.
|
|
50
|
+
"@phreshos/core": "^0.1.11"
|
|
50
51
|
},
|
|
51
52
|
"dependencies": {
|
|
52
53
|
"@msgpack/msgpack": "^3.1.3"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
|
-
"@phreshos/core": "^0.1.
|
|
56
|
+
"@phreshos/core": "^0.1.11",
|
|
56
57
|
"typescript": "^6.0.3"
|
|
57
58
|
}
|
|
58
59
|
}
|