@phreshos/client 0.1.47 → 0.1.49

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.
@@ -1,4 +1,4 @@
1
- import { type Appearance, type AppearanceEvents, type WritableAppearance } from "@phreshos/core";
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 {
@@ -10,8 +10,9 @@ export default class ClientAppearance extends Events<AppearanceEvents, never> im
10
10
  shadow: import("@phreshos/core").ThemedValue<import("@phreshos/core").AppearanceShadow>;
11
11
  material: import("@phreshos/core").ThemedValue<import("@phreshos/core").AppearanceMaterial>;
12
12
  transaction: import("@phreshos/core").AppearanceTransaction;
13
+ taskbar: import("@phreshos/core").AppearanceTaskbar;
13
14
  signInWallpaper: import("@phreshos/core").ThemedValue<string | null>;
14
15
  desktopWallpaper: import("@phreshos/core").ThemedValue<string | null>;
15
16
  }>>;
16
- update(appearance: Appearance): Promise<void>;
17
+ update(appearance: AppearanceUpdate): Promise<void>;
17
18
  }
package/dist/context.js CHANGED
@@ -2,7 +2,7 @@ import Deadline from "./deadline.js";
2
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 { contextPermissions } from "./permissions.js";
5
+ import { programPermissions } from "./permissions.js";
6
6
  class ContextServerHandle extends ServerEndpoint {
7
7
  owner;
8
8
  subscribe;
@@ -96,7 +96,7 @@ class ClientContext extends Events {
96
96
  server = contextServer;
97
97
  window = contextClient.window;
98
98
  presentation = presentation(currentAddress);
99
- permissions = contextPermissions();
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.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, parsePermissions, 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;
@@ -314,7 +321,7 @@ class WindowHandle extends Events {
314
321
  }
315
322
  async title() { return (await this.state()).title; }
316
323
  async header() { return (await this.state()).header; }
317
- async frame() { return (await this.state()).frame; }
324
+ async surface() { return (await this.state()).surface; }
318
325
  async transaction() { return (await this.state()).transaction; }
319
326
  async position() { return (await this.state()).position; }
320
327
  async size() { return (await this.state()).size; }
@@ -329,7 +336,7 @@ class WindowHandle extends Events {
329
336
  async maximize(maximized = true) { await wire.request(["maximize", await this.target(), maximized]); }
330
337
  async setTitle(title) { await wire.request(["setTitle", await this.target(), title]); }
331
338
  async setHeader(header) { await wire.request(["setHeader", await this.target(), header]); }
332
- async setFrame(frame) { await wire.request(["setFrame", await this.target(), frame]); }
339
+ async setSurface(surface) { await wire.request(["setSurface", await this.target(), surface]); }
333
340
  async setTransaction(transaction) { await wire.request(["setTransaction", await this.target(), transaction]); }
334
341
  async raise() { await wire.request(["raise", await this.target()]); }
335
342
  }
@@ -358,7 +365,7 @@ class WindowPresentationHandle extends Events {
358
365
  }
359
366
  async title() { return await this.read("title"); }
360
367
  async header() { return await this.read("header"); }
361
- async frame() { return await this.read("frame"); }
368
+ async surface() { return await this.read("surface"); }
362
369
  async position() { return await this.read("position"); }
363
370
  async size() { return await this.read("size"); }
364
371
  async minimized() { return await this.read("minimized"); }
@@ -372,7 +379,7 @@ class WindowPresentationHandle extends Events {
372
379
  async maximize(maximized = true) { await this.change("windowPresentationMaximize", maximized); }
373
380
  async setTitle(title) { await this.change("windowPresentationTitle", title); }
374
381
  async setHeader(header) { await this.change("windowPresentationHeader", header); }
375
- async setFrame(frame) { await this.change("windowPresentationFrame", frame); }
382
+ async setSurface(surface) { await this.change("windowPresentationSurface", surface); }
376
383
  async follow() { await this.change("windowPresentationFollow"); }
377
384
  async unfollow() { await this.change("windowPresentationUnfollow"); }
378
385
  async raise() { await this.change("windowPresentationRaise"); }
@@ -407,7 +414,7 @@ function deferredScoped(route, target, convert) {
407
414
  ];
408
415
  }
409
416
  function windowEvent(event) {
410
- return event === "move" || event === "resize" || event === "minimize" || event === "maximize" || event === "changeTitle" || event === "changeHeader" || event === "changeFrame" || event === "changeTransaction" || event === "front";
417
+ return event === "move" || event === "resize" || event === "minimize" || event === "maximize" || event === "changeTitle" || event === "changeHeader" || event === "changeSurface" || event === "changeTransaction" || event === "front";
411
418
  }
412
419
  function deferred(target, register, impossible) {
413
420
  let active = true;
@@ -484,6 +491,13 @@ function programEvent(event, values) {
484
491
  return { process: process(values[0]), ...exit(values[1], values[2]) };
485
492
  if (event === "uninstall")
486
493
  return { purge: values[0] === true };
494
+ if (event === "pinned")
495
+ return values[0] === true;
496
+ if (event === "permissions") {
497
+ const record = values[0];
498
+ program(record);
499
+ return parsePermissions(record.permissions);
500
+ }
487
501
  return undefined;
488
502
  }
489
503
  function processEvent(event, values) {
@@ -1,7 +1,5 @@
1
- import type { ContextPermissions, ProgramPermissions } from "@phreshos/core";
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: HandleAddress): ProgramPermissions;
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;
@@ -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(["context-permission-request", identity, name, permission], timeout);
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
- return parsePermission(name, (await wire.request(["context-permission-get", name]))[0]);
27
- },
28
- async allows(name, permission = true) {
29
- return (await wire.request(["context-permission-allows", name, permission]))[0] === true;
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.js CHANGED
@@ -22,11 +22,14 @@ class ServiceHandle {
22
22
  async waitReady(timeout) {
23
23
  await wire.request(["service-wait-ready", this.serviceAddress, timeout], timeout);
24
24
  }
25
- async programMetadata(options = {}) {
26
- const iconSize = options.icon ?? "medium";
27
- const [value] = await wire.request(["service-program-metadata", this.serviceAddress, iconSize]);
25
+ async programMetadata() {
26
+ const [value] = await wire.request(["service-program-metadata", this.serviceAddress]);
28
27
  return parseServiceProgramMetadata(value);
29
28
  }
29
+ async programIcon(size = "medium") {
30
+ const [value] = await wire.request(["service-program-icon", this.serviceAddress, size]);
31
+ return parseServiceProgramIcon(value);
32
+ }
30
33
  }
31
34
  class ServerHandler extends CoreServerService {
32
35
  serviceAddress;
@@ -48,7 +51,8 @@ class ServerHandler extends CoreServerService {
48
51
  publish = (event, payload = undefined) => { this.service.publish(event, payload); };
49
52
  address() { return this.serviceAddress; }
50
53
  available() { return this.service.available(); }
51
- programMetadata(options) { return this.service.programMetadata(options); }
54
+ programMetadata() { return this.service.programMetadata(); }
55
+ programIcon(size) { return this.service.programIcon(size); }
52
56
  waitReady(timeout) { return this.service.waitReady(timeout); }
53
57
  async ask(event, payload = undefined) {
54
58
  return await this.askWithin(new Deadline(), event, payload);
@@ -90,7 +94,8 @@ class ClientHandler extends CoreClientService {
90
94
  publish = (event, payload = undefined) => { this.service.publish(event, payload); };
91
95
  address() { return this.serviceAddress; }
92
96
  available() { return this.service.available(); }
93
- programMetadata(options) { return this.service.programMetadata(options); }
97
+ programMetadata() { return this.service.programMetadata(); }
98
+ programIcon(size) { return this.service.programIcon(size); }
94
99
  waitReady(timeout) { return this.service.waitReady(timeout); }
95
100
  }
96
101
  export function prepareService(address) {
@@ -117,13 +122,14 @@ function parseServiceProgramMetadata(value) {
117
122
  if (!value || typeof value !== "object")
118
123
  throw new Error("The System returned invalid Service Program metadata");
119
124
  const metadata = value;
120
- if (typeof metadata.name !== "string" || typeof metadata.version !== "string"
121
- || !Array.isArray(metadata.icon) || metadata.icon.some(byte => typeof byte !== "number")) {
125
+ if (typeof metadata.name !== "string" || typeof metadata.version !== "string") {
122
126
  throw new Error("The System returned invalid Service Program metadata");
123
127
  }
124
- return Object.freeze({
125
- name: metadata.name,
126
- version: metadata.version,
127
- icon: new Blob([Uint8Array.from(metadata.icon)], { type: "image/png" })
128
- });
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" });
129
135
  }
package/dist/system.js CHANGED
@@ -1,4 +1,4 @@
1
- import { parseShellEvent, parseSessionEndSnapshot, execute as executeRequest } from "@phreshos/core";
1
+ import { parseShellEvent, parseAuthenticationRequirements, parseAuthenticationState, parsePermissions, parseSessionEndSnapshot, execute as executeRequest } from "@phreshos/core";
2
2
  import ClientAppearance from "./appearance.js";
3
3
  import wire from "./wire.js";
4
4
  import { prepareService } from "./service.js";
@@ -13,8 +13,7 @@ class ClientSystem {
13
13
  appearance = new ClientAppearance();
14
14
  program = new SystemProgramHandle();
15
15
  process = new SystemProcessHandle();
16
- connection = new SystemConnectionHandle();
17
- session = new SystemSessionHandle();
16
+ authentication = new SystemAuthenticationHandle();
18
17
  service = new SystemServiceHandle();
19
18
  uploads = uploads;
20
19
  network = network;
@@ -84,37 +83,52 @@ class SystemProcessHandle extends Events {
84
83
  return answer[0] ? process(answer[0]) : null;
85
84
  }
86
85
  }
87
- class SystemConnectionHandle extends Events {
86
+ class SystemAuthenticationHandle extends Events {
88
87
  constructor() {
89
- super((event, listener, impossible) => wire.on("host-connection", event, (...values) => listener(systemConnectionEvent(event, values)), null, impossible), observer => wire.onAll("host-connection", (event, ...values) => {
90
- if (typeof event === "string")
91
- observer(event, systemConnectionEvent(event, values));
92
- }));
93
- }
94
- async list() {
95
- const [snapshots] = await wire.request(["host-connection-list"]);
88
+ super((event, listener, impossible) => {
89
+ const [route, sourceEvent] = authenticationEventRoute(event);
90
+ return wire.on(route, sourceEvent, (...values) => listener(systemAuthenticationEvent(route, sourceEvent, values)), null, impossible);
91
+ }, (observer, impossible) => {
92
+ const stops = ["host-connection", "host-session"].map(route => wire.onAll(route, (event, ...values) => {
93
+ if (typeof event !== "string")
94
+ return;
95
+ const name = authenticationEventName(route, event);
96
+ if (name)
97
+ observer(name, systemAuthenticationEvent(route, event, values));
98
+ }, null, impossible));
99
+ return () => stops.forEach(stop => stop());
100
+ });
101
+ }
102
+ async state() {
103
+ const [value] = await wire.request(["host-authentication-state"]);
104
+ return parseAuthenticationState(value);
105
+ }
106
+ async requirements() {
107
+ const [value] = await wire.request(["host-authentication-requirements"]);
108
+ return parseAuthenticationRequirements(value);
109
+ }
110
+ async connections() {
111
+ const [snapshots] = await wire.request(["host-authentication-connections"]);
96
112
  return snapshots.map(connection);
97
113
  }
98
- async find(identity) {
99
- const [snapshot] = await wire.request(["host-connection-find", identity]);
114
+ async connection(identity) {
115
+ const [snapshot] = await wire.request(["host-authentication-connection", identity]);
100
116
  return snapshot === null ? null : connection(snapshot);
101
117
  }
102
- }
103
- class SystemSessionHandle extends Events {
104
- constructor() {
105
- super((event, listener, impossible) => wire.on("host-session", event, (...values) => listener(systemSessionEvent(event, values)), null, impossible), observer => wire.onAll("host-session", (event, ...values) => {
106
- if (typeof event === "string")
107
- observer(event, systemSessionEvent(event, values));
108
- }));
109
- }
110
- async list() {
111
- const [snapshots] = await wire.request(["host-session-list"]);
118
+ async sessions() {
119
+ const [snapshots] = await wire.request(["host-authentication-sessions"]);
112
120
  return snapshots.map(session);
113
121
  }
114
- async find(identity) {
115
- const [snapshot] = await wire.request(["host-session-find", identity]);
122
+ async session(identity) {
123
+ const [snapshot] = await wire.request(["host-authentication-session", identity]);
116
124
  return snapshot === null ? null : session(snapshot);
117
125
  }
126
+ async setCredentials(credentials) {
127
+ await wire.request(["host-authentication-set-credentials", credentials]);
128
+ }
129
+ async signOutAllSessions() {
130
+ await wire.request(["host-authentication-sign-out-all-sessions"]);
131
+ }
118
132
  }
119
133
  function systemProcessEvent(event, values) {
120
134
  if (event === "create")
@@ -128,12 +142,39 @@ function systemProgramEvent(event, values) {
128
142
  return program(values[1]);
129
143
  if (event === "uninstall")
130
144
  return { program: program(values[1]), purge: values[2] === true };
145
+ if (event === "pinned")
146
+ return { program: program(values[1]), pinned: values[2] === true };
147
+ if (event === "permissions") {
148
+ const handle = program(values[1]);
149
+ return { program: handle, permissions: parsePermissions(values[1].permissions) };
150
+ }
131
151
  return values[0];
132
152
  }
133
- function systemConnectionEvent(_event, values) {
134
- return connection(values[1]);
153
+ function authenticationEventRoute(event) {
154
+ if (event === "connectionCreate")
155
+ return ["host-connection", "create"];
156
+ if (event === "connectionDisconnect")
157
+ return ["host-connection", "disconnect"];
158
+ if (event === "sessionCreate")
159
+ return ["host-session", "create"];
160
+ if (event === "sessionEnd")
161
+ return ["host-session", "end"];
162
+ throw new Error(`The Authentication domain does not expose a ${event} event`);
163
+ }
164
+ function authenticationEventName(route, event) {
165
+ if (route === "host-connection" && event === "create")
166
+ return "connectionCreate";
167
+ if (route === "host-connection" && event === "disconnect")
168
+ return "connectionDisconnect";
169
+ if (route === "host-session" && event === "create")
170
+ return "sessionCreate";
171
+ if (route === "host-session" && event === "end")
172
+ return "sessionEnd";
173
+ return null;
135
174
  }
136
- function systemSessionEvent(event, values) {
175
+ function systemAuthenticationEvent(route, event, values) {
176
+ if (route === "host-connection")
177
+ return connection(values[1]);
137
178
  const handle = session(values[1]);
138
179
  return event === "end" ? { session: handle, reason: parseSessionEndSnapshot({ ...values[1], reason: values[2] }).reason } : handle;
139
180
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phreshos/client",
3
- "version": "0.1.47",
3
+ "version": "0.1.49",
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.55"
49
+ "@phreshos/core": "^0.1.58"
50
50
  },
51
51
  "dependencies": {
52
52
  "@the-link/messagepack": "^0.1.0"
53
53
  },
54
54
  "devDependencies": {
55
- "@phreshos/core": "^0.1.55",
55
+ "@phreshos/core": "^0.1.58",
56
56
  "typescript": "^6.0.3",
57
57
  "vitest": "^4.1.10"
58
58
  }
package/dist/launch.d.ts DELETED
@@ -1,4 +0,0 @@
1
- import { type ProgramLaunch } from "@phreshos/core";
2
- import type { HandleAddress } from "./domain.js";
3
- /** Bind saved launch operations to one Program handle. */
4
- export default function launch(program: HandleAddress): ProgramLaunch;
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
- }