@phreshos/client 0.1.20 → 0.1.22
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 +5 -1
- package/dist/controlled-stream.d.ts +2 -0
- package/dist/controlled-stream.js +26 -0
- package/dist/main.d.ts +1 -1
- package/dist/storage.js +2 -26
- package/dist/system.d.ts +3 -3
- package/dist/system.js +4 -42
- package/dist/uploads.d.ts +12 -0
- package/dist/uploads.js +58 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ capabilities, or contain System and transport implementations.
|
|
|
19
19
|
|
|
20
20
|
Its `System` contract exposes only desktop-session capabilities: read-only
|
|
21
21
|
System Appearance, the mutable Theme local to this Desktop, desktop and pointer
|
|
22
|
-
state,
|
|
22
|
+
state, flat public uploads, and unrestricted server-side Fetch.
|
|
23
23
|
`system.appearance.snapshot()` reads complete unresolved authoritative state.
|
|
24
24
|
`system.theme.snapshot()` reads only the effective `"light" | "dark"` mode;
|
|
25
25
|
`update("default")` resumes following the native environment. Both expose
|
|
@@ -27,6 +27,10 @@ ordinary live-only `change` subscriptions with no initial replay. A Client
|
|
|
27
27
|
cannot write authoritative Appearance or discover system-wide Programs and
|
|
28
28
|
Processes.
|
|
29
29
|
|
|
30
|
+
`system.uploads` has the same flat contract as the Server SDK. It writes a
|
|
31
|
+
value, then reads or describes it using exactly one opaque generated file key;
|
|
32
|
+
it exposes no filesystem path, path segments, listing, deletion, or clearing.
|
|
33
|
+
|
|
30
34
|
Desktop and pointer access are independent objects rather than events merged
|
|
31
35
|
into System:
|
|
32
36
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Wrap a transferred byte stream so cancellation and completion release its transport. */
|
|
2
|
+
export default function controlledStream(body, abort, close) {
|
|
3
|
+
const reader = body.getReader();
|
|
4
|
+
return new ReadableStream({
|
|
5
|
+
async pull(controller) {
|
|
6
|
+
try {
|
|
7
|
+
const next = await reader.read();
|
|
8
|
+
if (next.done) {
|
|
9
|
+
close();
|
|
10
|
+
controller.close();
|
|
11
|
+
}
|
|
12
|
+
else
|
|
13
|
+
controller.enqueue(next.value);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
close();
|
|
17
|
+
controller.error(error);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
async cancel(reason) {
|
|
21
|
+
abort();
|
|
22
|
+
close();
|
|
23
|
+
await reader.cancel(reason);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
package/dist/main.d.ts
CHANGED
|
@@ -5,4 +5,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
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, Storage, ProgramEvents, ProgramProcessEvents, ProgramProcessExit, ProgramSql, ProgramStore, ProcessEvents, Publishable,
|
|
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, Storage, ProgramEvents, ProgramProcessEvents, ProgramProcessExit, ProgramSql, ProgramStore, ProcessEvents, Publishable, SystemUploads, Upload, Size, Subscribable, SubscribableEvents, SubscribableFallback, TimedAskable, TimedPermission, Timeoutable, Appearance, AppearanceEvents, AppearanceSource, AppearanceSurface, SystemTheme, ThemedValue, Theme, ThemeEvents, ThemePreference, Value, WindowEvents, WindowGeometry, WindowLayer, WindowState, Easing, LocalWindow, LocalWindowSurface, VisibilityTransition, Transaction } from "@phreshos/core";
|
package/dist/storage.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { content } from "./content.js";
|
|
2
|
+
import controlledStream from "./controlled-stream.js";
|
|
2
3
|
import wire from "./wire.js";
|
|
3
4
|
/** Client-side Program storage, structurally scoped by the iframe boundary. */
|
|
4
5
|
export function area(which) {
|
|
@@ -18,7 +19,7 @@ export function area(which) {
|
|
|
18
19
|
}
|
|
19
20
|
if (!(answer[0] instanceof ReadableStream))
|
|
20
21
|
throw new Error("The storage response has no byte stream");
|
|
21
|
-
return
|
|
22
|
+
return controlledStream(answer[0], abort, close);
|
|
22
23
|
}
|
|
23
24
|
catch (error) {
|
|
24
25
|
abort();
|
|
@@ -69,28 +70,3 @@ export function sql(kind) {
|
|
|
69
70
|
}
|
|
70
71
|
};
|
|
71
72
|
}
|
|
72
|
-
function controlled(body, abort, close) {
|
|
73
|
-
const reader = body.getReader();
|
|
74
|
-
return new ReadableStream({
|
|
75
|
-
async pull(controller) {
|
|
76
|
-
try {
|
|
77
|
-
const next = await reader.read();
|
|
78
|
-
if (next.done) {
|
|
79
|
-
close();
|
|
80
|
-
controller.close();
|
|
81
|
-
}
|
|
82
|
-
else
|
|
83
|
-
controller.enqueue(next.value);
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
close();
|
|
87
|
-
controller.error(error);
|
|
88
|
-
}
|
|
89
|
-
},
|
|
90
|
-
async cancel(reason) {
|
|
91
|
-
abort();
|
|
92
|
-
close();
|
|
93
|
-
await reader.cancel(reason);
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
}
|
package/dist/system.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AppearanceSource, ClientServiceHandler,
|
|
1
|
+
import type { AppearanceSource, ClientServiceHandler, ServerServiceHandler, ServiceKey, SystemUploads, SystemTheme } from "@phreshos/core";
|
|
2
2
|
import { type SystemPointer } from "./pointer.js";
|
|
3
3
|
import { type SystemDesktop } from "./desktop.js";
|
|
4
4
|
type ServiceEndpoint = ServiceKey["endpoint"];
|
|
@@ -16,8 +16,8 @@ export interface System {
|
|
|
16
16
|
readonly desktop: SystemDesktop;
|
|
17
17
|
/** Permission-guarded desktop pointer reads and live movement. */
|
|
18
18
|
readonly pointer: SystemPointer;
|
|
19
|
-
/**
|
|
20
|
-
|
|
19
|
+
/** Flat System-owned public uploads capability. */
|
|
20
|
+
readonly uploads: SystemUploads;
|
|
21
21
|
/** Performs an unrestricted server-side fetch on behalf of this Client. */
|
|
22
22
|
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
23
23
|
/** Returns a precisely typed stable handle for either service endpoint. */
|
package/dist/system.js
CHANGED
|
@@ -1,31 +1,18 @@
|
|
|
1
1
|
import ClientAppearance from "./appearance.js";
|
|
2
|
-
import { content } from "./content.js";
|
|
3
2
|
import ClientTheme from "./theme.js";
|
|
4
3
|
import wire from "./wire.js";
|
|
5
4
|
import ClientPointer, {} from "./pointer.js";
|
|
6
5
|
import ClientDesktop, {} from "./desktop.js";
|
|
7
6
|
import { prepareService } from "./service.js";
|
|
7
|
+
import { uploads } from "./uploads.js";
|
|
8
|
+
import controlledStream from "./controlled-stream.js";
|
|
8
9
|
class ClientSystem {
|
|
9
10
|
appearance = new ClientAppearance();
|
|
10
11
|
theme = new ClientTheme();
|
|
11
12
|
desktop = new ClientDesktop();
|
|
12
13
|
pointer = new ClientPointer();
|
|
14
|
+
uploads = uploads;
|
|
13
15
|
service(key) { return prepareService(key); }
|
|
14
|
-
async serve(value) {
|
|
15
|
-
const source = content(value);
|
|
16
|
-
const channel = new MessageChannel();
|
|
17
|
-
const abort = () => channel.port1.postMessage("abort");
|
|
18
|
-
try {
|
|
19
|
-
const answer = await wire.request(["serve", source.body, { extension: source.extension, type: source.type }, channel.port2], undefined, source.body instanceof ReadableStream ? [source.body, channel.port2] : [channel.port2]);
|
|
20
|
-
channel.port1.close();
|
|
21
|
-
return answer[0];
|
|
22
|
-
}
|
|
23
|
-
catch (error) {
|
|
24
|
-
abort();
|
|
25
|
-
channel.port1.close();
|
|
26
|
-
throw error;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
16
|
async fetch(input, init) {
|
|
30
17
|
const request = new Request(input, {
|
|
31
18
|
...init,
|
|
@@ -65,7 +52,7 @@ class ClientSystem {
|
|
|
65
52
|
throw request.signal.aborted ? request.signal.reason : error;
|
|
66
53
|
}
|
|
67
54
|
const responseBody = result.body
|
|
68
|
-
?
|
|
55
|
+
? controlledStream(result.body, abort, () => closeControl(request.signal, control.port1, abort))
|
|
69
56
|
: null;
|
|
70
57
|
if (!responseBody)
|
|
71
58
|
closeControl(request.signal, control.port1, abort);
|
|
@@ -93,31 +80,6 @@ function requestHeaders(normalized, supplied) {
|
|
|
93
80
|
const names = new Set(explicit.map(([name]) => name.toLowerCase()));
|
|
94
81
|
return [...normalized.entries()].filter(([name]) => !names.has(name.toLowerCase())).concat(explicit);
|
|
95
82
|
}
|
|
96
|
-
function controlled(body, abort, close) {
|
|
97
|
-
const reader = body.getReader();
|
|
98
|
-
return new ReadableStream({
|
|
99
|
-
async pull(controller) {
|
|
100
|
-
try {
|
|
101
|
-
const next = await reader.read();
|
|
102
|
-
if (next.done) {
|
|
103
|
-
close();
|
|
104
|
-
controller.close();
|
|
105
|
-
}
|
|
106
|
-
else
|
|
107
|
-
controller.enqueue(next.value);
|
|
108
|
-
}
|
|
109
|
-
catch (error) {
|
|
110
|
-
close();
|
|
111
|
-
controller.error(error);
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
async cancel(reason) {
|
|
115
|
-
abort();
|
|
116
|
-
close();
|
|
117
|
-
await reader.cancel(reason);
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
83
|
function closeControl(signal, port, abort) {
|
|
122
84
|
signal.removeEventListener("abort", abort);
|
|
123
85
|
port.close();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type SystemUploads, type Upload } from "@phreshos/core";
|
|
2
|
+
/** Flat upload access transported through the Client's Desktop boundary. */
|
|
3
|
+
declare class ClientUploads implements SystemUploads {
|
|
4
|
+
write(value: unknown): Promise<Upload>;
|
|
5
|
+
stream(file: string): Promise<ReadableStream<Uint8Array>>;
|
|
6
|
+
bytes(file: string): Promise<Uint8Array<ArrayBuffer>>;
|
|
7
|
+
text(file: string): Promise<string>;
|
|
8
|
+
json<Value>(file: string): Promise<Value>;
|
|
9
|
+
stat(file: string): Promise<Upload | null>;
|
|
10
|
+
}
|
|
11
|
+
export declare const uploads: ClientUploads;
|
|
12
|
+
export {};
|
package/dist/uploads.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { isUploadFile } from "@phreshos/core";
|
|
2
|
+
import { content } from "./content.js";
|
|
3
|
+
import controlledStream from "./controlled-stream.js";
|
|
4
|
+
import wire from "./wire.js";
|
|
5
|
+
/** Flat upload access transported through the Client's Desktop boundary. */
|
|
6
|
+
class ClientUploads {
|
|
7
|
+
async write(value) {
|
|
8
|
+
const source = content(value);
|
|
9
|
+
const channel = new MessageChannel();
|
|
10
|
+
const abort = () => channel.port1.postMessage("abort");
|
|
11
|
+
try {
|
|
12
|
+
const answer = await wire.request(["uploads", "write", source.body, { extension: source.extension, type: source.type }, channel.port2], undefined, source.body instanceof ReadableStream ? [source.body, channel.port2] : [channel.port2]);
|
|
13
|
+
channel.port1.close();
|
|
14
|
+
return answer[0];
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
abort();
|
|
18
|
+
channel.port1.close();
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async stream(file) {
|
|
23
|
+
requireFile(file);
|
|
24
|
+
const channel = new MessageChannel();
|
|
25
|
+
const abort = () => channel.port1.postMessage("abort");
|
|
26
|
+
const close = () => channel.port1.close();
|
|
27
|
+
try {
|
|
28
|
+
const answer = await wire.request(["uploads", "stream", file, channel.port2], undefined, [channel.port2]);
|
|
29
|
+
if (!(answer[0] instanceof ReadableStream))
|
|
30
|
+
throw new Error("The upload response has no byte stream");
|
|
31
|
+
return controlledStream(answer[0], abort, close);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
abort();
|
|
35
|
+
close();
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async bytes(file) {
|
|
40
|
+
return new Uint8Array(await new Response(await this.stream(file)).arrayBuffer());
|
|
41
|
+
}
|
|
42
|
+
async text(file) {
|
|
43
|
+
return new Response(await this.stream(file)).text();
|
|
44
|
+
}
|
|
45
|
+
async json(file) {
|
|
46
|
+
return JSON.parse(await this.text(file));
|
|
47
|
+
}
|
|
48
|
+
async stat(file) {
|
|
49
|
+
requireFile(file);
|
|
50
|
+
const answer = await wire.request(["uploads", "stat", file]);
|
|
51
|
+
return answer[0];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function requireFile(file) {
|
|
55
|
+
if (!isUploadFile(file))
|
|
56
|
+
throw new Error("That is not an upload file");
|
|
57
|
+
}
|
|
58
|
+
export const uploads = new ClientUploads();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phreshos/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.22",
|
|
4
4
|
"description": "The SDK used by a Program's client endpoint.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -47,13 +47,13 @@
|
|
|
47
47
|
"prepack": "node --run build"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@phreshos/core": "^0.1.
|
|
50
|
+
"@phreshos/core": "^0.1.19"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@msgpack/msgpack": "^3.1.3"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@phreshos/core": "^0.1.
|
|
56
|
+
"@phreshos/core": "^0.1.19",
|
|
57
57
|
"typescript": "^6.0.3"
|
|
58
58
|
}
|
|
59
59
|
}
|